| | |
| | | namespace Yw.WinFrmUI.HydroL2d |
| | | |
| | | namespace Yw.WinFrmUI.HydroL2d |
| | | { |
| | | /// <summary> |
| | | /// 管网面板 |
| | |
| | | |
| | | //设置允许的最小尺寸 |
| | | this.MinimumSize = new Size(10, 10); |
| | | |
| | | } |
| | | |
| | | |
| | | private Network _network = null;//管网 |
| | | private Bitmap _cache = null;//绘制缓存 |
| | | private float _zoomMin = 1;//最小缩放层级 |
| | | private float _zoomMax = 3200;//最大缩放层级 |
| | | private float _zoom = 1;//当前缩放层级 |
| | | private float _dxo = 0;//x偏移量 |
| | | private float _dyo = 0;//y偏移量 |
| | | protected Network _network = null;//管网 |
| | | protected RectangleF _networkBounds;//管网边界 |
| | | private Bitmap _cache = null;//缓存<依据工作区域创建的空图片> |
| | | private object _cacheLocker = new();//缓存锁 |
| | | private Bitmap _disp = null;//显示<在cache基础上进行绘制,最终的显示图片> |
| | | private object _dispLocker = new();//显示锁 |
| | | private float _zoomMin = 0.01f;//最小缩放层级 |
| | | private float _zoomMax = 10000f;//最大缩放层级 |
| | | private float _zoom = 1f;//当前缩放层级 |
| | | private float _dxo = 0f;//x偏移量 |
| | | private float _dyo = 0f;//y偏移量 |
| | | private RectangleF _clientRectf;//工作区域矩形 |
| | | |
| | | |
| | | #region 初始化 |
| | | |
| | | /// <summary> |
| | | /// 是否初始化 |
| | | /// </summary> |
| | | public bool Initialized => _network != null; |
| | | |
| | | |
| | | |
| | | |
| | | /// <summary> |
| | | /// 初始化 |
| | |
| | | public virtual void Initial(Network network) |
| | | { |
| | | _network = network; |
| | | _networkBounds = _network.GetBounds(); |
| | | _clientRectf = GetClientRectangleF(); |
| | | CreateCache(); |
| | | ZoomAll(); |
| | | } |
| | | |
| | | protected override void OnPaint(PaintEventArgs e) |
| | | #endregion |
| | | |
| | | #region 缓存与显示 |
| | | |
| | | /// <summary> |
| | | /// 创建缓存 |
| | | /// </summary> |
| | | protected virtual void CreateCache() |
| | | { |
| | | base.OnPaint(e); |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | try |
| | | var img = new Bitmap((int)_clientRectf.Width, (int)_clientRectf.Height); |
| | | img.MakeTransparent(Color.White); |
| | | lock (_cacheLocker) |
| | | { |
| | | e.Graphics.PageUnit = GraphicsUnit.Pixel; |
| | | e.Graphics.InterpolationMode = InterpolationMode.High; |
| | | e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; |
| | | e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; |
| | | e.Graphics.PageScale = _zoom; |
| | | e.Graphics.TranslateTransform(_dxo, _dyo); |
| | | e.Graphics.ScaleTransform(1, -1); |
| | | if (_cache != null) |
| | | { |
| | | _cache.Dispose(); |
| | | } |
| | | _cache = img; |
| | | } |
| | | catch |
| | | { |
| | | return; |
| | | } |
| | | _network.Draw(e.Graphics); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 界面尺寸发生改变 |
| | | /// 绘制缓存 |
| | | /// </summary> |
| | | /// <param name="eventargs"></param> |
| | | protected override void OnResize(EventArgs eventargs) |
| | | protected virtual void DrawCache() |
| | | { |
| | | base.OnResize(eventargs); |
| | | ZoomAll(); |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | if (_cache == null) |
| | | { |
| | | return; |
| | | } |
| | | var disp = _cache.CloneC(); |
| | | if (disp == null) |
| | | { |
| | | return; |
| | | } |
| | | var dispRect = GetDispRectangleF(); |
| | | using (var g = Graphics.FromImage(disp)) |
| | | { |
| | | g.PageUnit = GraphicsUnit.Pixel; |
| | | g.InterpolationMode = InterpolationMode.High; |
| | | g.SmoothingMode = SmoothingMode.AntiAlias; |
| | | g.PixelOffsetMode = PixelOffsetMode.HighQuality; |
| | | g.PageScale = _zoom; |
| | | g.TranslateTransform(_dxo, _dyo); |
| | | g.ScaleTransform(1, -1); |
| | | |
| | | //_network.Draw(g, dispRect); |
| | | _network.Draw(g); |
| | | } |
| | | lock (_dispLocker) |
| | | { |
| | | if (_disp != null) |
| | | { |
| | | _disp.Dispose(); |
| | | } |
| | | _disp = disp; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 应用缓存 |
| | | /// </summary> |
| | | protected virtual void ApplyCache(Graphics g) |
| | | { |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | lock (_dispLocker) |
| | | { |
| | | if (_disp != null) |
| | | { |
| | | g.DrawImage(_disp, _clientRectf); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 缩放 |
| | | |
| | | /// <summary> |
| | | /// 缩放等级 |
| | | /// </summary> |
| | | public float Zoom |
| | | { |
| | | get => _zoom; |
| | | private set |
| | | { |
| | | if (_networkBounds.IsEmpty) |
| | | { |
| | | _zoom = 1f; |
| | | return; |
| | | } |
| | | |
| | | float sizeMax = Math.Max(_networkBounds.Height, _networkBounds.Width); |
| | | float sizeNew = sizeMax * value; |
| | | |
| | | if (sizeNew > _zoomMax) |
| | | { |
| | | _zoom = _zoomMax / sizeMax; |
| | | } |
| | | else if (sizeNew < _zoomMin) |
| | | { |
| | | _zoom = _zoomMin / sizeMax; |
| | | } |
| | | else |
| | | { |
| | | _zoom = value; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 自适应 |
| | | /// </summary> |
| | | public void ZoomAll() |
| | | { |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | var networkBounds = _network.GetBounds(); |
| | | if (networkBounds.IsEmpty) |
| | | { |
| | | return; |
| | | } |
| | | this.Zoom = networkBounds.Width / networkBounds.Height < this.Width / this.Height ? |
| | | this.Height / networkBounds.Height : |
| | | this.Width / networkBounds.Width; |
| | | |
| | | |
| | | _dxo = -networkBounds.X; |
| | | _dyo = networkBounds.Bottom; |
| | | |
| | | this.Zoom *= 0.9f; |
| | | |
| | | _dxo += this.Width * 0.5f / this.Zoom - networkBounds.Width * 0.5f; |
| | | _dyo += this.Height * 0.5f / this.Zoom - networkBounds.Height * 0.5f; |
| | | } |
| | | |
| | | |
| | | private void ZoomToPoint(MouseEventArgs e) |
| | | { |
| | | float scale = e.Delta > 0 ? this.Zoom * 1.5f : this.Zoom / 1.5f; |
| | | var pt = ClientToDispPoint(e.Location); |
| | | this.Zoom = scale; |
| | | _dxo = -pt.X + e.X / this.Zoom; |
| | | _dyo = pt.Y + e.Y / this.Zoom; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 坐标转换 |
| | | |
| | | protected PointF ClientToDispPoint(PointF cp) |
| | | { |
| | | return new PointF(-_dxo + cp.X / _zoom, _dyo - cp.Y / _zoom); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 边框绘制 |
| | | |
| | | /// <summary> |
| | | /// 边框颜色 |
| | | /// </summary> |
| | | [Browsable(true)] |
| | | [Description("自定义边框颜色")] |
| | | public Color CustomBorderColor |
| | | { |
| | | get { return _customBorderColor; } |
| | | set { _customBorderColor = value; } |
| | | } |
| | | private Color _customBorderColor = Color.Gray; |
| | | |
| | | /// <summary> |
| | | /// 边框宽度 |
| | | /// </summary> |
| | | [Browsable(true)] |
| | | [Description("自定义边框宽度")] |
| | | public int CustomBorderWidth |
| | | { |
| | | get { return _customBorderWidth; } |
| | | set { _customBorderWidth = value; } |
| | | } |
| | | private int _customBorderWidth = 1; |
| | | |
| | | /// <summary> |
| | | /// 边框是否显示 |
| | | /// </summary> |
| | | [Browsable(true)] |
| | | [Description("自定义边框可见性")] |
| | | [DefaultValue(false)] |
| | | public bool CustomBorderVisible |
| | | { |
| | | get { return _customBorderVisible; } |
| | | set |
| | | { |
| | | _customBorderVisible = value; |
| | | } |
| | | } |
| | | private bool _customBorderVisible = false; |
| | | |
| | | /// <summary> |
| | | /// 绘制自定义边框 |
| | | /// </summary> |
| | | protected virtual void DrawCustomBorder(Graphics g) |
| | | { |
| | | if (this.CustomBorderVisible) |
| | | { |
| | | ControlPaint.DrawBorder(g, |
| | | this.ClientRectangle, |
| | | this.CustomBorderColor, this.CustomBorderWidth, ButtonBorderStyle.Solid, |
| | | this.CustomBorderColor, this.CustomBorderWidth, ButtonBorderStyle.Solid, |
| | | this.CustomBorderColor, this.CustomBorderWidth, ButtonBorderStyle.Solid, |
| | | this.CustomBorderColor, this.CustomBorderWidth, ButtonBorderStyle.Solid); |
| | | } |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | |
| | | #region 获取矩形 |
| | | |
| | | /// <summary> |
| | | /// 获取工作区域 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | protected virtual RectangleF GetClientRectangleF() |
| | | { |
| | | return new RectangleF(0, 0, this.Width, this.Height); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取显示区域 |
| | | /// </summary> |
| | | protected virtual RectangleF GetDispRectangleF() |
| | | { |
| | | if (_clientRectf.IsEmpty) |
| | | { |
| | | return default; |
| | | } |
| | | if (!Initialized) |
| | | { |
| | | return default; |
| | | } |
| | | var pt = ClientToDispPoint(_clientRectf.Location); |
| | | var width = _clientRectf.Width / _zoom; |
| | | var height = _clientRectf.Height / _zoom; |
| | | return new RectangleF(pt, new SizeF(width, height)); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 鼠标左键按下拖动 |
| | | |
| | | /// <summary> |
| | | /// 当鼠标左键按下时允许拖动 |
| | | /// </summary> |
| | | [Browsable(true)] |
| | | [Description("当鼠标左键按下时允许拖动")] |
| | | [DefaultValue(true)] |
| | | public bool AllowMoveWhenMouseLeftDown |
| | | { |
| | | get => _allowMoveWhenMouseLeftDown; |
| | | set => _allowMoveWhenMouseLeftDown = value; |
| | | } |
| | | private bool _allowMoveWhenMouseLeftDown = true; |
| | | |
| | | protected bool _hasMouseLeftDown = false;//鼠标左键是否按下 |
| | | protected Point _mouseLeftDownMovePoint;//鼠标左键按下移动点 |
| | | |
| | | /// <summary> |
| | | /// 判断鼠标左键是否按下 |
| | | /// </summary> |
| | | protected virtual bool HasMouseLeftDown(MouseEventArgs e) |
| | | { |
| | | if (e.Button == MouseButtons.Left) |
| | | { |
| | | if (Initialized) |
| | | { |
| | | if (this.AllowMoveWhenMouseLeftDown) |
| | | { |
| | | _hasMouseLeftDown = true; |
| | | _mouseLeftDownMovePoint = e.Location; |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 鼠标左键按下移动 |
| | | /// </summary> |
| | | /// <param name="e"></param> |
| | | protected virtual bool MouseLeftDownMove(MouseEventArgs e) |
| | | { |
| | | if (e.Button == MouseButtons.Left) |
| | | { |
| | | if (this.AllowMoveWhenMouseLeftDown) |
| | | { |
| | | if (_hasMouseLeftDown) |
| | | { |
| | | if (Initialized) |
| | | { |
| | | var pt = new PointF(e.X - _mouseLeftDownMovePoint.X, e.Y - _mouseLeftDownMovePoint.Y); |
| | | _dxo += pt.X / _zoom; |
| | | _dyo += pt.Y / _zoom; |
| | | _mouseLeftDownMovePoint = e.Location; |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 判断鼠标左键是否弹起 |
| | | /// </summary> |
| | | protected virtual bool HasMouseLeftUp(MouseEventArgs e) |
| | | { |
| | | _hasMouseLeftDown = false; |
| | | return true; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 鼠标双击恢复自适应 |
| | | |
| | | /// <summary> |
| | | /// 当鼠标双击时允许自适应 |
| | | /// </summary> |
| | | [Browsable(true)] |
| | | [Description("当鼠标双击时允许自适应")] |
| | | [DefaultValue(true)] |
| | | public bool AllowZoomAllWhenMouseDoubleClick |
| | | { |
| | | get => _allowZoomAllWhenMouseDoubleClick; |
| | | set => _allowZoomAllWhenMouseDoubleClick = value; |
| | | } |
| | | private bool _allowZoomAllWhenMouseDoubleClick = true; |
| | | |
| | | /// <summary> |
| | | /// 鼠标双击时自适应 |
| | | /// </summary> |
| | | protected virtual bool ZoomAllWhenMouseDoubleClick(MouseEventArgs e) |
| | | { |
| | | if (e.Clicks > 1) |
| | | { |
| | | if (AllowZoomAllWhenMouseDoubleClick) |
| | | { |
| | | ZoomAll(); |
| | | return true; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 释放资源 |
| | | |
| | | /// <summary> |
| | | /// 释放资源 |
| | |
| | | |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 选择 |
| | | |
| | | /// <summary> |
| | | /// 自适应 |
| | | /// 选择(通过点选择) |
| | | /// </summary> |
| | | public void ZoomAll() |
| | | protected virtual List<Parter> Select(MouseEventArgs e) |
| | | { |
| | | if (!Initialized) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | float w = Width; |
| | | float h = Height; |
| | | var networkBounds = _network.GetBounds(); |
| | | if (networkBounds.IsEmpty) |
| | | { |
| | | return; |
| | | } |
| | | _zoom = networkBounds.Width / networkBounds.Height < w / h ? |
| | | h / networkBounds.Height : |
| | | w / networkBounds.Width; |
| | | |
| | | |
| | | _dxo = -networkBounds.X; |
| | | _dyo = networkBounds.Bottom; |
| | | |
| | | _zoom *= 0.95f; |
| | | |
| | | _dxo += w * 0.5f / _zoom - networkBounds.Width * 0.5f; |
| | | _dyo += h * 0.5f / _zoom - networkBounds.Height * 0.5f; |
| | | |
| | | Invalidate(); |
| | | var pt = ClientToDispPoint(e.Location); |
| | | var list = _network.Select(pt); |
| | | return list; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 悬停 |
| | | /// </summary> |
| | | protected virtual List<Parter> Hover(MouseEventArgs e) |
| | | { |
| | | var pt = ClientToDispPoint(e.Location); |
| | | var list = _network.Hover(pt); |
| | | return list; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | /// <summary> |
| | | /// 重绘 |
| | | /// </summary> |
| | | protected override void OnPaint(PaintEventArgs e) |
| | | { |
| | | base.OnPaint(e); |
| | | DrawCustomBorder(e.Graphics); |
| | | DrawCache(); |
| | | ApplyCache(e.Graphics); |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 界面尺寸发生改变 |
| | | /// </summary> |
| | | /// <param name="eventargs"></param> |
| | | protected override void OnResize(EventArgs eventargs) |
| | | { |
| | | base.OnResize(eventargs); |
| | | _clientRectf = GetClientRectangleF(); |
| | | ZoomAll(); |
| | | CreateCache(); |
| | | this.Invalidate(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 鼠标按下 |
| | | /// </summary> |
| | | protected override void OnMouseDown(MouseEventArgs e) |
| | | { |
| | | base.OnMouseDown(e); |
| | | HasMouseLeftDown(e); |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 鼠标移动 |
| | | /// </summary> |
| | | protected override void OnMouseMove(MouseEventArgs e) |
| | | { |
| | | base.OnMouseMove(e); |
| | | Hover(e); |
| | | MouseLeftDownMove(e); |
| | | this.Invalidate(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 鼠标弹起 |
| | | /// </summary> |
| | | protected override void OnMouseUp(MouseEventArgs e) |
| | | { |
| | | base.OnMouseUp(e); |
| | | HasMouseLeftUp(e); |
| | | Select(e); |
| | | this.Invalidate(); |
| | | } |
| | | |
| | | //鼠标滚轮滚动 |
| | | protected override void OnMouseWheel(MouseEventArgs e) |
| | | { |
| | | base.OnMouseWheel(e); |
| | | ZoomToPoint(e); |
| | | this.Refresh(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 鼠标双击 |
| | | /// </summary> |
| | | protected override void OnMouseDoubleClick(MouseEventArgs e) |
| | | { |
| | | base.OnMouseDoubleClick(e); |
| | | if (ZoomAllWhenMouseDoubleClick(e)) |
| | | { |
| | | this.Invalidate(); |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
| | | } |