Zoom on a graph in WPF and C#


example

It’s remarkably easy to zoom on a graph in WPF. This example extends the example Let the user click on graph points in WPF and C#.

To modify the previous version, you first need to rebuild the user interface a bit. The following code shows the new XAML code. The most interesting changes are highlighted in blue.

<Window x:Class="howto_wpf_scaled_graph.Window1"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="howto_wpf_scaled_graph"
   Height="300" Width="480" Loaded="Window_Loaded">
   <Grid Background="LightGreen">
      <Grid.RowDefinitions>
         <RowDefinition Height="30"/>
         <RowDefinition Height="*"/>
      </Grid.RowDefinitions>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="50"/>
         <ColumnDefinition Width="*"/>
      </Grid.ColumnDefinitions>

      <Label Name="lblZoom" Content="100%"
         HorizontalAlignment="Center"
         VerticalAlignment="Center"
         Grid.Row="0" Grid.Column="0"/>
      <Slider Name="sliZoom" Orientation="Vertical"
         ValueChanged="sliZoom_ValueChanged"
         HorizontalAlignment="Center"
         Margin="0,0,0,5"
         Grid.Row="1" Grid.Column="0"
         Minimum="25" Maximum="200" Value="100"
         SmallChange="25" LargeChange="25"
         TickFrequency="25" TickPlacement="BottomRight"
         IsSnapToTickEnabled="True"/>

      <ScrollViewer Name="scvGraph"
         Grid.Row="0" Grid.Column="1" Grid.RowSpan="2"
         HorizontalScrollBarVisibility="Auto"
         VerticalScrollBarVisibility="Auto">
         <Canvas Name="canGraph" Background="White"
            MouseMove="canGraph_MouseMove"
            MouseUp="canGraph_MouseUp"
            Width="400" Height="250"
            VerticalAlignment="Center"
            HorizontalAlignment="Center"/>
      </ScrollViewer>
   </Grid>
</Window>

The Slider lets you manage the zoom factor. Its properties let you select multiples of 25 between 25 and 200 (to represent a zoom factor of 25% to 200%).

The IsSnapToTickEnabled property is particularly important. Because this property is set to True, the control only selects values at its tic marks. In this case, that means you can select only multiples of 25 and not values such as 30, 110, or 79.45.

The second change is the addition of a ScrollViewer control containing the Canvas control. A ScrollViewer can automatically display scroll bars if its contents won’t fit inside it. In this example, the ScrollViewer displays scroll bars if the zoom factor makes the Canvas too big to fit.

The revised user interface also contains a couple of Label controls and its Grid uses some new rows and columns to arrange everything nicely. Study the XAML code shown above to understand the details.

The only change to the code is the addition of the following Slider control’s ValueChanged event handler.

// Zoom.
private double Zoom = 1;
private void sliZoom_ValueChanged(object sender,
    RoutedPropertyChangedEventArgs<double> e)
{
   // Make sure the control's are all ready.
   if (!IsInitialized) return;

   // Display the zoom factor as a percentage.
   lblZoom.Content = sliZoom.Value + "%";

   // Get the scale factor as a fraction 0.25 - 2.00.
   double scale = (double)(sliZoom.Value / 100.0);

   // Scale the graph.
   canGraph.LayoutTransform = new ScaleTransform(scale, scale);
}

First the code checks IsInitialized. If this value is false, some of the controls may not have been created yet, so the method exits.

If the controls have all been created, the program displays the Slider control’s value followed by a % symbol in the Label lblZoom.

Next the code gets the Slider control’s value and divides it by 100 to get a scale factor between 0.25 and 2.00. It creates a ScaleTransform that scales by that amount, and sets the Canvas control’s LayoutTransform to the ScaleTransform to scale it.

That’s all there is to it. The LayoutTransform scales the Canvas, and the ScrollViewer displays scroll bars if necessary.


Note that the previous example’s code lets you click on points to see their values. It searches for the data points in device coordinates. The means the mouse needs to be within 3 pixels of a data point to select it even if you zoom in on the graph. I decided that was reasonable because you should be able to control the mouse with the same device coordinate precision at any scale. This could be a problem if you zoom out so the graph is really tiny so more than one point fits within a 3 pixel area, but the graph isn’t very useful at that scale and you won’t be able to read the label giving the point’s values anyway.

If you don’t like this behavior, you can modify the program to search for points in world coordinates instead of device coordinates. Then the area you need to click to select a point changes size when you zoom.


You can actually display the zoom factor and scale the Canvas control by using only XAML code. It’s fairly complicated and confusing, and only saves you three lines of C# code. Still it’s interesting. It also shows how you can bind one control’s values to another control’s values, so it’s worth learning. I’ll show how to do it that way in my next post.


Download Example   Follow me on Twitter   RSS feed




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in algorithms, drawing, geometry, graphics, mathematics and tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

2 Responses to Zoom on a graph in WPF and C#

  1. Pingback: Zoom on a graph with XAML code in C# -

  2. Shalene says:

    Thank you. This worked brilliantly for me.
    Exactly what I was looking for and super easy to implement.
    I just had one little hitch – my canvas was already in a scrollviewer and a viewbox, so had to set a maximum width on the scrollviewer.

Leave a Reply

Your email address will not be published. Required fields are marked *