Reputation: 403
I have an app that I can zoom in and out, only problem I want to zoom in and out but focused into the current middle of the panel location , instead of using mouse position
any ideas?
private void panel1_Paint(object sender, PaintEventArgs e)
{
SolidBrush brushs = new SolidBrush(Color.White);
e.Graphics.Clip = new Region(new Rectangle(0, 0, Viewer.Width, Viewer.Height));
e.Graphics.FillRegion(brushs, e.Graphics.Clip);
Graphics g = e.Graphics;
g.TranslateTransform(_ImgX, _ImgY);
g.ScaleTransform(_Zoom, _Zoom);
g.SmoothingMode = SmoothingMode.AntiAlias;
SolidBrush myBrush = new SolidBrush(Color.Black);
Pen p = new Pen(Color.Red);
foreach (CircuitData.ResistorRow resistorRow in ResistorData.Resistor)
{
RectangleF rec = new RectangleF((float)(resistorRow.CenterX - resistorRow.Length/ 2), (float)(resistorRow.CenterY - resistorRow.Width/ 2), (float)resistorRow.Length, (float)resistorRow.Width);
float orientation = 360 - (float)resistorRow.Orientation;
PointF center = new PointF((float)resistorRow.CenterX, (float)resistorRow.CenterY);
PointF[] points = CreatePolygon(rec, center, orientation);
if (!Double.IsNaN(resistorRow.HiX) && !Double.IsNaN(resistorRow.HiY))
{
g.FillEllipse(myBrush, (float)resistorRow.HiX - 2 , (float)resistorRow.HiY - 2, 4, 4);
g.DrawLine(p, new PointF((float)resistorRow.HiX , (float)resistorRow.HiY ), center);
}
g.FillPolygon(myBrush, points);
}
}
Update The zooming function, I know it is wrong but if anyone can help me fixing the logic or better Idea.
private void trackBar1_Scroll(object sender, EventArgs e)
{
float oldZoom = _Zoom;
_Zoom = zoomTrackPad.Value / 10f;
int x = Math.Abs(Viewer.Width / 2 );
int y = Math.Abs(Viewer.Height / 2 );
int oldImageX = (int)(x / oldZoom);
int oldImageY = (int)(y / oldZoom);
int newImageX = (int)(x / _Zoom);
int newImageY = (int)(y / _Zoom);
_ImgX = newImageX - oldImageX + _ImgX;
_ImgY = newImageY - oldImageY + _ImgY;
Viewer.Invalidate();
}
Thanks
Upvotes: 4
Views: 2374
Reputation: 15151
As you said, your logic for zooming is wrong. And it's wrong because of how transformation matrices work.
Transformation matrices are appended one after other, in you case you are translating the image as if it where already scaled and then you zoom it, this will change the zoom origin and will not be centered.
I'm going to assume some things here, if anything is wrong pelase comment.
Suppose your visible area (panel size) is 100 * 100 pixels, and you want a "virtual" content size of 200 * 200 pixels. I think you have two scrollbars to displace the content inside the panel, if you are just using the panel size and have no scrollbars then you should adapt how you calculate your displacement.
So, your scrollbars will range from 0 to (panel.(with/height) - content.(width/height)), in this case will range from 0 to 100.
Let's first do our content be centered at the start. To center it we apply a TranslateTransform to the Graphics object with the half of the size of our visible area less half of the size of the virtual area:
e.Graphics.TranslateTransform(panel.With / 2 - content.Width / 2, panel.Height / 2 - content.Height / 2);
This will do the drawing to be centered, but,hey! we're not using the positioning scrollbars!
Okokoko, let's apply those scrollbar offsets. First, as we have our content centered, set the values of these scrollbars to the half of it's max value, in our example we should set those to 50.
Now, as we said, transformations are appended, so, nothing impedes you to add a new TranslateTransform. You can do this in only one call, but for simplicity we are doing this in two calls (also, it will be better for applying zoom later).
e.Graphics.TranslateTransform(panel.With / 2 - content.Width / 2, panel.Height / 2 - content.Height / 2);
e.Graphics.TranslateTransform(hScrollBar1.Value - (hScrollbar1.Maximum / 2), vScrollBar1.Value - (vScrollbar1.Maximum / 2));
As you see we are subtracting half of it's max value, we already have our content centered so when the scrollbars are in the center we need to apply a translation of 0, we will range from -Maximum / 2 to Maximum / 2, in this example from -50 to 50.
Well, we now have a virtual content area centered in our screen and we can displace on it, now we need to apply that zoom.
As I see you have an scrollbar, so let's follow our example using it.
The ranging of the scrollbar would be your choice, I see you're using value / 10f, so if your scrollbar ranges from 1 to 100 you will have a zoom from 0.1 to 10, It's a good choice for start.
Now, lets set this scrollbar to 10, to initally have a unitary zoom.
Now comes the interesting part, the transformations are applied in the order you set them, so it's not the same to apply a zoom before a translation than doing it after.
In our case we first want to center the content, translate to the position we want to see (the scrollbars values) and then zoom.
e.Graphics.TranslateTransform(panel.With / 2 - content.Width / 2, panel.Height / 2 - content.Height / 2);
e.Graphics.TranslateTransform(hScrollBar1.Value - (hScrollbar1.Maximum / 2), vScrollBar1.Value - (vScrollbar1.Maximum / 2));
float scale = zScrollBar.Value / 10f;
e.Graphics.ScaleTransform(scale, scale);
Ok, it sounds good, but wait! it will fail miserably. Why? because when we zoom our virtual size is being also scaled up respect to the view area (panel size), so we need to apply this scale to the content size (and thus, to the scrollbar values):
float scale = zScrollBar.Value / 10f;
e.Graphics.TranslateTransform(panel.With / 2 - ((content.Width / 2) * scale), panel.Height / 2 - ((content.Height / 2) * scale));
e.Graphics.TranslateTransform((hScrollBar1.Value - (hScrollbar1.Maximum / 2)) * scale, (vScrollBar1.Value - (vScrollbar1.Maximum / 2)) * scale);
e.Graphics.ScaleTransform(scale, scale);
And finally we have a fully working virtual area where you can zoom and displace through it's bounds.
I'm a bit rusty with graphics, so maybe some calculation is wrong, I hope not, in any case this will give you the general idea on how to do this.
Cheers!
P.D.: if you don't want to be able to displace the virtual area and just zoom on the center of your panel skip the second translate transform, also if you want to zoom in the current visible center of your virtual area just use the displacement (without scaling it, the transforms already have the logic for this) instead of the scrollbars values.
Upvotes: 3