Problem - Before the zoom operation, the user can draw "points" according to the click position of the mouse on the canvas(picturebox
), but when the user uses the mouse wheel to zoom (without returning to the original zoom ratio), the user draws a "point" with the mouse clicke again, the clicked position of the mouse is inconsistent with the position of the drawn "point" on the canvas(picturebox
).
The demo code is down below:
private List<Point> _points;
private int _pointRadius = 60;
private float _zoom = 1f;
private float _offsetX = 0f;
private float _offsetY = 0f;
private void picturebox_MouseDown(object sender, MouseEventArgs e)
{
_points.Add(e.Location);
}
private void picturebox_MouseWheel(object sender, MouseEventArgs e)
{
if(e.Delta < 0)
{
_zoom = 0.1f;
_offsetX = e.X * (1f - _zoom);
_offsetY = e.Y * (1f - _zoom);
}
else
{
if (_zoom <= 1f)
{
return;
}
_zoom -= 0.1f;
_offsetX = e.X * (1f - _zoom);
_offsetY = e.Y * (1f - _zoom);
}
picturebox.Invalidate();
}
private void picturebox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.TranslateTransform(_offsetX, _offsetY);
e.Graphics.ScaleTransform(_zoom, _zoom);
foreach (Point point in _points)
{
e.Graphics.FillEllipse(Brushes.Black, point.X - _pointRadius, point.Y - _pointRadius, 2 * _pointRadius, 2 * _pointRadius);
}
}
[Edit1 - add the picturebox
properties screenshot]
[Edit2 - add a .gif to show the problem]
I would appreciate any help, it would be better if your answer could be more detailed.
CodePudding user response:
If you also use the mouse inputs to draw your shapes, then you also need to take the offset into account to get the right point.
Revising the first example to mainly add the ScalePoint
method to do the required calculations.
private float _zoom = 1f;
private PointF _wheelPoint;
private readonly SizeF _recSize = new Size(60, 60);
private List<RectangleF> _rects = new List<RectangleF>();
private PointF ScalePoint(PointF p) =>
new PointF(
(p.X _wheelPoint.X) / _zoom - (_recSize.Width / 2),
(p.Y _wheelPoint.Y) / _zoom - (_recSize.Height / 2));
private void picturebox_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_rects.Add(new RectangleF(ScalePoint(e.Location), _recSize));
picturebox.Invalidate();
}
}
private void picturebox_MouseWheel(object sender, MouseEventArgs e)
{
_zoom = e.Delta < 0 ? -.1f : .1f;
_zoom = Math.Max(.1f, Math.Min(10, _zoom));
_wheelPoint = new PointF(e.X * (_zoom - 1f), e.Y * (_zoom - 1f));
picturebox.Invalidate();
}
private void picturebox_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
g.TranslateTransform(-_wheelPoint.X, -_wheelPoint.Y);
g.ScaleTransform(_zoom, _zoom);
g.SmoothingMode = SmoothingMode.AntiAlias;
_rects.ForEach(r => g.FillEllipse(Brushes.Black, r));
}