Saturday, March 10, 2012

How to zoom in GDI+ painting?

When you are creating a GDI+ painting control, you may need to add some facilities to zoom in the painting area and scroll inside it.
It's simple. I show you how to do it with a few lines of code:
I supposed that the amount of zooming is set to the zoomFactor variable. First of all, you need to transform the Graphics object of the OnPaint event handler, and the amount of the scrolls are set as the value of your scrollable control horizonal and vertical scroll bar values.
So add the below code to the overriden OnPaint event handler:

/// <summary>
/// Occures when the entire control needs repainting.
/// </summary>
/// <param name="e">A PaintEventArgs that contains the event data.</param>
protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    e.Graphics.Transform = this.SetGraphicsMatrix();
    e.Graphics.TranslateTransform(
        (float)Math.Round(
            this.Unzoom(AutoScrollPosition.X) - AutoScrollPosition.X, 
            MidpointRounding.AwayFromZero),
        (float)Math.Round(
            this.Unzoom(AutoScrollPosition.Y) - AutoScrollPosition.Y, 
            MidpointRounding.AwayFromZero));
    // Your paintings here
}
 
SetGraphicsMatrix() creates a matrix to scale the painting area, and synchronizes thetop-left corner of the painting area with the horizontal and vertical scroll bars:
 
/// <summary>
/// Creates a matrix to scale the painting area and synchronize
/// the top-left corner of the control with the scroll bars.
/// </summary>
/// <returns>The translated matrix.</returns>
private Matrix SetGraphicsMatrix()
{
    Matrix matrix = new System.Drawing.Drawing2D.Matrix();
    matrix.Scale(this.zoomFactor, this.zoomFactor);
            matrix.Translate(-this.HorizontalScroll.Value, 
                             -this.VerticalScroll.Value);
    return matrix;
}
 
Using the above codes, your painting will be drawn and zoomed correctly on your scrollable control. 





What if you need to obtain the location of a point on your scrolled and zoomed control?
The Unzoom method calculates a value describing its original value when the painting area is unzoomed (zoomFactor = 1). Below you can find two overloads of it:
 
/// <summary>
/// Calculates the original value of a float value when zooming.
/// </summary>
/// <param name="value">The value which its original value 
/// should be calculated.</param>
/// <returns>The original value of the float value when zooming.</returns>
internal float Unzoom(float value)
{
    return value / this.zoomFactor;
}


/// <summary>
/// Calculates the original values of a location point when zooming.
/// </summary>
/// <param name="location">The location which its original values 
/// should be calculated.</param>
/// <returns>The original values of the location when zooming.</returns>
internal PointF Unzoom(PointF location)
{
    return new PointF(location.X / this.zoomFactor, 
                      location.Y / this.zoomFactor);
}
 
And finaly, you may need to know the location of a point on your control considering the scroll values. To do this, Use ScrolledLocation method:
 
/// <summary>
/// Calculates the correct values of a location
/// when Canvas2D control is scrolled.
/// </summary>
/// <param name="location">The specified location.</param>
/// <returns>The calculated location after scrolling.</returns>
internal PointF ScrolledLocation(PointF location)
{
    return new PointF(location.X - AutoScrollPosition.X, 
        location.Y - AutoScrollPosition.Y);
}
 
Although ScrolledLocation method calculates the location of a point when your control is scrolled, it does not work correctly when the zoomFactor is not equal to 1. To resolve this problem, you need to combine it with Unzoom method.
For example: To get the correct location of mouse when you click on the control, use the below piece of code:

PointF PaintLocation = this.Unzoom(
     this.ScrolledLocation(this.PointToClient(MousePosition)));
 
That's all. Enjoy your programming.


3 comments:

  1. Hi Merhdad

    do you have an example project?
    i can't get it work.

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Hi,

    You can download a sample project at:
    Link

    ReplyDelete