在JavaScript中,无需画布即可缩放到光标位置

5
我有一个<img>标签,通过调整transform: scale()来实现鼠标滚轮缩放。我希望缩放效果像Google Maps一样,即缩放到鼠标光标所在位置,而不是图像中心。但我不想使用canvas,只是为了学习体验(这也是为什么我找到的其他问题并没有真正帮助我的原因)。我设置了一个JSFiddle来演示问题。我的思路如下:当缩小10%时,图像会从图像中心向所有方向扩展10%。这意味着例如左边和右边的边缘将分别向两个方向移动原始宽度的5%。因此,我尝试以下解决方法:
  1. 计算图像中心到鼠标光标的偏移量
  2. 通过将鼠标偏移量乘以缩放因子并除以2来计算新的图像偏移(上和左)
  3. 应用偏移并观察它们全部爆炸的力量,就像一百万个太阳燃烧一样
看起来我只是找不到适合的公式或算法。
2个回答

12

最终我自己解决了问题,尽管是通过查看现有的解决方案。这里是包含必要内容的JSFiddle

首先设置transform-origin: 0 0,这样可以确保在缩放时,图像向下和向右扩展,而不是将宽度增加分布在四个边上。请注意,它不会重新定位图像,它只是更改所有变换的原点

此外,这个JSFiddle假设图像的顶部和左侧边距与容器元素的顶部和左侧边距对齐。如果在缩放发生之前应该重新定位图像,则应通过transform: translate()进行操作,并相应地更新translateXtranslateY值。

逻辑的核心是这个:

  // 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 wheel 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
  */

因此,总结所需步骤:

  1. 计算下一个比例尺
  2. 计算相对于翻译图像的当前鼠标偏移量
  3. 调整缩放变化的鼠标偏移量,例如:const percentChange = 1 - nextScale / currentScale
  4. 将调整后的鼠标偏移量添加到现有的 translate() 值中
  5. 应用变换(缩放和平移)

链接的 JSFiddle 还包括 Lodash 和 transition: transform 330ms ease-in-out;,使滚动更加流畅,不会对浏览器性能产生太大影响。


1
注意:在JSFiddle中,已经弃用mousewheel,请改用wheel作为eventListener - user11484628
1
JSFiddle 中缩小 无效,而是会向下滚动。 - user11484628
感谢@LukoFoks的评论,我更新了JSFiddle(或者说保存了一个新的),修复了问题。在Firefox和Safari上对我有效。 - Vey
很高兴看到你更新了代码片段,不过现在它有些奇怪的行为。缩小视图根本不起作用,而且非常敏感。单次滚动就会将视图缩放约200%。已在 Firefox Developer EditionMicrosoft Edge 进行测试。 - user11484628
在 Firefox 开发者版中,缩小页面对我有效。我使用轨迹板。灵敏度有点不一样,确实如此。我需要研究一下如何稍微调整一下这个。 - Vey

0

你可以使用 transform-origin : <鼠标指针位置>

  • transform-origin : 0% 0% 指向左上角。
  • transform-origin : 100% 100% 指向右下角。

这是我制作的一个示例:https://jsfiddle.net/zez538L8/4/

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;
}

1
这仅适用于初始缩放。如果您将视点对准其他位置并缩放,则会出现错误。感觉有点像我遇到的问题。 - Vey
@Vey在解决那个故障方面有什么进展吗? - deLiz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接