Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zoom toward mouse (eg. Google maps)

I've written a home-brew view_port class for a 2D strategy game. The panning (with arrow keys) and zooming (with mouse wheel) work fine, but I'd like the view to also home towards wherever the cursor is placed, as in Google Maps or Supreme Commander

I'll spare you the specifics of how the zoom is implemented and even what language I'm using: this is all irrelevant. What's important is the zoom function, which modifies the rectangle structure (x,y,w,h) that represents the view. So far the code looks like this:

void zoom(float delta, float mouse_x, float mouse_y)
{
    zoom += delta;
    view.w = window.w/zoom;
    view.h = window.h/zoom;  
    // view.x = ???
    // view.y = ???
}

Before somebody suggests it, the following will not work:

view.x = mouse_x - view.w/2;
view.y = mouse_y - view.h/2;

This picture illustrates why, as I attempt to zoom towards the smiley face:

http://oi43.tinypic.com/16m21au.jpg

As you can see when the object underneath the mouse is placed in the centre of the screen it stops being under the mouse, so we stop zooming towards it!

If you've got a head for maths (you'll need one) any help on this would be most appreciated!

like image 567
wilbefast Avatar asked Mar 06 '12 21:03

wilbefast


People also ask

How do you zoom in smoothly on Google Maps?

The shortcut is simple: just double-tap the maps interface, but instead of lifting your finger after the second tap (the shortcut for zooming in), you leave it touching the screen. Then a swipe up zooms out, and a swipe down zooms in.

Can you zoom in on Google Maps?

You can zoom in and out of the map with one hand. Double tap a spot on the map, and then: Drag down to zoom in. Drag up to zoom out.


2 Answers

I managed to figure out the solution, thanks to a lot of head-scratching a lot of little picture: I'll post the algorithm here in case anybody else needs it.

Vect2f mouse_true(mouse_position.x/zoom + view.x, mouse_position.y/zoom + view.y);
Vect2f mouse_relative(window_size.x/mouse_pos.x, window_size.y/mouse_pos.y);   
view.x = mouse_true.x - view.w/mouse_relative.x;
view.y = mouse_true.y - view.h/mouse_relative.y;

This ensures that objects placed under the mouse stay under the mouse. You can check out the code over on github, and I also made a showcase demo for youtube.

like image 146
wilbefast Avatar answered Oct 19 '22 21:10

wilbefast


In my concept there is a camera and a screen. The camera is the moving part. The screen is the scalable part.

I made an example script including a live demo. The problem is reduced to only one dimension in order to keep it simple. https://www.khanacademy.org/cs/cam-positioning/4772921545326592

var a = (mouse.x + camera.x) / zoom;

// now increase the zoom e.g.: like that:
zoom = zoom + 1;

var newPosition = a * zoom - mouse.x;

camera.setX(newPosition);
screen.setWidth(originalWidth * zoom);

For a 2D example you can simply add the same code for the height and y positions.

like image 45
GDur Avatar answered Oct 19 '22 21:10

GDur