Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
218 lines (185 sloc) 6.66 KB
<!--
Goal: benchmark multi-touch on many different devices.
- test which touch events are fired on what platforms
- test event firing resolution
- test which attributes touch events have
-->
<!doctype html>
<head>
<title>Multi-touch Feature Test</title>
<meta name="viewport" content="width=device-width, user-scalable=no">
<style>
body {margin: 0; overflow: hidden; width: 100%; height: 100%;}
.touchable {position: absolute; z-index: 99;}
#obj1 {left: 0px; bottom: 0px; background: red;}
#obj2 {right: 0px; bottom: 0px; background: green;}
</style>
</head>
<body>
<ul id="instructions">
</ul>
<canvas id="obj1" class="touchable" width="200" height="200"></canvas>
<canvas id="obj2" class="touchable" width="200" height="200"></canvas>
<div id="report">
<li>
Test: single touch. Touch red and draw stuff. Expect touchstart, touchmoves and touchend
</li>
<li>
Test: single touch entering and leaving. Touch body, drag through red. Expect touchenter and touchleave to be fired on red
</li>
<li>
Test: multi touch events. Touch red, then touch green, then move green, then move red, then remove fingers. Expect a bunch of events!
</li>
<button id="summarize" onclick="javascript:summarize()">summarize</button>
<br/>
</div>
<object id="tuio" type="application/x-tuio" style="width: 0px; height: 0px;">
Touch input plugin failed to load!
</object>
<script src="magictouch.js"></script>
<script>
var OBJECTS = ['obj1', 'obj2'];
// Constants according to spec
var EVENTS = ['touchstart', 'touchend', 'touchmove', 'touchenter', 'touchleave', 'touchcancel'];
var EVENT_PROPERTIES = ['touches', 'targetTouches', 'changedTouches'];
var EVENTLIST_PROPERTIES = ['identifier', 'target', 'timestamp', 'screenX',
'screenY', 'clientX', 'clientY', 'pageX', 'pageY', 'radiusX', 'radiusY',
'rotationAngle', 'force', 'altKey', 'metaKey', 'ctrlKey', 'shiftKey'];
// Data to collect
// Touchmove firing resolution
var resolution = [];
// Attributes touch events have
// mA['eventName'] = ['prop1', 'prop2', ...]
var supportedEventProps = {};
var supportedTouchProps = {};
// Helper variables
var lastMoveTime = 0;
// Assign event listeners for all events to all objects
for (var i = 0; i < OBJECTS.length; i++) {
var obj = document.getElementById(OBJECTS[i]);
(function(o) {
for (var j = 0; j < EVENTS.length; j++) {
var eventName = EVENTS[j];
//console.log('bound ' + eventName);
(function(event, eventName) {
o.addEventListener(eventName, function(event) {
console.log(eventName + ' fired on ' + event.target.id);
analyzeEvent(event, eventName);
});
})(event, eventName);
}
// Also track resolution
o.addEventListener('touchmove', function(event) {
var now = new Date();
if (lastMoveTime) {
resolution.push(now - lastMoveTime);
}
lastMoveTime = now;
});
makeDrawable(o);
//makeDraggable(o);
})(obj);
}
function summarize() {
var r = document.getElementById('report');
r.innerHTML = '';
// Show summary of everything
// Get average touchmove resolution
var averageResolution = resolution.sum() / resolution.length;
report('<strong>average touchmove resolution</strong>: ' + averageResolution);
// Show which touch events fire
report('<strong>touch events:</strong> ' + supportedEventProps.keys());
// For each touch event, show which properties it has
for (var k in supportedEventProps) {
if (supportedEventProps.hasOwnProperty(k)) {
report('<strong>' + k + ' event properties:</strong> ' + supportedEventProps[k]);
report('<strong>touch properties:</strong> ' + supportedTouchProps[k]);
}
}
}
function report(message) {
var report = document.getElementById('report');
report.innerHTML += message + '<br/>';
}
function analyzeEvent(event, eventName) {
// Ensure eventName is in the missingProps
if (! supportedEventProps.hasOwnProperty(eventName)) {
supportedEventProps[eventName] = [];
}
if (! supportedTouchProps.hasOwnProperty(eventName)) {
supportedTouchProps[eventName] = [];
}
// Check if the event has properties
for (var i = 0; i < EVENT_PROPERTIES.length; i++) {
var prop = EVENT_PROPERTIES[i];
if (prop in event) {
supportedEventProps[eventName].pushUnique(prop);
}
}
if ('touches' in event && event.touches.length > 0) {
// Get a touch from the list and
var touch = event.touches[0];
// Check if the properties are meaningful
for (var i = 0; i < EVENTLIST_PROPERTIES.length; i++) {
var prop = EVENTLIST_PROPERTIES[i];
if (prop in touch) {
supportedTouchProps[eventName].pushUnique(prop);
}
}
}
}
Array.prototype.sum = function() {
var out = 0;
for (var i = 0; i < this.length; i++) {
out += this[i];
}
return out;
}
Array.prototype.pushUnique = function(val) {
if (this.indexOf(val) === -1) {
this.push(val);
}
};
Object.prototype.keys = function() {
var out = [];
for (var k in this) {
if (this.hasOwnProperty(k)) {
out.push(k);
}
};
return out;
}
function makeDrawable(obj) {
var ctx = obj.getContext('2d');
var isDrawing = false;
obj.addEventListener('touchstart', function(event) {
isDrawing = true;
var touch = event.targetTouches[0];
ctx.moveTo(touch.pageX - obj.offsetLeft, touch.pageY - obj.offsetTop);
});
obj.addEventListener('touchend', function(event) {
isDrawing = false;
ctx.stroke();
});
obj.addEventListener('touchmove', function(event) {
event.preventDefault();
if (!isDrawing) {
return;
}
var touch = event.targetTouches[0];
ctx.lineTo(touch.pageX - obj.offsetLeft, touch.pageY - obj.offsetTop);
ctx.stroke();
});
}
function makeDraggable(obj) {
var isMoving = false;
obj.addEventListener('touchstart', function(event) { isMoving = true; });
obj.addEventListener('touchend', function(event) { isMoving = false; });
obj.addEventListener('touchmove', function(event) {
var touch = event.targetTouches[0];
obj.style.left = touch.pageX + 'px';
obj.style.top = touch.pageY + 'px';
});
}
</script>
</body>