Javascript – Gesture and touch events – smoothly resize a square

gestureiosjavascriptjquerytouch

I have a blue #square vertically and horizontally centered in my viewport on my iOS device …

<div id="square"></div>
#square {
    width:100px;
    height:100px;
    background:blue;
    margin:0 auto;
}

I'd like to resize it within a min and max value when doing a pinch/zoom gesture on my phone.

Right now, this is all the javascript I'm using for it.

$(document).ready(function() {

    var dom = document.body,
        _width = parseInt($('#square').css('width')),
        vel = 3,
        min = _width,
        max = 300,
        scale;

    dom.addEventListener("gesturechange", gestureChange, false);

    function gestureChange(e) {

        e.preventDefault();

        scale = e.scale;
        _width = Math.round(_width*(scale/vel));

        if ( _width <= max && _width >= min )
            $('#square').css({
                'width' : _width + 'px',
                'height' : _width + 'px'
            });

        if ( _width > max ) _width = max;
        if ( _width < min ) _width = min;
    }


});

However, the entire reszining experience feels kind of choppy and doesn't really smoothly respond to my fingers. It does work, but not as smoothly as I want it to be.

First off. I don't really get the difference between a javascript "touch"-event and a javascript "gesture"-event. Do I need more eventListeners here? Like gestureStart and gestureEnd for this to work?

The problems I have right now is that when I zoom in the #square jumps to its max-value (300) really fast, but I can't really control its size exactly with my fingers. And when once resized I have also trouble decreasing the size again when doing a zoom-out gesture.

I put my current code on jsfiddle so you might be able to test it yourself. http://jsfiddle.net/Ec3az/

Maybe someone can help me out here as I'd love to finish this piece. The overall outcome should simply be a really smooth experience and actual control over the size of the square when zooming in and zooming out on a Smartphone.

Thank you in advance

edit: btw. I'd love to use only standard touch events and not use an additional library.

Best Answer

The problem you were having is that when you get a new gesture change event, you were scaling the current width of the square, when really you wanted to scale the original width and height of the square. Doing it your way accumulates each change in scale and causes a very quick increase in the size of the square, which is what you were experiencing.

After the zoom has finished, we also need to update the original width to the current width, so next time the user zooms, it'll scale from the correct size.

So this creates a smoother experience as it's always scaling the original width:

var dom = document.body,
    _width = parseInt($('#square').css('width')),
    vel = 5.0,
    min = _width,
    max = 300,
    scale;

dom.addEventListener("gesturechange", gestureChange, false);
dom.addEventListener("gestureend", gestureEnd, false);

function gestureChange(e) {

    e.preventDefault();

    scale = e.scale;
    var tempWidth = _width * scale;

    if (tempWidth > max) tempWidth = max;
    if (tempWidth < min) tempWidth = min;

    $('#square').css({
        'width': tempWidth + 'px',
        'height': tempWidth + 'px'
    });
}

function gestureEnd(e) {

    e.preventDefault();
    _width = parseInt($('#square').css('width'));
}

This fiddle seems to be smooth on the iPad 1, iOS 5.1.something! :)

http://jsfiddle.net/D9NC3/

Also, with regards to the gesture and touch events, I the touch events are supported in a number of browsers (android, iOS safari and Firefox it seems http://caniuse.com/#search=touch), but the gesture events as far as I know are proprietary to iOS safari. They are essentially there to help you with handling iOS type gestures (pinch and zoom, rotate etc), so you don't have to implement gesture checking yourself.

Hope it helps!

Related Topic