developer guide
Time Scrubber: Replay a Data Grid Over Time
A live grid can be wound back: the scrubber replays the feed, the table shows what it held at that moment with the changes marked, and letting go returns it to now.
Developer guide › Presenting and saved views › Time Scrubber: Replay a Data Grid Over Time
Time scrubber
Move the grid back through recent data changes: what did this look like a minute ago, before that number moved.
Scrubbing
grid.timeline.attach(); // start recording; the window fills from here
grid.timeline.seek(5); // stand five changes back
grid.timeline.step(-1); // one further back
grid.timeline.at(); // the moment being shown
grid.timeline.toLive(); // return, applying everything stepped over
grid.timeline.detach();
Attaching puts a control on the grid. A slider along the bottom with two
readings beside it: how long ago, and the clock time. Relative answers the question actually
being asked; absolute is what someone reads out to the person next to them. It moves the grid
while the handle is dragged rather than on release, and it turns accent-coloured the moment
you are off live, because a grid quietly showing stale data is the failure this control can
cause. It removes itself on detach().
It reads the data, not your actions. Undo history records what the user did (sorts, filters, edits) which is rarely the question. This reads the change log: a bounded, timestamped, deliberately unmerged record of everything that arrived, so the intermediate states are all still there to move between.
Nothing is scrubbable before attach(). What a value used to
be is not recoverable after the fact (no other part of the grid remembers it) so recording
has to be switched on before there is a past to move through. It is off by default because
reading a row per key on every change is real cost on a hot feed, and paying it for a
scrubber nobody opened would be the wrong default.
Scrubbed back, the grid is not live. Changes keep being recorded but are not applied, because applying them would fight the position being held. Returning to the present applies everything missed.
Value changes reverse; row additions and removals do not. An add would need a removal and a remove would need re-insertion at its old position, and neither is recoverable from what the log holds. A window containing them scrubs over the value changes and leaves the row set alone: stated plainly because the alternative is a scrubber that silently half-works.
What moved is marked. Seeking compares each affected row before and after
and marks the cells whose value changed, in --lattice-timeline-changed. Without
it a scrub is nearly unreadable: the grid moves, and on a row twelve columns wide the one
number you are hunting for goes past unseen.
The mark is held, not flashed. It stays until the next seek clears it.
Every other transient signal in the grid fades on a timer, and this one deliberately does not,
a scrub is someone hunting for what changed, and a highlight they can miss while reading the
other end of the row helps nobody. timeline:seeking fires before any change is
applied, so a five-step drag clears once and marks once rather than strobing per entry.
It compares column values, not raw fields. A computed column has no field of its own; diffing the source row would leave it silently unmarked while its number visibly moved. Reading through the column instead costs a little more and marks what the viewer can actually see change, which is the only definition of "changed" that matters here.
The window is bounded by rows, not only by changes. A cap on entries
alone does not bound memory, because an entry is not a fixed size: one carrying a single
changed cell and one carrying a fifty-thousand-row batch both count as one. So the log holds
at most updates.logLimit changes (2000) and updates.logRows
rows between them (100,000), dropping oldest-first on whichever it meets. It matters more
here than it looks: the log is what keeps superseded row objects alive after the source has
swapped in their replacements, so on a feed delivering five thousand rows a batch an
entry-only cap retains twenty million of them. The one exception is a single change larger
than the whole cap, which is kept: emptying the log would be worse than being briefly over,
and it would drop the newest change rather than the oldest. Watch held against
heldLimit in grid.updates.stats(); rows is a lifetime
total and says nothing about memory.
Charts scrub like anything else. A sparkline column redraws to the series
the row held at that point, and its cell is marked with the rest. The exception is the
delta renderer: it samples on a wall-clock timer and compares against its own
previous sample, so it reads a seek as a genuine movement and draws an arrow for it. Keep it
off a grid you intend to scrub.