使用 CSS3 进行缩放

Posted

技术标签:

【中文标题】使用 CSS3 进行缩放【英文标题】:Pinch to zoom with CSS3 【发布时间】:2012-06-03 20:31:45 【问题描述】:

我正在尝试实现与 Google 地图中完全相同的捏合缩放手势。我观看了 Stephen Woods 的演讲 - "Creating Responsive html5 Touch Interfaces” - 关于这个问题并使用了提到的技术。这个想法是将目标元素的变换原点设置在 (0, 0) 并在变换点处缩放。然后平移图像以使其保持在变换点的中心。

在我的测试代码缩放工作正常。图像在后续翻译之间放大和缩小。问题是我没有正确计算翻译值。我正在使用 jQuery 和 Hammer.js 来处理触摸事件。如何在转换回调中调整我的计算,以使图像保持在转换点的中心?

CoffeeScript(#test-resize 是带有背景图像的div

image = $('#test-resize')

hammer = image.hammer ->
  prevent_default: true
  scale_treshold: 0

width = image.width()
height = image.height()
toX = 0
toY = 0
translateX = 0
translateY = 0
prevScale = 1
scale = 1

hammer.bind 'transformstart', (event) ->

  toX = (event.touches[0].x + event.touches[0].x) / 2
  toY = (event.touches[1].y + event.touches[1].y) / 2

hammer.bind 'transform', (event) ->

  scale = prevScale * event.scale
  shiftX = toX * ((image.width() * scale) - width) / (image.width() * scale)
  shiftY = toY * ((image.height() * scale) - height) / (image.height() * scale)
  width = image.width() * scale
  height = image.height() * scale

  translateX -= shiftX
  translateY -= shiftY

  css = 'translateX(' + @translateX + 'px) translateY(' + @translateY + 'px) scale(' + scale + ')'
  image.css '-webkit-transform', css
  image.css '-webkit-transform-origin', '0 0'

hammer.bind 'transformend', () ->
  prevScale = scale

【问题讨论】:

【参考方案1】:

我设法让它工作。

jsFiddle demo

在 jsFiddle 演示中,单击图像表示以单击点为中心的捏合手势。随后的点击将比例因子增加一个常数。为了使它有用,您可能希望在转换事件上更频繁地进行缩放和转换计算(hammer.js 提供了一个)。

让它工作的关键是正确计算相对于图像的比例坐标点。我使用event.clientX/Y 来获取屏幕坐标。以下行将屏幕坐标转换为图像坐标:

x -= offset.left + newX
y -= offset.top + newY

然后我们计算图像的新尺寸并找到要平移的距离。平移方程取自Stephen Woods' talk。

newWidth = image.width() * scale
newHeight = image.height() * scale

newX += -x * (newWidth - image.width) / newWidth
newY += -y * (newHeight - image.height) / newHeight

最后,我们缩放和翻译

image.css '-webkit-transform', "scale3d(#scale, #scale, 1)"         
wrap.css '-webkit-transform', "translate3d(#newXpx, #newYpx, 0)"

我们在包装元素上进行所有翻译,以确保翻译原点位于图像的左上角。

【讨论】:

Stephen Woods 有一个非常好的观点:在使用 css 进行转换(不加载东西等)时,绝对不要在代码中做任何其他事情。对我自己的项目帮助很大。【参考方案2】:

我使用锤子和 jquery 成功地使用了 sn-p 来调整 phonegap 上的图像大小。

如果有人感兴趣,我把它翻译成 JS。

function attachPinch(wrapperID,imgID)

    var image = $(imgID);
    var wrap = $(wrapperID);

    var  width = image.width();
    var  height = image.height();
    var  newX = 0;
    var  newY = 0;
    var  offset = wrap.offset();

    $(imgID).hammer().on("pinch", function(event) 
        var photo = $(this);

        newWidth = photo.width() * event.gesture.scale;
        newHeight = photo.height() * event.gesture.scale;

        // Convert from screen to image coordinates
        var x;
        var y;
        x -= offset.left + newX;
        y -= offset.top + newY;

        newX += -x * (newWidth - width) / newWidth;
        newY += -y * (newHeight - height) / newHeight;

        photo.css('-webkit-transform', "scale3d("+event.gesture.scale+", "+event.gesture.scale+", 1)");      
        wrap.css('-webkit-transform', "translate3d("+newX+"px, "+newY+"px, 0)");

        width = newWidth;
        height = newHeight;
    );


【讨论】:

你能看懂吗? “我成功地使用了 sn-p 来调整图像大小”我从来没有提到 拖动$(imgID).hammer().on("pinch", function(event)[...] function attachPinch(wrapperID,imgID)[...]" 这是一个很棒的脚本,但对于任何想要复制它的人来说 - 请注意 (a) 它使用 Jquery 插件作为锤子,并且 (b) 您需要修改插件,因为 您必须启用锤子内的捏合以使其工作。 hamObj = new Hammer($el[0], options); hamObj.get('pinch').set( enable: true ); $el.data("锤子", hamObj);【参考方案3】:

我浏览了整个互联网,以及任何外网,直到我发现唯一可以工作的插件/库 - http://cubiq.org/iscroll-4

var myScroll;
myScroll = new iScroll('wrapper');

其中 wrapper 是您的 id,如 id="wrapper"

<div id="wrapper">
    <img src="smth.jpg" />
</div>

【讨论】:

【参考方案4】:

不是真正的答案,而是指向为您完成所有工作的插件的链接。做得好!

https://github.com/timmywil/jquery.panzoom

(谢谢'Timmywil',不管你是谁)

【讨论】:

并非所有英雄都穿着斗篷【参考方案5】:

这是我几年前用 Java 写的,最近转换成 javascript

function View()

 this.pos = x:0,y:0;
 this.Z = 0;
 this.zoom = 1;
 this.scale = 1.1;
 this.Zoom = function(delta,x,y)
 
  var X = x-this.pos.x;
  var Y = y-this.pos.y;
  var scale = this.scale;
  if(delta>0) this.Z++;
  else
  
   this.Z--;
   scale = 1/scale;
  
  this.zoom = Math.pow(this.scale, this.Z);
  this.pos.x+=X-scale*X;
  this.pos.y+=Y-scale*Y;
 

this.Zoom = function(delta,x,y) 需要:

delta = 放大或缩小 x = 缩放原点的 x 位置 y = 缩放原点的 y 位置

一个小例子:

<script>
var view = new View();
var DivStyle = x:-123,y:-423,w:300,h:200;
function OnMouseWheel(event)

 event.preventDefault();
 view.Zoom(event.wheelDelta,event.clientX,event.clientY);
 div.style.left = (DivStyle.x*view.zoom+view.pos.x)+"px";
 div.style.top = (DivStyle.y*view.zoom+view.pos.y)+"px";
 div.style.width = (DivStyle.w*view.zoom)+"px";
 div.style.height = (DivStyle.h*view.zoom)+"px";

function OnMouseMove(event)

 view.pos = x:event.clientX,y:event.clientY;
 div.style.left = (DivStyle.x*view.zoom+view.pos.x)+"px";
 div.style.top = (DivStyle.y*view.zoom+view.pos.y)+"px";
 div.style.width = (DivStyle.w*view.zoom)+"px";
 div.style.height = (DivStyle.h*view.zoom)+"px";

</script>
<body onmousewheel="OnMouseWheel(event)" onmousemove="OnMouseMove(event)">
<div id="div" style="position:absolute;left:-123px;top:-423px;width:300px;height:200px;border:1px solid;"></div>
</body>

这是为了与画布和图形一起使用而制作的,但它应该可以完美地用于正常的 HTML 布局

【讨论】:

我没有看到这个工作 - 如果没有别的,它似乎依赖鼠标滚轮而不是捏和缩放; jsfiddle.net/Abeeee/w527f6cx/5 @user1432181 好发现!这让我想起了我早期的回忆......我会看看添加触摸支持

以上是关于使用 CSS3 进行缩放的主要内容,如果未能解决你的问题,请参考以下文章

使用 CSS3 转换 scale() 缩放/缩放 DOM 元素及其占用的空间

CSS3 PIE 不能在 IE 中缩放背景图像

使用 CSS3 变换比例缩放一个点

Chrome + css3:媒体查询缩放错误

理解CSS3中的background-size(对响应性图片等比例缩放)

CSS3缩放和移动img上的动画效果