118 lines
3.2 KiB
JavaScript
Executable File
118 lines
3.2 KiB
JavaScript
Executable File
import { MovementXSmbl, MovementYSmbl } from './move-evt-mobile-fix.js';
|
|
import { listenDel, listen } from './util.js';
|
|
|
|
/**
|
|
* @param { Element } elemTrackOutdown poitdows in this element will be tracking to fire {onOutdown} callback
|
|
* @param { Element } elem
|
|
* @param { {scale:number} } canvasScale
|
|
* @param { Point } shapePosition
|
|
* @param { {(evt:PointerEvent):void} } onMoveStart
|
|
* @param { {(evt:PointerEvent):void} } onMove
|
|
* @param { {(evt:PointerEvent):void} } onMoveEnd
|
|
* @param { {(evt:PointerEvent):void} } onClick
|
|
* @param { {():void} } onOutdown
|
|
*/
|
|
export function moveEvtProc(elemTrackOutdown, elem, canvasScale, shapePosition, onMoveStart, onMove, onMoveEnd, onClick, onOutdown) {
|
|
let isMoved = false;
|
|
let isInit = false;
|
|
/** @type {Element} */ let target;
|
|
|
|
/** @param {PointerEventFixMovement} evt */
|
|
function move(evt) {
|
|
if (!isInit) { return; }
|
|
|
|
if (!isMoved) {
|
|
onMoveStart(evt);
|
|
|
|
// if reset
|
|
if (!isInit) { return; }
|
|
}
|
|
|
|
movementApplay(shapePosition, canvasScale.scale, evt);
|
|
isMoved = true;
|
|
onMove(evt);
|
|
}
|
|
|
|
/** @param {PointerEvent} evt */
|
|
function cancel(evt) {
|
|
if (isMoved) {
|
|
onMoveEnd(evt);
|
|
} else {
|
|
onClick(evt);
|
|
}
|
|
reset(true);
|
|
}
|
|
|
|
/** @param {PointerEvent & { target:Node}} docEvt */
|
|
function docDown(docEvt) {
|
|
if (!elem.contains(docEvt.target)) {
|
|
reset();
|
|
onOutdown();
|
|
}
|
|
}
|
|
|
|
function wheel() {
|
|
reset();
|
|
onOutdown();
|
|
}
|
|
|
|
/**
|
|
* @param {ProcEvent} evt
|
|
*/
|
|
function init(evt) {
|
|
if (evt[ProcessedSmbl] || !evt.isPrimary) {
|
|
return;
|
|
}
|
|
|
|
evt[ProcessedSmbl] = true;
|
|
target = /** @type {Element} */(evt.target);
|
|
if (evt.pointerId !== fakePointerId) { target.setPointerCapture(evt.pointerId); }
|
|
listen(target, 'pointercancel', cancel, true);
|
|
listen(target, 'pointerup', cancel, true);
|
|
listen(target, 'pointermove', move);
|
|
|
|
listen(elemTrackOutdown, 'wheel', wheel, true);
|
|
listen(elemTrackOutdown, 'pointerdown', docDown);
|
|
|
|
isInit = true;
|
|
}
|
|
|
|
listen(elem, 'pointerdown', init);
|
|
|
|
/** @param {boolean=} saveOutTrack */
|
|
function reset(saveOutTrack) {
|
|
listenDel(target, 'pointercancel', cancel);
|
|
listenDel(target, 'pointerup', cancel);
|
|
listenDel(target, 'pointermove', move);
|
|
if (!saveOutTrack) {
|
|
listenDel(elemTrackOutdown, 'pointerdown', docDown);
|
|
listenDel(elemTrackOutdown, 'wheel', wheel);
|
|
}
|
|
target = null;
|
|
isMoved = false;
|
|
isInit = false;
|
|
}
|
|
|
|
return reset;
|
|
}
|
|
|
|
/** @param {Point} point, @param {number} scale, @param {PointerEventFixMovement} evt */
|
|
export function movementApplay(point, scale, evt) {
|
|
point.x += evt[MovementXSmbl] / scale;
|
|
point.y += evt[MovementYSmbl] / scale;
|
|
}
|
|
|
|
const fakePointerId = 42; // random number
|
|
/** @param {SVGGraphicsElement} shapeOrPathEl */
|
|
export function shapeSelect(shapeOrPathEl) {
|
|
shapeOrPathEl.ownerSVGElement.focus();
|
|
shapeOrPathEl.dispatchEvent(new PointerEvent('pointerdown', { isPrimary: true, pointerId: fakePointerId }));
|
|
shapeOrPathEl.dispatchEvent(new PointerEvent('pointerup', { isPrimary: true }));
|
|
}
|
|
|
|
export const ProcessedSmbl = Symbol('processed');
|
|
|
|
/** @typedef {PointerEvent & { [ProcessedSmbl]?: boolean }} ProcEvent */
|
|
/** @typedef {import('./move-evt-mobile-fix.js').PointerEventFixMovement} PointerEventFixMovement */
|
|
/** @typedef { {x:number, y:number} } Point */
|