Zooming graphics without scrolling

2019-09-07 05:27发布

问题:

I have a user control and I'm using ScaleTransform() to implement zoom.

However, in order to keep the center content in the center after the zoom, it is also necessary to scroll. For example, if I zoom in (make things bigger), the X and Y origin should increase so that most of the content does not move down and to the right. (That is, as I zoom in, some of the content should disappear to the left and top.)

Has anyone worked out the calculations of how much to scroll in the X and Y direction in response to a zoom?

For example:

e.Graphics.ScaleTransform(2.0F, 2.0F);
e.Graphics.TranslateTransform(?, ?);

What would be my arguments to TranslateTransform() be so that the center part of the content remains at the center?

Note: I am not displaying an image. I am drawing the graphic content to the surface of my user control.

Or perhaps there's an even easier way?

回答1:

This should work and I can't imagine any easier way; it assumes you have decided on the center of the zooming. I have chosen to draw centered on the panel:

float zoom = 1f;

private void drawPanel1_Paint(object sender, PaintEventArgs e)
{
    Point c = new Point(drawPanel1.ClientSize.Width / 2, drawPanel1.ClientSize.Height / 2);

    // a blue sanity check for testing
    e.Graphics.FillEllipse(Brushes.DodgerBlue, c.X - 3, c.Y - 3, 6, 6);

    // the offsets you were looking for:
    float ox = c.X * ( zoom - 1f);
    float oy = c.Y * ( zoom - 1f);

    // first move and then scale
    e.Graphics.TranslateTransform(-ox, -oy);
    e.Graphics.ScaleTransform(zoom, zoom);

     // now we can draw centered around our point c
    Size sz = new Size(300, 400);
    int count = 10;
    int wx = sz.Width  / count;
    int wy = sz.Height / count;

    for (int i = 0; i < count; i++)
    {
        Rectangle r = new Rectangle(c.X - i * wx / 2 , c.Y - i * wy / 2, i * wx, i * wy );
        e.Graphics.DrawRectangle(Pens.Red, r );
    }
}

Note the order of moving and scaling!



回答2:

I guess you are using some differet interface, but in my case, that's what got the job done (for leaving the mouse in it's original location on the draw after the mouse wheel event):

private void DrawPb_MouseWheel(object sender, MouseEventArgs e)
    {
        // e contains current mouse location and the wheel direction
        int wheelDirection = e.Delta / Math.Abs(e.Delta); // is 'in' or 'out' (1 or -1).
        double factor = Math.Exp(wheelDirection * Constants.ZoomFactor); // divide or multiply
        double newX = e.X - e.X / factor; // what used to be x is now newX
        double newY = e.Y - e.Y / factor; // same for y
        Point offset = new Point((int)(-newX), (int)(-newY)); // the offset of the old point to it's new location
        Graph.AddOffset(offset); // apply offset
    }