title: Dynamically scaling canvas in WPF by setting in- and outpoints
body: <p>I'm working on plotting program in WPF using the canvas element. What I want to achieve is a scrollbar with draggable endpoints. Example of these kinds of scrollbars are in the After Effects video editing software by Adobe.</p>
  
  <p>Basic functionality of such a scrollbar is that it is able to scroll trough content that is bigger then it's container, but both the left and right endpoint can be dragged to dynamically change the scale of the content. </p>
  
  <p>I have implemented a similar scrollbar in the plotting program; users should be able to drag around the in and outpoint (Rectangles in a canvas), and the plot canvas should respond to this by scaling to the desired range.
  Information I need for this:</p>
  
  <ul>
  <li>Width of the total plot (amount of plotpoints)</li>
  <li>Width of the container (static, 600px)</li>
  <li>Percentage of the in and out points relative to the total width of the scrollbar canvas</li>
  </ul>
  
  <p><a href="http://i.imgur.com/56mjG.png" rel="nofollow">Link to current screenshot</a></p>
  
  <p>With this information I have created a MatrixTransform, using the ScaleAt() method to scale the plot canvas inside the container so that it matches the in and outpoints in the scrollbar below. For this I used the following code. resetTransform gets called <em>FPS</em> times a second to keep up with the incoming data and XMAX and YMAX are updated elsewhere to reflect this.
  </p>
  
  <pre><code>public void resetTransform(Boolean useSlider = false)
  {
      //Add transformgroup to plot
      double yscale = plot.Height / view.YMAX; //YMAX is maximum plot value received
      double xscale = plot.Width / view.XMAX; //XMAX is total ammount of plotted points
      Matrix m = new Matrix(1, 0, 0, 1, 0, 0);
      if (useSlider)
      {
          double maxVal = zoomBar.ActualWidth - outPoint.Width;
          double outP = Canvas.GetLeft(outPoint); //points position relative to the scrollbar
          double inP = Canvas.GetLeft(inPoint);
          double center = (((outP + inP) / 2) / maxVal) * plot.ActualWidth;
          double delta = (outP-inP);
          double factor = (maxVal/delta) * xscale;
          double mappedinP = (inP / maxVal) * view.XMAX;
  
          double anchorOut = (outP / maxVal) * view.XMAX;
          double anchorIn = (inP / maxVal) * view.XMAX;
  
          m.ScaleAt(factor, -yscale,center,0); //scale around the center point, 
          m.Translate(0, plot.Height); //to compensate the flipped graph, move it back down
      }
      scale = new ScaleTransform(m.M11, m.M22, 0, 0); //save scale factors in a scaletransform for reference
      signals.scaleSignalStrokes(scale); //Scale the plotlines to compensate for canvas scaling
      MatrixTransform matrixTrans = new MatrixTransform(m); //Create matrixtransform
      plot.RenderTransform = matrixTrans; //Apply to canvas
  }
  </code></pre>
  
  <p>Expectation: Everything should work and the plotted graph would scale nicely when the amount of plotpoints grows over time. Reality: The graph scales when moving the points around, but it is not representative; Moreover, the more plot points are added, the more the whole canvas shifts to the right and the less control I seem to have over the transformation. The algorithm as it is now is probably to wrong approach to get the result I need, but I have spent quite some time thinking how to do this right. </p>
  
  <p><strong>Update</strong></p>
  
  <p>I have uploaded a video to give a clearer picture on the interaction. In the video you can clearly see the canvas shifting to the right.
  <a href="http://dl.dropbox.com/u/7668847/screencap.avi" rel="nofollow">Screencapture video</a></p>
  
  <p>How should I scale the canvas (plot) to fit within two boundaries? </p>