UNPKG

ixfx

Version:

A framework for programming interactivity

337 lines (333 loc) 8.7 kB
import { TrackedValueMap, TrackerBase } from "./chunk-7ICNCHYJ.js"; import { Empty, Vector_exports, joinPointsToLines } from "./chunk-AKHRG6J4.js"; import { Placeholder, angleRadian, distance, length, relation, subtract } from "./chunk-R4JIRHLR.js"; import { toStringDefault } from "./chunk-6UZ3OSJO.js"; // src/trackers/ObjectTracker.ts var ObjectTracker = class extends TrackerBase { constructor(opts = {}) { super(opts); this.values = []; } onTrimmed(reason) { } /** * Reduces size of value store to `limit`. * Returns number of remaining items * @param limit */ trimStore(limit) { if (limit >= this.values.length) return this.values.length; this.values = this.values.slice(-limit); return this.values.length; } /** * Allows sub-classes to be notified when a reset happens * @ignore */ onReset() { this.values = []; } /** * Tracks a value * @ignore */ filterData(p) { const ts = p.map( (v) => `at` in v ? v : { ...v, at: Date.now() } ); const last = ts.at(-1); if (this.storeIntermediate) this.values.push(...ts); else switch (this.values.length) { case 0: { this.values.push(last); break; } case 1: { this.values.push(last); break; } case 2: { this.values[1] = last; break; } } return ts; } /** * Last seen value. If no values have been added, it will return the initial value */ get last() { if (this.values.length === 1) return this.values[0]; return this.values.at(-1); } /** * Returns the oldest value in the buffer */ get initial() { return this.values.at(0); } /** * Returns number of recorded values (includes the initial value in the count) */ get size() { return this.values.length; } /** * Returns the elapsed time, in milliseconds since the initial value */ get elapsed() { return Date.now() - this.values[0].at; } }; // src/trackers/PointTracker.ts var PointTracker = class extends ObjectTracker { constructor(opts = {}) { super(opts); } /** * Notification that buffer has been knocked down to `sampleLimit`. * * This will reset the `initialRelation`, which will use the new oldest value. */ onTrimmed(reason) { this.initialRelation = void 0; } /** * @ignore */ onReset() { super.onReset(); this.lastResult = void 0; this.initialRelation = void 0; this.markRelation = void 0; } /** * Adds a PointerEvent along with its * coalesced events, if available. * @param p * @returns */ seenEvent(p) { if (`getCoalescedEvents` in p) { const events = p.getCoalescedEvents(); const asPoints = events.map((event) => ({ x: event.clientX, y: event.clientY })); return this.seen(...asPoints); } else { return this.seen({ x: p.clientX, y: p.clientY }); } } /** * Makes a 'mark' in the tracker, allowing you to compare values * to this point. */ mark() { this.markRelation = relation(this.last); } /** * Tracks a point, returning data on its relation to the * initial point and the last received point. * * Use {@link seenEvent} to track a raw `PointerEvent`. * * @param _p Point */ computeResults(_p) { const currentLast = this.last; const previousLast = this.values.at(-2); if (this.initialRelation === void 0 && this.initial) { this.initialRelation = relation(this.initial); } else if (this.initialRelation === void 0) { throw new Error(`Bug: No initialRelation, and this.inital is undefined?`); } const lastRelation = previousLast === void 0 ? relation(currentLast) : relation(previousLast); const initialRel = this.initialRelation(currentLast); const markRel = this.markRelation !== void 0 ? this.markRelation(currentLast) : void 0; const speed = previousLast === void 0 ? 0 : length(previousLast, currentLast) / (currentLast.at - previousLast.at); const lastRel = { ...lastRelation(currentLast), speed }; const r = { fromInitial: initialRel, fromLast: lastRel, fromMark: markRel, values: [...this.values] }; this.lastResult = r; return r; } /** * Returns a polyline representation of stored points. * Returns an empty array if points were not saved, or there's only one. */ get line() { if (this.values.length === 1) return []; return joinPointsToLines(...this.values); } /** * Returns a vector of the initial/last points of the tracker. * Returns as a polar coordinate */ get vectorPolar() { return Vector_exports.fromLinePolar(this.lineStartEnd); } /** * Returns a vector of the initial/last points of the tracker. * Returns as a Cartesian coordinate */ get vectorCartesian() { return Vector_exports.fromLineCartesian(this.lineStartEnd); } /** * Returns a line from initial point to last point. * * If there are less than two points, Lines.Empty is returned */ get lineStartEnd() { const initial = this.initial; if (this.values.length < 2 || !initial) return Empty; return { a: initial, b: this.last }; } /** * Returns distance from latest point to initial point. * If there are less than two points, zero is returned. * * This is the direct distance from initial to last, * not the accumulated length. * @returns Distance */ distanceFromStart() { const initial = this.initial; return this.values.length >= 2 && initial !== void 0 ? distance(initial, this.last) : 0; } /** * Difference between last point and the initial point, calculated * as a simple subtraction of x,y & z. * * `Points.Placeholder` is returned if there's only one point so far. */ difference() { const initial = this.initial; return this.values.length >= 2 && initial !== void 0 ? subtract(this.last, initial) : Placeholder; } /** * Returns angle (in radians) from latest point to the initial point * If there are less than two points, undefined is return. * @returns Angle in radians */ angleFromStart() { const initial = this.initial; if (initial !== void 0 && this.values.length > 2) { return angleRadian(initial, this.last); } } /** * Returns the total length of accumulated points. * Returns 0 if points were not saved, or there's only one */ get length() { if (this.values.length === 1) return 0; const l = this.line; return length(l); } /** * Returns the last x coord */ get x() { return this.last.x; } /** * Returns the last y coord */ get y() { return this.last.y; } /** * Returns the last z coord (or _undefined_ if not available) */ get z() { return this.last.z; } }; var TrackedPointMap = class extends TrackedValueMap { constructor(opts = {}) { super((key, start) => { if (start === void 0) throw new Error(`Requires start point`); const p = new PointTracker({ ...opts, id: key }); p.seen(start); return p; }); } /** * Track a PointerEvent * @param event */ seenEvent(event) { if (`getCoalescedEvents` in event) { const events = event.getCoalescedEvents(); const seens = events.map((subEvent) => super.seen(subEvent.pointerId.toString(), subEvent)); return Promise.all(seens); } else { return Promise.all([super.seen(event.pointerId.toString(), event)]); } } }; var points = (options = {}) => new TrackedPointMap(options); var point = (opts = {}) => new PointTracker(opts); // src/trackers/TrackUnique.ts var unique = (toString = toStringDefault) => { const set = /* @__PURE__ */ new Set(); return (value) => { if (value === null) throw new TypeError(`Param 'value' cannot be null`); if (value === void 0) throw new TypeError(`Param 'value' cannot be undefined`); const asString = typeof value === `string` ? value : toString(value); if (set.has(asString)) return false; set.add(asString); return true; }; }; var uniqueInstances = () => { const set = /* @__PURE__ */ new Set(); return (value) => { if (value === null) throw new TypeError(`Param 'value' cannot be null`); if (value === void 0) throw new TypeError(`Param 'value' cannot be undefined`); if (set.has(value)) return false; set.add(value); return true; }; }; export { ObjectTracker, PointTracker, TrackedPointMap, points, point, unique, uniqueInstances }; //# sourceMappingURL=chunk-SDJ3QNB4.js.map