UNPKG

svelte-motion

Version:

Svelte animation library based on the React library framer-motion.

158 lines (155 loc) 6.02 kB
/** based on framer-motion@4.0.3, Copyright (c) 2018 Framer B.V. */ import {fixed} from '../utils/fix-process-env'; import { isMouseEvent, isTouchEvent } from './utils/event-type.js'; import { extractEventInfo } from '../events/event-info.js'; import sync, { getFrameData, cancelSync } from 'framesync'; import { secondsToMilliseconds } from '../utils/time-conversion.js'; import { addPointerEvent } from '../events/use-pointer-event.js'; import { distance, pipe } from 'popmotion'; /** * @internal */ var PanSession = /** @class */ (function () { function PanSession(event, handlers, _a) { var _this = this; var _b = _a === void 0 ? {} : _a, transformPagePoint = _b.transformPagePoint; /** * @internal */ this.startEvent = null; /** * @internal */ this.lastMoveEvent = null; /** * @internal */ this.lastMoveEventInfo = null; /** * @internal */ this.handlers = {}; this.updatePoint = function () { if (!(_this.lastMoveEvent && _this.lastMoveEventInfo)) return; var info = getPanInfo(_this.lastMoveEventInfo, _this.history); var isPanStarted = _this.startEvent !== null; // Only start panning if the offset is larger than 3 pixels. If we make it // any larger than this we'll want to reset the pointer history // on the first update to avoid visual snapping to the cursoe. var isDistancePastThreshold = distance(info.offset, { x: 0, y: 0 }) >= 3; if (!isPanStarted && !isDistancePastThreshold) return; var point = info.point; var timestamp = getFrameData().timestamp; _this.history.push(Object.assign(Object.assign({}, point), { timestamp: timestamp })); var _a = _this.handlers, onStart = _a.onStart, onMove = _a.onMove; if (!isPanStarted) { onStart && onStart(_this.lastMoveEvent, info); _this.startEvent = _this.lastMoveEvent; } onMove && onMove(_this.lastMoveEvent, info); }; this.handlePointerMove = function (event, info) { _this.lastMoveEvent = event; _this.lastMoveEventInfo = transformPoint(info, _this.transformPagePoint); // Because Safari doesn't trigger mouseup events when it's above a `<select>` if (isMouseEvent(event) && event.buttons === 0) { _this.handlePointerUp(event, info); return; } // Throttle mouse move event to once per frame sync.update(_this.updatePoint, true); }; this.handlePointerUp = function (event, info) { _this.end(); var _a = _this.handlers, onEnd = _a.onEnd, onSessionEnd = _a.onSessionEnd; var panInfo = getPanInfo(transformPoint(info, _this.transformPagePoint), _this.history); if (_this.startEvent && onEnd) { onEnd(event, panInfo); } onSessionEnd && onSessionEnd(event, panInfo); }; // If we have more than one touch, don't start detecting this gesture if (isTouchEvent(event) && event.touches.length > 1) return; this.handlers = handlers; this.transformPagePoint = transformPagePoint; var info = extractEventInfo(event); var initialInfo = transformPoint(info, this.transformPagePoint); var point = initialInfo.point; var timestamp = getFrameData().timestamp; this.history = [Object.assign(Object.assign({}, point), { timestamp: timestamp })]; var onSessionStart = handlers.onSessionStart; onSessionStart && onSessionStart(event, getPanInfo(initialInfo, this.history)); this.removeListeners = pipe(addPointerEvent(window, "pointermove", this.handlePointerMove), addPointerEvent(window, "pointerup", this.handlePointerUp), addPointerEvent(window, "pointercancel", this.handlePointerUp)); } PanSession.prototype.updateHandlers = function (handlers) { this.handlers = handlers; }; PanSession.prototype.end = function () { this.removeListeners && this.removeListeners(); cancelSync.update(this.updatePoint); }; return PanSession; }()); function transformPoint(info, transformPagePoint) { return transformPagePoint ? { point: transformPagePoint(info.point) } : info; } function subtractPoint(a, b) { return { x: a.x - b.x, y: a.y - b.y }; } function getPanInfo(_a, history) { var point = _a.point; return { point: point, delta: subtractPoint(point, lastDevicePoint(history)), offset: subtractPoint(point, startDevicePoint(history)), velocity: getVelocity(history, 0.1), }; } function startDevicePoint(history) { return history[0]; } function lastDevicePoint(history) { return history[history.length - 1]; } function getVelocity(history, timeDelta) { if (history.length < 2) { return { x: 0, y: 0 }; } var i = history.length - 1; var timestampedPoint = null; var lastPoint = lastDevicePoint(history); while (i >= 0) { timestampedPoint = history[i]; if (lastPoint.timestamp - timestampedPoint.timestamp > secondsToMilliseconds(timeDelta)) { break; } i--; } if (!timestampedPoint) { return { x: 0, y: 0 }; } var time = (lastPoint.timestamp - timestampedPoint.timestamp) / 1000; if (time === 0) { return { x: 0, y: 0 }; } var currentVelocity = { x: (lastPoint.x - timestampedPoint.x) / time, y: (lastPoint.y - timestampedPoint.y) / time, }; if (currentVelocity.x === Infinity) { currentVelocity.x = 0; } if (currentVelocity.y === Infinity) { currentVelocity.y = 0; } return currentVelocity; } export { PanSession };