From f1c64f4825c1aafb6eb398e406e47dde6bf6c0cb Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Wed, 4 Dec 2013 20:54:43 -0800 Subject: [PATCH] start of a working pinch/rotate impl --- build.json | 1 + pointergestures.js | 1 + src/pinch.js | 109 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 src/pinch.js diff --git a/build.json b/build.json index 8ff2f1c..786f1a5 100644 --- a/build.json +++ b/build.json @@ -7,5 +7,6 @@ "src/hold.js", "src/track.js", "src/flick.js", + "src/pinch.js", "src/tap.js" ] diff --git a/pointergestures.js b/pointergestures.js index 0b27094..e32359c 100644 --- a/pointergestures.js +++ b/pointergestures.js @@ -18,6 +18,7 @@ 'src/hold.js', 'src/track.js', 'src/flick.js', + 'src/pinch.js', 'src/tap.js' ]; diff --git a/src/pinch.js b/src/pinch.js new file mode 100644 index 0000000..0727c67 --- /dev/null +++ b/src/pinch.js @@ -0,0 +1,109 @@ +/* + * Copyright 2013 The Polymer Authors. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +/* + * Basic strategy: find the farthest apart points, use as diameter of circle + * react to size change and rotation of the chord + */ + +(function(scope) { + var dispatcher = scope.dispatcher; + var pointermap = new scope.PointerMap(); + var RAD_TO_DEG = 180 / Math.PI; + var pinch = { + events: [ + 'pointerdown', + 'pointermove', + 'pointerup', + 'pointercancel' + ], + reference: {}, + pointerdown: function(ev) { + pointermap.set(ev.pointerId, ev); + if (pointermap.pointers() == 2) { + var points = this.calcChord(); + var angle = this.calcAngle(points); + this.reference = { + angle: angle, + diameter: points.diameter, + target: scope.findLCA(points.a.target, points.b.target) + }; + } + }, + pointerup: function(ev) { + pointermap.delete(ev.pointerId); + }, + pointermove: function(ev) { + if (pointermap.has(ev.pointerId)) { + pointermap.set(ev.pointerId, ev); + if (pointermap.pointers() > 1) { + this.calcPinchRotate(); + } + } + }, + pointercancel: function(ev) { + this.pointerup(ev); + }, + dispatchPinch: function(diameter, target) { + var zoom = diameter / this.reference.diameter; + var ev = dispatcher.makeEvent('pinch', { + scale: zoom + }); + dispatcher.dispatchEvent(ev, this.reference.target); + }, + dispatchRotate: function(angle) { + var diff = Math.round((angle - this.reference.angle) % 360); + var ev = dispatcher.makeEvent('rotate', { + angle: diff + }); + dispatcher.dispatchEvent(ev, this.reference.target); + }, + calcPinchRotate: function() { + var points = this.calcChord(); + var diameter = points.diameter; + var angle = this.calcAngle(points); + if (diameter != this.reference.diameter) { + this.dispatchPinch(diameter); + } + if (angle != this.reference.angle) { + this.dispatchRotate(angle); + } + }, + calcChord: function() { + var pointers = []; + pointermap.forEach(function(p) { + pointers.push(p); + }); + var dist = 0; + var points = {}; + var x, y, d; + for (var i = 0; i < pointers.length; i++) { + var a = pointers[i]; + for (var j = i + 1; j < pointers.length; j++) { + var b = pointers[j]; + x = Math.abs(a.clientX - b.clientX); + y = Math.abs(a.clientY - b.clientY); + d = x + y; + if (d > dist) { + dist = d; + points = {a: a, b: b}; + } + } + } + x = Math.abs(points.a.clientX - points.b.clientX / 2); + y = Math.abs(points.a.clientY - points.b.clientY / 2); + points.center = { x: x, y: y }; + points.diameter = dist; + return points; + }, + calcAngle: function(points) { + var x = points.a.clientX - points.b.clientX; + var y = points.a.clientY - points.b.clientY; + return (360 + Math.atan2(y, x) * RAD_TO_DEG) % 360; + }, + }; + dispatcher.registerRecognizer('pinch', pinch); +})(window.PointerGestures);