feat: use ECharts to have faster charts (and more interactive)#2234
Conversation
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
…ing charts Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
There was a problem hiding this comment.
No code review, just observations from testing. Improvements I observe are:
- Speed
- Panning
- Zooming
- Hover effect to focus on a single trace (line)
- Heat map interactivity (select a value range to see)
Missing:
- Asset page shows misaligned x-axis on vertically concatenated subcharts (tip: try the replay on asset 77) (✅ )
- Bar chart of a year of 15-minute prices has missing data
- SVG export on large heatmaps has missing data
- No annotations visible on sensor bar chart (tip: select a time period on sensor 14 covering some Dutch public holidays) (✅ )
- SVG export should exclude buttons (✅ )
- Double click to reset
- Font size too small (✅ )
- Tooltip hover on nearest data point (this can be discussed)
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…mps, fonts) - show hover annotations on the sensor page, matching the Vega-Lite SHADE_LAYER/TEXT_LAYER (gray bands, highlight + label on hover) - use tableau10 colors and zero-based y-axis like Vega-Lite - use linear interpolation for instantaneous sensors so ramps are visible - match Poppins font and Vega-Lite font sizes - always show the legend below on the sensor page - mixed date/time x-axis labels and extra inter-subplot spacing
Let's discuss the rest of the items in a call. |
- dataZoom realtime:false + throttle:80 so a slider drag coalesces into a single redraw on release instead of one per tick (removes mid-drag jank) - large mode on line series for batched canvas drawing - measured on asset 77 (7,728 rows): initial render 134ms -> 71ms, slider drag 25 re-renders -> 1
Updated list of observationsSensor page:
Asset page:
|
Export read the canvas/SVG synchronously right after setOption, but heatmaps render cells progressively across animation frames, so a year-long heatmap (>5000 cells) lost every cell past the first chunk. buildExportOption now forces progressive:0 on every series so the full chart renders in one pass. CSV is unaffected (it serializes the raw rows). Also place the SVG export icon between Reset Zoom and PNG on the sensor page only, leaving the asset-page toolbox order unchanged.
…asset-charts # Conflicts: # documentation/changelog.rst
- Native ECharts Charge Point sessions chart with companion subplots and working per-session tooltips; charge-points type switchable in fast mode - Do not render the Charge Point sessions panel in the default view - Align companion subplots on a shared time domain - Remove the always-visible range-slider zoom bar (keep wheel/drag zoom) - Move the Source line-style key to the bottom, matching Vega-Lite: a vertical column at the bottom-left with side legends, or a second column beside the Sensor legend in the legends-below layout
Drop the Arrival/Plug-in/Charging key from the sessions chart along with the now-unused buildChargePointKey helper and CHARGEPOINT_KEY_ROWS constant.
Vega uses linear interpolation for a subplot row when any of its sensors is instantaneous (event_resolution 0), and step-after otherwise. The fast chart had to guess resolution from event spacing because the chart data never carried the real event_resolution, which mislabeled instantaneous sensors as interval data (stepped lines where Vega draws smooth ones). Serialize event_resolution (seconds) through every chart-data path the UI uses: Sensor.as_dict, Sensor.search_beliefs, GenericAsset.search_beliefs, and the fixed-value flex-sensor metadata in GenericAsset.chart_data_json. Carry it through decompressChartData, then decide interpolation per subplot in fast-chart.js exactly as chart_for_multiple_sensors does, with a spacing-based fallback for legacy data.
Use axis-trigger tooltips on the line/bar charts so hovering anywhere over a subplot reveals the nearest data point (the ruler), as in the Vega-Lite charts, instead of requiring a direct hit on the thin line. The formatter picks the single point nearest to the ruler and shows its details, scoped to the hovered subplot.
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
|
@copilot resolve the merge conflicts in this pull request |
Co-authored-by: Ahmad-Wahid <59763365+Ahmad-Wahid@users.noreply.github.com>
Merge conflicts have been resolved and merged with |
The axis-trigger tooltip picked the nearest point by x, but all series share the ruler's x, so it could name the wrong sensor. Track the cursor pixel and pick the series whose point is nearest in 2D (i.e. vertically), so the tooltip reflects the line under the cursor and switches sensor to sensor between traces.
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
…asset-charts # Conflicts: # flexmeasures/ui/templates/includes/graphs.html
Render the canvas-based ECharts chart by default (opt-out) instead of opt-in: treat a missing fm-fast-charts preference as on, so users get the faster chart automatically and can switch back to Vega-Lite via the toggle if needed. Update the changelog wording accordingly.
Nine fixes to the fast (ECharts) charts, keeping parity with Vega-Lite: 1. x-axis spans the full requested query window, not just the data extent (a day with data only 18:00-22:00 now shows the whole day). Window is captured as primitives before getAssetKPIs mutates storeEndDate (+1 day). 2. Port the per-sub-chart y-axis modes from #2244 (zero / data / [min,max] floor / {min,max} strict; % floors to [0,105]) to the ECharts value axis. 3. Pre-select the toolbox marquee "zoom" tool so a drag zooms right away. 4. Fix the tooltip/marker mismatch in a two-sensor subchart by disabling the axis-hover emphasis pop-out (tooltip already snaps to the nearest line). 5. Move the "Fast chart" toggle into the replay column (top), beside replay. 6. Match the Vega-Lite subplot height (300px) and keep the centered subplot title above the y-axis title. 7. Softly round the stepped (interval) line corners via a round line-join. 8. Hide overlapping x-axis tick labels on narrow/small screens (ECharts only). 9. Double-click the chart to reset the zoom to the full range. Signed-off-by: F.N. Claessen <felix@seita.nl>
Addresses follow-up feedback on the fast (ECharts) charts: 2. y-axis modes now update immediately on a sensors_to_show save (rebuild the groupSpec client-side from the saved config) instead of only after a reload. 3. Ctrl+drag pans (inside dataZoom moveOnMouseMove:'ctrl') alongside the pre-selected marquee zoom on plain drag. 4. Keep the emphasis pop-out but sync it to the tooltip's series (syncEmphasis), so the marker lands on the same sensor the tooltip shows. 5. Make the relocated "Fast chart" toggle wrap/shrink so it no longer overflows the narrow replay column onto the chart card. 6. Lower the subplot height to 150px (Vega parity) and raise the subplot title further above the y-axis title. 7. Actually-visible rounded step corners (expand to cut step vertices + smooth), with the tooltip snapping back to the real data points. 9. Fix double-click-to-reset by listening on the zrender canvas (fires on empty plot area) and resetting every dataZoom to full range. Signed-off-by: F.N. Claessen <felix@seita.nl>
6. Lower subplot height to 150px, raise the title (TITLE_RAISE=60) and drop the
toolbox to sit level with the first y-axis title.
7. Keep rounded step corners circular at every zoom: cut them a fixed number of
pixels deep and recompute on each dataZoom (refreshRoundedSteps).
2. Nice-round the "Fixed range" (floor) y-axis bounds ([-3, 3] not [-2.68, 2.79]),
and make the strict-range clamp toast fire in fast mode too (de-duplicated).
10. Mobile: one-finger swipe scrolls the page (touch-action: pan-y, no chart pan),
pinch zooms, double-tap resets; a drag no longer resets the zoom.
3. Desktop Ctrl+drag now actually pans (disable the marquee brush while Ctrl held).
11. Drop the fixed x-axis minInterval so zooming reveals finer datetime ticks.
Signed-off-by: F.N. Claessen <felix@seita.nl>
2. Fix the strict-range y-axis toast never firing: checkStrictYAxisRanges was
called in graphs.html but never imported, so every call threw a ReferenceError
(in both Vega and fast mode). Add it to the import.
3. Fix the regression where the marquee zoom stopped being pre-selected: IS_TOUCH
used maxTouchPoints, which is truthy on many desktops (touchscreens/precision
touchpads), so they wrongly took the touch branch. Detect the PRIMARY pointer
via matchMedia("(pointer: coarse)") instead.
6. Raise the toolbox (TOOLBOX_TOP) so it no longer dips into the subchart grid.
10. On touch, show the tooltip on TAP only (tooltip.triggerOn "click"), so a
one-finger swipe scrolls the page instead of being captured; and ignore
swipes in the double-tap reset so scrolling no longer resets the zoom.
Signed-off-by: F.N. Claessen <felix@seita.nl>
10. Mobile: one-finger swipe now scrolls the page (re-add preventDefaultMouseMove:
false alongside touch-action: pan-y, so ECharts stops eating the swipe), and
tapping the tooltip or outside the chart closes it (enterable + dismiss wiring).
12. Keep x-axis grid lines equidistant while zooming: apply one uniform, visible-
span-based time interval to the axes and recompute it on every dataZoom
(refreshTimeTicks), instead of ECharts' unevenly-spaced automatic time ticks.
13. Stack the "Fast chart" toggle vertically so it never overflows the narrow
replay column onto the chart card before wrapping.
Signed-off-by: F.N. Claessen <felix@seita.nl>
10a. One-finger HORIZONTAL swipe now pans the chart (moveOnMouseMove:true on touch);
vertical still scrolls the page (touch-action: pan-y + preventDefaultMouseMove:false).
10b. Force pointer-events:auto on the touch tooltip so a tap lands on it and closes it
(enterable alone left the tap passing through to the canvas).
12. Drop the x-axis minor gridlines (they were the uneven-at-the-edges lines) and give
the sessions chart the same uniform, adaptive major ticks (refreshTimeTicks).
13. Revert the toggle to a single horizontal line that shrinks the label (beta wraps
under "Fast chart") before wrapping, instead of always stacking vertically.
Signed-off-by: F.N. Claessen <felix@seita.nl>
10b. Close the tooltip on tapping it: ECharts swallows the synthetic click on touch,
so dismiss on "touchend" too (any tap not on the chart canvas closes it).
12. Force the x-axis interval via minInterval==maxInterval (a plain time-axis
`interval` was ignored, giving 4h not 3h for a day) and re-add finer unlabelled
gridlines at a NICE time sub-step (minorSplitFor), not a blind half.
13. Revert the toggle to the round-5 vertical, centered stack (no overflow/mis-align).
14. Zoom toolbox button is now a pan/zoom mode toggle (custom icon swaps zoom<->pan):
zoom mode = drag zooms, pan mode = drag pans; Ctrl temporarily inverts. Inside
dataZoom moveOnMouseMove:true so drag pans whenever the marquee is off.
Signed-off-by: F.N. Claessen <felix@seita.nl>
12. Switch the x-axis from type "time" to type "value" (epoch ms): ECharts ignores
a forced `interval` on a time axis, so majors came out at 2h/4h. A value axis
honors it, so majors are exactly the width-adaptive nice step (a day → 3h → 6h
→ 12h as it narrows) and the minor gridlines subdivide it at uniform absolute
positions — equidistant at the domain edges too.
13. Revert the toggle to the round-4 single horizontal line (overflow accepted).
14. Replace the single mode-toggle with separate buttons: keep the built-in Zoom +
Zoom-reset, add a "Pan" button (short tooltip). All three are desktop-only —
hidden on touch, where pinch/swipe/double-tap are used. Drop the Ctrl inversion.
10b. Left as-is per feedback (tap-to-close-on-tooltip not pursued).
Signed-off-by: F.N. Claessen <felix@seita.nl>
12. Revert the x-axis to type "time" so ticks stay on nice clock times when zoomed
(the value axis honored the interval but placed ticks at the raw domain edges,
e.g. 08:21). Bias the granularity toward 3h/6h/12h via a width/zoom-adaptive
minInterval. Minor gridlines stay off (they mis-space at the edges on a time axis).
14. Custom Zoom / Pan / Zoom-reset toolbox buttons. The active one is highlighted
blue (Zoom or Pan); Ctrl inversion is back and the blue jumps to the other button
while Ctrl is held. Reset is a button too, so it also shows on mobile (Zoom/Pan
stay desktop-only). The built-in dataZoom feature is kept only as the (hidden,
tooltip-less) marquee brush the buttons drive.
Signed-off-by: F.N. Claessen <felix@seita.nl>
ECharts' time axis honors maxInterval (a cap) but not minInterval (a floor), so a 2-day selection jumped from the day level (only midnights) straight to 4h with nothing in between. Cap the interval at ~span/4 so a 2-day view shows 12h gridlines, while a 1-day view keeps its 4h (already below the cap). Recomputed on zoom. Signed-off-by: F.N. Claessen <felix@seita.nl>
…2234) The double-tap-to-reset was detected from zrender's synthetic click, which is unreliable once touch-action:pan-y hands a vertical swipe to the browser for scrolling — so a scroll could still trip the reset. Detect the double-tap from native touchstart/touchend on the container instead, measuring real finger movement: a swipe moves too far to count as a tap, and a swipe between two taps clears the pending tap, so scrolling can never complete a double-tap. Signed-off-by: F.N. Claessen <felix@seita.nl>
…croll) (#2234) The real cause of "scrolling resets the zoom" on mobile: scrolling shows/hides the browser address bar, firing a window resize (height changes, width doesn't). The resize handler re-rendered with notMerge, which resets the zoom to full. Chart layout only depends on width, so ignore height-only resizes and keep the current zoom. Signed-off-by: F.N. Claessen <felix@seita.nl>
|
Great work on this, @Ahmad-Wahid! 🎉 The ECharts "fast chart" is a real step up — noticeably snappier and more interactive than Vega-Lite while staying visually faithful across all the chart types, replay, annotations and export. Really nice contribution. After some hands-on testing on desktop and mobile, I pushed a series of follow-up refinements straight onto this branch (all on top of your implementation): Charts & axes
Zoom / pan UX
Mobile
Misc
All of the above is tested (desktop + mobile) and already merged into this branch. LGTM from my side — great job, and thanks for pushing the charts forward! 🚀 |
Description
Adds an optional Fast chart mode (Apache ECharts, canvas-based) alongside the existing Vega-Lite charts. A toggle in the chart header switches between them, and the choice is remembered per browser. The fast chart renders and interacts far faster on dense time series while staying visually and functionally equivalent to the Vega-Lite charts.
What's included
Canvas rendering with mouse-wheel zoom, drag-to-pan, and a shared ruler + nearest-point tooltip synced across subplots
Parity with Vega-Lite: subplot layout, colors, legends (including the Source line-style key), titles/axes/fonts, annotations, replay, and step-vs-linear interpolation based on each sensor's resolution
All chart types: line, bar, histogram, heatmap, and charge-point sessions
PNG / SVG / CSV export
Added changelog item in
documentation/changelog.rstLook & Feel
Vega-Lite:

ECharts:

EChart will show the legends of those sensors that has data. Although, they are not dropped from the
sensors_to_showlist.How to test
Switch between Vega-Lite and ECharts using this toogle button.

Further Improvements
Related Items