简体   繁体   English

C# 如何使用 SkiaSharp 控件缩放到光标位置?

[英]C# How to zoom to cursor location using SkiaSharp control?

I have a 2D map I want to zoom in to based on the cursor X and Y coordinates.我有一个 2D 地图,我想根据光标 X 和 Y 坐标放大。 Currently I have some working code, but if I move the cursor to a new position after an initial zoom the next zoom is slightly off.目前我有一些工作代码,但是如果我在初始缩放后将光标移动到新位置,则下一个缩放会稍微关闭。 I've been trying to figure this out for a while but I can't get my head around the math.我一直试图弄清楚这一点,但我无法解决数学问题。 Its probably something simple I just can't visualize the right way to do this.它可能很简单,我只是无法想象正确的方法来做到这一点。

Sample code.示例代码。

    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);
        }          
    }

This is what I came up with if anyone has a similar problem.如果有人有类似的问题,这就是我想出的。

    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);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM