198 lines
4.3 KiB
JavaScript
198 lines
4.3 KiB
JavaScript
'use strict';
|
|
|
|
var $ = require('jquery');
|
|
var _ = require('lodash');
|
|
|
|
function TouchInteraction(eventBus, canvas) {
|
|
|
|
var context;
|
|
|
|
var RANGE = { min: 0.2, max: 4 };
|
|
var DOUBLE_TAP_THRESHOLD = 300; // ms
|
|
|
|
function handleTouchStart(event) {
|
|
|
|
var orgEvent = event.originalEvent ? event.originalEvent : event;
|
|
|
|
_.forEach(orgEvent.changedTouches, function (touch) {
|
|
context.start[touch.identifier] = touch;
|
|
});
|
|
|
|
if (orgEvent.touches.length === 1) {
|
|
initMove(orgEvent);
|
|
}
|
|
|
|
if (orgEvent.touches.length === 2) {
|
|
initScale(orgEvent);
|
|
}
|
|
|
|
//Stop all interaction for more than 2 touch sources
|
|
if (orgEvent.touches.length > 2) {
|
|
contextInit();
|
|
}
|
|
|
|
event.preventDefault();
|
|
}
|
|
|
|
function handleTouchMove(event) {
|
|
var orgEvent = event.originalEvent;
|
|
var cX = 0;
|
|
var cY = 0;
|
|
var mX = 0;
|
|
var mY = 0;
|
|
|
|
if (context.move && !context.scale) {
|
|
|
|
_.forEach(orgEvent.changedTouches, function (touch) {
|
|
if (touch.identifier === context.moveId) {
|
|
cX = touch.clientX;
|
|
cY = touch.clientY;
|
|
}
|
|
});
|
|
|
|
if (!context.lasttouch.cX) {
|
|
context.lasttouch.cX = cX;
|
|
}
|
|
|
|
if (!context.lasttouch.cY) {
|
|
context.lasttouch.cY = cY;
|
|
}
|
|
|
|
mX = cX - context.lasttouch.cX;
|
|
mY = cY - context.lasttouch.cY;
|
|
|
|
canvas.scroll({
|
|
dx: mX,
|
|
dy: mY
|
|
});
|
|
|
|
context.lasttouch.cX = cX;
|
|
context.lasttouch.cY = cY;
|
|
}
|
|
|
|
if (context.scale) {
|
|
var dist = euclideanDistance(orgEvent.touches[0], orgEvent.touches[1]);
|
|
var distRatio = dist / context.start.dist;
|
|
|
|
zoom(distRatio * context.start.zoom, context.start.mid);
|
|
context.lastDistance = dist;
|
|
}
|
|
|
|
// prevent select
|
|
event.preventDefault();
|
|
}
|
|
|
|
function handleTouchEnd(event) {
|
|
|
|
var orgEvent = event.originalEvent;
|
|
|
|
if (orgEvent.touches.length < 1) {
|
|
contextInit();
|
|
}
|
|
if (orgEvent.touches.length === 1) {
|
|
initMove(orgEvent);
|
|
}
|
|
if (orgEvent.touches.length === 2) {
|
|
initScale(orgEvent);
|
|
}
|
|
|
|
_.forEach(orgEvent.changedTouches, function (touch) {
|
|
delete context[touch.identifier];
|
|
});
|
|
|
|
// prevent select
|
|
event.preventDefault();
|
|
}
|
|
|
|
function init(element) {
|
|
|
|
contextInit();
|
|
|
|
//--- general handlers
|
|
$(element).on('touchstart', handleTouchStart);
|
|
$(element).on('touchmove', handleTouchMove);
|
|
$(document).on('touchend', handleTouchEnd);
|
|
|
|
|
|
//--- snap handler
|
|
|
|
eventBus.on('shape.touchstart', function(event) {
|
|
// ---
|
|
// TODO must forwarded to touchstart???#
|
|
handleTouchStart(event);
|
|
});
|
|
|
|
eventBus.on('shape.touchend', function(event) {
|
|
|
|
if(event.touches.length !== 0) {
|
|
return;
|
|
}
|
|
|
|
if((Date.now() - context.lastTap.time) < DOUBLE_TAP_THRESHOLD) {
|
|
eventBus.fire('shape.dbltap', event);
|
|
}
|
|
|
|
context.lastTap.time = Date.now();
|
|
});
|
|
}
|
|
|
|
function cap(scale) {
|
|
return Math.max(RANGE.min, Math.min(RANGE.max, scale));
|
|
}
|
|
|
|
function zoom(pinchRatio, position) {
|
|
canvas.zoom(cap(pinchRatio), position);
|
|
}
|
|
|
|
function euclideanDistance(touch1, touch2) {
|
|
var dist =
|
|
Math.sqrt(
|
|
(touch1.clientX - touch2.clientX) *
|
|
(touch1.clientX - touch2.clientX) +
|
|
(touch1.clientY - touch2.clientY) *
|
|
(touch1.clientY - touch2.clientY)
|
|
);
|
|
|
|
return dist;
|
|
}
|
|
|
|
function initMove(orgEvent) {
|
|
context.move = true;
|
|
context.moveId = orgEvent.touches[0].identifier;
|
|
context.scale = false;
|
|
if (!context.lasttouch) {
|
|
context.lasttouch = {
|
|
cX: undefined,
|
|
cY: undefined,
|
|
mX: 0,
|
|
mY: 0
|
|
};
|
|
}
|
|
}
|
|
|
|
function initScale(orgEvent) {
|
|
context.scale = true;
|
|
context.start.dist = euclideanDistance(orgEvent.touches[0], orgEvent.touches[1]);
|
|
context.lastDistance = context.start.dist;
|
|
context.start.zoom = canvas.zoom();
|
|
context.start.mid = {
|
|
x: (orgEvent.touches[0].clientX + orgEvent.touches[1].clientX) / 2,
|
|
y: (orgEvent.touches[0].clientY + orgEvent.touches[1].clientY) / 2
|
|
};
|
|
}
|
|
|
|
function contextInit() {
|
|
context = {
|
|
start: {},
|
|
lastTap: {}
|
|
};
|
|
}
|
|
|
|
eventBus.on('canvas.init', function(e) {
|
|
init(e.paper.node);
|
|
});
|
|
}
|
|
|
|
TouchInteraction.$inject = [ 'eventBus', 'canvas', 'touchFix' ];
|
|
|
|
module.exports = TouchInteraction; |