feat(charts): add the uPlot renderer alongside dygraph - #234
Open
novykh wants to merge 2 commits into
Open
Conversation
Introduces uplot as a second time-series chart library, reaching feature parity with dygraph across line, area, stacked, stackedBar, multiBar, heatmap and sparkline, plus every overlay and interaction the dygraph renderer supports. The renderer is opt-in. The shipped default stays chartLibrary: "dygraph" until the real-dashboard measurement in docs/uplot-migration-progress.md has been run; flipping it is a one-attribute change because chartLibrary is now the single selector and chartLibrariesByType only overrides per-type. Renderer - Plot geometry, axis ticks, borders and label widths matched to dygraph, and held across resize. - Stacking: per-value +/- accumulation for diverging stacks, correct draw order, ranges and mixed signs, stepped interiors, per-pixel row thinning. - Overlays on draw hooks: alarm, alarmRange, alertTransitions, highlight, annotation, proceeded, point markers, the anomaly ribbon and the anomaly-rate badge in the y-axis gutter. - Crosshair on its own overlay canvas, driven by the SDK's synced hoverX rather than the local pointer, so cross-chart sync spans both renderers. - Navigation: pan, wheel zoom, select, pinch, dblclick reset, with dygraph's thresholds and click semantics. - Smooth curves via uPlot's built-in spline; a collapsed y-range is expanded instead of stalling uPlot's tick search. SDK - chartLibrariesByType maps a chart type to a renderer, with getRendererForChartType and isTimeSeriesRenderer resolving through it. - perfMonitor plugin and a render-timing seam, off by default. Tooling - Playwright-driven headless benchmark (yarn perf:bench), a browser geometry probe and a CPU profile probe. - Storybook: a chart-library toolbar arg, a side-by-side renderer comparison story and a showcase story. Measured: uPlot is 2.7-3.9x cheaper per render than dygraph at every CPU throttle level, and cheaper per frame in all 20 rendering cells of the sweep. Under saturation that converts into frames. Details, caveats and the retracted earlier numbers are in docs/uplot-migration-progress.md. Note for consumers: uplot ships as a runtime dependency (~48KB) and its CSS (uplot/dist/uPlot.min.css) is functional, not cosmetic, so a consumer must import it. Squashed from the explore/uplot-spike branch.
The "Remaining work" list was written 2026-07-15 and never revised as the work landed, so it still described heatmap, the overlays, bars and the stacked top stroke as missing. All four are done; each is now marked with the file:line that implements it, and the section points at the parity worklist for genuinely open items. Two claims were wrong rather than merely stale: - Consumers do not need to import uplot/dist/uPlot.min.css. The rules the renderer actually uses are inlined in chartContentWrapper.js, and the only upstream selectors missing from it are legend and title chrome, which never render (legend is disabled, no title is set). - The flip is not a one-attribute change. In cloud-frontend it takes three, two of them permanent, and two fail silently: byType needs a uplot entry or every chart renders as an empty container with no error, and getMenuChartAttributes hardcodes dygraph per-chart, which overrides the root attribute and makes both halves of an A/B measure dygraph. Also records that Playwright is available but only drives Storybook, refreshes the test and build counts, and drops a local absolute path.
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.
Adds uPlot as a second time-series chart library, at feature parity with dygraph.
The default does not change
chartLibrarystill ships as"dygraph". uPlot is opt-in — setchartLibrary: "uplot"on the SDK root, or map a single type withchartLibrariesByType.Flipping the default later is a one-attribute change:
chartLibraryis now the single selector,chartLibrariesByTypedefaults to{}and only overrides per-type, andgetRendererForChartTypefalls back tochartLibrary. The flip is deliberately not in this PR — it is gated on the real-dashboard measurement protocol indocs/uplot-migration-progress.md, which has to be run in a browser on a live streaming dashboard.What is covered
Chart types: line, area, stacked, stackedBar, multiBar, heatmap, sparkline.
Overlays, all drawn from uPlot
drawhooks: alarm, alarmRange, alertTransitions, highlight, annotation, proceeded, per-series point markers, anomaly ribbon, and the anomaly-rate badge in the y-axis gutter.Interaction: pan, wheel zoom, select, pinch, dblclick reset, click-to-annotate — using dygraph's thresholds and semantics. The crosshair lives on its own overlay canvas and is driven by the SDK's synced
hoverX, not the local pointer, so cross-chart hover sync spans both renderers.Geometry: plot area, axis ticks, borders and label widths matched to dygraph and held across resize. Collapsed y-ranges are expanded rather than left to stall uPlot's tick search.
Also in here
perfMonitorSDK plugin and a render-timing seam, off by default.yarn perf:bench— a Playwright-driven headless dygraph-vs-uPlot benchmark, plus a browser geometry probe and a CPU profile probe underscripts/.src/chartLibraries/helpers/— colour, overlay-area and dimension-visibility helpers now shared by both renderers.src/helpers/deepMergeremoved; it had no remaining references.Performance
uPlot is 2.7–3.9× cheaper per render than dygraph at every CPU throttle level tested, and cheaper per frame in all 20 rendering cells of the sweep. Under saturation that converts into frames: at 6× throttle, 60±29 → 157±28 renders.
Caveats, the measurement protocol, and the earlier numbers that were retracted (everything measured before the unit-conversion rebuild fix is void) are recorded in
docs/uplot-migration-progress.md.For consumers
uplotis a new runtime dependency (~48KB), so consumers resolve it transitively — no change needed in theirpackage.json.The stylesheet is not an extra step: the rules uPlot needs (
.u-wrap,.u-over,.u-under,.u-axis,.u-select,.u-cursor-*) are inlined insrc/components/line/chartContentWrapper.js, scoped to the chart container. Upstream's remaining selectors are all legend/title chrome, and the renderer setslegend: { show: false }and no title, souplot/dist/uPlot.min.cssdoes not need importing.A consumer that maps
chartLibraryto its own React component must add auplotentry. It maps to the same genericcomponents/linecomponent as dygraph —components/linehas no renderer-specific branching, and the renderer is resolved from thechartLibraryattribute viasdk.ui. Verified in cloud-frontend:src/charts/index.jshas abyTypemap with adygraphkey and nouplotkey, andChartdoesif (!Component) return null, so charts render as empty containers with no console error. So enabling uPlot there is a two-line change (uplot: LineinbyType, plus thechartLibraryattribute) — not the one-attribute changedocs/uplot-migration-progress.mdclaims.Verification
yarn buildcompiles clean: 537 CJS / 540 ES6.Notes for review
Squashed from
explore/uplot-spike(124 commits), which is left in place unchanged.The
docs/uplot-*.mdfiles are the working record of the migration.uplot-migration-progress.mdis the entry point; its stale sections have been corrected in a follow-up commit, with the superseded claims kept struck through rather than deleted so the history stays readable. Open parity items live inuplot-parity-worklist.md(§ "Queued work").