Pinch to Zoom with CSS3

Pinch to zoom with CSS3

I managed to get it working.

jsFiddle demo

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

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

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.

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.

Zooming on a point with CSS3 transform scale

One thing to watch out for when using transforms is the order that you apply them. You'll find your example works rather differently if you switch the scale and the translate around.

Here is an interesting article on the matter:

https://staff.washington.edu/fmf/2011/07/15/css3-transform-attribute-order/

I wasn't able to repair your version, mainly because it misbehaves unexpectedly when you switch the order of the transforms. Basically it seems you are running into odd behaviour because the scale itself causes an automatic translation in position, and then you also translate... and it seems these different translations are occurring at a slightly different pace.

I did however re-implement a version that works, and allows you to translate before scaling. Keeping the transforms in this order seems to avoid the issue.

http://jsfiddle.net/fxpc5rao/32/

I've modified the version below to use translate3D just because it performs better for many systems.

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

How to enable pinch-zoom only when both touches are in the same pane

The solution was to use event.targetTouches.length to detect and discard cases where the touches are not both starting in the same DOM element.

Disable Pinch Zoom on Mobile Web

EDIT: Because this keeps getting commented on, we all know that we shouldn't do this. The question was how do I do it, not should I do it.

Add this into your for mobile devices. Then do your widths in percentages and you'll be fine:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />

Add this in for devices that can't use viewport too:

<meta name="HandheldFriendly" content="true" />


Related Topics



Leave a reply



Submit