var current = {x: 0,y: 0,zoom: 1},c = document.getElementById('container'); window.onclick = function(e) { wx = current.x + e.clientX / current.zoom; wy = current.y + e.clientY / current.zoom; var coef = e.ctrlKey ? 0.5 : 2; current.zoom *= coef; current.x = wx - e.clientX / current.zoom; current.y = wy - e.clientY / current.zoom; c.style.transform = 'scale(' + current.zoom +') translate(' + (-current.x) + 'px,' + (-current.y) + 'px)'; };
html,body { margin: 0; padding: 0; overflow: hidden; min-height: 100%; } #container { position: absolute; transform-origin: 0 0; transition-duration: 3s;} #item { position: absolute; left:0px; top:0px; }
<div id="container"><div id="item"><img src="http://fadili.users.greyc.fr/demos/WaveRestore/EMInpaint/parrot_original.png"></img></div></div>
唯一的问题是转换是奇怪的,就像首先翻译然后缩放一样;它产生一个奇怪的之字形效果.在这种情况下如何有一个顺利的CSS3转换?
看到动画GIF这里奇怪的过渡效应:http://gget.it/zf3fmwum/weirdtransition.gif
注意:点击的点是缩放变换的一个固定点(例如:点击眼睛,图像缩放,光标仍然在眼睛上),就像在GoogleMaps-doubleclick-zooming中一样.
解决方法
这是一篇有趣的文章:
https://staff.washington.edu/fmf/2011/07/15/css3-transform-attribute-order/
我无法修复您的版本,主要是因为当您切换转换顺序时意外地错误.基本上看来,您正在遇到奇怪的行为,因为规模本身会导致自动翻译的位置,然后您也会翻译…似乎这些不同的翻译以稍微不同的速度发生.
然而,我重新实现了一个有效的版本,并允许您在缩放之前进行翻译.保持这个顺序的转换似乎避免了这个问题.
http://jsfiddle.net/fxpc5rao/32/
我已经修改了下面的版本来使用translate3D,因为它对许多系统表现更好.
var current = {x: 0,con = document.getElementById('container'); window.onclick = function(e) { var coef = e.shiftKey || e.ctrlKey ? 0.5 : 2,oz = current.zoom,nz = current.zoom * coef,/// offset of container ox = 20,oy = 20,/// mouse cords mx = e.clientX - ox,my = e.clientY - oy,/// calculate click at current zoom ix = (mx - current.x) / oz,iy = (my - current.y) / oz,/// calculate click at new zoom nx = ix * nz,ny = iy * nz,/// move to the difference /// make sure we take mouse pointer offset into account! cx = mx - nx,cy = my - ny ; // update current current.zoom = nz; current.x = cx; current.y = cy; /// make sure we translate before scale! 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) 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)
NOTE: Because you are relying on
e.clientX
ande.clientY
you will find annoying offseting will occur if you move#container
away from its current0,0
coordinate. This can be done,but you will have to modify your calculations to localise the coordinates to whatever#container's
location ends up being.
更新2
好的电话@Basj,我不知道转换发生在相反的顺序,我会从你的评论添加链接在这里:
CSS3 transform order matters: rightmost operation first
所以如你所说,你需要在处理术语的翻译之前发生比例,但是在实际变换值中的缩放之前要翻译的翻译 – 如果这是有道理的:)仍然不完全确定为什么在其他结果之前做一个然而在奇数插值.
此外,我注意到有一个相当明显的优化 – 我相信,当你实现这一点时,你会发现 – 没有必要添加一些东西以减去它.我想我那天刚刚过了欢乐的欢呼声!
cx = e.clientX - nx,cy = e.clientY - ny
更新3
没有问题@jdavies,它只是一个转换你的鼠标坐标,所以它们是相对于容器的左上角的问题.如何计算此偏移量将完全取决于您的项目(使用像jQuery.offset这样的东西,获得图层的偏移量 – 跨浏览器要容易得多).然而,我已经更新了这个答案中的代码,以考虑到使用位置绝对的0,0的硬编码/固定偏移量 – 仅仅是为了说明.这是一个更新的小提琴:
http://jsfiddle.net/fxpc5rao/5/
当我们使用clientX和clientY时,鼠标坐标将始终从浏览器窗口的左上角计算出来,使其全局到页面(disregarding scrolling).为了将它们本地化到容器,您只需要减去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元素,它将利用margin来抵消所有的一切,只要ox,oy变量用所有应该行为的margin值更新.
http://jsfiddle.net/fxpc5rao/34/
NOTE: If you place this system inside a scrollable page you will also need to add the 07008 to the mouse coordinates,I give an example here,but this is most likely not a full cross browser solution. You are better off looking at an established library like jQuery to calculate coordinates and offsets for you.