Pan and Zoom in WPF

DeepZoom is a cool feature of Silverlight 2.0 allowing the user to zoom and pan around an image, while optimizing the bandwidth and how much of the image is downloaded.  The UI metaphor is potentially quite powerful – even outside of image viewing.  Take WPF, with its scalable vector content, panning and zooming around ad-hoc rendered content could have several uses – even without the dynamic image loading.

This quick post details how to achieve this is WPF with a simple ContentControl.  It borrows some functionality from Jaime Rodriguez’s excellent DeepZoom Primer.

The entire pan and zoom functionality can be achieved by a single transform group.  I use a class derived from a content control with two transforms, a scale transform for zooming and a TranslateTransform for panning.  This transform group will then pan and zoom the content of the content control (much like the scroll viewer).  The initialization is done in code:

     this.source = VisualTreeHelper.GetChild(this, 0) as FrameworkElement;
      this.translateTransform = new TranslateTransform();
      this.zoomTransform = new ScaleTransform();
      this.transformGroup = new TransformGroup();
      this.transformGroup.Children.Add(this.zoomTransform);
      this.transformGroup.Children.Add(this.translateTransform);
      this.source.RenderTransform = this.transformGroup;

The DoZoom function modifies these transforms based on the parameters sent.  This is similar to Jaime’s DoZoom function:

 /// <summary>Zoom into or out of the content.</summary>
 /// <param name="deltaZoom">Factor to mutliply the zoom level by. </param>
 /// <param name="mousePosition">Logical mouse position relative to the
 /// original content.</param>
 /// <param name="physicalPosition">Actual mouse position on the screen
 /// (relative to the parent window)</param>
 public void DoZoom(double deltaZoom, Point mousePosition, Point physicalPosition)
 {
   double currentZoom = this.zoomTransform.ScaleX;
   currentZoom *= deltaZoom;
   this.translateTransform.BeginAnimation(TranslateTransform.XProperty,
        CreateZoomAnimation(-1 * (mousePosition.X * currentZoom - physicalPosition.X)));
   this.translateTransform.BeginAnimation(TranslateTransform.YProperty,
        CreateZoomAnimation(-1 * (mousePosition.Y * currentZoom - physicalPosition.Y)));
   this.zoomTransform.BeginAnimation(ScaleTransform.ScaleXProperty,
        CreateZoomAnimation(currentZoom));
   this.zoomTransform.BeginAnimation(ScaleTransform.ScaleYProperty,
        CreateZoomAnimation(currentZoom));
}

The rest of the code simply hooks up the mouse events to the DoZoom function.  This is all self contained within the ContentControl, so using this Pan And Zoom functionality is simply a matter of adding the control and filling in the content.

It’s still missing some functionality, like the navigation overlay.  It would also be nice to add events for the zoom detail so you could adjust detail of the rendered content based on the zoom level.

Source code can be found here

Updated this post and source code link here: http://blogs.windowsclient.net/joeyw/archive/2009/06/02/pan-and-zoom-updated.aspx

About these ads

2 Comments on “Pan and Zoom in WPF”

  1. Ming Huang says:

    The links to source code are broken. Could you please update the links?

    Thanks a lot,
    Ming Huang

  2. Stone says:

    Thanks for this good post :-( …but the link to your source-code is broken… – maybe you can fix this?

    Stone


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.