Trackers
- API Reference Data module
- Related: FrequencyMutable: tracks 'seen' values
The ixfx suite of trackers are meant for streams of data. In their simplest usage, they can keep track of the range of data. In more advanced usage, they are helpful in comparing some start value to a current value.
Numbers
numberTracker
keeps track of the minimum, maximum and average of a stream of numbers, without storing them.
// repl-pad
import { numberTracker } from 'https://unpkg.com/ixfx/dist/data.js';
// Initialise
const t = numberTracker();
// Add some random values
for (let i=0;i<10;i++) t.seen(Math.floor(Math.random()*100)));
// Get computed values
t.avg
t.min
t.total
An example usage might be to track the range of a sensor over time.
See also:
numberTracker
API docs for more- The pointer scale demo (source) uses
numberTracker
andpointsTracker
.
Intervals
intervalTracker
tracks time intervals.
This is useful when you're interested in the period or frequency of events rather than event data itself.
Once initialised, call mark
on the returned object to capture the elapsed time.
import { intervalTracker } from 'https://unpkg.com/ixfx/dist/data.js';
// Initialise
const t = intervalTracker();
// Call `mark` to record the interval since last `mark` (or init)
t.mark();
...
t.mark();
// Get average time (in millis) between calls
t.avg;
For example, to figure how quickly the pointer is being clicked:
import { intervalTracker } from 'https://unpkg.com/ixfx/dist/data.js';
const clickInterval = intervalTracker();
document.addEventListener(`click`, evt => {
clickInterval.mark();
console.log(`Average interval: ${clickInterval.avg}`);
});
See also:
intervalTracker
API docs- typer demo (source) uses
intervalTracker
to work with typing speed
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.
pointTracker
keeps track of a single point, returning an instance of PointTracker.
First initialise:
import { pointTracker } from 'https://unpkg.com/ixfx/dist/data.js';
const t = pointTracker();
// Or alternatively, keep track of only the last 10 samples:
const t = pointTracker({
sampleLimit: 10
})
And then call seen()
whenever there is a point to track, for example, based on a pointer move event.
const info = t.seen({ x: 10, y: 20 });
seen()
returns an object with useful data comparing the value you passed with the previous value and initial value. You also get a snapshot of all the stored values thus far.
const { fromInitial, fromLast, values } = info;
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:
{
speed: number // units/ms
angle: number // in radians
distance: number
average: Point // average of all points
centroid: Point
distance: number
}
For example:
const { fromInitial, fromLast } = t.seen(pointerEvent); // Add pointer event
console.log(`Distance from start: ${fromInitial.distance}`);
In the example below, we start tracking when the pointer is down and add points when there is a pointer move event.
import { pointTracker } from 'https://unpkg.com/ixfx/dist/data.js';
let tracker = null;
document.addEventListener(`pointerdown`, evt => {
// Init new tracker
tracker = pointTracker();
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;
There are a few helper functions on the tracker:
// Distance & angle from initial point
tracker.distanceFromStart(); // number
tracker.angleFromStart(); // number (radians)
// Latest point subtracted from initial point
tracker.difference(); // { x, y }
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.
pointsTracker
to the rescue! It does all this housekeeping for you.
Initalise like so:
import { pointsTracker } from 'https://unpkg.com/ixfx/dist/data.js';
const t = pointsTracker();
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 { pointsTracker } from 'https://unpkg.com/ixfx/dist/data.js';
const t = pointsTracker();
// Track a point by its id
document.addEventListener(`pointermove`, e => {
const info = await pt.seen(e.pointerId, { x: e.x, y: e.y });
});
Note that seen
is an async function, so await
needs to be used if you want the result.
To get data:
t.last(); // Iterate last seen {x,y} for each named point
t.ids(); // Iterate over point names
t.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)
:
// Get the point tracker for this named point
const noseValue = t.get(`nose`);
noseValue.last; // Last seen { x, y }
noseValue.initial; // Initial { x, y }
noseValue.elapsed; // milliseconds since first seen
noseValue.reset(); // reset this named point
See also:
pointsTracker
API docs for more on the tracker, including sorting points by when they were recently updated.- The pointer scale demo (source) uses
numberTracker
andpointsTracker
.
Trackers in general
All the trackers can take some options. Eg, creating a numberTracker
with a string id of someTracker
, have it automatically reset every 10 samples, and to store these values:
import { numberTracker } from 'https://unpkg.com/ixfx/dist/data.js';
const t = numberTracker(`someTracker`, {
resetAfterSamples: 10,
storeIntermediate: true
});