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.
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?
The CoffeeScript (#test-resize
is a div
with a background image)
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
The zoom property in CSS allows you to scale your content. It is non-standard, and was originally implemented only in Internet Explorer. Although several other browsers now support zoom, it isn't recommended for production sites. .zoom { zoom: 150%; }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With