使用转换时需要注意应用的顺序。如果交换了缩放和平移,则会发现示例的工作方式有所不同。以下是有关此问题的有趣文章:
https://staff.washington.edu/fmf/2011/07/15/css3-transform-attribute-order/。保持这个顺序的变换似乎可以避免问题。我已经修改了下面的版本,使用
translate3D
,因为它对许多系统性能更好。
http://jsfiddle.net/fxpc5rao/32/
var current = {x: 0, y: 0, zoom: 1},
con = document.getElementById('container');
window.onclick = function(e) {
var coef = e.shiftKey || e.ctrlKey ? 0.5 : 2,
oz = current.zoom,
nz = current.zoom * coef,
ox = 20,
oy = 20,
mx = e.clientX - ox,
my = e.clientY - oy,
ix = (mx - current.x) / oz,
iy = (my - current.y) / oz,
nx = ix * nz,
ny = iy * nz,
cx = mx - nx,
cy = my - ny
;
current.zoom = nz;
current.x = cx;
current.y = cy;
con.style.transform
= 'translate3D('+cx+'px, '+cy+'px,0) '
+ 'scale('+nz+')'
;
};
#container {
position: absolute;
left: 20px;
top: 20px;
width: 100%;
height: 100%;
transform-origin: 0 0 0;
transition: transform 0.3s;
transition-timing-function: ease-in-out;
transform: translate3D(0,0,0) scale(1);
}
#item {
position: absolute;
}
<div id="container">
<div id="item">
<img src="http://fadili.users.greyc.fr/demos/WaveRestore/EMInpaint/parrot_original.png" />
</div>
</div>
更新
我已经更新了我的回答(以及上面的代码片段),以考虑到您的额外要求,您只需修改计算以包括鼠标指针偏移量的差异。
http://jsfiddle.net/fxpc5rao/33/
现在每次点击时,会添加计算出的未缩放位置和e.clientX,e.clientY
之间的差异。这为您提供了保持缩放翻译围绕鼠标指针发生的偏移量所需的偏移量。关键更改如下:
cx = (ix + (e.clientX - ix) - nx),
cy = (iy + (e.clientY - iy) - ny)
注意:如果您依赖于e.clientX
和e.clientY
,则会发现如果您将#container
移动到其当前0,0
坐标之外,将会出现烦人的偏移。虽然可以这样做,但您必须修改计算以使坐标定位到#container
最终所在的任何位置。
更新2
很好的建议@Basj,我不知道变换是按相反的顺序进行的,我会从你的评论中添加链接:
CSS3变换顺序很重要:最右侧的操作优先
因此,正如您所说,您需要在处理术语中先进行缩放,然后才进行平移,但是在实际的转换值中,需要先编写平移,然后再编写缩放 — 如果这有意义:)仍然不确定为什么一次在另一次之前执行会导致奇怪的插值。
此外,我还注意到一个非常明显的优化—我相信,由于您正在实施此操作,您将已经注意到—没有必要添加只会稍后再减去的内容。我猜那天我只是过了太多的节日愉悦!
cx = e.clientX - nx,
cy = e.clientY - ny
更新3
@jdavies,没问题,只需要将你的鼠标坐标转换为相对于容器左上角的坐标即可。如何计算这个偏移量完全取决于你的项目(使用类似 jQuery.offset 这样的工具可以更轻松地获取图层的偏移量-跨浏览器)。然而,我已经更新了这个答案中的代码,考虑到了一个硬编码/固定偏移量,采用了绝对定位,以示例说明。这里也更新了一个 fiddle:
http://jsfiddle.net/fxpc5rao/5/
由于我们使用的是 clientX
和 clientY
,鼠标坐标将始终从浏览器窗口的左上角计算,使它们成为页面全局坐标(与滚动无关)。要将其本地化为容器,则只需减去容器的 x 和 y 位置即可。
Container at 0,0 Container at 80,100
+------+------- screen x 0 +--------------- 0
| | |
| | | +------+
| x | <-- mouse click | |x | <-- mouse click
+------+ at 100,120 | | | at 100,120
| | | | but relative
| | +------+ 20,20
| | so we us 20,20
0 screen y 0
#container
可以包含在其他元素中,但您需要考虑这些元素给 #container
的任何位置偏移。在下面的示例中,有一个 #page-setting
元素,它通过边距来对一切进行偏移,只要使用边距值更新 ox, oy
变量,一切都应该正常工作。
http://jsfiddle.net/fxpc5rao/34/
注意: 如果您将此系统放置在可滚动页面中,则还需要将 视口的滚动偏移量 添加到鼠标坐标中,我在此提供了一个示例,但这很可能不是全浏览器解决方案。更好的做法是使用像 jQuery 这样的已建立库来为您计算坐标和偏移量。
transform-origin
,但没有成功,这让我了解到仿射变换的组合可能会很棘手:如果将一个因子为k的仿射缩放与一个因子为1/k的仿射缩放组合起来,结果并不是仿射缩放,而是平移等操作。(这让我写出了一些可怕的代码,只能有一半的时间正常工作) - Basjscale3d
http://jsfiddle.net/zpb5jxzw/ 有些效果 - Vitorino fernandestransition-property: none
;(2)仅应用translate
变换;(3)设置transition-property: all
;(4)更新scale
变换。如果转换仍然存在,请尝试在第三步后触发一次回流。 - Amir Nissim