namespace Yw.WinFrmUI.HydroL2d
|
{
|
/// <summary>
|
/// 管网面板
|
/// </summary>
|
public partial class NetworkPanel : Panel
|
{
|
public NetworkPanel()
|
{
|
InitializeComponent();
|
|
#region 防止闪烁
|
|
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
SetStyle(ControlStyles.DoubleBuffer, true);
|
SetStyle(ControlStyles.UserPaint, true);
|
|
#endregion
|
|
//设置允许的最小尺寸
|
this.MinimumSize = new Size(10, 10);
|
}
|
|
#region 初始化
|
|
protected Network _network = null;//管网
|
protected RectangleF _networkBounds;//管网边界
|
protected RectangleF _clientRectf;//工作区域矩形
|
|
/// <summary>
|
/// 是否初始化
|
/// </summary>
|
public bool Initialized => _network != null;
|
|
/// <summary>
|
/// 初始化
|
/// </summary>
|
public virtual void Initial(Network network)
|
{
|
_network = network;
|
_networkBounds = _network.GetBounds();
|
_clientRectf = GetClientRectangleF();
|
CreateCache();
|
ZoomAll();
|
}
|
|
#endregion
|
|
#region 缓存与显示
|
|
private Bitmap _cache = null;//缓存<依据工作区域创建的空图片>
|
private object _cacheLocker = new();//缓存锁
|
|
/// <summary>
|
/// 创建缓存
|
/// </summary>
|
protected virtual void CreateCache()
|
{
|
if (!Initialized)
|
{
|
return;
|
}
|
var img = new Bitmap((int)_clientRectf.Width, (int)_clientRectf.Height);
|
lock (_cacheLocker)
|
{
|
if (_cache != null)
|
{
|
_cache.Dispose();
|
}
|
_cache = img;
|
}
|
}
|
|
/// <summary>
|
/// 绘制缓存
|
/// </summary>
|
protected virtual void DrawCache()
|
{
|
if (!Initialized)
|
{
|
return;
|
}
|
if (_cache == null)
|
{
|
return;
|
}
|
var dispRect = GetDispRectangleF();
|
using (var g = Graphics.FromImage(_cache))
|
{
|
g.Clear(Color.White);
|
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);
|
}
|
}
|
|
/// <summary>
|
/// 应用缓存
|
/// </summary>
|
protected virtual void ApplyCache(Graphics g)
|
{
|
if (!Initialized)
|
{
|
return;
|
}
|
lock (_cacheLocker)
|
{
|
if (_cache != null)
|
{
|
g.DrawImage(_cache, _clientRectf);
|
}
|
}
|
|
}
|
|
#endregion
|
|
#region 缩放与偏移
|
|
private float _zoomMin = 0.001f;//最小缩放层级
|
private float _zoomMax = 30000f;//最大缩放层级
|
private float _zoom = 1f;//当前缩放层级
|
private float _dxo = 0f;//x偏移量
|
private float _dyo = 0f;//y偏移量
|
|
/// <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(new PointF(_clientRectf.X, _clientRectf.Height));
|
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)
|
{
|
_hasMouseLeftDown = true;
|
_mouseLeftDownMovePoint = e.Location;
|
return true;
|
}
|
return false;
|
}
|
|
/// <summary>
|
/// 鼠标左键按下移动
|
/// </summary>
|
/// <param name="e"></param>
|
protected virtual bool MouseLeftDownMove(MouseEventArgs e)
|
{
|
if (_hasMouseLeftDown)
|
{
|
if (this.AllowMoveWhenMouseLeftDown)
|
{
|
if (this.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)
|
{
|
if (_hasMouseLeftDown)
|
{
|
_hasMouseLeftDown = false;
|
return true;
|
}
|
return false;
|
}
|
|
#endregion
|
|
#region 鼠标右键按下拖动
|
|
/// <summary>
|
/// 当鼠标右键按下时允许拖动
|
/// </summary>
|
[Browsable(true)]
|
[Description("当鼠标右键按下时允许拖动")]
|
[DefaultValue(true)]
|
public bool AllowMoveWhenMouseRightDown
|
{
|
get => _allowMoveWhenMouseRightDown;
|
set => _allowMoveWhenMouseRightDown = value;
|
}
|
private bool _allowMoveWhenMouseRightDown = true;
|
|
protected bool _hasMouseRightDown = false;//鼠标右键是否按下
|
protected Point _mouseRightDownMovePoint;//鼠标右键按下移动点
|
|
/// <summary>
|
/// 判断鼠标右键是否按下
|
/// </summary>
|
protected virtual bool HasMouseRightDown(MouseEventArgs e)
|
{
|
if (e.Button == MouseButtons.Right)
|
{
|
_hasMouseRightDown = true;
|
_mouseRightDownMovePoint = e.Location;
|
return true;
|
}
|
return false;
|
}
|
|
/// <summary>
|
/// 鼠标右键按下移动
|
/// </summary>
|
protected virtual bool MouseRightDownMove(MouseEventArgs e)
|
{
|
if (_hasMouseRightDown)
|
{
|
if (this.AllowMoveWhenMouseRightDown)
|
{
|
if (this.Initialized)
|
{
|
var pt = new PointF(e.X - _mouseRightDownMovePoint.X, e.Y - _mouseRightDownMovePoint.Y);
|
_dxo += pt.X / _zoom;
|
_dyo += pt.Y / _zoom;
|
_mouseRightDownMovePoint = e.Location;
|
return true;
|
}
|
}
|
}
|
return false;
|
}
|
|
/// <summary>
|
/// 判断鼠标左键是否弹起
|
/// </summary>
|
protected virtual bool HasMouseRightUp(MouseEventArgs e)
|
{
|
if (_hasMouseRightDown)
|
{
|
_hasMouseRightDown = false;
|
return true;
|
}
|
return false;
|
}
|
|
#endregion
|
|
#region 鼠标左键双击恢复自适应
|
|
/// <summary>
|
/// 当鼠标双击时允许自适应
|
/// </summary>
|
[Browsable(true)]
|
[Description("当鼠标双击时允许自适应")]
|
[DefaultValue(true)]
|
public bool AllowZoomAllWhenMouseLeftDoubleClick
|
{
|
get => _allowZoomAllWhenMouseLeftDoubleClick;
|
set => _allowZoomAllWhenMouseLeftDoubleClick = value;
|
}
|
private bool _allowZoomAllWhenMouseLeftDoubleClick = true;
|
|
/// <summary>
|
/// 鼠标双击时自适应
|
/// </summary>
|
protected virtual bool ZoomAllWhenMouseLeftDoubleClick(MouseEventArgs e)
|
{
|
if (e.Button == MouseButtons.Left)
|
{
|
if (e.Clicks > 1)
|
{
|
if (this.AllowZoomAllWhenMouseLeftDoubleClick)
|
{
|
if (this.Initialized)
|
{
|
ZoomAll();
|
return true;
|
}
|
}
|
}
|
}
|
return false;
|
}
|
|
#endregion
|
|
#region 鼠标悬停
|
|
/// <summary>
|
/// 允许鼠标悬停
|
/// </summary>
|
[Browsable(true)]
|
[Description("允许鼠标悬停")]
|
[DefaultValue(true)]
|
public bool AllowMouseHover
|
{
|
get => _allowMouseHover;
|
set => _allowMouseHover = value;
|
}
|
private bool _allowMouseHover = true;
|
private List<Parter> _lastHoverList = null;//最后一次悬停列表
|
|
/// <summary>
|
/// 悬停
|
/// 如果发生改变就返回true
|
/// </summary>
|
protected virtual bool Hover(MouseEventArgs e)
|
{
|
if (this.AllowMouseHover)
|
{
|
if (this.Initialized)
|
{
|
var pt = ClientToDispPoint(e.Location);
|
var hoverList = _network.Hover(pt);
|
if (hoverList == null || hoverList.Count < 1)
|
{
|
if (_lastHoverList == null || _lastHoverList.Count < 1)
|
{
|
return false;
|
}
|
}
|
_lastHoverList = hoverList;
|
return true;
|
}
|
}
|
if (_lastHoverList == null || _lastHoverList.Count < 1)
|
{
|
return false;
|
}
|
return true;
|
}
|
|
#endregion
|
|
#region 鼠标左键点击选择
|
|
/// <summary>
|
/// 允许鼠标左键单击选择
|
/// </summary>
|
[Browsable(true)]
|
[Description("允许鼠标左键单击选择")]
|
[DefaultValue(true)]
|
public bool AllowMouseLeftSingleClickSelect
|
{
|
get => _allowMouseLeftSingleClickSelect;
|
set => _allowMouseLeftSingleClickSelect = value;
|
}
|
private bool _allowMouseLeftSingleClickSelect = true;
|
private List<Parter> _lastMouseLeftClickSelectList = null;//最后一次鼠标左键单击选择列表
|
|
|
/// <summary>
|
/// 当鼠标左键单击时选择
|
/// </summary>
|
protected virtual bool SelectWhenMouseLeftSingleClick(MouseEventArgs e)
|
{
|
if (e.Button == MouseButtons.Left)
|
{
|
if (e.Clicks == 1)
|
{
|
if (this.Initialized)
|
{
|
var pt = ClientToDispPoint(e.Location);
|
var selectList = _network.Select(pt);
|
if (selectList == null || selectList.Count < 1)
|
{
|
if (_lastMouseLeftClickSelectList == null || _lastMouseLeftClickSelectList.Count < 1)
|
{
|
return false;
|
}
|
}
|
_lastMouseLeftClickSelectList = selectList;
|
return true;
|
}
|
}
|
}
|
if (_lastMouseLeftClickSelectList == null || _lastMouseLeftClickSelectList.Count < 1)
|
{
|
return false;
|
}
|
return true;
|
}
|
|
#endregion
|
|
#region 鼠标滚轮滚动缩放
|
|
/// <summary>
|
/// 当鼠标滚轮滚动时允许缩放
|
/// </summary>
|
[Browsable(true)]
|
[Description("当鼠标滚轮滚动时允许缩放")]
|
[DefaultValue(true)]
|
public bool AllowZoomWhenMouseWheelRoll
|
{
|
get => _allowZoomWhenMouseWheelRoll;
|
set => _allowZoomWhenMouseWheelRoll = value;
|
}
|
private bool _allowZoomWhenMouseWheelRoll = true;
|
|
/// <summary>
|
/// 当鼠标滚轮滚动时缩放
|
/// </summary>
|
protected virtual bool ZoomWhenMouseWheelRoll(MouseEventArgs e)
|
{
|
if (e.Delta != 0)
|
{
|
if (this.AllowZoomWhenMouseWheelRoll)
|
{
|
if (this.Initialized)
|
{
|
ZoomToPoint(e);
|
return true;
|
}
|
}
|
}
|
return false;
|
}
|
|
#endregion
|
|
#region 释放资源
|
|
/// <summary>
|
/// 释放资源
|
/// </summary>
|
protected virtual void DisposeResources()
|
{
|
if (_cache != null)
|
{
|
_cache.Dispose();
|
}
|
|
}
|
|
#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);
|
HasMouseRightDown(e);
|
}
|
|
/// <summary>
|
/// 鼠标移动
|
/// </summary>
|
protected override void OnMouseMove(MouseEventArgs e)
|
{
|
base.OnMouseMove(e);
|
var hoverResult = Hover(e);
|
var hasMouseLeftDownMove = MouseLeftDownMove(e);
|
var hasMouseRightDownMove = MouseRightDownMove(e);
|
if (hoverResult || hasMouseLeftDownMove || hasMouseRightDownMove)
|
{
|
this.Invalidate();
|
}
|
}
|
|
/// <summary>
|
/// 鼠标弹起
|
/// </summary>
|
protected override void OnMouseUp(MouseEventArgs e)
|
{
|
base.OnMouseUp(e);
|
var hasMouseLeftUp = HasMouseLeftUp(e);
|
var hasMouseRightUp = HasMouseRightUp(e);
|
var mouseLeftSingleClickSelectResult = SelectWhenMouseLeftSingleClick(e);
|
if (hasMouseLeftUp || hasMouseRightUp || mouseLeftSingleClickSelectResult)
|
{
|
this.Invalidate();
|
}
|
}
|
|
//鼠标滚轮滚动
|
protected override void OnMouseWheel(MouseEventArgs e)
|
{
|
base.OnMouseWheel(e);
|
var zoomWhenMouseWheelRollResult = ZoomWhenMouseWheelRoll(e);
|
if (zoomWhenMouseWheelRollResult)
|
{
|
this.Refresh();
|
}
|
}
|
|
/// <summary>
|
/// 鼠标双击
|
/// </summary>
|
protected override void OnMouseDoubleClick(MouseEventArgs e)
|
{
|
base.OnMouseDoubleClick(e);
|
var zoomAllWhenMouseLeftDoubleClickResult = ZoomAllWhenMouseLeftDoubleClick(e);
|
if (zoomAllWhenMouseLeftDoubleClickResult)
|
{
|
this.Invalidate();
|
}
|
}
|
|
}
|
}
|