|
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);
|
}
|
|
|
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>
|
/// 初始化
|
/// </summary>
|
public virtual void Initial(Network network)
|
{
|
_network = network;
|
_networkBounds = _network.GetBounds();
|
_clientRectf = GetClientRectangleF();
|
CreateCache();
|
ZoomAll();
|
}
|
|
#endregion
|
|
#region 缓存与显示
|
|
/// <summary>
|
/// 创建缓存
|
/// </summary>
|
protected virtual void CreateCache()
|
{
|
if (!Initialized)
|
{
|
return;
|
}
|
var img = new Bitmap((int)_clientRectf.Width, (int)_clientRectf.Height);
|
img.MakeTransparent(Color.White);
|
lock (_cacheLocker)
|
{
|
if (_cache != null)
|
{
|
_cache.Dispose();
|
}
|
_cache = img;
|
}
|
}
|
|
/// <summary>
|
/// 绘制缓存
|
/// </summary>
|
protected virtual void DrawCache()
|
{
|
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(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)
|
{
|
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>
|
/// 释放资源
|
/// </summary>
|
protected virtual void DisposeResources()
|
{
|
if (_cache != null)
|
{
|
_cache.Dispose();
|
}
|
|
}
|
|
#endregion
|
|
#region 选择
|
|
/// <summary>
|
/// 选择(通过点选择)
|
/// </summary>
|
protected virtual List<Parter> Select(MouseEventArgs e)
|
{
|
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();
|
}
|
|
}
|
|
}
|
}
|