Skip to content

Latest commit

 

History

History
104 lines (69 loc) · 8.12 KB

igesture.md

File metadata and controls

104 lines (69 loc) · 8.12 KB

How I came to write iGesture

As mentioned, I have been working on a personal project, a Go server. I recently extracted iGesture, an event-driven model for supporting gestures (like swiping the screen) from my Go server. Here's how that came about. I hope you find it interesting.

I started the UI for my Go application on jQTouch, an excellent framework for writing iPhone applications using HTML, CSS, and JQuery. One of the nice things about jQTouch is that it provides the swipe custom event for a common gesture, swiping. I like using gestures on the iPhone because screen space is very limited. Visible affordances like buttons take away from space to display valuable information like a game board. Furthermore, because of Fitts' Law, making the affordances smaller makes them harder to use.

Gestures are the ultimate trade-off in favour of making commands highly usable, because you can use the entire screen. They also give you the maximum amount of screen real estate for information, because you don't need to display controls. They do so by providing the absolute minimum in discoverability, because there is no clue that anything will happen if you swipe the screen or perform some other gesture.

How is a user to know that swiping the screen from left to right displays the previous board position? In my Go interface, I can't solve this problem but I do provide some hints to help the user remember what the gestures do when they try them: I animate the result. For example, I animate a slide when the user swipes horizontally, providing a spatial navigation metaphor suggesting that they are "moving backwards and forwards in time." If swiping downwards reveals game info, you can likewise animate the info sliding down from the top to cover the current game board. Users will quickly guess that a swipe up will slide the game info back upwards.

Sliding something to cover something else suggests modality. Sliding the current thing out while sliding something else in suggests an infinite ribbon of information with some sort of scalar relationship along the axis of movement. Or so I rationalize my design to myself.

jQTouch provides a simple event model. You get the one swipe event, and you examine it for direction. Here's some of the code was using at the time:

var swiper = function(event, data) {
  if (data.direction == 'left') {
    swipeBoardLeft(event.currentTarget);
    return false;
  }
  else {
    swipeBoardRight(event.currentTarget);
    return false;
  }
};

...

elements.bind('swipe', swiper);

As I grew more ambitious, I quickly exhausted jQTouch's built-in gesture support, and I had little stomache for rolling my own from scratch. I went looking and found jGesture, a JQuery plugin that used a callback model. With jGesture, you could attach callbacks to DOM elements and your function would be passed a special gesture object when the user did something like swipe the screen or draw a circle with their finger. Here are two such gestures, the "close," (so named because it is often used to dismiss dialogs), and the "rotate:"

Gestures

With jGesture, you ask the gesture for its name and decide what to do based on the answer. It works like a charm. Here's how the code to handle swipes looks with jGesture:

var gesturer = function (gs) {
	if (gs.getName() == 'left') {
		return swipeBoardLeft(this);
	}
	else if (gs.getName() == 'right') {
		return swipeBoardRight(this);
	}
	return true;
};

...

elements.gesture(gesturer);

Like jQTouch, you have to examine what you get to figure out what to do. Unlike jQTouch, you get lots more gestures. I quickly decided I wanted to use the "close" gesture to close any dialogs that appeared in my application. (There's also a close button, but I was gesture-happy).

It took about ten seconds to realize that I didn't like the callback model for this. I wanted events just like jQTouch and, incidentally, just like JavaScript usually works, like mouseup: You handle that with .bind, not by calling a special mouse handling callback registrar.

So I wrote a little doohicky that would call .gesture and in turn would trigger custom events. My theory was that by extracting this code into its own file, you could include it alongside jGesture to get an event-driven model. Then you could write code that looked like this:

$('.message.wants_close').bind('gesture_close', function (event) {
	message_dialog_instance.dialog("close");
	return false;
});

And presto, every message dialog would handle a gesture_close event by closing itself. So... At this point I had:

  1. Touch events generated by the browser
  2. jGesture created a callback-based abstraction for touch events
  3. My doohicky created an event-based abstraction for the callback-based abstraction for touch events.

As Alan Perlis noted, "Every problem can be solved by creating another layer of abstraction, except for the problem of having too many layers of abstraction."

I contacted Nico Goeminne, the author of jGesture, and he had no problem with my creating a derivative work. Its Apache license obviously permits such an action, but I contacted Nico: Maybe he was working on the very same idea, maybe he'd want such a thing rolled into jGesture. As it happens, he has moved on to other interesting projects with his students, and he was ok with a new work.

This brings me up to date. I have just released iGesture, a substantial modification of jGesture to generate events "from the ground up." Like jGesture, it's a jQuery plugin. And like jQTouch, you handle everything with events.

It goes further, by having events for each different gesture. So you don't have to handle a swipe and then write a big set of cascading if statements once you figure out which direction has been swiped. If you want a swipe to the left, you bind your handler to gesture_left. iGesture supports all of jGesture's named events plus some new ones. So far, in addition to swipes in any direction, circles, close, and various combinations of consecutive directions, iGesture also supports:

  1. Rotation and pinching on Mobile Safari (rotate and scale).
  2. scrub, a back-and-forth wiping similar to the gesture the Apple Newton used to discard things.

iGesture has a demo called Naughts and Crosses that demonstrates gestures on a modern browser or iPhone. Draw an X (see the diagram above) to create a cross, a circle to create a naught, scrub to wipe the board clean, and you can even rotate the board using multi-touch on an iPhone.

Naughts and Crosses

The README explains how all these gestures are supported with essentially six lines of code. And if you want to see how I'm using iGesture in my Go server's iPhone UI, help yourself :-) I hope you like it.


NEW! Kestrels, Quirky Birds, and Hopeless Egocentricity, all of my writing about combinators, collected into one conevnient and inexpensive e-book!


(Spot a bug or a spelling mistake? This is a Github repo, fork it and send me a pull request!)

Reg Braithwaite | @raganwald