Jerrin George Mathew Jerrin George Mathew - 2 months ago 20
C# Question

c# Canvas Zoom Functionality issue ?Not able to zoom out to original postion after zooming in to a point using matrix transform

I'm trying to implement a canvas zoom functionality in c# using matrix transform. I'm able to zoom in to one particular point, but while zooming out to the original scale(i've limited to original scale) the position of the canvas changes(out of the window) . I would like it to zoom out to its original position. Can anyone help?

Please find the code below:

<ScrollViewer Name="C1_S" Grid.Row="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" VerticalAlignment="Bottom" Grid.ColumnSpan="2" >
<Canvas Name="canvas_core0" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Height="600" Width="1000000" MouseWheel="Canvas_MouseWheel" ClipToBounds="True" >
<Canvas.Background>
<DrawingBrush TileMode="Tile" Viewport="0,20,40,40" ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,50,50"/>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Brush="Gray" Thickness=".1"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Canvas.Background>
<Canvas.RenderTransform>
<MatrixTransform/>
</Canvas.RenderTransform>
</Canvas>
</ScrollViewer>


C# Code:`

private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
var element = sender as UIElement;
var position = e.GetPosition(element);
if(e.Delta>0)
{
previousposition = position;
}
var transform = element.RenderTransform as MatrixTransform;
var matrix = transform.Matrix;
scrollcountprevious = scrollcountcurrent;
scrollcountcurrent = scrollcountcurrent + e.Delta;
// var scale1 = scrollcountcurrent > scrollcountprevious ? 1.1 : scrollcountcurrent <scrollcountprevious0 ? 1.0 : (1.0 / 1.1); // choose appropriate scaling factor
var scale1=1.0;
if (scrollcountcurrent > scrollcountprevious)
{
scale1 = 1.1;
matrix.ScaleAtPrepend(scale1, scale1, position.X, position.Y);
transform.Matrix = matrix;
}
else if (scrollcountcurrent < scrollcountprevious&&scrollcountcurrent>=0)
{
scale1 = 1 / 1.1;
matrix.ScaleAtPrepend(scale1, scale1, previousposition.X, previousposition.Y);
transform.Matrix = matrix;

}
else
{
scale1 = 1;
scrollcountcurrent = 0;
matrix.ScaleAtPrepend(scale1, scale1, previousposition.X, previousposition.Y);
transform.Matrix = matrix;
}

}

Answer

Not sure if I understand what you're exactly trying to achieve. Also, having the Canvas in a ScrollViewer might mess things up.

But probably this MouseWheel handler does what you want:

private double scale = 1;

private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
    var element = (UIElement)sender;
    var position = e.GetPosition(element);
    var matrix = Matrix.Identity;

    scale = Math.Max(e.Delta > 0 ? scale * 1.1 : scale / 1.1, 1.0);
    matrix.ScaleAt(scale, scale, position.X, position.Y);

    ((MatrixTransform)element.RenderTransform).Matrix = matrix;
}

In order to also scale the actual size of the Canvas in the ScrollViewer, scale its LayoutTransform instead of the RenderTransform:

<Canvas.LayoutTransform>
    <MatrixTransform/>
</Canvas.LayoutTransform>

private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
    var element = (FrameworkElement)sender;
    var position = e.GetPosition(element);
    var matrix = Matrix.Identity;

    scale = Math.Max(e.Delta > 0 ? scale * 1.1 : scale / 1.1, 1.0);
    matrix.ScaleAt(scale, scale, position.X, position.Y);

    ((MatrixTransform)element.LayoutTransform).Matrix = matrix;
}
Comments