c# - C# 如何使用 SkiaSharp 控件缩放到光标位置?
问题描述
我有一个要根据光标 X 和 Y 坐标放大的 2D 地图。目前我有一些工作代码,但如果我在初始缩放后将光标移动到新位置,下一次缩放会稍微关闭。我一直试图弄清楚这一点,但我无法理解数学。它可能很简单,我只是无法想象正确的方法来做到这一点。
示例代码。
float ZoomMax = 7f;
float ZoomMin = 1f;
private float[] MapPan = new float[] { 0, 0 };
private float MapScale = 1f;
protected override void OnMouseWheel(MouseEventArgs e)
{
var coordinates = panelMap.PointToClient(Cursor.Position);
if (e.Delta > 0)
{
if (MapScale < ZoomMax)
{
MapScale += 0.2f;
ZoomToMouse(coordinates.X, coordinates.Y);
}
else
{
MapScale = ZoomMax;
}
}
else if (e.Delta < 0)
{
if (MapScale > ZoomMin)
{
MapScale -= 0.2f;
ZoomToMouse(coordinates.X, coordinates.Y);
}
else
{
MapPan[0] = 0;
MapPan[1] = 0;
MapScale = ZoomMin;
}
}
}
private void ZoomToMouse(int x, int y)
{
float xScaled = x * MapScale;
float xScaled = y * MapScale;
float X = x - xScaled;
float Y = y - yScaled;
MapPan[0] = X / MapScale;
MapPan[1] = Y / MapScale;
}
private void map_PaintSurface(object sender, SKPaintGLSurfaceEventArgs e)
{
SKCanvas skCanvas = e.Surface.Canvas;
skCanvas.Scale(MapScale);
skCanvas.Translate(MapPan[0], MapPan[1]);
using(SKPaint skPaint = new SKPaint())
{
skCanvas.DrawText("Hello", 0, 0, skPaint);
}
}
解决方案
如果有人有类似的问题,这就是我想出的。
private float ZoomMax = 7f;
private float ZoomMin = 1f;
private PointF MapPan = new PointF(0, 0);
private float MapScale = 1f;
protected override void OnMouseWheel(MouseEventArgs e)
{
if (FindControlAtCursor(this) != map) { return; }
var coordinates = map.PointToClient(Cursor.Position);
float ScrollDelta = e.Delta * 0.002f;
float prevScale = MapScale;
MapScale = Clamp(MapScale + ScrollDelta,ZoomMin,ZoomMax);
ZoomToMouse(coordinates, prevScale);
}
public static Control FindControlAtCursor(Form form)
{
Point pos = Cursor.Position;
if (form.Bounds.Contains(pos))
return FindControlAtPoint(form, form.PointToClient(pos));
return null;
}
public static float Clamp(float value, float min, float max)
{
return (value < min) ? min : (value > max) ? max : value;
}
private void ZoomToMouse(PointF Mouse, float PreviousScale)
{
PointF TranslatedMouse = new PointF((Mouse.X / PreviousScale) - MapPan.X, (Mouse.Y / PreviousScale) - MapPan.Y);
PointF ScaledMouse = new PointF(TranslatedMouse.X * MapScale, TranslatedMouse.Y * MapScale);
PointF NewPosition = new PointF((Mouse.X - ScaledMouse.X) / MapScale, (Mouse.Y - ScaledMouse.Y) / MapScale);
float currentWidth = map.Width * MapScale;
float currentHeight = map.Height * MapScale;
float diffX = (currentWidth - map.Width) / MapScale;
float diffY = (currentHeight - map.Height) / MapScale;
MapPan.X = Clamp(NewPosition.X, -diffX, 0);
MapPan.Y = Clamp(NewPosition.Y, -diffY, 0);
}
private void map_PaintSurface(object sender, SKPaintGLSurfaceEventArgs e)
{
SKCanvas skCanvas = e.Surface.Canvas;
skCanvas.Scale(MapScale);
skCanvas.Translate(MapPan.X, MapPan.Y);
using (SKPaint skPaint = new SKPaint())
{
skCanvas.DrawText("Hello", 0, 0, skPaint);
}
}
推荐阅读
- https - htaccess - 使用查询重定向到 https
- angular - 如何解决此错误“错误类型错误:无法删除 [object Array] 的属性 '0'”
- java - 在回收站视图 Android 中禁用滚动后移至下一项
- flutter - SliverList SliverChildBuilderDelegate 中的 ListView.builder 在首次加载时不呈现图像
- c# - 将字符串从 E 表示法转换为“百万、十亿、万亿等)
- reactjs - antd design - 生产构建问题
- java - 如何在 Spring Boot 中使用 WebClient 使用二进制和字符串响应?
- flutter - 如何使“compute()”函数在隔离过程中向sqlite插入数据?
- angular - 我想在谷歌地图中添加路线图
- javascript - 尝试使用 html2canvas 拍摄图像来创建一个可拖动的 div 缩放...缩放有问题