Pinch support and general improvements for mobile touch interface (#9)
This commit is contained in:
@@ -18,6 +18,8 @@ export default class Cartographer {
|
||||
'move',
|
||||
'_checkMove',
|
||||
|
||||
'pinch',
|
||||
|
||||
'zoom',
|
||||
].map(method => this[method] = this[method].bind(this));
|
||||
|
||||
@@ -120,10 +122,33 @@ export default class Cartographer {
|
||||
}
|
||||
}
|
||||
|
||||
zoom(event) {
|
||||
let scaleOrig = this.scale;
|
||||
pinch(event) {
|
||||
const scaleOrig = this.scale;
|
||||
|
||||
let scaleTemp = parseInt((scaleOrig + (event.deltaY / -10)) * 1000) / 1000;
|
||||
let scaleTemp = scaleOrig * event.scaleStep;
|
||||
|
||||
scaleTemp = Math.max(scaleTemp, this.scaleMin);
|
||||
scaleTemp = Math.min(scaleTemp, this.scaleMax);
|
||||
|
||||
if (scaleTemp !== scaleOrig) {
|
||||
this.scale = scaleTemp;
|
||||
|
||||
// zoom to the current mouse location
|
||||
this.move({
|
||||
deltaX: (((event.offsetX - this.originX) / scaleOrig) * (scaleOrig - scaleTemp)),
|
||||
deltaY: (((event.offsetY - this.originY) / scaleOrig) * (scaleOrig - scaleTemp)),
|
||||
target: {
|
||||
offsetWidth: event.target.offsetWidth,
|
||||
offsetHeight: event.target.offsetHeight,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
zoom(event) {
|
||||
const scaleOrig = this.scale;
|
||||
|
||||
let scaleTemp = scaleOrig + (event.deltaY / -10);
|
||||
|
||||
// make sure 'scale' doesn't get too small nor too big
|
||||
if (scaleTemp < this.scaleMin)
|
||||
@@ -131,7 +156,7 @@ export default class Cartographer {
|
||||
else if (scaleTemp > this.scaleMax)
|
||||
scaleTemp = this.scaleMax;
|
||||
|
||||
if (scaleOrig != scaleTemp) {
|
||||
if (scaleOrig !== scaleTemp) {
|
||||
|
||||
this.scale = scaleTemp;
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class Demo {
|
||||
|
||||
const key = `${ x },${ z != null ? z : y }`;
|
||||
|
||||
this.map[key].pips = Tessellate.utils.random(1,9);
|
||||
this.map[key].pips = Tessellate.utils.random(1,7);
|
||||
console.log(this.map[key].pips);
|
||||
|
||||
// console.log(tap.tile.getPoint());
|
||||
|
||||
128
src/onTap.js
128
src/onTap.js
@@ -7,8 +7,6 @@ export default class OnTap {
|
||||
|
||||
this.debug = false;
|
||||
this.state = {
|
||||
clickStartX: null,
|
||||
clickStartY: null,
|
||||
clickStartTime: null
|
||||
};
|
||||
|
||||
@@ -24,29 +22,41 @@ export default class OnTap {
|
||||
threshold: settings.doubletapThreshold || 500, // less than in milliseconds
|
||||
callback: settings.doubletap || noop
|
||||
},
|
||||
pinch: {
|
||||
callback: settings.pinch || noop
|
||||
},
|
||||
press: {
|
||||
threshold: settings.pressThreshold || 1000, // greater than or equal to in milliseconds
|
||||
callback: settings.press || noop
|
||||
},
|
||||
zoom: {
|
||||
callback: settings.zoom || noop
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
this.events = ['mousedown', 'mouseup', 'mousemove', 'touchstart', 'touchend', 'touchmove', 'touchcancel', 'wheel'];
|
||||
[
|
||||
'mousedown',
|
||||
'mouseup',
|
||||
'mousemove',
|
||||
|
||||
this.events.map(method => {
|
||||
'touchstart',
|
||||
'touchend',
|
||||
'touchmove',
|
||||
'touchcancel',
|
||||
|
||||
'wheel',
|
||||
].map(method => {
|
||||
this[method] = this[method].bind(this);
|
||||
this.element.addEventListener(method, this[method]);
|
||||
});
|
||||
}
|
||||
|
||||
mousedown(event) {
|
||||
if (this.debug) console.dir('onTap.mousedown', event);
|
||||
if (this.debug) console.debug('onTap.mousedown', event);
|
||||
|
||||
if (!this.state.clickStartTime) {
|
||||
this.state.clickStartX = event.pageX;
|
||||
this.state.clickStartY = event.pageY;
|
||||
this.state.lastX = event.offsetX;
|
||||
this.state.lastY = event.offsetY;
|
||||
this.state.clickStartTime = event.timeStamp;
|
||||
}
|
||||
}
|
||||
@@ -54,17 +64,26 @@ export default class OnTap {
|
||||
touchstart(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (this.debug) console.dir('onTap.touchstart', event);
|
||||
if (this.debug) console.debug('onTap.touchstart', event);
|
||||
|
||||
const touches = [...event.touches];
|
||||
event.offsetX = touches.reduce((memo, touch) => memo + touch.pageX, 0) / touches.length;
|
||||
event.offsetY = touches.reduce((memo, touch) => memo + touch.pageY, 0) / touches.length;
|
||||
|
||||
this.state.lastX = event.offsetX;
|
||||
this.state.lastY = event.offsetY;
|
||||
|
||||
if (event.touches.length > 1) {
|
||||
this.state.pinching = true;
|
||||
}
|
||||
|
||||
if (!this.state.clickStartTime) {
|
||||
this.state.clickStartX = event.pageX;
|
||||
this.state.clickStartY = event.pageY;
|
||||
this.state.clickStartTime = event.timeStamp;
|
||||
}
|
||||
}
|
||||
|
||||
mouseup(event) {
|
||||
if (this.debug) console.dir('onTap.mouseup', event);
|
||||
if (this.debug) console.debug('onTap.mouseup', event);
|
||||
|
||||
if (!this.state.moving) {
|
||||
this.actions.tap.callback(event);
|
||||
@@ -73,51 +92,63 @@ export default class OnTap {
|
||||
this.state.moving = null;
|
||||
this.state.lastX = null;
|
||||
this.state.lastY = null;
|
||||
this.state.clickStartX = null;
|
||||
this.state.clickStartY = null;
|
||||
this.state.clickStartTime = null;
|
||||
}
|
||||
|
||||
touchend(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (this.debug) console.dir('onTap.touchend', event);
|
||||
if (this.debug) console.debug('onTap.touchend', event);
|
||||
|
||||
if (!this.state.moving) {
|
||||
event.offsetX = event.offsetX || event.pageX - event.target.offsetLeft;
|
||||
event.offsetY = event.offsetY || event.pageY - event.target.offsetTop;
|
||||
const touches = [...event.touches];
|
||||
|
||||
if (touches.length) {
|
||||
event.offsetX = touches.reduce((memo, touch) => memo + touch.pageX, 0) / touches.length;
|
||||
event.offsetY = touches.reduce((memo, touch) => memo + touch.pageY, 0) / touches.length;
|
||||
|
||||
this.state.lastX = event.offsetX;
|
||||
this.state.lastY = event.offsetY;
|
||||
}
|
||||
else {
|
||||
event.offsetX = this.state.lastX;
|
||||
event.offsetY = this.state.lastY;
|
||||
}
|
||||
|
||||
if (!(this.state.moving || this.state.pinching)) {
|
||||
this.actions.tap.callback(event);
|
||||
}
|
||||
|
||||
this.state.moving = null;
|
||||
this.state.lastX = null;
|
||||
this.state.lastY = null;
|
||||
this.state.clickStartX = null;
|
||||
this.state.clickStartY = null;
|
||||
this.state.clickStartTime = null;
|
||||
if (event.touches.length <= 1) {
|
||||
this.state.lastPinch = null;
|
||||
}
|
||||
|
||||
if (event.touches.length === 0) {
|
||||
this.state.pinching = false;
|
||||
this.state.moving = null;
|
||||
this.state.lastX = null;
|
||||
this.state.lastY = null;
|
||||
this.state.clickStartTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
mousemove(event) {
|
||||
if (this.debug) console.dir('onTap.mousemove', event);
|
||||
if (this.debug) console.debug('onTap.mousemove', event);
|
||||
|
||||
if (this.state.clickStartTime) {
|
||||
if (!this.state.moving) {
|
||||
if ((Math.abs(event.pageX - this.state.clickStartX) > this.actions.move.threshold)
|
||||
|| (Math.abs(event.pageY - this.state.clickStartY) > this.actions.move.threshold)) {
|
||||
if ((Math.abs(event.offsetX - this.state.lastX) > this.actions.move.threshold)
|
||||
|| (Math.abs(event.offsetY - this.state.lastY) > this.actions.move.threshold)) {
|
||||
this.state.moving = true;
|
||||
this.state.lastX = this.state.clickStartX;
|
||||
this.state.lastY = this.state.clickStartY;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state.moving) {
|
||||
event.deltaX = event.pageX - this.state.lastX,
|
||||
event.deltaY = event.pageY - this.state.lastY
|
||||
event.deltaX = event.offsetX - this.state.lastX,
|
||||
event.deltaY = event.offsetY - this.state.lastY
|
||||
this.actions.move.callback(event);
|
||||
|
||||
this.state.lastX = event.pageX;
|
||||
this.state.lastY = event.pageY;
|
||||
this.state.lastX = event.offsetX;
|
||||
this.state.lastY = event.offsetY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,25 +156,36 @@ export default class OnTap {
|
||||
touchmove(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (this.debug) console.dir('onTap.touchmove', event);
|
||||
if (this.debug) console.debug('onTap.touchmove', event);
|
||||
|
||||
if (this.state.clickStartTime) {
|
||||
const touches = [...event.touches];
|
||||
event.offsetX = touches.reduce((memo, touch) => memo + touch.pageX, 0) / touches.length;
|
||||
event.offsetY = touches.reduce((memo, touch) => memo + touch.pageY, 0) / touches.length;
|
||||
|
||||
if (this.state.pinching) {
|
||||
event.scaleStep = event.scale / (this.state.lastPinch || 1);
|
||||
|
||||
this.actions.pinch.callback(event);
|
||||
|
||||
this.state.lastPinch = event.scale;
|
||||
}
|
||||
|
||||
if (!this.state.moving) {
|
||||
if ((Math.abs(event.pageX - this.state.clickStartX) > this.actions.move.threshold)
|
||||
|| (Math.abs(event.pageY - this.state.clickStartY) > this.actions.move.threshold)) {
|
||||
if ((Math.abs(event.offsetX - this.state.lastX) > this.actions.move.threshold)
|
||||
|| (Math.abs(event.offsetY - this.state.lastY) > this.actions.move.threshold)) {
|
||||
this.state.moving = true;
|
||||
this.state.lastX = this.state.clickStartX;
|
||||
this.state.lastY = this.state.clickStartY;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state.moving) {
|
||||
event.deltaX = event.pageX - this.state.lastX,
|
||||
event.deltaY = event.pageY - this.state.lastY
|
||||
event.deltaX = event.offsetX - this.state.lastX,
|
||||
event.deltaY = event.offsetY - this.state.lastY
|
||||
|
||||
this.actions.move.callback(event);
|
||||
|
||||
this.state.lastX = event.pageX;
|
||||
this.state.lastY = event.pageY;
|
||||
this.state.lastX = event.offsetX;
|
||||
this.state.lastY = event.offsetY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,7 +195,7 @@ export default class OnTap {
|
||||
}
|
||||
|
||||
wheel(event) {
|
||||
if (this.debug) console.dir('onTap.wheel', event);
|
||||
if (this.debug) console.debug('onTap.wheel', event);
|
||||
|
||||
this.actions.zoom.callback(event);
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ export class Tessellate {
|
||||
'checkSettings',
|
||||
'tap',
|
||||
'move',
|
||||
'pinch',
|
||||
'zoom',
|
||||
'pixelToTile',
|
||||
'tileToPixel',
|
||||
@@ -90,8 +91,11 @@ export class Tessellate {
|
||||
this.onTap = new OnTap({
|
||||
element: this.settings.element,
|
||||
tap: this.tap,
|
||||
doubletap: this.doubletap,
|
||||
hold: this.hold,
|
||||
move: this.move,
|
||||
zoom: this.zoom
|
||||
pinch: this.pinch,
|
||||
zoom: this.zoom,
|
||||
});
|
||||
|
||||
const cartographer = selectCartographer(this.settings.board, this.settings.orientation);
|
||||
@@ -131,10 +135,42 @@ export class Tessellate {
|
||||
this.settings.tap(tap);
|
||||
}
|
||||
|
||||
doubletap(event) {
|
||||
let point = new Point(event.offsetX, event.offsetY);
|
||||
let tile = this.cartographer.pixelToTile(point);
|
||||
|
||||
let tap = {
|
||||
event,
|
||||
point,
|
||||
tile
|
||||
};
|
||||
|
||||
console.log('DOUBLETAP');
|
||||
console.log(tap);
|
||||
}
|
||||
|
||||
hold(event) {
|
||||
let point = new Point(event.offsetX, event.offsetY);
|
||||
let tile = this.cartographer.pixelToTile(point);
|
||||
|
||||
let tap = {
|
||||
event,
|
||||
point,
|
||||
tile
|
||||
};
|
||||
|
||||
console.log('HOLD');
|
||||
console.log(tap);
|
||||
}
|
||||
|
||||
move(event) {
|
||||
this.cartographer.move(event);
|
||||
}
|
||||
|
||||
pinch(event) {
|
||||
this.cartographer.pinch(event);
|
||||
}
|
||||
|
||||
zoom(event) {
|
||||
this.cartographer.zoom(event);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user