gpjt/webgl-lessons — pull request #10 by codecurve (2013-07-18 03:08:00+00:00)
Title: Make example work on touch screen as well.

I've only tested touch interaction on Firefox and Google Chrome, both on Android on a Samsung Galaxy S3.
Testing of mouse interaction done on MacOS: Safari, Chrome, Firefox, and seems to work as before.

The tutorial text would need to be updated, here is a suggestion:
Title: WebGL Lesson 11 – spheres, rotation matrices, and mouse __and touch__ events.

First paragraph:
... which the viewer can spin around using the mouse __or touch screen__.

First code snippet:
Remove:
```javascript
document.onmouseup = handleMouseUp;
```
Replace with:
```javascript
document.onmouseup = handleMouseUpOrTouchEnd;
```
Then, after:
```javascript
document.onmousemove = handleMouseMove;
```
Insert, also in red:
```javascript
canvas.addEventListener("touchstart", handleTouchStart, false);
canvas.addEventListener("touchend", handleMouseUpOrTouchEnd, false);
canvas.addEventListener("touchcancel", handleMouseUpOrTouchEnd, false);
canvas.addEventListener("touchleave", handleMouseUpOrTouchEnd, false);
canvas.addEventListener("touchmove", handleTouchMove, false);
```

In the paragraph just after the code snippet:
Change "These three new lines allow us to ..." to "__The first three lines of these__ new lines allow us to ..."

After that paragraph, insert:
__The next 6 lines of the new lines set-up the handling of touch screen events, which are similar in many ways to mouse events. For more information on handling touch events in conjunction with mouse events, see
https://developer.mozilla.org/en-US/docs/Web/Guide/DOM/Events/Touch_events. In a nutshell, we only want to process touch events for touches that originated on the canvas, and for touches this means attaching all callbacks to the canvas. Note that there are 3 ways the touch can end.

Paragraph starting "Immediately above the initBuffers ...":
Change first line: Immediately above the initBuffers function are the __six__ functions that deal with the mouse __and touches__.

Next paragraph:
Change " When the user drags the mouse around, we get a sequence of mouse-move events"
to
" When the user drags the mouse __(or touch location)__ around, we get a sequence of mouse-move __(or touch-move)__ events"

Insert the following paragraph just before "So, with all that explained, the code below should be pretty clear:":
"Handling touch events are similar to handling mouse events. The touch event handlers for touch-start and touch-move call evt.preventDefault() since otherwise a mouse event is also processed. Touch-end and mouse-up use the same callback. Too keep things simple, this example also tries to avoid having to handle multi-touch gestures on the canvas, although some cool multi-touch interactions are easy to imagine. It does this by checking that the number of touches is 1, and that the touch id matches the one that has been used since the touch started."

Change the code snippet that follows to the new (almost identical) code:
```javascript
var mouseDownOrTouchActive = false;
var lastMouseX = null;
var lastMouseY = null;
var touchId = null;

var moonRotationMatrix = mat4.create();
mat4.identity(moonRotationMatrix);

function handleMouseDown(event) {
mouseDownOrTouchActive = true;
lastMouseX = event.clientX;
lastMouseY = event.clientY;
}

function handleTouchStart(evt) {
evt.preventDefault();
var touches = evt.targetTouches;

if (touches.length == 1 && !mouseDownOrTouchActive ) {
touchId = touches[0].identifier;
lastMouseX = touches[0].pageX,
lastMouseY = touches[0].pageY;
}
}

function handleMouseUpOrTouchEnd(event) {
mouseDownOrTouchActive = false;
}

function handleMouseMove(event) {
if (!mouseDownOrTouchActive) {
return;
}
var newX = event.clientX;
var newY = event.clientY;

processDrag(newX, newY);
}

function handleTouchMove(evt) {
evt.preventDefault();
var touches = evt.targetTouches;

if (touches.length == 1 && touchId == touches[0].identifier) {
var newX = touches[0].pageX;
var newY = touches[0].pageY;
processDrag(newX, newY);
}
}

function processDrag(newX, newY) {
var deltaX = newX - lastMouseX
var newRotationMatrix = mat4.create();
mat4.identity(newRotationMatrix);
mat4.rotate(newRotationMatrix, degToRad(deltaX / 10), [0, 1, 0]);

var deltaY = newY - lastMouseY;
mat4.rotate(newRotationMatrix, degToRad(deltaY / 10), [1, 0, 0]);

mat4.multiply(newRotationMatrix, moonRotationMatrix, moonRotationMatrix);

lastMouseX = newX
lastMouseY = newY;
}
```