[英]How make scroll follow mouse location when pictureBox is scale inside a panel windows forms c#
[英]How to scale panel in C#
我正在制作一個包含 400 多個節點的圖表並嘗試繪制它們。 節點是城市的代表,所以我把它們的經度和緯度設置為 X 和 Y。問題是這些城市來自一個縣,所以它們的經度和緯度彼此非常接近,所以即使我做了 X 和Y 大 10 倍,它們仍然彼此靠近。 唯一的事情是將“分辨率”提高到 100 倍,但隨后它們將不可見,因為值會上升到 5000px
我的問題是:我可以縮放面板以顯示所有內容,即使它有 5000 像素大? 或者也許有一種方法可以縮放經度和緯度,這樣它們的間距會更大,但仍然類似於城市的現實生活布局? 謝謝你
給定一組點,為 X 取最小值和最大值,為 Y 取最小值和最大值
var minMaxX = new PointF(
points.Min(point => point.X),
points.Max(point => point.X)
);
var minMaxY = new PointF(
points.Min(point => point.Y),
points.Max(point => point.Y)
);
接下來,您需要計算 X 和 Y 的標量值,其中寬度和高度是視口的大小。
scalarX = (minMaxX.Y - minMaxX.X) * width;
scalarY = (minMaxY.Y - minMaxY.X) * height;
然后循環遍歷每個點並將 point.x 乘以標量 x 和 point.y 乘以標量 y。
var posX = (int)(point.X * scalarX);
var posY = (int)(point.Y * scalarY);
以上沒有考慮原始點矩形的縱橫比,因此您的結果可能會被擠壓。 這可以使用信箱或柱箱解決,具體取決於點矩形與視口矩形相比的寬度/高度。
我認為這就是你想要的:
以及隨之而來的代碼。
顯示的任意城市坐標是
74.2344f, 25.3134f
41.4388f, -12.158f
58.8734f, 32.3634f
22.8486f, 7.678f
83.8304f, 12.3733f
根據Project()
方法中面板的大小將其映射為像素。
public readonly struct City
{
public City(float longitude, float latitude, float size) : this()
{
Longitude=longitude;
Latitude=latitude;
Size=size;
}
public float Longitude { get; }
public float Latitude { get; }
public float Size { get; }
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Cities = new List<City>();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
pictureBox1.Paint += (s, ev) =>
{
ev.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
using (var fill = new SolidBrush(Color.Black))
{
// Draw cities as dots of various sizes.
var cities = Cities.ToArray();
var points = Project(cities, pictureBox1, out var scale);
for (int i = 0; i < points.Length; i++)
{
float r = Math.Max(1, scale * cities[i].Size);
ev.Graphics.FillEllipse(fill, points[i].X-r, points[i].Y-r, 2*r, 2*r);
ev.Graphics.DrawString($"City {i+1}", SystemFonts.CaptionFont, Brushes.Blue, points[i].X-2*r, points[i].Y+2*r);
}
// Draw a bounding box to check math is correct.
using (var pen = new Pen(Color.LightGray,0))
{
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
var bounds = GetBounds(cities);
var box = Project(
new City[] {
new City(bounds.Left, bounds.Top,0),
new City(bounds.Right, bounds.Top,0),
new City(bounds.Right, bounds.Bottom,0),
new City(bounds.Left, bounds.Bottom,0) }, pictureBox1, out scale);
ev.Graphics.DrawPolygon(pen, box);
}
}
};
pictureBox1.Resize += (s, ev) =>
{
pictureBox1.Invalidate();
};
Cities.Add(new City(74.2344f, 25.3134f, 0.2f));
Cities.Add(new City(41.4388f, -12.158f, 0.25f));
Cities.Add(new City(58.8734f, 32.3634f, 0.12f));
Cities.Add(new City(22.8486f, 7.678f, 0.25f));
Cities.Add(new City(83.8304f, 12.3733f, 0.07f));
}
public List<City> Cities { get; }
public RectangleF GetBounds(City[] map)
{
RectangleF bounds = new RectangleF(map[0].Longitude, map[0].Latitude, 0, 0);
for (int i = 1; i < map.Length; i++)
{
bounds.X = Math.Min(bounds.X, map[i].Longitude);
bounds.Width = Math.Max(bounds.Width, map[i].Longitude-bounds.X);
bounds.Y = Math.Min(bounds.Y, map[i].Latitude);
bounds.Height = Math.Max(bounds.Height, map[i].Latitude-bounds.Y);
}
return bounds;
}
public PointF[] Project(City[] map, Control target, out float scale)
{
// Find the bounds of the map
var bounds = GetBounds(map);
// Find the scaling between pixels and map distances
int margin = 32;
int wt = target.ClientSize.Width, ht = target.ClientSize.Height;
scale = Math.Min(
(wt-2*margin)/bounds.Width,
(ht-2*margin)/bounds.Height);
// Minimum 1 pixel per unit (to avoid negative scales etc)
scale = Math.Max(1, scale);
// Convert map to pixels starting from the center
// of the target control.
PointF[] pixels = new PointF[map.Length];
for (int i = 0; i < pixels.Length; i++)
{
pixels[i] = new PointF(
wt/2 + scale * (map[i].Longitude - bounds.X - bounds.Width/2),
ht/2 - scale * (map[i].Latitude - bounds.Y - bounds.Height/2));
}
return pixels;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.