using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Windows.Forms; namespace CloudWaterNetwork { partial class MapControl : Control { private Point backgroundImageOffset = Point.Empty; // 背景图偏移量 private Image backgroundImage; // 背景图片 private RectangleF chartArea; // 直角坐标系范围 private PointF origin; // 坐标轴原点 private float zoomLevel = 1f; // 缩放级别 private bool isPanning = false; // 是否正在平移 private Point lastMousePosition = Point.Empty; // 上一次鼠标位置 private bool isSelecting = false; // 是否正在框选矩形 private RectangleF selectionRect; // 框选矩形 public MapControl() { this.DoubleBuffered = true; } public Image BackgroundImage { get { return this.backgroundImage; } set { this.backgroundImage = value; this.Invalidate(); } } protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); if (e.Button == MouseButtons.Middle) { // 启动平移模式 this.isPanning = true; this.lastMousePosition = e.Location; } else if (e.Button == MouseButtons.Left) { // 启动框选矩形模式 this.isSelecting = true; this.selectionRect = new RectangleF(e.Location, SizeF.Empty); } } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (this.isPanning) { // 平移坐标系范围和背景图片 int dx = e.X - this.lastMousePosition.X; int dy = e.Y - this.lastMousePosition.Y; this.backgroundImageOffset.Offset(dx, dy); this.chartArea.Offset(dx / this.zoomLevel, -dy / this.zoomLevel); this.origin.X += dx; this.origin.Y += dy; //Offset(dx, dy); this.lastMousePosition = e.Location; this.Invalidate(); } else if (this.isSelecting) { // 更新框选矩形范围 this.selectionRect.Width = e.X - this.selectionRect.Left; this.selectionRect.Height = e.Y - this.selectionRect.Top; this.Invalidate(); } } protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); if (this.isPanning) { // 停止平移模式 this.isPanning = false; } else if (this.isSelecting) { // 停止框选矩形模式,并重新计算坐标系范围和原点位置 this.isSelecting = false; float x1 = (this.selectionRect.Left - this.origin.X) * (this.chartArea.Width / this.ClientSize.Width) + this.chartArea.Left; float y1 = (this.ClientSize.Height - this.selectionRect.Bottom + this.origin.Y) * (this.chartArea.Height / this.ClientSize.Height) + this.chartArea.Top; float x2 = (this.selectionRect.Right - this.origin.X) * (this.chartArea.Width / this.ClientSize.Width) + this.chartArea.Left; float y2 = (this.ClientSize.Height - this.selectionRect.Top + this.origin.Y) * (this.chartArea.Height / this.ClientSize.Height) + this.chartArea.Top; this.chartArea = new RectangleF(x1, y1, x2 - x1, y2 - y1); this.origin = new PointF(this.chartArea.Left, this.chartArea.Bottom); this.Invalidate(); } } protected override void OnMouseWheel(MouseEventArgs e) { base.OnMouseWheel(e); // 缩放坐标系范围和背景图片 float factor = e.Delta > 0 ? 1.1f : 0.9f; float oldZoomLevel = this.zoomLevel; this.zoomLevel *= factor; if (this.zoomLevel < 0.1f) { this.zoomLevel = 0.1f; } if (this.zoomLevel > 10f) { this.zoomLevel = 10f; } float dx = (this.chartArea.Width / oldZoomLevel - this.chartArea.Width / this.zoomLevel) / 2; float dy = (this.chartArea.Height / oldZoomLevel - this.chartArea.Height / this.zoomLevel) / 2; this.backgroundImageOffset.Offset((int)(e.Location.X * dx), (int)(e.Location.Y * dy)); this.chartArea.Inflate(dx, dy); this.origin = new PointF(this.chartArea.Left, this.chartArea.Bottom); this.Invalidate(); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); // 绘制背景图片 if (this.backgroundImage != null) { e.Graphics.DrawImage(this.backgroundImage, this.backgroundImageOffset); } // 绘制直角坐标系和矩形 using (Pen axisPen = new Pen(Color.Black, 2)) { e.Graphics.DrawLine(axisPen, this.origin.X, this.origin.Y, this.origin.X + this.chartArea.Width / this.zoomLevel, this.origin.Y); // X轴 e.Graphics.DrawLine(axisPen, this.origin.X, this.origin.Y, this.origin.X, this.origin.Y - this.chartArea.Height / this.zoomLevel); // Y轴 if (this.isSelecting) { // 绘制框选矩形 using (Pen selectionPen = new Pen(Color.Red, 2)) { selectionPen.DashStyle = DashStyle.Dot; e.Graphics.DrawRectangle(selectionPen, Rectangle.Round(this.selectionRect)); } } } } protected override void OnResize(EventArgs e) { base.OnResize(e); // 初始化坐标系范围和原点位置 float widthRatio = (float)this.ClientSize.Width / this.chartArea.Width; float heightRatio = (float)this.ClientSize.Height / this.chartArea.Height; float zoomRatio = Math.Min(widthRatio, heightRatio); this.chartArea = new RectangleF(0, 0, this.ClientSize.Width / zoomRatio, this.ClientSize.Height / zoomRatio); this.origin = new PointF(this.chartArea.Left, this.chartArea.Bottom); this.Invalidate(); } } }