title: XAML/WPF zoom to a specific area on a canvas
body: <p>So I have a WPF window with a grid which has 2 columns. In the first column I have a canvas which I am rendering an SVG image to. This canvas is re-sized to be the same size as the image (so there are no transforms going on) and it is assumed that the image is a lot smaller than the screen so there is no need for a scroll viewer - I'll call this the left canvas.</p>
  
  <p>In the second column I have another canvas which is inside a Viewbox, the same SVG is also being rendered to this canvas and it is assumed that the SVG image size is larger than the Viewbox fixed size. The Viewbox re-sizes the canvas to fit inside it - although doesn't appear to apply any transforms to the canvas and doesn't change its width or height, some other magic goes on here - but fine, it works.</p>
  
  <p>The idea is that the user can draw a rectangle on the left canvas, which will represent a zoom area, and then the right canvas will zoom in so that rectangle will fit to the Viewbox containing the canvas - by fit I mean without cropping or stretching/squashing any of the zoom area , so if it is a landscape zoom area in a portrait Viewbox, the sides of the zoom area will meet the sides of the Viewbox leaving space at the top and bottom which is fine.</p>
  
  <p>I though this would be straight forward as there are no transforms applied to either of the canvases, and they both have the same width and height (even though some magic from the Viewbox is making the right one smaller). This is how I'm doing it at the moment:</p>
  
  <p>Find the centre point:</p>
  
  <pre><code>centreX = Canvas.GetLeft(zoomAreaRect) + (zoomAreaRect.Width / 2);
  centreY = Canvas.GetTop(zoomAreaRect) + (zoomAreaRect.Height / 2);
  </code></pre>
  
  <p>Find the scale amount:</p>
  
  <pre><code>double scale;
  
  if(zoomAreaRect.Width &gt; zoomAreaRect.Height)
  {
      scale = RightCanvas.Width / zoomAreaRect.Width;
  }
  else
  {
      scale = RightCanvas.Height / zoomAreaRect.Height;
  }
  </code></pre>
  
  <p>Then use a scale transform using centreX and centreY as the centre of the transform, and scale for both scaleX and scaleY on the transform.</p>
  
  <p>Now this clearly doesn't work because I need to somehow take into account the Viewbox size when working out the scale amount, I'm just not sure how to do this. Can anyone help please?</p>
  
  <p><strong>Update:</strong></p>
  
  <p>I have scrapped the Viewbox as this complicates things.. so the right canvas is just normal size too but is contained inside a border with fixed width and height. The aim is to zoom in on the zoom area until it fits to the border.</p>
  
  <p>Here is the XAML for the right side:</p>
  
  <pre><code>&lt;Border Name="ContainingBorder" 
                Grid.Column="1"
                MaxWidth="295"
                MaxHeight="487"
                Height="487"&gt;
      &lt;Border.Clip&gt;
          &lt;RectangleGeometry Rect="0.5, 0.5, 295, 487"/&gt;
      &lt;/Border.Clip&gt;
  
      &lt;Canvas Name="RightCanvas"/&gt;
  &lt;/Border&gt;
  </code></pre>
  
  <p>I have managed to zoom in the correct amount, it just doesn't zoom into the right centre. I just use the aspect ratio as the scale amount which appears to work:</p>
  
  <pre><code>double ratioX = ContainingBorder.AcctualWidth / zoomAreaRect.Width;
  double ratioY = ContainingBorder.AcctualHeight / zoomAreaRect.Height;
  
  double scale = ratioX &lt; ratioY ? ratioX : ratioY;
  </code></pre>
  
  <p>Any ideas how I can figure out the centre x and y? The above centreX and centreY calculations don't appear to work properly.</p>