Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pinch to zoom with CSS3

Tags:

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 
like image 817
Maros Avatar asked May 29 '12 15:05

Maros


People also ask

What is * Zoom in CSS?

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%; }


1 Answers

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.

like image 123
Maros Avatar answered Sep 17 '22 19:09

Maros