UNPKG

@stringsync/vexml

Version:

MusicXML to Vexflow

298 lines (297 loc) 12 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.EventMappingFactory = void 0; const spatial = __importStar(require("../spatial")); const util = __importStar(require("../util")); const MOUSEDOWN_MOVEMENT_TOLERANCE = 10; const LONGPRESS_DURATION_MS = 500; class EventMappingFactory { root; elementLocator; timestampLocator; topic; constructor(root, elementLocator, timestampLocator, topic) { this.root = root; this.elementLocator = elementLocator; this.timestampLocator = timestampLocator; this.topic = topic; } static create(root, elementLocator, timestampLocator, topic, inputType) { return new EventMappingFactory(root, elementLocator, timestampLocator, topic).create(inputType); } create(inputType) { switch (inputType) { case 'mouse': return [this.mousePress(), this.mouseEgress(), this.scroll()]; case 'touch': return [this.touchPress(), this.touchEgress(), this.scroll()]; case 'hybrid': return [...this.create('mouse'), ...this.create('touch')]; case 'auto': switch (util.device().inputType) { case 'mouseonly': return this.create('mouse'); case 'touchonly': return this.create('touch'); case 'hybrid': return this.create('hybrid'); default: return []; } default: return []; } } locate(clientPoint) { const point = this.point(clientPoint); const targets = this.elementLocator.locate(point); const closestTarget = targets[0] ?? null; const timestampMs = this.timestampLocator.locate(point)?.ms ?? null; return { point, target: closestTarget, timestampMs }; } point(clientPoint) { const rect = this.root.getOverlay().getElement().getBoundingClientRect(); const x = clientPoint.clientX - rect.left; const y = clientPoint.clientY - rect.top; return new spatial.Point(x, y); } scroll() { const scrollContainer = this.root.getScrollContainer(); return { src: 'scroll', vexml: ['scroll', 'scroll'], native: { scroll: (event) => { this.topic.publish('scroll', { type: 'scroll', scrollX: scrollContainer.scrollLeft, scrollY: scrollContainer.scrollTop, native: event, }); }, }, }; } mousePress() { let timeout = 0; let lastMouseDownInvocation = Symbol(); let lastMouseDownPoint = spatial.Point.origin(); let isPending = false; return { src: 'overlay', vexml: ['click', 'longpress'], native: { mousedown: (event) => { const mouseDownInvocation = Symbol(); const { point, target: closestTarget, timestampMs } = this.locate(event); if (!closestTarget) { return; } lastMouseDownInvocation = mouseDownInvocation; lastMouseDownPoint = point; isPending = true; timeout = setTimeout(() => { if (lastMouseDownInvocation === mouseDownInvocation) { this.topic.publish('longpress', { type: 'longpress', target: closestTarget, point, native: event, timestampMs, }); } isPending = false; }, LONGPRESS_DURATION_MS); }, mousemove: (event) => { if (isPending && lastMouseDownPoint.distance(this.point(event)) > MOUSEDOWN_MOVEMENT_TOLERANCE) { clearTimeout(timeout); isPending = false; } }, mouseup: (event) => { if (isPending) { const { point, target: closestTarget, timestampMs } = this.locate(event); if (closestTarget) { this.topic.publish('click', { type: 'click', target: closestTarget, point, native: event, timestampMs }); } } clearTimeout(timeout); lastMouseDownInvocation = Symbol(); lastMouseDownPoint = spatial.Point.origin(); isPending = false; }, }, }; } mouseEgress() { let lastResult = null; return { src: 'overlay', vexml: ['enter', 'exit'], native: { mousemove: (event) => { const result = this.locate(event); if (lastResult && lastResult.target && lastResult.target !== result.target) { this.topic.publish('exit', { type: 'exit', target: lastResult.target, point: lastResult.point, native: event, timestampMs: lastResult.timestampMs, }); } if (result.target && result.target !== lastResult?.target) { this.topic.publish('enter', { type: 'enter', target: result.target, point: result.point, native: event, timestampMs: result.timestampMs, }); } lastResult = result; }, }, }; } touchPress() { let timeout = undefined; let isPending = false; let lastTouchStartInvocation = Symbol(); return { src: 'overlay', vexml: ['click', 'longpress'], native: { touchstart: (event) => { const touchStartInvocation = Symbol(); const { point, target: closestTarget, timestampMs } = this.locate(event.touches[0]); if (!closestTarget) { return; } lastTouchStartInvocation = touchStartInvocation; isPending = true; timeout = setTimeout(() => { if (lastTouchStartInvocation === touchStartInvocation) { this.topic.publish('longpress', { type: 'longpress', target: closestTarget, point, native: event, timestampMs, }); } isPending = false; }, LONGPRESS_DURATION_MS); }, touchmove: () => { clearTimeout(timeout); isPending = false; }, touchend: (event) => { if (isPending) { const { point, target: closestTarget, timestampMs } = this.locate(event.changedTouches[0]); if (closestTarget) { this.topic.publish('click', { type: 'click', target: closestTarget, point, native: event, timestampMs }); } } clearTimeout(timeout); isPending = false; }, touchcancel: () => { clearTimeout(timeout); isPending = false; }, }, }; } touchEgress() { let lastResult = null; return { src: 'overlay', vexml: ['enter', 'exit'], native: { touchmove: (event) => { const result = this.locate(event.touches[0]); if (lastResult && lastResult.target && lastResult.target !== result.target) { this.topic.publish('exit', { type: 'exit', target: lastResult.target, point: lastResult.point, native: event, timestampMs: lastResult.timestampMs, }); } if (result.target && result.target !== lastResult?.target) { this.topic.publish('enter', { type: 'enter', target: result.target, point: result.point, native: event, timestampMs: result.timestampMs, }); lastResult = result; } }, touchcancel: (event) => { if (lastResult?.target) { this.topic.publish('exit', { type: 'exit', target: lastResult.target, point: lastResult.point, native: event, timestampMs: lastResult.timestampMs, }); lastResult = null; } }, touchend: (event) => { if (lastResult?.target) { this.topic.publish('exit', { type: 'exit', target: lastResult.target, point: lastResult.point, native: event, timestampMs: lastResult.timestampMs, }); lastResult = null; } }, }, }; } } exports.EventMappingFactory = EventMappingFactory;