Tracking points
Single point
Tracking an x, y Point over time is common for working with gestures - be it touch gestures on a screen, or movements of limbs in space.
Trackers.point keeps track of a single point, returning an instance of Trackers.PointTracker .
import { Trackers } from 'https://unpkg.com/ixfx/dist/bundle.js';// Keep track of the last 10 pointsconst t = Trackers.point({ sampleLimit: 10})
Call seen()
whenever there is a point to track, for example, based on a ‘pointermove’ event.
const info = t.seen(event);// 'info' looks like: { fromInitial, fromLast, values }
seen()
returns Type Trackers.PointTrackerResults - { fromInitial, fromLast, values }
- which can be used for comparing the latest point with the initial point or the last point. values
is a set of all the recorded points, fromInitial
and fromLast
yield the relation between the very first seen point and the last point. For both of these, you get:
type PointRelationResult = { angle: number // in radians average: Point // average of all points centroid: Point distanceFromLast: number distanceFromStart: number}
For example:
const { fromInitial, fromLast } = t.seen(pointerEvent); // Add pointer event// How far away pointer is from the startconst d = fromInitial.fromInitial.distanceFromStart;
In action
In the example below, we start tracking when the pointer is down and add points when there is a pointer move event.
import { Trackers } from 'https://unpkg.com/ixfx/dist/bundle.js';
let tracker = null;
document.addEventListener(`pointerdown`, evt => { // Init new tracker tracker = Trackers.point(); tracker.seen({ x: evt.x, y: evt.y });});
document.addEventListener(`pointermove`, evt => { if (!tracker) return; const info = tracker.seen({x: evt.x, y: evt.y });
console.log(`Angle from start: ${info.fromInitial.angle}`);});
To get the last result without adding anything:
const nfo = tracker.lastResult;
PointTracker
There are a few additional features of the Trackers.PointTracker :
import { Trackers } from 'https://unpkg.com/ixfx/dist/bundle.js';const tracker = Trackers.point();
// Distance & angle from initial pointtracker.distanceFromStart(); // numbertracker.angleFromStart(); // number (radians)
// Latest point subtracted from initial pointtracker.difference(); // { x, y }
// Propertiestracker.length; // Total length of all points, connected togethertracker.lines; // Set of Lines connecting points in ordertracker.lineStartEnd; // Line that connects start and end point immediatelytracker.vectorCartesian; // Angle based on initial/lasttracker.vectorPolar; // Angle based on initial/lasttracker.x / tracker.y; // Last x,y
Multiple points
If you want to keep track of several different logical points, for example different touches in a multi-touch gesture, or body parts in TensorFlow, it can be a pain to create and manage several PointTracker instances.
Trackers.points to the rescue! It does all this housekeeping for you. Usage is very similar to the PointTracker, but now we have a TrackedPointMap .
import { Trackers } from 'https://unpkg.com/ixfx/dist/bundle.js';const t = Trackers.points(); // note the plural!
And then whenever there is new data for a point, call seen()
, giving the id of the point, and then the point ({x: .., y: ...}
). This could be based on a pointer event, or when new predictions are made by TensorFlow, for example.
t.seen(`nose`, pose[`nose`]);
In the example below, we track each named pointer id.
import { Trackers } from 'https://unpkg.com/ixfx/dist/bundle.js';
const tracker = Trackers.points();
document.addEventListener(`pointermove`, async e => { // Track a point by its id const info = await tracker.seen(e.pointerId, { x: e.x, y: e.y });});
To get data:
tracker.last(); // Iterate last seen {x,y} for each named pointtracker.ids(); // Iterate over point namestracker.has(`nose`); // true if point has been seen
Under-the-hood, it automatically creates a PointTracker
for each named point. This can be retrieved using t.get(id)
. And then you can use all the single-point tracking features described earlier.
// Get the PointTracker for 'nose'const noseValue = t.get(`nose`);noseValue.last; // Last seen { x, y }noseValue.initial; // Initial { x, y }noseValue.elapsed; // milliseconds since first seennoseValue.reset(); // reset this named point...etc
The pointer scale demo (source) uses numberTracker
and pointsTracker
.