Skip to content

Retire canvas-gauges: render the three ng gauges as Skip's own SVG #588

Description

@mairas

Skip's three canvas gauges (widget-gauge-ng-linear, widget-gauge-ng-radial, widget-gauge-ng-compass) render through @godind/ng-canvas-gauges@6.2.1, a thin Angular wrapper over @godind/canvas-gauges@2.2.1. That lineage is a fork of a fork of a library whose upstream (Mikhus/canvas-gauges) last shipped 2.1.7 in April 2020. Retire it in favour of Skip's own SVG rendering, one widget at a time.

Why now

The wrapper is published in full Ivy compilation. Its fesm2022 bundle calls ɵɵdefineComponent directly and contains zero ɵɵngDeclare* declarations, so the emitted component definitions are bound to the private Angular runtime API of the version that built them (Angular 16 era). Angular's linker guarantees forward compatibility only for partial-compiled libraries. It works on our @angular/core@21.2.7 today and the suite is green, but every major bump is an unhedged bet, and the declared peer range (@angular/core >=9.0.0) is fiction.

Nobody will fix it. Both packages were last published 2024-05-15 and both GitHub repos last pushed the same day. Both are zero-star personal forks of forks (godind/ng-canvas-gaugesbiacsics/ng-canvas-gauges; godind/canvas-gaugesngbrown-forks/canvas-gaugesMikhus/canvas-gauges). The KIP maintainer marked that project unmaintained on 2026-08-10, which confirms the direction but changes nothing — these were already frozen for two years.

The engine is not vendorable. @godind/canvas-gauges@2.2.1 ships four files, and the only code among them is gauge.min.js — 43 KB minified, no sourcemap, no sources. Copying it into the tree buys nothing node_modules does not already give us; owning it for real means forking Mikhus/canvas-gauges (last pushed 2023-11-11, 95 open issues) and adopting its build.

No maintained library to move to

Surveyed, with last-publish dates:

Package Latest Published Verdict
ngx-gauge 13.3.1 2026-06-18 Only maintained Angular-native gauge, but arc-only: type surface is full | arch | semi with thresholds and markers, and its .d.ts has zero occurrences of "needle" or "pointer". No needle, no tick scale, no linear bar, no compass.
echarts 6.1.0 2026-05-19 The only capable and maintained option. 489 KB minified for the simple dist, 1 096 KB full, against 43 KB today. A tree-shaken gauge-only build is smaller but unmeasured; this is Pi-class hardware.
apexcharts 6.8.0 2026-08-09 radialBar only.
justgage / gaugeJS / svg-gauge 2.0.1 / 1.3.9 / 1.0.7 2025-10 / 2024-10 / 2022-07 Too simple for a needle-and-tick instrument.
canvas-gauges 2.1.7 2020-04-09 The dead upstream.
steelseries 2.0.9 2024-10-08 134 weekly downloads; the same library Skip already ships as src/assets/steelseries-min.js. Trading one dead gauge library for another.

A compatibility shim is the wrong shape

Skip sets 65 distinct canvas-gauges options in the linear widget and about 78 in each of radial and compass: plate colour and three border layers, needle circle inner/outer colours, value-box geometry, per-element fonts, highlight arrays, animationTarget. No other library implements that model — ECharts configures gauges through axisLine / splitLine / axisTick / pointer / anchor / progress / detail, with different geometry semantics. A shim would not adapt one library to another; it would reimplement a spec only a dead library ever had.

A large share of what such a shim would faithfully preserve is us switching the library's own chrome off: colorNeedleCircleInner = colorPlate, colorNumbers = '' as unknown as string, majorTicks = 0 as unknown as string[], barStrokeWidth = 0, borderShadowWidth = 0. Those casts also dispose of the "at least we keep a typed surface" argument — the shipped .d.ts already disagrees with the runtime, which is why the widgets cast around it.

Skip already renders instruments like these

Component Lines What it renders
svg-windsteer 568 TS + 743 SVG Rotating compass rose, 34 text labels, 20 rotation transforms
svg-racesteer 572 Rotating rose with lay-line sectors
widget-heel-gauge 411 Scale with a moving indicator
svg-autopilot 304 Instrument face with state
svg-simple-linear-gauge 108 Linear bar

The rotating compass card — the hardest thing widget-gauge-ng-compass does — exists in-tree twice. The three ng widgets are 441 / 425 / 327 lines today, much of it option plumbing that disappears with the library rather than moving into a shim.

Plan

  1. Compass first. svg-windsteer is the nearest twin, so it is the cheapest proof and the clearest reuse.
  2. Measure it with perf-harness/ before anything follows. Whether SVG holds up against canvas on a Pi with a gauge-heavy dashboard is not established, and a gauge-heavy dashboard is exactly the freeze scenario the harness exists for. If SVG loses, this plan stops here and we reconsider — including the fallback of absorbing the ~416-line wrapper as a Skip component (MIT, notice retained) and keeping the engine pinned at 2.2.1.
  3. Radial, then linear, each behind the same measurement.
  4. Drop @godind/ng-canvas-gauges when the last widget is off it. src/test-shims/ng-canvas-gauges-shim.ts and its vitest.config.ts alias go at the same time — the shim exposes only options and value, so every imperative update() push in these widgets currently throws into a swallowing catch and is unobservable in specs (see docs(testing): record the gauge test-shim trap #533). Own-SVG widgets are directly assertable, which is the point.

Out of scope: steelseries, which has the same disease in a worse form — src/assets/steelseries-min.js (229 KB) loaded by a <script defer> in index.html and reached through declare let steelseries: any in gauge-steel and widget-horizon. Worth its own issue once the canvas-gauges exit proves the approach.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:angularAngular best practices & reactivityarea:architectureArchitecture & data flowarea:uxUX & interaction designenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions