Repository navigation
Redesign the charts on uPlot - #2448
Merged
Merged
Conversation
|
No issues found. |
Member
Author
|
Pinning the disk axis to capacity is intentional and matches the reference design; the description now says so. Whether disk should scale like memory is an open question we will settle before merging. |
carlhoerberg
approved these changes
Oct 14, 2026
carlhoerberg
left a comment
Member
There was a problem hiding this comment.
Code approved, not tested. Yes, disk should probably scale like memory, going from 1 to 50 MiB disk usage wont probably even register on a 1 TiB disk chart, but may still indicate something unexpected for the user.
Member
Author
Member
Author
Member
|
B, scale like memory |
layout.js requests api/whoami when the page loads and caches the response in localStorage. page.goto resolves on the load event, which does not wait for that request, so the whoAmI specs could navigate away while it was still in flight. The aborted request was never cached and the next page load fetched it again, failing the call count. The user tag state class specs lost the same race from the other side. The saved login state already holds user-is-administrator in localStorage and layout.js applies it on load, so a spec that read the class list right after page.goto saw the cached classes rather than the tags from the mocked whoami. The race only lost often enough to notice once the chart library got smaller and pages started loading faster. The whoAmI specs now wait until the response has been cached before the next navigation, and the state class specs use retrying assertions on the html element.
The charts are redesigned around reading values rather than guessing
them from the plot. Chart.js drew everything on a canvas: the legend
sat inside the plot and the only way to read a value was a tooltip
that followed the mouse. The new charts put the legend in a table
under the plot, aligned with the plot area, and the table is where the
values are read: it shows the latest value until the cursor enters a
plot, then the value under the cursor. The plot itself is only the
shape.
uPlot replaces Chart.js as the engine. It draws just the plot on a
small canvas and leaves the legend to the page, which is what makes
the table possible, and it is the engine Grafana uses.
What the user sees:
- The legend table has a colour marker, the series name and its value.
Click a row to isolate that series, shift, cmd or ctrl-click to
toggle a single one. Each row's tooltip explains the series.
- The card heading shows the timestamp of the sample the legend is
showing, or "Paused at hh:mm:ss" while refresh is paused.
- Hovering any chart moves the cursor on every chart on the page, so
the legends all report the same instant.
- Byte axes tick on powers of two (128 KiB, 256 KiB) and byte legend
rows share the unit of the largest value. The y axis only shrinks
after five polls below 60% of its range, so a spike leaving the
window doesn't make the scale jump.
- The nodes page gets a Disk usage chart next to Memory usage. Both
draw a dashed line at the capacity (mem_limit, disk_total) and grow
toward it once usage passes half. The CPU axis starts at 100% and
grows past it on multi-core nodes. IO is renamed Disk I/O.
- Charts redraw when the theme changes instead of keeping the old grid
colours.
How the data flows:
Chart.js charts appended one point per poll and had to fill gaps when
polling was slower than the stats interval or paused. uPlot charts
rebuild from the history log in every response instead, so there is
nothing to fill: the resolution is the server's stats interval
(advertised in LavinMQ-Stats-Interval) no matter how often the page
polls, and pausing leaves no hole. The Chart.js gap spec goes with it.
Chart.update accepts the API's stats objects as before, or an array of
{ key, label, value, log, desc } for derived series such as disk used
and CPU percent. Pages used to build fake API-shaped objects for those.
The y axis keeps its range until the data has sat below 60% of it for
five polls. That hysteresis lives in stableMax, which counts polls
rather than redraws so legend toggles cannot collapse the axis, and is
exported so the spec can drive it: the axis is drawn on a canvas and
has nothing in the DOM to assert on.
uPlot 1.6.32 is fetched and checksummed by the Makefile, replacing
Chart.js, Luxon and the Luxon adapter.
The disk chart pinned its y axis to disk_total, so on a large volume any change smaller than a few percent of capacity drew as a flat line. It now uses the same scaleCap as memory: the axis follows usage and snaps to capacity once usage passes half of it, with the capacity label pinned above the plot while the line is off scale.
The label for a capacity line pinned above the plot was drawn inside the plot area, so it covered the series whenever usage sat near the top of the axis, which is common once disk scales with usage. The plot now reserves a fixed 16 px at the top, and every capacity label is drawn in the space above its line: in that padding when the line is off the axis, otherwise just above the dashed line.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.





Stacked on #2447.
Replaces Chart.js with uPlot and redesigns the charts around reading values instead of guessing them from the plot:
LavinMQ-Stats-Intervalheader, so a slower or paused refresh leaves no gaps.uPlot 1.6.32 replaces Chart.js, Luxon and the adapter. Chart assets go from 165 KiB to 48 KiB deflated, and main thread time per refresh on the overview from 68 ms to 2.6 ms, most of the difference being Chart.js's update animation.
Also carries a spec-only commit for whoami races in
auth.spec.jsthat faster page loads exposed.Before and after
Rows: the overview, the overview while hovering the message rates chart, and the nodes page. Same load on both servers.