"Google maps"-like zooming of NSScrollView's content view

319 views
Skip to first unread message

Nick

unread,
Apr 1, 2012, 11:28:43 AM4/1/12
to cocoa-dev Dev
Hello

I am trying to implement a zooming of a content view (actually it is a
PDFView page) using a mouse scrolling wheel.
What I want to have in the end - is to have the final content view
zoomed in or out in a way that the point, where the mouse was located,
does not move during this zooming operation (this point would be some
kind of an anchor around which the rest of the content view should be
zoomed). Here is an example of this: http://maps.google.com

I've managed to make the view zoom in and out using a view's center
point as such an anchor (this is an example i found on the internet):

float zoomFactor = 1.3;

-(void)zoomIn
{
NSRect visible = [scrollView documentVisibleRect];
NSRect newrect = NSInsetRect(visible, NSWidth(visible)*(1 -
1/zoomFactor)/2.0, NSHeight(visible)*(1 - 1/zoomFactor)/2.0);
NSRect frame = [scrollView.documentView frame];

[scrollView.documentView
scaleUnitSquareToSize:NSMakeSize(zoomFactor, zoomFactor)];
[scrollView.documentView setFrame:NSMakeRect(0, 0,
frame.size.width * zoomFactor, frame.size.height * zoomFactor)];

[[scrollView documentView] scrollPoint:newrect.origin];
}

-(void)zoomOut
{
NSRect visible = [scrollView documentVisibleRect];
NSRect newrect = NSOffsetRect(visible,
-NSWidth(visible)*(zoomFactor - 1)/2.0, -NSHeight(visible)*(zoomFactor
- 1)/2.0);

NSRect frame = [scrollView.documentView frame];

[scrollView.documentView
scaleUnitSquareToSize:NSMakeSize(1/zoomFactor, 1/zoomFactor)];
[scrollView.documentView setFrame:NSMakeRect(0, 0,
frame.size.width / zoomFactor, frame.size.height / zoomFactor)];

[[scrollView documentView] scrollPoint:newrect.origin];
}

However, I can't figure out how to make zooming like google maps does,
preserving that mouse "anchor" point's location. Could you give me a
hint?

Thank you
_______________________________________________

Cocoa-dev mailing list (Coco...@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/cocoa-dev-garchive-98506%40googlegroups.com

This email sent to cocoa-dev-ga...@googlegroups.com

Dave Fernandes

unread,
Apr 1, 2012, 11:52:31 AM4/1/12
to Nick, cocoa-dev Dev
Just a comment about the UI… I find this behavior horribly counter-intuitive. I always end up zooming when I mean to pan.

> https://lists.apple.com/mailman/options/cocoa-dev/dave.fernandes%40utoronto.ca
>
> This email sent to dave.fe...@utoronto.ca

Alex Zavatone

unread,
Apr 1, 2012, 12:05:04 PM4/1/12
to Dave Fernandes, cocoa-dev Dev
Dave, while I can see that you may want the mouse wheel to navigate the current map, does it not make more sense to allow the mouse wheel to zoom in or out and then hold the mouse button down and drag left and right to pan?

If you use the mouse wheel to pan, what is naturally your zoom control?

On Apr 1, 2012, at 11:52 AM, Dave Fernandes wrote:

> Just a comment about the UI… I find this behavior horribly counter-intuitive. I always end up zooming when I mean to pan.

Nick

unread,
Apr 1, 2012, 12:42:11 PM4/1/12
to Alex Zavatone, cocoa-dev Dev
This is a very customized application, it is not intended for public use.
Just wondering if someone could help me with the math to create this
zooming effect..

Per Bull Holmen

unread,
Apr 1, 2012, 12:51:58 PM4/1/12
to cocoa-dev Dev
Den 17:28 1. april 2012 skrev Nick <eveni...@gmail.com> følgende:

> However, I can't figure out how to make zooming like google maps does,
> preserving that mouse "anchor" point's location. Could you give me a
> hint?
>
> Thank you

I can't give you readymade example code, but here's the steps:

1) Find the mouse location in the clip view's ( = content view's )
coordinate space. ( [clipView convertPoint:[theEvent locationInWindow]
formView:nil] )
2) Compute the mouse location in fractions of the clip view's bounds.
All the way to the left means x = 0, all the way to the right means x
= 1. Vice versa with y. If the point is equal to the content view's
origin, the fraction point becomes { 0, 0 }, if it's in the center,
you get { 0.5, 0.5 }, if the point's x value equals the
bounds.origin.x + bounds.size.width, and vice versa with y, you get {
1, 1 }.
3) Manipulate the bounds of the content view (NOT the document view),
so that the bounds rectangle gets smaller if you zoom in, larger if
you zoom out. How much you change the content view bound's location is
given by the fraction you found in point 2 (along each axis). How much
you change the bound's size is given by one minus the fraction you
found in point 2. For the fraction point { 0, 0 }, you do not touch
the bound's origin at all. For the fraction point { 1, 1 } you only
change the origin, not the size.

Don't touch the document view's frame or bounds. This way of zooming,
by manipulating the content view's bounds instead of the document
view's frame has worked fine for me in the past. It's usually easier,
I think.

Per

Alex Zavatone

unread,
Apr 1, 2012, 1:00:33 PM4/1/12
to Nick, cocoa-dev Dev
There is code from Paul Hegarty's class on UImageView that works really easily with the pinch gesture.

I'll look to see if I have any code handy.

On Apr 1, 2012, at 12:42 PM, Nick wrote:

> This is a very customized application, it is not intended for public use.
> Just wondering if someone could help me with the math to create this
> zooming effect..
>
> Alex Zavatone <z...@mac.com> wrote:
>> Dave, while I can see that you may want the mouse wheel to navigate the current map, does it not make more sense to allow the mouse wheel to zoom in or out and then hold the mouse button down and drag left and right to pan?
>>
>> If you use the mouse wheel to pan, what is naturally your zoom control?
>>
>> On Apr 1, 2012, at 11:52 AM, Dave Fernandes wrote:
>>
>>> Just a comment about the UI… I find this behavior horribly counter-intuitive. I always end up zooming when I mean to pan.
>>

- Alex Zavatone

Per Bull Holmen

unread,
Apr 1, 2012, 1:56:36 PM4/1/12
to cocoa-dev Dev
Den 18:51 1. april 2012 skrev Per Bull Holmen <pbho...@gmail.com> følgende:
> Den 17:28 1. april 2012 skrev Nick <eveni...@gmail.com> følgende:
>
>> However, I can't figure out how to make zooming like google maps does,
>> preserving that mouse "anchor" point's location. Could you give me a
>> hint?
>>
>> Thank you
>
> I can't give you readymade example code, but here's the steps:

OK, just because I am a naive altruist, I made one for you. This one
takes a zoom factor where 1 is 1:1, 0.5 means half size, 2.0 means
double size, etc. Works on my machine. I haven't checked what happens
if the bounds origin gets negative coordinates. You may want to put in
a little check to prevent that.

-(void)zoom:(float)newFactor event:(NSEvent *)mouseEvent {
NSScrollView *scrollView = [self enclosingScrollView];
NSClipView *clipView = [scrollView contentView];
NSRect clipViewBounds = [clipView bounds];
NSSize clipViewSize = [clipView frame].size;

NSPoint clipLocalPoint = [clipView convertPoint:[mouseEvent
locationInWindow] fromView:nil];

float xFraction = ( clipLocalPoint.x - clipViewBounds.origin.x ) /
clipViewBounds.size.width;
float yFraction = ( clipLocalPoint.y - clipViewBounds.origin.y ) /
clipViewBounds.size.height;

clipViewBounds.size.width = clipViewSize.width / newFactor;
clipViewBounds.size.height = clipViewSize.height / newFactor;

clipViewBounds.origin.x = clipLocalPoint.x - ( xFraction *
clipViewBounds.size.width );
clipViewBounds.origin.y = clipLocalPoint.y - ( yFraction *
clipViewBounds.size.height );

[clipView setBounds:clipViewBounds];

Dave Fernandes

unread,
Apr 1, 2012, 3:59:10 PM4/1/12
to Alex Zavatone, cocoa-dev Dev
I guess it makes some sense with a mouse wheel, but doesn't seem right with a Magic Mouse. On a trackpad, at least there is a pinch zoom gesture.

Alex Zavatone

unread,
Apr 1, 2012, 5:07:21 PM4/1/12
to Dave Fernandes, cocoa-dev Dev

On Apr 1, 2012, at 3:59 PM, Dave Fernandes wrote:

> I guess it makes some sense with a mouse wheel, but doesn't seem right with a Magic Mouse. On a trackpad, at least there is a pinch zoom gesture.
>

You could have buttons on the screen to zoom in and out , as in google maps and use the scroll wheel to pan, but it appears that Apple is pushing the control-less pan/zooming.

Gestures to zoom ala pinch and single finger swipes to pan.

Anyway, it's Sunday. Back to work.

- Alex Zavatone

Reply all
Reply to author
Forward
0 new messages