Inconsistent node rectangle sizing on the weathermap panel #54

Closed
opened 2026-07-10 10:49:51 +00:00 by Damien · 1 comment
Owner

Follow-up to #53 (layout work). Reported after visual review: node rectangle size varies inconsistently, including between two nodes of the identical role (e.g. campus-leaf1 vs campus-leaf2).

Observation from live dashboard data

No node has an explicit size field (width/height) — every node shares identical padding: {horizontal:12, vertical:6}. Rendered size is therefore computed by the plugin, not stored. Working hypothesis: it scales with anchors[<side>].numLinks (link count per side) combined with useConstantSpacing: false / compactVerticalLinks: false, both currently false on every generated node.

Supporting evidence: campus-leaf1 (3 total links) and campus-leaf2 (4 total links) render at different sizes despite being the same device role — link count, not role, appears to drive size.

Task: confirm root cause against real plugin source, don't assume

Same caution as #48 (where the documented schema turned out to differ from the actually-installed tamirsuliman-weathermap-panel fork — anchors handling was a real surprise, not theoretical). Before changing anything:

  1. Pull the real module.js (or source, if buildable) from the installed plugin and confirm what actually drives node width/height at render time — useConstantSpacing, compactVerticalLinks, anchors[*].numLinks, or something else entirely
  2. Confirm whether there IS an explicit size override field the fork supports that isn't in the schema doc from #48 (worth a specific grep, given the fork has already diverged from documented schema once)

Fix — consistent sizing per role tier

Once confirmed, make node size deterministic and consistent by role (all leafs same size, all spines same size, etc.), decoupled from link count:

  • If useConstantSpacing: true achieves this cleanly, set it uniformly on generation
  • If an explicit size field exists in the real plugin, set it explicitly per role instead of relying on auto-sizing
  • Role tiers to use: same classification as #53's layout work (spine / core / border-leaf / leaf / access) — reuse that parsing, don't reimplement

Validation

  • Regenerate, confirm every node of the same role renders at the same size regardless of link count (spot-check campus-leaf1 vs campus-leaf2 specifically, since that's the reported case)
  • Confirm this doesn't break the live-position-preservation logic from #53 — size and position are independent fields, changing size defaults shouldn't touch position
  • Visual check in Grafana UI (still no image-renderer / browser access on the agent side — flag if still true, ask for a human look)

Document

  • What actually controls size in the installed plugin (ground truth, not the schema doc's guess)
  • Final size values chosen per role tier, and why
Follow-up to #53 (layout work). Reported after visual review: node rectangle size varies inconsistently, including between two nodes of the identical role (e.g. `campus-leaf1` vs `campus-leaf2`). ## Observation from live dashboard data No node has an explicit size field (`width`/`height`) — every node shares identical `padding: {horizontal:12, vertical:6}`. Rendered size is therefore computed by the plugin, not stored. Working hypothesis: it scales with `anchors[<side>].numLinks` (link count per side) combined with `useConstantSpacing: false` / `compactVerticalLinks: false`, both currently `false` on every generated node. Supporting evidence: `campus-leaf1` (3 total links) and `campus-leaf2` (4 total links) render at different sizes despite being the same device role — link count, not role, appears to drive size. ## Task: confirm root cause against real plugin source, don't assume Same caution as #48 (where the documented schema turned out to differ from the actually-installed `tamirsuliman-weathermap-panel` fork — `anchors` handling was a real surprise, not theoretical). Before changing anything: 1. Pull the real `module.js` (or source, if buildable) from the installed plugin and confirm what actually drives node width/height at render time — `useConstantSpacing`, `compactVerticalLinks`, `anchors[*].numLinks`, or something else entirely 2. Confirm whether there IS an explicit size override field the fork supports that isn't in the schema doc from #48 (worth a specific grep, given the fork has already diverged from documented schema once) ## Fix — consistent sizing per role tier Once confirmed, make node size deterministic and consistent by role (all leafs same size, all spines same size, etc.), decoupled from link count: - If `useConstantSpacing: true` achieves this cleanly, set it uniformly on generation - If an explicit size field exists in the real plugin, set it explicitly per role instead of relying on auto-sizing - Role tiers to use: same classification as #53's layout work (spine / core / border-leaf / leaf / access) — reuse that parsing, don't reimplement ## Validation - Regenerate, confirm every node of the same role renders at the same size regardless of link count (spot-check `campus-leaf1` vs `campus-leaf2` specifically, since that's the reported case) - Confirm this doesn't break the live-position-preservation logic from #53 — size and position are independent fields, changing size defaults shouldn't touch `position` - Visual check in Grafana UI (still no image-renderer / browser access on the agent side — flag if still true, ask for a human look) ## Document - What actually controls size in the installed plugin (ground truth, not the schema doc's guess) - Final size values chosen per role tier, and why
Damien added the telemetry label 2026-07-10 10:49:51 +00:00
Author
Owner

Implemented in 9b53ab0 (branch feat/telemetry).

Root cause (confirmed against the real plugin, not the #48 doc)

Pulled the actual bundle from the installed plugin ($GRAFANA_URL/public/plugins/tamirsuliman-weathermap-panel/module.js, ~177KB minified) rather than trusting the #48 schema research, per the issue's own caution. Found the two functions that compute the rendered rectangle dimensions directly (z() = width, L() = height, both fed straight into the SVG rect via useMemo):

Width (z()): label_width + 2*padding.horizontal when useConstantSpacing is false (our current/unchanged setting) — label_width itself is always recomputed fresh from the actual label text via canvas.measureText() at render time (i.labelWidth = I(i.label, fontSize).width inside the node-normalization function). There is no explicit width override field anywhere in the schema — nothing we set in JSON for width would ever be read. useConstantSpacing: true would only pull in a term based on Top/Bottom anchor link count, which this generator never populates (links always attach Right/Left, per the existing anchor_counts comment) — so it's a dead lever for our topology either way, width is purely a function of label string length + font. This confirms width was never actually the bug: campus-leaf1/campus-leaf2 have identical-length labels, so their widths were already identical.

Height (L()) — the actual bug: max(anchors[Left].numLinks, anchors[Right].numLinks) directly scales a link-stack height term, and return !compactVerticalLinks && c > s ? c : s means that term wins over the constant font-based height s whenever compactVerticalLinks is false (the value every node had, generated by #48/#52/#53) and the link-count term is larger. campus-leaf1 (3 links) vs campus-leaf2 (4 links) is exactly max(anchors[Left], anchors[Right]) differing → different c → different rendered height. Confirmed by reading the numLinks/numFilledLinks accounting in the bundle, not by inference.

So the issue's own hypothesis named the wrong flag (useConstantSpacing) for the actual defect — compactVerticalLinks is the real lever, and it fully explains the reported symptom.

Fix

compactVerticalLinks: True on every node (was False). Per the confirmed formula this makes height an unconditional constant — fontSize + 2*padding.vertical — for every node, since padding and fontSize are already uniform fabric-wide (no per-node override exists in the generator). This isn't just "consistent per role tier" as asked, it's consistent across every node regardless of role, which satisfies the requirement without needing per-role values (there's nothing to differentiate by, since the plugin gives us no size field to key off role in the first place — only this one boolean).

useConstantSpacing left false (unchanged) — confirmed it has no bearing on this bug given our anchor usage pattern, so touching it would be a no-op dressed up as a fix.

Validation

  • Diffed the full merged output against the previous commit, isolated to exactly the fields that changed across all 28 nodes: {'position', 'compactVerticalLinks'}. No other field (statusQuery, anchors, colors, padding, label, etc.) touched.
  • position: unrelated drift, not from this change — the live Grafana dashboard had already moved between the #53 and #54 sessions (x roughly preserved per node, y snapped into a few discrete bands — looks like the plugin's own auto-arrange, likely from the manual UI pass requested at the end of #53). This is exactly #53's live-position-preservation mechanism doing its job correctly: whatever was live got carried over untouched by this run, regardless of source. Confirms size and position stayed fully independent, as required.
  • campus-leaf1/campus-leaf2 spot-check: both now have compactVerticalLinks: true, identical padding, no fontSize override → guaranteed identical rendered height by the confirmed formula, regardless of their differing per-side link counts (max(1,3)=3 vs max(2,2)=2).
  • Provisioned to Grafana.

Outstanding

Still no image-renderer plugin / browser access on my end — I can't screenshot the result. Please do a visual pass to confirm the rectangles actually look uniform now; the source-level analysis is solid but a render-level confirmation from a human is still the right final check here, same caveat as #49/#52/#53.

Implemented in `9b53ab0` (branch `feat/telemetry`). ## Root cause (confirmed against the real plugin, not the #48 doc) Pulled the actual bundle from the installed plugin (`$GRAFANA_URL/public/plugins/tamirsuliman-weathermap-panel/module.js`, ~177KB minified) rather than trusting the #48 schema research, per the issue's own caution. Found the two functions that compute the rendered rectangle dimensions directly (`z()` = width, `L()` = height, both fed straight into the SVG rect via `useMemo`): **Width (`z()`)**: `label_width + 2*padding.horizontal` when `useConstantSpacing` is false (our current/unchanged setting) — `label_width` itself is **always recomputed fresh from the actual label text** via `canvas.measureText()` at render time (`i.labelWidth = I(i.label, fontSize).width` inside the node-normalization function). There is **no explicit width override field** anywhere in the schema — nothing we set in JSON for width would ever be read. `useConstantSpacing: true` would only pull in a term based on `Top`/`Bottom` anchor link count, which this generator never populates (links always attach `Right`/`Left`, per the existing `anchor_counts` comment) — so it's a dead lever for our topology either way, width is purely a function of label string length + font. This confirms width was never actually the bug: `campus-leaf1`/`campus-leaf2` have identical-length labels, so their widths were already identical. **Height (`L()`)** — the actual bug: `max(anchors[Left].numLinks, anchors[Right].numLinks)` directly scales a link-stack height term, and `return !compactVerticalLinks && c > s ? c : s` means that term wins over the constant font-based height `s` whenever `compactVerticalLinks` is `false` (the value every node had, generated by #48/#52/#53) and the link-count term is larger. `campus-leaf1` (3 links) vs `campus-leaf2` (4 links) is exactly `max(anchors[Left], anchors[Right])` differing → different `c` → different rendered height. Confirmed by reading the `numLinks`/`numFilledLinks` accounting in the bundle, not by inference. So the issue's own hypothesis named the wrong flag (`useConstantSpacing`) for the actual defect — `compactVerticalLinks` is the real lever, and it fully explains the reported symptom. ## Fix `compactVerticalLinks: True` on every node (was `False`). Per the confirmed formula this makes height an unconditional constant — `fontSize + 2*padding.vertical` — for every node, since `padding` and `fontSize` are already uniform fabric-wide (no per-node override exists in the generator). This isn't just "consistent per role tier" as asked, it's consistent across *every* node regardless of role, which satisfies the requirement without needing per-role values (there's nothing to differentiate by, since the plugin gives us no size field to key off role in the first place — only this one boolean). `useConstantSpacing` left `false` (unchanged) — confirmed it has no bearing on this bug given our anchor usage pattern, so touching it would be a no-op dressed up as a fix. ## Validation - Diffed the full merged output against the previous commit, isolated to exactly the fields that changed across all 28 nodes: `{'position', 'compactVerticalLinks'}`. No other field (`statusQuery`, `anchors`, `colors`, `padding`, `label`, etc.) touched. - `position`: unrelated drift, not from this change — the live Grafana dashboard had already moved between the #53 and #54 sessions (x roughly preserved per node, y snapped into a few discrete bands — looks like the plugin's own auto-arrange, likely from the manual UI pass requested at the end of #53). This is exactly #53's live-position-preservation mechanism doing its job correctly: whatever was live got carried over untouched by this run, regardless of source. Confirms size and position stayed fully independent, as required. - `campus-leaf1`/`campus-leaf2` spot-check: both now have `compactVerticalLinks: true`, identical `padding`, no `fontSize` override → guaranteed identical rendered height by the confirmed formula, regardless of their differing per-side link counts (`max(1,3)=3` vs `max(2,2)=2`). - Provisioned to Grafana. ## Outstanding Still no image-renderer plugin / browser access on my end — I can't screenshot the result. Please do a visual pass to confirm the rectangles actually look uniform now; the source-level analysis is solid but a render-level confirmation from a human is still the right final check here, same caveat as #49/#52/#53.
Damien added reference feat/telemetry 2026-07-10 13:01:08 +00:00
Sign in to join this conversation.