ixfx
Version:
A framework for programming interactivity
337 lines (333 loc) • 8.7 kB
JavaScript
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