使用CSS3变换缩放比例缩放

即使下面的代码片段看起来很短,我在几天内挣扎(耻辱我!)找到一种放大点击使用 CSS3变换点的方法.它现在工作:
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 and e.clientY you will find annoying offseting will occur if you move #container away from its current 0,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.

相关文章

Css3如何实现鼠标移上变长特效?(图文+视频)
css3怎么实现鼠标悬停图片时缓慢变大效果?(图文+视频)
jquery如何实现点击网页回到顶部效果?(图文+视频)
css3边框阴影效果怎么做?(图文+视频)
css怎么实现圆角边框和圆形效果?(图文+视频教程)
Css3如何实现旋转移动动画特效