April 19, 2011

Javascript: Handle touch gestures for pinch (scale) and rotation

I wrote a little class to handle pinch & rotate gestures on a web page in iOS. There's a bunch of event listener adding/removing, which can get a little messy, so this should help keep your code clean if you need to handle gestures.

Here's the class:
function GestureCallback( element, endCallback, changeCallback ) {
  this.element = element;
  this.end_callback = endCallback;
  this.change_callback = changeCallback;
  this.scale = 1;
  this.rotation = 0;
  this.init();
}

GestureCallback.prototype.init = function() {
  // scope functions for listener removal
  var self = this;
  this.gestureStart = function(e){ self.onGestureStart(e) };
  this.gestureChange = function(e){ self.onGestureChange(e) };
  this.gestureEnd = function(e){ self.onGestureEnd(e) };
  
  // really no need to check for IE stupidness, but maybe they'll support gestures someday? oy.
  if( this.element.attachEvent ) this.element.attachEvent( "touchstart", this.gestureStart ); else this.element.addEventListener( "touchstart", this.gestureStart, false );
  if( this.element.attachEvent ) this.element.attachEvent( "gesturestart", this.gestureStart ); else this.element.addEventListener( "gesturestart", this.gestureStart, false );
};

GestureCallback.prototype.onGestureStart = function ( e ) {
  if( this.element.attachEvent ) this.element.attachEvent( "gesturechange", this.gestureChange ); else this.element.addEventListener( "gesturechange", this.gestureChange, false );
  if( this.element.attachEvent ) this.element.attachEvent( "gestureend", this.gestureEnd ); else this.element.addEventListener( "gestureend", this.gestureEnd, false );
};

GestureCallback.prototype.onGestureChange = function ( e ) {
  this.scale = e.scale;
  this.rotation = e.rotation;
  if( this.change_callback ) this.change_callback( this.scale, this.rotation );
};

GestureCallback.prototype.onGestureEnd = function ( e ) {
  if( this.element.detachEvent ) this.element.detachEvent( "gesturechange", this.gestureChange ); else this.element.removeEventListener( "gesturechange", this.gestureChange, false );
  if( this.element.detachEvent ) this.element.detachEvent( "gestureend", this.gestureEnd ); else this.element.removeEventListener( "gestureend", this.gestureEnd, false );

  this.scale = e.scale;
  this.rotation = e.rotation;
  if( this.end_callback ) this.end_callback( this.scale, this.rotation );
};

GestureCallback.prototype.dispose = function() {
  if( this.element.attachEvent ) this.element.detachEvent( "touchstart", this.gestureStart ); else this.element.removeEventListener( "touchstart", this.gestureStart, false );
  if( this.element.attachEvent ) this.element.detachEvent( "gesturestart", this.gestureStart ); else this.element.removeEventListener( "gesturestart", this.gestureStart, false );
  
  this.element = null;
  this.end_callback = null;
  this.change_callback = null;
  
  this.gestureStart = null;
  this.gestureChange = null;
  this.gestureEnd = null;
};
And the instantiation:
var pinchCallback = new GestureCallback( yourElement, function( scale, rotation ){
  console.log('done: '+scale+','+rotation);
  if( scale < 1 ) {
    // leave the section, since we've pinched it closed
  }
}, function( scale, rotation ){
  console.log('changing: '+scale+','+rotation);
});
And when you're done with your gesture needs, collect your garbage:
pinchCallback.dispose();
pinchCallback = null;

No comments:

Post a Comment