Skip to content

Commit 92552a2

Browse files
committed
fix(legend)!: default the legend to top, and drop it on labeled pies
Three related legend changes. **Default position is 'top' at every breakpoint.** Charts wider than 700px defaulted to a right-hand legend, which surrendered a column of plotting width and truncated to "+N more" past a couple of series -- the election-results bar in the visual suite was labelling one of its two series. Compact and medium already defaulted to 'top', so this only moves wide charts and makes the position uniform rather than width-dependent. `legend: { position: 'right' }` restores it per spec. **Pie/donut charts drop the categorical legend when every slice is labeled.** The leader-line labels already name each category, so the legend restated them one-for-one -- the same redundancy rule bar, lollipop, and beeswarm already apply when color.field matches the category axis. The legend stays whenever the labels do not cover every slice: density 'none' or 'endpoints', a slice count past the point where labels start losing collisions (measured: first drop at 22 slices in the tightest container that renders a pie, so the limit is 21), or any explicit legend config. Waffle and parliament are untouched; they attach no per-mark labels, so their legend is the sole identifier. Deliberately NOT gated on strategy.labelMode: charts/pie/index.ts passes only spec.labels.density to computePieLabels and never consults the strategy, so reading labelMode would make the legend disagree with what the renderer draws (hiding the legend on compact while every label still rendered). **Fix pie slice labels landing on the wrong wedge.** Labels were assigned to marks by array position, but the label array is both density-filtered and re-sorted by collision priority. With density 'endpoints' on a 5-slice pie the second wedge (Bravo) was captioned "Echo". Labels now carry their source index -- a field LabelCandidate already had for exactly this hazard -- and are assigned by it. Leader-line connectors were drawn by the same broken zip and are fixed with them. This was pre-existing, but hiding the legend would have made it the only identifier, so it ships together. Snapshot oracle regenerated: the reclaimed gutter widens the plot 625.8 -> 683.0. 12 visual baselines regenerated for the reflow. 4327 tests pass; typecheck and biome clean.
1 parent 0ccdaed commit 92552a2

25 files changed

Lines changed: 415 additions & 153 deletions

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
2828
- **graph!:** `zoomToFit()` and `zoomToNode()` animate by default (geodesic camera flight). Pass `{ duration: 0 }` to snap like before.
2929
- **graph!:** `update(spec)` is unified: it diffs prev vs next and picks position-preserving refresh or local reheat itself. The camera no longer resets on update, selection persists for surviving ids, and `updateVisuals()` is now a deprecated alias of `update()`. See [migration guide](docs/migrating-v8.md#18-graph-animation-interaction-and-api-changes).
3030
- **graph!:** transparent-background graphs resolve dark mode from the theme's `isDark` flag instead of inferring it from text luminance — transparent + dark mode now renders dark-mode labels/halos without a manual text-color override.
31+
- **legend!:** the responsive default is now `'top'` at every breakpoint. Charts wider than 700px previously defaulted to a right-hand legend, which surrendered a column of plotting width and, on charts with more than a couple of series, truncated to "+N more" — the election-results bar in the visual suite was labelling one of its two series. Compact and medium breakpoints already defaulted to `'top'`, so this only changes wide charts, and it makes the position uniform rather than width-dependent. Set `legend: { position: 'right' }` per spec to restore the old placement. Visual baselines that include a wide legend will shift.
32+
- **legend!:** pie/donut charts no longer render a categorical legend by default. The slices already carry leader-line labels naming every category, so the legend restated them one-for-one — the same redundancy rule bar/lollipop/beeswarm already applied when `color.field` matched the category axis. The legend still renders whenever the labels don't name every slice: `labels: { density: 'none' }` (no labels) or `'endpoints'` (first and last only), a slice count high enough that leader-line labels start dropping to collisions (>21), or any explicit `legend` config. Waffle and parliament are unaffected; they attach no per-mark labels, so their legend is the only identifier.
3133

3234
### Bug Fixes
3335

3436
- **renderer:** faceted charts never resolved a rendering backend at all, so `renderer: 'canvas'` on a facet grid was ignored with no warning (every other refused shape reported it). The facet compile path now runs the same resolution and reports the refusal.
3537
- **renderer:** a chart dense enough to want the canvas layer but shaped so canvas is refused (faceted, layered, sparkline, non-point) now warns once instead of silently painting a DOM node per point. Fires above 5,000 point marks, well clear of the 1,000-point `'auto'` promotion threshold so ordinary facet/layer charts stay quiet. Hosts can reroute or silence it through `onWarn` like any other advisory warning.
38+
- **arc:** pie/donut slice labels were assigned to marks by array position, but the label array is both density-filtered and re-sorted by collision priority, so the text could land on the wrong wedge. With `labels: { density: 'endpoints' }` on a 5-slice pie, the second wedge (Bravo) was captioned "Echo". Labels now carry their source index and are assigned by it; leader-line connectors were drawn by the same broken zip and are fixed with them.
3639
- **graph:** spec validation checks encoding fields against the union of keys across ALL nodes/edges instead of only the first row — a field present on some nodes/edges no longer hard-fails validation. `edgeStyle` is accepted as an edge channel, and `sort` on a quantitative field warns instead of erroring.
3740
- **graph:** node/edge tooltip race eliminated — hovering from an edge onto a node can no longer leave a stale edge tooltip; edge-hover state always clears before the node hover fires.
3841
- **legend:** rows missing the color field no longer manufacture a phantom `undefined` legend entry. In a layered spec every layer's rows flatten into the color-legend source, so a sibling layer (e.g. a diagonal reference-line) that doesn't carry the color field was seeding `String(undefined)` as a category — and with an explicit `scale.domain` it appended past the authored entries, breaking domain authority.
-1.24 KB
Loading
-422 Bytes
Loading
-422 Bytes
Loading
366 Bytes
Loading
-144 Bytes
Loading
139 Bytes
Loading
-20 KB
Loading
-9.31 KB
Loading
-2.31 KB
Loading

0 commit comments

Comments
 (0)