stricter thresholds for clicks and taps to avoid accidental pixel
placing
This commit is contained in:
parent
ce09198374
commit
641c996c0c
|
@ -16,6 +16,7 @@ import {
|
||||||
screenToWorld,
|
screenToWorld,
|
||||||
getChunkOfPixel,
|
getChunkOfPixel,
|
||||||
getOffsetOfPixel,
|
getOffsetOfPixel,
|
||||||
|
getTapOrClickCenter,
|
||||||
} from '../core/utils';
|
} from '../core/utils';
|
||||||
import {
|
import {
|
||||||
HOLD_PAINT,
|
HOLD_PAINT,
|
||||||
|
@ -28,8 +29,9 @@ class PixelPainterControls {
|
||||||
//
|
//
|
||||||
clickTapStartView = [0, 0];
|
clickTapStartView = [0, 0];
|
||||||
clickTapStartTime = 0;
|
clickTapStartTime = 0;
|
||||||
clickTapStartCoords = [0, 0];
|
|
||||||
tapStartDist = 50;
|
tapStartDist = 50;
|
||||||
|
// screen coords of where a tap/click started
|
||||||
|
clickTapStartCoords = [0, 0];
|
||||||
// stored speed for acceleration
|
// stored speed for acceleration
|
||||||
speedScalar = 0;
|
speedScalar = 0;
|
||||||
// on mouse: true as long as left mouse button is pressed
|
// on mouse: true as long as left mouse button is pressed
|
||||||
|
@ -118,7 +120,7 @@ class PixelPainterControls {
|
||||||
].map(Math.abs);
|
].map(Math.abs);
|
||||||
// thresholds for single click / holding
|
// thresholds for single click / holding
|
||||||
if (clickTapStartTime > Date.now() - 250
|
if (clickTapStartTime > Date.now() - 250
|
||||||
&& coordsDiff[0] < 3 && coordsDiff[1] < 3
|
&& coordsDiff[0] < 6 && coordsDiff[1] < 6
|
||||||
) {
|
) {
|
||||||
PixelPainterControls.placePixel(
|
PixelPainterControls.placePixel(
|
||||||
store,
|
store,
|
||||||
|
@ -231,7 +233,7 @@ class PixelPainterControls {
|
||||||
this.clearTabTimeout();
|
this.clearTabTimeout();
|
||||||
this.isTapPainting = false;
|
this.isTapPainting = false;
|
||||||
this.clickTapStartTime = Date.now();
|
this.clickTapStartTime = Date.now();
|
||||||
this.clickTapStartCoords = PixelPainterControls.getTouchCenter(event);
|
this.clickTapStartCoords = getTapOrClickCenter(event);
|
||||||
this.clickTapStartView = this.renderer.view;
|
this.clickTapStartView = this.renderer.view;
|
||||||
|
|
||||||
if (event.touches.length > 1) {
|
if (event.touches.length > 1) {
|
||||||
|
@ -263,26 +265,25 @@ class PixelPainterControls {
|
||||||
onTouchEnd(event) {
|
onTouchEnd(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (event.touches.length) {
|
if (event.touches.length) {
|
||||||
// still other touches left
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { store, renderer } = this;
|
const { store, renderer } = this;
|
||||||
if (!this.wasEverMultiTap) {
|
if (!this.wasEverMultiTap) {
|
||||||
const { pageX, pageY } = event.changedTouches[0];
|
const [clientX, clientY] = getTapOrClickCenter(event);
|
||||||
const { clickTapStartCoords, clickTapStartTime } = this;
|
const { clickTapStartCoords, clickTapStartTime } = this;
|
||||||
const coordsDiff = [
|
const coordsDiff = [
|
||||||
clickTapStartCoords[0] - pageX,
|
clickTapStartCoords[0] - clientX,
|
||||||
clickTapStartCoords[1] - pageY,
|
clickTapStartCoords[1] - clientY,
|
||||||
].map(Math.abs);
|
].map(Math.abs);
|
||||||
// thresholds for single click / holding
|
// thresholds for single click / holding
|
||||||
if (clickTapStartTime > Date.now() - 580
|
if (clickTapStartTime > Date.now() - 580
|
||||||
&& coordsDiff[0] < 3 && coordsDiff[1] < 3
|
&& coordsDiff[0] < 6 && coordsDiff[1] < 6
|
||||||
) {
|
) {
|
||||||
PixelPainterControls.placePixel(
|
PixelPainterControls.placePixel(
|
||||||
store,
|
store,
|
||||||
this.renderer,
|
this.renderer,
|
||||||
this.screenToWorld([pageX, pageY]),
|
this.screenToWorld([clientX, clientY]),
|
||||||
);
|
);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
store.dispatch(unsetHover());
|
store.dispatch(unsetHover());
|
||||||
|
@ -300,7 +301,7 @@ class PixelPainterControls {
|
||||||
const multiTouch = (event.touches.length > 1);
|
const multiTouch = (event.touches.length > 1);
|
||||||
const state = this.store.getState();
|
const state = this.store.getState();
|
||||||
|
|
||||||
const [clientX, clientY] = PixelPainterControls.getTouchCenter(event);
|
const [clientX, clientY] = getTapOrClickCenter(event);
|
||||||
if (this.isMultiTap !== multiTouch) {
|
if (this.isMultiTap !== multiTouch) {
|
||||||
this.wasEverMultiTap = true;
|
this.wasEverMultiTap = true;
|
||||||
// if one finger got lifted or added, reset clickTabStart
|
// if one finger got lifted or added, reset clickTabStart
|
||||||
|
@ -328,7 +329,7 @@ class PixelPainterControls {
|
||||||
const [lastPosX, lastPosY] = clickTapStartView;
|
const [lastPosX, lastPosY] = clickTapStartView;
|
||||||
const deltaX = clientX - clickTapStartCoords[0];
|
const deltaX = clientX - clickTapStartCoords[0];
|
||||||
const deltaY = clientY - clickTapStartCoords[1];
|
const deltaY = clientY - clickTapStartCoords[1];
|
||||||
if (deltaX > 2 || deltaY > 2) {
|
if (deltaX > 5 || deltaY > 5) {
|
||||||
this.clearTabTimeout();
|
this.clearTabTimeout();
|
||||||
}
|
}
|
||||||
const { viewscale: scale } = this.renderer;
|
const { viewscale: scale } = this.renderer;
|
||||||
|
|
|
@ -636,6 +636,30 @@ export function getDateKeyOfTs(ts) {
|
||||||
return `${year}${month}${day}`;
|
return `${year}${month}${day}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get screen coords of touch / mouse event
|
||||||
|
* @param event MouseEvent or TouchEvent
|
||||||
|
* @return [x, y] in screen coordinates
|
||||||
|
*/
|
||||||
|
export function getTapOrClickCenter(event) {
|
||||||
|
if (event instanceof TouchEvent) {
|
||||||
|
const touches = (event.touches.length)
|
||||||
|
? event.touches : event.changedTouches;
|
||||||
|
let x = 0;
|
||||||
|
let y = 0;
|
||||||
|
for (const { pageX, pageY } of touches) {
|
||||||
|
x += pageX;
|
||||||
|
y += pageY;
|
||||||
|
}
|
||||||
|
const { length } = touches;
|
||||||
|
return [x / length, y / length];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
event.clientX,
|
||||||
|
event.clientY,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check if parent window exists and
|
* check if parent window exists and
|
||||||
* is accessible
|
* is accessible
|
||||||
|
|
|
@ -28,6 +28,7 @@ import ChunkLoader from './ChunkLoader3D';
|
||||||
import {
|
import {
|
||||||
getChunkOfPixel,
|
getChunkOfPixel,
|
||||||
getOffsetOfPixel,
|
getOffsetOfPixel,
|
||||||
|
getTapOrClickCenter,
|
||||||
} from '../core/utils';
|
} from '../core/utils';
|
||||||
import {
|
import {
|
||||||
THREE_TILE_SIZE,
|
THREE_TILE_SIZE,
|
||||||
|
@ -62,12 +63,15 @@ class Renderer3D extends Renderer {
|
||||||
threeRenderer;
|
threeRenderer;
|
||||||
// temp variables for mouse events
|
// temp variables for mouse events
|
||||||
mouse = new Vector2();
|
mouse = new Vector2();
|
||||||
mouseMoveStart;
|
|
||||||
raycaster = new Raycaster();
|
raycaster = new Raycaster();
|
||||||
pressTime;
|
pressTime;
|
||||||
pressCdTime;
|
pressCdTime;
|
||||||
multitap = 0;
|
multitap = 0;
|
||||||
lastIntersect = 0;
|
lastIntersect = 0;
|
||||||
|
// on touch: true if current tab was ever more than one figher at any time
|
||||||
|
wasEverMultiTap = false;
|
||||||
|
// screen coords of where a tap/click started
|
||||||
|
clickTapStartCoords = [0, 0];
|
||||||
|
|
||||||
constructor(store) {
|
constructor(store) {
|
||||||
super(store);
|
super(store);
|
||||||
|
@ -188,7 +192,6 @@ class Renderer3D extends Renderer {
|
||||||
);
|
);
|
||||||
this.controls = controls;
|
this.controls = controls;
|
||||||
|
|
||||||
|
|
||||||
this.onDocumentMouseMove = this.onDocumentMouseMove.bind(this);
|
this.onDocumentMouseMove = this.onDocumentMouseMove.bind(this);
|
||||||
this.onDocumentTouchMove = this.onDocumentTouchMove.bind(this);
|
this.onDocumentTouchMove = this.onDocumentTouchMove.bind(this);
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
|
@ -516,13 +519,16 @@ class Renderer3D extends Renderer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDocumentMouseDownOrTouchStart() {
|
onDocumentMouseDownOrTouchStart(event) {
|
||||||
this.pressTime = Date.now();
|
this.pressTime = Date.now();
|
||||||
const state = this.store.getState();
|
this.clickTapStartCoords = getTapOrClickCenter(event);
|
||||||
this.mouseMoveStart = state.canvas.hover;
|
this.wasEverMultiTap = (event.touches?.length > 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDocumentTouchMove() {
|
onDocumentTouchMove(event) {
|
||||||
|
if (event.touches?.length > 1) {
|
||||||
|
this.wasEverMultiTap = true;
|
||||||
|
}
|
||||||
this.updateRollOverMesh(0, 0);
|
this.updateRollOverMesh(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,7 +587,7 @@ class Renderer3D extends Renderer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
multiTapEnd() {
|
multiTapEnd(event) {
|
||||||
const {
|
const {
|
||||||
store,
|
store,
|
||||||
multitap,
|
multitap,
|
||||||
|
@ -589,12 +595,16 @@ class Renderer3D extends Renderer {
|
||||||
this.multitap = 0;
|
this.multitap = 0;
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
|
|
||||||
if (!this.mouseMoveStart || !state.canvas.hover) {
|
if (!state.canvas.hover || this.wasEverMultiTap) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const [px, py, pz] = this.mouseMoveStart;
|
const [clientX, clientY] = getTapOrClickCenter(event);
|
||||||
const [qx, qy, qz] = state.canvas.hover;
|
const { clickTapStartCoords } = this;
|
||||||
if (px !== qx || py !== qy || pz !== qz) {
|
const coordsDiff = [
|
||||||
|
clickTapStartCoords[0] - clientX,
|
||||||
|
clickTapStartCoords[1] - clientY,
|
||||||
|
].map(Math.abs);
|
||||||
|
if (coordsDiff[0] > 5 || coordsDiff[1] > 5) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,7 +615,7 @@ class Renderer3D extends Renderer {
|
||||||
if (this.rollOverMesh.position.y < 0) {
|
if (this.rollOverMesh.position.y < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.placeVoxel(px, py, pz);
|
this.placeVoxel(...state.canvas.hover);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2: {
|
||||||
|
@ -644,6 +654,9 @@ class Renderer3D extends Renderer {
|
||||||
|
|
||||||
onDocumentTouchEnd(event) {
|
onDocumentTouchEnd(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
if (event.touches.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const curTime = Date.now();
|
const curTime = Date.now();
|
||||||
if (curTime - this.pressTime > 600) {
|
if (curTime - this.pressTime > 600) {
|
||||||
|
@ -654,7 +667,7 @@ class Renderer3D extends Renderer {
|
||||||
// we should reset on every tap
|
// we should reset on every tap
|
||||||
// but we don't need that right now...
|
// but we don't need that right now...
|
||||||
if (this.multitap === 0) {
|
if (this.multitap === 0) {
|
||||||
setTimeout(this.multiTapEnd, 500);
|
setTimeout(() => this.multiTapEnd(event), 500);
|
||||||
}
|
}
|
||||||
this.multitap += 1;
|
this.multitap += 1;
|
||||||
}
|
}
|
||||||
|
@ -680,21 +693,21 @@ class Renderer3D extends Renderer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.mouseMoveStart || !state.canvas.hover) {
|
if (!state.canvas.hover) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const [px, py, pz] = this.mouseMoveStart;
|
const [clientX, clientY] = getTapOrClickCenter(event);
|
||||||
const [qx, qy, qz] = state.canvas.hover;
|
const { clickTapStartCoords } = this;
|
||||||
if (px !== qx || py !== qy || pz !== qz) {
|
const coordsDiff = [
|
||||||
|
clickTapStartCoords[0] - clientX,
|
||||||
|
clickTapStartCoords[1] - clientY,
|
||||||
|
].map(Math.abs);
|
||||||
|
if (coordsDiff[0] > 5 || coordsDiff[1] > 5) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const {
|
const { button } = event;
|
||||||
clientX,
|
|
||||||
clientY,
|
|
||||||
button,
|
|
||||||
} = event;
|
|
||||||
const {
|
const {
|
||||||
innerWidth,
|
innerWidth,
|
||||||
innerHeight,
|
innerHeight,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user