Skip to content

perf(web): stop dashboard render loops when their view is hidden #881

Description

@frahlg

Problem

Two dashboard animations keep doing work when nobody can see them:

  • web/app.js:3797-3805 redraws the full live chart at about 30 fps. web/diagnose.js:53-93 moves that chart into the Energy view, which is hidden on the default Overview route. The loop only checks document.hidden.
  • web/components/ftw-energy-flow.js:390-400 keeps both the shown and opacity-zero particle layers running. It also keeps running when another main view is open or the user selects Power Now → Values.

This spends CPU, GPU time, and battery on the Raspberry Pi and mobile browser without changing visible output.

Desired result

  • Hidden chart and energy-flow surfaces schedule no animation work.
  • Both resume with the latest readings as soon as they become visible.
  • Energy flow animates only the selected aggregate or individual layer after its 300 ms crossfade ends.
  • Repeated route and toggle changes never create more than one animation loop per visible surface.

Out of scope

  • Changing status polling, control, dispatch, telemetry, or API contracts.
  • Replacing SVG or Canvas with WebGL, Wasm, or another renderer.
  • Changing chart, particle, label, hover, or control design.
  • General dashboard bundling or asset work.

Safety and failure behavior

Polling must continue while a view is hidden so the first visible frame is current. This work changes paint scheduling only.

If visibility detection is unavailable or fails, keep rendering rather than leave stale UI. A pause must never alter readings, commands, safety state, or dispatch.

Measured evidence

These are source counts from origin/master, not browser timings:

  • The chart holds up to 360 points and receives status every 2 seconds, yet redraws about 30 times per second. A 360-point, three-series source model counts 10,827 smoothing-loop visits, value visits, point allocations, and path calls per frame, or about 324,810 per second. One full redraw per status sample would mean 60 times fewer full redraws.
  • A four-edge, 5 kW energy-flow fixture creates 75 particles per edge in both aggregate and individual layers: 4 × 2 × 75 = 600 SVG circles. At 60 Hz, two position writes per circle give a source upper bound of 72,000 SVG attribute writes per second.
  • Real cost will vary with hardware, browser throttling, device count, power, and route. We need a Chrome trace before making a CPU or frame-time claim.

Proof and acceptance

Automated checks:

  • Overview + Flow: energy flow runs; chart does not.
  • Overview + Values: neither loop runs.
  • Energy: chart runs; energy flow does not.
  • Plan, History, and More: neither loop runs.
  • Readings received while paused appear on the first visible frame.
  • Aggregate switching may run both layers during the crossfade, then stops the old layer.
  • Repeated navigation and reconnects leave no extra animation loops.
  • Run the new narrow tests, npm test, then make verify.

Browser proof:

  • Record Chrome Performance traces on the reference Raspberry Pi with 360 chart points and a fixed four-edge flow fixture.
  • Record at least 30 seconds in Overview, Values, Energy, and one unrelated view.
  • After each transition, the hidden surface must show zero animation callbacks and zero particle position writes.
  • Compare scripting time, rendering time, frame rate, and loop counts before and after.

Human review:

  • Inspect desktop and phone layouts in a browser.
  • Compare Flow, Values, every main view, aggregate crossfade, particle direction, chart hover, live pulse, and resume behavior.
  • Capture before-and-after video or screenshots where motion permits. Source review alone cannot establish visual parity.

Target files

  • web/app.js
  • web/components/ftw-energy-flow.js
  • One focused web test file if needed

Do not broaden this work into web/index.html, routing, history components, settings, or PV 3D code.

Open PR overlap

Read-only check on 2026-08-10: no open PR touches either target source file.

Existing PRs have right of way in adjacent files: #714, #769, #701, #732, #734, #735, #736, and #826. Recheck open PR files before implementation and stop if a new overlap appears.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions