放大画布,以鼠标位置为中心

时间:2018-11-03 05:01:36

标签: c# wpf canvas zoom mouse

我知道堆栈和其他网站上有几篇文章,但看来我还是做错了什么。当我使用MouseWheel事件进行缩放时,缩放始终不会居中,但画布的左侧始终位于ViewBox的左侧,因此当我放大时,只能看到画布的左侧。

XAML代码:

<Grid x:Name="MainGrid">
        <Viewbox x:Name="ViewBoxDessin" Stretch="None" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Canvas  x:Name="monDessin" Background="WhiteSmoke" MouseWheel="monDessin_MouseWheel">
                <Canvas.LayoutTransform>
                    <ScaleTransform x:Name="st" ScaleX="1" ScaleY="-1" CenterX=".5" CenterY=".5" />
                </Canvas.LayoutTransform>
            </Canvas>
        </Viewbox>
        <Viewbox x:Name="ViewBoxDessin2" Stretch="None">
            <Canvas x:Name="monDessin2">
                <Canvas.LayoutTransform>
                    <ScaleTransform x:Name="st2" ScaleX="1" ScaleY="1" CenterX=".5" CenterY=".5" />
                </Canvas.LayoutTransform>
            </Canvas>
        </Viewbox>
    </Grid>

后面的代码

public AfficheGraphiquePiece()
        {
            InitializeComponent();
            MakeMyDrawing();
            ViewBoxDessin.Width = System.Windows.SystemParameters.PrimaryScreenWidth;
            ViewBoxDessin.Height = System.Windows.SystemParameters.PrimaryScreenHeight;

            double ech_x = monDessin.Width / System.Windows.SystemParameters.PrimaryScreenWidth;
            double ech_y = monDessin.Height / System.Windows.SystemParameters.PrimaryScreenHeight;
            double ech = Math.Min(ech_x, ech_y);
            this.ech_full = ech;
            st.ScaleX = ech;
            st.ScaleY = -ech;
            st2.ScaleX = ech;
            st2.ScaleY = ech;
        }
        private void monDessin_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            double zoom = e.Delta > 0 ? 1.1 : 0.9;
            if(st.ScaleX<this.ech_full*1.1 && zoom<1)
            {
                st.ScaleX = this.ech_full;
                st.ScaleY = -this.ech_full;
            }
            else
            {
                st.ScaleX *= zoom;
                st.ScaleY *= zoom;
                double coor_x = Mouse.GetPosition(monDessin).X;
                double coor_y = Mouse.GetPosition(monDessin).Y;
                st.CenterX = coor_x;
                st.CenterY = coor_y;

            }

        }

对不起,没有删除一些代码,这可能会造成混乱,只需将其替换为函数MakeMyDrawing()

好吧,在克莱门斯(Clemens)建议之后,并借助link进行矩阵使用,我可以执行以下操作:

XAML:

<Grid x:Name="MainGrid">
        <Canvas  x:Name="monDessin" Background="WhiteSmoke" MouseWheel="monDessin_MouseWheel" MouseLeftButtonDown="image_MouseLeftButtonDown" MouseMove="image_MouseMove" MouseLeftButtonUp="image_MouseLeftButtonUp" MouseLeave="image_MouseLeave" >
            <Canvas.RenderTransform >
                <MatrixTransform/>
            </Canvas.RenderTransform>
        </Canvas>
        <Canvas x:Name="monDessin2">
            <Canvas.RenderTransform >
                <MatrixTransform/>
            </Canvas.RenderTransform>
        </Canvas>
    </Grid>

后面的代码

public AfficheGraphiquePiece(Repere rep)
        {
            InitializeComponent();
            ClassGraphique monGraphe = new ClassGraphique(monDessin);
            ClassGraphique monGraphe2 = new ClassGraphique(monDessin2);
            MakeMyDrawing();
            double screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
            double screenHeight = System.Windows.SystemParameters.PrimaryScreenHeight;

            double ech_x = screenWidth/ monDessin.Width ;
            double ech_y = screenHeight/ monDessin.Height;
            double ech = Math.Min(ech_x, ech_y)*0.9;
            this.ech_full = ech;
            this.echelleNow = this.ech_full;
            MatrixTransform maTrans =(MatrixTransform)monDessin.RenderTransform;
            var mat = maTrans.Matrix;
            mat.ScaleAt(ech, -ech, 0.1* screenWidth, (screenHeight-monDessin.Height*ech)/2-0.1*screenHeight);
            MatrixTransform maTrans2 = (MatrixTransform)monDessin2.RenderTransform;
            var mat2 = maTrans2.Matrix;
            mat2.ScaleAt(ech, ech, 0.1 * screenWidth, screenHeight*ech-((screenHeight - monDessin.Height * ech) / 2 - 0.1 * screenHeight));
            maTrans.Matrix = mat;
            maTrans2.Matrix = mat2;
        }
        private void monDessin_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            try
            {
                var position = e.GetPosition(monDessin);
                MatrixTransform transform = (MatrixTransform)monDessin.RenderTransform;
                MatrixTransform transform2 = (MatrixTransform)monDessin2.RenderTransform;
                var matrix = transform.Matrix;
                var matrix2 = transform2.Matrix;
                var scale = e.Delta >= 0 ? 1.1 : (1.0 / 1.1); 
                this.echelleNow *= scale;
                matrix.ScaleAtPrepend(scale, scale, position.X, position.Y);
                matrix2.ScaleAtPrepend(scale, scale, position.X,monDessin.Height-position.Y);
                monDessin.RenderTransform = new MatrixTransform(matrix);
                monDessin2.RenderTransform = new MatrixTransform(matrix2);
            }
            catch { }
        }

1 个答案:

答案 0 :(得分:1)

这是一个非常基本的示例,用于缩放和平移具有固定初始大小的Canvas。内部Canvas的RenderTransform中的MatrixTransform提供了必要的转换,而外部Canvas处理鼠标输入并设置初始缩放。

<Canvas Background="Transparent"
        SizeChanged="ViewportSizeChanged"
        MouseLeftButtonDown="ViewportMouseLeftButtonDown"
        MouseLeftButtonUp="ViewportMouseLeftButtonUp"
        MouseMove="ViewportMouseMove"
        MouseWheel="ViewportMouseWheel">

    <Canvas x:Name="canvas" Width="1000" Height="600">
        <Canvas.RenderTransform>
            <MatrixTransform x:Name="transform"/>
        </Canvas.RenderTransform>

        <Ellipse Fill="Red" Width="100" Height="100" Canvas.Left="100" Canvas.Top="100"/>
        <Ellipse Fill="Green" Width="100" Height="100" Canvas.Right="100" Canvas.Bottom="100"/>
    </Canvas>
</Canvas>

后面的代码:

private Point? mousePos;

private void ViewportSizeChanged(object sender, SizeChangedEventArgs e)
{
    ((MatrixTransform)canvas.RenderTransform).Matrix = new Matrix(
        e.NewSize.Width / canvas.ActualWidth,
        0, 0,
        e.NewSize.Height / canvas.ActualHeight,
        0, 0);
}

private void ViewportMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var viewport = (UIElement)sender;
    viewport.CaptureMouse();
    mousePos = e.GetPosition(viewport);
}

private void ViewportMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    ((UIElement)sender).ReleaseMouseCapture();
    mousePos = null;
}

private void ViewportMouseMove(object sender, MouseEventArgs e)
{
    if (mousePos.HasValue)
    {
        var pos = e.GetPosition((UIElement)sender);
        var matrix = transform.Matrix;
        matrix.Translate(pos.X - mousePos.Value.X, pos.Y - mousePos.Value.Y);
        transform.Matrix = matrix;
        mousePos = pos;
    }
}

private void ViewportMouseWheel(object sender, MouseWheelEventArgs e)
{
    var pos = e.GetPosition((UIElement)sender);
    var matrix = transform.Matrix;
    var scale = e.Delta > 0 ? 1.1 : 1 / 1.1;
    matrix.ScaleAt(scale, scale, pos.X, pos.Y);
    transform.Matrix = matrix;
}