Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to zoom to mouse pointer while using my own mousewheel smoothscroll?

Tags:

javascript

Part of my app contains functionality similar to google maps in that the user should be able to zoom in and out on an image within a container.

In the same way that google maps does I want the user to be able to scroll with the mousewheel and the pixel on the image to remain directly under the mousepointer at all times. So essentially the user will be zooming to wherever their mouse pointer is.

For the zooming/translating I am using css transforms like so:

visible

   $('#image').css({
            '-moz-transform': 'scale(' + ui.value + ') translate(' + self.zoomtrans.xNew + 'px, ' + self.zoomtrans.yNew + 'px)',
            '-moz-transform-origin' : self.zoomtrans.xImage + 'px ' + self.zoomtrans.yImage + 'px',
              '-webkit-transform': 'scale(' + ui.value + ') translate(' + self.zoomtrans.xNew + 'px, ' + self.zoomtrans.yNew + 'px)',
            '-webkit-transform-origin' : self.zoomtrans.xImage + 'px ' + self.zoomtrans.yImage + 'px',
              '-o-transform': 'scale(' + ui.value + ') translate(' + self.zoomtrans.xNew + 'px, ' + self.zoomtrans.yNew + 'px)',
            '-o-transform-origin' : self.zoomtrans.xImage + 'px ' + self.zoomtrans.yImage + 'px',
              '-ms-transform': 'scale(' + ui.value + ') translate(' + self.zoomtrans.xNew + 'px, ' + self.zoomtrans.yNew + 'px)',
            '-ms-transform-origin' : self.zoomtrans.xImage + 'px ' + self.zoomtrans.yImage + 'px',
              'transform': 'scale(' + ui.value + ') translate(' + self.zoomtrans.xNew + 'px, ' + self.zoomtrans.yNew + 'px)',
            'transform-origin' : self.zoomtrans.xImage + 'px ' + self.zoomtrans.yImage + 'px'
            });

I have managed to find various implementations of how to go about doing this however I am using a self rolled smooth scroll technique to interpolate the mouse events and provide momentum.

Trying to get the two to work correctly together is proving troublesome.

Rather than paste a whole load of code here I have created a jsFiddle that includes the mousewheel smoothscroll technique along with the zoom function that I have so far.

http://jsfiddle.net/gordyr/qGGwx/2/

This is essentially a fully functioning demo of this part of my app.

If you scroll the mousewheel you will see that the jqueryui slider interpolates and provides the momentum/deceleration correctly. However the zoom does not react correctly.

If you scroll your mousewheel only one point the zoom works perfectly but any further scrolls do not work. I assume this is because the scale of the image has now changed causing the calculations to be incorrect. I have attempted to compensate for this but have not had any luck so far.

So to summarise, I would like to modify the code in my jsFiddle so that the image zooms directly to the mousepointer at all times.

Huge thanks in advance to anyone willing to help.

like image 357
gordyr Avatar asked Jan 17 '13 11:01

gordyr


People also ask

How do I make my mouse wheel zoom?

If you didn't know, if you press any of the CTRL keys and scroll upwards or downwards, the mouse's scroll will produce zooming.

How do I stop my scroll wheel from zooming?

With the Advanced / Editing tab selected, move over to the right-hand pane and uncheck the box associated with Zoom on roll with IntelliMouse. Click Ok to save the changes, then restart your computer and see if the issue is resolved at the next computer startup.


1 Answers

You can do it more easily with css3 transitions.
Exemple: http://jsfiddle.net/BaliBalo/xn75a/
The main center-mouse algorithm is here:

//Center the image if it's smaller than the container
if(scale <= 1)
{
    currentLocation.x = im.width() / 2;
    currentLocation.y = im.height() / 2;
}
else
{
    currentLocation.x += moveSmooth * (mouseLocation.x - currentLocation.x) / currentScale;
    currentLocation.y += moveSmooth * (mouseLocation.y - currentLocation.y) / currentScale;
}

If you want to keep your already-existing code, I think you can do it approximatively the same: the trick to get the mouse position on the zoomed image when the image itself is zoomed by a css scale transform and using transform-origin is to substract the transform origin to your point then multiply by the factor and finally re-add the transform-origin.

You can also use translate as in this updated example: http://jsfiddle.net/BaliBalo/xn75a/15/ As you can see it even simplifies the formulas but don't forget to sub the center of the element to mouse point as a translation of {0, 0} will zoom on the middle of the image.


EDIT:

I stumbled on this answer of mine today and figured it wasn't really the behaviour you wanted. I didn't understand correctly the first time that you didn't want to center the point under the mouse but to keep it in the same spot. As I did it recently for a personnal project I tried to correct myself. So here is a more accurate answer :
http://jsfiddle.net/BaliBalo/7ozrc1cq/

The main part is now (if currentLocation is the top-left point of the image in the container) :

var factor = 1 - newScale / currentScale;
currentLocation.x += (mouseLocation.x - currentLocation.x) * factor;
currentLocation.y += (mouseLocation.y - currentLocation.y) * factor;

I also removed the CSS transition. I think the best way to achieve a smooth scrolling would be to use requestAnimationFrame to create an animation loop and instead of changing values directly in the zoom function, store values and animate towards them in the loop.

like image 161
Bali Balo Avatar answered Oct 19 '22 20:10

Bali Balo