Pinch support and general improvements for mobile touch interface (#9)

This commit is contained in:
gavin
2018-08-01 01:06:02 +00:00
committed by Gitea
parent 5cb4308251
commit 584e917fc6
4 changed files with 152 additions and 49 deletions

View File

@@ -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;

View File

@@ -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());

View File

@@ -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);
}

View File

@@ -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);
}