Zoom to cursor without canvas in javascript

依然范特西╮ 提交于 2021-02-07 04:00:07

问题


I have an <img> that is zoomed upon mousewheel scrolling, by adjusting transform: scale(). I want the zooming to be like in Google Maps, where you zoom to where the mouse cursor is, not to the center of the image. I'd like to not use canvas though, just for the learning experience (that's also why the other questions I found did not really help).

I set up a JSFiddle to demonstrate the problem. My thought process was as follows: when zooming in by 10%, the image expands in all directions, from the center of the image, by 10%. That means that e.g., the left and right edge will travel 5% of the original width in each direction. I therefore tried to solve the problem like so:

  1. Calculate mouse offset from image center
  2. Calculate new image offset (top and left) by multiplying mouse offset with zoom factor and divide by two
  3. Apply offset and watch it all blow up it my face with the power of a million burning suns

It seems that I just can't find a formula or algorithm that fits.


回答1:


Eventually I figured it out myself, although only by looking at existing solutions. Here is the JSFiddle that contains only the essentials.

The idea is to first set transform-origin: 0 0. This makes sure that, upon zooming, the image expands down and right, instead of distributing the increase in width over all four sides. Note that it does not reposition the image, it just changes the origin for all transformations.

Additionally, this JSFiddle assumes that the top and left margins of the image are aligned with the top and left margins of the container element. If the image should be repositioned before zooming occurs, this should be done through transform: translate() and the translateX and translateY values need to be updated accordingly.

The heart of the logic is this:

  // Track the percentage change between the old
  // and the new scale of the image
  const ratio = 1 - nextScale / currentScale

  // get the current mouse offset
  const {
    clientX,
    clientY
  } = event

  // The += here is extremely important!
  // The new 2D translation values are derived from the difference
  // between mouse cursor position and current (!) 2D translation.
  // So where is the mouse cursor relative to the translated image
  // This difference is then adjusted by the % change of the scaling
  translateX += (clientX - translateX) * ratio
  translateY += (clientY - translateY) * ratio

  /*
  This would work for the first mousewheel scroll. But afterwards, the 
  image will not be translated enough to offset the zooming because 
  we're not taking into account the existing translation
  translateX += (clientX - translateX) * ratio
  translateY += (clientY - translateY) * ratio
  */

So to summarize the required steps:

  1. Calculate the next scale
  2. Calculate the current mouse offset relative to the translated image
  3. Adjust the mouse offset for the change in scaling, e.g., const percentChange = 1 - nextScale / currentScale
  4. Add the adjusted mouse offset to the existing values for translate()
  5. Apply the transformation (scaling and the translation)



回答2:


You could use transform-origin : <position of your mouse pointer> :

  • transform-origin : 0% 0% points on the top left corner.
  • transform-origin : 100% 100% points on the bottom right corner.

Here's an example I made : https://jsfiddle.net/zez538L8/4/

The javaScript :

var currentzoom = 1;

function zoom(delta, e) {
   var img = document.getElementById("test");
   var width = img.offsetWidth; //calculating the size of the img (in px)
   var height = img.offsetHeight;
   var x = event.offsetX; //calculating the position of the mouse pointer on the picture (in px)
   var y = event.offsetY; 
   var xpercent = x*100/width; //calculating the position of the mouse pointer on the picture (in %)
   var ypercent = y*100/height;
   img.style.transform = "scale("+currentzoom+")"; //scaling the picture
   img.style.transformOrigin = xpercent + "% "+ ypercent +"%"; //transform-origin
   currentzoom += delta;
}


来源:https://stackoverflow.com/questions/44154041/zoom-to-cursor-without-canvas-in-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!