feat: add z-axis / 3D chart support with echarts-gl#122
Merged
Conversation
Add a 4th categorical dimension (zAxis) to benchmark data. When a data
point carries xAxis, yAxis AND zAxis, bar/line charts render as 3D via
echarts-gl, and pie renders as three side-by-side reduced pies.
Parsing & data:
- BenchmarkData gains a ZAxis field (shared/bench.go)
- DimensionZAxis added; merge inject/empty + --tag-axis z support
- group-pattern/group-regex accept z/zAxis tokens across all parsers
(golang, criterion, divan, tinybench, vitest)
UI:
- new use3DChartOptions builds bar3D/line3D: xAxis->X floor,
yAxis->Y depth, value->Z height, zAxis->color (one stacked series
per z, legend on left)
- stacked bar3D with beveled edges; per-cell tooltip lists all z values;
stack-top label shows the cell total (rounded to 2 decimals)
- sort applies to x, y and z axes
- pie 3-up layout for 3D data
- echarts-gl wired into ChartCard; ambient type shim added
- html/template delimiters switched to [[VIZB .. VIZB]] to avoid
colliding with clay.gl GLSL {{ }} loop-unroll markers
- 3D sample dataset added for dev
echarts-gl bundles the clay.gl WebGL engine, inflating the single-file HTML to ~1.24MB. Store the inlined module JS gzip+base64-encoded and inflate at runtime via DecompressionStream + a deferred module bootstrap, cutting the UI shell to ~512KB (below the prior 786KB 2D baseline). Also extend the axis-swap selector to the z dimension: swap options are now k-permutations of the present axis roles, enabling 3D<->2D toggling (xyz vs nxy). z is only offered alongside both x and y, since a 3D floor requires an x/y grid.
- Fullscreen button (Maximize2/Minimize2) on every chart card via requestFullscreen; chart height expands to fill viewport - Extract module-level helpers in use3DChartOptions (round2, mapPoints, makeLabel, makeAxisCommon) to eliminate duplication - Switch 3D shading to lambert + ambient 0.9 / main 0.3 to minimize face-darkening during rotation without losing depth cue
ScaleSelector hides the log/linear toggle when the active chart is 3D (x+y+z present) — log scale isn't supported for 3D yet. vite.config now logs emitted HTML size before/after bundle compression.
- ui: add Auto-rotate toggle (3D charts only) wired to grid3D.viewControl - ui: fix blank 3D saveAsImage — cap export pixelRatio at device dpr so zrender composites the WebGL layer instead of a 2D-only redraw - parser: reject group patterns/regex that use zAxis without both x and y (z is the depth dim of a 3D chart and needs an x/y floor); add tests
- shared tooltip theme (light/dark) so 2D and 3D match - 2D tooltip: per-series y-totals + labeled x-marginal sum - 3D tooltip: Σ z / Σ x / Σ y, precomputed cell aggregates for O(1) hover - 3D sums reflect legend z-toggle via controlled selection
- new ui/3d-charts page; sidebar entry; cross-links from grouping/root/merge/ui pages - features, roadmap, settings, swapping updated for z-axis, auto-rotate, fullscreen, axis-sum tooltips - AxisSwapper: 1D data offers only x/y placement (drop useless name grouping)
Chart builders: extract useSortedSeriesData, getEffectiveScale, computeSeriesTotals, sortByAxisTotal into shared/common.ts; add makeDataItem to seriesConfig.ts; remove dead createBar/LineSeriesConfig; decompose 209-line pie options into helpers + spec-driven series arrays; lift 3D inline sort closure to shared util. bar/line/pie options each ~25-35% smaller. Badges: new useSortedHistory composable + HistoryPopover presentational component; Cpu/Os/TimestampBadge become thin wrappers. Settings: useSyncedSetting writable-computed kills ref+watch+handler triples in ChartSettings, ScaleSelector, AutoRotateToggle; dedupe is3DChart/isAxisChart into useActiveChartShape composable. Dashboard: useDashboardInit composable owns init watchers + title side effect; split template into BenchmarkHeader, LoadingSkeleton, LoadError, AppFooter presentational components. 202 → 84 lines. Helpers: isValidIndex, SORT_ORDERS, SCALE_TYPES replace 5 inline bounds checks and hardcoded validation arrays. Net: 3855 → 3536 LOC (-319), bundle delta < 1 kB.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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.
Summary
zAxis) to benchmark data; when x+y+z all present, bar/line charts render as 3D via echarts-gl; pie falls back to 3-up side-by-side layoutDecompressionStreamto keep single-file HTML at ~512 KB (down from ~1.24 MB with echarts-gl inlined)Changes
feat
zAxisfield onBenchmarkData;DimensionZAxistoken;--tag-axis zsupport; merge inject/empty for zz/zAxistokens across all parsers (golang, criterion, divan, tinybench, vitest)use3DChartOptions:bar3D/line3Dwith stacked series per z-value, beveled edges, stack-top labels, per-cell tooltipsrequestFullscreen; chart height expands to fill viewportgrid3D.viewControl(3D charts only)fix
saveAsImage— cap exportpixelRatioat device dpr so zrender composites WebGL layerperf
html/templatedelimiters switched to[[VIZB..VIZB]]to avoid collision with clay.gl GLSL{{}}loop-unroll markersrefactor
useSortedSeriesData,getEffectiveScale,computeSeriesTotals,sortByAxisTotal,makeDataIteminto shared utilitiesuseSyncedSettingwritable-computed eliminates ref+watch+handler triples;useActiveChartShapededupesis3DChart/isAxisChartuseDashboardInitcomposable; split Dashboard template intoBenchmarkHeader,LoadingSkeleton,LoadError,AppFooterdocs
ui/3d-chartspage with features, settings, axis-swap, roadmap; cross-linked from grouping/root/merge/ui pagesTest Plan
go test ./...passesvizbwith 3D benchmark data renders bar3D/line3D chart