Skip to content

Bugfix Issue 921 EventViewer Chart Rerender

opencode-bot edited this page Sep 4, 2026 · 2 revisions

Bugfix Issue #921 — Event Viewer Apply leaves charts frozen (Chart.js v1 has no .clear())

Problem

On the modernized Event Viewer, the two charts ('Events by Level' doughnut + 'Events per Day' line) rendered correctly on first load, but after changing a filter and clicking Apply the charts stayed frozen on the previous dataset. The DataTable below refreshed correctly.

Symptoms (browser console, one per Apply click):

  • Uncaught TypeError: pieChart.clear is not a function
  • Uncaught TypeError: lineChart.clear is not a function

In-page proof: typeof (pieChart.clear) === 'undefined'.

pre-fix symptom — charts frozen on stale data

Root cause (file:line chain, reproduced)

  1. gui/templates/eventviewer/eventviewer.html:314 renderPie() and :329 renderLine() guarded chart re-creation with if (pieChart) { pieChart.clear(); pieChart = null; }.
  2. The bundled gui/templates/dashio/lib/chart-master/Chart.js is the 2013 v1 build with no public .clear() on chart instances. The only clear in the library is an internal helper var clear = function(c){ c.clearRect(0,0,width,height); } at Chart.js:353, invoked from the animation loop at Chart.js:1243 — never exposed on the chart objects.
  3. ⇒ pieChart.clear() throws TypeError, aborting the rest of renderPie / renderLine before new Chart(ctx)...Doughnut(...) / new Chart(ctx).Line(...) and before the #pieLegend innerHTML regeneration.
  4. The DataTable refresh (renderTable) lives on an independent code path, so the split behaviour (table updates, charts don't) is exactly what the report saw.

Regression source: the screen's original modernization assumed a modern Chart.js API; every re-render (Apply filter, Clear Events) trips the missing method.

Fix (commits 95d8432fa, cb3e45a56) — minimal

  1. Dropped the non-existent .clear() call, keeping the reference discard:
    • renderPie(): if (pieChart) { pieChart.clear(); pieChart = null; } → if (pieChart) { pieChart = null; }
    • renderLine(): if (lineChart) { lineChart.clear(); lineChart = null; } → if (lineChart) { lineChart = null; }
  2. Hardened the same re-render path for HiDPI displays: Chart.js v1 multiplies context.canvas.width/height by devicePixelRatio on every instantiation (Chart.js:157-161), so on a dpr>1 screen each Apply used to scale the canvas up from the already-doubled backing store (240→480→960 px …). renderPie / renderLine now reset the canvas to its markup size (pieCanvasSize / lineCanvasSize, captured once at page init) before re-instantiating, so the backing store stays constant (dpr=2: pie 480, line 1400 across repeated Applies).

Why this is safe: Chart.js v1 clears the whole canvas itself on re-creation — the constructor resizes context.canvas when window.devicePixelRatio is truthy (Chart.js:157-161), and the animation loop calls clear(ctx) (full clearRect) at the start of every frame (Chart.js:1243 → :353). So no stale pixels can survive into the new chart. #pieLegend is regenerated unconditionally. The tooltip shims (tl-pie-tooltip.js / tl-line-tooltip.js) already de-register prior listeners on re-attach (if (canvas._tlPieMove) canvas.removeEventListener(...)), so repeated re-renders do not stack handlers.

Why not other approaches

  • Add a .clear() method to the bundled Chart.js: rejected — needless surface change to a shared legacy library used by every Dashio chart screen.
  • Upgrade to Chart.js v2/v3: rejected — every .Doughnut()/.Bar()/.Line() call site in the app uses the v1 API; out of scope for a bug fix.

Blast radius: grep '\.clear()' gui/templates/**/*.html → only these two call sites, both in eventviewer.html. No other screen calls .clear() on chart instances.

Verification (CI: MariaDB 127.0.0.1:3306, TestLink @ http://localhost:8082, admin/admin)

Dataset for the final pass: 7 seeded events (AUDIT 3 / WARNING 2 / INFO 1 / ERROR 1).

  1. First load: both charts + legend render, footer 7 events, zero console errors.
  2. Apply with 04/09/2026-04/09/2026 filter: table → 4 events, pie legend updates to AUDIT: 2 (50%) / INFO: 1 (25%) / WARNING: 1 (25%) / ERROR: 0 (0%), line chart re-renders, zero console errors.
  3. Repeated Apply (same + changed filters): stable values, still zero errors.
  4. Empty-result filter (dates in 2020): table 0 events, legend all zeros, no errors (line-tooltip geometry already guards degenerate all-zero data).
  5. Clear Events flow: confirm dialog → 0 events, charts zeroed, zero console errors (exercises the same re-render path).
  6. Pie hover tooltip after re-render: WARNING: 2 (25%) shown at the hit point.
  7. events table: zero new ERROR/WARNING rows generated by the app (only the intentionally seeded fixtures).
  8. HiDPI (emulated devicePixelRatio:2): 4 consecutive Applies keep the pie canvas at 240px CSS / 480 backing and the line canvas at 700px CSS / 1400 backing — no per-Apply canvas growth.

post-fix — charts updated to the filtered dataset

Files

File Purpose
gui/templates/eventviewer/eventviewer.html Fix: drop the two non-existent .clear() calls + HiDPI canvas-size reset on re-render
docs/screenshots/issue-921-eventviewer-charts-frozen.png Pre-fix symptom screenshot
docs/screenshots/issue-921-eventviewer-charts-updated.png Post-fix verification screenshot

Clone this wiki locally