wpf 将画布缩放到鼠标位置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22349953/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 11:12:29  来源:igfitidea点击:

Scale canvas to mouse position

c#wpf

提问by Eggi

I am trying to implement a zoom-functionality for a canvas using the mouse wheel. Currently I am just Zooming to the center position of the canvas using CenterX="0.5" and CenterY="0.5". I would like to change the behavior so that the zooming happens at the mouse position and I would like to know if this is possible with a ScaleTransform.

我正在尝试使用鼠标滚轮为画布实现缩放功能。目前我只是使用 CenterX="0.5" 和 CenterY="0.5" 缩放到画布的中心位置。我想更改行为,以便缩放发生在鼠标位置,我想知道这是否可以使用 ScaleTransform。

Currently I use the following code:

目前我使用以下代码:

<Canvas Width="500" Height="500">
    <Canvas.LayoutTransform>
        <ScaleTransform CenterX="0.5" CenterY="0.5"
                                ScaleX="{Binding Zoom}"
                                ScaleY="{Binding Zoom}" />
    </Canvas.LayoutTransform>
</Canvas>

回答by Clemens

A very basic approach to zoom a Canvas (or any other UIElement) at a specific position would be to use a MatrixTransform for the RenderTransformproperty

在特定位置缩放 Canvas(或任何其他 UIElement)的一种非常基本的方法是对RenderTransform属性使用 MatrixTransform

<Canvas Width="500" Height="500" MouseWheel="Canvas_MouseWheel">
    <Canvas.RenderTransform>
        <MatrixTransform/>
    </Canvas.RenderTransform>
</Canvas>

and update the Matrixproperty of the transform like in this MouseWheel handler:

Matrix像在此 MouseWheel 处理程序中一样更新变换的属性:

private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
    var element = sender as UIElement;
    var position = e.GetPosition(element);
    var transform = element.RenderTransform as MatrixTransform;
    var matrix = transform.Matrix;
    var scale = e.Delta >= 0 ? 1.1 : (1.0 / 1.1); // choose appropriate scaling factor

    matrix.ScaleAtPrepend(scale, scale, position.X, position.Y);
    transform.Matrix = matrix;
}

回答by NWoodsman

I spent the past two days agonizing over this issue and I figured it out. This will get you smooth zooming in toward the mouse and smooth zooming out. I'm posting my solution here for anyone who might search and stumble back here.

这两天一直在纠结这个问题,终于搞明白了。这将使您平滑地向鼠标放大和平滑地缩小。我在这里发布我的解决方案,供任何可能搜索和绊倒在这里的人使用。

// Class constructor
public YourClass(Canvas theCanvas) //You may not need the Canvas as an argument depending on your scope
    {
        panTransform = new TranslateTransform();
        zoomTransform = new ScaleTransform();
        bothTransforms = new TransformGroup();

        bothTransforms.Children.Add(panTransform);
        bothTransforms.Children.Add(zoomTransform);

        theCanvas.RenderTransform = bothTransforms;

        //Handler
        theCanvas.MouseWheel += wheelEvent;
        //You also need your own handlers for panning, which I'm not showing here.
    }

private void returnCalculatedScale()
    {
        double d;
        //Do some math to get a new scale. I keep track of an integer, and run it through the formula y^(x/3) where X is the integer.

        return d;
    }


// Mouse wheel handler, where the magic happens
private void wheelEvent(object sender, MouseWheelEventArgs e)
    {
        Point position = e.GetPosition(mainCanvas);           

        zoomTransform.CenterX = position.X;
        zoomTransform.CenterY = position.Y;

        zoomTransform.ScaleX = returnCalculatedScale();
        zoomTransform.ScaleY = returnCalculatedScale();

        Point cursorpos = Mouse.GetPosition(mainCanvas); //This was the secret, as the mouse position gets out of whack when the transform occurs, but Mouse.GetPosition lets us get the point accurate to the transformed canvas.

        double discrepancyX = cursorpos.X - position.X;
        double discrepancyY = cursorpos.Y - position.Y;

        //If your canvas is already panned an arbitrary amount, this aggregates the discrepancy to the TranslateTransform.
        panTransform.X += discrepancyX;
        panTransform.Y += discrepancyY;