{"version":3,"file":"PanSession.mjs","sources":["../../../../src/gestures/pan/PanSession.ts"],"sourcesContent":["import type { EventInfo, PanHandler } from \"motion-dom\"\nimport { cancelFrame, frame, frameData, isPrimaryPointer } from \"motion-dom\"\nimport {\n    millisecondsToSeconds,\n    pipe,\n    Point,\n    secondsToMilliseconds,\n    TransformPoint,\n} from \"motion-utils\"\nimport { addPointerEvent } from \"../../events/add-pointer-event\"\nimport { extractEventInfo } from \"../../events/event-info\"\nimport { distance2D } from \"../../utils/distance\"\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\n    distanceThreshold?: number\n    contextWindow?: (Window & typeof globalThis) | null\n}\n\ninterface TimestampedPoint extends Point {\n    timestamp: number\n}\n\n/**\n * @internal\n */\nexport class PanSession {\n    /**\n     * @internal\n     */\n    private history: TimestampedPoint[]\n\n    /**\n     * @internal\n     */\n    private startEvent: PointerEvent | null = null\n\n    /**\n     * @internal\n     */\n    private lastMoveEvent: PointerEvent | null = null\n\n    /**\n     * @internal\n     */\n    private lastMoveEventInfo: EventInfo | null = null\n\n    /**\n     * @internal\n     */\n    private transformPagePoint?: TransformPoint\n\n    /**\n     * @internal\n     */\n    private handlers: Partial<PanSessionHandlers> = {}\n\n    /**\n     * @internal\n     */\n    private removeListeners: Function\n\n    /**\n     * For determining if an animation should resume after it is interupted\n     *\n     * @internal\n     */\n    private dragSnapToOrigin: boolean\n\n    /**\n     * The distance after which panning should start.\n     *\n     * @internal\n     */\n    private distanceThreshold: number\n\n    /**\n     * @internal\n     */\n    private contextWindow: PanSessionOptions[\"contextWindow\"] = window\n\n    constructor(\n        event: PointerEvent,\n        handlers: Partial<PanSessionHandlers>,\n        {\n            transformPagePoint,\n            contextWindow = window,\n            dragSnapToOrigin = false,\n            distanceThreshold = 3,\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 = 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        const { timestamp } = frameData\n\n        this.history = [{ ...point, timestamp }]\n\n        const { onSessionStart } = handlers\n        onSessionStart &&\n            onSessionStart(event, getPanInfo(initialInfo, this.history))\n\n        this.removeListeners = pipe(\n            addPointerEvent(\n                this.contextWindow,\n                \"pointermove\",\n                this.handlePointerMove\n            ),\n            addPointerEvent(\n                this.contextWindow,\n                \"pointerup\",\n                this.handlePointerUp\n            ),\n            addPointerEvent(\n                this.contextWindow,\n                \"pointercancel\",\n                this.handlePointerUp\n            )\n        )\n    }\n\n    private updatePoint = () => {\n        if (!(this.lastMoveEvent && this.lastMoveEventInfo)) return\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        const { timestamp } = frameData\n        this.history.push({ ...point, timestamp })\n\n        const { onStart, onMove } = this.handlers\n\n        if (!isPanStarted) {\n            onStart && onStart(this.lastMoveEvent, info)\n            this.startEvent = this.lastMoveEvent\n        }\n\n        onMove && onMove(this.lastMoveEvent, info)\n    }\n\n    private handlePointerMove = (event: PointerEvent, info: EventInfo) => {\n        this.lastMoveEvent = event\n        this.lastMoveEventInfo = transformPoint(info, this.transformPagePoint)\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        this.end()\n\n        const { onEnd, onSessionEnd, resumeAnimation } = this.handlers\n\n        if (this.dragSnapToOrigin) resumeAnimation && resumeAnimation()\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        if (this.startEvent && onEnd) {\n            onEnd(event, panInfo)\n        }\n\n        onSessionEnd && onSessionEnd(event, panInfo)\n    }\n\n    updateHandlers(handlers: Partial<PanSessionHandlers>) {\n        this.handlers = handlers\n    }\n\n    end() {\n        this.removeListeners && this.removeListeners()\n        cancelFrame(this.updatePoint)\n    }\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    const time = millisecondsToSeconds(\n        lastPoint.timestamp - timestampedPoint.timestamp\n    )\n    if (time === 0) {\n        return { x: 0, y: 0 }\n    }\n\n    const currentVelocity = {\n        x: (lastPoint.x - timestampedPoint.x) / time,\n        y: (lastPoint.y - timestampedPoint.y) / time,\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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"}