Javascript 使用 CSS3 捏合缩放

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10802176/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 02:59:42  来源:igfitidea点击:

Pinch to zoom with CSS3

javascriptjquerycsstouchcoffeescript

提问by Maros

I'm trying to implement pinch-to-zoom gestures exactly as in Google Maps. I watched a talk by Stephen Woods - "Creating Responsive HTML5 Touch Interfaces”- about the issue and used the technique mentioned. The idea is to set the transform origin of the target element at (0, 0) and scale at the point of the transform. Then translate the image to keep it centered at the point of transform.

我正在尝试像在 Google 地图中一样实现双指缩放手势。我观看了 Stephen Woods 的演讲 - “Creating Responsive HTML5 Touch Interfaces”- 关于这个问题并使用了提到的技术。这个想法是将目标元素的变换原点设置为 (0, 0) 并在该点进行缩放变换。然后平移图像以使其保持在变换点的中心。

In my test code scaling works fine. The image zooms in and out fine between subsequent translations. The problem is I am not calculating the translation values properly. I am using jQuery and Hammer.js for touch events. How can I adjust my calculation in the transform callback so that the image stays centered at the point of transform?

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

The CoffeeScript (#test-resizeis a divwith a background image)

所述的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

采纳答案by Maros

I managed to get it working.

我设法让它工作。

jsFiddle demo

jsFiddle 演示

In the jsFiddle demo, clicking on the image represents a pinch gesture centred at the click point. Subsequent clicks increase the scale factor by a constant amount. To make this useful, you would want to make the scale and translate computations much more often on a transform event (hammer.js provides one).

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

The key to getting it to work was to correctly compute the point of scale coordinates relative to the image. I used event.clientX/Yto get the screen coordinates. The following lines convert from screen to image coordinates:

让它工作的关键是正确计算相对于图像的比例点坐标。我曾经event.clientX/Y得到屏幕坐标。以下几行将屏幕坐标转换为图像坐标:

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

Then we compute a new size for the image and find the distances to translate by. The translation equation is taken from Stephen Woods' talk.

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

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

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

Finally, we scale and translate

最后,我们缩放和翻译

image.css '-webkit-transform', "scale3d(#{scale}, #{scale}, 1)"         
wrap.css '-webkit-transform', "translate3d(#{newX}px, #{newY}px, 0)"

We do all our translations on a wrapper element to ensure that the translate-origin stays at the top left of our image.

我们在包装元素上进行所有翻译,以确保 translate-origin 保持在图像的左上角。

回答by Raphael Toselli

I successfully used that snippet to resize images on phonegap, using hammer and jquery.

我使用锤子和 jquery 成功地使用该片段调整了 phonegap 上的图像大小。

If it interests someone, i translated this to JS.

如果有人感兴趣,我将其翻译为 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;
    });

}

回答by Andrei Cristian Prodan

I looked all over the internet, and outernet whatever, until I came across the only working plugin/library - http://cubiq.org/iscroll-4

我查看了整个互联网和外网,直到我遇到了唯一可用的插件/库 - http://cubiq.org/iscroll-4

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

where wrapper is your id as in id="wrapper"

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

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

回答by Ideogram

Not a real answer, but a link to a plug=in that does it all for you. Great work!

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

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

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

(Thanks 'Timmywil', who-ever you are)

(感谢 'Timmywil',无论你是谁)

回答by Isaac

This is something I wrote a few years back in Java and recently converted to JavaScript

这是我几年前用 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;
 }
}

The this.Zoom = function(delta,x,y)takes:

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

  • delta= zoom in or out
  • x= x position of the zoom origin
  • y= y position of the zoom origin
  • delta= 放大或缩小
  • x= 缩放原点的 x 位置
  • y= 缩放原点的 y 位置

A small example:

一个小例子:

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

This was made with the intention of being used with a canvas and graphics, but it should work perfectly for normal HTML layout

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