Zooming into a fixed point on a ScrollableControl
If I'd built subtitle support into the CMS that powers this website, then surely the subtitle would have been "or how I fixed that annoying zoom bug in the ImageBox control". And with that digression out of the way, onto the article, a nice and short one for a change!
I should probably point out that this article doesn't describe how to actually do any zooming (as that is dependant on what it is you are actually doing a zoom upon), but rather how to keep the viewport focused on a given point after zooming. To learn about zooming, please see previous articles that describe the ImageBox control in detail.
Users of the ImageBox
control are probably aware of the zoom
bug, where each time you use the mouse wheel to zoom in or out,
the final image position is slightly offset, as shown by this
short animation:
Fixing this bug is actually quite simple and I'm actually embarrassed at how long it took to fix and how I missed the solution for so long. The key to resolving this issue is finding out the document position under the mouse (by which I mean the position in the entire scroll area, not just the visible viewport) before applying the zoom, and then recalculating this position with the new zoom level, offset by the mouse position in the client control.
As it's probably easier just to show you the code rather than try and describe it, it results in this small function:
public virtual void ScrollTo(Point imageLocation, Point relativeDisplayPoint)
{
int x;
int y;
x = (int)(imageLocation.X * this.ZoomFactor) - relativeDisplayPoint.X;
y = (int)(imageLocation.Y * this.ZoomFactor) - relativeDisplayPoint.Y;
this.AutoScrollPosition = new Point(x, y);
}
To use it, you add code similar to the following where you process mouse clicks, or mouse wheel, however you control zooming with the mouse:
Point cursorPosition;
Point currentPixel;
int currentZoom;
// TODO: Obtain cursor position from MouseEventArgs etc.
currentPixel = this.PointToImage(cursorPosition);
currentZoom = this.Zoom;
// TODO: Perform zoom here
if (this.Zoom != currentZoom)
this.ScrollTo(currentPixel, cursorPosition);
So how does this work?
- Get the mouse cursor position, relative to the control
- Convert that position into the position of your virtual
document - for the
ImageBox
control we use thePointToImage
method - Perform your zoom and recalculate the document scroll size etc.
- Call the
ScrollTo
method, passing in the document position and mouse cursor position
And now you end up with something similar to this:
There is one case where this does not work as expected - when you scroll in or out sufficiently to remove the scrollbars, or when moving from no-scrollbars to scrollbars. However, I think is fine given it works so well the rest of the time!
That's fine, but where's the ImageBox update?
Thanks to a generous donation from a visitor to the site, I
recently sat down to work on the ImageBox
control and resolve
some of the issues - like the scrolling above. The next update
has quite a lot of new functionality (better keyboard support,
configurable zoom levels, flicker free scrolling and a handful
of bug fixes to name a few of the changes) and will be posted
presently. While the build is being finalized however, the above
code will work fine in current builds of the ImageBox
, if you
adjust for the pixel offset the current PointToImage
implementation uses.
Update History
- 2012-08-29 - First published
- 2020-11-21 - Updated formatting
Related articles you may be interested in
- Displaying multi-page tiff files using the ImageBox control and C#
- Adding drag handles to an ImageBox to allow resizing of selection regions
- ImageBox 1.1.4.0 update
- ImageBox and TabList update's - virtual mode, pixel grid, bug fixes and more!
- ImageBox update, version 1.1.0.0
- Zooming to fit a region in a ScrollableControl
- Arcade explosion generator
- Creating an image viewer in C# Part 5: Selecting part of an image
- Extending the ImageBox component to display the contents of a PDF file using C#
- Creating a scrollable and zoomable image viewer in C# Part 4
- Creating a scrollable and zoomable image viewer in C# Part 3
- Creating a scrollable and zoomable image viewer in C# Part 2
- Creating a scrollable and zoomable image viewer in C# Part 1
Leave a Comment
While we appreciate comments from our users, please follow our posting guidelines. Have you tried the Cyotek Forums for support from Cyotek and the community?