UNPKG

motion-dom

Version:
1 lines • 22.6 kB
{"version":3,"file":"PanSession.mjs","sources":["../../../../src/gestures/pan/PanSession.ts"],"sourcesContent":["import { addDomEvent } from \"../../events/add-dom-event\"\nimport { addPointerEvent } from \"../../events/add-pointer-event\"\nimport { extractEventInfo } from \"../../events/event-info\"\nimport { cancelFrame, frame } from \"../../frameloop/frame\"\nimport { time } from \"../../frameloop/sync-time\"\nimport type { EventInfo } from \"../../node/types\"\nimport { distance2D } from \"../../utils/distance\"\nimport { isPrimaryPointer } from \"../utils/is-primary-pointer\"\nimport type { PanHandler } from \"./types\"\nimport {\n millisecondsToSeconds,\n pipe,\n Point,\n secondsToMilliseconds,\n TransformPoint,\n} from \"motion-utils\"\n\ninterface PanSessionHandlers {\n onSessionStart: PanHandler\n onStart: PanHandler\n onMove: PanHandler\n onEnd: PanHandler\n onSessionEnd: PanHandler\n resumeAnimation: () => void\n}\n\ninterface PanSessionOptions {\n transformPagePoint?: TransformPoint\n dragSnapToOrigin?: boolean | \"x\" | \"y\"\n distanceThreshold?: number\n contextWindow?: (Window & typeof globalThis) | null\n /**\n * Element being dragged. When provided, scroll events on its\n * ancestors and window are compensated so the gesture continues\n * smoothly during scroll.\n */\n element?: HTMLElement | null\n /**\n * Start panning from `event` straight away, as if the pointer had moved\n * there, rather than waiting for it to move past `distanceThreshold`.\n */\n immediate?: boolean\n}\n\ninterface TimestampedPoint extends Point {\n timestamp: number\n}\n\nconst overflowStyles = /*#__PURE__*/ new Set([\"auto\", \"scroll\"])\n\nexport class PanSession {\n /**\n * The pointer's points since the session started. The first is where\n * offsets are measured from. Public so pinch() can restart a drag\n * from where it leaves the element.\n */\n history: TimestampedPoint[]\n\n private startEvent: PointerEvent | null = null\n\n private lastMoveEvent: PointerEvent | null = null\n\n private lastMoveEventInfo: EventInfo | null = null\n\n /**\n * Raw (untransformed) event info, re-transformed each frame\n * so transformPagePoint sees the current parent matrix.\n */\n private lastRawMoveEventInfo: EventInfo | null = null\n\n /**\n * Whether a pointermove has arrived since the last updatePoint.\n */\n private hasPendingMove?: boolean\n\n private transformPagePoint?: TransformPoint\n\n private handlers: Partial<PanSessionHandlers> = {}\n\n private removeListeners?: Function\n\n /**\n * For determining if an animation should resume after it is interrupted\n */\n private dragSnapToOrigin: boolean | \"x\" | \"y\"\n\n /**\n * The distance after which panning should start.\n */\n private distanceThreshold: number\n\n private contextWindow: PanSessionOptions[\"contextWindow\"] = window\n\n /**\n * Scroll positions of scrollable ancestors and window.\n */\n private scrollPositions: Map<Element | Window, Point> = new Map()\n\n /**\n * Cleanup function for scroll listeners.\n */\n private removeScrollListeners?: Function\n\n constructor(\n event: PointerEvent,\n handlers: Partial<PanSessionHandlers>,\n {\n transformPagePoint,\n contextWindow = window,\n dragSnapToOrigin = false,\n distanceThreshold = 3,\n element,\n immediate,\n }: PanSessionOptions = {}\n ) {\n // If we have more than one touch, don't start detecting this gesture\n if (!isPrimaryPointer(event)) return\n\n this.dragSnapToOrigin = dragSnapToOrigin\n this.handlers = handlers\n this.transformPagePoint = transformPagePoint\n this.distanceThreshold = immediate ? 0 : distanceThreshold\n this.contextWindow = contextWindow || window\n\n const info = extractEventInfo(event)\n const initialInfo = transformPoint(info, this.transformPagePoint)\n const { point } = initialInfo\n\n /**\n * Stamp the origin with time.now(), not frameData.timestamp: when\n * the frameloop is idle, frameData.timestamp is from the last frame\n * that ran, which can be seconds old, and a fast flick from a\n * standstill would then report near-zero velocity. See #1747.\n */\n this.history = [{ ...point, timestamp: time.now() }]\n\n const { onSessionStart } = handlers\n onSessionStart &&\n onSessionStart(event, getPanInfo(initialInfo, this.history))\n\n // Listen in the capture phase so a descendant calling\n // stopPropagation() (e.g. in its own pointerup handler) can't\n // prevent the gesture from ending. See #2794.\n const eventOptions = { passive: true, capture: true }\n this.removeListeners = pipe(\n addPointerEvent(\n this.contextWindow,\n \"pointermove\",\n this.handlePointerMove,\n eventOptions\n ),\n addPointerEvent(\n this.contextWindow,\n \"pointerup\",\n this.handlePointerUp,\n eventOptions\n ),\n addPointerEvent(\n this.contextWindow,\n \"pointercancel\",\n this.handlePointerUp,\n eventOptions\n )\n )\n\n // Start scroll tracking if element provided\n if (element) {\n this.startScrollTracking(element)\n }\n\n if (immediate) {\n this.handlePointerMove(event, info)\n this.updatePoint()\n }\n }\n\n /**\n * Start tracking scroll on ancestors and window.\n */\n private startScrollTracking(element: HTMLElement): void {\n // Store initial scroll positions for scrollable ancestors\n let current = element.parentElement\n while (current) {\n const style = getComputedStyle(current)\n if (\n overflowStyles.has(style.overflowX) ||\n overflowStyles.has(style.overflowY)\n ) {\n this.scrollPositions.set(current, getScroll(current))\n }\n current = current.parentElement\n }\n\n // Track window scroll\n this.scrollPositions.set(window, getScroll(window))\n\n this.removeScrollListeners = pipe(\n // Capture listener catches element scroll events as they bubble\n addDomEvent(window, \"scroll\", this.onElementScroll, {\n capture: true,\n }),\n // Direct window scroll listener (window scroll doesn't bubble)\n addDomEvent(window, \"scroll\", this.onWindowScroll, {})\n )\n }\n\n private onElementScroll = (event: Event): void => {\n this.handleScroll(event.target as Element)\n }\n\n private onWindowScroll = (): void => {\n this.handleScroll(window)\n }\n\n /**\n * Handle scroll compensation during drag.\n *\n * For element scroll: adjusts history origin since pageX/pageY doesn't change.\n * For window scroll: adjusts lastMoveEventInfo since pageX/pageY would change.\n */\n private handleScroll(target: Element | Window): void {\n const initial = this.scrollPositions.get(target)\n if (!initial) return\n\n const isWindow = target === window\n const current = getScroll(target)\n\n const delta = { x: current.x - initial.x, y: current.y - initial.y }\n if (delta.x === 0 && delta.y === 0) return\n\n if (isWindow) {\n // Window scroll: pageX/pageY changes, so update lastMoveEventInfo\n if (this.lastMoveEventInfo) {\n this.lastMoveEventInfo.point.x += delta.x\n this.lastMoveEventInfo.point.y += delta.y\n }\n } else {\n // Element scroll: pageX/pageY unchanged, so adjust history origin\n if (this.history.length > 0) {\n this.history[0].x -= delta.x\n this.history[0].y -= delta.y\n }\n }\n\n this.scrollPositions.set(target, current)\n frame.update(this.updatePoint, true)\n }\n\n private updatePoint = () => {\n if (!(this.lastMoveEvent && this.lastMoveEventInfo)) return\n this.hasPendingMove = false\n\n // Re-transform raw point through current transformPagePoint so\n // animated parent transforms (e.g. rotation) are picked up each frame\n if (this.lastRawMoveEventInfo) {\n this.lastMoveEventInfo = transformPoint(\n this.lastRawMoveEventInfo,\n this.transformPagePoint\n )\n }\n\n const info = getPanInfo(this.lastMoveEventInfo, this.history)\n const isPanStarted = this.startEvent !== null\n\n // Only start panning if the offset is larger than 3 pixels. If we make it\n // any larger than this we'll want to reset the pointer history\n // on the first update to avoid visual snapping to the cursor.\n const isDistancePastThreshold =\n distance2D(info.offset, { x: 0, y: 0 }) >= this.distanceThreshold\n\n if (!isPanStarted && !isDistancePastThreshold) return\n\n const { point } = info\n this.history.push({ ...point, timestamp: time.now() })\n\n const { onStart, onMove } = this.handlers\n\n if (!isPanStarted) {\n onStart?.(this.lastMoveEvent, info)\n this.startEvent = this.lastMoveEvent\n }\n\n onMove?.(this.lastMoveEvent, info)\n }\n\n private handlePointerMove = (event: PointerEvent, info: EventInfo) => {\n /**\n * This event's pageX/pageY already include any window scroll that\n * hasn't fired its scroll event yet. Settle it now, so that scroll\n * event doesn't add it to the new point a second time.\n */\n this.handleScroll(window)\n\n this.lastMoveEvent = event\n this.lastRawMoveEventInfo = info\n this.lastMoveEventInfo = transformPoint(info, this.transformPagePoint)\n this.hasPendingMove = true\n\n // Throttle mouse move event to once per frame\n frame.update(this.updatePoint, true)\n }\n\n private handlePointerUp = (event: PointerEvent, info: EventInfo) => {\n // Browsers flush a coalesced pointermove immediately before\n // pointerup, so the final move can still be waiting for a frame.\n this.hasPendingMove && this.updatePoint()\n this.end()\n\n const { onEnd, onSessionEnd, resumeAnimation } = this.handlers\n\n // Resume animation if dragSnapToOrigin is set OR if no drag started (user just clicked)\n // This ensures constraint animations continue when interrupted by a click\n if (this.dragSnapToOrigin || !this.startEvent) {\n resumeAnimation?.()\n }\n if (!(this.lastMoveEvent && this.lastMoveEventInfo)) return\n\n const panInfo = getPanInfo(\n event.type === \"pointercancel\"\n ? this.lastMoveEventInfo\n : transformPoint(info, this.transformPagePoint),\n this.history\n )\n\n this.startEvent && onEnd?.(event, panInfo)\n onSessionEnd?.(event, panInfo)\n }\n\n updateHandlers(handlers: Partial<PanSessionHandlers>) {\n this.handlers = handlers\n }\n\n end() {\n this.removeListeners?.()\n this.removeScrollListeners?.()\n this.scrollPositions.clear()\n cancelFrame(this.updatePoint)\n }\n}\n\nconst getScroll = (target: Element | Window): Point =>\n target === window\n ? { x: window.scrollX, y: window.scrollY }\n : {\n x: (target as Element).scrollLeft,\n y: (target as Element).scrollTop,\n }\n\nfunction transformPoint(\n info: EventInfo,\n transformPagePoint?: (point: Point) => Point\n) {\n return transformPagePoint ? { point: transformPagePoint(info.point) } : info\n}\n\nfunction subtractPoint(a: Point, b: Point): Point {\n return { x: a.x - b.x, y: a.y - b.y }\n}\n\nfunction getPanInfo({ point }: EventInfo, history: TimestampedPoint[]) {\n return {\n point,\n delta: subtractPoint(point, lastDevicePoint(history)),\n offset: subtractPoint(point, startDevicePoint(history)),\n velocity: getVelocity(history, 0.1),\n }\n}\n\nfunction startDevicePoint(history: TimestampedPoint[]): TimestampedPoint {\n return history[0]\n}\n\nfunction lastDevicePoint(history: TimestampedPoint[]): TimestampedPoint {\n return history[history.length - 1]\n}\n\nfunction getVelocity(history: TimestampedPoint[], timeDelta: number): Point {\n if (history.length < 2) {\n return { x: 0, y: 0 }\n }\n\n let i = history.length - 1\n let timestampedPoint: TimestampedPoint | null = null\n const lastPoint = lastDevicePoint(history)\n while (i >= 0) {\n timestampedPoint = history[i]\n if (\n lastPoint.timestamp - timestampedPoint.timestamp >\n secondsToMilliseconds(timeDelta)\n ) {\n break\n }\n i--\n }\n\n if (!timestampedPoint) {\n return { x: 0, y: 0 }\n }\n\n /**\n * If the selected point is the pointer-down origin (history[0]),\n * there are better movement points available, and the time gap\n * is suspiciously large (>2x timeDelta), use the next point instead.\n * This prevents stale pointer-down points from diluting velocity\n * in hold-then-flick gestures.\n */\n if (\n timestampedPoint === history[0] &&\n history.length > 2 &&\n lastPoint.timestamp - timestampedPoint.timestamp >\n secondsToMilliseconds(timeDelta) * 2\n ) {\n timestampedPoint = history[1]\n }\n\n const seconds = millisecondsToSeconds(\n lastPoint.timestamp - timestampedPoint.timestamp\n )\n if (seconds === 0) {\n return { x: 0, y: 0 }\n }\n\n const currentVelocity = {\n x: (lastPoint.x - timestampedPoint.x) / seconds,\n y: (lastPoint.y - timestampedPoint.y) / seconds,\n }\n\n if (currentVelocity.x === Infinity) {\n currentVelocity.x = 0\n }\n if (currentVelocity.y === Infinity) {\n currentVelocity.y = 0\n }\n\n return currentVelocity\n}\n"],"names":[],"mappings":"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"}