don't use outdated hammerjs in pixelpaintercontrols
This commit is contained in:
parent
709fd3af9f
commit
87629bf1b4
|
@ -4,7 +4,6 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import Hammer from 'hammerjs';
|
||||
import keycode from 'keycode';
|
||||
|
||||
import {
|
||||
|
@ -28,100 +27,108 @@ import {
|
|||
getOffsetOfPixel,
|
||||
} from '../core/utils';
|
||||
|
||||
let store = null;
|
||||
class PixelPlainterControls {
|
||||
constructor(renderer, viewport: HTMLCanvasElement, curStore) {
|
||||
this.store = curStore;
|
||||
this.renderer = renderer;
|
||||
this.viewport = viewport;
|
||||
|
||||
function onKeyPress(event: KeyboardEvent) {
|
||||
// ignore key presses if modal is open or chat is used
|
||||
if (event.target.nodeName === 'INPUT'
|
||||
|| event.target.nodeName === 'TEXTAREA'
|
||||
) {
|
||||
return;
|
||||
this.onMouseDown = this.onMouseDown.bind(this);
|
||||
this.onKeyPress = this.onKeyPress.bind(this);
|
||||
this.onAuxClick = this.onAuxClick.bind(this);
|
||||
this.onMouseOut = this.onMouseOut.bind(this);
|
||||
this.onMouseMove = this.onMouseMove.bind(this);
|
||||
this.onWheel = this.onWheel.bind(this);
|
||||
this.onMouseUp = this.onMouseUp.bind(this);
|
||||
this.onTouchStart = this.onTouchStart.bind(this);
|
||||
this.onTouchEnd = this.onTouchEnd.bind(this);
|
||||
this.onTouchMove = this.onTouchMove.bind(this);
|
||||
|
||||
this.clickTabStartView = [0, 0];
|
||||
this.clickTabStartTime = 0;
|
||||
this.clickTabStartCoords = [0, 0];
|
||||
this.startTabDist = 50;
|
||||
this.startTabScale = this.store.getState().scale;
|
||||
this.isMultiTab = false;
|
||||
this.isMouseDown = false;
|
||||
|
||||
document.addEventListener('keydown', this.onKeyPress, false);
|
||||
viewport.addEventListener('auxclick', this.onAuxClick, false);
|
||||
viewport.addEventListener('mousedown', this.onMouseDown, false);
|
||||
viewport.addEventListener('mousemove', this.onMouseMove, false);
|
||||
viewport.addEventListener('mouseup', this.onMouseUp, false);
|
||||
viewport.addEventListener('wheel', this.onWheel, false);
|
||||
viewport.addEventListener('touchstart', this.onTouchStart, false);
|
||||
viewport.addEventListener('touchend', this.onTouchEnd, false);
|
||||
viewport.addEventListener('touchmove', this.onTouchMove, false);
|
||||
viewport.addEventListener('mouseout', this.onMouseOut, false);
|
||||
}
|
||||
|
||||
switch (keycode(event)) {
|
||||
case 'up':
|
||||
case 'w':
|
||||
store.dispatch(moveNorth());
|
||||
break;
|
||||
case 'left':
|
||||
case 'a':
|
||||
store.dispatch(moveWest());
|
||||
break;
|
||||
case 'down':
|
||||
case 's':
|
||||
store.dispatch(moveSouth());
|
||||
break;
|
||||
case 'right':
|
||||
case 'd':
|
||||
store.dispatch(moveEast());
|
||||
break;
|
||||
/*
|
||||
case 'space':
|
||||
if ($viewport) $viewport.click();
|
||||
return;
|
||||
*/
|
||||
case '+':
|
||||
case 'e':
|
||||
store.dispatch(zoomIn());
|
||||
break;
|
||||
case '-':
|
||||
case 'q':
|
||||
store.dispatch(zoomOut());
|
||||
break;
|
||||
default:
|
||||
dispose() {
|
||||
document.removeEventListener('keydown', this.onKeyPress, false);
|
||||
}
|
||||
}
|
||||
|
||||
export function initControls(renderer, viewport: HTMLCanvasElement, curStore) {
|
||||
store = curStore;
|
||||
viewport.onmousemove = ({ clientX, clientY }: MouseEvent) => {
|
||||
const state = store.getState();
|
||||
const screenCoor = screenToWorld(state, viewport, [clientX, clientY]);
|
||||
store.dispatch(setHover(screenCoor));
|
||||
};
|
||||
viewport.onmouseout = () => {
|
||||
store.dispatch(unsetHover());
|
||||
};
|
||||
viewport.onwheel = ({ deltaY }: WheelEvent) => {
|
||||
const state = store.getState();
|
||||
const { hover } = state.gui;
|
||||
let zoompoint = null;
|
||||
if (hover) {
|
||||
zoompoint = hover;
|
||||
}
|
||||
if (deltaY < 0) {
|
||||
store.dispatch(zoomIn(zoompoint));
|
||||
}
|
||||
if (deltaY > 0) {
|
||||
store.dispatch(zoomOut(zoompoint));
|
||||
}
|
||||
store.dispatch(onViewFinishChange());
|
||||
};
|
||||
viewport.onauxclick = ({ which, clientX, clientY }: MouseEvent) => {
|
||||
// middle mouse button
|
||||
if (which !== 2) {
|
||||
return;
|
||||
}
|
||||
const state = store.getState();
|
||||
if (state.canvas.scale < 3) {
|
||||
return;
|
||||
}
|
||||
const coords = screenToWorld(state, viewport, [clientX, clientY]);
|
||||
const clrIndex = renderer.getColorIndexOfPixel(...coords);
|
||||
if (clrIndex === null) {
|
||||
return;
|
||||
}
|
||||
store.dispatch(selectColor(clrIndex));
|
||||
};
|
||||
onMouseDown(event: MouseEvent) {
|
||||
event.preventDefault();
|
||||
|
||||
// fingers controls on touch
|
||||
const hammertime = new Hammer(viewport);
|
||||
hammertime.get('pan').set({ direction: Hammer.DIRECTION_ALL });
|
||||
hammertime.get('swipe').set({ direction: Hammer.DIRECTION_ALL });
|
||||
// Zoom-in Zoom-out in touch devices
|
||||
hammertime.get('pinch').set({ enable: true });
|
||||
if (event.button === 0) {
|
||||
this.isMouseDown = true;
|
||||
const { clientX, clientY } = event;
|
||||
this.clickTabStartTime = Date.now();
|
||||
this.clickTabStartCoords = [clientX, clientY];
|
||||
this.clickTabStartView = this.store.getState().canvas.view;
|
||||
const { viewport } = this;
|
||||
setTimeout(() => {
|
||||
viewport.style.cursor = 'move';
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
hammertime.on('tap', ({ center }) => {
|
||||
onMouseUp(event: MouseEvent) {
|
||||
event.preventDefault();
|
||||
|
||||
if (event.button === 0) {
|
||||
this.isMouseDown = false;
|
||||
const { clientX, clientY } = event;
|
||||
const { clickTabStartCoords, clickTabStartTime } = this;
|
||||
const coordsDiff = [
|
||||
clickTabStartCoords[0] - clientX,
|
||||
clickTabStartCoords[1] - clientY,
|
||||
];
|
||||
// thresholds for single click / holding
|
||||
if (clickTabStartTime > Date.now() - 300
|
||||
&& coordsDiff[0] < 10 && coordsDiff[1] < 10) {
|
||||
PixelPlainterControls.placePixel(
|
||||
this.store,
|
||||
this.viewport,
|
||||
this.renderer,
|
||||
[clientX, clientY],
|
||||
);
|
||||
}
|
||||
this.viewport.style.cursor = 'auto';
|
||||
}
|
||||
}
|
||||
|
||||
static getTouchCenter(event: TouchEvent) {
|
||||
switch (event.touches.length) {
|
||||
case 1: {
|
||||
const { pageX, pageY } = event.touches[0];
|
||||
return [pageX, pageY];
|
||||
}
|
||||
case 2: {
|
||||
const pageX = Math.floor(0.5
|
||||
* (event.touches[0].pageX + event.touches[1].pageX));
|
||||
const pageY = Math.floor(0.5
|
||||
* (event.touches[0].pageY + event.touches[1].pageY));
|
||||
return [pageX, pageY];
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static placePixel(store, viewport, renderer, center) {
|
||||
const state = store.getState();
|
||||
const { autoZoomIn } = state.gui;
|
||||
const { placeAllowed } = state.user;
|
||||
|
@ -133,8 +140,7 @@ export function initControls(renderer, viewport: HTMLCanvasElement, curStore) {
|
|||
|
||||
if (isHistoricalView) return;
|
||||
|
||||
const { x, y } = center;
|
||||
const cell = screenToWorld(state, viewport, [x, y]);
|
||||
const cell = screenToWorld(state, viewport, center);
|
||||
|
||||
if (autoZoomIn && scale < 8) {
|
||||
store.dispatch(setViewCoordinates(cell));
|
||||
|
@ -142,7 +148,7 @@ export function initControls(renderer, viewport: HTMLCanvasElement, curStore) {
|
|||
return;
|
||||
}
|
||||
|
||||
// don't allow placing of pixel just on low zoomlevels
|
||||
// allow placing of pixel just on low zoomlevels
|
||||
if (scale < 3) return;
|
||||
|
||||
if (!placeAllowed) return;
|
||||
|
@ -156,61 +162,218 @@ export function initControls(renderer, viewport: HTMLCanvasElement, curStore) {
|
|||
selectedColor,
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const initialState: State = store.getState();
|
||||
[window.lastPosX, window.lastPosY] = initialState.canvas.view;
|
||||
let lastScale = initialState.canvas.scale;
|
||||
hammertime.on(
|
||||
'panstart pinchstart pan pinch panend pinchend',
|
||||
({
|
||||
type, deltaX, deltaY, scale,
|
||||
}) => {
|
||||
viewport.style.cursor = 'move'; // like google maps
|
||||
const { scale: viewportScale } = store.getState().canvas;
|
||||
static getMultiTouchDistance(event: TouchEvent) {
|
||||
if (event.touches.length < 2) {
|
||||
return 1;
|
||||
}
|
||||
const a = event.touches[0];
|
||||
const b = event.touches[1];
|
||||
return Math.sqrt(
|
||||
(b.pageX - a.pageX) ** 2 + (b.pageY - a.pageY) ** 2,
|
||||
);
|
||||
}
|
||||
|
||||
// pinch start
|
||||
if (type === 'pinchstart') {
|
||||
store.dispatch(unsetHover());
|
||||
lastScale = viewportScale;
|
||||
onTouchStart(event: TouchEvent) {
|
||||
event.preventDefault();
|
||||
|
||||
this.clickTabStartTime = Date.now();
|
||||
this.clickTabStartCoords = PixelPlainterControls.getTouchCenter(event);
|
||||
const state = this.store.getState();
|
||||
this.clickTabStartView = state.canvas.view;
|
||||
|
||||
if (event.touches.length > 1) {
|
||||
this.startTabScale = state.canvas.scale;
|
||||
this.startTabDist = PixelPlainterControls.getMultiTouchDistance(event);
|
||||
this.isMultiTab = true;
|
||||
} else {
|
||||
this.isMultiTab = false;
|
||||
}
|
||||
}
|
||||
|
||||
onTouchEnd(event: TouchEvent) {
|
||||
event.preventDefault();
|
||||
|
||||
if (event.changedTouches.length < 2) {
|
||||
const { pageX, pageY } = event.changedTouches[0];
|
||||
const { clickTabStartCoords, clickTabStartTime } = this;
|
||||
const coordsDiff = [
|
||||
clickTabStartCoords[0] - pageX,
|
||||
clickTabStartCoords[1] - pageY,
|
||||
];
|
||||
// thresholds for single click / holding
|
||||
if (clickTabStartTime > Date.now() - 300
|
||||
&& coordsDiff[0] < 10 && coordsDiff[1] < 10) {
|
||||
const { store, viewport } = this;
|
||||
PixelPlainterControls.placePixel(
|
||||
store,
|
||||
viewport,
|
||||
this.renderer,
|
||||
[pageX, pageY],
|
||||
);
|
||||
setTimeout(() => {
|
||||
store.dispatch(unsetHover());
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// panstart
|
||||
if (type === 'panstart') {
|
||||
store.dispatch(unsetHover());
|
||||
const { view: initView } = store.getState().canvas;
|
||||
[window.lastPosX, window.lastPosY] = initView;
|
||||
}
|
||||
onTouchMove(event: TouchEvent) {
|
||||
event.preventDefault();
|
||||
|
||||
// pinch
|
||||
if (type === 'pinch') {
|
||||
store.dispatch(setScale(lastScale * scale));
|
||||
}
|
||||
const multiTouch = (event.touches.length > 1);
|
||||
|
||||
// pan
|
||||
const [clientX, clientY] = PixelPlainterControls.getTouchCenter(event);
|
||||
const { store } = this;
|
||||
const state = store.getState();
|
||||
if (this.isMultiTab !== multiTouch) {
|
||||
// if one finger got lifted or added, reset clickTabStart
|
||||
this.isMultiTab = multiTouch;
|
||||
this.clickTabStartCoords = [clientX, clientY];
|
||||
this.clickTabStartView = state.canvas.view;
|
||||
this.startTabDist = PixelPlainterControls.getMultiTouchDistance(event);
|
||||
this.startTabScale = state.canvas.scale;
|
||||
} else {
|
||||
// pan
|
||||
const { clickTabStartView, clickTabStartCoords } = this;
|
||||
const [lastPosX, lastPosY] = clickTabStartView;
|
||||
|
||||
const deltaX = clientX - clickTabStartCoords[0];
|
||||
const deltaY = clientY - clickTabStartCoords[1];
|
||||
const { scale } = state.canvas;
|
||||
store.dispatch(setViewCoordinates([
|
||||
window.lastPosX - (deltaX / viewportScale),
|
||||
window.lastPosY - (deltaY / viewportScale),
|
||||
lastPosX - (deltaX / scale),
|
||||
lastPosY - (deltaY / scale),
|
||||
]));
|
||||
|
||||
// pinch end
|
||||
if (type === 'pinchend') {
|
||||
lastScale = viewportScale;
|
||||
// pinch
|
||||
if (multiTouch) {
|
||||
const a = event.touches[0];
|
||||
const b = event.touches[1];
|
||||
const { startTabDist, startTabScale } = this;
|
||||
const dist = Math.sqrt(
|
||||
(b.pageX - a.pageX) ** 2 + (b.pageY - a.pageY) ** 2,
|
||||
);
|
||||
const pinchScale = dist / startTabDist;
|
||||
store.dispatch(setScale(startTabScale * pinchScale));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// panend
|
||||
if (type === 'panend') {
|
||||
store.dispatch(onViewFinishChange());
|
||||
const { view } = store.getState().canvas;
|
||||
[window.lastPosX, window.lastPosY] = view;
|
||||
viewport.style.cursor = 'auto';
|
||||
}
|
||||
},
|
||||
);
|
||||
onWheel(event: MouseEvent) {
|
||||
const { deltaY } = event;
|
||||
const { store } = this;
|
||||
const state = store.getState();
|
||||
const { hover } = state.gui;
|
||||
let zoompoint = null;
|
||||
if (hover) {
|
||||
zoompoint = hover;
|
||||
}
|
||||
if (deltaY < 0) {
|
||||
store.dispatch(zoomIn(zoompoint));
|
||||
}
|
||||
if (deltaY > 0) {
|
||||
store.dispatch(zoomOut(zoompoint));
|
||||
}
|
||||
store.dispatch(onViewFinishChange());
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', onKeyPress, false);
|
||||
onMouseMove(event: MouseEvent) {
|
||||
event.preventDefault();
|
||||
|
||||
const { clientX, clientY } = event;
|
||||
const { store, isMouseDown } = this;
|
||||
const state = store.getState();
|
||||
if (isMouseDown) {
|
||||
const { clickTabStartView, clickTabStartCoords } = this;
|
||||
const [lastPosX, lastPosY] = clickTabStartView;
|
||||
const deltaX = clientX - clickTabStartCoords[0];
|
||||
const deltaY = clientY - clickTabStartCoords[1];
|
||||
|
||||
const { scale } = state.canvas;
|
||||
store.dispatch(setViewCoordinates([
|
||||
lastPosX - (deltaX / scale),
|
||||
lastPosY - (deltaY / scale),
|
||||
]));
|
||||
} else {
|
||||
const screenCoor = screenToWorld(
|
||||
state,
|
||||
this.viewport,
|
||||
[clientX, clientY],
|
||||
);
|
||||
store.dispatch(setHover(screenCoor));
|
||||
}
|
||||
}
|
||||
|
||||
onMouseOut() {
|
||||
const { store } = this;
|
||||
store.dispatch(unsetHover());
|
||||
}
|
||||
|
||||
onAuxClick(event: MouseEvent) {
|
||||
const { which, clientX, clientY } = event;
|
||||
const { store } = this;
|
||||
// middle mouse button
|
||||
if (which !== 2) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
const state = store.getState();
|
||||
if (state.canvas.scale < 3) {
|
||||
return;
|
||||
}
|
||||
const coords = screenToWorld(state, this.viewport, [clientX, clientY]);
|
||||
const clrIndex = this.renderer.getColorIndexOfPixel(...coords);
|
||||
if (clrIndex === null) {
|
||||
return;
|
||||
}
|
||||
store.dispatch(selectColor(clrIndex));
|
||||
}
|
||||
|
||||
onKeyPress(event: KeyboardEvent) {
|
||||
// ignore key presses if modal is open or chat is used
|
||||
if (event.target.nodeName === 'INPUT'
|
||||
|| event.target.nodeName === 'TEXTAREA'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const { store } = this;
|
||||
|
||||
switch (keycode(event)) {
|
||||
case 'up':
|
||||
case 'w':
|
||||
store.dispatch(moveNorth());
|
||||
break;
|
||||
case 'left':
|
||||
case 'a':
|
||||
store.dispatch(moveWest());
|
||||
break;
|
||||
case 'down':
|
||||
case 's':
|
||||
store.dispatch(moveSouth());
|
||||
break;
|
||||
case 'right':
|
||||
case 'd':
|
||||
store.dispatch(moveEast());
|
||||
break;
|
||||
/*
|
||||
case 'space':
|
||||
if ($viewport) $viewport.click();
|
||||
return;
|
||||
*/
|
||||
case '+':
|
||||
case 'e':
|
||||
store.dispatch(zoomIn());
|
||||
break;
|
||||
case '-':
|
||||
case 'q':
|
||||
store.dispatch(zoomOut());
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function removeControls() {
|
||||
document.removeEventListener('keydown', onKeyPress, false);
|
||||
}
|
||||
export default PixelPlainterControls;
|
||||
|
|
|
@ -18,10 +18,7 @@ import {
|
|||
renderPlaceholder,
|
||||
renderPotatoPlaceholder,
|
||||
} from './render2Delements';
|
||||
import {
|
||||
initControls,
|
||||
removeControls,
|
||||
} from '../controls/PixelPainterControls';
|
||||
import PixelPainterControls from '../controls/PixelPainterControls';
|
||||
|
||||
|
||||
import ChunkLoader from './ChunkLoader2D';
|
||||
|
@ -90,7 +87,7 @@ class Renderer {
|
|||
}
|
||||
|
||||
destructor() {
|
||||
removeControls(this.viewport);
|
||||
this.controls.dispose();
|
||||
window.removeEventListener('resize', this.resizeHandle);
|
||||
this.viewport.remove();
|
||||
}
|
||||
|
@ -120,8 +117,8 @@ class Renderer {
|
|||
canvasSize,
|
||||
} = state.canvas;
|
||||
this.updateCanvasData(state);
|
||||
initControls(this, this.viewport, store);
|
||||
this.updateScale(viewscale, canvasMaxTiledZoom, view, canvasSize);
|
||||
this.controls = new PixelPainterControls(this, this.viewport, store);
|
||||
}
|
||||
|
||||
updateCanvasData(state: State) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user