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