diff --git a/.claude/rules/frontend/react.md b/.claude/rules/frontend/react.md index dfdbccc6..9864e872 100644 --- a/.claude/rules/frontend/react.md +++ b/.claude/rules/frontend/react.md @@ -18,7 +18,7 @@ paths: The react package wraps vanilla renderers. Key components: -- `` - renders a chart from a VizSpec +- `` - renders a chart from a `ChartSpec | LayerSpec` (use `` when the spec type varies) - `` - renders a data table from a TableSpec - `` - renders a network graph from a GraphSpec - `` - provides theme context to descendants diff --git a/.claude/rules/testing.md b/.claude/rules/testing.md index a2abc0b2..d18c0ca3 100644 --- a/.claude/rules/testing.md +++ b/.claude/rules/testing.md @@ -25,7 +25,7 @@ When fixing flaky tests, load the ce:writing-tests skill (flaky-test guidance is Collision and fitting logic (label rotation, thinning, tick density) is font-size- and width-dependent. Tests for it must sweep both dimensions: -- Font: `axisTick: 11` (default) AND `axisTick: 14` (the deployed blog theme) +- Font: `axisTick: 12` (default) AND `axisTick: 14` (the deployed blog theme) - Width: ~330 (blog mobile), ~360 (small phone), ~680 (desktop-ish) Why: the 7.9.x dropped-label bug passed every default-theme test across three diff --git a/.claude/rules/visual-regression.md b/.claude/rules/visual-regression.md index ea81ccf5..062fb4bc 100644 --- a/.claude/rules/visual-regression.md +++ b/.claude/rules/visual-regression.md @@ -18,7 +18,7 @@ Don't rely on it for: ## How it works -`playwright.config.ts` at the repo root spawns the Ladle dev server on port 61000, then two specs screenshot the canonical story set: `e2e/visual/stories.spec.ts` (60 desktop entries) and `e2e/visual/stories-mobile.spec.ts` (12 entries at a mobile viewport). Both go through the shared harness in `e2e/visual/capture.ts`. Baselines live in `e2e/visual/__screenshots__/-snapshots/` and are committed to git. +`playwright.config.ts` at the repo root spawns the Ladle dev server on port 61000, then two specs screenshot the canonical story set: `e2e/visual/stories.spec.ts` (94 desktop entries) and `e2e/visual/stories-mobile.spec.ts` (21 entries at a mobile viewport). Both go through the shared harness in `e2e/visual/capture.ts`. Baselines live in `e2e/visual/__screenshots__/-snapshots/` and are committed to git. Before each screenshot the harness disables animations via an injected stylesheet and hides the Ladle dev overlays, then waits for fonts to settle, so timing and layout are deterministic. diff --git a/CHANGELOG.md b/CHANGELOG.md index 36c6795b..f16fd9d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,142 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this ## [Unreleased] +### Chart and map design + +- Keep the two endpoint date labels readable when a slope chart has a narrow plot, + without moving the data anchors or overriding explicit tick values. + +- Add optional detail geography with zoom thresholds and explicit topology-object + selection, preserving the primary fitted projection. Validate decoded source + planes for identity maps before updates mutate the figure. +- Add explicitly covered, independently labeled geographic insets with scoped + cameras, callouts and mark events across vanilla and all wrappers. Share place + identity and scale semantics across views; export all current view cameras. + +- Add opt-in date-slice A/B comparison and geographic reader controllers, with + host-placed readouts, local place search/ranking, keyboard inspection and explicit + Show on map actions. Missing observations remain distinct from zero; controlled + selection updates are silent in vanilla and React/Vue/Svelte. +- Add optional active-value and distribution map keys without changing authored + scale domains or class boundaries. Size side gutters to their content, use compact + quantitative range lists, and remove unnecessary backgrounds from reserved keys. +- Measure source, byline, footer and branding together across chart, map, bar list, + Sankey, tile map, table and graph. Stack long attribution when it fits better, + preserve custom brands, and use a consistent 12px default watermark. This can + change footer wrapping and available plot space in migrated documents. +- Add opt-in geographic `text`/`textPriority` channels and keyed `callouts`, with + polygon-interior anchors, bounded collision placement, fixed note capacity and + constant-screen-size labels through camera movement. +- Preserve every authored place name and callout in an accessible inventory; add + a host-placed `labelInventory` disclosure in vanilla and all GeoMap wrappers. +- Include settled geographic labels and full inventory descriptions in SVG export + and GeoMap static rendering; add stable `idPrefix` for multiple static figures. + +- Add measured bar value placement (`adaptive`, `inside`, `outside`, `column`), + including shared value columns in facets and diagnostics when labels cannot fit. +- Add opt-in `rowHover` across vanilla and all Chart wrappers: quiet full-row + inspection for simple horizontal bars, shared with keyboard focus and passive + around annotations, legends and editing. +- Add horizontal y-axis unit headers through `titleAngle: 0` and `titleAnchor: 'end'`. +- Align endpoint precision across a displayed column, preserve source values and + missing observations, and measure formatted labels with the host font metrics. +- Budget both endpoint columns, gaps and date context against the measured axes; + automatic layouts retain a usable plot, while impossible authored fits diagnose. +- Default stacked-area endpoints to their band midpoint; retain explicit boundary + anchors and opt-in fit-tested interior series names. Hover geometry is unchanged. +- Preserve complete series names and band leaders in independent-scale layers; + resolve stacked domains from accumulated bands and separate clipped endpoint anchors. +- Measure the complete independent-layer legend before placing either axis, so + wrapped rows and side keys reserve space for every eligible series. +- Honor the resolved label font on bars, columns, dots and ranges; determine + column label direction from the source number instead of its formatted text. +- Add useful endpoint typography/spacing and map ink theme controls. Keep current + bar proportions and endpoint spacing; use quieter ordinary gridlines and stronger + existing zero rules in SVG and canvas without changing scale domains. +- Adopt quieter map borders while retaining the current no-data hatch. Measure + static map key titles/units/context before fitting geography, and place size keys + using their full bounds and geographic obstacles. +- Preserve expressible v8 grid, band-anchor and border styling in migration; report + the unavoidable new map-key layout behavior. +- Keep enlarged bar labels within available space, and keep enlarged rotated + axis titles inside the viewport. +- Place top point-color keys in their reserved band; reserve wrapped category + rows accurately and avoid double-counting mixed bottom key heights. +- Honor right and bottom-right map legends with measured gutters, narrow-layout + fallback diagnostics, and camera clipping that keeps geography out of the key. +- Describe actual map scale intervals in accessible legend text and accept the + built-in diverging palettes for quantitative geographic color encodings. + +## [9.0.0] - 2026-10-17 + +### Annotation and figure defaults + +- Adopt 12px small/axis/source/byline/footer text and 16px/12px chrome spacing. + Background stays transparent; default axis and eyebrow colors are unchanged. +- Default callouts to measured wrapping, regular primary text, 12/13 subtitle + sizing, and curves without implied arrows. Explicit author settings still win. +- Default reference labels to automatic placement and reference/range labels to + theme small text. Process automatic annotations by priority then source order, + and score connector crossings when selecting placements. +- Keep one eligible inline callout at compact widths by default. Per-annotation + `responsive: false` stays pinned; existing chart-level responsive opt-outs retain + their compact behavior. Null still disables count and wrap limits. +- Grow omitted `chromeLayout` by the note band only. Explicit `subtract` keeps an + exact outer budget; `grow` grows by all chrome. Resolved heights avoid double + counting in mounts and exports, including layered and faceted figures. +- Render complete wrapped rich-text notes with source-order numbering. Number + gaps are intentional and facet instances share source identity. Notes and + markers support transient linked focus/click/tap emphasis. +- Retune default reference-rule and range ink; derive marker and plate fills from + the resolved neutral surface while preserving authored colors. + +### Breaking API and authoring changes + +- Make `onEdit(EditTransaction)` the sole durable editing callback. Remove + `ElementEdit`, `onEditTransaction`, `onAnnotationEdit`, and `onTextEdit`; use + `applyEditTransaction` for atomic application, stale-target rejection, and undo. +- In edit mode, arrows nudge 1px, Shift+arrows nudge 10px, and Tab/Shift+Tab cycle + selection. Native text editing keeps its normal keyboard behavior. +- Remove the inert `onDataPointClick`, graph `updateVisuals()`, and the Chart + mount/wrapper `responsive` resize alias. Use `onMarkClick`, `update()`, and + `autoResize`, respectively; spec `responsive` is unchanged. +- Enforce the discriminated `MarkDef` union and reject inapplicable authored mark + options before sugar expansion, with matching TypeScript/schema/runtime checks. +- Reject retired table `compact`, Sankey/map/barlist `valueFormat`, annotation + `rule`, spec `darkMode`, theme chrome color strings, arc-family `encoding.y` + aliases, dead encoding channels, `mark.render`, and explicit `legacy` animation + presets. Tilemap `valueFormat` and ordinary chrome text shorthand remain valid. +- Remove legacy line-end series labels, manual series-label offsets/dragging, and + series-label element refs. Use the endpoint column; warn when both identifiers + are explicitly disabled on a multi-series line chart. +- Remove `footnoteBandHeight` helpers and narrow-breakpoint constant aliases. + Read `layout.chrome.noteBandHeight` and use `NARROW_VIEWPORT_MAX`. +- Unify builder/compiler field inference: sample up to 50 rows, require more than + 80% agreement, and recognize numeric strings before dates. Explicit field types + remain authoritative. + +### Themes and migration + +- Deep-merge spec/provider/host themes; leaf themes override parent themes and + mount/compile options have highest precedence. Arrays and color pairs replace + atomically; partial rules inherit and `rule: null` clears a preset rule. +- Prefer authored chrome font sizes over general font propagation. Remove public + `Theme` and the empty `editorial` preset; use `ThemeConfig` / `ResolvedTheme` and + omit the preset. Deprecate `clarity`, retaining its remaining color choices. +- Stamp only authored CSS theme overrides through one renderer helper. Host CSS + can override omitted tokens; dark defaults include all registered tokens and + SVG/raster exports retain live CSS token values. +- Keep layer font measurement and font-load updates aligned with the primary + leaf theme; keep hidden annotation notes out of keyboard navigation. +- Normalize breakpoint annotations and apply endpoint-label patches consistently + with root specs, including migrated legacy labels. +- Extend `migrateSpecV8` with `{ styling: 'v9' }` for alias-only migration. Default + migration materializes former v8 styling, including annotation colors/spacing, + and reports repairs without mutating input. Layout pixel parity is not promised. +- Add [the v9 migration guide](docs/migrating-v9.md), including persistence handler, + exact-height embed, theme, CSS, and mark-union changes. + + ## [8.9.1] - 2026-10-17 ### Annotation layout and theme options diff --git a/README.md b/README.md index 5c171a3e..bbbe5d04 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ function App() { That's the whole interface. `encoding` maps data fields to visual channels. `chrome` adds editorial framing. The engine figures out the rest. -The fixed-height wrapper is optional. Without one, the chart sizes itself: a 400px budget for the visualization (axes + plot), and titles, legends, and other chrome grow the figure on top of that. Give the wrapper an explicit height when you need the chart to fit a fixed slot. +The fixed-height wrapper is optional. Without one, the chart sizes itself: a 400px budget for the visualization (axes + plot), and titles, legends, and other chrome grow the figure on top of that. Give the wrapper an explicit height and set `chromeLayout: 'subtract'` when the chart must fit an exact slot; otherwise annotation notes can grow the figure. ## Features @@ -115,6 +115,7 @@ Release candidates publish under the `next` dist-tag, so a plain install always | [Accessibility](docs/accessibility.md) | What's automatic, what's opt-in (alt text, pattern fills, contrast warnings), WCAG mapping | | [Agent patterns](docs/agent-patterns.md) | Visualization patterns and cookbook for LLM-generated charts | | [Architecture](docs/architecture.md) | Compilation pipeline, package boundaries, design decisions | +| [Migrating to v9](docs/migrating-v9.md) | Annotation defaults, transaction editing, theme precedence, and retired APIs | | [Migrating to v8](docs/migrating-v8.md) | Breaking changes, before/after specs, and jq codemod recipes for the v8 upgrade | | [Theming tokens](docs/theming-tokens.md) | Design token system, `TokenValue` light/dark pairs, `seriesStrategy`, named presets | | [Contributing](CONTRIBUTING.md) | Setup, running tests, adding chart types, PR guidelines | diff --git a/bunfig.toml b/bunfig.toml new file mode 100644 index 00000000..daf6566a --- /dev/null +++ b/bunfig.toml @@ -0,0 +1,4 @@ +[install] +# Keep tools that require TypeScript's JS API on the root JS compiler alias. +# Isolated installs hoist the native CLI-only package into .bun/node_modules. +linker = "hoisted" diff --git a/docs/accessibility.md b/docs/accessibility.md index 5f61ab34..ed0774a4 100644 --- a/docs/accessibility.md +++ b/docs/accessibility.md @@ -19,7 +19,7 @@ Every chart gets these without configuration, in the vanilla adapter and all fra - **Alt text**: a generated description of the chart (mark type, title, data range, series, point count) set as `aria-label` on the SVG with `role="img"`. - **Screen reader data table**: a visually hidden HTML `` with the chart's data rendered alongside the SVG, so screen reader users can read the actual values. - **Per-mark ARIA labels**: each bar, slice, and point carries a descriptive label for assistive technology. -- **Keyboard navigation**: the chart container is focusable; arrow keys move between marks, Enter/Space shows the tooltip, Escape dismisses it. Focus indicators use the `--oc-focus` token, which has distinct light and dark values so the ring is visible in both modes. +- **Keyboard navigation**: the chart container is focusable; arrow keys move between marks, Enter/Space shows the tooltip, Escape dismisses it. In edit mode (`interaction: 'edit'`, or an `onEdit` handler) arrows nudge the selected annotation instead, so reader navigation is off; `'read'` and `'select'` keep it. Focus indicators use the `--oc-focus` token, which has distinct light and dark values so the ring is visible in both modes. - **Dismissible tooltips**: Escape hides a visible tooltip even while hovering, without moving the pointer (WCAG 1.4.13). - **Data tables**: semantic HTML (`
`, `
`), ARIA grid roles, sort state attributes, and a live region announcing sort/search changes. diff --git a/docs/agent-patterns.md b/docs/agent-patterns.md index 73c30df7..f97f5e5a 100644 --- a/docs/agent-patterns.md +++ b/docs/agent-patterns.md @@ -64,7 +64,7 @@ All specs use realistic data with plausible numbers. Copy and adapt. } ``` -**Multi-series variant:** Add a `color` encoding to split by category. Keep to 5 series max for readability. +**Multi-series variant:** Add a `color` encoding to split by category. Keep to 5 series max for readability. Use the legend or `endpointLabels` to identify series; legacy line-end labels and manual series-label offsets are removed. ```json { @@ -182,7 +182,7 @@ All specs use realistic data with plausible numbers. Copy and adapt. { "browser": "Other", "share": 8.4 } ], "encoding": { - "y": { "field": "share", "type": "quantitative" }, + "theta": { "field": "share", "type": "quantitative" }, "color": { "field": "browser", "type": "nominal" } }, "chrome": { @@ -553,6 +553,8 @@ All specs use realistic data with plausible numbers. Copy and adapt. | `range` | Time periods, regions, phases | Use low `opacity` (0.05-0.1) so data is still visible. | | `refline` | Thresholds, baselines, averages | Use `dashed` or `dotted` style to visually separate from data. | +**Responsive annotation defaults:** Omit offsets and anchors when automatic placement is sufficient. Lower `priority` values stay inline first; compact charts keep one eligible text callout and put the rest in wrapped notes, including subtitles. `responsive: false` pins a callout inline and can cause overlap at narrow widths. Use `maxWidth: null` or `responsive.compactAnnotationLimit: null` only when an unlimited layout is intentional. Source-order note numbers may have gaps. Curves do not imply arrows; use `{ "type": "curve", "arrow": true }` explicitly. + **Combining annotations:** Layer them. Ranges go behind the data (low opacity). Reference lines mark horizontal/vertical thresholds. Text callouts highlight specific inflection points or notable data values. This layering creates visual depth. --- diff --git a/docs/architecture.md b/docs/architecture.md index 9419c3dc..155d3752 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -79,9 +79,9 @@ graph LR Step by step: -1. **Validate**: Runtime type checking of the raw spec. Catches missing fields, wrong types, invalid encoding combinations. On a missing data field, the validator suggests the nearest real column name (Levenshtein) so the error tells the author how to fix it. -2. **Normalize**: Fill in defaults, resolve shorthand, produce a `NormalizedChartSpec` with all optional fields resolved. This stage also expands spec sugar (Vega-Lite idioms, bin/timeUnit) and collects deprecation warnings. The engine never calls `console.*`; it returns a structured warnings array that the vanilla adapter surfaces once at its boundary (see Compile warnings below). -3. **Resolve theme**: Deep-merge user theme overrides onto the default theme. Produces a `ResolvedTheme` with every property set. +1. **Validate**: Reject removed fields and inapplicable mark options against authored paths before sugar expansion, then validate the canonical spec. Catches missing fields, wrong types, invalid encoding combinations. On a missing data field, the validator suggests the nearest real column name (Levenshtein) so the error tells the author how to fix it. +2. **Normalize**: Fill in defaults, resolve shorthand, produce a `NormalizedChartSpec` with all optional fields resolved. The pre-validation sugar pass expands supported Vega-Lite idioms and bin/timeUnit transforms. Deprecated v8 aliases are no longer normalized silently. The engine never calls `console.*`; it returns a structured warnings array that the vanilla adapter surfaces once at its boundary (see Compile warnings below). +3. **Resolve theme**: Deep-merge authored layers with `mergeThemeConfig`, then resolve defaults into `ResolvedTheme`. Leaf themes override their parent and mount/compile options override the spec. 4. **Dark mode adapt**: If dark mode is active, transform colors (lighten backgrounds, adjust palette brightness, swap text colors). 5. **Compute legend**: Determine legend entries from the color encoding. Calculate space needed for legend positioning. Categorical color produces swatch entries; a quantitative color scale produces a continuous legend instead, either a gradient bar (sequential/diverging scales) or discrete swatches with class breaks (binned scales like quantile/quantize/threshold). 6. **Compute dimensions**: Account for chrome (title, subtitle, source, footer), legend, axis labels. Produce the chart area `Rect`. @@ -92,12 +92,20 @@ Step by step: 11. **Compute endpoint labels**: For line/area charts with `layout.endpointLabels` enabled, place a chip+swatch label at each series' trailing point. A capped iterative sweep (`endpoint-labels/compute.ts`) resolves vertical overlaps and clamps to the chart edges so the tail label never falls off-canvas. 12. **Compute metric bar**: When `chrome.metrics` is set, lay out the chrome metric pills (label + value + delta) so the renderer can paint them above the chart area. 13. **Apply suppression truth table**: A single source of truth (`legend/suppression.ts`) decides what disappears for each hidden series — endpoint label, leader line, dot annotation, and series-anchored text annotations all consult the same table so legend toggles, `hiddenSeries`, and runtime hides never disagree. -14. **Compute annotations**: Map annotation specs (reference lines, ranges, text callouts) to pixel positions using the scales. +14. **Compute annotations**: Resolve reference lines, ranges, and text callouts using the scales. Automatic placement follows priority/source order and scores leader crossings; compact thinning creates source-numbered rich notes. Resolved note bands participate in figure growth. 15. **Compute tooltips**: Build tooltip content descriptors keyed by mark ID. 16. **Compute a11y**: Generate alt text, ARIA labels, and a screen-reader data table from the spec and data. The output is a `ChartLayout` with everything the renderer needs: positioned marks, resolved chrome, axes, gridlines, annotations, tooltips, accessibility metadata, and the resolved theme. +### Geographic label compilation + +GeoMap place labels and callouts are optional. The compiler measures their complete text and fixed authored callout-note capacity before the single projection fit. `geo/labels.ts` builds stable candidates from explicit text channels and typed anchors. `geo/label-geometry.ts` captures projected components and holes through the same projection stream as feature paths, retaining only candidate geometry within a bounded vertex budget. + +The portable `GeoMapLayout.labels` bundle contains measured text, projected geometry, obstacles, note slots and the initial overlay. It contains no DOM nodes or projection functions. The pure `resolveGeoOverlay` applies a camera affine transform, validates visible interior anchors and places labels deterministically. Camera settlement and export share this resolver; neither refits the topology. + +The vanilla adapter paints constant-screen-size text in a sibling of the transformed camera group. During movement it projects accepted anchors and culls offscreen boxes; settlement recomputes placement. The separate inventory controller owns a hidden accessible list and an optional disclosure in a host-supplied container. It cannot reserve SVG space or change camera state. Framework wrappers forward the runtime option and reconcile container replacement without remounting. + ### Table compilation Tables follow a similar validate-normalize-theme pipeline, then run a different set of computations: @@ -204,7 +212,7 @@ Maps, tile maps, bar lists and Sankey diagrams share mark keyboard navigation. A Static chart exports render the terminal layout rather than serializing hover or in-flight geometry. Map exports retain the current camera, authored focus and zoom viewport clipping. Font embedding resolves inline styles before presentation attributes and inherits font declarations for text spans, including detached export scenes. Table CSV exports use all filtered/sorted rows, independently of the displayed page. -Both adapters use `ResizeObserver` to detect container size changes and trigger recompilation at the new dimensions. The responsive system uses breakpoints to adjust layout strategy (label density, legend position, annotation placement). +Both adapters use `ResizeObserver` to detect container size changes and trigger recompilation at the new dimensions; every mount takes `autoResize: false` to opt out. The responsive system uses breakpoints to adjust layout strategy (label density, legend position, annotation placement). ### Update flow @@ -224,17 +232,32 @@ sequenceDiagram Vanilla->>DOM: Restore valid focus and wire interactions ``` +## Annotation editing and figure ownership + +The engine owns resolved annotation geometry and frozen edit contexts. Vanilla +previews gestures from that geometry and emits one `EditTransaction` through +`onEdit` at commit. Core's `applyEditTransaction` validates all operations before +returning a new spec and inverse; cancelled gestures emit nothing. Internal +gesture payloads are not public editing APIs. Framework wrappers forward the +same transaction contract. + +Omitted `chromeLayout` grows only the note band. `subtract` preserves exact outer +height; `grow` keeps the full plot budget and adds all chrome. Layers and facets +report `chrome.grownHeight` once, and mounts consume final `dimensions.height` +without double counting. Notes preserve source identity across thinning and +facet instances. Their linked marker emphasis is transient renderer state. + ## Theme resolution -Themes flow through three stages: +Themes flow through authored composition, default resolution, and mode adaptation: -1. **User config** (`ThemeConfig`): Partial overrides. Only specify what you want to change. -2. **Deep merge** (`resolveTheme()`): Merge user config onto `DEFAULT_THEME`. Produces a `ResolvedTheme` with every field set. +1. **Authored composition** (`ThemeConfig`, `mergeThemeConfig`): Deep-merge partial spec/provider/host overrides. Arrays and TokenValues are atomic; null replaces. In a layer, the root scope (chrome, axes, legend) uses the layer theme, falling back to the first leaf's theme when the layer has none; each leaf's marks use the leaf theme merged over the layer theme. Host options apply on top of both. +2. **Default resolution** (`resolveTheme()`): Fill omitted fields from `DEFAULT_THEME`. Produces `ResolvedTheme`, with authored metadata retained for token stamping. Authored chrome font sizes win over general size propagation; partial rules inherit and null clears them. 3. **Dark mode adaptation** (`adaptTheme()`): If dark mode is active, transform the resolved theme. Swap background/text, adjust palette brightness, lighten gridlines. -The default theme uses Inter as the primary font and a categorical palette tuned for distinguishability. Theme tokens remain the source of truth for typography; the opt-in `clarity` preset provides the newer editorial hierarchy without changing v8 defaults. +The default theme uses Inter, 12px small/tick text, 16px/12px chrome gaps, and a categorical palette tuned for distinguishability. Background remains transparent. `clarity` is deprecated and retains only its remaining colors; `legacyEditorial` provides v8 typography. The public `Theme` alias and empty `editorial` preset are removed. -Themes can be applied per-component (via prop) or globally (via `VizThemeProvider` in React, or the `theme` option in vanilla). +Themes can be applied per component or through `VizThemeProvider` in React/Vue/Svelte. Provider and component props deep-merge; vanilla mount options take highest precedence. A shared renderer helper stamps only authored token overrides and restores previous host inline values when overrides disappear. Unauthored values remain CSS defaults; exports capture live token values. ## Accessibility @@ -243,6 +266,6 @@ The engine generates accessibility metadata as part of compilation: - **Alt text**: Auto-generated description of the chart (type, data summary, encoding). - **Data table fallback**: A screen-reader-only HTML table with the chart's data. - **ARIA labels**: Role, roledescription, and label attributes for the SVG container. -- **Keyboard navigation**: Arrow keys navigate between marks. Enter/Space shows tooltip. Escape hides it. +- **Keyboard navigation**: Arrow keys navigate between marks. Enter/Space shows tooltip. Escape hides it. In edit mode (`interaction: 'edit'`) arrows nudge the selected annotation instead. The vanilla adapter creates a visually-hidden data table alongside the SVG, and wires keyboard event handlers on the container. React components inherit this through the vanilla adapter. diff --git a/docs/chart-types.md b/docs/chart-types.md index a77d0d16..0cd358a0 100644 --- a/docs/chart-types.md +++ b/docs/chart-types.md @@ -195,13 +195,13 @@ const spec = { { os: "Other", share: 1 }, ], encoding: { - y: { field: "share", type: "quantitative" }, + theta: { field: "share", type: "quantitative" }, color: { field: "os", type: "nominal" }, }, }; ``` -The `y` channel maps to slice values, `color` maps to slice categories. No `x` encoding is needed. +The `theta` channel maps to slice values, `color` maps to slice categories. No `x` encoding is needed. **Live examples**: [Basic pie](https://tryopendata.github.io/openchart/?story=charts--pie-and-donut#pie-inline-labels) | [Small slice grouping](https://tryopendata.github.io/openchart/?story=charts--pie-and-donut#small-slice-grouping) | [Seven categories](https://tryopendata.github.io/openchart/?story=charts--pie-and-donut#many-categories) @@ -222,7 +222,7 @@ const spec = { { category: "All Other", spending: 29 }, ], encoding: { - y: { field: "spending", type: "quantitative" }, + theta: { field: "spending", type: "quantitative" }, color: { field: "category", type: "nominal" }, }, }; @@ -347,7 +347,7 @@ const spec = { ``` -Options: `nodeWidth`, `nodePadding`, `nodeAlign` (`'justify'` | `'left'` | `'right'` | `'center'`), `linkStyle` (`'gradient'` | `'source'` | `'target'` | `'neutral'`), `encoding.value.format` for number formatting (top-level `valueFormat` is deprecated in v8). +Options: `nodeWidth`, `nodePadding`, `nodeAlign` (`'justify'` | `'left'` | `'right'` | `'center'`), `linkStyle` (`'gradient'` | `'source'` | `'target'` | `'neutral'`), `encoding.value.format` for number formatting (top-level `valueFormat` is removed in v9). For the full field reference, see [SankeySpec in spec-reference.md](spec-reference.md#sankeyspec). @@ -566,7 +566,7 @@ const spec = { }; ``` -`theta` is the quantitative share value (the same part-to-whole channel arc marks use; it is an alias for `y`, so provide one of the two). `color` is the required category. Values normalize to the grid via largest-remainder rounding, so the cells always sum exactly even when the shares are fractional. +`theta` is the quantitative share value (the same part-to-whole channel arc marks use; the old authored `y` alias is removed). `color` is the required category. Values normalize to the grid via largest-remainder rounding, so the cells always sum exactly even when the shares are fractional. **Mark options:** - `units` (default 100) -- total number of cells in the grid @@ -632,7 +632,7 @@ const spec = { }; ``` -`theta` is the quantitative seat count (an alias for `y`; provide one of the two) and `color` is the required party. Order the data left to right by political group; the layout preserves that order across the arc. Party colors typically come from an explicit `color.scale.range` rather than the default palette. +`theta` is the quantitative seat count (the old authored `y` alias is removed) and `color` is the required party. Order the data left to right by political group; the layout preserves that order across the arc. Party colors typically come from an explicit `color.scale.range` rather than the default palette. **Mark options:** - `shape` (`'hemicycle'`, the default and only shape) diff --git a/docs/codebase-map.md b/docs/codebase-map.md index 2f636aef..299a515d 100644 --- a/docs/codebase-map.md +++ b/docs/codebase-map.md @@ -10,17 +10,22 @@ | Looking for... | File | |---|---| +| Measured bar value modes and common facet value columns | `packages/engine/src/charts/bar/label-plan.ts`; frame ownership in `layout/frame.ts`, validation in `compiler/validation/label-placement.ts`. | +| Endpoint observation provenance, shared precision and interior area labels | `packages/engine/src/endpoint-labels/{observations,source,precision,formatter,interior}.ts`; `predict.ts` and `compute.ts` share formatting and host measurement. | +| Measured horizontal axis title headers and authored angle footprint | `packages/engine/src/layout/axis-title-plan.ts`; reserved by frame/plan, positioned by `layout/axes.ts`. | +| Map composition and accessible legend scale intervals | `packages/engine/src/geo/layout.ts` (pure measured gutters/fallback), `geo/legend-semantics.ts` (scale-faithful descriptions and metadata captions); consumed by `compile-geo-map.ts`. Static legend `textRows` are measured before fitting and painted by `vanilla/src/renderers/legend.ts`; size-key scoring uses complete measured bounds and projected obstacles. | +| Endpoint and map theme roles | `packages/core/src/theme/{defaults,resolve,dark-mode}.ts`, `styles/token-definitions.ts`; authored overrides stamped by `packages/vanilla/src/theme-tokens.ts`. Zero-gridline colors flow through both SVG axes and scatter canvas. | | Top-level chart spec types (`ChartSpec`, `Encoding`, `Mark`, `Annotation`, `Chrome`) | `packages/core/src/types/spec.ts` (~1670 lines) | | Resolved layout types (`ChartLayout`, `ResolvedChrome`, `AxisLayout`, `ResolvedLabel`) | `packages/core/src/types/layout.ts` (~1290 lines) | -| Theme types (`Theme`, `ResolvedTheme`, `ThemeColors`, `ThemeFonts`, `ThemeChromeDefaults`) | `packages/core/src/types/theme.ts` | +| Theme types (`ThemeConfig` input, `ResolvedTheme` output, `ThemeColors`, `ThemeFonts`, `ThemeChromeDefaults`) | `packages/core/src/types/theme.ts` | | `DEFAULT_THEME` literal | `packages/core/src/theme/defaults.ts` | -| Theme deep-merge | `packages/core/src/theme/resolve.ts` → `resolveTheme()` | +| Theme deep-merge | `packages/core/src/theme/merge.ts` → public `mergeThemeConfig()` for authored layers; `resolve.ts` → `resolveTheme()` for defaults and resolved metadata. Arrays and TokenValues replace atomically. | | Dark-mode adapter (binary-search lightness) | `packages/core/src/theme/dark-mode.ts` → `adaptTheme()`, `adaptColorForDarkMode()` | -| Theme presets (`editorial`, `essay`, `wire`, `broadsheet`, `terminal`) | `packages/core/src/theme/presets.ts`. `broadsheet` is the only one that sets `rule`; `terminal` resolves `isDark: true` in light mode off its own dark background. | -| Editorial rule (masthead bar above the chrome block) | `ThemeConfig.rule` (`types/spec.ts`) → `Theme.rule` (`types/theme.ts`, `ThemeRule`) → reserved by `computeChrome` (`layout/chrome.ts`, `ResolvedChrome.rule`) → drawn by `renderChrome` as `` (`vanilla/src/renderers/chrome.ts`). `rule.color` is registered in `collectTokenPairs` so dark mode needs no literal branch. | +| Theme presets (`essay`, `wire`, `broadsheet`, `terminal`; deprecated colors-only `clarity` and compatibility `legacyEditorial`) | `packages/core/src/theme/presets.ts`. `broadsheet` is the only one that sets `rule`; `terminal` resolves `isDark: true` in light mode off its own dark background. | +| Editorial rule (masthead bar above the chrome block) | `ThemeConfig.rule` (`types/spec.ts`) → `ResolvedTheme.rule` (`types/theme.ts`, `ThemeRule`) → reserved by `computeChrome` (`layout/chrome.ts`, `ResolvedChrome.rule`) → drawn by `renderChrome` as `` (`vanilla/src/renderers/chrome.ts`). `rule.color` is registered in `collectTokenPairs` so dark mode needs no literal branch. | | Categorical palettes (stroke/fill x light/dark, plus `CATEGORICAL_EXTENDED_PALETTE`) and sequential/diverging | `packages/core/src/colors/palettes.ts` | | `ThemeColors.categoricalFill` (quieter fill variant for bar/area/arc/waffle/calendar/rect; copied from `categorical` when unset) and `hairline` (structural line, distinct from `gridline`) | `types/theme.ts`, `theme/defaults.ts`, `theme/resolve.ts` (`themeConfigToPartial`); picked per mark type by `packages/engine/src/compile/color-scale-range.ts` (`FILL_MARKS` set, `categoricalColorsForDomain`) | -| Derived neutral gray ramp (`deriveNeutralRamp`, on `ResolvedTheme.colors.neutral`) | `packages/core/src/colors/neutral.ts`. Also carries `neutral.surface`: the one answer to "what opaque color does this theme paint on" (the background when it is opaque, else the mode's `--oc-bg` token). Knockout rings (`engine/charts/utils.ts` → `resolveKnockoutColor`), table fills (`engine/tables/utils.ts` → `resolveTableSurface`), graph rings (`engine/graphs/encoding.ts` → `resolveGraphSurface`), tilemap label blending and `vanilla/theme-tokens.ts` → `resolvedSurface` all read it — no `--oc-bg` resolution outside core. | +| Derived neutral gray ramp (`deriveNeutralRamp`, on `ResolvedTheme.colors.neutral`) | `packages/core/src/colors/neutral.ts`. Also carries `neutral.surface`: the one answer to "what opaque color does this theme paint on" (the background when it is opaque, else the mode's `--oc-bg` token). Knockout rings (`engine/charts/utils.ts` → `resolveKnockoutColor`), table fills (`engine/tables/utils.ts` → `resolveTableSurface`), graph rings (`engine/graphs/encoding.ts` → `resolveGraphSurface`), default annotation marker/plate fills, tilemap label blending and `vanilla/theme-tokens.ts` → `resolvedSurface` all read it — no `--oc-bg` resolution outside core. | | Palette a11y guard (contrast, hue adjacency, CVD) | `packages/core/src/colors/__tests__/palette-a11y.test.ts` | | Color contrast / accessibility helpers | `packages/core/src/colors/contrast.ts`, `colorblind.ts` | | CSS token source of truth | `packages/core/src/styles/token-definitions.ts` | @@ -37,48 +42,54 @@ | Text wrapping | `packages/core/src/layout/text-wrap.ts` (`wrapText`) | | Chrome layout computation (title/subtitle/source/byline/footer geometry) | `packages/core/src/layout/chrome.ts` → `computeChrome()` | | Spec normalization (defaults, shorthand expansion) | `packages/engine/src/compiler/normalize.ts` → `normalizeSpec()` | -| Data transforms (filter, bin, calculate, timeUnit, aggregate, joinaggregate, fold, window, density) | `packages/engine/src/transforms/` — one file per transform plus `index.ts` → `runTransforms(data, transforms)`, called once from `compile.ts` against the post-sugar spec, before scales. A histogram is `bin` + `aggregate: count`; there is no separate binning implementation. | +| Data transforms (filter, bin, calculate, timeUnit, aggregate, joinaggregate, fold, window, density) | `packages/engine/src/transforms/` — one file per transform plus `index.ts` → `runTransforms(data, transforms)`, called once from `compile/prepare.ts` (`prepareChartSpec`) against the post-sugar spec, before scales. A histogram is `bin` + `aggregate: count`; there is no separate binning implementation. | | Spec sugar (pre-validation rewrites: `theta`→`y`, `x.bin`→`BinTransform`, `mark: 'histogram'`/`'density'`→ canonical form) | `packages/engine/src/compile/spec-sugar.ts` → `expandSpecSugar()`. Runs before validation, so sugar mark types never reach the validator or the renderer dispatch. | | Binned bar (histogram) renderer | `packages/engine/src/charts/binned-bar/compute.ts`. Dispatched as `'bar:binned'` when x is quantitative, `x2` is present, AND y is quantitative — a nominal-y bar with `x2` is a floating range bar and keeps the band path. `isBinnedBarEncoding` (`charts/post-process.ts`) is the one predicate; the layout gutter and the x zero default read it too. Color groups overlap at `OVERLAP_FILL_OPACITY` (0.55) unless `stack` is set — the inverse of the band-scale bar default, because a binned axis exists to compare shapes. | -| Spec validation | `packages/engine/src/compiler/validate.ts` → `validateSpec()` | +| Spec validation | `packages/engine/src/compiler/validate.ts` → `validateSpec()` (dispatch, shape checks, annotation layout). Per-kind rules live in `compiler/validation/`: `chart.ts`, `table.ts`, `graph.ts`, `sankey.ts`, `tilemap.ts`, `geo-map.ts`, `barlist.ts`, `layer.ts`, plus `mark-rules.ts`, `common-fields.ts` and `helpers.ts` (shared field/did-you-mean helpers). | | Top-level compile entry | `packages/engine/src/compiler/index.ts` → `compile()` | -| Chart compile orchestration | `packages/engine/src/compile.ts` → `compileChart()`, `compileFaceted()` | +| Chart compile orchestration | `packages/engine/src/compile.ts` holds the public entry points (`compileChart`, `compileLayer`, `compileTable`, graph/sankey/tilemap/geomap/barlist wrappers). The chart path is `compile/chart.ts` → `compileChartInternal()` (prepare → theme → height context → sizing → facet or single-chart) and `layoutSingleChart()` (scales, axes, marks, legend, annotations, a11y, final layout). Facets: `compile/faceted.ts` → `compileFaceted()`. | +| Chart compile phases | `packages/engine/src/compile/`: `prepare.ts` (`prepareChartSpec`: sugar, validate+normalize, transforms, breakpoint override, display defaults; `applySpecSize`), `breakpoint-overrides.ts` (`collectUserExplicit`, `applyBreakpointOverride`), `display-defaults.ts` (sparkline defaults, `resolveChartAnimation`, `resolveCrosshair`, `watermarkResolver`), `height-context.ts` (`heightContextResolver`), `render-spec.ts` (`buildRenderSpec`, `desugarRowColumn`), `chart-scales.ts` (`computeChartScales`, shared by single and facet paths), `annotation-obstacles.ts`, `accessibility.ts` (`buildChartA11y`), `scale-invert.ts`, `series-summary.ts`. | | Chart-type registry | `packages/engine/src/charts/registry.ts` | | Chart-type implementations | `packages/engine/src/charts/{bar,column,line,pie,scatter,dot,range,calendar,rule,tick,text}/` (registered via `charts/builtin.ts`) | | Layout: axes (tick generation, density, label fitting) | `packages/engine/src/layout/axes.ts` (`computeAxes`) | +| Default y-tick density (densify sparse d3 results to at least 3 ticks, kept 20px apart) | `packages/engine/src/layout/axes/ticks.ts` (`buildDefaultYTicks`, `MIN_Y_TICK_SPACING`); called from `layout/plan.ts`, which sizes y ticks against the plot the shared figure frame (`layout/frame.ts`) places for the final layout. Not used for authored `tickCount`. | | Inline vs gutter y-tick placement (shared predicate) | `packages/engine/src/layout/axes.ts` (`yTickPositionIsInline`) — single source of truth for `computeAxes`, `plan.ts`, and `dimensions.ts`; keyed on resolved scale type, not field type | -| Band x-label rotation + thinning policy | `packages/engine/src/layout/axes/rotation.ts` (`resolveBandTickAngle`, `bandLabelStride`) — parallel-ribbon collision model, angle ladder flat → -45° → -90°, last-anchored stride safety net; shared by `computeAxes` and `plan.ts` so reserved margin matches rendered angle | +| Band x-label rotation + thinning policy | `packages/engine/src/layout/axes/rotation.ts` (`resolveBandTickAngle`, `bandLabelStride`) — parallel-ribbon collision model, angle ladder flat → -45° → -90°, last-anchored stride safety net; shared by `computeAxes` and `plan.ts` so reserved margin matches rendered angle. Only band x-axes rotate; `categoricalAxisIsBand` (`layout/scales.ts`) is the band-vs-point rule both the scale builder and the plan read | | Outer x tick label edge clamping (label nudged inward off the container edge) | `packages/engine/src/layout/axes.ts` (`clampXTickLabels`) — point/band x-scales run flush to the plot edges, so the outermost centered label would spill past the SVG. Emits `AxisTick.labelPosition` (drawn x); `position` stays on the data. Renderer: `packages/vanilla/src/renderers/axes.ts`; transitions: `transition/chrome-tweens.ts` | -| Layout: dimensions (chrome reservation, chartArea computation) | `packages/engine/src/layout/dimensions.ts` (`computeDimensions`) | -| Layout: facet grid geometry (panel rects, responsive column degradation) | `packages/engine/src/layout/facet.ts` (`computeFacetGrid`, `autoColumns`) | +| Layout: figure frame (the one owner of plot sizing: margins, header bands, reference lane, metrics rollback, chartArea) | `packages/engine/src/layout/frame.ts` (`createFrame`, `frameMargins`, `frameSpacing`, `frameReference`, `BudgetReserves`). Both the layout plan (`layout/plan.ts`, `plan.plotArea`) and the figure budget build it, so they place the same plot; `__tests__/figure-frame.test.ts` pins `plan.plotArea === budget.chartArea` and planned vs drawn x extent. Pass the same `BudgetReserves` to `resolveLayoutPlan` and `computeDimensions`. | +| Layout: figure budget (authored reserves, chrome reservation, fallback ladder) | `packages/engine/src/layout/budget.ts` (`measureAuthoredReserves`, `resolveFigureBudget`, `outsideBudget`, `resolveNoteOverflow`); `layout/dimensions.ts` (`computeDimensions`) is a thin wrapper. Vertical stack primitives used by the frame (`stackTop`, `stackHeight`, `headerBands`, top reference lane share cap `fitReferenceLane`, `referenceLaneFor`) live in `layout/stack.ts`. Engine-internal compile options (`frozenBudget`, `leafContext`, `rightAxisReserve`, `layered`) live in `engine/src/compile/internal-options.ts` | +| Layout: facet grid geometry (panel rects, responsive column degradation, per-row top reference lane cap) | `packages/engine/src/layout/facet.ts` (`computeFacetGrid`, `autoColumns`). The lane is fit with `fitReferenceLane` per grid row, measured at the height a short grid grows to; each panel's admitted reserve is `FacetGridPanel.referenceReserve`. Right-lane chrome inset: `chromeInsetReference` in `layout/stack.ts` | | Layout: gridlines | `packages/engine/src/layout/gridlines.ts` | -| Layout: scales (d3-scale construction) | `packages/engine/src/layout/scales.ts` | +| Layout: scales (d3-scale construction) | `packages/engine/src/layout/scales.ts`; `data/area-stack.ts` shares area pivot/offset semantics with the renderer so signed cumulative extents use the same boundaries. `buildRenderSpec` creates a fresh internal stack cache per compilation, shared by scale measurement and marks without surviving an update. `data/sort-by-field.ts` supplies the shared stable x ordering. | | Annotations: top-level compile | `packages/engine/src/annotations/compute.ts` → `computeAnnotations()` | | Annotations: text resolution (anchor → offset → connector) | `packages/engine/src/annotations/resolve-text.ts` | | Annotations: refline / range | `packages/engine/src/annotations/resolve-refline.ts`, `resolve-range.ts` | -| Annotations: geometry (text bounds, anchor offsets, ray-box connector exit, connector rebuild, arrowhead points) | `packages/engine/src/annotations/geometry.ts` (`connectorExit`, `refreshConnector`, `automaticControlPoint`, `computeArrowheadPoints`). No `computeConnectorOrigin` — that's the pre-v8 name. | +| Annotations: geometry (text bounds, anchor offsets, ray-box connector exit, connector rebuild, arrowhead points) | `packages/engine/src/annotations/geometry.ts` (`connectorExit`, `refreshConnector`, `automaticControlPoint`, `computeArrowheadPoints`, `pullBackConnector` — curves are shaped to the data point, then shortened along their end tangent; `stopAtTargetLabel` — a leader stops short of its target's own value label, kept on `connector.targetLabel` so rebuilds re-stop). No `computeConnectorOrigin` — that's the pre-v8 name. | | Annotations: `**bold**` span parsing | `packages/engine/src/annotations/rich-text.ts` → `parseAnnotationSpans()`, `RichSpan`, `BOLD_SPAN_FONT_WEIGHT` | | Annotations: block repositioning (label + subtitle + bounds + connector move as one; auto-placement's `textAnchor` stamp) | `packages/engine/src/annotations/move.ts` → `moveAnnotationTo()`, `moveAnnotationBy()`, `annotationBlockBounds()` | | Annotations: collision resolution | `packages/engine/src/annotations/collisions.ts` | -| Annotations: chrome guard (labels can't climb into the title block) | `packages/engine/src/annotations/collisions.ts` → `clampAnnotationsToBounds(annotations, svgWidth, svgHeight, measure, topBound)`. `topBound` is the first y a label may occupy; `compile.ts` passes `dims.topPad + dims.chrome.topHeight` (`LayoutDimensions.topPad` in `engine/layout/dimensions.ts`) when there is a chrome block, and the same band is fed to auto-placement as a `'chrome'` `ObstacleKind` (`annotations/placement.ts`). | +| Annotations: chrome guard (labels can't climb into the title block) | `packages/engine/src/annotations/collisions.ts` → `clampAnnotationsToBounds(annotations, svgWidth, svgHeight, measure, topBound)`. `topBound` is the first y a label may occupy; `compile/chart.ts` passes `dims.topPad + dims.chrome.topHeight` (`LayoutDimensions.topPad` in `engine/layout/dimensions.ts`) when there is a chrome block, and the same band is fed to auto-placement as a `'chrome'` `ObstacleKind` (`annotations/placement.ts`). | | Annotations: auto-thinning (demote callouts → numbered footnotes) | `packages/engine/src/annotations/thinning.ts` → `thinAnnotations()`. Three independent demotion rules: pairwise overlap (padded by `COLLISION_PADDING`), containment (`fitsWithin`, checked against `containerBounds ?? plotArea` — callouts legitimately live in the margin, so only labels escaping the *chart* demote), and a `COVERAGE_BUDGET` cap on the share of *plot* area inline labels may claim. The budget is what thins narrow charts — collision resolution spreads labels apart and clamping tucks them back in, so crowded layouts never trip the first two rules. Pinned (`responsive: false`) labels are exempt from the budget. | -| Annotations: wrapped note lines and reserve counts | `packages/engine/src/annotations/notes.ts` → `wrapAnnotationNotes()`, `annotationNoteLineCount()`, `annotationNoteCapacity()` (internal; source capacity including pinned text/subtitles and widest numeric prefix). `AnnotationFootnote.lines` carries engine-wrapped display lines to rendering/export; optional `ResolvedChrome.noteBandHeight` carries the stable source-capacity reserve to footer/brand/export and layered alignment. | +| Annotations: wrapped note lines and reserve counts | `packages/engine/src/annotations/notes.ts` → `wrapAnnotationNotes()`, `annotationNoteLineCount()`, `annotationNoteCapacity()` (internal; source capacity including pinned text/subtitles and widest numeric prefix). `AnnotationFootnote.lines` and `.spans` carry engine-wrapped, source-numbered rich display lines to rendering/export; optional `ResolvedChrome.noteBandHeight` carries the stable source-capacity reserve to footer/brand/export and layered alignment. | | Annotations: frozen editing geometry | `packages/engine/src/annotations/edit-context.ts` → public `createAnnotationEditContext()`, `previewAnnotationMove()`, `previewConnectorBend()`, `inverseLabelPlacement()`. Uses compiled annotation metadata (scales and measurement stay inside engine); snapshots preserve source/facet identity and clamp bounds. | | Annotations: data → pixel resolver | `packages/engine/src/annotations/position.ts` | -| Annotations: shared constants (`ANCHOR_OFFSET=28`, `CONNECTOR_STANDOFF=6`, `MIN_CONNECTOR_LENGTH=8`, dot defaults, `LEDE_FONT_WEIGHT`, connector strokes, default font) | `packages/engine/src/annotations/constants.ts` | +| Annotations: shared constants (`ANCHOR_OFFSET=28`, `CONNECTOR_STANDOFF=6`, `MIN_CONNECTOR_LENGTH=8`, dot defaults, subtitle sizing, connector strokes, default font) | `packages/engine/src/annotations/constants.ts` | | Legend layout (entries, wrapping, positioning, `entryPositions`) | `packages/engine/src/legend/compute.ts`, `wrap.ts`; internal `measureCategoricalLegendContent()` reuses the same measurement for merged layer entries. | | Size legend (graduated circles + title row) | `packages/engine/src/legend/size.ts` (`computeSizeLegendContent`, `placeSizeLegend`, `sizeLegendTitleStyle`). The title comes from `size.title ?? size.field`; the map's own copy is built inline in `geo/compile-geo-map.ts` (`pointSizeLegend`). Rendered by `renderSizeLegend` in `packages/vanilla/src/renderers/legend.ts`. | | Knockout ring / seam color (scatter, line points, dot, beeswarm, pie seams, stacked seams, map bubbles) | `packages/engine/src/charts/utils.ts` → `resolveKnockoutColor(theme)`. Resolved theme background when opaque, else the mode surface. `stackSeamStroke()` delegates to it. Never hardcode `'#ffffff'` — the `terminal` preset is dark in both modes. | | Top-legend / inline-tick clearance (top legend lifted above the reserved inline y-tick overhang) | `packages/engine/src/legend/compute.ts` → `placeLegend(..., axisGapBelowLegend)`, threaded from `computeDimensions`' `effectiveAxisGap` | | Legend / endpoint-label suppression truth table (per-series UI hides when series hidden) | `packages/engine/src/legend/suppression.ts` | -| Endpoint labels: compute (placement, leader lines, anti-overlap sweep) | `packages/engine/src/endpoint-labels/compute.ts` | +| Endpoint labels: compute (placement, leader lines, anti-overlap sweep) | `packages/engine/src/endpoint-labels/compute.ts`. Markers sit centered on the end point with a `resolveKnockoutColor` fill; a default annotation dot on a marker adopts its colors (`annotations/compute.ts` → `adoptPointMarker`). | | Endpoint labels: number formatting (currency / unit / compact) | `packages/engine/src/endpoint-labels/format.ts` | | Compact temporal tick formats (`GRANULARITY_FORMATS_COMPACT`, `formatDate(..., compact)`) | `packages/core/src/locale/format.ts`; the fitting rung that tries compact-at-same-count before thinning lives in `fitContinuousTicks` (`packages/engine/src/layout/axes.ts`). X-axes only — `resolveExplicitTicks` (planner y path) deliberately never compacts; explicit user `axis.format` always wins. | | Default number formatting (compact notation, years guard, percent/currency keywords) | Core primitives: `packages/core/src/locale/format.ts` (`defaultNumberFormatter`, `resolveNumberFormatter`, `formatPercent`, `formatCurrency`, `buildCompactStepFormatter`, `FieldFormatContext`). Engine resolver: `packages/engine/src/format/field-format.ts` (`resolveFieldFormatter`). Charts get compact (1k, 2.5M); tables get full precision. | | Endpoint labels: text-width prediction for layout reservation | `packages/engine/src/endpoint-labels/predict.ts` | | Endpoint labels: shared constants (chip padding, swatch geometry, leader gaps) | `packages/engine/src/endpoint-labels/constants.ts` | -| Vanilla mount + lifecycle | `packages/vanilla/src/mount.ts` (~2500 lines) | -| Auto-height growth contract (400px is the viz budget; chrome/legend/metrics overheads grow the figure) | `packages/vanilla/src/mount.ts` → `getContainerDimensions()` + the bounded convergence loop in `compile()` | +| Vanilla mount + lifecycle | `packages/vanilla/src/mount.ts` → `createChart()` (render cycle, update/transition, resize, destroy; per-render wiring is torn down through one LIFO `renderDisposers` list). Public types (`MountOptions`, `ChartInstance`, `UpdateOptions`, `ExportOptions`, `resolveInteractionMode`) live in `mount-types.ts` and are re-exported from `mount.ts`. | +| Chart select/edit interaction | `packages/vanilla/src/chart-editing.ts` → `createEditSession()`: selection + overlay, inline text editing, keyboard nudges/Tab/Delete, dblclick-to-add, gesture → edit transaction (`emit`). `attach(svg)`/`detach()` per render. | +| Legend toggle state | `packages/vanilla/src/series-visibility.ts` → `createSeriesVisibility()` (runtime hide/show over authored `hiddenSeries`; refuses to hide the last visible series) | +| `chart.export()` | `packages/vanilla/src/chart-export.ts` → `createChartExporter()` | +| Auto-height growth contract (400px is the viz budget; chrome/legend/metrics overheads grow the figure) | `packages/vanilla/src/chart-sizing.ts` → `createChartSizer()`: `dimensions()` (auto-height latch), `compile()` (bounded 3-pass convergence), `verticalOverheads()`, and `shouldResize()` (self-induced-resize guard) | | Vanilla SVG renderer entry | `packages/vanilla/src/svg-renderer.ts` → `renderChartSVG()`, `renderFacetedPanels()` | | Static SVG renderer (SSR) | `packages/vanilla/src/static.ts` → `renderStaticSVG()`. Subpath: `@opendata-ai/openchart-vanilla/static`. Requires `happy-dom` peer dep. | | Renderer: chrome (title/subtitle/source/byline/footer) | `packages/vanilla/src/renderers/chrome.ts` → `renderChrome()` | @@ -99,10 +110,11 @@ | Zoom viewport clipping for live maps and exports | `packages/vanilla/src/map-camera.ts` → `ensureMapClip`; reused by `map-zoom.ts` and terminal map export. | | Animation lifecycle / cleanup | `packages/vanilla/src/animation.ts`. `computeAnimationDuration(svg)` is the shared total-entrance-time calc (used by cleanup timing and GIF capture). | | Data-update transition driver (rAF-based mark/axis tweening) | `packages/vanilla/src/transition/` (driver.ts, gate.ts, svg-tweens.ts, canvas-tweens.ts, chrome-tweens.ts, ...; `transition.ts` is the re-export barrel) | -| Export (SVG/PNG/JPG/CSV) | `packages/vanilla/src/export.ts` → `exportSVG`, `exportPNG`, `exportJPG`, `exportCSV`, plus `rasterizeSVGToCanvas`/`getSVGDimensions`/`embedFonts` helpers reused by GIF export. Wired into `chart.export(format)` in `mount.ts`. | -| Animated GIF export | `packages/vanilla/src/export-gif.ts` → `exportGIF()`. Deterministic entrance re-creation (not CSS scrubbing — computed-style animation doesn't serialize), encoded via the optional `gifenc` peer dep. Subpath: `@opendata-ai/openchart-vanilla/gif`; dynamic-imported by the `'gif'` case in `mount.ts` so `gifenc` stays out of the core bundle. | +| Export (SVG/PNG/JPG/CSV) | `packages/vanilla/src/export.ts` → `exportSVG`, `exportPNG`, `exportJPG`, `exportCSV`, plus `rasterizeSVGToCanvas`/`getSVGDimensions`/`embedFonts` helpers reused by GIF export. Wired into `chart.export(format)` in `chart-export.ts`. | +| Animated GIF export | `packages/vanilla/src/export-gif.ts` → `exportGIF()`. Deterministic entrance re-creation (not CSS scrubbing — computed-style animation doesn't serialize), encoded via the optional `gifenc` peer dep. Subpath: `@opendata-ai/openchart-vanilla/gif`; dynamic-imported by the `'gif'` case in `chart-export.ts` so `gifenc` stays out of the core bundle. | | Mark key serialization / dedup | `packages/engine/src/compiler/keys.ts` | | Tooltip rendering | `packages/vanilla/src/tooltip.ts`. Rows carry `emphasis` (nearest series in a shared tooltip) and `role: 'total'` (stack sum) from `TooltipField`; CSS `packages/core/src/styles/tooltip.css`. | +| Opt-in horizontal bar row inspection | `packages/vanilla/src/interactions/row-hover.ts` → `wireRowHover`; `MountOptions.rowHover` and all Chart wrappers. Passive background/outline, shared keyboard row identity; no handlers or paint when omitted. | | Hover emphasis (dim-the-rest / outline, legend + endpoint hover-link) | `packages/vanilla/src/interactions/hover-emphasis.ts` (`createHoverEmphasis`, `wireEndpointLabelHover`); CSS `packages/core/src/styles/interaction.css`. Two registers keyed on distinct `seriesKey` count: multi-series dims to `--oc-hover-dim`, single-series outlines the hovered mark. Everything is a class so it beats `opacity` attributes and loses to the transition driver's inline `style.opacity`; the driver sets `.oc-transitioning` on the SVG for its lifetime to switch the fade off. | | Legend click-toggle + hover-link wiring (real `role="button"` entries, `aria-pressed`, 24px hit rect) | `packages/vanilla/src/interactions/legend-interaction.ts` → `wireLegendInteraction`. | | Keyboard nav for line/area charts (arrow keys drive the crosshair when no per-mark tooltip descriptors exist) | `packages/vanilla/src/interactions/keyboard-nav.ts` → `wireKeyboardNav`; gates on `layout.tooltipDescriptors.size === 0`, driving the `CrosshairController` from `interactions/crosshair.ts`. | @@ -121,22 +133,29 @@ | Demo index registry (Welcome's findability index; single source of truth) | `examples/src/gallery/registry.ts` assembles per-page `examples/src/gallery/.demos.ts` sidecars. Sidecars live outside `*.stories.*` on purpose: Ladle turns every named export in a story file into a story, so a shared `export const demos` collides (e.g. all five Charts pages → duplicate `charts--demos`) and fails `ladle build`. | | Legacy-slug redirect map (old published `?story=` deep links → new page+anchor; guarantees no 404s after the flip) | `examples/.ladle/redirects.ts`. Provider reads `?story=` on mount and redirects. | | Ladle config (defaultStory, storyOrder wildcards, width/theme addons) + head (favicon, OG/twitter meta, Bricolage-only font), shell CSS, 6 named house styles | `examples/.ladle/config.mjs`, `head.html`, `shell.css`, `themes.ts`. Social OG image: `examples/public/og-preview.png`. | -| Theming gallery page (five presets, six named house styles, custom ThemeConfig, dark adaptation) | `examples/src/gallery/features-theming.stories.tsx` (slug `features--theming`) | +| Theming gallery page (default and four presets, six named house styles, custom ThemeConfig, dark adaptation) | `examples/src/gallery/features-theming.stories.tsx` (slug `features--theming`) | | Visual regression spec | `e2e/visual/stories.spec.ts` | | Mobile visual regression spec (390px viewport, `visual-mobile` project) | `e2e/visual/stories-mobile.spec.ts` | | Visual regression baselines | `e2e/visual/__screenshots__/` | | Mobile layout invariants (6 geometry rules incl. Rule 6 label presence; 4 Playwright projects, the chromium ones run in CI) | `e2e/invariants/mobile-invariants.spec.ts` | | Rendered layout invariants (real Chromium `getBoundingClientRect`, catches engine-vs-renderer disagreements happy-dom can't) | `e2e/invariants/rendered-invariants.spec.ts` (reuses the visual-suite story slugs); table column widths: `e2e/invariants/table-column-width.spec.ts` (an explicit `200px` column renders at exactly 200px, no horizontal overflow). Others in `e2e/invariants/`: `canvas-alpha-parity`, `font-race`, `graph-surface`, `known-bugs`, `graph-3d` (live WebGL context on a `dimensions: 3` demo, the over-gate 2D fallback, and one context released per destroyed 3D mount; chromium-desktop only, no fps assertions). | -| Blog-theme mobile repro (bugs on labs.tryopendata.ai need `axisTick: 14`, not the 11px default; production mirror story) | `examples/src/charts/mobile-regression.stories.tsx` → `testing--mobile-regression--one-wide-x-label-large-ticks` (retitled `Testing / Mobile Regression`; file stays put, slugs are now `testing--mobile-regression--*`) | +| Blog-theme mobile repro (bugs on labs.tryopendata.ai need `axisTick: 14`, not the 12px default; production mirror story) | `examples/src/charts/mobile-regression.stories.tsx` → `testing--mobile-regression--one-wide-x-label-large-ticks` (retitled `Testing / Mobile Regression`; file stays put, slugs are now `testing--mobile-regression--*`) | | Frozen e2e fixture copies (pinned visual/invariant stories, pixel-identical, `Testing / Fixtures`) + frozen stylesheet | `examples/src/testing/fixtures-*.stories.tsx` (+ `testing.css`, the `.tfix-` frozen namespace). Slugs are `testing--fixtures--*`. Includes `rotated-with-source`, moved here from `examples/src/charts/`. Design-refresh fixtures live in `fixtures-refresh.stories.tsx` (flat columns, donut `centerLabel`, presets), `fixtures-tables.stories.tsx` (density, delta chips, heatmap dark, shared sparklines, cards), `fixtures-tilemaps.stories.tsx`, `fixtures-sankey.stories.tsx` (energy light/dark, `other` bucket), `fixtures-dashboards.stories.tsx` (KPI tiles, 140px tiny tile); `us-bubbles` and `world-diverging-quantize` are appended to `fixtures-maps.stories.tsx`. | | GeoMap spec types (`GeoMapSpec`, `GeoMapEncoding`, `GeoMapPointsLayer`, `GeoMapGeo`) | `packages/core/src/types/spec.ts` (search "GeoMapSpec") | | GeoMap layout types (`GeoMapLayout`, `GeoMapFeatureMark`, `GeoMapPointMark`, `GeoMapBorders`) | `packages/core/src/types/layout.ts` (search "GeoMapLayout") | | GeoMap compile (projection, data join, choropleth marks, point marks, legends, focus) | `packages/engine/src/geo/compile-geo-map.ts` → `compileGeoMap()`. Helpers: `buildBasemapMarks`, `buildQuantitativeMarks`, `buildCategoricalMarks`, `resolveFocus`. Unjoined features get `noData: true` + `pattern` on `GeoMapFeatureMark` — only under a color encoding (a basemap has nothing to be missing). Both legends carry a detached `noData` swatch keying that hatch, gated on `marks.some(m => m.noData)`. Rendering: `buildPatternDefs`/`resolvePatternFill` in `vanilla/src/map-renderer.ts` emit one shared `` def and resolve the swatch fill to its `url(#id)`; the swatch itself is drawn by the shared `renderNoDataSwatch` in `renderers/legend.ts` (the categorical branch passes a rounded chip + `dominant-baseline: central` so it matches its entries). The categorical map legend emits its own `entryPositions` via `wrapCategoricalEntries`, mirroring the renderer's wrap rule, so the "No data" key lands after the last entry (or on a row of its own) instead of off the frame. | +| Geographic label/callout authoring | `packages/core/src/types/spec.ts` → `GeoAnchor`, `GeoCallout`, optional GeoMap `text`/`textPriority` channels. Validation: `engine/src/compiler/validation/geo-map.ts`. | +| Portable geographic label geometry and inventory | `packages/core/src/types/geo-labels.ts`; optional `GeoMapLayout.labels` in `types/layout.ts`. | +| Geographic label candidate/notes preparation | `packages/engine/src/geo/labels.ts` → `prepareGeoLabels`, `compilePreparedGeoLabels`; fixed authored note reserve integrated before projection in `geo/compile-geo-map.ts`. | +| Projected polygon interiors and pure overlay placement | `packages/engine/src/geo/label-geometry.ts` (projection stream, component/hole associations, bounded interior anchors and vertex budget); `geo/overlay-layout.ts` → `resolveGeoOverlay` (stateless camera placement, notes and full visibility inventory). | +| Geographic label rendering and accessible disclosure | `packages/vanilla/src/map-labels.ts`, `map-label-inventory.ts`; camera settlement in `map-mount.ts`/`map-zoom.ts`; `labelInventory` option and `setLabelInventory` reconcile the host list without remounting. | +| GeoMap static SVG and ID scope | `packages/vanilla/src/static.ts`, `svg-ids.ts`; optional stable `StaticRenderOptions.idPrefix` isolates multiple static figures. | +| Geographic label documentation and browser invariants | `docs/geographic-labels.md`, `examples/src/gallery/geo-labels.stories.tsx`, `e2e/chart-map-design/geo-labels.spec.ts`; separate Chromium/WebKit projects. | | GeoMap data join (feature id matching) | `packages/engine/src/geo/join.ts` → `joinDataToFeatures()` | | GeoMap projections (albersUsa, mercator, equalEarth, identity) | `packages/engine/src/geo/projections.ts` → `createProjection()`. Default inference lives here too: `resolveDefaultProjection(topology)` (pre-projected bbox → identity + a dev-only `PROJECTION_INFERRED` warning, lon span > 200 → equalEarth, else albersUsa). `normalize.ts` leaves `geo.projection` undefined; `compileGeoMap` resolves it. | | Map/legend class scale (one scale shared by fills and swatches) | `packages/engine/src/legend/continuous.ts` → `buildClassScale()` / `classScaleForChannel()`. Default is quantize with `tickStep` round breaks; quantile/threshold only when authored; a diverging ramp over a zero-straddling domain forces an odd, zero-centered classing. | | Compact `Less ▢▢▢▢▢ More` class key (calendar) | `packages/engine/src/legend/continuous.ts` → `computeCompactClassLegendContent()`. Selected in `legend/compute.ts` for `markType === 'calendar'` when the spec sets no `legend.position`; placed bottom-right via `ContinuousLegendContent.align: 'right'` + `barOffsetX` + `labelBaselineOffset` (labels sit *on* the swatch row, not under it). | -| Chrome economy (what a small container may draw) | `packages/core/src/responsive/breakpoints.ts` → `resolveChromeEconomy(width, height)`, `getHeightClass(height)` (`HeightClass` `'minimal'` under `HEIGHT_MINIMAL_MAX` 100 → chrome hidden, `'cramped'` under `HEIGHT_CRAMPED_MAX` 200 → compact chrome), `HEIGHT_NO_GRID_MAX` 150, `COMPACT_MAX_X_TICKS` 3. In the cramped band the default title shrinks by `CRAMPED_TITLE_SCALE` (`core/src/layout/chrome.ts`, `computeChrome`'s `crampedTitle` param, set in `engine/layout/plan.ts`) and the metric bar / series-search bands are gated off (`engine/layout/dimensions.ts`, `isCrampedHeight`) — both would otherwise blow the min-chart-height guardrail and strip the title back out. Consumed once, in `compile.ts` (feeds `skipX`/`skipY` and `AxesDataContext.suppressGrid` / `.maxXTicks`). Explicit `axis` / `axis.grid` always wins. Facet panels are deliberately NOT run through it (the economy is a container-size rule, not a panel-size rule). | +| Chrome economy (what a small container may draw) | `packages/core/src/responsive/breakpoints.ts` → `resolveChromeEconomy(width, height)`, `getHeightClass(height)` (`HeightClass` `'minimal'` under `HEIGHT_MINIMAL_MAX` 100 → chrome hidden, `'cramped'` under `HEIGHT_CRAMPED_MAX` 200 → compact chrome), `HEIGHT_NO_GRID_MAX` 150, `COMPACT_MAX_X_TICKS` 3. In the cramped band the default title shrinks by `CRAMPED_TITLE_SCALE` (`core/src/layout/chrome.ts`, `computeChrome`'s `crampedTitle` param, set in `engine/layout/plan.ts`) and the metric bar / series-search bands are gated off (`engine/layout/stack.ts` → `headerBands`) — both would otherwise blow the min-chart-height guardrail and strip the title back out. Consumed once, in `compile/chart.ts` (feeds `skipX`/`skipY` and `AxesDataContext.suppressGrid` / `.maxXTicks`). Explicit `axis` / `axis.grid` always wins. Facet panels are deliberately NOT run through it (the economy is a container-size rule, not a panel-size rule). | | Sparkline data-arrival pulse | `packages/vanilla/src/transition/driver.ts` → `pulseSparklineTerminator()` in `finish()`; keyframe `oc-pulse` in `core/src/styles/keyframes.css`, rule + reduced-motion opt-out in `sparkline.css`. Only fires when the SVG carries `data-display="sparkline"`. | | Waffle "Other" bucketing (opt-in) | `mark.other: number | { threshold, label? }`. Implemented in `packages/engine/src/compiler/normalize.ts` → `applyWaffleOther()` — it rewrites the *rows*, not the marks, so the grid, the color scale and the legend cannot disagree. Emits a `WAFFLE_OTHER_BUCKET` warning. Same spelling/shape as `SankeySpec.other`. | | Calendar color-scale default | `packages/engine/src/compiler/normalize.ts` → `withCalendarColorScale()` defaults `encoding.color.scale.type` to `'quantize'` (5 classes via `DEFAULT_BIN_COUNT`). A recorded zero therefore lands on the lightest class and stays distinct from a missing day (`theme.colors.annotationFill`). | @@ -159,13 +178,13 @@ | Graph encoding resolve (nodeColor/edgeColor/nodeSize/nodeLabelPriority; category domain via `sort`, default `'ascending'`) | `packages/engine/src/graphs/encoding.ts`. Graph channels default `sort: 'ascending'` (VL-aligned, deterministic); `sort: null` restores insertion order; explicit `scale.domain` wins. `nodeLabelPriority` maps a quantitative field to 0-1 label visibility priority (falls back to degree-based when omitted). | | Graph animation resolve (DEFAULT-ON; the deliberate chart/graph divergence) | `packages/engine/src/graphs/animation.ts` → `resolveGraphAnimation()`. `undefined`/`true` → full defaults; `false` → no choreography (warmup still applies); per-phase `false` → that phase `null`. | | Graph interaction resolve (hover mode, cursor repulsion, springy drag, select/flyTo) | `packages/engine/src/graphs/interaction.ts` → `resolveGraphInteraction()`. | -| Graph mount (lifecycle, events, tooltips, legend, search, camera, highlight, update) | `packages/vanilla/src/graph-mount.ts` → `createGraph()`. Public API: `GraphInstance` (search/zoomToFit/zoomToNode/flyTo/centerAt/getCamera/selectNode/highlight/clearHighlight/getHighlight/setActiveCategories/getActiveCategories/getLegend/update/updateVisuals). `suppressEntrance` mount option skips the reveal on a theme/darkMode-only remount (instant fit, warmup still runs). Physics-feel gates: `SPRINGY_DRAG_MAX_NODES` (5000), `CURSOR_FORCE_MAX_NODES` (2000). | +| Graph mount (lifecycle, events, tooltips, legend, search, camera, highlight, update) | `packages/vanilla/src/graph-mount.ts` → `createGraph()`. Public API: `GraphInstance` (search/zoomToFit/zoomToNode/flyTo/centerAt/getCamera/selectNode/highlight/clearHighlight/getHighlight/setActiveCategories/getActiveCategories/getLegend/update). `suppressEntrance` mount option skips the reveal on a theme/darkMode-only remount (instant fit, warmup still runs). Physics-feel gates: `SPRINGY_DRAG_MAX_NODES` (5000), `CURSOR_FORCE_MAX_NODES` (2000). Public types live in `graph/mount-types.ts` (re-exported from `graph-mount.ts`). Split-out pieces: `graph/focus-model.ts` (`createGraphFocusModel`: sticky category filter + transient highlight composition, focus crossfade, hover radius tween), `graph/graph-data.ts` (data maps, adjacency, sim inputs, `hitTestEdge`), `graph/tooltip-content.ts` (defaults + host formatter), `graph/update-fades.ts` (enter fade + exit ghosts). | | Graph camera payload (`getCamera`/`onCameraChange`/`flyTo` types, shared 2D+3D) | `packages/vanilla/src/graph/types.ts` → `GraphCamera`, `GraphFlyTarget`. `x`/`y`/`k` always present (2D zoom transform, 3D look-at + `FIT_DISTANCE/distance`); `position`/`target` are 3D-only and therefore optional. `graph-3d/mount.ts` `Camera3D` extends `GraphCamera` narrowing those to required; `FlyTarget3D` is an alias of `GraphFlyTarget`. Re-exported from the vanilla barrel and by each framework's `useGraph`. | -| Graph mount shell (wrapper, chrome, legend slot, tooltip, resize) | `packages/vanilla/src/graph/shell.ts` → `createGraphShell()`, `getContainerDimensions()`, `escapeHtml()`. Everything that is the same in 2D and 3D. Owns the `--oc-bg`/`--oc-text` theme custom properties on `.oc-graph-wrapper`, the `oc-dark` class on the container, `renderChrome`/`syncChromeInset`, and `mountSurface(el)` which inserts the renderer's surface between the chrome and the legend. `createDOM()` in graph-mount.ts no longer exists; the 2D canvas is built by `createSurface()`. | +| Graph mount shell (wrapper, chrome, legend slot, tooltip, resize) | `packages/vanilla/src/graph/shell.ts` → `createGraphShell()`, `getContainerDimensions()`, `escapeHtml()`. Everything that is the same in 2D and 3D. Uses `theme-tokens.ts` to stamp authored theme custom properties on `.oc-graph-wrapper`, the `oc-dark` class on the container, `renderChrome`/`syncChromeInset`, and `mountSurface(el)` which inserts the renderer's surface between the chrome and the legend. `createDOM()` in graph-mount.ts no longer exists; the 2D canvas is built by `createSurface()`. | | Graph renderer registry (2D vs 3D dispatch) | `packages/vanilla/src/graph/renderer-registry.ts` → `GraphShell`, `GraphRendererContext`, `GraphRendererFactory`, `registerGraphRenderer(3, factory)`, `getGraphRenderer(dims)`, `resetGraphRendererRegistry()` (test hook), `GRAPH_3D_NOT_REGISTERED_ERROR`. `createGraph()` dispatches on `compilation.numDimensions` after building the shell. | | 3D graph renderer (WebGL, optional peers) | `packages/vanilla/src/graph-3d/` → the `@opendata-ai/openchart-vanilla/graph-3d` subpath (one-line framework mirrors, so a host never deep-imports a transitive dep: `packages/{react,vue,svelte}/src/graph-3d.ts` → `@opendata-ai/openchart-{react,vue,svelte}/graph-3d`). Registers itself on import; `three`, `3d-force-graph`, `three-spritetext` are optional peers, `d3-force-3d` a dependency. Spec field: `GraphSpec.dimensions?: 2 \| 3`. Node gate `MAX_3D_NODES` (2000) lives in `packages/engine/src/graphs/types.ts` and is applied by `compileGraph` (above it, 3D warns and falls back to 2D). | | Graph canvas renderer (batched draw passes, focus tiers, label budget) | `packages/vanilla/src/graph/canvas-renderer.ts` → `GraphCanvasRenderer`. `labelBudget(zoom)` = `clamp(round(zoom*30), 12, 80)` non-forced labels, placed greedily by priority with an AABB declutter; hovered/selected/`alwaysShowLabel`/search-matched labels bypass both and are the only ones with a halo. Resting edge alpha is 0.3 light / 0.25 dark; the dim tier is `interaction.dimOpacity` (0.3) for nodes and a third of it for edges. | -| Graph surface (canvas background, node knockout ring) | `packages/engine/src/graphs/encoding.ts` → `resolveGraphSurface(theme)` and `vanilla/src/theme-tokens.ts` → `resolvedSurface(theme)`, both thin reads of `theme.colors.neutral.surface` which `graph-mount.ts` stamps as `--oc-bg` on the wrapper. Node strokes are a 1.5px ring in that color. `graph.css` carries NO dark-mode canvas override (the old `#0d1117` is gone); `e2e/invariants/graph-surface.spec.ts` locks it. | +| Graph surface (canvas background, node knockout ring) | `packages/engine/src/graphs/encoding.ts` → `resolveGraphSurface(theme)` and `vanilla/src/theme-tokens.ts` → `resolvedSurface(theme)`, both thin reads of `theme.colors.neutral.surface` which the shared theme-token helper stamps as `--oc-bg` only when the theme authors a background. Node strokes are a 1.5px ring in that color. `graph.css` carries NO dark-mode canvas override (the old `#0d1117` is gone); `e2e/invariants/graph-surface.spec.ts` locks it. | | Graph force simulation (d3-force wrapper, warmup, tick streaming, sync + worker) | `packages/vanilla/src/graph/simulation.ts` → `SimulationManager`. Worker protocol: `graph/worker-protocol.ts`; worker URL: `graph/simulation-worker-url.ts`. | | Graph seeded layout (deterministic initial positions) | `packages/vanilla/src/graph/seed.ts` → `seedNodePositions()`. Start position is a pure function of `(id, seed, community)`, so the settled layout is reproducible across data reshapes (not d3's order-dependent phyllotaxis). | | Animation scheduler (rAF loop, first-frame arming) | `packages/vanilla/src/motion/scheduler.ts` → `AnimationScheduler`, `Animation`. Shared by graph and the scatter canvas layer. Owns the running animations; the host's render loop ticks it once/frame and re-arms rAF only while animations are active (zero cost when idle). | @@ -183,7 +202,7 @@ | Canvas render state (struct-of-arrays) | `packages/vanilla/src/scatter-canvas/state.ts` → `buildScatterCanvasState()`, `flattenFill()`. `markIds` are built from the ORIGINAL `layout.marks` index (`point-${i}`) because a trendline is `unshift`ed onto the array and tooltip descriptors key off that index. Types in `scatter-canvas/types.ts`. | | Canvas entrance animation | `packages/vanilla/src/scatter-canvas/entrance.ts` → `playCanvasEntrance()`, `computeEntranceDuration()`, `clampStagger()`. Replicates the CSS point entrance (fade-only, 40% of duration, 300ms total stagger budget, mirroring `MAX_TOTAL_STAGGER_MS` in `engine/src/compiler/animation.ts`). Its `totalMs` MUST be passed to `setupAnimationCleanup` -- the DOM-counting estimate sees no point elements in canvas mode. | | Canvas pointer interactions (tooltips, click/hover) | `packages/vanilla/src/scatter-canvas/interactions.ts` → `wireCanvasInteractions()`. Listeners on the canvas; the SVG is `pointer-events:none` with legend/annotations/chrome/metrics re-enabled. | -| Mark render mode resolution (`auto`/`svg`/`canvas`) | `packages/engine/src/compiler/mark-render-mode.ts` → `resolveMarkRenderMode()`, `AUTO_CANVAS_THRESHOLD`. The request comes from `CompileOptions.renderer` (a mount option, NOT a spec field — `mark.render` was removed in v8). Sets `ChartLayout.markRenderMode` only when canvas. AUTHORITY RULE: `renderChartSVG` keys ONLY on its `opts.canvasMarks`, never on the layout flag, so SSR/exports always emit a complete SVG. | +| Mark render mode resolution (`auto`/`svg`/`canvas`) | `packages/engine/src/compiler/mark-render-mode.ts` → `resolveMarkRenderMode()`, `AUTO_CANVAS_THRESHOLD`. The request comes from `CompileOptions.renderer` (a mount option, NOT a spec field — `mark.render` is a validation error in v9). Sets `ChartLayout.markRenderMode` only when canvas. AUTHORITY RULE: `renderChartSVG` keys ONLY on its `opts.canvasMarks`, never on the layout flag, so SSR/exports always emit a complete SVG. | | Canvas-mode exports (materialize the missing half) | `packages/vanilla/src/export-canvas.ts` → `materializeCanvasModeSVG()`, `VECTOR_EXPORT_MAX_POINTS`. Vector re-render at or below the cap (byte-identical to SVG mode); above it, vector everything with the dots inlined as one raster ``. Raster formats force vector. | | Sankey compile (layout, label gutters, "Other" bucketing, links) | `packages/engine/src/sankey/compile-sankey.ts` → `compileSankey()`; d3-sankey wrapper in `sankey/layout.ts`. Labels: first column outside-left, last outside-right, interior right, with a symmetric gutter reservation capped at 35% of the width (`MAX_LABEL_GUTTER`). Each node carries a `valueLabel` tspan (tabular, axis ink) — dropped on interior columns when it would run into the next column. `SankeySpec.other` (opt-in) buckets sub-threshold nodes per column into a neutral "Other" node, preserving total flow. | | Sankey render + path hover | `packages/vanilla/src/sankey-renderer.ts` (`renderLabels` stamps `.oc-sankey-label[data-node-id]` and the value tspan), `sankey-mount.ts` → `tracePath()` / `highlightPath()` (BFS upstream + downstream; on-path links 0.7, off-path 0.12, off-path nodes and labels 0.3). Transitions live in `packages/core/src/styles/sankey.css`. | @@ -195,12 +214,13 @@ | `llms.txt` generator | `scripts/generate-llms.mjs` — hand-written narrative + a mark-encoding table generated from the built core's `MARK_ENCODING_RULES`/`MARK_DISPLAY_NAMES`. Build core first. | | Freshness CI (schema + llms.txt) | `bun run check:generated` (both generators in `--check` mode); wired into `.github/workflows/ci.yml` after typecheck. Editing spec types without regenerating fails CI. | | Schema/artifact tests | `packages/core/src/schema/__tests__/{schema,generated-artifacts}.test.ts` (ajv-validates all 16 marks, rejects hallucinated fields, asserts artifacts cover every mark). | -| "Did you mean" repair hints | levenshtein `editDistance`/`nearestColumn`/`didYouMean` in `packages/engine/src/compiler/validate.ts` (wired into DATA_FIELD_MISSING suggestions). Test: `validate-did-you-mean.test.ts`. | +| "Did you mean" repair hints | levenshtein `editDistance`/`nearestColumn`/`didYouMean` in `packages/engine/src/compiler/validation/helpers.ts` (wired into DATA_FIELD_MISSING suggestions). Test: `validate-did-you-mean.test.ts`. | | LLM spec-generation eval (manual, per-release) | `scripts/llm-eval/` (`fixtures.json`, `run.mjs`, `README.md`). Hits the Anthropic API; not in CI; `@anthropic-ai/sdk` is not a monorepo dep (dynamic import). | | Generating-specs guide | `docs/generating-specs.md` (schema usage, tool-use, strict-mode transform, validate-repair loop). | +| v9 migration guide | `docs/migrating-v9.md` (default changes, edit transactions, theme merging, removed forms, and styling migration modes) | | v8 migration guide | `docs/migrating-v8.md` (breaking changes, before/after specs, jq codemods). Keep in sync with the deprecation warnings. | | Dashboard usage guide (tile sizing, sparkline KPI cards, metrics vs HTML stat cards, chrome economy, watermark auto-hide rules, grid composition, BarList/DataTable in tiles) | `docs/dashboards.md` | -| VL-idiom sugar + deprecation warnings | `packages/engine/src/compile/spec-sugar.ts` (`expandSpecSugar`, `emitSpecWarnings`) — dead channels (`radius`/`shape`/`href`/`order`, removed in v8), stack default, theta<->y (theta is canonical in v8; `y` on arc/waffle/parliament is a deprecated alias, expanded both directions since the engine still reads `y` internally), `'rule'`->`'refline'` annotation alias, `$schema`. All of these run pre-validation so canonical form is all `compiler/normalize.ts`/`validate.ts` ever see. Tests: `engine/src/__tests__/spec-sugar.test.ts`. | +| VL-idiom sugar + deprecation warnings | `packages/engine/src/compile/spec-sugar.ts` (`expandSpecSugar`, `emitSpecWarnings`) — stack default, theta→y mirroring (theta is the only authored arc/waffle/parliament value channel; the engine still reads `y` internally), `$schema`. Retired v8 forms (dead channels `radius`/`shape`/`href`/`order`, authored `y` on theta marks, annotation `type: 'rule'`, spec `darkMode`, `mark.render`, etc.) are rejected before sugar by `compiler/removed-spec-fields.ts` → `collectRemovedSpecErrors`. All of these run pre-validation so canonical form is all `compiler/normalize.ts`/`validate.ts` ever see. Tests: `engine/src/__tests__/spec-sugar.test.ts`, `compiler/__tests__/v9-removed-fields.test.ts`. | ## Package responsibilities (one-liner each) @@ -211,7 +231,7 @@ Build order: `core` → `engine` → `vanilla` → (react, vue, svelte in parallel). Workspace deps use `workspace:*`. -## Compile pipeline (anchor file: `packages/engine/src/compile.ts` for charts) +## Compile pipeline (anchor file: `packages/engine/src/compile/chart.ts` for charts) ``` VizSpec @@ -253,15 +273,16 @@ The vanilla adapter (`mount.ts`) takes the resulting `ChartLayout` and calls `re - **`refreshConnector(connector, bounds, markerRadius)`** (`geometry.ts`) is the single rebuild path used by `resolve-text.ts`, `compute.ts` Pass 2, and every `collisions.ts` reposition. It re-runs `connectorExit` for `from` (then re-applies the author's `connectorOffset.from`, carried on the resolved connector as `fromOffset`, before the pullback) and re-derives `to` by pulling back from `connector.endpoint` (never from the already-pulled-back `to`). Both author nudges survive rebuilds this way: `to` via `endpoint`, `from` via `fromOffset`. Returns `undefined` when the connector should be suppressed. - **Connector suppression:** a connector shorter than `MIN_CONNECTOR_LENGTH` (8) after pullback, or one whose target is inside the text block, is dropped. The dot survives. `MIN_CONNECTOR_LENGTH` must stay well under the standoff + marker-pullback overhead (~18px) that is spent before any line is drawn — set it near or above that and the default annotation becomes structurally unable to draw a connector at any offset, which is exactly the bug `842c1dc` fixed. A plain `{type:'text'}` annotation sits `ANCHOR_OFFSET` (28) off its point and draws a real leader with zero authoring. - **One marker system.** `annotation.dot` is it — the renderer's old hardcoded bullseye (ring + center dot) is gone. `resolveDot` (`resolve-text.ts`) resolves a default dot whenever a connector is enabled, no arrowhead is set, and `dot` is `undefined`. `dot: false` → bare. Arrow + unset `dot` → no marker. The dot sits on the data point (plus `connectorOffset.to`), not on the pulled-back connector tip. Drop-lines get one too. -- **Connector spec union**: `boolean | ConnectorType | ConnectorConfig` where `ConnectorType = 'straight' | 'curve' | 'drop-line'` and `ConnectorConfig = { type: ConnectorType, arrow?: boolean }`. Defaults: `arrow=true` for curve, `arrow=false` for straight/drop-line. Resolved connector carries `arrow: boolean` and `exit`. Two voices: arrowed connectors take the label's text ink, quiet leaders (non-arrow straight, drop-line) take `LIGHT/DARK_CONNECTOR_STROKE`. Curves render as a single quadratic; arrowheads are a stroked open-V `` (`geometry.ts:computeArrowheadPoints`, a public engine export, defaults length 7 / halfWidth 3.5). +- **Connector spec union**: `boolean | ConnectorType | ConnectorConfig` where `ConnectorType = 'straight' | 'curve' | 'drop-line'` and `ConnectorConfig = { type: ConnectorType, arrow?: boolean, bend?: number }`. All connector types default to `arrow=false`; explicit arrows remain supported. Resolved connector carries `arrow: boolean` and `exit`. Two voices: arrowed connectors take the label's text ink, quiet leaders (non-arrow curves, straight, drop-line) take `LIGHT/DARK_CONNECTOR_STROKE`. Curves render as a single quadratic; arrowheads are a stroked open-V `` (`geometry.ts:computeArrowheadPoints`, a public engine export, defaults length 7 / halfWidth 3.5). - **Rich text** (`annotations/rich-text.ts`): `parseAnnotationSpans(line)` → `RichSpan[]` for `**bold**` markers, in `text` and `subtitle`. Unmatched (and empty) delimiters render literally. `computeTextBlockBounds` measures bold spans at `BOLD_SPAN_FONT_WEIGHT` (700), so bounds, collisions, placement, and connector exits all account for them. Exported from `engine/src/index.ts` for the renderer. - **Alignment:** the *text* never center-aligns. `textAnchor` is `'end'` when `anchor: 'left'` (block sits left of the point, right edge faces it) and `'start'` otherwise; the auto-placement `DIRECTIONS` table in `placement.ts` assigns start/end by direction. - **Block centering (distinct from text alignment):** a `top`/`bottom` anchor means the block sits *above/below* the point, so it straddles it horizontally — the lines inside stay left-aligned/ragged-right. Explicit path: `centeringShift` in `resolve-text.ts` backs `labelX` off by half the widest line (primary vs subtitle — a subtitle is often wider). Auto path: `labelPositionFromAttachment` in `placement.ts` honors `attach: 'top-center'`/`'bottom-center'`. Skip either and `anchor: 'top'` renders as "up and to the right", forcing authors to hand-compute a negative `dx` of half the block width. -- **Typography:** 13px / weight 400 by default, in `theme.fonts.family` (threaded via `AnnotationContext.fontFamily` from `compile.ts`; `FALLBACK_FONT_FAMILY` covers SSR paths). The **lede rule** (`resolveLedeFontWeight`): a `subtitle` with no explicit `fontWeight` promotes the primary text to `LEDE_FONT_WEIGHT` (700); the subtitle stays 400. -- **Thinning** (`annotations/thinning.ts`): `thinAnnotations(annotations, specs, measure, plotArea?, containerBounds?)` demotes overlapping/overflowing labels to numbered footnotes. Containment is checked against `containerBounds ?? plotArea` — annotations legitimately sit in the margin (above a peak, below a trough), so only labels escaping the *chart* demote. The coverage budget still measures against the plot. +- **Typography:** 13px / weight 400 by default, in `theme.fonts.family` (threaded via `AnnotationContext.fontFamily` from `compile.ts`; `FALLBACK_FONT_FAMILY` covers SSR paths). A subtitle no longer promotes the primary text to bold; explicit `fontWeight` and rich bold spans win. Subtitle size is the rounded primary size × 12/13; reference/range labels use the theme small size. +- **Placement order and crossings:** `compute.ts` places higher-priority annotations first with source order as the tie-breaker; `connector-crossings.ts` spatially indexes labels, marks, and accepted leaders for candidate scoring. Explicit zero offsets are pinned. +- **Thinning** (`annotations/thinning.ts`): `thinAnnotations(annotations, specs, measure, plotArea?, containerBounds?)` demotes overlapping/overflowing labels to numbered footnotes. Containment is checked against `containerBounds ?? plotArea` — annotations legitimately sit in the margin (above a peak, below a trough), so only labels escaping the *chart* demote. The coverage budget still measures against the plot. Compact charts default to one inline callout; D15 responsive opt-outs bypass thinning. Note numbers use source annotation ordinals and can have gaps. - **`specIndex` — the resolved array is NOT the spec array.** `computeAnnotations` drops any annotation whose position falls outside the scale domain, so `annotations[i]` is not `spec.annotations[i]`. Every resolved annotation carries `specIndex` for the trip back; thinning's priority/`responsive` lookup and the faceted footnote numbering both key on it. Indexing `specs[i]` by resolved position is the bug this exists to prevent — it silently mis-associates annotations, and it only shows up once one of them fails to resolve. -- **Faceted thinning** (`compile.ts`, in `compileFaceted`): faceted charts do *not* reach the single-chart `thinAnnotations` call — `compileChart` branches to `compileFaceted` first, so before this existed `autoThin` on a facet was a silent no-op and labels sprawled across neighbouring panels. Each panel now thins against its own `gridPanel.area`, passed as **both** `plotArea` and `containerBounds` (a panel is its own little chart). Footnotes pool into one figure-level `chrome.footnotes` list; since a spec annotation resolves into *every* panel, numbering is keyed on `specIndex` so a label demoted in all N panels gets one footnote, not N copies. The shared preflight reserves source note capacity once per annotation, including pinned text and subtitles. `frozenChartArea` prevents leaf recompilation from moving the common layer plot. -- **Shared constants:** `annotations/constants.ts` (`ANCHOR_OFFSET`, `CONNECTOR_STANDOFF`, `MIN_CONNECTOR_LENGTH`, `DEFAULT_DOT_RADIUS`/`_STROKE_WIDTH`, `LEDE_FONT_WEIGHT`, connector strokes, default font sizing, dash pattern, refline/text fills for light/dark). +- **Faceted thinning** (`compile/faceted.ts`, in `compileFaceted`): faceted charts do *not* reach the single-chart `thinAnnotations` call — `compileChart` branches to `compileFaceted` first, so before this existed `autoThin` on a facet was a silent no-op and labels sprawled across neighbouring panels. Each panel now thins against its own `gridPanel.area`, passed as **both** `plotArea` and `containerBounds` (a panel is its own little chart). Footnotes pool into one figure-level `chrome.footnotes` list; since a spec annotation resolves into *every* panel, numbering is keyed on `specIndex` so a label demoted in all N panels gets one footnote, not N copies. The shared preflight reserves source note capacity once per annotation, including pinned text and subtitles. `frozenBudget` (engine-internal `InternalCompileOptions`) prevents leaf recompilation from moving the common layer plot. +- **Shared constants:** `annotations/constants.ts` (`ANCHOR_OFFSET`, `CONNECTOR_STANDOFF`, `MIN_CONNECTOR_LENGTH`, `DEFAULT_DOT_RADIUS`/`_STROKE_WIDTH`, `SUBTITLE_FONT_SIZE_RATIO`, connector strokes, default font sizing, dash pattern, refline/text fills for light/dark). ## Chrome system @@ -272,14 +293,15 @@ The vanilla adapter (`mount.ts`) takes the resulting `ChartLayout` and calls `re - `dimensions.ts` (engine) calls `computeChrome` and subtracts top/bottom reservations from the available area to get `chartArea`. - The renderer (`vanilla/src/renderers/chrome.ts`) is small (~96 lines) — it just maps `ResolvedChrome` to SVG `` elements with the right CSS classes. - `chromeLayout` (`'subtract' | 'grow'`, top-level spec prop) and `ChromeTextStyle.maxLines` are the chrome-layout spec surface in `packages/core/src/types/spec.ts`. -- `resolveChromeLayout` in `packages/engine/src/layout/shared.ts` picks subtract vs grow (spec wins over compile option; faceted specs pin to `'subtract'`). +- `resolveChromeLayout` in `packages/engine/src/layout/shared.ts` picks the public subtract/grow opt-outs or the internal default `'notes'` policy. Notes grow below the ordinary figure budget; explicit subtract keeps the exact height and grow preserves the plot budget. Facet assembly owns growth once. - `truncateToWidth` in `packages/core/src/responsive/metrics.ts` is the exported ellipsis helper that caps text to a pixel budget (backs both `maxLines` and rotated-tick truncation). ## Theme system - **Default theme:** `DEFAULT_THEME` literal in `packages/core/src/theme/defaults.ts`. Single source of truth. -- **User overrides:** `ThemeConfig` (partial) → `resolveTheme()` deep-merges onto `DEFAULT_THEME` → `ResolvedTheme` (every field set). +- **User overrides:** public `mergeThemeConfig()` deep-merges authored configuration; arrays and TokenValues are atomic, null replaces. In a layer the root scope (chrome, axes, legend) takes the layer theme (`resolveLayerTheme`) while each leaf's marks merge the leaf theme over it; mount options beat both. Framework providers merge into component props. `resolveTheme()` adds defaults and returns `ResolvedTheme`, retaining internal `_authored` metadata for CSS and dark adaptation. Public `Theme` is removed; `ThemeBase` remains internal. - **Dark mode:** `adaptTheme(resolved)` in `dark-mode.ts` swaps surface tokens, adapts categorical palette via binary-search on lightness to preserve contrast against the dark background. +- **Authored CSS tokens:** `packages/vanilla/src/theme-tokens.ts` → `stampThemeProperties()` is shared by chart/table/graph/map and specialized renderers. It stamps authored overrides only, restoring previous host inline values when an override disappears. `theme-style-block.ts` → `prepareSettledExportTheme()` preserves live computed tokens across chart, map, tilemap, Sankey, and barlist exports, or clears authored inline overrides when an explicit export theme wins. - **CSS tokens** (`tokens.css`, `dark.css`) are **generated** from `packages/core/src/styles/token-definitions.ts`. Run `bun run generate:tokens` after editing. CI enforces freshness via `check:generated`. - **Cascade layers:** all CSS is wrapped in `@layer oc.*` sub-layers declared in `index.css`: `oc.tokens, oc.base, oc.components, oc.animation, oc.reduced-motion`. Consumer un-layered CSS beats all openchart rules (v8 breaking change, see `docs/migrating-v8.md` section 14). @@ -311,7 +333,9 @@ The `size` channel maps a field onto a font-size range with a **linear** scale ( ## Layered scales (`engine/src/compile/layer.ts`) -Shared scales means shared **domains**, not just a shared plot rect. `compileLayer` freezes the primary's chart area for every leaf (`frozenChartArea`), but each leaf otherwise re-fits its own domain from its own rows — so a layer holding fewer or narrower rows than its siblings (a label layer naming only the notable points) lands on a different scale and its marks slide off the ones they annotate. `computeSharedDomains`/`withSharedDomains` union the quantitative x/y extents across all leaves and pin them. The union bails on any channel where a leaf is non-quantitative or has an author-pinned `scale.domain`. +Independent y-scale assemblies choose endpoint names before measurement when a leaf requests interior identification; overlapping independent bands cannot guarantee a shared interior label background. The endpoint merge retains mandatory band leaders in both columns. `__tests__/layer-endpoint-identification.test.ts` covers names, authored formats, source observations and the diagnostic fallback. `__tests__/layer-legend-assembly.test.ts` covers complete legend measurement before the shared frame freezes, transformed/hidden leaves and authored limits. + +Shared scales means shared **domains**, not just a shared plot rect. `compileLayer` freezes the primary's chart area for every leaf (`frozenBudget.chartArea`), but each leaf otherwise re-fits its own domain from its own rows — so a layer holding fewer or narrower rows than its siblings (a label layer naming only the notable points) lands on a different scale and its marks slide off the ones they annotate. `computeSharedDomains`/`withSharedDomains` union the quantitative x/y extents across all leaves and pin them. The union bails on any channel where a leaf is non-quantitative or has an author-pinned `scale.domain`. ## Animation system @@ -371,11 +395,11 @@ The browser authoring application lives in the separate [OpenStudio repository]( | Concern | Source / exports | | --- | --- | | Atomic authored-spec edits and inverse operations | `packages/core/src/helpers/edit-transactions.ts`: public `applyEditTransaction`, `EditTransactionResult`; `types/events.ts`: `EditOp`, `EditTransaction`, optional revision and callback | -| Authored annotation ownership and legacy event bridge | `packages/core/src/helpers/annotation-source.ts`: `annotationSource`; `packages/vanilla/src/interactions/edit-transactions.ts`: `editToTransaction`; mount stamps source paths, renderer stamps facet instances; selection and click events preserve both identities | +| Authored annotation ownership and transaction bridge | `packages/core/src/helpers/annotation-source.ts`: `annotationSource`; `packages/vanilla/src/interactions/edit-transactions.ts`: `editToTransaction`; mount stamps source paths, renderer stamps facet instances; selection and click events preserve both identities | | Alias migration with repair paths | `packages/engine/src/migration/v8.ts`: public `migrateSpecV8`, `SpecRepair`; layer migrations reuse `compile/layer.ts:buildPrimarySpec` and `compiler/normalize.ts:flattenLayers` | -| Shared v8 shallow theme precedence | `packages/core/src/theme/merge.ts`: `mergeThemeConfig`; `ThemeBase` is internal, public `Theme` remains deprecated | -| Mount compatibility warnings | `packages/vanilla/src/deprecations.ts`; engine warnings remain in `compile/spec-sugar.ts` | -| Example migration parity | `examples/src/__tests__/migration-parity.test.ts`; test-only collector in `examples/vitest.config.ts` exposes authored story/layout values | +| Shared theme precedence | `packages/core/src/theme/merge.ts`: `mergeThemeConfig`; introduced shallow in Track A and deep in v9. `ThemeBase` is internal; public inputs use `ThemeConfig`. | +| Retired compatibility forms | v9 rejects removed spec fields in `packages/engine/src/compiler/removed-spec-fields.ts` before sugar; migration remains in `migration/v8.ts`. | +| Example migration contract fixtures | `examples/src/__tests__/migration-parity.test.ts`; test-only collector in `examples/vitest.config.ts` exposes authored story/layout values | Annotation computation requires the existing `AnnotationContext`; dimensions require a `LayoutPlan`. Their old positional/plan-less fallbacks are gone. @@ -391,7 +415,7 @@ transitions accept `MapTransitionSnapshot` only. | Curve control and per-frame annotation geometry | `annotations/geometry.ts`: `automaticControlPoint`, `refreshConnector`; `annotations/interpolate.ts`: `interpolateAnnotationGeometry`; all exported from engine | | Cancellable mouse/touch gestures and keyboard batches | `packages/vanilla/src/interactions/drag-handler.ts`, `annotation-nudges.ts`; mount flushes pending edits before gesture starts and retargets after synchronous host updates | | In-place annotation drawing shared by preview and animation | `packages/vanilla/src/renderers/annotations.ts`: `updateAnnotationGeometry`; transition gate/build/apply consume resolved geometry | -| Cross-browser geometry contract | `e2e/annotation-invariants/`; two dedicated projects; gallery `AnnotationCurves` and `AnnotationGestures` stay outside visual baselines | +| Cross-browser geometry contract | `e2e/annotation-invariants/`; two dedicated projects; gallery `AnnotationCurves` and `AnnotationGestures` provide dedicated fixtures; visual-suite selection lives in `e2e/visual/stories.spec.ts` | | Preview benchmark | `packages/engine/src/annotations/__tests__/preview.bench.ts`; Vitest 5 test-context bench, run with `bunx vitest bench --run` | The chart compiler places right-side legends after resolving the endpoint column, @@ -405,15 +429,52 @@ regular, shared-layer and dual-axis column separation. | Concern | Location | |---|---| | Rich wrapping without changing authored text/transition keys | `packages/engine/src/annotations/wrap-text.ts`: `wrapAnnotationText`; `resolve-text.ts` stores `label.lines`/subtitle lines | -| Opt-in reference end/auto/outside geometry | `packages/engine/src/annotations/reference-layout.ts`: `referenceLabelReserve`, `placeReferenceLabel`; `geometry.ts` retains corridor attachments during rebuilds; `compute.ts` uses per-panel reserved lanes owned by `layout/facet.ts`; `dimensions.ts` and `compile/layer.ts` reserve the gutter | -| Compact priority/source count limit | `annotations/thinning.ts`: optional final `compactLimit`; `compile.ts` gates on outer width and height before coverage/collision thinning | -| Resolved note arithmetic and compatibility exports | `packages/core/src/layout/chrome.ts`: `computeNoteBandHeight` and deprecated `footnoteBandHeight`, exported through core index; vanilla adapter in `renderers/chrome.ts`; renderers/brand consume resolved `noteBandHeight` | +| Reference end/auto/outside geometry (auto by default in v9) | `packages/engine/src/annotations/reference-layout.ts`: `referenceLabelReserve`, `packReferenceRows` (top-lane row packing by x extent), `admitReferenceRows`, `placeReferenceLabel` (reads the budget's admitted rows); `geometry.ts` retains corridor attachments during rebuilds; `compute.ts` uses per-panel reserved lanes owned by `layout/facet.ts`; `dimensions.ts` and `compile/layer.ts` reserve the gutter | +| Compact priority/source count limit | `annotations/thinning.ts`: optional final `compactLimit`; `compile/chart.ts` gates on outer width and height before coverage/collision thinning | +| Resolved note arithmetic | `packages/core/src/layout/chrome.ts`: public `computeNoteBandHeight`; vanilla adapter in `renderers/chrome.ts`; renderers/brand consume resolved `noteBandHeight`. The `footnoteBandHeight` compatibility export is removed in v9. | | Exactly-once facet grow metadata | `packages/engine/src/compile.ts` facet assembly and `layout/dimensions.ts` populate optional `chrome.grownHeight`; `packages/vanilla/src/mount.ts` deducts engine-owned growth | -| Authored mark-option warnings | `packages/engine/src/compiler/mark-options.ts`: `collectMarkOptionWarnings`; `compile/spec-sugar.ts` calls it before rewrites; `validate.ts` exposes optional warnings | -| 8.x default materialization | `packages/engine/src/migration/v8.ts`: `migrateSpecV8`; parity fixtures in `examples/src/__tests__/migration-parity.test.ts` | +| Authored mark-option contract | `core/src/types/spec.ts`: discriminated `MarkDef`; `engine/src/compiler/types.ts`: internal wide `NormalizedMarkDef`; `compiler/mark-options.ts`: `collectMarkOptionErrors` / `assertMarkOptions`, checked before sugar with authored JSON Pointer paths | +| Mark contract parity matrix | `packages/engine/src/__test-fixtures__/mark-options.ts`: every mark × option plus compile-time union assertions; `compiler/__tests__/mark-options.test.ts`: published schema, strict-null transform, and runtime agreement | +| Migration and optional v8 styling materialization | `packages/engine/src/migration/v8.ts`: `migrateSpecV8`; default preserves v8 styling, `{ styling: 'v9' }` applies alias rewrites only. Contract fixtures in `examples/src/__tests__/migration-parity.test.ts`; no pixel-layout parity promise. | | Layout opt-in browser fixtures | `examples/src/gallery/features-annotations.demos.ts` and `.stories.tsx`: ReferenceLabels, CrowdedCallouts, NotesSizing; `e2e/annotation-invariants/layout.spec.ts` covers geometry, note counts, heights, SVG/PNG and canvas | The seven annotation colors are resolved theme fields in `core/src/types/theme.ts`, registered with dark pairs in `theme/resolve.ts` and `theme/dark-mode.ts`, and mirrored by `styles/token-definitions.ts` and generated CSS. Existing generic annotation colors retain their previous uses. + +## v9 current contract additions and removals + +| Concern | Source / exports | +|---|---| +| Transaction-only edit events | `core/src/types/events.ts`: `ChartEventHandlers.onEdit(EditTransaction)`; internal `vanilla/src/interactions/gesture-edit.ts` feeds `edit-transactions.ts`. `ElementEdit` and `onEditTransaction` are removed. | +| Keyboard annotation editing | `vanilla/src/interactions/annotation-nudges.ts` previews arrows/Shift+arrows and commits 500ms after release; `mount.ts` handles Tab/Shift+Tab selection and batch flush/cancel paths. | +| Linked notes and markers | `vanilla/src/interactions/annotation-notes.ts`: `wireAnnotationNotes`; renderer `data-note-spec-index` / `data-note-marker-index` identity links pointer/focus/keyboard emphasis without changing placement. | +| Removed-spec validation | `engine/src/compiler/removed-spec-fields.ts`: `collectRemovedSpecErrors`; called before sugar and by `validateSpec`, with authored paths. | +| Shared bounded field inference | `core/src/helpers/spec-builders.ts`: public `inferFieldType`; normalization and chart helpers sample up to 50 values, with numeric strings before temporal matching. The engine duplicate is removed. | +| V9 default and removal guards | `engine/src/annotations/__tests__/v9-defaults.test.ts`, `compiler/__tests__/v9-removed-fields.test.ts`; migration fixtures in `engine/src/__tests__/migrate-spec-v8.test.ts`. | +| Connector crossing score | `engine/src/annotations/connector-crossings.ts`: internal `ConnectorCrossings`; geometry tests in `annotations/__tests__/connector-crossings.test.ts`. | +| Layer theme ownership | `engine/src/compile/layer.ts`: public `resolveLayerTheme` (root theme: `layer.theme ?? leaves[0].theme`) is shared with mount font measurement; leaf marks deep-merge `layer.theme` + `leaf.theme`. | +| Former line label implementation | `engine/src/charts/line/labels.ts` removed; endpoint columns use `engine/src/endpoint-labels/` and `vanilla/src/renderers/endpoint-labels.ts`. | +| Typed date slices and conservative comparison | `core/src/types/reader-slices.ts`; `engine/src/design/reader-slices.ts` indexes actual compiled observations and reconciles binding identity. `tooltips/metadata.ts` assigns explicit role/source metadata. | +| Chart reader lifecycle | `vanilla/src/{reader,slice-reader,observation-reader,reader-binding,reader-options}.ts`; `interactions/reader-arbitration.ts` owns private gesture/layout subscriptions. Existing observation overload remains available. | +| Host-owned comparison and place search | `vanilla/src/{reader-panel,reader-view-model,map-reader,map-companion,map-reader-overlays}.ts`; shared styling in `core/src/styles/reader.css`. Public `createGeoReader`, `GeoReaderController`, `GeoReaderOptions`. | +| Map index and key context | `core/src/types/{geo-reader,geo-color-key}.ts`; `engine/src/geo/{reader-index,color-key}.ts`; `vanilla/src/map-color-key.ts`. Static distribution and transient active selection have separate paint paths. | +| Shared measured attribution | `core/src/layout/chrome.ts` resolves `watermark` and `attributionLayout`; `vanilla/src/renderers/{brand,attribution-footer}.ts` paints the portable footer. Graph shell and table renderer reuse it. Exact v8 migration exceptions live in `examples/src/__tests__/migration-v8-attribution-changes.ts`. | +| Reader and attribution journeys | `examples/src/gallery/{reader,attribution}.stories.tsx`; Chromium/WebKit cases in `e2e/chart-map-design/{reader,attribution}.spec.ts`. | + +The migration guide records remaining type/field removals. The built-in `editorial` +preset, public `Theme`, `footnoteBandHeight`, and responsive padding-cap constants +are removed. CSS defaults and theme configuration remain supported for all mount +families; `clarity` is a deprecated colors-only migration bridge. + + +## Geographic detail and inset views + +| Concern | Source / exports | +|---|---| +| Optional authoring/layout contracts | `core/src/types/geo-views.ts`: `GeoDetailLayer`, `GeoInset`, `GeoViewLayout`, `GeoProjectionContext`; `GeoMapSpec.geo` references these optional fields. | +| Object selection, source-plane validation and immutable projection fit | `engine/src/geo/view-geometry.ts`; `compiler/validation/geo-map.ts`; `geo/compile-geo-map.ts` creates root/inset layouts with shared joins and explicit coverage. | +| Independent cameras and scenes | `vanilla/src/map-view-camera.ts`, `map-view-renderer.ts`; `map-mount.ts` exposes scoped camera methods and preserves root compatibility. | +| Labels, identity and portable export | `map-labels.ts`, `map-label-inventory.ts`, `map-reader.ts`, `map-reader-overlays.ts`, `static.ts`; view scope changes representation, not observation identity. | +| Real geography and browser journeys | `engine/src/geo/__tests__/fixtures/travis-tracts-2020.geojson` with source provenance; `examples/src/gallery/geo-views.stories.tsx`; `e2e/chart-map-design/geo-views.spec.ts`. | diff --git a/docs/dashboards.md b/docs/dashboards.md index 5ad02144..53028b2f 100644 --- a/docs/dashboards.md +++ b/docs/dashboards.md @@ -120,7 +120,7 @@ const spec: BarListSpec = { }; ``` -`TableSpec` tiles should set `density: 'condensed'` for reduced padding and font size (40px rows instead of 48px), and keep row counts small enough that the tile doesn't grow a second scrollbar inside a dashboard card. `compact: true` still works as an alias but warns — prefer `density` directly. Tables resolve `watermark` on their own (see [Watermark rules](#watermark-rules) above), so set it explicitly: +`TableSpec` tiles should set `density: 'condensed'` for reduced padding and font size (40px rows instead of 48px), and keep row counts small enough that the tile doesn't grow a second scrollbar inside a dashboard card. `compact` is removed in v9; use `density` directly. Tables resolve `watermark` on their own (see [Watermark rules](#watermark-rules) above), so set it explicitly: ```ts const spec: TableSpec = { diff --git a/docs/design-evolution.md b/docs/design-evolution.md index 93aa6b9e..8dd474b4 100644 --- a/docs/design-evolution.md +++ b/docs/design-evolution.md @@ -4,7 +4,7 @@ OpenChart's direction is editorial clarity, continuous interaction, and explaina ## Delivery and evidence -This record distinguishes implementation from release validation. No comprehension, authoring, or performance improvement is claimed without measurements. Breaking defaults remain reserved for the next major release. +This record distinguishes implementation from release validation. No comprehension, authoring, or performance improvement is claimed without measurements. Breaking defaults are recorded separately from publication and release validation. | Phase | Scope retained | Status | | --- | --- | --- | @@ -53,3 +53,40 @@ Performance targets: 60fps reference motion; desktop p95 frame interval below 33 Human validation (requires real participants, not simulated results): matched baseline comprehension tasks, at least 80% correct, no accuracy regression and 20% lower median response time; at least five representative authors, four completing import/refine/mobile check/undo/reopen/export without JSON. Record completion time and corrections. These gates remain pending until the study is conducted. Technical architecture and product UX reviewers must independently approve the implementation after fix/review cycles before the final commit, merge, and push. This does not substitute for the human release gates. + + +## v9 chart clarity and annotation contract (implementation record) + +The additive Track A work shipped in 8.9.1. The v9 implementation adopts the +accepted chart-clarity plan's defaults and removes its compatibility APIs. This +record describes the library changes in the v9 branch; it does not claim that an +RC or final release has been published, that Studio has adopted it, or that the +human studies above have been conducted. + +| Decision | v9 contract and reason | +| --- | --- | +| Figure budget | Omitted `chromeLayout` adds only the note band; public `grow` and `subtract` retain their meanings. The engine reports total and grown heights so mounts/exports count growth once. Exact-height embeds author `subtract`. | +| Editorial typography | Small/axis/footer text becomes 12px, with 16px chrome-to-chart and 12px chart-to-footer gaps. Background, axis, and eyebrow defaults retain their prior choices. Subtitle ratio becomes 12/13 and a subtitle no longer implies a bold primary label. | +| Annotation placement | Automatic labels use priority then source order, measured wrapping, and connector-crossing costs. Curves no longer imply arrows. Reference labels default to automatic placement unless a legacy anchor is explicitly authored. | +| Compact reading | One eligible inline callout is the compact default; null removes that count limit. Pinned annotations remain inline and may overlap after narrow clamping. Existing chart-level responsive opt-outs retain their behavior. | +| Note identity | Rich primary/subtitle content wraps in the engine. Numbers follow source text-annotation order before filtering, allow gaps, and are shared across facet instances. Linked note/marker emphasis is transient reader state. | +| Surface and ink | D19 reference/range colors are retuned; marker and plate colors derive from the neutral surface. Authored annotation and theme colors remain authoritative. | +| Editing | `onEdit` receives atomic transactions; hosts use `applyEditTransaction` and its inverse. Arrows nudge, Shift accelerates, Tab cycles selection. Engine geometry remains authoritative through preview, commit, animation, and export. | +| Theme composition | Spec, provider, and host overrides deep-merge; leaves override parent themes. Authored chrome sizes beat general font propagation. Arrays/color pairs are atomic and null clears rules. Unauthored CSS tokens remain available to host styles. | +| Authoring grammar | `MarkDef` is a discriminated union with pre-sugar errors and schema/type/runtime parity. Inference has one core implementation. Retired aliases fail validation; endpoint labels replace legacy line-end labels. | +| Migration | Default `migrateSpecV8` rewrites aliases and materializes former styling. `{ styling: 'v9' }` rewrites aliases only. Neither mode promises v8 pixel layout; every repair is inspectable. | + +The implementation retains the portable boundary: core owns pure contracts and +theme/inference helpers, engine owns geometry and layout, and vanilla/framework +packages own rendering and interaction. OpenStudio's v2 envelope, migration +choice, storage recovery, and version adoption remain separate application work. +The external authoring-skill synchronization and publication are separate release +steps, not implied by this implementation record. + +Validation locations: `e2e/annotation-invariants/` owns the two annotation browser +projects; the existing `invariants*` projects keep their original scope. The +preview benchmark is `packages/engine/src/annotations/__tests__/preview.bench.ts`. +Theme and transaction behavior have direct integration tests. Visual baselines +must be reviewed once for the completed v9 composition before release; this +record does not substitute for that review or claim reader-comprehension gains. +See [the migration guide](migrating-v9.md) for the public before/after contract. diff --git a/docs/design-system.md b/docs/design-system.md index 4236f969..b896089b 100644 --- a/docs/design-system.md +++ b/docs/design-system.md @@ -111,12 +111,14 @@ and the mode's `--oc-bg` token (`#ffffff` light, `#09090b` dark) when the background is transparent. Everything that has to knock a hole in the canvas reads it, so there is exactly one answer: knockout rings and stacked-segment seams (`resolveKnockoutColor`), table cell fills (`resolveTableSurface`), -graph node rings (`resolveGraphSurface`), tilemap label contrast, and the -`--oc-bg` the vanilla mount stamps (`resolvedSurface`). +graph node rings (`resolveGraphSurface`), annotation marker/plate fills, and +tilemap label contrast. Authored backgrounds also feed the `--oc-bg` token +stamped by the shared renderer helper (`resolvedSurface`). Source: `packages/core/src/colors/neutral.ts` — `deriveNeutralRamp(text, bg, isDark)`. Computed once in `resolveTheme`/`adaptTheme` and carried on -`ResolvedTheme.colors.neutral`; mounts stamp the CSS tokens from it. The +`ResolvedTheme.colors.neutral`. Mounts stamp authored theme overrides and +their derived tokens; omitted tokens keep the CSS cascade available to hosts. The direction is one-way (theme → CSS): engine code reads `theme.colors.neutral.*` directly and never calls `cssTokenDefault`. When the background is transparent (the default theme's is) the ramp falls back to the static CSS @@ -133,6 +135,9 @@ case. | `colors.gridline` | `rgba(0,0,0,0.08)` | `rgba(255,255,255,0.06)` | | `colors.hairline` | `rgba(0,0,0,0.14)` | `rgba(255,255,255,0.14)` | | `colors.axis` | `#71717a` | `#a1a1aa` | +| `colors.annotationRule` | `#888888` | `#9ca3af` | +| `colors.annotationRangeFill` | `#f0c040` | `#f0c040` | +| `colors.annotationMarkerFill` / `annotationPlate` | Resolved neutral surface | Resolved neutral surface | `axis` is both the axis-line color and the tick-label ink, and must clear WCAG AA (4.5:1) on its background — zinc-500 hits roughly 5.7:1 on white, @@ -148,17 +153,18 @@ Source: `packages/core/src/theme/defaults.ts` (`DEFAULT_THEME`), One weight ladder everywhere: 400 regular (body), 500 medium (eyebrow, labels, UI chrome, values), 600 semibold (title, series names, tooltip -title, annotation lede), 700 bold (`**bold**` spans only). Tabular numerals -apply to every number, including static SVG chrome. +title), 700 bold (`**bold**` spans or explicit author emphasis). Annotation +primary text stays regular when a subtitle is present. Tabular numerals apply +to every number, including static SVG chrome. | Element | Size | Weight | Color | |---|---|---|---| | Title | 26px | 600, -0.022em tracking | `#09090b` | | Subtitle | 14px | 400 | `#71717a` (muted) | | Eyebrow | 11px | 500 | `#06b6d4` (accent) | -| Source / byline / footer | 11px | 400 | `#71717a` | +| Source / byline / footer | 12px | 400 | `#71717a` | | Body | 13px | 400 | — | -| Axis tick / small | 11px | 400 | — | +| Axis tick / small | 12px | 400 | — | | Metric label | 11px | 500 | muted | | Metric value | 22px | 600 | — | @@ -167,14 +173,21 @@ Source: `packages/core/src/theme/defaults.ts` (`fonts.sizes`, `fonts.weights`, fallback stack; nothing is bundled. Monospace is JetBrains Mono, used by the `terminal` preset and any mono-family theme. +Annotation primary text defaults to 13px/400 with a 12px subtitle at that size +(the ratio is 12/13, rounded). Reference/range labels use the theme small size. +Callouts wrap within 240px or the available plot width; compact charts keep one +eligible inline callout by default and move the rest to complete numbered notes. +Curves use quiet leaders unless an arrow is authored. Explicit weights, colors, +widths, and responsive opt-outs remain authoritative. + ## Spacing, lines, and radius | Token | Default | |---|---| | `spacing.padding` | 20px | | `spacing.chromeGap` | 6px | -| `spacing.chromeToChart` | 8px | -| `spacing.chartToFooter` | 8px | +| `spacing.chromeToChart` | 16px | +| `spacing.chartToFooter` | 12px | | `spacing.axisMargin` | 6px | Hairline vs. gridline is a deliberate two-tier system: the hairline (14% @@ -392,18 +405,19 @@ the committed values diverge from the in-progress edit. ## Presets -Five named presets, exported from `@opendata-ai/openchart-core`: +Four named presets, exported from `@opendata-ai/openchart-core`, alongside the default configuration: | Preset | Palette | Background | Title | Radius | Notable | |---|---|---|---|---|---| -| `editorial` | default six-hue | white / `#09090b` | 26/600 | 8px | The default; empty `ThemeConfig` | +| Default (omit theme) | default six-hue | transparent | 26/600 | 8px | Empty `ThemeConfig`; follows the host surface | | `essay` | default | warm paper `#faf8f5` / `#1a1816` | 28/600 | 0px | Serif feel via larger sizes, generous spacing | | `wire` | default | `#ffffff` / `#0a0a0a` | 16/600 | 2px | Dense, tight chrome, dashboard feel | | `broadsheet` | `#1d5f8a #e3120b #7fb0d3 #e0a63b #3a8a6e #8c8680` | warm paper `#fffdf9` / `#171513` | 24/700 | 0px | Red masthead `rule` (40×3px) and eyebrow; hairline 0.28 alpha | | `terminal` | dark-mode categorical variants | `#0b0f14` (both modes) | 15/600 | 4px | `seriesStrategy: 'accent-neutral'`, JetBrains Mono available, dense spacing | -`editorial` is `{}` — every other theme value in this document is its -default. `broadsheet`'s slot-2 red (`#e3120b`, OKLCH chroma 0.232) is a +`editorial` has been removed; omit `theme` or use `{}` for the default. +`clarity` is deprecated and retains only its background, axis, and eyebrow +colors. `legacyEditorial` retains the v8 typography for migrations. `broadsheet`'s slot-2 red (`#e3120b`, OKLCH chroma 0.232) is a deliberate deviation from the palette's usual chroma ceiling: it's the one loud hue in an otherwise quiet ramp (the other five broadsheet slots run 0.011–0.137 chroma), kept because it still clears both CVD checks at a diff --git a/docs/generating-specs.md b/docs/generating-specs.md index 8fd98723..563ec310 100644 --- a/docs/generating-specs.md +++ b/docs/generating-specs.md @@ -23,7 +23,7 @@ export (not the main barrel, so a large JSON never lands in a consumer bundle): | Import | Covers | Use for | |--------|--------|---------| | `@opendata-ai/openchart-core/schema` | Full `VizSpec` union (every spec kind) | Plain, non-strict tool `input_schema` | -| `@opendata-ai/openchart-core/schema/chart.schema.json` | `ChartSpec` (all 16 marks) | The LLM chart workhorse; strict-mode subset | +| `@opendata-ai/openchart-core/schema/chart.schema.json` | `ChartSpec` (all 18 marks) | The LLM chart workhorse; strict-mode subset | | `@opendata-ai/openchart-core/schema/table.schema.json` | `TableSpec` | Data tables; strict-mode subset | The schemas are draft-07 and generated directly from the TypeScript spec types, @@ -36,7 +36,7 @@ import chartSchema from '@opendata-ai/openchart-core/schema/chart.schema.json' w ## Which schema to use -- **Charts** (bar, line, area, point, arc, and the rest of the 16 marks): use +- **Charts** (bar, line, area, point, arc, and the rest of the 18 marks): use `chart.schema.json`. It is the primary generation surface. - **Tables**: use `table.schema.json`. - **Anything, or "let the model pick the visualization"**: use the full VizSpec @@ -108,6 +108,18 @@ For strict modes, use a per-type **subset** schema (`chart.schema.json` or 3. Strip keywords the target API does not support (`$comment`, format annotations it rejects, etc.). +Preserve each `anyOf` branch separately, including nested mark unions. In v9, +`{ type: 'density', bandwidth: 2 }` is valid, while +`{ type: 'bar', bandwidth: 2 }` is rejected by the TypeScript contract, the +published schema, and runtime validation. Merging branch properties into one +object would erase this contract. The mark-option matrix tests the published +schema after the required-and-nullable transform for every mark and option. + +Nulls added by the strict transform represent omitted fields. Remove those +placeholder nulls before calling `validateSpec`; preserve authored nulls only for +fields whose public contract accepts them (for example `mark.tooltip`). Strict +schema transforms are provider-specific adapters, not a different chart format. + Never claim strict-mode compatibility for the full VizSpec schema — ship the subset. Measure the serialized token size of the subset against your API's limit before shipping; the ChartSpec subset is the tightest surface the library offers. @@ -117,8 +129,9 @@ before shipping; the ChartSpec subset is the tightest surface the library offers Field-level validation against the provided data is what kills the dominant failure mode (a spec that references a hallucinated column and renders an empty chart). `validateSpec` returns machine-readable errors: each carries a `code`, the -offending `path`, and a repair-friendly `suggestion`. Misspelled field names get a -nearest-column "did you mean" hint. +offending `path` as a root-relative JSON Pointer (`/encoding/y/field`), and a +repair-friendly `suggestion`. Misspelled field names get a nearest-column "did you +mean" hint. ```js const { valid, errors } = validateSpec(withData); diff --git a/docs/geographic-labels.md b/docs/geographic-labels.md new file mode 100644 index 00000000..961ded13 --- /dev/null +++ b/docs/geographic-labels.md @@ -0,0 +1,103 @@ +# Geographic labels and callouts + +Maps can show explicitly authored place names and findings. Leaving out `encoding.text`, `points.text`, and `callouts` preserves the existing map layout and adds no label geometry or inventory DOM. + +## Place names from data + +Add a `text` channel to the feature encoding or point layer: + +```ts +const spec: GeoMapSpec = { + type: 'map', + geo: { features: topology, projection: 'albersUsa', zoom: true }, + data: [ + { id: '48', place: 'Texas triangle', population: 31, priority: 10 }, + { id: '06', place: 'California coast', population: 39, priority: 8 }, + ], + encoding: { + key: { field: 'id', type: 'nominal' }, + color: { field: 'population', type: 'quantitative', title: 'Population (millions)' }, + text: { field: 'place', type: 'nominal' }, + textPriority: { field: 'priority', type: 'quantitative' }, + }, +}; +``` + +The topology and data are supplied by the host. A feature's requested text field is read from its joined row, or from the same explicitly named topology property when the row does not provide that property. An explicit null does not become a guessed topology name. Point names come from the point data and require a unique `points.key`. + +Higher finite `textPriority` values place first. Point labels otherwise use their size value as priority. Equal priorities use stable tagged identities, so input reordering does not arbitrarily change collision winners. Placement is bounded to 200 text candidates per view; this is a safety limit, not an exact top-N selection feature. All names remain in the inventory even when they cannot be painted. + +## Authored findings + +Use `callouts` for explanatory text or a coordinate-only place: + +```ts +spec.callouts = [ + { + id: 'texas-growth', + anchor: { kind: 'feature', id: '48' }, + text: 'The Texas triangle', + subtitle: 'An explanation that remains available when its label cannot fit.', + priority: 10, + maxWidth: 220, + }, + { + id: 'austin-detail', + anchor: { kind: 'coordinate', space: 'geographic', x: -97.7431, y: 30.2672 }, + text: 'Austin', + minZoom: 3, + }, +]; +``` + +Each callout needs a unique nonblank string ID, an anchor, and plain text. Optional fields are `subtitle`, finite `priority`, `minZoom`, `maxZoom`, `offset: { dx, dy }`, and positive `maxWidth`. Zoom limits are relative to the base map; the upper bound is inclusive. Offsets and widths use screen CSS pixels. + +| Anchor | Meaning | +| --- | --- | +| `{ kind: 'feature', id }` | The topology feature ID, using the map's canonical ID matching | +| `{ kind: 'point', id }` | A value of the authored `points.key`, in a separate namespace from feature IDs | +| `{ kind: 'coordinate', space: 'geographic', x, y }` | Longitude/latitude through the map's geographic projection | +| `{ kind: 'coordinate', space: 'source', x, y }` | Coordinates in a preprojected identity map's source system, before fit | + +Do not use longitude/latitude on a preprojected identity map or assume source coordinates are geographic. Those mismatches are rejected. Numeric `1` and string `"1"` identify the same key within an entity namespace; ambiguous duplicate keys are rejected when geographic labels need persistent identity. Missing targets retain their exact authored text with an unresolved-anchor explanation. + +Callouts place before ordinary place names. Text avoids keys, zoom controls, accepted labels, and point symbols. When a callout cannot fit, it moves to its numbered note slot with a keyed anchor marker when possible. The engine measures complete authored note capacity before fitting the geography; unused slots can leave reserved space. Panning and zooming never change that reserve or refit the map. Visual placement considers at most 128 callouts; additional callouts retain complete note slots and inventory entries. For a fixed-height figure that cannot accommodate its notes, inspect the diagnostic and increase the height or reduce authored content. The complete text remains accessible even when the fixed frame cannot paint it. + +These callouts do not participate in Cartesian annotation editing or emit edit transactions. + +## Access to every name + +Every labeled map has a visually hidden inventory associated with the SVG's accessible description. It includes exact custom names, callout subtitles, coordinates, unresolved targets, and names omitted by collisions or zoom limits. Entries are text rather than hundreds of additional tab stops. + +To offer a visible list, supply a separate host-owned container: + +```ts +const map = createGeoMap(mapElement, spec, { + labelInventory: { container: placesElement }, +}); + +// Move or hide the visible disclosure without resetting the camera. +map.setLabelInventory({ container: anotherPlacesElement }); +map.setLabelInventory(false); +``` + +The native “Map places and notes” disclosure works independently of reader comparison. Opening it changes only the host's list area, not the SVG dimensions or projection. React, Vue and Svelte `GeoMap` components accept the same `labelInventory` prop. Omission or `false` hides the visible disclosure while retaining the hidden inventory. The library removes only the list nodes it owns on update or destruction. + +## Camera, geometry, and export + +Labels keep a constant screen size while the camera moves. During a gesture, accepted identities follow their anchors and boxes leaving the viewport are hidden. At settlement, placement is recomputed from the current camera, viewport, and compiled measurements. Reaching the same view by a different pan/zoom history produces the same settled placement and export. + +Feature anchors use proven polygon interiors, including holes and visible multipolygon components. Label geometry comes from the same projection stream as the rendered feature paths; it is not reconstructed from SVG strings. The retained geometry budget is 50,000 vertices per view. Excess candidates use previously validated canonical anchors while those anchors are visible, with a diagnostic describing the inability to switch visible components. Rings and holes are never silently truncated to fit the budget. Topology, ring nesting, and interior-search work are bounded separately. Anchors are checked against the complete feature’s nonzero fill, including overlapping polygon groups; ambiguous or numerically degenerate rings cause conservative omission rather than a label on unfilled space. The same proof applies after camera clipping. + +The transient ring collector also has a 100,000-vertex limit per feature. Denser features use a second streaming pass to verify a bounded set of interior probes without retaining rings. If no probe can be proven inside land, the feature label is omitted with an explanation; authored text remains in the inventory. This bounds the label collector, not the host's source topology or the projection library's own buffers. The engine's `compileGeoMap` diagnostic callback reports compile-time limits; pure `resolveGeoOverlay` results also contain camera-dependent diagnostics. + +SVG and raster exports include settled place labels, leaders, and notes. SVG descriptions also contain the complete inventory. They do not screenshot the visible HTML disclosure. `renderStaticSVG` also accepts `GeoMapSpec`; supply a stable, distinct `idPrefix` when embedding multiple static figures in one document: + +```ts +const first = renderStaticSVG(spec, { width: 960, height: 700, idPrefix: 'map-one' }); +const second = renderStaticSVG(otherSpec, { width: 960, height: 700, idPrefix: 'map-two' }); +``` + +Prefixes must start with a letter or underscore and contain only letters, digits, underscores, periods, or hyphens. Without a prefix, each standalone render retains deterministic IDs. Static rendering still uses the existing serialized rendering contract. + +The [geographic-label gallery](../examples/src/gallery/geo-labels.stories.tsx) demonstrates place names, zoom-gated callouts, a host-placed disclosure, data replacement, and multiple maps. The [migration guide](migrating-v9.md) separates these opt-ins from v9's approved default visual changes. diff --git a/docs/getting-started.md b/docs/getting-started.md index 4ac34b47..4e430f38 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -108,7 +108,7 @@ const spec = { The `encoding` object maps data fields to visual channels. `type` tells the engine how to interpret the values: `temporal` for dates, `quantitative` for numbers, `nominal` for categories. -The chart component fills its parent container. Set width and height on the wrapper element. +Set the wrapper width to the desired embed width. An explicit height supplies the figure budget; omitted `chromeLayout` can grow it by the note band. Set `chromeLayout: 'subtract'` for an exact-height slot. Without a height constraint, the mount uses a 400px visualization budget and adds chrome. See this running: [live example](https://tryopendata.github.io/openchart/?story=charts--line-and-area#single-line) @@ -151,7 +151,7 @@ chrome: { ## Change mark type -Swap `mark: 'line'` for any supported mark type. The encoding channels stay the same, the engine handles the rest. +Swap `mark: 'line'` for any supported mark type. Use the channels required by the new mark: arc, waffle, and parliament use `theta` for values; positional marks use `x`/`y`. Mark-specific options must belong to the chosen mark. ```tsx const spec = { @@ -284,7 +284,7 @@ Dark mode adapts the theme automatically: background, text colors, gridlines, ax ## Custom theme -Override any part of the default theme with a `ThemeConfig` object. The engine deep-merges your overrides onto the defaults, so you only specify what you want to change. +Override any part of the default theme with a `ThemeConfig` object. Spec, provider, and component themes deep-merge in that order; nested fields survive and arrays/color pairs replace atomically. Mount options have highest precedence. Only authored overrides are stamped inline, so omitted CSS tokens remain available to host styles. ```tsx import { Chart, VizThemeProvider } from "@opendata-ai/openchart-react"; @@ -349,7 +349,7 @@ Theme config options: | Property | What it controls | | -------------------- | ----------------------------------------------------- | | `colors.categorical` | Array of CSS color strings for series differentiation | -| `colors.background` | Chart background color | +| `colors.background` | Chart and table background (transparent by default) | | `colors.text` | Default text color | | `colors.gridline` | Gridline color | | `colors.axis` | Axis line and tick color | @@ -594,7 +594,7 @@ const chart = createChart( }, { darkMode: "auto", - responsive: true, + autoResize: true, }, ); @@ -618,7 +618,7 @@ chart.destroy(); | `export(format)` | Export as `'svg'`, `'png'`, `'jpg'`, `'gif'` (animated, needs the optional `gifenc` peer), or `'csv'` | | `destroy()` | Remove DOM elements, disconnect observers | -Responsive mode (enabled by default) uses a `ResizeObserver` on the container, so charts resize automatically when the container changes size. +`autoResize` (enabled by default) uses `ResizeObserver` so charts resize with their container. The spec `responsive` field controls layout adaptation, not observation. For transaction-based editing and changed defaults, see [Migrating to v9](migrating-v9.md). ### Table @@ -640,7 +640,7 @@ const table = createTable( pagination: { pageSize: 20 }, }, { - responsive: true, + autoResize: true, onRowClick: (row) => console.log("Clicked:", row), onStateChange: (state) => { // { sort, search, page } diff --git a/docs/integration-guide.md b/docs/integration-guide.md index d995f192..6cf663b5 100644 --- a/docs/integration-guide.md +++ b/docs/integration-guide.md @@ -327,7 +327,7 @@ import { VizThemeProvider, Chart, DataTable } from "@opendata-ai/openchart-svelt ``` -Each framework uses its native context system (React context, Vue provide/inject, Svelte context). A `theme` prop on a component takes precedence over the context theme. +Each framework uses its native context system (React context, Vue provide/inject, Svelte context). A component `theme` prop deep-merges over the context theme, preserving unrelated nested provider values. Arrays and light/dark pairs replace atomically. ### Reading the theme in custom components @@ -394,7 +394,7 @@ createGraph(container, graphSpec, { watermark: false }); createSankey(container, sankeySpec, { watermark: false }); ``` -Spec-level `watermark` takes precedence over the mount option when both are set. +The mount `watermark` option takes precedence over the spec and active breakpoint values when both are set. Chart-family specs also auto-hide the watermark when the compiled container is under 200px tall — chrome is already hidden at that height, so the brand band would paint over the plot. Set `watermark` explicitly (top level or in an active breakpoint override) to opt back in; an explicit `watermark: true` in that cramped state reserves a compact brand band instead of overlapping the chart. This auto-hide is scoped to charts — sankey, tilemap, graph, geo-map, and table watermarks are unaffected and still need an explicit `watermark: false`. @@ -576,6 +576,43 @@ import type { MarkEvent } from "@opendata-ai/openchart-core"; // event.event - the raw browser MouseEvent ``` +### Interaction mode + +The `interaction` mount option (and wrapper prop) sets what a reader can do with +chart elements: + +| Mode | Selection | Edit gestures (drag, nudge, delete, text) | Arrow keys | +| --- | --- | --- | --- | +| `'read'` | None | None | Reader data navigation | +| `'select'` | Click and Tab; `onSelect`/`onDeselect` fire | None | Reader data navigation | +| `'edit'` | Click and Tab | All, emitted through `onEdit` | Nudge the selection | + +When `interaction` is omitted it is inferred once per mount: an `onEdit` handler +gives `'edit'`, otherwise `onSelect`/`onDeselect` give `'select'`, otherwise +`'read'`. Selection callbacks alone never enable text editing. + +```tsx + +``` + +Vue uses `:interaction="'edit'"`, Svelte uses `interaction="edit"`. Every +`ElementRef` passed to `onSelect`, `onDeselect` and `onAnnotationClick`, or +returned by `getSelectedElement()`, carries a JSON Pointer `path` (`/chrome/` +for chrome, `/legend` for the legend and its entries). `chart.isTextEditing` is +true while the inline text editor is open. + +### Persisting edits + +In edit mode, `onEdit` receives one `EditTransaction` per committed gesture. +Apply it atomically with `applyEditTransaction` from core, persist the returned +spec, and retain the inverse for undo. A rejected transaction leaves the original +unchanged. Do not persist transient selection, note emphasis, or legend visibility +as gesture edits. Cancelled pointer gestures emit nothing. + +React uses `onEdit`, Vue uses `@edit`, and Svelte uses `onedit`. The former +`onEditTransaction` and element-edit callbacks are removed. See the complete +[persistence example and keyboard contract](migrating-v9.md#editing-and-keyboard-navigation). + ### Click-to-drill-down pattern ```tsx @@ -931,7 +968,7 @@ import { useTable } from "@opendata-ai/openchart-react"; function AdvancedTable({ spec }: { spec: TableSpec }) { const { ref, table, state } = useTable(spec, { onRowClick: (row) => console.log("Clicked:", row), - responsive: true, + autoResize: true, }); return ( @@ -953,7 +990,7 @@ import { useTable } from "@opendata-ai/openchart-vue"; const { containerRef, table, layout } = useTable(spec, { onRowClick: (row) => console.log("Clicked:", row), - responsive: true, + autoResize: true, }); @@ -971,7 +1008,7 @@ import { useTable } from "@opendata-ai/openchart-svelte"; const { action, table, layout } = useTable(spec, { onRowClick: (row) => console.log("Clicked:", row), - responsive: true, + autoResize: true, }); @@ -1002,13 +1039,13 @@ The responsive system also uses breakpoints to adjust layout strategy at smaller - **Label density**: Fewer labels at smaller widths to avoid overcrowding - **Legend position**: May shift from inline to top/bottom at narrow widths - **Annotation placement**: Adjusts for available space -- **Tables**: Auto-apply compact mode at small breakpoints +- **Tables**: Adapt density and switch to the chosen mobile layout ### Container sizing The `` and `` components render a wrapper div set to `width: 100%; height: 100%`. They fill whatever container you put them in. -For charts, the container needs an explicit height (charts don't have intrinsic height): +An explicit height supplies the chart's figure budget. To keep an exact outer height even when annotations produce notes, set `chromeLayout: 'subtract'` on the spec. Without a height constraint, charts use a 400px visualization budget and add chrome: ```tsx { @@ -1029,7 +1066,7 @@ For charts, the container needs an explicit height (charts don't have intrinsic ; { - /* Won't work: no height constraint, chart collapses to minimum */ + /* Automatic height: 400px visualization budget plus chrome */ }
@@ -1052,7 +1089,7 @@ createChart(container, spec, { autoResize: false }); ### Forcing size for export -When you need a chart at specific dimensions (for image export, thumbnails, etc.), set the container to the exact size you want, disable responsive, and export: +For exact export dimensions, set the container size, use `chromeLayout: 'subtract'` to prevent note-band growth, and disable automatic resize: ```ts const container = document.createElement("div"); @@ -1060,7 +1097,7 @@ container.style.width = "1200px"; container.style.height = "800px"; document.body.appendChild(container); -const chart = createChart(container, spec, { autoResize: false }); +const chart = createChart(container, { ...spec, chromeLayout: 'subtract' }, { autoResize: false }); const pngBlob = await chart.export("png", { dpi: 2 }); chart.destroy(); @@ -1346,7 +1383,7 @@ import { createTable } from "@opendata-ai/openchart-vanilla"; const table = createTable(container, tableSpec, { darkMode: "auto", - responsive: true, + autoResize: true, onRowClick: (row) => console.log(row), onStateChange: (state) => { // state: { sort: SortState | null, search: string, page: number } @@ -1551,7 +1588,7 @@ import { createGraph } from "@opendata-ai/openchart-vanilla"; const graph = createGraph(container, graphSpec, { darkMode: "auto", - responsive: true, + autoResize: true, onNodeClick: (node) => console.log("Clicked:", node), onNodeDoubleClick: (node) => console.log("Double-clicked:", node), onSelectionChange: (nodeIds) => console.log("Selected:", nodeIds), diff --git a/docs/migrating-v9.md b/docs/migrating-v9.md new file mode 100644 index 00000000..b2660ffa --- /dev/null +++ b/docs/migrating-v9.md @@ -0,0 +1,579 @@ +# Migrating to OpenChart v9 + +v9 makes the annotation layout options introduced in 8.9.1 the default, consolidates theme precedence, and removes the deprecated authoring and editing APIs. Upgrade all six OpenChart packages together. This guide covers the library; OpenStudio's document envelope, migration dialog, and adoption are separate work. + +## How to use this guide + +If you are upgrading from v7 or earlier, work through [the v8 migration guide](migrating-v8.md) first. This guide starts from v8.9.1. Unlike v8's deprecation period, v9 rejects the retired spec forms listed below; it does not silently rewrite them during compilation. + +1. Upgrade the OpenChart packages your app uses to the same 9.x version. Update your lockfile and run TypeScript before changing stored documents. +2. Run `migrateSpecV8` on a copy of each older spec and review its repairs. Choose whether to preserve v8 styling or adopt the new defaults. +3. Update callbacks, imports, wrapper props, and host CSS using the sections below. The spec migration cannot change application code. +4. Review narrow and exact-height embeds, edit/undo flows, and exports before saving migrated documents. + +A useful first search in your application source is: + +```sh +rg 'onEditTransaction|onAnnotationEdit|onTextEdit|ElementEdit|onDataPointClick|updateVisuals|footnoteBandHeight|TOP_PAD_NARROW_MAX|LABEL_GAP_NARROW_MAX|oc-table--compact' +``` + +Also inspect `responsive` in mount options or component props (every mount family, see [Interaction mode, chart specs, and resize options](#interaction-mode-chart-specs-and-resize-options)), `compact` in tables, `valueFormat` in specialized specs, `Theme` imports, and `labels.offsets`. Those names have valid uses elsewhere, so do not replace them globally. + +## Choose how older documents should look + +Run the public engine migration on the original authored document, before compiling it: + +```ts +import { migrateSpecV8 } from '@opendata-ai/openchart-engine'; + +// Default: rewrite retired fields and materialize former v8 styling defaults. +const preserved = migrateSpecV8(legacyDocument); + +// Rewrite retired fields, leaving omitted defaults to v9. +const adopted = migrateSpecV8(legacyDocument, { styling: 'v9' }); + +// Present these changes to the author or record them with the document. +console.table(preserved.repairs); +const spec = preserved.spec; +``` + +The helper is pure and idempotent. Repairs report `path`, `from`, `to`, and `reason`. Explicit authored values, including `false` and `null` opt-outs, remain authoritative. Keep the original document until you have reviewed and saved the result. The helper migrates spec data; it cannot rewrite JavaScript callbacks, TypeScript imports, or host CSS. + +The default styling mode writes former annotation weights, subtitle sizes, curve arrows, unlimited wrapping/compact limits, legacy reference anchors, `chromeLayout: 'subtract'`, and v8 theme typography, spacing, and annotation colors. Endpoint controls are materialized at their released v8 values: 13px names, 12px values, 6px entry spacing, 4px name/value spacing and an 18px column gap. `legacyEditorial` remains available for v8 typography alone; it is not a full document migration. + +**Keeping v8 styling does not promise pixel-identical v8 layout.** Placement scoring, note numbering, theme composition, rich-text notes, and other v9 layout rules still apply. Review migrated charts at their actual embed sizes. In particular, the legacy series-label rewrite moves labels into the endpoint column and drops manual per-series offsets; each dropped offset appears in `repairs`. + +## Value labels, endpoint correctness, and chart craft + +Value labels now use the resolved theme font in horizontal bars, vertical columns, lollipop/dot plots and dumbbell ranges. Pie labels already did so. This fixes the former hardcoded system font. Even the default migration cannot preserve that font mismatch independently: there is no value-label-only font-family control. Its theme repair records the limitation when applicable, and repeated migration remains idempotent. To use a system font throughout a chart, author `theme.fonts.family`; this also changes its axes and chrome. Review custom-font charts and exported labels. + +Adaptive horizontal bars also check the complete formatted text width before putting a value inside a mark, including at large font sizes. If neither inside nor outside fits, the value stays available in accessible data and tooltips instead of overflowing. Negative column labels now follow the source number even when the formatted value uses a Unicode minus or omits its sign. Endpoint values share precision across the displayed field, measure all formatted values, and honor the host text measurer. Explicit endpoint formatting still wins, followed by the existing channel/axis format. These correctness fixes can change text width and placement in migrated documents. They do not change source observations or units. + +Endpoint budgeting now includes both columns, their gaps, date context and the final axis reservations. Automatic endpoints can yield to the existing legend or requested keyed summary to retain a usable plot. Explicit endpoint choices remain authoritative; an impossible fit emits an `onDiagnostic` message at `/endpointLabels`. Rotated y-axis titles also keep their full glyph ascent inside the figure, including with enlarged fonts. + +Bar placement and interior names remain opt-in. The approved defaults below change grid/zero hierarchy, stacked-area endpoint anchors, static map keys and map borders. Bar/column proportions, endpoint sizes/gaps and the no-data hatch retain their previous values. + +### Bar and column placement + +`labels.placement` accepts `'adaptive'`, `'inside'`, `'outside'` or `'column'` on bar marks. Omission uses adaptive placement. Inside labels are hidden when their complete text box cannot fit; their values remain in accessible data and tooltips. Outside labels follow the positive or negative endpoint, with space reserved before scales are computed. + +In a short fixed-height figure, outside labels yield to suppression if their reserves would leave less than the usable plot height after axes, chrome, notes and headers. The diagnostic identifies `/labels/placement`; values remain available through tooltips and accessible data. + +A value column is for simple horizontal bars with one value per category. It is unsupported on vertical, grouped or stacked bars. It measures the complete formatted values, including affixes, and reserves that width plus 12px. Facets share the measurement and align columns. If it cannot retain a usable plot, the entire chart falls back to outside labels, then suppression if necessary, with an `onDiagnostic` message at `/labels/placement`. + +```ts +{ + mark: 'bar', + data: [{ department: 'Research', budget: 128.4 }, { department: 'Operations', budget: 75.2 }], + encoding: { + x: { field: 'budget', type: 'quantitative', axis: false }, + y: { field: 'department', type: 'nominal', axis: { grid: false } }, + }, + labels: { placement: 'column', format: '.1f', suffix: 'M' }, +} +``` + +Dot/lollipop, range and pie marks reject explicit placement at `/labels/placement`; their existing label configuration remains supported. + +### Optional bar row inspection + +Pass `{ rowHover: true }` to `createChart` or the `rowHover` prop on any Chart wrapper. Pointer inspection spans the category, plot and value-column zones; the existing keyboard navigation highlights the same row. It applies to simple horizontal bars, and yields to editing. Omission adds no hover presentation. Grouped, stacked, layered and faceted charts retain their existing behavior. The highlight is transient and does not appear in settled chart exports. + +### Stacked-area identification + +Stacked areas now anchor endpoints at the band midpoint. Interior series names remain opt-in: + +```ts +endpointLabels: { anchor: 'band', placement: 'interior' } +``` + +Omitted placement remains `'end'`; the anchor default is now `'band'`. Set `anchor: 'boundary'` to retain cumulative-edge anchors; `migrateSpecV8` materializes this when preserving v8 styling. Band anchoring places the series' own endpoint value at the middle of its compiled band. It leaves the mark's hover/crosshair points unchanged. Interior labels identify series by name; they do not select a new numerical observation. A series without a fitting interior box retains endpoint identification. Missing and synthetic pivot rows do not become observed zero labels, and endpoints on different dates retain date context. + +Layers with independent y-scales fall back from interior names to endpoint names with a diagnostic: one independently scaled band can cover another's accepted text box. This choice happens before the shared columns are measured. Band anchors, value formats and leading/trailing settings remain authored, and band leaders remain visible on the assembled chart. + +Independent-layer legends now measure the complete eligible series set before the shared frame is fixed. Authored hiding, row and symbol limits remain in force; previously overflowing wrapped keys can reserve more space. + +Stacked-area domains now cover the complete bands, including when stacking is omitted and the existing area default applies. Independent scales no longer pin stacked data to raw row extrema. This corrects clipped bands; it can change axes and geometry in older affected charts. `stack: null` or `false` still requests overlapping areas. Endpoint collision placement also separates labels whose natural anchors lie above the visible domain when the label stack fits. + +### Horizontal axis-title headers + +Use the existing axis vocabulary to put a y-axis title above its top tick: + +```ts +encoding: { + y: { + field: 'revenue', type: 'quantitative', + axis: { title: 'Revenue per customer ($)', titleAngle: 0, titleAnchor: 'end' }, + }, +} +``` + +Rotated y-axis titles also receive enough left-edge clearance for their SVG alphabetic baseline. Previously, large text could clip past the figure edge. This correctness fix can move a migrated title while keeping its plot, ticks and observations unchanged; migration does not restore that clipping. + +The engine measures and reserves the header, including wrapping, before scales and placement. Omission keeps the rotated title. This example documents the header combination; inspect other authored title angles at the actual embed size. + +### Map legend positions and theme controls + +Point category keys now paint in their resolved legend band. v8 could reserve a top band while painting that key at the bottom; omission now correctly paints at the top. Migration does not preserve that misplaced-key bug. Authoring `legend.position: 'bottom'` requests a real bottom reservation, so it can also change map geometry and is not a pixel-identical substitute. Review maps with categorical point keys after migration. + +Maps now honor `legend.position: 'right'` and `'bottom-right'` as a measured side gutter. Both previously type-checked but rendered at the top, so documents already setting them change appearance. A side key that cannot fit falls back to the top with a diagnostic. Top/bottom behavior stays available; `'top-left'` retains its existing point-key overlay meaning, and unsupported map `'inline'` warns and uses a top band. Projection proportions and geographic coverage are preserved. + +Endpoint typography and spacing are theme controls with the current, released-v8 numerical values: + +```ts +theme: { + fonts: { sizes: { endpointLabel: 13, endpointValue: 12 } }, + spacing: { endpointEntryGap: 6, endpointValueGap: 4, endpointColumnGap: 18 }, +} +``` + +Map authors may set `colors.mapNoDataFill`, `mapNoDataHatch`, `mapInteriorBorder` and `mapOutlineBorder`, including light/dark color pairs. Omission uses the quieter v9 borders and the existing map palette and pattern treatment. Keep no-data patterns distinguishable from valid zero and diverging midpoints. These controls do not introduce an automatic crop, drop regions, reorder points or transform measures. + +## Changed annotation and figure defaults + +**Who is affected:** Charts relying on omitted styling, wrapping, placement, or height options. These are deliberate default changes and do not produce deprecation warnings. Use explicit settings from the table below or the default migration mode to retain the former authored styling. + +| Setting | v8 default | v9 default / explicit override | +| --- | --- | --- | +| Small and axis tick text | 11px | 12px; set `theme.fonts.sizes.small` / `axisTick` explicitly | +| Source, byline, footer | 11px | 12px; set `theme.chrome..fontSize` | +| Chrome-to-chart / chart-to-footer gap | 8px / 8px | 16px / 12px; set the corresponding `theme.spacing` fields | +| Subtitled callout primary weight | 700 | 400; set `fontWeight: 700` for a bold lede | +| Subtitle size | `round(fontSize * 0.85)` | `round(fontSize * 12 / 13)`; set `subtitleFontSize` to override | +| Curve connector arrow | Implied | Off; use `connector: { type: 'curve', arrow: true }` | +| Labeled reference line | Legacy anchor placement | Automatic placement if neither `labelPlacement` nor `labelAnchor` is authored | +| Callout wrapping | Unlimited | Up to `min(240, plotWidth - 2 * padding)` pixels, with a positive minimum; `maxWidth: null` disables wrapping limits | +| Compact inline callout limit | Unlimited | One eligible text callout; `responsive.compactAnnotationLimit: null` removes this count limit | +| Reference/range label size | 11px | Theme `small`; explicit annotation `fontSize` wins | +| Reference rule ink | `#666666` in both modes | `#888888` light / `#9ca3af` dark | +| Range fill | `#000000` | `#f0c040`; opacity behavior is unchanged | +| Marker/label-plate fill | Fixed white / near-black | Resolved neutral surface, unless explicitly authored | + +Callouts with `responsive: false` remain inline and do not count toward the compact limit. Annotations written in `overrides.compact.annotations` are exempt from the default limit; an explicit `responsive.compactAnnotationLimit` still applies to them. The limit uses the **outer container width**, including facets, at the compact breakpoint of 400px. It does not override the existing behavior of chart-level `responsive: false`, `responsive.autoThin: false`, or fixed-size specs: those still hide unpinned annotations at compact widths. Heights below 200px retain tooltip-only behavior. + +Automatic placement processes higher-priority annotations first, breaking ties by authored source order. Placement also penalizes connector crossings. Those choices can move labels even when you preserve v8 styling. Explicit offsets remain pinned, including `{ dx: 0, dy: 0 }`. + +- A text connector stops a few pixels short of its target's own value label instead of striking through it, including on callouts with explicit offsets (the label stays put). Automatic and anchor-nudged placement also prefer spots whose connector clears other value labels. The endpoint dot still sits on the data point, and a connector with too little length left before the value label is dropped. +- Default numeric tick labels use the least precision that tells the ticks apart and drop trailing zeros: `3.5 / 4 / 4.5` instead of `3.50 / 4 / 4.50`. An authored `axis.format` or field `format` is unchanged. +- A default temporal x-axis at compact widths always shows at least two ticks; it no longer collapses to a single date such as `2024`. When the compact tick cap drops the tick that names the year, the kept ticks use full labels (`Jul 2023`, `Apr 2024`) if they fit. Authored `axis.tickCount` and `axis.values` are unchanged. +- A right-lane outside reference label ends at the chrome padding, aligned with the title, source, and brand, instead of a fixed 16px from the edge. The plot narrows by the difference (1-4px at common sizes). +- Facet panels cap their top reference lane like single charts: each lane takes at most 25% of its grid row and leaves the panel its 100px minimum, admitting whole rows in source order. Labels that do not fit fall back inside the panel with the usual lane warning. A short grid still grows to its minimum height, measured with the rows that fit at that height. + +Omitting `chromeLayout` now grows the figure by its note band while title, subtitle, source, and other chrome retain their existing subtraction behavior. The internal name for this mode is `notes`; it is **not** an authored spec value. + +- Use `chromeLayout: 'subtract'` when an embed needs an exact outer height. +- Use `chromeLayout: 'grow'` to grow by all chrome, including facets. +- Read `layout.dimensions.height` for the resulting height. Engine-added height is reported in `layout.chrome.grownHeight`; mounts already account for it once. + +The note band includes annotation notes and `seriesSummary`. Its reserved source capacity stays stable during annotation drags, so it can contain unused space. Use `layout.chrome.noteBandHeight`; the old core and vanilla `footnoteBandHeight` helpers are removed. + +### Outside reference label lanes + +**Who is affected:** Charts with `labelPlacement: 'outside'` on vertical reference lines (`x` rules), and charts whose y ticks were planned without a reserved band. + +- **Rows pack.** Labels whose horizontal extents don't overlap share a row in the lane above the plot. Packing is greedy in source order, so the result is deterministic. In 8.9.1, each label had its own row, and facet panels still work that way. +- **The lane is capped.** It takes at most 25% of the requested height, which is the same basis as the 40% chrome cap. A row that doesn't fit is not admitted. Each of its labels falls back to automatic placement inside the plot on its own, and one "exceed their available lane" warning covers the whole compile. A row is reserved whole when admitted, so growing the figure past a row's threshold can shrink the plot by that row's height. The share cap bounds that step; in 8.9.1 an uncapped lane could take a 220px cliff. +- **The right lane fits its labels.** Horizontal outside labels reserve the width of the widest wrapped label (still capped at 160px or 25% of the width) instead of always reserving the cap, so the plot gets the slack back. +- **The lane yields before chrome.** When the plot would drop below its minimum, the lane shrinks first. Title and subtitle step down only if the plot still doesn't fit. In 8.9.1 the subtitle could be dropped to keep a label lane. +- **Tick counts can change.** The layout plan now sizes y ticks against the same margin stack as the final layout: the reference lane, metric bar, series-search band, and (with `chromeLayout: 'subtract'`) the note band. Charts with those bands can get a different number of y ticks than in v8, which planned for a taller plot than it drew and could pack ticks 16px apart. When d3's round steps would leave fewer than three default ticks, v9 asks for a denser set as long as ticks stay at least 20px apart. + +### Endpoint markers and curved connectors + +**Who is affected:** Line charts with `endpointLabels.showMarker`, and annotations with `connector: 'curve'`. + +- Endpoint markers now sit centered on the line's last (or first) point, the same x as hover dots, the crosshair and annotation anchors. In 8.9.1 they were offset by their radius. The default marker fill is the opaque canvas color instead of the theme background, so the ring covers the line end; set `endpointLabels.markerStyle.fill` to keep a transparent ring. +- A text annotation whose default dot lands on an endpoint marker takes the marker's colors, so the point draws one ring. +- Curved connectors are shaped to the data point and shortened along their end tangent, so the tail aims at the marker. + +### Table surface + +Tables paint `theme.colors.background` (transparent by default) like charts do, instead of the mode's opaque `--oc-bg`, so a table sits on the host surface. The header, totals row, search input and pager buttons are transparent too; the opt-in sticky first column keeps `--oc-bg` so scrolled cells don't show through. Inline bar fills render at 40% opacity in dark mode (18% in light). Set a `theme.colors.background` to get an opaque table back. + +## Notes and annotation identity + +Notes include the complete primary text and subtitle, with wrapping and `**bold**` spans. Numbers are source-order ordinals of text annotations, assigned before filtering and thinning. Gaps are intentional: note 4 remains note 4 when another note is hidden. Inserting, deleting, or reordering authored annotations can renumber them. Facet instances share one source number and note. + +Notes and their markers support linked focus/click/tap emphasis. This is transient reader state, not a spec edit, and is excluded from exports. Authored unique annotation IDs remain the recommended durable identity. Missing or duplicate IDs use revision-local source indices and produce diagnostics. + +A label drag converts resolved placement into an explicit anchor/offset and sets `responsive: false` in one transaction. The annotation then stays inline on narrow screens; the position is clamped and can overlap other pinned annotations. Changing the data attachment remains a separate operation. + +### Editing and keyboard navigation + +**Search for:** `onEditTransaction`, `onAnnotationEdit`, `onTextEdit`, `ElementEdit`, and any `onEdit` handler that expects a single legacy element edit. Change the handler to consume the complete transaction, rather than reading the former payload fields. + +`onEdit` now receives an `EditTransaction`. The old `ElementEdit` union and the +additive `onEditTransaction` callback are removed. Apply the complete transaction +atomically; its inverse supports one undo entry per gesture. + +```ts +// v8 additive API +createChart(container, spec, { onEditTransaction: persist }); + +// v9 +import { applyEditTransaction } from '@opendata-ai/openchart-core'; + +const chart = createChart(container, spec, { + onEdit(transaction) { + const result = applyEditTransaction(spec, transaction); + if (!result.ok) return; // Stale or invalid target: keep the current document. + spec = result.spec; + undoStack.push(result.inverse); + chart.update(spec); + }, +}); +``` + +React uses `onEdit`, Vue uses `@edit` (or `onEdit`), and Svelte uses `onedit`. +`revision` still cancels an active gesture when the document revision changes. +Selection and transient visibility remain separate: use `onSelect`, `onDeselect`, +and `onLegendToggle`; legend toggles do not emit durable transactions. + +In edit mode, arrow keys nudge the selected text annotation 1px; Shift+arrow nudges +10px. Tab/Shift+Tab cycle editable elements; past the last (or first) element +the selection clears and focus leaves the chart normally. A sequence of nudges +commits 500ms after the last arrow release, or immediately before selection, +another gesture, cancellation, or focus leaving the chart. Native text-editing +keys keep their usual behavior. + +Edit mode (`interaction: 'edit'`, or an `onEdit` handler) replaces reader keyboard +navigation, because arrow keys nudge instead of moving between data points. +Select mode (`onSelect`/`onDeselect` alone) keeps reader navigation. See +[Interaction mode](#interaction-mode-chart-specs-and-resize-options). + +Removed APIs and their replacements: + +| Removed | Replacement | +| --- | --- | +| `onAnnotationEdit`, `onTextEdit` | `onEdit` transaction operations | +| `onDataPointClick` | `onMarkClick` (the old callback had no effect) | +| Chart mount/wrapper `responsive` option | `autoResize` (spec `responsive` is unchanged) | +| Graph `updateVisuals()` | `update()` | +| `ElementRef` series-label variant and `elementRef.seriesLabel()` | Endpoint labels; manual endpoint-label offsets are not supported | + +For Chart mounts, move only the resize option: + +```ts +// v8: mount option +createChart(container, spec, { responsive: false }); +// v9: mount option; spec.responsive keeps its annotation behavior +createChart(container, spec, { autoResize: false }); +``` + +Other mount families rename the same option; see +[Resize option on every mount](#resize-option-on-every-mount). + +`applyEditTransaction` validates the whole operation list before returning a new spec. A failed transaction leaves the input unchanged. Annotation `expect` preconditions carry identity/type/text checks, so a stale edit cannot silently target a reordered ID-less annotation. The helper does not compare `revision`; hosts may use it for their own bookkeeping. + +## Interaction mode, chart specs, and resize options + +**Who is affected:** Hosts that pass `editable`, read `isEditing`, rely on selection callbacks to enable text editing, pass a graph spec to ``/`createChart`, or pass `responsive` to a table, graph, sankey, tilemap, map, or barlist mount. + +**Search for:** + +```sh +rg '\beditable[:=]|\beditable=\{|\.isEditing\b|responsive:\s*(true|false)|responsive=\{' +rg ']*spec=\{[^}]*[Gg]raph|createChart\([^)]*[Gg]raph' +``` + +### Interaction mode + +The `editable` mount option and wrapper prop are removed. Use `interaction`, one of `'read'`, `'select'`, or `'edit'`: + +| Mode | Selection | Edit gestures (drag, nudge, delete, text) | Arrow keys | +| --- | --- | --- | --- | +| `'read'` | None, including `select()` and `selectedElement` | None | Reader data navigation | +| `'select'` | Click and Tab; `onSelect`/`onDeselect` fire | None | Reader data navigation | +| `'edit'` | Click and Tab | All, emitted through `onEdit` | Nudge the selection | + +When `interaction` is omitted it is inferred once per mount: `onEdit` gives `'edit'`, otherwise `onSelect`/`onDeselect` give `'select'`, otherwise `'read'`. Wrappers recreate the chart when `interaction` or the presence of those listeners changes, including Vue's `@select`/`@deselect` (previously read only at setup). `interaction: 'edit'` without `onEdit` warns once, because gestures have nowhere to send transactions. `youDrawIt`, chart stories, and `seriesSearch` suppression all use the resolved mode, so `interaction: 'read'` keeps a youDrawIt chart drawable even when an `onSelect` handler is passed. + +**Behavior change:** in v8, selection callbacks alone enabled double-click and Enter text editing. In v9 that is select mode, which never edits; pass `interaction: 'edit'` (with `onEdit`) to keep text editing. + +```ts +// v8 +createChart(container, spec, { editable: false, onEdit, onSelect }); + +if (chart.isEditing) return; + +// v9 +createChart(container, spec, { interaction: 'read', onEdit, onSelect }); + +if (chart.isTextEditing) return; +``` + +`editable: false` maps to `interaction: 'read'`; `editable: true` maps to `interaction: 'edit'`. Vue uses `:interaction="'edit'"`, Svelte uses `interaction="edit"`. `ChartInstance.isEditing` is renamed `isTextEditing`; it still means the inline text editor is open. `InteractionMode` and `resolveInteractionMode` are exported from the vanilla package (the type is also re-exported by each wrapper). + +### Chart specs only + +`` (React, Vue, Svelte), `useChart`, `createChart`, `ChartInstance.update()`, `beginManualUpdate()`, and chart stories accept `ChartSpec | LayerSpec`. A graph spec passed there already threw at compile time; now TypeScript rejects it. Render graphs with ``/`createGraph`, or `` when the spec type varies. + +```tsx +// v8 (type-checked, failed at runtime) + +// v9 + +``` + +### Resize option on every mount + +Every mount family now names the resize option `autoResize`, matching Chart. Spec-level `responsive` (annotation and chart responsiveness) is unchanged. + +```ts +// v8 +createTable(container, spec, { responsive: false }); +createGraph(container, spec, { responsive: false }); +// v9 +createTable(container, spec, { autoResize: false }); +createGraph(container, spec, { autoResize: false }); +``` + +This covers `createTable`, `createGraph`, `createSankey`, `createTileMap`, `createGeoMap`, `createBarList`, and the Svelte `useGraph` composable option. The wrappers already observe resizes, so component props are unaffected. + +### Element references carry `path` + +Every `ElementRef` emitted to `onSelect`, `onDeselect`, and `onAnnotationClick`, and returned by `getSelectedElement()`, now has `path`, including refs from Tab cycling, legend entries, and programmatic `select()` calls that omitted it. Chrome refs use `/chrome/`; legend and legend-entry refs use `/legend`. Hosts that treated a missing `path` as "no authored object" should read `type` instead. + +## Theme composition + +**Search for:** `Theme` imports, `editorial` / `clarity` preset use, shallow theme spreads, and custom `--oc-*` CSS. Recheck nested overrides: previously discarded leaves now survive theme composition. + +Authored theme layers now deep-merge: spec theme, provider theme, then component prop or mount/compile option. A layer resolves two scopes. The root (chrome, axes, legend) uses the layer theme when it has one and the first leaf's theme otherwise, as a whole object, like the layer's other root properties. Each leaf's marks use the leaf theme deep-merged over the layer theme. Host overrides apply on top of both. With independent y-scales, each side's marks and its own axis also use its merged leaf theme. Shared-axis layers match v8, so migration leaves them unchanged. A v8 dual-axis chart ignored leaf themes when the layer set a theme, so migration removes those leaf themes. This preserves unrelated nested fields that a shallow merge previously discarded. + +Arrays and `{ light, dark }` color pairs replace atomically. `colors: string[]` remains shorthand for `colors.categorical`. An authored `chrome..fontSize` wins over propagation from the general `fonts.sizes` scale, even when those values originate in different layers. Presets no longer duplicate general title sizes in chrome defaults. + +```ts +import { broadsheet, mergeThemeConfig } from '@opendata-ai/openchart-core'; + +// Preserve the preset, changing only the rule length. +const wideRule = mergeThemeConfig(broadsheet, { rule: { width: 80 } }); +// Explicitly remove its rule. +const noRule = mergeThemeConfig(broadsheet, { rule: null }); +``` + +`rule` accepts a partial object or `null`. Without a preset rule, omitted width/thickness resolve to 40px/3px and color uses theme text ink. The mount/compile `watermark` option overrides spec and breakpoint values. The graph mount `legend` option also takes precedence over the spec. + +Use `ThemeConfig` for authored input and `ResolvedTheme` for compiled output; `Theme` is removed. The empty `editorial` preset is removed: omit `theme` or pass `{}`. `clarity` is deprecated for removal in v10 and now contains only its remaining background, axis, and eyebrow colors. The default background is still transparent; the default axis/eyebrow colors have not adopted clarity's colors. + +Only authored theme tokens and their derived values are stamped inline. Omitted tokens stay available to host CSS, including `--oc-border-radius`. Removing an authored override restores the host value. Dark-mode defaults come from generated CSS; authored light/dark pairs still win. SVG/raster export preserves the live CSS token values before leaving the page. See [the token guide](theming-tokens.md). + +## Retired spec forms and helpers + +Retired spec forms are now validation errors, and removed imports stop compiling. `migrateSpecV8` handles spec rewrites in either styling mode; update imports and application options yourself. + +| Removed form | Replacement | +| --- | --- | +| Table `compact: true` | `density: 'condensed'`; `false` becomes `'regular'` | +| `valueFormat` on Sankey/barlist | `encoding.value.format` | +| `valueFormat` on maps | `encoding.color.format` | +| Annotation `type: 'rule'` | `type: 'refline'` | +| Arc/waffle/parliament authoring through `encoding.y` | `encoding.theta` | +| `theme.chrome.title: '#333'` and other theme chrome strings | `theme.chrome.title: { color: '#333' }` | +| Spec `darkMode` | Mount/component `darkMode` option | +| `mark.render` | Mount/component `renderer` option | +| `encoding.radius`, `shape`, `href`, `order` | Remove them; these channels had no renderer | +| `animation: 'legacy'` / `animation.preset: 'legacy'` | Use `true` / omit `preset`; omitting animation itself still disables it | +| `labels.offsets` and legacy line-end series labels (`labels.density` no longer draws anything on line or area marks) | `endpointLabels` | +| `TOP_PAD_NARROW_MAX`, `LABEL_GAP_NARROW_MAX` imports | `NARROW_VIEWPORT_MAX` | + +For example, the migration moves specialized formatting and renames annotation aliases: + +```js +// v8 spec fragments +{ type: 'barlist', valueFormat: '$,.0f', encoding: { value: { field: 'amount' } } } +{ annotations: [{ type: 'rule', y: 0, label: 'Baseline' }] } + +// v9 +{ type: 'barlist', encoding: { value: { field: 'amount', format: '$,.0f' } } } +{ annotations: [{ type: 'refline', y: 0, label: 'Baseline' }] } +``` + +Move spec `darkMode` to the mount/component yourself: the migration removes the retired spec key and reports the repair, but cannot configure its host. Likewise, move `mark.render` to the host's `renderer` option if you still need that renderer selection. + +The spec-level chrome text shorthand **stays**: `chrome: { title: 'A title' }` is valid. Tilemap `valueFormat` also stays, including for record data with no encoding channel. `colors: string[]`, ordinary Vega-Lite sugar, and chart-type value-label configuration remain supported. + +Host table styles targeting `.oc-table--compact` must target `.oc-table--condensed` instead. `TableLayout.compact` is removed; read `density`. + +For multi-series lines, the traditional legend and endpoint column are now the two series identifiers. If both are explicitly off, the compiler emits an accessibility warning. The old fallback of setting `legend: false`, `endpointLabels: false`, and relying on line-end labels no longer renders those labels. Migration replaces that fallback with: + +```ts +endpointLabels: { content: 'label', showMarker: false } +``` + +Series ending before the last x value move to the right-edge column. Manual legacy label offsets are dropped; endpoint-label dragging is not part of v9. + +Lines whose series come from `strokeDash` alone (no color encoding) now get the same identification as color series: the endpoint column by default, and otherwise a legend with dashed line swatches, as Vega-Lite builds for `strokeDash`. Both swatches show each series' dash pattern. v8 drew line-end labels on these charts whatever the legend and endpoint settings, so migration writes the endpoint rewrite above for any of them that had labels (`labels.density` not `'none'`). As with color series, that explicit config keeps the column at the compact breakpoint, where v8 drew no labels. `detail` groups without identifying, as in Vega-Lite: it gets no legend, endpoint column, or warning. + +## Mark-specific options and field inference + +`MarkDef` is now a discriminated union. Options must belong to the authored mark: density `bandwidth`, for example, is not a bar option. Validation checks authored paths before sugar expands histogram/density, and agrees with the published JSON Schema and TypeScript union. Correct the mark or remove the inapplicable option; the migration helper does not guess the intended mark. + +A union cannot be extended with an interface. Replace: + +```ts +// v8 +interface AppMark extends MarkDef { + editorLabel?: string; +} +``` + +with: + +```ts +// v9 +import type { MarkDef } from '@opendata-ai/openchart-core'; +type AppMark = MarkDef & { editorLabel?: string }; +``` + +Builders and compilation share one field-inference function. It examines up to 50 rows, ignores nulls, and requires more than 80% agreement. Numeric strings are considered numeric before date parsing, so an untyped column containing `'2020'` is quantitative. Other strings count as dates only when they are date-shaped (ISO dates and date-times such as `'2020-01'` or `'2020-01-01T12:00Z'`, month-name dates such as `'Jan 2020'`, and slash dates) and parse, so labels like `'Product 1'` stay nominal. Set `encoding..type` explicitly when numeric-looking years should be ordinal or temporal. This avoids relying on inference for mixed columns. + +A temporal channel whose values are all date-only ISO strings (`'2020'`, `'2020-04'`, `'2020-04-01'`) now gets a UTC time scale. JavaScript parses those strings as UTC midnight, and v8 ticked them in the host's local time, so the first or last date's tick went missing and labels changed with the machine's timezone. The compiled `xInvert.scaleType` / `yInvert.scaleType` for such data reads `'utc'` instead of `'time'`. Data with a time of day, or `Date` objects, keeps the local-time scale; set `scale: { type: 'time' }` to keep local time for date-only strings. + +## Validation paths, diagnostic fixes, and annotation labels + +**Search for:** `.path` on `validateSpec` errors (string comparisons such as `'encoding.x.field'`, `startsWith('encoding.')`, or code that splits on `.`/`[`), `ValidationResult.warnings`, `markOptionWarnings`, `applySpecPatch`, `SpecPatch`, `.fix.changes`, and `label` on `type: 'text'` annotations. + +Every `ValidationError.path` is now a root-relative RFC 6901 JSON Pointer, the same form used by edit transactions, migration repairs, and diagnostics. Keys are escaped (`~` as `~0`, `/` as `~1`) and the root is `''`. Errors inside a layer carry the layer prefix; an error in a value the leaf inherits (shared `data`, or an encoding channel it does not override) points at the parent layer that authored it. `path` is always present. Messages remain prose. + +```ts +// v8 +errors.find((e) => e.path === 'encoding.y.field'); +errors.find((e) => e.path === `data[${i}].${field}`); + +// v9 +import { jsonPointer } from '@opendata-ai/openchart-core'; +errors.find((e) => e.path === '/encoding/y/field'); +errors.find((e) => e.path === jsonPointer('data', i, field)); +errors.find((e) => e.path === '/layer/1/encoding/y/field'); // formerly 'encoding.y.field' +``` + +The `Invalid spec:` error thrown by compilation prefixes each line with its pointer (`/encoding/y/field: Spec error: ...`) unless the message already names it. `ValidationResult.warnings` was never populated and is removed, as is the internal `compile(spec, { markOptionWarnings })` option. + +Diagnostic fixes are edit operations. `SpecPatch.changes` is `EditOp[]`, and `applySpecPatch` applies it with `applyEditTransaction` and returns the inverse: + +```ts +// v8 +// fix.changes: [{ path: '/theme/fonts/sizes/axisTick', value: 12 }] +spec = applySpecPatch(spec, diagnostic.fix); + +// v9 +// fix.changes: [{ op: 'set', path: '/theme/fonts/sizes/axisTick', value: 12 }] +const { spec: next, inverse } = applySpecPatch(spec, diagnostic.fix); +undoStack.push(inverse); // applySpecPatch(next, inverse) restores spec +spec = next; +``` + +A fix that must create a missing object uses `add`; `set` requires the parent to exist. Stale or invalid patches still throw. The inverse is guarded by the patched document, so it is rejected after later edits. + +`label` belongs only to `range` and `refline` annotations. On a `text` annotation it had no effect and is now a validation error at `/annotations//label`. `migrateSpecV8` removes it and reports the repair. Put the callout copy in `text`, and supporting copy in `subtitle`. + +```js +// v8 +{ type: 'text', x: '2020', y: 12, text: 'Peak', label: 'Peak' } +// v9 +{ type: 'text', x: '2020', y: 12, text: 'Peak' } +``` + +`LayerSpec.responsive` now accepts the same `boolean | ResponsiveConfig` as `ChartSpec.responsive`, matching what validation and migration already wrote. + +## Internal compile options + +**Search for:** `footnoteReserve`, `footnotePass`, `facetHeightGrown`, `frozenChartArea`, `rightAxisReserve`, and `layered` in options passed to `compileChart`, `compileLayer`, or a mount. + +These fields were on the public `CompileOptions` type in v8 but documented as internal: the engine set them when it re-entered its own compile for note bands, facet growth, and dual-axis layers. v9 sizes a chart in one pass, so the re-entry fields are gone and the layer fields moved to an engine-internal type. Remove them from any options object you build. `chromeLayout: 'subtract' | 'grow'` is unchanged. + +A custom `measureText` whose note wrapping needs more lines than the reserved note band no longer triggers a second compile. In grow mode, and in the default layout, the figure grows by the extra height. With `chromeLayout: 'subtract'` the figure keeps its size and `onDiagnostic` receives a `layout.note-capacity` diagnostic. Monotone measures, including the built-in heuristic, never hit this case. + +## Validate the upgrade + +Review exact-height embeds, narrow charts, custom fonts/themes, layers/facets, and exported SVG/PNG. Exercise one edit, undo, cancelled drag, and keyboard nudge with the new transaction handler. Test application persistence against stale annotation identity. Library migration does not upgrade OpenStudio storage or publish packages; those release steps have their own validation. + +### Approved chart and map defaults + +Ordinary gridlines are quieter, and existing zero rules have stronger contrast. This does not add ticks, expand domains or enable disabled grids. Set `theme.colors.gridline` and `gridlineZero` to override either role. Explicit colors and light/dark pairs remain supported. Bar/column padding and endpoint sizes/gaps are unchanged. When two automatic slope-axis endpoint labels overlap, their text positions now spread apart while the data anchors remain fixed. Explicit tick values retain their authored behavior. + +Map interior borders and outlines are quieter in both modes. The no-data hatch and fill remain unchanged: missing observations still differ from valid zero and neutral classes. `migrateSpecV8` restores old grid and border colors where the theme can express them; `{ styling: 'v9' }` adopts the new defaults. + +Map keys now reserve measured title/unit/context rows before projection fitting, and size keys choose a less obstructed location using their complete text/circle bounds. These layout changes have no legacy switch; migration reports that limitation rather than claiming pixel parity. Scale values, class boundaries, point sizes and paint order are unchanged. In fixed-height maps, fuller keys leave less height for geography; increase the authored container height when both detailed keys and a large map are required. The library does not crop coverage or move keys automatically to recover that space. + + +### Optional geographic labels + +Existing maps do not gain place labels or note bands automatically. Add `encoding.text` or `points.text` for data-driven labels, and `callouts` for authored geographic findings. Point labels and point-anchored callouts require a unique `points.key`. Feature anchors use topology IDs; geographic longitude/latitude and preprojected source coordinates are separate explicit anchor kinds. + +Callouts reserve complete note capacity before the map is fitted. Review fixed-height embeds when enabling them; panning and zooming never change that reserve. Hidden inventory text remains available when visual labels collide or are outside their zoom range. Enable `labelInventory: { container }` on a vanilla mount or GeoMap wrapper for a visible host-placed list. This option does not enable reader comparison or annotation editing. + +`renderStaticSVG` accepts maps. Use a distinct stable `idPrefix` for each static figure embedded in one document, so clip paths, patterns and descriptions cannot refer to another figure's IDs. Omission retains the existing deterministic standalone-ID behavior. See [geographic labels and callouts](geographic-labels.md) for authoring, camera, accessibility and export details. + +### Shared attribution and side map keys + +Source, byline, footer and branding now use the same measured footer across all visualization families. The default OpenData mark is 12px. A custom `chrome.brand` replaces it, including in maps, tables and graphs. Long attribution uses the full row and stacks the brand below when that needs less space than a shared row. Explicit text, font size, offsets and `maxLines` still take precedence; an authored offset can intentionally move text beyond its reserved area. + +There is no legacy footer-layout switch. `migrateSpecV8` reports this limitation: even with preserved v8 typography, the measured brand reserve can change wrapping and available plot height. Automatic tile labels may become larger when more room is available, and automatic chart connectors may disappear when a label can sit beside its mark. Source observations, domains and units do not change. Review fixed-height embeds and exports after migrating. Compact/hidden chrome retains its existing attribution visibility policy; `watermark: false` removes the default mark and its reserve. + +Side map keys now reserve their actual measured content width. Quantitative side keys show explicit range rows using the existing class boundaries, with accessible inclusive/exclusive descriptions. Reserved gutters have no legend plate; overlays keep a background where geography sits behind them. Narrow frames can fall back to the existing top key before projection fitting. These changes preserve coverage and projection proportions; they do not crop geography to enlarge a map. + +### Optional reader comparison + +The existing four-argument `createReader` observation API is unchanged. To inspect complete date slices, pass a fifth argument with `mode: 'slices'` and a host-owned panel container: + +```ts +const reader = createReader(container, chart, spec, onReaderChange, { + mode: 'slices', + panel: { container: comparisonHost }, + comparison: 'absolute', +}); +``` + +Slice mode currently supports a single line or area binding; unsupported layered slice readers report a diagnostic. Declare matching field metadata (`measure`, `unit`, `representation`) before expecting numerical comparisons. Date slices use actual transformed observations; sparse series remain missing, and duplicate series/date observations are ambiguous. A third pin replaces B; removing A promotes B. Durable keyed observations reconcile through updates. Replacing unkeyed data or changing the explicit source `revision` clears ephemeral pins; geometry-only updates retain them. `setSelection` is silent; user and data-driven changes include a reason in the callback. + +Maps opt in through `createGeoReader`, or the `reader` option on framework GeoMap wrappers. A companion container enables local name search, explicit ranking and pagination. Pins never automatically move the camera: Show on map is a separate action. `colorKey: { activeValue: true, distribution: true }` reserves its complete context before projection fitting. Missing places remain findable and unranked, and distribution counts include only finite joined feature observations represented in the root or an inset, counting duplicated coverage once. Source-only places that the projection cannot display remain searchable without inflating the visible distribution. + +Reader pins, preview outlines and HTML comparison panels are transient UI and are excluded from static export. Authored geographic labels and distribution keys are portable and remain in SVG. A snapshot of the comparison readout is intentionally not offered until it has a portable layout; no HTML screenshot or `foreignObject` is embedded. Graph mounts retain their existing export API limitations. + + +### Optional detail geography and inset views + +Existing maps keep one root view. To add contextual boundaries without moving the +primary map, author `geo.detailLayers` with a unique `id`, `features`, and `minZoom`. +An optional `maxZoom` bounds visibility. Layers use the root view's original fitted +projection; they do not change joins, values, class boundaries or reader identity. +`geo.objectKey` selects the primary TopoJSON object and `fitObjectKey` selects its +fitting geography. Each topology is decoded independently, including its own +transform. GeoJSON should use the winding expected by the selected D3 projection. + +Identity-projection detail requires matching nonempty `sourcePlane` values on the +primary geography and every detail layer. This is an explicit assertion about +already decoded coordinates, not a coordinate-system conversion or proof. Source-space insets use identity projection. Mixing +geographic and source coordinates is rejected before updating the mounted map. + +Insets reserve independent labeled frames before the primary fit. For example: + +```ts +geo: { + features: states, + objectKey: 'states', + projection: 'albersUsa', + zoom: true, + insets: [{ + id: 'alaska', label: 'Alaska', featureIds: ['02'], + placement: 'bottom-left', width: 140, + }], +} +``` + +Inset feature IDs refer to primary geography. `removeFromMain` defaults to true; +set it false to explicitly duplicate coverage. Points are included only through +explicit `pointIds` matching `points.key`. Shared observations retain one color +scale and reader identity across views. Inset `featureIds` use topology feature IDs, even when `geo.idField` selects a different property for the data join. Insets disclose their separate scale and +coverage; impossible frame packing rejects rather than silently dropping a view. +Choose a projection compatible with the inset geography: not every projection +produces a useful local fit around an antimeridian or a composite projection clip. + +Existing camera methods target the root. Use `getCamera('alaska')`, +`setCamera(camera, { viewId: 'alaska' })`, and `getCameras()` for independent views. +Camera callbacks retain the existing first argument and add scope metadata for +multiview layouts. Geographic anchors can specify `viewId` and `layerId`; unknown +explicit scopes reject, while a missing feature in a known scope retains its note +and accessible inventory. Context detail layers currently belong to the root view. +SVG export preserves every current camera. Keep unique `idPrefix` values for +multiple static figures; transient reader pins remain excluded. diff --git a/docs/spec-reference.md b/docs/spec-reference.md index afd2117f..0b541552 100644 --- a/docs/spec-reference.md +++ b/docs/spec-reference.md @@ -68,12 +68,12 @@ The primary input for standard chart types. Source: `core/src/types/spec.ts`. | `data` | `DataRow[]` | (required) | Array of data rows. Each row is a `Record`. Must be non-empty. | | `encoding` | `Encoding` | (required) | Maps data fields to visual channels. See [Encoding](#encoding). | | `chrome` | `Chrome` | `undefined` | Editorial text: title, subtitle, source, byline, footer. See [Chrome](#chrome). | -| `chromeLayout`| `'subtract' \| 'grow'` | `'subtract'` | How chrome text interacts with the container height budget. See [Chrome layout](#chrome-layout). | +| `chromeLayout`| `'subtract' \| 'grow'` | note-band growth | How chrome text interacts with the container height budget. See [Chrome layout](#chrome-layout). | | `annotations` | `Annotation[]` | `undefined` | Text callouts, highlighted ranges, reference lines. See [Annotations](#annotations). | | `labels` | `LabelConfig` | `undefined` | Data label display controls. See [Labels](#labels). | -| `responsive` | `boolean` | `true` | Whether the chart adapts to container width via ResizeObserver. | +| `responsive` | `boolean \| ResponsiveConfig` | `true` | Layout adaptations at compact sizes; mount `autoResize` controls ResizeObserver. | | `theme` | `ThemeConfig` | `undefined` | Theme overrides. Deep-merged onto the default theme. See [ThemeConfig](#themeconfig). | -| `watermark` | `boolean` | `true` | Whether to show the tryOpenData.ai watermark. Spec-level value takes precedence over mount/compile options. Defaults to `true`; auto-hides when the container is under 200px tall unless explicitly set. | +| `watermark` | `boolean` | `true` | Whether to show the tryOpenData.ai watermark. Mount/compile options take precedence over spec and active breakpoint values. Defaults to `true`; auto-hides when the container is under 200px tall unless explicitly set. | | `animation` | `AnimationSpec`| `undefined` | Animation configuration. `true` enables entrance + update/exit animations. See [Animation](#animation). | | `description` | `string` | `undefined` | Alt text for the chart (Vega-Lite aligned). Sugar for `a11y.description`. Auto-generated when absent. See the [accessibility guide](accessibility.md). | | `a11y` | `A11yConfig` | `undefined` | Accessibility overrides: `description` (custom alt text, wins over top-level `description`) and `hidden` (hide from assistive technology). | @@ -88,6 +88,8 @@ A plain object with string keys. Values can be numbers, strings, dates, nulls, a ### Mark properties +`MarkDef` is a discriminated union: each object accepts only options for its mark type. TypeScript, JSON Schema, and runtime validation enforce the same contract before sugar expansion. Extend it with an intersection type rather than an interface. + The `mark` field on ChartSpec accepts either a string (`'line'`) or an object with additional mark configuration. LayerSpec children are ChartSpecs, so they use `mark` too. ```ts @@ -187,7 +189,7 @@ Overlay multiple chart types on shared scales. Source: `core/src/types/spec.ts`. | `annotations` | `Annotation[]` | `undefined` | Annotations on the layered view. | | `labels` | `LabelConfig` | `undefined` | Label display configuration. | | `legend` | `LegendConfig` | `undefined` | Legend display configuration. | -| `responsive` | `boolean` | `true` | Whether the chart adapts to container width. | +| `responsive` | `boolean \| ResponsiveConfig` | `undefined` | Same as `ChartSpec.responsive`. When omitted, the first leaf's value applies. | | `theme` | `ThemeConfig` | `undefined` | Theme overrides. | | `watermark` | `boolean` | `true` | Whether to show the watermark. Defaults to `true`; auto-hides when the container is under 200px tall unless explicitly set. | | `resolve` | `ResolveConfig` | `undefined` | Resolution strategy for shared vs. independent scales/axes/legends. | @@ -234,6 +236,7 @@ interface Encoding { y?: EncodingChannel; color?: EncodingChannel; size?: EncodingChannel; + theta?: EncodingChannel; // arc/waffle/parliament quantitative value detail?: EncodingChannel; facet?: FacetChannel; // small multiples -- see Faceting row?: FacetChannel; // vertical facet stack -- see Faceting @@ -311,14 +314,14 @@ The engine validates encoding channels at runtime using `MARK_ENCODING_RULES`. S | `area` | temporal, ordinal (req) | quantitative (req) | nominal, ordinal (opt) | quantitative (opt) | nominal (opt) | Same encoding as line, filled region | | `bar` | quantitative (req) | nominal, ordinal (req) | nominal, ordinal (opt) | quantitative (opt) | nominal (opt) | Horizontal bars. x = values, y = categories | | `column` | nominal, ordinal, temporal (req) | quantitative (req) | nominal, ordinal (opt) | quantitative (opt) | nominal (opt) | Vertical bars. x = categories, y = values | -| `pie` | -- (opt, unused) | quantitative (req) | nominal, ordinal (req) | quantitative (opt) | nominal (opt) | color = slice categories, y = slice values | -| `donut` | -- (opt, unused) | quantitative (req) | nominal, ordinal (req) | quantitative (opt) | nominal (opt) | Same as pie with inner radius | +| `pie` | -- (opt, unused) | -- (use theta) | nominal, ordinal (req) | quantitative (opt) | nominal (opt) | color = slice categories, theta = slice values | +| `donut` | -- (opt, unused) | -- (use theta) | nominal, ordinal (req) | quantitative (opt) | nominal (opt) | theta = slice values; same as pie with inner radius | | `dot` | quantitative (req) | nominal, ordinal (req) | nominal, ordinal (opt) | quantitative (opt) | nominal (opt) | Dot plot. x = values, y = categories | | `scatter` | quantitative (req) | quantitative (req) | nominal, ordinal (opt) | quantitative (opt) | nominal (opt) | Both axes quantitative. size creates bubble chart | | `beeswarm` | quantitative or nominal (opt) | quantitative or nominal (opt) | nominal, ordinal, quantitative (opt) | quantitative (opt) | nominal (opt) | One position is the quantitative value axis; the other (nominal/ordinal) splits into grouped lanes | | `range` | quantitative or nominal (req) | quantitative or nominal (req) | nominal, ordinal (opt) | -- | nominal (opt) | Dumbbell/arrow/range-bar. x+x2 (horizontal) or y+y2 (vertical); orientation-dependent second endpoint | -| `waffle` | -- (opt, unused) | quantitative (req, via `theta`) | nominal, ordinal (req) | -- | nominal (opt) | Unit grid. `theta` (alias for y) = share, color = category | -| `parliament` | -- (opt, unused) | quantitative (req, via `theta`) | nominal, ordinal (req) | -- | nominal (opt) | Hemicycle seats. `theta` (alias for y) = seat count, color = party | +| `waffle` | -- (opt, unused) | -- (use theta) | nominal, ordinal (req) | -- | nominal (opt) | Unit grid. `theta` = share, color = category | +| `parliament` | -- (opt, unused) | -- (use theta) | nominal, ordinal (req) | -- | nominal (opt) | Hemicycle seats. `theta` = seat count, color = party | | `histogram` | quantitative (req) | quantitative (opt) | nominal, ordinal (opt) | quantitative (opt) | nominal (opt) | Raw values on x; y defaults to the per-bin count. Color groups overlap rather than dodge | | `density` | quantitative (req) | -- (computed) | nominal, ordinal (opt) | -- | nominal (opt) | KDE over raw x values; y is the estimated density | | `calendar` | temporal (req) | -- (not allowed) | quantitative (req) | -- | nominal (opt) | Calendar heatmap. x = daily date, color = per-day value; owns its own geometry | @@ -329,6 +332,8 @@ The engine validates encoding channels at runtime using `MARK_ENCODING_RULES`. S **y channel**: Vertical position. Quantitative values for most types. Nominal/ordinal categories for bar and dot (horizontal layout). +**theta channel**: Quantitative part-to-whole values for arc, waffle, and parliament. Their former authored `y` alias is rejected; use `theta`. + **color channel**: Series differentiation. Assigns colors from the categorical palette. Required for pie/donut (defines slices). Optional for all others (creates multi-series with legend). **size channel**: Mark size. Creates bubble charts when applied to scatter. Maps a quantitative field to the dot **radius in pixels**, area-proportionally (sqrt curve); the default range is [3, 30] and `scale.range` overrides it in radius px. A constant lives at `mark.size`, also a radius (default 5, typical 2-12). Note this differs from Vega-Lite, where point `size` is an **area** in px² — a VL size of 110 is `mark.size: 6` here (r = √(area/π)); validation rejects radii above 50 with the conversion. @@ -422,12 +427,12 @@ Each field accepts either a plain string or a `ChromeText` object for style over | Field | Position | Default style | | ---------- | ------------------------------- | ------------------------------------------------------------ | -| `eyebrow` | Above title | 11px, semibold, uppercase, theme accent — leading accent dot | -| `title` | Top, above chart | 22px, bold (700), `#333333` | -| `subtitle` | Below title | 15px, normal (400), `#666666` | -| `source` | Below chart area | 12px, normal (400), `#999999` | -| `byline` | Below source | 12px, normal (400), `#999999` | -| `footer` | Below byline | 12px, normal (400), `#999999` | +| `eyebrow` | Above title | 11px, medium (500), uppercase, theme accent — leading accent dot | +| `title` | Top, above chart | 26px, semibold (600), `#09090b` | +| `subtitle` | Below title | 14px, normal (400), `#71717a` | +| `source` | Below chart area | 12px, normal (400), `#71717a` | +| `byline` | Below source | 12px, normal (400), `#71717a` | +| `footer` | Below byline | 12px, normal (400), `#71717a` | | `brand` | Right-aligned on the source row | 12px, suppresses the default watermark | **KPI metric row** is a separate top-level field on chart specs, not part of `Chrome`. Use `metrics: Metric[]` on the chart spec for a horizontal row of label+value cells rendered between the subtitle and the chart area. Each cell can carry a delta and a secondary value. See `Metric` in `core/src/types/spec.ts` for the full shape. @@ -481,7 +486,8 @@ The top-level `chromeLayout` property controls how chrome text height interacts | Value | Behavior | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| `'subtract'` | Default. The container height is fixed and chrome text (title, subtitle, source) is subtracted from it, shrinking the plot. Historical behavior. | +| omitted | Notes and the series summary grow the figure; title, subtitle, source, and other chrome subtract from the container height budget. | +| `'subtract'` | Keep the exact outer height; all chrome and notes subtract from it, shrinking the plot. | | `'grow'` | The container height is treated as the plot budget. The rendered SVG grows taller by the measured chrome height, so the plot keeps its full budget (minus axis and padding overhead) no matter how many lines the title wraps to. | Reach for `'grow'` on fixed-height article or blog charts where a long title on a narrow phone must not compress the plot. @@ -496,7 +502,7 @@ Reach for `'grow'` on fixed-height article or blog charts where a long title on } ``` -`chromeLayout: 'grow'` is a no-op for faceted (small-multiples) specs in this version and falls back to `'subtract'`. It is also honored by bar list, sankey, map, and tilemap specs via the spec or compile option. +`chromeLayout: 'grow'` supports faceted charts and layers; engine-added height is counted once. Read `layout.dimensions.height` for the final height and `layout.chrome.grownHeight` for the added height. The default note-growth policy is internal: `'notes'` is not a public spec value. Bar list, Sankey, map, and tilemap also honor the public spec/compile policies. --- @@ -533,6 +539,8 @@ Carrying both bin edges matters: the end edge goes to `x2`, which is what puts t Data-positioned overlays. Source: `core/src/types/spec.ts`. +Use unique annotation `id` values for durable selection and editing. Notes preserve complete primary/subtitle text and rich spans; their numbers follow source text-annotation order before filtering, so gaps are intentional. Notes and markers support linked focus and click/tap emphasis. + Three annotation types are available, discriminated by the `type` field: ### TextAnnotation @@ -546,15 +554,16 @@ A callout label positioned at a data coordinate. | `y` | `string \| number` | (required) | Y-axis data value or position. | | `text` | `string` | (required) | The annotation text. Supports `\n` for line breaks and `**bold**` spans. | | `subtitle` | `string` | `undefined` | Optional muted second-tone text rendered below `text`. Use for supporting context (methodology, source, etc.). Supports `**bold**` too. | -| `maxWidth` | `number \| null` | unlimited | Optional positive wrapping width in pixels; null disables wrapping. | -| `subtitleFontSize` | `number` | `round(fontSize * 0.85)` | Optional positive subtitle size in pixels. | +| `maxWidth` | `number \| null` | `min(240, plotWidth - 2 * padding)`, at least 1px | Positive display wrapping width in pixels; null disables wrapping. | +| `subtitleFontSize` | `number` | `round(fontSize * 12 / 13)` | Optional positive subtitle size in pixels. | | `dot` | `boolean \| AnnotationDot` | see below | Open-ring marker on the data point. Appears by default on non-arrowed connectors. `false` for none, an object to restyle. | -| `label` | `string` | `undefined` | Additional label text. | | `fontSize` | `number` | `13` | Font size override in pixels. | -| `fontWeight` | `number` | `400` (`700` with a `subtitle`) | Font weight override. | +| `priority` | `number` | source order | Lower values get placement and compact-inline preference; ties retain source order. | +| `responsive` | `boolean` | `true` | `false` pins the annotation inline and exempts it from thinning/count limits. | +| `fontWeight` | `number` | `400` | Font weight override. | | `offset` | `AnnotationOffset` | `undefined` | Pixel offset from computed position. `{ dx?: number, dy?: number }`. | | `anchor` | `AnnotationAnchor` | `'auto'` | Label placement direction: `'top'`, `'bottom'`, `'left'`, `'right'`, `'auto'`. | -| `connector` | `boolean \| ConnectorType \| ConnectorConfig` | `true` | `'straight'`, `'curve'`, or `'drop-line'`; `{ type, arrow? }` for explicit arrow control; `false` disables it. | +| `connector` | `boolean \| ConnectorType \| ConnectorConfig` | `true` | `'straight'`, `'curve'`, or `'drop-line'`; `{ type, arrow?, bend? }` for explicit control; `false` disables it. | | `connectorOffset` | `{ from?, to? }` | `undefined` | Per-endpoint pixel offsets for the connector line. | | `background` | `string \| true` | `undefined` | Background plate behind the text, for readability over chart lines. `true` follows the theme surface. | | `fill` | `string` | theme `annotationFill` | Fill color. | @@ -562,7 +571,7 @@ A callout label positioned at a data coordinate. | `opacity` | `number` | `1` | Opacity (0 to 1). | | `zIndex` | `number` | `0` | Render ordering. Higher values render on top. | -#### Text: line breaks, bold spans, and the lede rule +#### Text: wrapping, line breaks, and bold spans Curve connectors accept optional `bend: -1..1`; omitted or zero preserves the existing automatic curve. Other connector types ignore `bend` with a warning. @@ -578,14 +587,14 @@ An authored `offset` object pins placement even when both values are zero. Only matched pairs turn bold. An unmatched `**` (and an empty `****`) renders literally, so specs with stray asterisks aren't mangled. Bold spans are measured at weight 700, so bounds, collision nudging, and connector exits all account for them. -When a `subtitle` is present and you set no `fontWeight`, the primary text resolves to weight 700 and the subtitle stays 400. That's the lede + context stack ("Feb. 25" over "2015 maximum"). Setting `fontWeight` explicitly opts out. +Primary text and subtitles default to weight 400. Set `fontWeight: 700` for a bold primary line or use `**bold**` for selective emphasis; adding a subtitle does not change the primary weight. #### Connectors -The connector leaves the text block (primary text plus subtitle, treated as one box) on the side facing the data point, with a 6px standoff gap, and stops short of the marker at the other end. Two voices: +The connector leaves the text block (primary text plus subtitle, treated as one box) on the side facing the data point, with a 6px standoff gap, and stops short of the marker at the other end. A curved connector is shaped to the data point and then pulled back along its end tangent, so the tail still aims at the marker. Two voices: -- **Emphasis.** An arrowed connector (`'curve'` defaults to `arrow: true`) is drawn in the label's text ink with a small open-V arrowhead, so the gesture reads as part of the sentence. -- **Quiet.** A non-arrowed straight leader or a `'drop-line'` is a gray hairline. It points without competing with the words. +- **Emphasis.** An explicitly arrowed connector (`{ type: 'curve', arrow: true }`) is drawn in the label's text ink with a small open-V arrowhead, so the gesture reads as part of the sentence. +- **Quiet.** A non-arrowed curve, straight leader, or `'drop-line'` is a gray hairline. It points without competing with the words. Connectors are dropped when they'd be noise rather than signal: a leader shorter than 8px, or one whose data point sits inside the text block. The marker still renders. A default annotation sits far enough off its point (28px) to draw a real leader without any `offset` authoring; you only lose the line by pulling the label back onto its own marker. @@ -594,11 +603,11 @@ Connectors are dropped when they'd be noise rather than signal: a leader shorter | Field | Type | Default | Description | | ------------- | -------- | --------------------------- | --------------------------------- | | `radius` | `number` | `4` | Circle radius in pixels. | -| `fill` | `string` | theme background | Interior fill (the "open ring"). | +| `fill` | `string` | theme `annotationMarkerFill` (neutral surface by default) | Interior fill (the "open ring"). | | `stroke` | `string` | the connector's stroke | Ring color. | | `strokeWidth` | `number` | `1.5` | Ring width in pixels. | -The marker sits on the data point itself, not on the pulled-back connector tip. You get one by default when a connector is enabled and carries no arrowhead, including drop-lines. An arrowed connector gets no marker unless you ask for one, since the arrowhead already marks the spot. `dot: false` is always bare; an explicit `dot` always wins. +The marker sits on the data point itself, not on the pulled-back connector tip. You get one by default when a connector is enabled and carries no arrowhead, including drop-lines. An arrowed connector gets no marker unless you ask for one, since the arrowhead already marks the spot. `dot: false` is always bare; an explicit `dot` always wins. A default dot that lands on a line's endpoint marker takes the marker's fill and stroke, so the two draw as one ring. ### RangeAnnotation @@ -615,9 +624,9 @@ A highlighted band or rectangle. | `label` | `string` | `undefined` | Range label text. | | `labelOffset` | `AnnotationOffset` | `undefined` | Pixel offset for the label. `{ dx?: number, dy?: number }`. | | `labelAnchor` | `AnnotationAnchor` | `'auto'` | Label placement direction. | -| `fontSize` | `number` | `11` | Font size override for the range label (px). | +| `fontSize` | `number` | theme `small` (12px) | Font size override for the range label (px). | | `fontWeight` | `number` | `500` | Font weight override for the range label. | -| `fill` | `string` | theme `annotationFill` | Fill color. | +| `fill` | `string` | theme `annotationRangeFill` (`#f0c040`) | Fill color. | | `stroke` | `string` | `undefined` | Stroke color. | | `opacity` | `number` | `1` | Opacity (0 to 1). | | `zIndex` | `number` | `0` | Render ordering. | @@ -642,16 +651,18 @@ A horizontal or vertical reference line. | `strokeWidth` | `number` | `1` | Line width in pixels. | | `labelOffset` | `AnnotationOffset` | `undefined` | Pixel offset for the label. | | `labelAnchor` | `AnnotationAnchor` | `'auto'` | Label placement direction. | -| `labelPlacement` | `'auto' \| 'start' \| 'end' \| 'outside'` | legacy anchor behavior | Opt-in screen-space end selection, automatic containment, or a reserved outside gutter/lane. `labelAnchor` selects the side; an authored offset pins the base. | -| `fontSize` | `number` | `11` | Font size override for the label (px). | +| `labelPlacement` | `'auto' \| 'start' \| 'end' \| 'outside'` | `'auto'` unless `labelAnchor` is authored | Screen-space end selection, automatic containment, or a reserved outside gutter/lane. `labelAnchor` selects the side; an authored offset pins the base. | +| `fontSize` | `number` | theme `small` (12px) | Font size override for the label (px). | | `fontWeight` | `number` | `400` | Font weight override for the label. | | `fill` | `string` | `undefined` | Fill color. | -| `stroke` | `string` | theme `annotationText` | Stroke/line color. | +| `stroke` | `string` | theme `annotationRule` | Stroke/line color. | | `opacity` | `number` | `1` | Opacity (0 to 1). | | `zIndex` | `number` | `0` | Render ordering. | Provide `x` for a vertical line or `y` for a horizontal line. Both can be set for a crosshair. +With `labelPlacement: 'outside'`, horizontal lines reserve a right lane as wide as the widest wrapped label (capped at 160px or 25% of the width). Vertical lines share a lane above the plot: labels whose extents don't overlap pack into one row, and whole rows are admitted while the lane stays within 25% of the height. A label whose row doesn't fit falls back to automatic placement inside the plot with a warning. The lane shrinks before the title or subtitle does. + ### Annotation example ```ts @@ -920,124 +931,80 @@ For line/area marks, mid-morph interruption uses a crossfade from the frozen int ## ThemeConfig -User-facing theme overrides. Source: `core/src/types/spec.ts`. +Public authored theme overrides live in `core/src/types/spec.ts`. Every field is optional. Use `ThemeConfig` for input and `ResolvedTheme` for compiled output; the former public `Theme` alias is removed. -All fields are optional. The engine deep-merges these onto `DEFAULT_THEME`. You only specify what you want to change. +`mergeThemeConfig()` deep-merges authored layers before `resolveTheme()` supplies defaults. Component theme props override provider themes; mount/compile options override the spec. In a `LayerSpec`, chrome, axes and legend use the layer theme (falling back to the first leaf's); each leaf's marks use its theme merged over the layer theme. Nested objects merge, arrays and `{ light, dark }` TokenValues replace atomically, and null replaces. `colors: string[]` is shorthand for `colors.categorical`. ```ts -interface ThemeConfig { - colors?: { - categorical?: string[]; - categoricalFill?: string[]; - sequential?: Record; - diverging?: Record; - background?: string; - text?: string; - gridline?: string; - hairline?: string; - axis?: string; - }; - fonts?: { - family?: string; - mono?: string; - }; - spacing?: { - padding?: number; - chromeGap?: number; - }; - rule?: { color: TokenValue; width: number; thickness: number }; - borderRadius?: number; -} -``` - -### Color overrides - -| Field | Type | Default | Description | -| -------------------- | -------------------------- | --------------------------------- | ----------------------------------------------------------------- | -| `colors.categorical` | `string[]` | 8-color palette | Categorical palette for nominal data. Array of CSS color strings. | -| `colors.categoricalFill` | `string[]` | copied from `categorical` | Quieter palette used for area-filling marks (bar, area, arc, waffle, calendar, rect). Set it only to control fills and strokes independently; leaving it unset copies `categorical` so a custom palette never drifts between the two. | -| `colors.sequential` | `Record` | `{ blue, green, orange, purple }` | Sequential palettes keyed by name. | -| `colors.diverging` | `Record` | `{ redBlue, brownTeal }` | Diverging palettes keyed by name. | -| `colors.background` | `string` | `'#ffffff'` | Visualization background color. | -| `colors.text` | `string` | `'#1d1d1d'` | Default text color. | -| `colors.gridline` | `string` | `'#e8e8e8'` | Gridline color. | -| `colors.hairline` | `string` | `'rgba(0,0,0,0.14)'` | Structural line color for axis lines and separators. Distinct from `gridline`, which is lighter. | -| `colors.axis` | `string` | `'#888888'` | Axis line and tick color. | +import { broadsheet, mergeThemeConfig } from '@opendata-ai/openchart-core'; +import type { ThemeConfig } from '@opendata-ai/openchart-core'; -### Font overrides +const theme: ThemeConfig = mergeThemeConfig(broadsheet, { + fonts: { sizes: { small: 12, axisTick: 12 } }, + chrome: { title: { fontSize: 28 } }, + rule: { width: 80 }, +}); +``` -| Field | Type | Default | Description | -| -------------- | -------- | ----------------------------------------- | ----------------------------------- | -| `fonts.family` | `string` | `'Inter, -apple-system, ..., sans-serif'` | Primary font family. | -| `fonts.mono` | `string` | `'"JetBrains Mono", ..., monospace'` | Monospace font for tabular numbers. | +Authored `chrome..fontSize` takes precedence over propagation from `fonts.sizes`, including across theme layers. Theme chrome values are objects such as `{ color: '#333' }`; string color shorthand is removed. Spec chrome text shorthand (`chrome: { title: 'A title' }`) remains valid. -### Spacing overrides +### Color overrides -| Field | Type | Default | Description | -| ------------------- | -------- | ------- | ---------------------------------------- | -| `spacing.padding` | `number` | `12` | Padding inside the chart container (px). | -| `spacing.chromeGap` | `number` | `4` | Gap between chrome elements (px). | +Single colors accept `TokenValue` (`string | { light: string; dark: string }`). Palette arrays contain color strings. These are light-mode defaults unless a pair is shown: + +| Field | Default | Description | +|---|---|---| +| `colors.categorical` | Six-hue palette | Nominal-series stroke palette | +| `colors.categoricalFill` | Default fill palette; inherits an authored categorical palette when omitted | Quieter fill colors for area-filling marks | +| `colors.sequential` / `diverging` | Named palette maps | Numeric color scales | +| `colors.background` | `transparent` | Visualization background; opaque surfaces derive from the neutral surface | +| `colors.text` | `#09090b` | Main text ink | +| `colors.gridline` | `rgba(0,0,0,0.08)` | Grid lines | +| `colors.hairline` | `rgba(0,0,0,0.14)` | Structural separators | +| `colors.axis` | `#71717a` | Axis lines and tick text | +| `colors.annotationLabel` | `#333333` | Primary callout ink | +| `colors.annotationMuted` | `#6b7280` | Subtitle and note ink | +| `colors.annotationLeader` | `#8f8f8f` | Quiet connector ink | +| `colors.annotationRule` | `#888888` / `#9ca3af` | Reference line ink, light/dark | +| `colors.annotationRangeFill` | `#f0c040` | Range fill before opacity | +| `colors.annotationMarkerFill` / `annotationPlate` | Resolved neutral surface | Marker interior and label plate; explicit colors win | + +Generic `annotationFill` and `annotationText` retain their other uses. See [Theming tokens](theming-tokens.md) for the complete token and dark-mode mapping. + +### Fonts, chrome, and spacing + +| Field | Default | Description | +|---|---|---| +| `fonts.family` | Inter Variable, Inter, system sans-serif | Primary font family | +| `fonts.mono` | JetBrains Mono, Fira Code, Cascadia Code, monospace | Tabular/monospace family | +| `fonts.sizes.title` / `subtitle` | 26 / 14 | General title sizes | +| `fonts.sizes.body` / `small` / `axisTick` | 13 / 12 / 12 | Body, small, and tick sizes | +| `fonts.sizes.metricLabel` / `metricValue` | 11 / 22 | Metric row sizes | +| `fonts.weights.normal` / `medium` / `semibold` / `bold` | 400 / 500 / 600 / 700 | Weight ladder | +| `chrome.eyebrow` | 11px, 500, `#06b6d4`, 1.4 line-height | Eyebrow style | +| `chrome.title` | 26px, 600, `#09090b`, 1.15 line-height | Title style | +| `chrome.subtitle` | 14px, 400, `#71717a`, 1.45 line-height | Subtitle style | +| `chrome.source` / `byline` / `footer` | 12px, 400, `#71717a`, 1.4 line-height | Attribution styles | +| `spacing.padding` / `chromeGap` | 20 / 6 | Container padding / gap between chrome elements | +| `spacing.chromeToChart` / `chartToFooter` | 16 / 12 | Gaps above and below the chart | +| `spacing.axisMargin` | 6 | Axis margin | +| `borderRadius` | 8 | Containers and tooltips | ### The editorial rule -`rule` draws a short colored bar above the chrome block — the Economist/FT -masthead device. Omit it (the default on every preset but `broadsheet`) for no -rule. +`rule` draws a short colored bar above top chrome. Omission inherits a preset rule, or draws none on the default theme. `rule: null` removes an inherited rule; partial objects preserve unmodified fields. -```ts -theme: { - rule: { color: { light: '#e3120b', dark: '#f4463f' }, width: 40, thickness: 3 }, -} -``` - -| Field | Type | Default | Description | -| ---------------- | ------------ | ----------- | ------------------------------------------------------------------ | -| `rule.color` | `TokenValue` | (required) | Rule color. A `TokenValue` accepts a `{ light, dark }` pair, so it needs no dark-mode branch. | -| `rule.width` | `number` | (required) | Rule length in pixels. | -| `rule.thickness` | `number` | (required) | Rule height in pixels. `computeChrome` reserves `thickness + chromeGap` above the eyebrow/title. | +| Field | Fallback when a rule is authored without a preset | Description | +|---|---|---| +| `rule.color` | Theme text ink | TokenValue color, including light/dark pairs | +| `rule.width` | 40px | Rule length | +| `rule.thickness` | 3px | Rule height; chrome reserves thickness plus chromeGap | No top chrome means no rule. -### Other - -| Field | Type | Default | Description | -| -------------- | -------- | ------- | -------------------------------------------------------- | -| `borderRadius` | `number` | `4` | Border radius for the chart container and tooltips (px). | - -### DEFAULT_THEME reference - -The full default theme (from `core/src/theme/defaults.ts`): - -| Property | Value | -| ------------------------ | ------------------------------------------------------------------------ | -| `colors.background` | `#ffffff` | -| `colors.text` | `#1d1d1d` | -| `colors.gridline` | `#e8e8e8` | -| `colors.axis` | `#888888` | -| `colors.annotationFill` | `rgba(0,0,0,0.04)` | -| `colors.annotationText` | `#555555` | -| `fonts.family` | Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif | -| `fonts.mono` | "JetBrains Mono", "Fira Code", "Cascadia Code", monospace | -| `fonts.sizes.title` | 22 | -| `fonts.sizes.subtitle` | 15 | -| `fonts.sizes.body` | 13 | -| `fonts.sizes.small` | 11 | -| `fonts.sizes.axisTick` | 11 | -| `fonts.weights.normal` | 400 | -| `fonts.weights.medium` | 500 | -| `fonts.weights.semibold` | 600 | -| `fonts.weights.bold` | 700 | -| `spacing.padding` | 12 | -| `spacing.chromeGap` | 4 | -| `spacing.chromeToChart` | 8 | -| `spacing.chartToFooter` | 8 | -| `spacing.axisMargin` | 6 | -| `borderRadius` | 4 | -| `chrome.title` | 22px, 700 weight, `#333333`, 1.3 line-height | -| `chrome.subtitle` | 15px, 400 weight, `#666666`, 1.4 line-height | -| `chrome.source` | 12px, 400 weight, `#999999`, 1.3 line-height | -| `chrome.byline` | 12px, 400 weight, `#999999`, 1.3 line-height | -| `chrome.footer` | 12px, 400 weight, `#999999`, 1.3 line-height | +The named presets are `essay`, `wire`, `broadsheet`, and `terminal`. Omit `theme` or pass `{}` for the default; `editorial` is removed. `clarity` is deprecated and contains only its background, axis, and eyebrow colors. `legacyEditorial` retains v8 typography for migration. + +Only authored theme overrides and derived values are stamped inline. Omitted CSS tokens remain overridable by host styles, including `--oc-border-radius`; removing an override restores the host's previous inline value. Export captures live token values. --- @@ -1080,9 +1047,8 @@ Input for data table visualizations. Source: `core/src/types/spec.ts`. | `striped` | `boolean` | `false` | Zebra striping on body rows. Hairlines only by default. | | `sort` | `SortState` | first inline-bar column, descending | Initial sort applied before the user touches a header. `{ column: string, direction: 'asc' \| 'desc' }`. | | `totalRow` | `boolean \| { label?: string }` | `false` | Sticky footer summing every quantitative column over the filtered rows (the whole result set, not just the current page). `true` uses the label `'Total'`. | -| `compact` | `boolean` | `false` | **Deprecated.** Alias for `density: 'condensed'`; still honored, with a warning. | | `responsive` | `boolean` | `true` | Whether the table adapts to container width. | -| `watermark` | `boolean` | `true` | Whether to show the tryOpenData.ai watermark. Spec-level value takes precedence over mount/compile options. | +| `watermark` | `boolean` | `true` | Whether to show the tryOpenData.ai watermark. Mount/compile options take precedence over spec and active breakpoint values. | ### ColumnConfig @@ -1198,8 +1164,13 @@ Pass these through `MountOptions` (vanilla) or `ChartProps` (React). | `onMarkClick` | `(event: MarkEvent) => void` | User clicks a data mark (bar, point, line, arc). | | `onMarkHover` | `(event: MarkEvent) => void` | Mouse enters a data mark. | | `onMarkLeave` | `() => void` | Mouse leaves a data mark. | +| `onEdit` | `(transaction: EditTransaction) => void` | One committed authored edit; apply atomically with `applyEditTransaction` and retain its inverse for undo. | | `onLegendToggle` | `(series: string, visible: boolean) => void` | User clicks a legend entry to show/hide a series. | -| `onAnnotationClick` | `(annotation: Annotation, event: MouseEvent) => void` | User clicks an annotation element. | +| `onAnnotationClick` | `(annotation: Annotation, event: MouseEvent, element: ElementRef) => void` | User clicks an annotation element. | +| `onSelect` | `(element: ElementRef) => void` | An element is selected by click, Tab, or `select()`. Requires `interaction` `'select'` or `'edit'`. | +| `onDeselect` | `(element: ElementRef) => void` | The selected element is deselected. | + +The `interaction` mount option (`'read' | 'select' | 'edit'`) gates selection and editing; when omitted, `onEdit` implies `'edit'` and `onSelect`/`onDeselect` imply `'select'`. Every `ElementRef` carries a JSON Pointer `path`. See [Editing and keyboard navigation](migrating-v9.md#editing-and-keyboard-navigation) for transaction persistence and cancelled-gesture behavior. See [Interaction mode](integration-guide.md#interaction-mode) for the full table. ### MarkEvent @@ -1242,7 +1213,7 @@ Graphs render force-directed network visualizations on canvas. They support node | `chrome` | `Chrome` | `undefined` | Editorial text. | | `annotations` | `Annotation[]` | `undefined` | Annotations. | | `theme` | `ThemeConfig` | `undefined` | Theme overrides. | -| `watermark` | `boolean` | `true` | Whether to show the tryOpenData.ai watermark. Spec-level value takes precedence over mount/compile options. | +| `watermark` | `boolean` | `true` | Whether to show the tryOpenData.ai watermark. Mount/compile options take precedence over spec and active breakpoint values. | ### GraphEncoding @@ -1305,7 +1276,6 @@ Sankey diagrams show flows between stages. Each data row represents a link from | `linkStyle` | `SankeyLinkColor` | `'gradient'`| Link coloring: `'gradient'`, `'source'`, `'target'`, `'neutral'`. | | `linkOpacity` | `number` | `0.5` | Link fill opacity (0-1). Defaults to 0.75 in dark mode. | | `nodeLabelAlign`| `string` | `'auto'` | Label placement: `'auto'`, `'left'`, `'right'`. | -| `valueFormat` | `string` | `undefined` | d3-format string for values in tooltips and ARIA labels (e.g. `"$,.0f"`, `"~s"`). | | `chrome` | `Chrome` | `undefined` | Editorial text (title, subtitle, source, byline, footer). | | `legend` | `LegendConfig` | `undefined` | Legend display configuration. | | `theme` | `ThemeConfig` | `undefined` | Theme overrides. | @@ -1370,7 +1340,6 @@ Maps render TopoJSON geometries as SVG, join tabular data rows to features by id | `theme` | `ThemeConfig` | `undefined` | Theme overrides. | | `watermark` | `boolean` | `true` | Whether to show the tryOpenData.ai watermark. | | `animation` | `AnimationSpec` | `undefined` | Entrance animation configuration. | -| `valueFormat` | `string` | `undefined` | Deprecated: use `encoding.color.format` instead. d3-format string for color values in tooltips and the legend (e.g. `".1f"`). `encoding.color.format` wins when both are set. | ### GeoMapGeo @@ -1509,7 +1478,7 @@ Every state renders as an equal-size square in a fixed 12x8 grid, so small state | `theme` | `ThemeConfig` | `undefined` | Theme overrides. | | `watermark` | `boolean` | `true` | Whether to show the tryOpenData.ai watermark. | | `animation` | `AnimationSpec` | `undefined` | Entrance animation configuration. | -| `valueFormat` | `string` | `undefined` | Deprecated: use `encoding.value.format` instead. d3-format string for tile values, legend labels, and tooltips. | +| `valueFormat` | `string` | `undefined` | Tilemap fallback d3-format string for values, legend labels, and tooltips; `encoding.value.format` takes precedence. | ### TileMapEncoding @@ -1524,7 +1493,7 @@ Every state renders as an equal-size square in a fixed 12x8 grid, so small state - **Quantitative mode** renders a gradient legend bar with min/max labels below the grid. **Categorical mode** (string values, a `color` channel, or a `colors` map) renders swatch rows instead. - States missing from the data render as empty tiles, keeping their place on the grid. -- **Number formatting:** set `encoding.value.format` (d3-format string, e.g. `".1f"`, `"$,.0f"`, `"~s"`). It applies to tile values, legend labels, and tooltips, and wins over the deprecated top-level `valueFormat`. With record-map data and no explicit encoding, `valueFormat` still applies (with a deprecation warning). +- **Number formatting:** set `encoding.value.format` (d3-format string, e.g. `".1f"`, `"$,.0f"`, `"~s"`). It applies to tile values, legend labels, and tooltips, and wins over top-level `valueFormat`. With record-map data and no explicit encoding, `valueFormat` remains supported. - **`scale.scheme` fails validation on tilemap encoding channels.** The tilemap compile path never reads it; the top-level `palette` property is the mechanism tilemaps use for color. ### Tilemap example @@ -1677,7 +1646,7 @@ const spec: ChartSpec = { { category: "Tablet", share: 7 }, ], encoding: { - y: { field: "share", type: "quantitative" }, + theta: { field: "share", type: "quantitative" }, color: { field: "category", type: "nominal" }, }, chrome: { title: "Traffic by device" }, @@ -1697,7 +1666,7 @@ const spec: ChartSpec = { { status: "Blocked", count: 5 }, ], encoding: { - y: { field: "count", type: "quantitative" }, + theta: { field: "count", type: "quantitative" }, color: { field: "status", type: "nominal" }, }, chrome: { title: "Task status" }, @@ -1837,9 +1806,9 @@ All builders accept field names as strings (auto-infer type from data) or full ` | `annotations` | `Annotation[]` | Annotations. | | `responsive` | `boolean` | Responsive behavior. | | `theme` | `ThemeConfig` | Theme overrides. | -| `watermark` | `boolean` | Whether to show the tryOpenData.ai watermark. Spec-level value takes precedence over mount/compile options; defaults to `true`. | +| `watermark` | `boolean` | Whether to show the tryOpenData.ai watermark. Mount/compile options take precedence over the spec; defaults to `true`. | -`FieldRef` is `string | EncodingChannel`. When a string is provided, `inferFieldType()` samples up to 20 data values to determine the encoding type (quantitative, temporal, or nominal). +`FieldRef` is `string | EncodingChannel`. When a string is provided, `inferFieldType()` uses the shared builder/compiler inference: sample up to 50 rows, ignore nulls, and require more than 80% agreement. Numeric strings are considered before dates, so a column of `'2020'` values is quantitative. Set the channel type explicitly when years should be ordinal or temporal. ### Builder example @@ -1870,12 +1839,12 @@ const result = validateSpec(spec); ### ValidationError -| Field | Type | Description | -| ------------ | --------------------- | ------------------------------------------------------------- | -| `message` | `string` | Human-readable error description. | -| `path` | `string \| undefined` | Dot-path to the field that failed, e.g. `'encoding.x.field'`. | -| `code` | `ValidationErrorCode` | Machine-readable error code. | -| `suggestion` | `string` | Actionable fix suggestion. | +| Field | Type | Description | +| ------------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| `message` | `string` | Human-readable error description. | +| `path` | `string` | Root-relative RFC 6901 JSON Pointer to the value that failed, e.g. `'/encoding/x/field'` or `'/layer/1/data/0/value'`. The root is `''`. | +| `code` | `ValidationErrorCode` | Machine-readable error code. | +| `suggestion` | `string` | Actionable fix suggestion. | ### ValidationErrorCode @@ -1901,14 +1870,14 @@ const result = validateSpec(spec); ## Authoring foundation additions -The separate [OpenStudio application](https://github.com/tryopendata/openstudio) consumes these additive interfaces. Existing v8 visual and animation defaults remain unchanged. +These library interfaces support authoring and reader applications. OpenStudio adoption is separate; see [Migrating to v9](migrating-v9.md) for the changed defaults and removed APIs. -- **Theme:** import `clarity` for white/ink surfaces, Inter titles and 12px axes; `legacyEditorial` restores documented v8 typography without freezing layout behavior. +- **Theme:** v9 defaults include 12px axes/small text and larger chrome gaps. `clarity` is deprecated and retains only background, axis, and eyebrow colors. `legacyEditorial` restores v8 typography; `migrateSpecV8` can materialize the wider v8 styling contract without freezing layout behavior. - **Motion:** `animation: 'fluid' | 'subtle' (omit the preset for v8 timing)`; explicit phases override their preset. A phase can use `spring: { stiffness: 320, damping: 36, mass: 1 }` or the existing duration/easing configuration. Combining a spring with duration/easing in the same phase is an error. Quantitative springs are bounded, with a finite terminal state. Omitted/false animation remains disabled. - **Responsiveness:** `responsive: { preserveEnd: true, labelSummary: true }` retains the final x-axis boundary and moves overflowing endpoint identities to a wrapped list. Explicit axis values and author choices remain authoritative. `chromeLayout: 'grow'` gives that content space. Tables may opt into `mobileLayout: 'priority'`; `cards` remains the default, with `scroll` also available. - **Field metadata:** chart, table and map documents accept `fields`, keyed by field name. Each entry may declare `type` (`text`, `number`, `date`), `role: 'identity'`, `label`, `unit`, `measure`, `provenance`, `representation` (`number`, `percent`, `proportion`), `interval: { lower: 'lowerField', upper: 'upperField' }`, or `statusField`. Supplied intervals are never synthesized. Percent means 0–100 and proportion means 0–1. - **Reader identity:** a unique authored `encoding.key` supports observation persistence. Missing/duplicate keys clear observation pins on data replacement. Aggregated observations are groups, not raw rows, and the reference reader clears them on data/grouping revision. The `createReader` controller is independent from editor selection and uses `ChartInstance.sampleLayout()` for supported moving geometry. Call `reader.update(spec)` after `chart.update(spec)`; it reconciles visibility against the compiled destination marks even when the source data array is unchanged. An explicit `visibleKeys` override remains supported. Layered charts retain per-layer hover/crosshair inspection, but reader pinning across layers is not yet supported: a `LayerSpec` clears pins with an announcement rather than guessing cross-layer identity. -- **Design review:** `diagnoseChart(spec, layout)` returns structured checks with code, severity, checkability, path, viewport, explanation and origin. `CompileOptions.onDiagnostic` receives these checks. `recommendCompositions(data, question, roles)` requires explicit field roles and returns explained alternatives. `applySpecPatch` rejects stale snapshot preconditions; hosts should preview patches and retain undo. The reference editor uses the full authored document for patches even while previewing a filtered scene. +- **Design review:** `diagnoseChart(spec, layout)` returns structured checks with code, severity, checkability, path, viewport, explanation and origin. `CompileOptions.onDiagnostic` receives these checks. `recommendCompositions(data, question, roles)` requires explicit field roles and returns explained alternatives. A diagnostic `fix` is a `SpecPatch` whose `changes` are `EditOp`s. `applySpecPatch(spec, patch)` rejects stale snapshot preconditions, applies the operations atomically through `applyEditTransaction`, and returns `{ spec, inverse }`; apply `inverse` to the patched document to undo. Hosts should preview patches before applying them. The reference editor uses the full authored document for patches even while previewing a filtered scene. Host-neutral identity, comparison and explicit dataset-binding helpers are also exported from the engine. They provide foundations for future linked views, without implicitly declaring compatible measures or raw-row/aggregate relationships. See the [delivery record](design-evolution.md) for the advanced capabilities and release gates still pending. @@ -1921,15 +1890,15 @@ Maps, tile maps, bar lists and Sankey support arrows for inspection and Enter/Sp Table `rowKey` values must be unique to support identity across revisions. Numeric `1` and string `"1"` are distinct. Missing/duplicate keys emit `TABLE_ROW_KEY_AMBIGUOUS` and use revision-local identities. Treat compiled row IDs as opaque. CSV export includes all filtered and sorted rows, not just the current pagination page. -### Compact callout limits and note sizing (8.9.1) +### Compact callout limits and note sizing `responsive.compactAnnotationLimit?: number | null` is an optional nonnegative -integer limit below 400px outer width. Omitted/null means unlimited; zero demotes -all eligible callouts. `responsive: false` callouts are exempt. Priority/source +integer limit below 400px outer width. Omitted means one; null means unlimited, +and zero demotes all eligible callouts. `responsive: false` callouts are exempt. Priority/source order precedes coverage/collision thinning. Existing disabled-response and short-height rules still apply. Facet panel width does not trigger this limit. Read `layout.chrome.noteBandHeight` for note space and `layout.dimensions.height` for the final rendered/exported height. `chromeLayout: 'grow'` also supports facets; `chrome.grownHeight` reports engine-added height for auto-height consumers. -See [annotation migration guidance](./migrating-v8.md#annotation-layout-opt-ins). +See [annotation migration guidance](./migrating-v9.md#changed-annotation-and-figure-defaults). diff --git a/docs/tables.md b/docs/tables.md index e3bd2433..d82ab10e 100644 --- a/docs/tables.md +++ b/docs/tables.md @@ -185,7 +185,6 @@ All features are opt-in via top-level `TableSpec` properties. | Striping | `striped: true` | `false` | Zebra rows. Hairlines only by default | | Initial sort | `sort: { column, direction }` | first inline-bar column, desc | Sort applied before the user touches a header | | Total row | `totalRow: true` | `false` | Sticky footer summing every quantitative column with a summable cell type (text/bar/heatmap). Set `columns[].total: false` to leave an individual column's total cell blank | -| Compact mode | `compact: true` | `false` | **Deprecated.** Alias for `density: 'condensed'`; warns | | Responsive | `responsive: true` | `true` | Table adapts to container width | In controlled mode a `sort` of `null` means "the user cleared sorting" and @@ -232,6 +231,15 @@ share whatever space is left. If the explicit widths on their own would exceed the container, they're scaled down proportionally (floored at 60px) and the engine emits a `TABLE_WIDTH_OVERFLOW` warning through `onWarn`. +### Surface + +Tables paint `theme.colors.background`, which is transparent by default, so a +table sits on the host surface like a chart does. The header, totals row, +search input and pager buttons are transparent too; the opt-in sticky first +column keeps the mode's `--oc-bg` so scrolled cells don't show through. Inline +bar fills render at 40% opacity in dark mode (18% in light). Set +`theme.colors.background` for an opaque table. + ### Full-featured example ```ts diff --git a/docs/theming-tokens.md b/docs/theming-tokens.md index 25538cdc..1efc1a42 100644 --- a/docs/theming-tokens.md +++ b/docs/theming-tokens.md @@ -1,16 +1,12 @@ -# Migration Guide +# Theming Design Tokens -## Theming Design Tokens +`ThemeConfig` controls colors, typography, spacing, rules, and component surfaces. +Defaults are shared by the JavaScript theme and generated CSS tokens. v9 +consolidates authored deep merging and leaves omitted CSS tokens available to +host styles. For removed forms and legacy styling, see [Migrating to v9](migrating-v9.md). -This release widens `ThemeConfig` to expose every design-decision field and unifies CSS custom properties with the JS theme engine. All changes are backward-compatible. Existing theme configs continue to work without modification. +### ThemeConfig fields -### What changed - -**Before:** `ThemeConfig` covered colors, font family/sizes, 4 spacing fields, border radius, and chrome color (string only). Font weights, chrome typography, semantic colors, and additional spacing fields were hardcoded in `DEFAULT_THEME` with no override path. CSS custom properties in `tokens.css`/`dark.css` were hand-maintained separately from the JS theme. - -**After:** `ThemeConfig` covers everything. CSS custom properties are generated from the resolved JS theme at mount time. The static CSS files serve as SSR/pre-mount fallback defaults. - -### New ThemeConfig fields ```ts const theme: ThemeConfig = { @@ -52,8 +48,8 @@ const theme: ThemeConfig = { subtitle: { fontWeight: 400, lineHeight: 1.4 }, eyebrow: { color: '#e3120b', fontWeight: 700 }, - // Plain strings still work (color-only, backward-compatible) - source: '#666', + // Color-only overrides use the same object form. + source: { color: '#666' }, }, // New: series color assignment strategy @@ -93,11 +89,10 @@ The neutral grays are surface-aware: on light backgrounds the second series gets ### Named presets -Five presets exported from `@opendata-ai/openchart-core`: +Four primary presets exported from `@opendata-ai/openchart-core`: | Preset | Feel | |--------|------| -| `editorial` | Current default (empty config, zero drift) | | `essay` | Serif titles, warm background, generous spacing | | `wire` | Monospace, dense, tight chrome, dashboard feel | | `broadsheet` | Newspaper editorial: warm paper, red masthead `rule` and eyebrow, 24/700 title, square corners | @@ -147,11 +142,11 @@ fixed zinc ladder. A warm or cool custom theme gets warm or cool grays for free instead of zinc showing up uninvited beside the palette. The ramp lives on `ResolvedTheme.colors.neutral` (`100`/`200`/`300`/`400`/`600`/`800`, plus `secondary` = `800`, `faint` = `300`, `border` = `100`, plus `surface`) and is -computed once in `resolveTheme`/`adaptTheme`; mounts stamp the CSS tokens from -it. `surface` is the opaque color the theme paints on — the background itself +computed once in `resolveTheme`/`adaptTheme`. Mounts stamp derived tokens when +the relevant theme colors are authored; omitted tokens use the CSS cascade. `surface` is the opaque color the theme paints on — the background itself when it is opaque, otherwise the mode's `--oc-bg` token — and is the single source for knockout rings, stacked-segment seams, table cell fills, graph node -rings and the stamped `--oc-bg`. When the +rings, annotation marker/plate fills, and authored background tokens. When the background is transparent (the default) the ramp falls back to the static token defaults, which is why the default theme and the generated `tokens.css` never disagree. @@ -169,9 +164,9 @@ never disagree. | `--oc-map-hover-dim` | 0.75 | map-local override; dimming 3000 county paths at 0.3 reads as a blackout, so maps use a lighter dim and only on legend-bin hover, never on feature hover | | `--oc-positive-tint` / `--oc-negative-tint` | 10% color-mix toward `--oc-bg` | delta chip backgrounds | -`--oc-border-radius` (8px) drives containers and tooltips. In v8, mounts stamp -resolved theme tokens inline, so ordinary stylesheet overrides of these tokens -do not win. Set `theme.borderRadius` to change this value. Mark geometry uses the fixed `--oc-radius-sm` +`--oc-border-radius` (8px) drives containers and tooltips. In v9, CSS overrides +work when `theme.borderRadius` is omitted. An authored `theme.borderRadius` +takes precedence. Mark geometry uses the fixed `--oc-radius-sm` regardless, so a theme with `borderRadius: 0` still draws a 2px bar-end radius. @@ -180,7 +175,7 @@ radius. `token-theme-parity` test asserts this, along with the four weight tokens, `--oc-gridline`, `--oc-axis`, `--oc-border-radius`, `colors.neutral`, and `--oc-animation-stagger`, so the JS theme and the generated CSS tokens can't -drift apart the way they did before this release. +drift apart. ### The editorial rule @@ -200,16 +195,32 @@ as `chrome.*.color` and needs no dark-mode branch. `computeChrome` reserves ### CSS custom properties -`--oc-*` custom properties are now stamped on each `.oc-root` container from the resolved JS theme at mount time. This means: - -- **Two charts with different themes on the same page** each get correct `--oc-*` values (per-container scoping). -- **`tokens.css` and `dark.css` are fallback defaults**, not the source of truth. They still work for SSR, static HTML, and pre-mount styling. -- **If you were reading `--oc-*` values from CSS** to style surrounding UI, those values now reflect the actual resolved theme rather than the hardcoded defaults. This is almost certainly what you wanted, but worth noting. - -No action required. If you import `tokens.css`/`dark.css`, keep doing so. The JS-stamped properties take precedence via inline style specificity. - - -### Annotation tokens (8.9.1) +Defaults remain in `tokens.css` and `dark.css`. The shared renderer helper stamps +only authored theme leaves and values derived from them. A host stylesheet can +override omitted tokens, including `--oc-border-radius`; an authored theme value +wins via its inline style. Removing a theme override restores the host value. +SVG and raster exports retain the live CSS token values before leaving the page. + +Theme layers deep-merge in this order: spec theme, provider theme, component prop +(or mount/compile option). For layered charts, chrome, axes and legend use the +layer theme (or the first leaf's when the layer sets none), and each leaf's marks +use its own theme merged over the layer theme. +Objects merge by leaf; arrays and `{ light, dark }` pairs replace atomically. +`colors: string[]` remains shorthand for `colors.categorical`. `null` replaces: +use `rule: null` to remove a preset rule. Partial rules inherit unspecified +preset values; without a preset, width is 40px, thickness is 3px, and color is +theme text ink. Authored `chrome..fontSize` overrides the general +`fonts.sizes` scale. Chrome color shorthand is now `{ color: '...' }`. + +The default small/axis tick/source/byline/footer size is 12px; chrome-to-chart +spacing is 16px and chart-to-footer spacing is 12px. The background remains +transparent. The empty `editorial` preset was removed (omit `theme` instead). +`clarity` is deprecated and retains only its background, axis, and eyebrow +colors. Use `ThemeConfig` for input and `ResolvedTheme` for output; the `Theme` +alias was removed. + + +### Annotation tokens `theme.colors` accepts `annotationLabel`, `annotationMuted`, `annotationLeader`, `annotationRule`, `annotationRangeFill`, `annotationMarkerFill`, and @@ -218,4 +229,6 @@ are `--oc-annotation-label`, `--oc-annotation-muted`, `--oc-annotation-leader`, `--oc-annotation-rule`, `--oc-annotation-range-fill`, `--oc-annotation-marker-fill`, and `--oc-annotation-plate`. Explicit annotation colors override the tokens. Arrow connectors match label ink. Existing `annotationText`/`annotationFill` -uses are unchanged. Omitted annotation tokens preserve current 8.x output. +uses are unchanged. Default rule ink is #888888 in light mode and #9ca3af in +dark mode; range fill is #f0c040. Marker and plate fills follow the resolved +neutral surface unless explicitly authored. diff --git a/e2e/annotation-invariants/curves.spec.ts b/e2e/annotation-invariants/curves.spec.ts index 55359742..26edbb6d 100644 --- a/e2e/annotation-invariants/curves.spec.ts +++ b/e2e/annotation-invariants/curves.spec.ts @@ -13,6 +13,9 @@ for (const width of [320, 390, 768, 1280]) const charts = page.getByTestId('annotation-curve'); await expect(charts).toHaveCount(10); for (const chart of await charts.all()) { + await expect(chart).toHaveAttribute('data-oc-fonts-state', 'ready'); + if (colorScheme === 'dark') await expect(chart).toHaveClass(/oc-dark/); + else await expect(chart).not.toHaveClass(/oc-dark/); await expect(chart.locator('.oc-annotation-label')).toBeVisible(); await chart.dispatchEvent('fixture-layout'); const layout: ChartLayout = JSON.parse((await chart.getAttribute('data-layout'))!); diff --git a/e2e/annotation-invariants/gestures.spec.ts b/e2e/annotation-invariants/gestures.spec.ts index 6330d851..190654ac 100644 --- a/e2e/annotation-invariants/gestures.spec.ts +++ b/e2e/annotation-invariants/gestures.spec.ts @@ -1,4 +1,5 @@ import { expect, test } from '@playwright/test'; +import { waitForResizeSettled } from '../settle'; const story = '/?story=features--annotation-gestures&mode=preview'; for (const width of [320, 390, 768, 1280]) @@ -115,7 +116,9 @@ for (const cancellation of ['Escape', 'pointercancel', 'touchcancel', 'replaceme else if (cancellation === 'width') { await page.setViewportSize({ width: 700, height: 900 }); await expect.poll(() => host.locator('svg').getAttribute('viewBox')).not.toContain('768'); - await page.waitForTimeout(100); + // Release only after every debounced resize render has landed, so the + // pointerup meets the rebuilt chart rather than a pending re-render. + await waitForResizeSettled(host); } else await page.evaluate((type) => document.dispatchEvent(new Event(type)), cancellation); await page.mouse.up(); await expect(page.getByTestId('edit-count')).toHaveText('0'); diff --git a/e2e/annotation-invariants/layout.spec.ts b/e2e/annotation-invariants/layout.spec.ts index cfb023c9..e7d509b8 100644 --- a/e2e/annotation-invariants/layout.spec.ts +++ b/e2e/annotation-invariants/layout.spec.ts @@ -1,99 +1,158 @@ import type { ChartLayout, ResolvedAnnotation } from '@opendata-ai/openchart-core'; -import { expect, test } from '@playwright/test'; +import { expect, test, type Page } from '@playwright/test'; +import { waitForResizeSettled } from '../settle'; -for (const width of [320, 390, 768, 1280]) for (const colorScheme of ['light', 'dark'] as const) { - for (const story of ['reference-labels', 'crowded-callouts', 'notes-sizing']) { - test(`${width} ${colorScheme}: ${story} layout and export`, async ({ page }) => { - await page.setViewportSize({ width, height: 900 }); - await page.emulateMedia({ colorScheme }); - await page.goto(`/?story=features--annotation-${story}&mode=preview`); - const charts = page.getByTestId('annotation-layout'); - await expect(charts.first().locator('svg')).toBeVisible(); - await page.evaluate(() => document.fonts.ready); - for (const chart of await charts.all()) { - await chart.dispatchEvent('fixture-layout'); - const layout: ChartLayout = JSON.parse((await chart.getAttribute('data-layout'))!); - expect(layout.theme.isDark).toBe(colorScheme === 'dark'); - const groups = layout.facet?.panels.map(p => p.annotations) ?? [layout.annotations]; - for (const annotations of groups) { - const visible = annotations.filter(a => a.label?.visible && !a.footnoteIndex); - for (const annotation of visible) { - const box = annotation.bounds ?? annotation.label!.bounds; - if (!box) continue; - expect(box.x, annotation.id).toBeGreaterThanOrEqual(-1); - expect(box.y, annotation.id).toBeGreaterThanOrEqual(-1); - expect(box.x + box.width, annotation.id).toBeLessThanOrEqual(layout.dimensions.width + 1); - expect(box.y + box.height, annotation.id).toBeLessThanOrEqual(layout.dimensions.height + 1); +for (const width of [320, 390, 768, 1280]) + for (const colorScheme of ['light', 'dark'] as const) { + for (const story of ['reference-labels', 'crowded-callouts', 'notes-sizing']) { + test(`${width} ${colorScheme}: ${story} layout and export`, async ({ page }) => { + await page.setViewportSize({ width, height: 900 }); + await page.emulateMedia({ colorScheme }); + await page.goto(`/?story=features--annotation-${story}&mode=preview`); + const charts = page.getByTestId('annotation-layout'); + await expect(charts.first().locator('svg')).toBeVisible(); + await page.evaluate(() => document.fonts.ready); + for (const chart of await charts.all()) { + await expect(chart).toHaveAttribute('data-oc-fonts-state', 'ready'); + if (colorScheme === 'dark') await expect(chart).toHaveClass(/oc-dark/); + else await expect(chart).not.toHaveClass(/oc-dark/); + await chart.dispatchEvent('fixture-layout'); + const layout: ChartLayout = JSON.parse((await chart.getAttribute('data-layout'))!); + expect(layout.theme.isDark).toBe(colorScheme === 'dark'); + const groups = layout.facet?.panels.map((p) => p.annotations) ?? [layout.annotations]; + for (const annotations of groups) { + const visible = annotations.filter((a) => a.label?.visible && !a.footnoteIndex); + for (const annotation of visible) { + const box = annotation.bounds ?? annotation.label!.bounds; + if (!box) continue; + expect(box.x, annotation.id).toBeGreaterThanOrEqual(-1); + expect(box.y, annotation.id).toBeGreaterThanOrEqual(-1); + expect(box.x + box.width, annotation.id).toBeLessThanOrEqual( + layout.dimensions.width + 1, + ); + expect(box.y + box.height, annotation.id).toBeLessThanOrEqual( + layout.dimensions.height + 1, + ); + } + const unpinned = visible.filter((a) => !a.id?.match(/^crowded-1[23]$/)); + for (let i = 0; i < unpinned.length; i++) + for (let j = i + 1; j < unpinned.length; j++) { + const a = unpinned[i].bounds, + b = unpinned[j].bounds; + if (!a || !b) continue; + const overlap = + Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x) > 1 && + Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y) > 1; + expect(overlap, `${unpinned[i].id}/${unpinned[j].id}`).toBe(false); + } + if (story === 'crowded-callouts') { + expect(visible.filter((a) => a.id?.match(/^crowded-1[23]$/))).toHaveLength(2); + expect(visible.length + (layout.chrome.footnotes?.length ?? 0)).toBe(14); + } + if (story === 'notes-sizing') + expect(visible.length + (layout.chrome.footnotes?.length ?? 0)).toBe(2); + for (const a of visible) assertConnector(a); } - const unpinned = visible.filter(a => !a.id?.match(/^crowded-1[23]$/)); - for (let i = 0; i < unpinned.length; i++) for (let j = i + 1; j < unpinned.length; j++) { - const a = unpinned[i].bounds, b = unpinned[j].bounds; - if (!a || !b) continue; - const overlap = Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x) > 1 && Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y) > 1; - expect(overlap, `${unpinned[i].id}/${unpinned[j].id}`).toBe(false); - } - if (story === 'crowded-callouts') { - expect(visible.filter(a => a.id?.match(/^crowded-1[23]$/))).toHaveLength(2); - expect(visible.length + (layout.chrome.footnotes?.length ?? 0)).toBe(14); - } - if (story === 'notes-sizing') expect(visible.length + (layout.chrome.footnotes?.length ?? 0)).toBe(2); - for (const a of visible) assertConnector(a); + expect( + await chart + .locator('svg') + .first() + .evaluate((svg) => svg.getBoundingClientRect().height), + ).toBeCloseTo(layout.dimensions.height, 1); + await chart.dispatchEvent('fixture-export'); + const exported = (await chart.getAttribute('data-export'))!; + expect(exported).not.toMatch(/oc-edit-handle|oc-selection-handle/); + await assertExportNotes(page, exported, layout); } - expect(await chart.locator('svg').first().evaluate(svg => svg.getBoundingClientRect().height)).toBeCloseTo(layout.dimensions.height, 1); - await chart.dispatchEvent('fixture-export'); - const exported = (await chart.getAttribute('data-export'))!; - expect(exported).not.toMatch(/oc-edit-handle|oc-selection-handle/); - for (const note of layout.chrome.footnotes ?? []) { - // Plain-text notes remain intentional in Track A, including literal bold markers. - expect(exported).toContain((note.lines?.[0] ?? `${note.index}. ${note.text}`).replaceAll('&', '&').replaceAll('<', '<')); + if (story === 'notes-sizing') { + const canvas = page.getByTestId('annotation-canvas'); + await expect(canvas.locator('canvas.oc-mark-canvas')).toBeAttached(); + await canvas.dispatchEvent('fixture-layout'); + await canvas.dispatchEvent('fixture-export'); + const canvasLayout: ChartLayout = JSON.parse((await canvas.getAttribute('data-layout'))!); + await assertExportNotes(page, (await canvas.getAttribute('data-export'))!, canvasLayout); + // Canvas changes only the mark renderer; annotation geometry and the + // figure-owned note band must match the equivalent SVG fixture. + const svgLayout: ChartLayout = JSON.parse( + (await charts.nth(4).getAttribute('data-layout'))!, + ); + expect(canvasLayout.annotations).toEqual(svgLayout.annotations); + expect(canvasLayout.chrome.footnotes).toEqual(svgLayout.chrome.footnotes); + expect(canvasLayout.dimensions).toEqual(svgLayout.dimensions); + await canvas.dispatchEvent('fixture-png'); + await expect(canvas).toHaveAttribute('data-png', /width/); + const png = JSON.parse((await canvas.getAttribute('data-png'))!); + expect(png.width).toBe(Math.floor(canvasLayout.dimensions.width)); + expect(png.height).toBe(Math.floor(canvasLayout.dimensions.height)); + const auto = page.getByTestId('annotation-auto-height'); + await auto.dispatchEvent('fixture-layout'); + const first: ChartLayout = JSON.parse((await auto.getAttribute('data-layout'))!); + expect(first.dimensions.height).toBeCloseTo(400 + (first.chrome.grownHeight ?? 0), 1); + await auto.dispatchEvent('fixture-png'); + await expect(auto).toHaveAttribute('data-png', /width/); + expect(JSON.parse((await auto.getAttribute('data-png'))!).height).toBe( + Math.floor(first.dimensions.height), + ); + // Auto-height grows the host, which re-fires the ResizeObserver. Wait + // for the mount to handle that echo (and any echo of its own render); + // a self-resize loop never settles, and a single re-render would show + // up as a changed height below. + await waitForResizeSettled(auto); + await auto.dispatchEvent('fixture-layout'); + expect(JSON.parse((await auto.getAttribute('data-layout'))!).dimensions.height).toBe( + first.dimensions.height, + ); } - } - if (story === 'notes-sizing') { - const canvas = page.getByTestId('annotation-canvas'); - await expect(canvas.locator('canvas.oc-mark-canvas')).toBeAttached(); - await canvas.dispatchEvent('fixture-layout'); - await canvas.dispatchEvent('fixture-export'); - const canvasLayout: ChartLayout = JSON.parse((await canvas.getAttribute('data-layout'))!); - for (const note of canvasLayout.chrome.footnotes ?? []) expect((await canvas.getAttribute('data-export'))!).toContain(note.text.replaceAll('&', '&').replaceAll('<', '<').split(' ').slice(0, 2).join(' ')); - // Canvas changes only the mark renderer; annotation geometry and the - // figure-owned note band must match the equivalent SVG fixture. - const svgLayout: ChartLayout = JSON.parse((await charts.nth(4).getAttribute('data-layout'))!); - expect(canvasLayout.annotations).toEqual(svgLayout.annotations); - expect(canvasLayout.chrome.footnotes).toEqual(svgLayout.chrome.footnotes); - expect(canvasLayout.dimensions).toEqual(svgLayout.dimensions); - await canvas.dispatchEvent('fixture-png'); - await expect(canvas).toHaveAttribute('data-png', /width/); - const png = JSON.parse((await canvas.getAttribute('data-png'))!); - expect(png.width).toBe(Math.floor(canvasLayout.dimensions.width)); - expect(png.height).toBe(Math.floor(canvasLayout.dimensions.height)); - const auto = page.getByTestId('annotation-auto-height'); - await auto.dispatchEvent('fixture-layout'); - const first: ChartLayout = JSON.parse((await auto.getAttribute('data-layout'))!); - expect(first.dimensions.height).toBeCloseTo(400 + (first.chrome.grownHeight ?? 0), 1); - await auto.dispatchEvent('fixture-png'); - await expect(auto).toHaveAttribute('data-png', /width/); - expect(JSON.parse((await auto.getAttribute('data-png'))!).height).toBe(Math.floor(first.dimensions.height)); - await page.waitForTimeout(250); - await auto.dispatchEvent('fixture-layout'); - expect(JSON.parse((await auto.getAttribute('data-layout'))!).dimensions.height).toBe(first.dimensions.height); - } - }); + }); + } } -} function assertConnector(annotation: ResolvedAnnotation) { const connector = annotation.label?.connector; const bounds = annotation.bounds; if (!connector?.endpoint || !bounds || connector.style === 'drop-line') return; - const cx = bounds.x + bounds.width / 2, cy = bounds.y + bounds.height / 2; - const dx = connector.endpoint.x - cx, dy = connector.endpoint.y - cy; + const cx = bounds.x + bounds.width / 2, + cy = bounds.y + bounds.height / 2; + const dx = connector.endpoint.x - cx, + dy = connector.endpoint.y - cy; const t = Math.min((bounds.width / 2 + 2) / Math.abs(dx), (bounds.height / 2 + 2) / Math.abs(dy)); if (connector.labelAttachment === 'left-center') { expect(connector.from.x).toBeCloseTo(bounds.x - 8, 1); expect(connector.from.y).toBeCloseTo(cy, 1); } else { - expect(Math.hypot(connector.from.x - (cx + dx * t), connector.from.y - (cy + dy * t))).toBeCloseTo(6, 1); + expect( + Math.hypot(connector.from.x - (cx + dx * t), connector.from.y - (cy + dy * t)), + ).toBeCloseTo(6, 1); } const radius = annotation.dot ? annotation.dot.radius + annotation.dot.strokeWidth / 2 : 0; - expect(Math.hypot(connector.to.x - connector.endpoint.x, connector.to.y - connector.endpoint.y)).toBeCloseTo(connector.arrow ? Math.max(radius + 2, 2) : Math.max(radius + 3, 4), 1); + expect( + Math.hypot(connector.to.x - connector.endpoint.x, connector.to.y - connector.endpoint.y), + ).toBeCloseTo(connector.arrow ? Math.max(radius + 2, 2) : Math.max(radius + 3, 4), 1); +} + +async function assertExportNotes(page: Page, source: string, layout: ChartLayout) { + const notes = await page.evaluate((svg) => { + const doc = new DOMParser().parseFromString(svg, 'image/svg+xml'); + return { + controls: doc.querySelectorAll( + '.oc-note-active, .oc-selection-overlay, .oc-anchor-handle, .oc-connector-handle', + ).length, + notes: [...doc.querySelectorAll('[data-note-spec-index]')].map((note) => ({ + label: note.getAttribute('aria-label'), + lines: [...note.children].map((line) => line.textContent), + bold: [...note.querySelectorAll('[font-weight="700"]')].map((span) => span.textContent), + })), + }; + }, source); + expect(notes.controls).toBe(0); + expect(notes.notes).toHaveLength(layout.chrome.footnotes?.length ?? 0); + for (const [index, note] of (layout.chrome.footnotes ?? []).entries()) { + const clean = (text: string) => text.replaceAll('**', ''); + expect(notes.notes[index].label).toBe( + `${note.index}. ${clean(note.text)}${note.subtitle ? `. ${clean(note.subtitle)}` : ''}`, + ); + expect(notes.notes[index].lines).toEqual((note.lines ?? []).map(clean)); + if (note.text.includes('**') || note.subtitle?.includes('**')) + expect(notes.notes[index].bold.length).toBeGreaterThan(0); + } } diff --git a/e2e/annotation-invariants/notes.spec.ts b/e2e/annotation-invariants/notes.spec.ts new file mode 100644 index 00000000..a419c97e --- /dev/null +++ b/e2e/annotation-invariants/notes.spec.ts @@ -0,0 +1,74 @@ +import { expect, test } from '@playwright/test'; +import { waitForResizeSettled } from '../settle'; + +for (const width of [320, 390, 768, 1280]) + for (const colorScheme of ['light', 'dark'] as const) { + test(`${width} ${colorScheme}: notes and markers share keyboard focus and clean export`, async ({ + page, + }) => { + await page.setViewportSize({ width, height: 900 }); + await page.emulateMedia({ colorScheme }); + await page.goto('/?story=features--annotation-crowded-callouts&mode=preview'); + const chart = page.getByTestId('annotation-layout').first(); + const firstNote = chart.locator('[data-note-spec-index]').first(); + await expect(chart.locator('svg')).toBeVisible(); + await page.evaluate(() => document.fonts.ready); + await expect(chart).toHaveAttribute('data-oc-fonts-state', 'ready'); + if (colorScheme === 'dark') await expect(chart).toHaveClass(/oc-dark/); + else await expect(chart).not.toHaveClass(/oc-dark/); + // This interaction fixture needs notes even when the viewport can fit all + // callouts. Full-width geometry remains covered by layout.spec.ts. + if (width === 1280) { + const chartWidth = await chart.evaluate((host) => { + host.style.maxWidth = '390px'; + return host.clientWidth; + }); + await expect + .poll(async () => + chart.locator('svg').evaluate((svg) => (svg as SVGSVGElement).viewBox.baseVal.width), + ) + .toBe(chartWidth); + } + // A re-render replaces the focused note, so let the entrance animation + // (which defers resizes) finish and the debounced resize settle before + // testing a user's focus action. + await expect(chart.locator('svg')).not.toHaveClass(/oc-animate/); + await waitForResizeSettled(chart); + await expect(firstNote).toBeVisible(); + const source = await firstNote.getAttribute('data-note-spec-index'); + const note = chart.locator(`[data-note-spec-index="${source}"]`); + const marker = chart.locator(`[data-note-marker-index="${source}"]`).first(); + await expect(chart.locator('svg')).toHaveAttribute('role', 'group'); + await expect(note).toHaveAttribute('role', 'listitem'); + await expect(marker).toHaveAttribute('role', 'button'); + await expect(note).not.toContainText('**'); + await note.focus(); + await expect(note).toHaveClass(/oc-note-active/); + await expect(marker).toHaveClass(/oc-note-active/); + await note.press('Enter'); + await expect(marker).toBeFocused(); + await marker.press('Space'); + await expect(note).toBeFocused(); + await expect(chart.locator('textarea, input, [contenteditable]')).toHaveCount(0); + await chart.dispatchEvent('fixture-export'); + const result = await chart.evaluate((host) => { + const doc = new DOMParser().parseFromString( + (host as HTMLElement).dataset.export!, + 'image/svg+xml', + ); + return { + active: doc.querySelectorAll( + '.oc-note-active, .oc-anchor-handle, .oc-connector-handle, .oc-selection-overlay', + ).length, + notes: [...doc.querySelectorAll('[data-note-spec-index]')].map((note) => + note.getAttribute('aria-label'), + ), + }; + }); + expect(result.active).toBe(0); + expect(result.notes).toContain(await note.getAttribute('aria-label')); + await expect(note).toHaveClass(/oc-note-active/); + await note.press('Escape'); + await expect(chart.locator('.oc-note-active')).toHaveCount(0); + }); + } diff --git a/e2e/chart-map-design/attribution.spec.ts b/e2e/chart-map-design/attribution.spec.ts new file mode 100644 index 00000000..600b225d --- /dev/null +++ b/e2e/chart-map-design/attribution.spec.ts @@ -0,0 +1,41 @@ +import { expect, test } from '@playwright/test'; + +for (const width of [390, 1280]) { + for (const variant of ['all-visualizations', 'custom-brand', 'large-text']) { + test(`${width}: ${variant} keeps complete attribution within every visualization`, async ({ page }) => { + await page.setViewportSize({ width, height: 950 }); + await page.goto(`/?story=gallery--attribution--${variant}&mode=preview`); + await expect(page.locator('[data-attribution-kind]')).toHaveCount(7); + await page.evaluate(async () => { + await document.fonts.ready; + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + }); + for (const kind of ['chart', 'map', 'barlist', 'sankey', 'tilemap', 'table', 'graph']) { + const card = page.locator(`[data-attribution-kind=${kind}]`); + await expect(card.locator('.oc-source')).toContainText('2020–2025'); + // SVG line breaks are separate tspans, without intervening text nodes. + await expect(card.locator('.oc-byline')).toContainText(/Open\s*research\s*team/); + await expect(card.locator('.oc-footer')).toContainText(/Methods\s*and\s*coverage/); + if (variant === 'all-visualizations') { + await expect(card.locator('.oc-watermark')).toHaveCount(1); + } else { + await expect(card.locator('.oc-brand')).toContainText(/Open\s*methods/); + await expect(card.locator('.oc-watermark')).toHaveCount(0); + } + const overflow = await card.evaluate((element) => { + const selectors = '.oc-source, .oc-byline, .oc-footer, .oc-brand, .oc-watermark'; + return [...element.querySelectorAll(selectors)].flatMap((text) => { + const box = text.getBoundingClientRect(); + const frame = text.ownerSVGElement!.getBoundingClientRect(); + return box.left < frame.left - 1 || box.right > frame.right + 1 || + box.top < frame.top - 1 || box.bottom > frame.bottom + 1 + ? [{ text: text.textContent, kind: element.getAttribute('data-attribution-kind') }] + : []; + }); + }); + expect(overflow, kind).toEqual([]); + } + }); + } +} diff --git a/e2e/chart-map-design/geo-labels.spec.ts b/e2e/chart-map-design/geo-labels.spec.ts new file mode 100644 index 00000000..10faffde --- /dev/null +++ b/e2e/chart-map-design/geo-labels.spec.ts @@ -0,0 +1,201 @@ +import { expect, type Locator, type Page, test } from '@playwright/test'; +import { waitForResizeSettled } from '../settle'; + +const story = '/?story=gallery--geographic-labels--places-and-notes&mode=preview'; +async function settle(page: Page) { + await page.evaluate(async () => { + await document.fonts.ready; + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + }); +} + +async function exportGeometry(host: Locator) { + await host.dispatchEvent('fixture-export'); + return host.evaluate((element) => { + const doc = new DOMParser().parseFromString(element.dataset.export!, 'image/svg+xml'); + return [...doc.querySelectorAll('[data-geo-label-id], [data-geo-note-id]')].map((node) => ({ + id: node.getAttribute('data-geo-label-id') ?? node.getAttribute('data-geo-note-id'), + content: node.textContent, + geometry: [node, ...node.querySelectorAll('*')].map((el) => + ['x', 'y', 'cx', 'cy', 'd', 'transform', 'font-size'].map((attr) => el.getAttribute(attr)), + ), + })); + }); +} + +for (const width of [390, 1280]) { + test(`${width}: complete inventory is independent of fixed-height map and survives replacement`, async ({ page }) => { + await page.setViewportSize({ width, height: 950 }); + await page.goto(story); + const host = page.getByTestId('geo-label-host'); + const disclosure = page.getByTestId('geo-label-disclosure'); + await expect(host.locator('svg.oc-map')).toBeVisible(); + await settle(page); + const height = await host.evaluate((el) => el.getBoundingClientRect().height); + const viewBox = await host.locator('svg.oc-map').getAttribute('viewBox'); + const camera = await host.getAttribute('data-camera'); + const hidden = host.locator('.oc-map-label-inventory'); + await expect(hidden).toContainText('California coast'); + await expect(hidden).toContainText('A place without a data row'); + await expect(hidden).toContainText('Austin detail at a closer zoom'); + await expect(hidden).toContainText('Visible at another zoom level'); + await disclosure.getByText('Map places and notes', { exact: true }).click(); + await expect(disclosure).toContainText('A place without a data row'); + expect(await host.evaluate((el) => el.getBoundingClientRect().height)).toBe(height); + expect(await host.locator('svg.oc-map').getAttribute('viewBox')).toBe(viewBox); + expect(await host.getAttribute('data-camera')).toBe(camera); + await page.getByRole('button', { name: 'Move place list' }).click(); + await expect(disclosure.locator('details')).toHaveCount(0); + await expect(page.getByTestId('geo-label-alternate').locator('details')).toHaveCount(1); + expect(await host.getAttribute('data-camera')).toBe(camera); + await page.getByRole('button', { name: 'Update a place name' }).click(); + await expect(hidden).toContainText('Texas updated'); + expect(await host.evaluate((el) => el.getBoundingClientRect().height)).toBe(height); + const described = await host.locator('svg.oc-map').evaluate((svg) => + (svg.getAttribute('aria-describedby') ?? '').split(/\s+/).some((id) => { + const node = document.getElementById(id); + return node?.textContent?.includes('Texas updated'); + }), + ); + expect(described).toBe(true); + }); + + test(`${width}: camera history does not affect settled geometry or standalone inventory`, async ({ page }) => { + await page.setViewportSize({ width, height: 950 }); + await page.goto(story); + const host = page.getByTestId('geo-label-host'); + await expect(host.locator('[data-geo-label-id]').first()).toBeVisible(); + await settle(page); + const before = await exportGeometry(host); + expect(before.length).toBeGreaterThan(0); + const camera = JSON.parse((await host.getAttribute('data-camera'))!); + await page.getByRole('button', { name: 'Show Texas' }).click(); + await settle(page); + await host.dispatchEvent('fixture-camera', { detail: camera }); + await settle(page); + expect(await exportGeometry(host)).toEqual(before); + const standalone = await host.getAttribute('data-export'); + expect(standalone).toContain('A place without a data row'); + expect(standalone).toContain('Austin detail at a closer zoom'); + expect(standalone).toContain('California coast'); + expect(standalone).not.toContain('foreignObject'); + const labelsInside = await host.evaluate((el) => { + const svg = el.querySelector('svg.oc-map')!.getBoundingClientRect(); + return [...el.querySelectorAll('[data-geo-label-id]')].every((label) => { + const r = label.getBoundingClientRect(); + return r.left >= svg.left - 1 && r.right <= svg.right + 1 && + r.top >= svg.top - 1 && r.bottom <= svg.bottom + 1; + }); + }); + expect(labelsInside).toBe(true); + }); +} + +test('invalid updates preserve the valid view and inventory', async ({ page }) => { + await page.goto(story); + const host = page.getByTestId('geo-label-host'); + await expect(host.locator('[data-geo-label-id]').first()).toBeVisible(); + await settle(page); + const geometry = await exportGeometry(host); + const camera = await host.getAttribute('data-camera'); + await host.dispatchEvent('fixture-invalid-update'); + await expect(host).toHaveAttribute('data-validation-error', /duplicate|unique/i); + expect(await exportGeometry(host)).toEqual(geometry); + expect(await host.getAttribute('data-camera')).toBe(camera); + await expect(host.locator('.oc-map-label-inventory')).toContainText('California coast'); +}); + +test('multiple maps keep accessible and SVG reference IDs separate', async ({ page }) => { + await page.goto('/?story=gallery--geographic-labels--multiple-maps&mode=preview'); + await expect(page.getByTestId('geo-label-second').locator('svg.oc-map')).toBeVisible(); + await settle(page); + const result = await page.evaluate(() => { + const hosts = [document.querySelector('[data-testid=geo-label-host]')!, + document.querySelector('[data-testid=geo-label-second]')!]; + const ids = hosts.flatMap((host) => [...host.querySelectorAll('[id]')].map((n) => n.id)); + const descriptionsLocal = hosts.every((host) => { + const svg = host.querySelector('svg.oc-map')!; + const refs = (svg.getAttribute('aria-describedby') ?? '').split(/\s+/).filter(Boolean); + return refs.length > 0 && refs.every((id) => host.contains(document.getElementById(id))); + }); + return { unique: new Set(ids).size === ids.length, descriptionsLocal }; + }); + expect(result).toEqual({ unique: true, descriptionsLocal: true }); +}); + +test('zoom keeps text at screen size and map controls clear of the size key', async ({ page }) => { + await page.setViewportSize({ width: 390, height: 950 }); + await page.goto(story); + const host = page.getByTestId('geo-label-host'); + await expect(host.locator('[data-geo-label-id]').first()).toBeVisible(); + await settle(page); + // Fonts and the initial debounced ResizeObserver can replace the SVG after + // its first label is visible. Wait for that render, then read one DOM snapshot. + await expect(host).toHaveAttribute('data-oc-fonts-state', 'ready'); + await waitForResizeSettled(host); + await expect(host.locator('svg text').filter({ hasText: /^Metro population$/ })).toBeVisible(); + const { controls, title } = await host.evaluate((element) => ({ + controls: element.querySelector('.oc-map-zoom-controls')?.getBoundingClientRect().toJSON() ?? null, + title: [...element.querySelectorAll('svg text')] + .find((text) => text.textContent === 'Metro population')?.getBoundingClientRect().toJSON() ?? null, + })); + expect(controls).not.toBeNull(); + expect(title).not.toBeNull(); + expect(controls!.x >= title!.x + title!.width || title!.x >= controls!.x + controls!.width || + controls!.y >= title!.y + title!.height || title!.y >= controls!.y + controls!.height).toBe(true); + const sizes = () => host.locator('[data-geo-label-id] text').evaluateAll((texts) => + Object.fromEntries(texts.map((text) => [text.textContent, text.getBoundingClientRect().height])), + ); + const before = await sizes(); + await page.getByRole('button', { name: 'Show Texas' }).click(); + await settle(page); + const after = await sizes(); + const shared = Object.keys(after).filter((name) => before[name] !== undefined); + expect(shared.length).toBeGreaterThan(0); + for (const name of shared) expect(after[name]).toBeCloseTo(before[name], 1); +}); + +test('schematic holes and unresolved anchors retain names without growing the map', async ({ page }) => { + await page.goto('/?story=gallery--geographic-labels--islands-and-holes&mode=preview'); + const host = page.getByTestId('geo-geometry-host'); + await expect(host.locator('[data-geo-label-id]').first()).toBeVisible(); + const inventory = host.locator('.oc-map-label-inventory'); + await expect(inventory).toContainText('Around the lake'); + await expect(inventory).toContainText('Island group'); + await expect(inventory).toContainText('A place outside this supplied geography'); + const height = await host.evaluate((el) => el.getBoundingClientRect().height); + await page.getByRole('button', { name: 'Show the small island' }).click(); + await settle(page); + await expect(host.locator('[data-geo-label-id="feature:islands"]')).toBeVisible(); + expect(await host.evaluate((el) => el.getBoundingClientRect().height)).toBe(height); + await page.getByRole('button', { name: 'All islands' }).click(); + await settle(page); + await expect(host.locator('[data-geo-label-id="feature:ring"]')).toBeVisible(); +}); + +for (const width of [390, 1280]) { + test(`${width}: multiple-map gallery controls remain valid and independent`, async ({ page }) => { + const errors: string[] = []; + page.on('pageerror', (error) => errors.push(error.message)); + await page.setViewportSize({ width, height: 950 }); + await page.goto('/?story=gallery--geographic-labels--multiple-maps&mode=preview'); + const first = page.getByTestId('geo-label-host'); + const second = page.getByTestId('geo-label-second'); + await expect(second.locator('svg.oc-map')).toBeVisible(); + await expect(page.getByRole('button', { name: 'Try an invalid update' })).toHaveCount(0); + const secondCamera = await second.getAttribute('data-camera'); + const secondGeometry = await exportGeometry(second); + for (const name of ['Show Texas', 'Full map', 'Update a place name', 'Move place list']) { + await page.getByRole('button', { name, exact: true }).click(); + await settle(page); + await expect(first.locator('svg.oc-map')).toBeVisible(); + expect(await second.getAttribute('data-camera')).toBe(secondCamera); + expect(await exportGeometry(second)).toEqual(secondGeometry); + } + await expect(first.locator('.oc-map-label-inventory')).toContainText('Texas updated'); + await expect(second.locator('.oc-map-label-inventory')).toContainText('Texas triangle'); + await expect(page.getByText(/Error: Invalid spec/)).toHaveCount(0); + expect(errors).toEqual([]); + }); +} diff --git a/e2e/chart-map-design/geo-views.spec.ts b/e2e/chart-map-design/geo-views.spec.ts new file mode 100644 index 00000000..bd0cce5d --- /dev/null +++ b/e2e/chart-map-design/geo-views.spec.ts @@ -0,0 +1,213 @@ +import { expect, type Locator, type Page, test } from '@playwright/test'; + +const story = (name: string) => `/?story=gallery--geographic-views--${name}&mode=preview`; +async function settle(page: Page) { + await page.evaluate(async () => { + await document.fonts.ready; + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + }); +} +async function exported(host: Locator) { + await host.dispatchEvent('fixture-export'); + return host.getAttribute('data-export'); +} +async function cameras(host: Locator) { + return JSON.parse((await host.getAttribute('data-cameras'))!); +} +for (const width of [390, 1280]) { + test(`${width}: Texas detail shares immutable fit and preserves Austin/RGV point geometry`, async ({ + page, + }) => { + await page.setViewportSize({ width, height: 1000 }); + await page.goto(story('texas-and-austin')); + const host = page.getByTestId('geo-texas-views'); + await expect(host.locator('svg.oc-map')).toBeVisible(); + await settle(page); + const points = await host.getAttribute('data-points'); + expect(JSON.parse(points!)).toHaveLength(4); + const detail = host.locator('[data-geo-layer-id="travis-tracts"]'); + await expect(detail).toHaveAttribute('display', 'none'); + await page.getByRole('button', { name: 'Austin detail', exact: true }).click(); + await settle(page); + await expect(detail).not.toHaveAttribute('display', 'none'); + expect(await detail.locator('path').count()).toBe(290); + expect(await host.getAttribute('data-points')).toBe(points); + await page.getByRole('button', { name: 'Toggle tract context', exact: true }).click(); + await settle(page); + await expect(host.locator('[data-geo-layer-id="travis-tracts"]')).toHaveCount(0); + expect(await host.getAttribute('data-points')).toBe(points); + await page.getByRole('button', { name: 'Toggle tract context', exact: true }).click(); + await settle(page); + expect(await host.getAttribute('data-points')).toBe(points); + const svg = await exported(host); + expect(svg).toContain('travis-tracts'); + expect(svg).not.toContain('foreignObject'); + }); + test(`${width}: explicit inset coverage has readable separate-scale captions and independent cameras`, async ({ + page, + }) => { + await page.setViewportSize({ width, height: 1000 }); + await page.goto(story('separate-scales')); + const host = page.getByTestId('geo-inset-views'); + await expect(host.locator('svg.oc-map')).toBeVisible(); + await settle(page); + await expect(host.locator('[data-geo-view-id]')).toHaveCount(3); + const views = JSON.parse((await host.getAttribute('data-views'))!); + const root = views.find((v: { id: string }) => v.id === 'root'); + expect(root.features).not.toContain('02'); + expect(root.features).not.toContain('15'); + expect(views.find((v: { id: string }) => v.id === 'alaska').features).toEqual(['02']); + expect(views.find((v: { id: string }) => v.id === 'hawaii').features).toEqual(['15']); + for (const id of ['alaska', 'hawaii']) { + const view = host.locator(`[data-geo-view-id="${id}"]`); + const captions = await view.locator(':scope > text').allTextContents(); + expect(captions.join(' ')).toMatch(/Alaska|Hawaii/); + expect(captions.join(' ')).toMatch(/separate scale/i); + } + const collisions = await host.evaluate((element) => { + const controls = [...element.querySelectorAll('.oc-map-zoom-controls')].map((node) => + node.getBoundingClientRect(), + ); + return [...element.querySelectorAll('[data-geo-label-id]')] + .filter((node) => { + const label = node.getBoundingClientRect(); + return controls.some( + (control) => + Math.min(label.right, control.right) - Math.max(label.left, control.left) > 0.5 && + Math.min(label.bottom, control.bottom) - Math.max(label.top, control.top) > 0.5, + ); + }) + .map((node) => node.textContent); + }); + expect(collisions).toEqual([]); + const before = await cameras(host); + await host.evaluate( + (element, camera) => { + element.dispatchEvent( + new CustomEvent('fixture-camera', { detail: { viewId: 'alaska', camera } }), + ); + }, + { ...before.alaska, k: before.alaska.k * 1.5 }, + ); + await settle(page); + const after = await cameras(host); + expect(after.root).toEqual(before.root); + expect(after.hawaii).toEqual(before.hawaii); + expect(after.alaska.k).toBeGreaterThan(before.alaska.k); + await page.getByRole('button', { name: 'Reset main view', exact: true }).click(); + await settle(page); + expect((await cameras(host)).alaska).toEqual(after.alaska); + const svg = await exported(host); + expect(svg).toContain('Alaska'); + expect(svg).toContain('Hawaii'); + expect(svg).toMatch(/Separate scale/i); // The accessible coverage description is a single string. + }); +} +test('incompatible identity source planes reject updates while preserving the last valid view', async ({ + page, +}) => { + await page.goto(story('texas-and-austin')); + const host = page.getByTestId('geo-texas-views'); + await expect(host.locator('svg.oc-map')).toBeVisible(); + await settle(page); + const before = await host.getAttribute('data-points'), + camera = await host.getAttribute('data-cameras'); + await host.dispatchEvent('fixture-invalid-plane'); + await expect(host).toHaveAttribute('data-validation-error', /sourcePlane|source plane/i); + expect(await host.getAttribute('data-points')).toBe(before); + expect(await host.getAttribute('data-cameras')).toBe(camera); + await expect(host.locator('svg.oc-map')).toBeVisible(); + for (const scope of ['view', 'layer'] as const) { + await host.evaluate((element, scope) => { + element.dispatchEvent(new CustomEvent('fixture-invalid-scope', { detail: scope })); + }, scope); + await expect(host).toHaveAttribute('data-scope-error', scope === 'view' ? /view/i : /layer/i); + expect(await host.getAttribute('data-points')).toBe(before); + expect(await host.getAttribute('data-cameras')).toBe(camera); + } +}); +test('two inset maps export independently scoped clips with resolvable references', async ({ + page, +}) => { + await page.goto(story('two-maps')); + const first = page.getByTestId('geo-inset-first'), + second = page.getByTestId('geo-inset-second'); + await expect(first.locator('svg.oc-map')).toBeVisible(); + await expect(second.locator('svg.oc-map')).toBeVisible(); + await settle(page); + await exported(first); + await exported(second); + const result = await page.evaluate(() => { + const strings = ['geo-inset-first', 'geo-inset-second'].map( + (id) => document.querySelector(`[data-testid="${id}"]`)!.dataset.export!, + ); + const docs = strings.map((svg) => new DOMParser().parseFromString(svg, 'image/svg+xml')); + const ids = docs.flatMap((doc) => [...doc.querySelectorAll('[id]')].map((node) => node.id)); + const unresolved = docs.flatMap((doc) => + [...doc.querySelectorAll('*')].flatMap((node) => + [...node.attributes].flatMap((attr) => + [...attr.value.matchAll(/url\(#([^)]*)\)/g)] + .filter((match) => !doc.getElementById(match[1])) + .map((match) => match[1]), + ), + ), + ); + return { + ids, + unresolved, + viewCounts: docs.map((doc) => doc.querySelectorAll('[data-geo-view-id]').length), + }; + }); + expect(result.viewCounts).toEqual([3, 3]); + expect(new Set(result.ids).size).toBe(result.ids.length); + expect(result.unresolved).toEqual([]); +}); + +test('one Alaska observation pins both explicitly duplicated view representations', async ({ + page, +}) => { + await page.goto(story('duplicated-place')); + const host = page.getByTestId('geo-duplicate-view'); + await expect(host.locator('[data-geo-view-id]')).toHaveCount(3); + await settle(page); + await page.getByRole('button', { name: 'Pin Alaska', exact: true }).click(); + await expect(page.getByTestId('geo-view-reader-panel')).toContainText('Alaska'); + const selection = JSON.parse((await host.getAttribute('data-reader'))!); + expect(selection.pinned).toHaveLength(1); + expect(selection.pinned[0].observation).toBe('feature:02'); + await expect(host.locator('[data-oc-reader-overlay] path')).toHaveCount(2); +}); + +for (const width of [390, 1280]) { + test(`${width}: larger inset captions remain inside their measured frames`, async ({ page }) => { + await page.setViewportSize({ width, height: 1000 }); + await page.goto(story('separate-scales')); + const host = page.getByTestId('geo-inset-views'); + await page.getByRole('button', { name: 'Enlarge caption text', exact: true }).click(); + await expect(host.locator('[data-geo-view-id]')).toHaveCount(3); + await settle(page); + const overflow = await host.evaluate((element) => + [...element.querySelectorAll('[data-geo-view-id]:not([data-geo-view-id="root"])')].flatMap( + (view) => { + const frame = view.querySelector(':scope > rect')!.getBoundingClientRect(); + return [...view.querySelectorAll(':scope > text')] + .filter((text) => { + const box = text.getBoundingClientRect(); + return ( + box.left < frame.left - 0.5 || + box.right > frame.right + 0.5 || + box.top < frame.top - 0.5 || + box.bottom > frame.bottom + 0.5 + ); + }) + .map((text) => text.textContent); + }, + ), + ); + expect(overflow).toEqual([]); + expect( + await host.locator('[data-geo-view-id="alaska"] > text').first().getAttribute('font-size'), + ).toBe('24'); + }); +} diff --git a/e2e/chart-map-design/reader.spec.ts b/e2e/chart-map-design/reader.spec.ts new file mode 100644 index 00000000..d1710036 --- /dev/null +++ b/e2e/chart-map-design/reader.spec.ts @@ -0,0 +1,102 @@ +import { expect, type Locator, type Page, test } from '@playwright/test'; + +async function settle(page: Page) { + await page.evaluate(async () => { + await document.fonts.ready; + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + }); +} +async function pinNext(host: Locator) { + await host.focus(); + await host.press('ArrowRight'); + await host.press('Enter'); +} + +for (const width of [390, 1280]) { + test(`${width}: date slices preserve sparse observations and reconcile keyed updates`, async ({ page }) => { + await page.setViewportSize({ width, height: 950 }); + await page.goto('/?story=gallery--reader-comparison--dates&mode=preview'); + const host = page.locator('[data-reader-chart]'); + const panel = page.getByRole('complementary', { name: 'Date comparison', exact: true }); + await expect(host.locator('svg.oc-chart')).toBeVisible(); + await settle(page); + await pinNext(host); + await pinNext(host); + await expect(panel.getByRole('heading', { name: 'A: 2022' })).toBeVisible(); + await expect(panel.getByRole('heading', { name: 'B: 2023' })).toBeVisible(); + await expect(panel).toContainText('No observation'); + await expect(panel).toContainText('3 percentage points'); + await expect(panel).toContainText('Change unavailable'); + await pinNext(host); + await expect(panel.getByRole('heading', { name: 'A: 2022' })).toBeVisible(); + await expect(panel.getByRole('heading', { name: 'B: 2024' })).toBeVisible(); + await page.getByRole('button', { name: 'Reorder observations' }).click(); + await expect(panel.getByRole('heading', { name: 'B: 2024' })).toBeVisible(); + await page.getByRole('button', { name: 'Remove 2024' }).click(); + await expect(panel.getByRole('heading', { name: 'B: 2024' })).toHaveCount(0); + await expect(panel.getByRole('heading', { name: 'A: 2022' })).toBeVisible(); + await page.getByRole('button', { name: 'Move comparison panel' }).click(); + await expect(panel.locator('.oc-reader-panel')).toHaveCount(0); + const alternate = page.getByRole('complementary', { name: 'Alternate date comparison' }); + await expect(alternate.getByRole('heading', { name: 'A: 2022' })).toBeVisible(); + await alternate.getByRole('button', { name: 'Clear selection' }).click(); + await expect(host.locator('.oc-reader-guides [data-reader-slice]')).toHaveCount(0); + }); + + test(`${width}: place search and pins do not change camera; exports omit transient selection`, async ({ page }) => { + await page.setViewportSize({ width, height: 950 }); + await page.goto('/?story=gallery--reader-comparison--places&mode=preview'); + const host = page.locator('[data-reader-map]'); + const companion = page.getByRole('complementary', { name: 'Find and rank places' }); + const panel = page.getByRole('complementary', { name: 'Place comparison' }); + await expect(host.locator('svg.oc-map')).toBeVisible(); + await settle(page); + const camera = await host.getAttribute('data-camera'); + const viewBox = await host.locator('svg.oc-map').getAttribute('viewBox'); + await companion.getByRole('button', { name: /^1\. California: 42/ }).click(); + await companion.getByRole('button', { name: /^2\. Texas: 31/ }).click(); + await expect(panel.getByRole('heading', { name: 'A: California' })).toBeVisible(); + await expect(panel.getByRole('heading', { name: 'B: Texas' })).toBeVisible(); + await expect(panel).toContainText('percentage points'); + expect(await host.getAttribute('data-camera')).toBe(camera); + expect(await host.locator('svg.oc-map').getAttribute('viewBox')).toBe(viewBox); + await host.dispatchEvent('fixture-export'); + const exported = await host.getAttribute('data-export'); + expect(exported).toContain('Regions per range'); + expect(exported).not.toMatch(/oc-map-reader|oc-reader-panel|foreignObject/); + await companion.getByRole('searchbox', { name: 'Find a place' }).fill('Washington'); + await companion.getByRole('button', { name: /Washington: 0/ }).click(); + await expect(panel.getByRole('heading', { name: 'B: Washington' })).toBeVisible(); + await expect(panel).toContainText('0 %'); + await companion.getByRole('searchbox', { name: 'Find a place' }).fill('Alabama'); + await companion.getByRole('button', { name: /^Alabama: No data/ }).click(); + await expect(panel.getByRole('heading', { name: 'B: Alabama' })).toBeVisible(); + await expect(panel).toContainText('No data'); + await expect(panel).toContainText('A comparison needs two observed finite values.'); + expect(await host.getAttribute('data-camera')).toBe(camera); + await companion.getByRole('button', { name: 'Show Alabama on map' }).click(); + await expect(host).not.toHaveAttribute('data-camera', camera!); + }); +} + +test('map keyboard inspection and Escape leave the fixed frame intact', async ({ page }) => { + await page.goto('/?story=gallery--reader-comparison--places&mode=preview'); + const host = page.locator('[data-reader-map]'); + await expect(host.locator('svg.oc-map')).toBeVisible(); + await settle(page); + const camera = await host.getAttribute('data-camera'); + const inspect = host.getByRole('button', { name: /^Inspect places/ }); + await inspect.focus(); + await inspect.press('ArrowRight'); + await inspect.press('Enter'); + const panel = page.getByRole('complementary', { name: 'Place comparison' }); + await expect(panel.locator('[data-reader-slot=A]')).toHaveCount(1); + await inspect.press('ArrowRight'); + await inspect.press('Enter'); + await expect(panel.locator('[data-reader-slot=B]')).toHaveCount(1); + expect(await host.getAttribute('data-camera')).toBe(camera); + await inspect.press('Escape'); + await expect(panel.locator('[data-reader-slot]')).toHaveCount(0); + expect(await host.getAttribute('data-camera')).toBe(camera); +}); diff --git a/e2e/invariants/canvas-alpha-parity.spec.ts b/e2e/invariants/canvas-alpha-parity.spec.ts index 253ef3e9..9871d1fb 100644 --- a/e2e/invariants/canvas-alpha-parity.spec.ts +++ b/e2e/invariants/canvas-alpha-parity.spec.ts @@ -42,8 +42,19 @@ test('canvas composites stacked translucent points like SVG does', async ({ page await page.waitForSelector('#parity-svg.oc-root svg.oc-chart'); await page.waitForSelector('#parity-canvas canvas.oc-mark-canvas'); await page.evaluate(() => document.fonts.ready); - // The canvas layer paints on a rAF tick; give it a couple of frames to land. - await page.waitForTimeout(200); + // The post-font recompile rebuilds the canvas layer, so wait for it first. + await page.waitForSelector('#parity-canvas[data-oc-fonts-state="ready"] canvas.oc-mark-canvas'); + // The canvas layer paints on a rAF tick, all marks in one pass (the story + // sets `animation: false`, so the first paint is the final one). Any + // non-transparent pixel means that pass has landed. + await page.waitForFunction(() => { + const c = document.querySelector('#parity-canvas canvas.oc-mark-canvas') as HTMLCanvasElement | null; + const ctx = c?.getContext('2d'); + if (!c || !ctx || c.width === 0 || c.height === 0) return false; + const { data } = ctx.getImageData(0, 0, c.width, c.height); + for (let i = 3; i < data.length; i += 4) if (data[i] !== 0) return true; + return false; + }); const sample = await page.evaluate(() => { const markCanvas = document.querySelector( diff --git a/e2e/invariants/known-bugs.spec.ts b/e2e/invariants/known-bugs.spec.ts index 74a1dcd6..e7693016 100644 --- a/e2e/invariants/known-bugs.spec.ts +++ b/e2e/invariants/known-bugs.spec.ts @@ -1,4 +1,6 @@ import { expect, test } from '@playwright/test'; +import { waitForResizeSettled } from '../settle'; +import { DEFAULT_THEME } from '../../packages/core/src/theme/defaults'; /** * Layout invariants that were once red-locked bugs and are now fixed. @@ -20,7 +22,8 @@ test('rotated x-axis labels do not overlap source text', async ({ page }) => { // Wait for the chart to render. await page.waitForSelector('.oc-root'); await page.evaluate(() => document.fonts.ready); - await page.waitForTimeout(100); + await page.waitForSelector('.oc-root[data-oc-fonts-state="ready"] svg.oc-chart:not(.oc-animate)'); + await waitForResizeSettled(page.locator('.oc-root').first()); const overlap = await page.evaluate(() => { // Collect bounding rects for all x-axis tick labels. @@ -53,18 +56,14 @@ test('rotated x-axis labels do not overlap source text', async ({ page }) => { // Primary invariant: the source text must never overlap the axis labels. expect(overlap.gap, 'source text overlaps rotated x-axis labels').toBeGreaterThanOrEqual(0); - // Secondary: the gap should stay a sane, readable size — roughly the theme's - // chartToFooter spacing (default 8px) without a large dead band. The exact - // value drifts by engine: Blink and WebKit place the bottom edge of a -45° - // rotated glyph several pixels apart for the same layout, so we bound the - // gap to a range that fits every engine (Chrome desktop ~3px, mobile WebKit - // ~19px) rather than pinning it to a tight window it can't hold. The bottom - // extent now reserves space from the real canvas-measured label width (axes - // and planner agree on the measurer), which on WebKit-mobile measures the - // rotated labels a few pixels wider than the old heuristic — a slightly more - // conservative reservation, never an overlap. + // Keep the same 14px cross-engine glyph-bounds tolerance above the theme's + // footer spacing. v8 used 8px + 14px = 22px; v9 deliberately uses 12px + + // 14px = 26px. WebKit places the bottom of a rotated glyph several pixels + // higher than Blink for the same reserved extent. The no-overlap bound above + // stays strict; this upper bound still rejects a large accidental dead band. + const maxGap = DEFAULT_THEME.spacing.chartToFooter + 14; expect( overlap.gap, - `gap between axis labels and source should be readable (0-22px), got ${overlap.gap.toFixed(1)}px`, - ).toBeLessThanOrEqual(22); + `gap between axis labels and source should be readable (0-${maxGap}px), got ${overlap.gap.toFixed(1)}px`, + ).toBeLessThanOrEqual(maxGap); }); diff --git a/e2e/invariants/library-interactions.spec.ts b/e2e/invariants/library-interactions.spec.ts index d0bd518c..b44b5479 100644 --- a/e2e/invariants/library-interactions.spec.ts +++ b/e2e/invariants/library-interactions.spec.ts @@ -79,9 +79,13 @@ test('table: Escape wins over pending search, sort retains focus and priority ce await search.press('Escape'); await expect(search).toHaveValue(''); await expect(host.locator('tbody')).toBeFocused(); - // Wait past the debounce and prove the stale query never returns. + // Prove the stale query never returns. The pending search is a 200ms + // setTimeout in table-mount.ts (handleSearchInput), scheduled before Escape. + // A page-side timer of the same delay scheduled now runs after it (equal + // delays run in scheduling order), so if the stale search were going to + // fire it has already re-rendered by the time this resolves. await expect(host.locator('tbody tr')).toHaveCount(10); - await page.waitForTimeout(250); + await page.evaluate(() => new Promise((resolve) => setTimeout(resolve, 200))); await expect(host.locator('tbody tr')).toHaveCount(10); const header = host.locator('th[data-column="state"]'); await header.focus(); diff --git a/e2e/invariants/rendered-invariants.spec.ts b/e2e/invariants/rendered-invariants.spec.ts index 6e34e56c..859e0e56 100644 --- a/e2e/invariants/rendered-invariants.spec.ts +++ b/e2e/invariants/rendered-invariants.spec.ts @@ -1,4 +1,5 @@ import { expect, test } from '@playwright/test'; +import { waitForResizeSettled } from '../settle'; /** * Layout invariant checks on real rendered charts. @@ -25,7 +26,10 @@ for (const { name, slug } of stories) { await page.goto(`/?story=${encodeURIComponent(slug)}&mode=preview`); await page.waitForSelector('.oc-root'); await page.evaluate(() => document.fonts.ready); - await page.waitForTimeout(100); + // Settled render: the post-font recompile ran and the entrance animation + // (which defers resizes) finished, then any debounced resize was handled. + await page.waitForSelector('.oc-root[data-oc-fonts-state="ready"] svg.oc-chart:not(.oc-animate)'); + await waitForResizeSettled(page.locator('.oc-root').first()); const violations = await page.evaluate(() => { const violations: string[] = []; @@ -187,7 +191,10 @@ for (const { name, slug } of stories) { await page.goto(`/?story=${encodeURIComponent(slug)}&mode=preview`); await page.waitForSelector('.oc-root'); await page.evaluate(() => document.fonts.ready); - await page.waitForTimeout(100); + // Settled render: the post-font recompile ran and the entrance animation + // (which defers resizes) finished, then any debounced resize was handled. + await page.waitForSelector('.oc-root[data-oc-fonts-state="ready"] svg.oc-chart:not(.oc-animate)'); + await waitForResizeSettled(page.locator('.oc-root').first()); const violations = await page.evaluate(() => { const violations: string[] = []; @@ -261,7 +268,8 @@ test('map legend anatomy: us-states-light', async ({ page }) => { ); await page.waitForSelector('svg.oc-map'); await page.evaluate(() => document.fonts.ready); - await page.waitForTimeout(100); + await page.waitForSelector('.oc-map-root[data-oc-fonts-state="ready"] svg.oc-map:not(.oc-animate)'); + await waitForResizeSettled(page.locator('.oc-map-root').first()); const violations = await page.evaluate(() => { const violations: string[] = []; @@ -321,7 +329,8 @@ test('sankey labels stay inside the svg: sankey-energy', async ({ page }) => { await page.goto(`/?story=${encodeURIComponent('testing--fixtures-sankey--energy')}&mode=preview`); await page.waitForSelector('svg.oc-sankey'); await page.evaluate(() => document.fonts.ready); - await page.waitForTimeout(100); + await page.waitForSelector('.oc-sankey-root[data-oc-fonts-state="ready"] svg.oc-sankey:not(.oc-animate)'); + await waitForResizeSettled(page.locator('.oc-sankey-root').first()); const violations = await page.evaluate(() => { const violations: string[] = []; @@ -372,7 +381,8 @@ test('no-data features render a hatch pattern: world-diverging-quantize', async ); await page.waitForSelector('svg.oc-map'); await page.evaluate(() => document.fonts.ready); - await page.waitForTimeout(100); + await page.waitForSelector('.oc-map-root[data-oc-fonts-state="ready"] svg.oc-map:not(.oc-animate)'); + await waitForResizeSettled(page.locator('.oc-map-root').first()); const fills = await page.evaluate(() => { const svg = document.querySelector('svg.oc-map'); diff --git a/e2e/settle.ts b/e2e/settle.ts new file mode 100644 index 00000000..429d0429 --- /dev/null +++ b/e2e/settle.ts @@ -0,0 +1,37 @@ +import type { Locator } from '@playwright/test'; + +/** + * Mirrors DEBOUNCE_MS in packages/vanilla/src/resize-observer.ts. If that + * debounce grows, raise this to match or the wait below stops covering it. + */ +const RESIZE_DEBOUNCE_MS = 16; + +/** + * Resolve once the chart mount has handled every ResizeObserver notification + * for `host`, including the echo of any render those notifications caused. + * + * The observer installed here is created after the chart's own, so within one + * notification the chart schedules its debounce timer first. Timers with equal + * delay run in scheduling order, so when ours fires the chart's has already + * run and any render it triggered is in the DOM. A render that changes the + * host's size produces a new notification, which re-arms ours. The promise + * therefore resolves only when the host is size-stable; a resize feedback loop + * never resolves and the test times out. + */ +export async function waitForResizeSettled(host: Locator): Promise { + await host.evaluate( + (el, debounceMs) => + new Promise((resolve) => { + let timer: ReturnType | undefined; + const observer = new ResizeObserver(() => { + clearTimeout(timer); + timer = setTimeout(() => { + observer.disconnect(); + resolve(); + }, debounceMs); + }); + observer.observe(el); + }), + RESIZE_DEBOUNCE_MS, + ); +} diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/bar-vertical-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/bar-vertical-mobile-visual-mobile-darwin.png index e044fb38..42c20947 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/bar-vertical-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/bar-vertical-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/dashboard-kpi-tile-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/dashboard-kpi-tile-mobile-visual-mobile-darwin.png index 64e1ff64..81ce6f7a 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/dashboard-kpi-tile-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/dashboard-kpi-tile-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/line-multi-series-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/line-multi-series-mobile-visual-mobile-darwin.png index 9d311e3d..52aedcfd 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/line-multi-series-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/line-multi-series-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-auto-height-chrome-growth-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-auto-height-chrome-growth-mobile-visual-mobile-darwin.png index 9b978653..2dcc9f6e 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-auto-height-chrome-growth-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-auto-height-chrome-growth-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-chrome-layout-grow-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-chrome-layout-grow-mobile-visual-mobile-darwin.png index cbeb9e22..bb47b47b 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-chrome-layout-grow-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-chrome-layout-grow-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-chrome-max-lines-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-chrome-max-lines-mobile-visual-mobile-darwin.png index 9eb1e1be..95aa1dde 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-chrome-max-lines-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-chrome-max-lines-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-bars-many-rows-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-bars-many-rows-mobile-visual-mobile-darwin.png index 40828c8e..5a678e49 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-bars-many-rows-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-bars-many-rows-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-bars-sparse-ticks-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-bars-sparse-ticks-mobile-visual-mobile-darwin.png index f029598f..0fdc98a4 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-bars-sparse-ticks-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-bars-sparse-ticks-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-columns-labels-all-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-columns-labels-all-mobile-visual-mobile-darwin.png index 155e8764..1acafc63 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-columns-labels-all-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-grouped-columns-labels-all-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-inline-y-title-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-inline-y-title-mobile-visual-mobile-darwin.png index bfabfd77..7499a086 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-inline-y-title-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-inline-y-title-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-long-title-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-long-title-mobile-visual-mobile-darwin.png index ba5900e5..632b42fe 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-long-title-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-long-title-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-one-wide-x-label-large-ticks-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-one-wide-x-label-large-ticks-mobile-visual-mobile-darwin.png index a0e53223..2b524f0b 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-one-wide-x-label-large-ticks-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-one-wide-x-label-large-ticks-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-one-wide-x-label-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-one-wide-x-label-mobile-visual-mobile-darwin.png index f66f527c..818dc688 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-one-wide-x-label-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-one-wide-x-label-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-reference-lane-overflow-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-reference-lane-overflow-mobile-visual-mobile-darwin.png new file mode 100644 index 00000000..0c826cd6 Binary files /dev/null and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-reference-lane-overflow-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-uniform-short-x-labels-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-uniform-short-x-labels-mobile-visual-mobile-darwin.png index f2fae404..a2e82093 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-uniform-short-x-labels-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/mr-uniform-short-x-labels-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/stacked-column-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/stacked-column-mobile-visual-mobile-darwin.png index 11ce198e..b771509b 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/stacked-column-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/stacked-column-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/table-cards-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/table-cards-mobile-visual-mobile-darwin.png index 5fca2dfd..57eb01c6 100644 Binary files a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/table-cards-mobile-visual-mobile-darwin.png and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/table-cards-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-crowded-callouts-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-crowded-callouts-mobile-visual-mobile-darwin.png new file mode 100644 index 00000000..f6f2afb8 Binary files /dev/null and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-crowded-callouts-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-curves-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-curves-mobile-visual-mobile-darwin.png new file mode 100644 index 00000000..82e4eb5f Binary files /dev/null and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-curves-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-notes-sizing-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-notes-sizing-mobile-visual-mobile-darwin.png new file mode 100644 index 00000000..0e45386c Binary files /dev/null and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-notes-sizing-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-reference-labels-mobile-visual-mobile-darwin.png b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-reference-labels-mobile-visual-mobile-darwin.png new file mode 100644 index 00000000..3e3d747b Binary files /dev/null and b/e2e/visual/__screenshots__/stories-mobile.spec.ts-snapshots/v9-reference-labels-mobile-visual-mobile-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-compact-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-compact-visual-darwin.png index a39c7c5d..3f64e0b0 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-compact-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-compact-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-donut-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-donut-visual-darwin.png index dd7a36dd..bdc52824 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-donut-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-donut-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-stacked-dark-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-stacked-dark-visual-darwin.png index 105f0989..d60de70f 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-stacked-dark-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-stacked-dark-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-stacked-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-stacked-visual-darwin.png index 105f0989..d60de70f 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-stacked-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/a11y-pattern-fills-stacked-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/agents-chat-analyst-final-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/agents-chat-analyst-final-visual-darwin.png index eefec222..efbeb178 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/agents-chat-analyst-final-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/agents-chat-analyst-final-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bar-horizontal-gradient-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bar-horizontal-gradient-visual-darwin.png index f470434e..ac41d4b8 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bar-horizontal-gradient-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bar-horizontal-gradient-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bar-vertical-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bar-vertical-visual-darwin.png index 3b821bd6..68fcc65c 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bar-vertical-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bar-vertical-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-basic-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-basic-visual-darwin.png index 161380df..7aba447f 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-basic-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-basic-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-grouped-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-grouped-visual-darwin.png index faaa508c..750ddd59 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-grouped-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-grouped-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-sized-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-sized-visual-darwin.png index 43281a1f..e0acb297 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-sized-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/beeswarm-sized-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bump-constructors-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bump-constructors-visual-darwin.png index 5cd90596..1eeeff15 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bump-constructors-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/bump-constructors-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-compact-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-compact-visual-darwin.png index 4b58f440..9f9973ef 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-compact-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-compact-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-diverging-year-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-diverging-year-visual-darwin.png index ada2c413..93663591 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-diverging-year-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-diverging-year-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-sequential-two-years-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-sequential-two-years-visual-darwin.png index 327ae70b..3b5241ac 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-sequential-two-years-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/calendar-sequential-two-years-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/canvas-scatter-static-dark-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/canvas-scatter-static-dark-visual-darwin.png index 671a3af2..8d82a350 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/canvas-scatter-static-dark-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/canvas-scatter-static-dark-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/canvas-scatter-static-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/canvas-scatter-static-visual-darwin.png index da15eed8..ef31e3b3 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/canvas-scatter-static-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/canvas-scatter-static-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/chart-with-annotations-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/chart-with-annotations-visual-darwin.png index 0eadb23d..a17738f9 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/chart-with-annotations-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/chart-with-annotations-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/chart-with-watermark-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/chart-with-watermark-visual-darwin.png index 7a5ab7f9..7dcba538 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/chart-with-watermark-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/chart-with-watermark-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-binned-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-binned-visual-darwin.png index 37023c44..975c4704 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-binned-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-binned-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-dark-diverging-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-dark-diverging-visual-darwin.png index 73a6b504..7a003fe5 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-dark-diverging-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-dark-diverging-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-gradient-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-gradient-visual-darwin.png index 81c16a9f..9a82c6ad 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-gradient-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/color-legend-gradient-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/compact-bar-320px-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/compact-bar-320px-visual-darwin.png index d2ee362b..42c951f4 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/compact-bar-320px-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/compact-bar-320px-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/compact-line-320px-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/compact-line-320px-visual-darwin.png index 17bc5648..c94a5aa6 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/compact-line-320px-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/compact-line-320px-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dark-mode-line-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dark-mode-line-visual-darwin.png index be9fef28..56a1dbf1 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dark-mode-line-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dark-mode-line-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-kpi-tile-dark-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-kpi-tile-dark-visual-darwin.png index 75654db8..aac9407b 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-kpi-tile-dark-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-kpi-tile-dark-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-kpi-tile-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-kpi-tile-visual-darwin.png index 023c6f55..edeb779b 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-kpi-tile-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-kpi-tile-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-tiny-tile-140-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-tiny-tile-140-visual-darwin.png index 093111e6..33d5d8be 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-tiny-tile-140-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-tiny-tile-140-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-tiny-tile-metrics-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-tiny-tile-metrics-visual-darwin.png index ddf2c6c8..2f755331 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-tiny-tile-metrics-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dashboard-tiny-tile-metrics-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/distribution-density-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/distribution-density-visual-darwin.png index afdfd5ac..4aa73000 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/distribution-density-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/distribution-density-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/distribution-histogram-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/distribution-histogram-visual-darwin.png index 0de425f2..479330c4 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/distribution-histogram-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/distribution-histogram-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/donut-center-label-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/donut-center-label-visual-darwin.png index 9805c0f5..78e530ad 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/donut-center-label-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/donut-center-label-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dual-axis-combo-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dual-axis-combo-visual-darwin.png index 8eb75628..946377df 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dual-axis-combo-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/dual-axis-combo-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/election-donut-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/election-donut-visual-darwin.png index 37c41093..855e3c07 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/election-donut-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/election-donut-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/election-results-bar-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/election-results-bar-visual-darwin.png index 01a347d5..5d93c1bf 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/election-results-bar-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/election-results-bar-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-bottom-right-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-bottom-right-visual-darwin.png index a882d969..9819539f 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-bottom-right-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-bottom-right-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-bottom-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-bottom-visual-darwin.png index 29d38bf7..5b8a5dbf 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-bottom-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-bottom-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-top-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-top-visual-darwin.png index 5b5dde39..c00979cb 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-top-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/legend-top-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/line-multi-series-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/line-multi-series-visual-darwin.png index 1bd26ede..c94fcf98 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/line-multi-series-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/line-multi-series-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/long-axis-labels-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/long-axis-labels-visual-darwin.png index 90c56d95..9ea7dc8c 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/long-axis-labels-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/long-axis-labels-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-categorical-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-categorical-visual-darwin.png index d9cc2187..91f2b338 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-categorical-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-categorical-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-dark-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-dark-visual-darwin.png index efae1610..f5976248 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-dark-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-dark-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-light-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-light-visual-darwin.png index d88fc8bb..09e7f783 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-light-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-us-states-light-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-world-equal-earth-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-world-equal-earth-visual-darwin.png index 983be66e..eea7c53e 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-world-equal-earth-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/map-world-equal-earth-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/multi-series-area-overlap-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/multi-series-area-overlap-visual-darwin.png index c96d2a37..e0f9f09f 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/multi-series-area-overlap-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/multi-series-area-overlap-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/multi-series-area-stacked-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/multi-series-area-stacked-visual-darwin.png index f8aeb952..f29e89ae 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/multi-series-area-stacked-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/multi-series-area-stacked-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-compact-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-compact-visual-darwin.png index 1a228fec..113a5208 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-compact-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-compact-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-eu-multi-party-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-eu-multi-party-visual-darwin.png index 6cfbe0dd..1b0035d3 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-eu-multi-party-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-eu-multi-party-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-us-house-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-us-house-visual-darwin.png index 0125a360..e3b97089 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-us-house-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/parliament-us-house-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/pie-with-legend-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/pie-with-legend-visual-darwin.png index 036cc712..e5cd6298 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/pie-with-legend-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/pie-with-legend-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/preset-broadsheet-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/preset-broadsheet-visual-darwin.png index 7caa63e5..c7ff8416 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/preset-broadsheet-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/preset-broadsheet-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/preset-terminal-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/preset-terminal-visual-darwin.png index 537c0fb4..4b048949 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/preset-terminal-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/preset-terminal-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-arrow-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-arrow-visual-darwin.png index 5800043a..3fc2893e 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-arrow-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-arrow-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-bar-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-bar-visual-darwin.png index ba7e0880..55812d04 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-bar-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-bar-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-dumbbell-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-dumbbell-visual-darwin.png index b873cc20..dba04abd 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-dumbbell-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/range-dumbbell-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/rect-heatmap-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/rect-heatmap-visual-darwin.png index 2e4a94be..0fc7169b 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/rect-heatmap-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/rect-heatmap-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/rotated-labels-with-source-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/rotated-labels-with-source-visual-darwin.png index e1b42598..017aa804 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/rotated-labels-with-source-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/rotated-labels-with-source-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-energy-dark-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-energy-dark-visual-darwin.png index 7182b55d..ae9a3f62 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-energy-dark-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-energy-dark-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-energy-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-energy-visual-darwin.png index 7ffa1c49..1bf5ff7a 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-energy-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-energy-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-narrow-long-labels-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-narrow-long-labels-visual-darwin.png index c243f7cc..31fcfe62 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-narrow-long-labels-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-narrow-long-labels-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-other-bucket-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-other-bucket-visual-darwin.png index 74ed856e..cc970c71 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-other-bucket-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/sankey-other-bucket-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scatter-trendline-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scatter-trendline-visual-darwin.png index 1fa96a5b..67c16751 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scatter-trendline-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scatter-trendline-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-annotated-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-annotated-visual-darwin.png index 07940c3f..2a178d68 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-annotated-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-annotated-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-base-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-base-visual-darwin.png index ce2fc9cf..feb4794f 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-base-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-base-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-highlight-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-highlight-visual-darwin.png index d76eefe3..ad921b9e 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-highlight-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-highlight-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-payoff-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-payoff-visual-darwin.png index d80809a6..a2c320d6 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-payoff-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-payoff-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-zoomed-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-zoomed-visual-darwin.png index 1cbcaeac..863a1f07 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-zoomed-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/scrolly-step-zoomed-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/series-search-mobile-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/series-search-mobile-visual-darwin.png index 5ed08ede..5b463573 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/series-search-mobile-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/series-search-mobile-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/series-search-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/series-search-visual-darwin.png index 4aef0320..8320428e 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/series-search-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/series-search-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/simple-columns-flat-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/simple-columns-flat-visual-darwin.png index 4f20c9b9..8b82e859 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/simple-columns-flat-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/simple-columns-flat-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/slope-market-share-compact-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/slope-market-share-compact-visual-darwin.png index 1f74686a..2858fe80 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/slope-market-share-compact-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/slope-market-share-compact-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/slope-market-share-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/slope-market-share-visual-darwin.png index 81de2123..570e578b 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/slope-market-share-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/slope-market-share-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/stacked-column-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/stacked-column-visual-darwin.png index a7819fe4..5d5d1e6c 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/stacked-column-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/stacked-column-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-basic-regular-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-basic-regular-visual-darwin.png index f4278385..0e54cb1c 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-basic-regular-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-basic-regular-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-cards-mobile-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-cards-mobile-visual-darwin.png index 54281190..5aeca9d7 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-cards-mobile-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-cards-mobile-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-delta-bars-condensed-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-delta-bars-condensed-visual-darwin.png index ba6b737a..cf85be41 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-delta-bars-condensed-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-delta-bars-condensed-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-heatmap-dark-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-heatmap-dark-visual-darwin.png index b0a654f0..691bbaee 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-heatmap-dark-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-heatmap-dark-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-sparklines-shared-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-sparklines-shared-visual-darwin.png index 3571d317..4860feef 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-sparklines-shared-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/table-sparklines-shared-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/text-mark-labels-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/text-mark-labels-visual-darwin.png index c38454a1..b7cf869f 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/text-mark-labels-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/text-mark-labels-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/tilemap-categorical-dark-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/tilemap-categorical-dark-visual-darwin.png index 707152b8..7a3b21d5 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/tilemap-categorical-dark-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/tilemap-categorical-dark-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/tilemap-quantitative-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/tilemap-quantitative-visual-darwin.png index eb5156bd..98489ebd 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/tilemap-quantitative-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/tilemap-quantitative-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/us-bubbles-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/us-bubbles-visual-darwin.png index 324d1a05..80054736 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/us-bubbles-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/us-bubbles-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-crowded-callouts-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-crowded-callouts-visual-darwin.png new file mode 100644 index 00000000..25ac36e6 Binary files /dev/null and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-crowded-callouts-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-curves-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-curves-visual-darwin.png new file mode 100644 index 00000000..031cd5a4 Binary files /dev/null and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-curves-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-notes-sizing-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-notes-sizing-visual-darwin.png new file mode 100644 index 00000000..73d9d951 Binary files /dev/null and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-notes-sizing-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-reference-labels-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-reference-labels-visual-darwin.png new file mode 100644 index 00000000..b4e0bcd7 Binary files /dev/null and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/v9-reference-labels-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/waffle-basic-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/waffle-basic-visual-darwin.png index ac6f82bd..09e08402 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/waffle-basic-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/waffle-basic-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/waffle-highlight-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/waffle-highlight-visual-darwin.png index c2d693a1..61afd2a3 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/waffle-highlight-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/waffle-highlight-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/world-diverging-quantize-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/world-diverging-quantize-visual-darwin.png index 92bf1806..d9419671 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/world-diverging-quantize-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/world-diverging-quantize-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-dark-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-dark-visual-darwin.png index b7b679d3..f8cf0325 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-dark-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-dark-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-mobile-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-mobile-visual-darwin.png index 81272f47..cf016b48 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-mobile-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-mobile-visual-darwin.png differ diff --git a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-visual-darwin.png b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-visual-darwin.png index f1d67bed..806da981 100644 Binary files a/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-visual-darwin.png and b/e2e/visual/__screenshots__/stories.spec.ts-snapshots/you-draw-it-visual-darwin.png differ diff --git a/e2e/visual/capture.ts b/e2e/visual/capture.ts index 577006c0..257d7ebc 100644 --- a/e2e/visual/capture.ts +++ b/e2e/visual/capture.ts @@ -11,6 +11,24 @@ export async function captureStory( screenshotName: string, query = '', ) { + // React may replace head styles while a story mounts. Hide only development + // overlays at their DOM owner as well, including any remount during capture. + await page.addInitScript(() => { + const hide = () => { + for (const element of document.querySelectorAll( + '.ladle-theme-picker, .oc-github-link', + )) { + if (element.style.getPropertyValue('display') !== 'none') + element.style.setProperty('display', 'none', 'important'); + } + }; + new MutationObserver(hide).observe(document, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: ['class', 'style'], + }); + }); await page.goto(`/?mode=preview&story=${encodeURIComponent(slug)}${query}`); // Kill animations so enter/stagger/annotation-delay timings don't leak diff --git a/e2e/visual/stories-mobile.spec.ts b/e2e/visual/stories-mobile.spec.ts index 352db986..98878de3 100644 --- a/e2e/visual/stories-mobile.spec.ts +++ b/e2e/visual/stories-mobile.spec.ts @@ -15,6 +15,11 @@ import { captureStory } from './capture'; */ const stories = [ + { name: 'v9-reference-labels', slug: 'features--annotation-reference-labels' }, + { name: 'v9-crowded-callouts', slug: 'features--annotation-crowded-callouts' }, + { name: 'v9-notes-sizing', slug: 'features--annotation-notes-sizing' }, + { name: 'v9-curves', slug: 'features--annotation-curves' }, + { name: 'mr-long-title', slug: 'testing--mobile-regression--long-title-mobile' }, { name: 'mr-grouped-columns-labels-all', slug: 'testing--mobile-regression--grouped-columns-labels-all' }, { name: 'mr-grouped-bars-many-rows', slug: 'testing--mobile-regression--grouped-bars-many-rows' }, @@ -31,6 +36,8 @@ const stories = [ { name: 'mr-chrome-layout-grow', slug: 'testing--mobile-regression--chrome-layout-grow' }, // maxLines — the same runaway title capped at 2 lines with an ellipsis. { name: 'mr-chrome-max-lines', slug: 'testing--mobile-regression--chrome-max-lines' }, + // Outside reference lanes that cannot fit: labels must stay on canvas. + { name: 'mr-reference-lane-overflow', slug: 'testing--mobile-regression--reference-lane-overflow' }, { name: 'bar-vertical', slug: 'testing--fixtures--simple-columns' }, { name: 'line-multi-series', slug: 'testing--fixtures--gdp-growth' }, { name: 'stacked-column', slug: 'testing--fixtures--energy-mix' }, diff --git a/e2e/visual/stories.spec.ts b/e2e/visual/stories.spec.ts index 8b7cc655..3d4a6115 100644 --- a/e2e/visual/stories.spec.ts +++ b/e2e/visual/stories.spec.ts @@ -13,6 +13,11 @@ import { captureStory } from './capture'; * compress the chart area. */ const stories: Array<{ name: string; slug: string; query?: string; note?: string }> = [ + { name: 'v9-reference-labels', slug: 'features--annotation-reference-labels' }, + { name: 'v9-crowded-callouts', slug: 'features--annotation-crowded-callouts' }, + { name: 'v9-notes-sizing', slug: 'features--annotation-notes-sizing' }, + { name: 'v9-curves', slug: 'features--annotation-curves' }, + { name: 'bar-vertical', slug: 'testing--fixtures--simple-columns' }, { name: 'bar-horizontal-gradient', slug: 'testing--fixtures--simple-bars' }, { name: 'line-multi-series', slug: 'testing--fixtures--gdp-growth' }, diff --git a/examples/src/__tests__/__fixtures__/v8-parity.json.gz b/examples/src/__tests__/__fixtures__/v8-parity.json.gz new file mode 100644 index 00000000..91d62210 Binary files /dev/null and b/examples/src/__tests__/__fixtures__/v8-parity.json.gz differ diff --git a/examples/src/__tests__/migration-parity.test.ts b/examples/src/__tests__/migration-parity.test.ts index 00cf593b..67ee0cfe 100644 --- a/examples/src/__tests__/migration-parity.test.ts +++ b/examples/src/__tests__/migration-parity.test.ts @@ -56,20 +56,22 @@ function compile(spec: VizSpec, width: number) { } } -describe('authored example migration parity', () => { +describe('authored example v8 migration compatibility', () => { it('discovers examples across the gallery and testing stories', () => { expect(fixtures.length).toBeGreaterThan(100); }); for (const { name, spec } of fixtures) { it(name, () => { - const { spec: migrated, repairs } = migrateSpecV8(spec); + const before = JSON.stringify(spec); + const { spec: migrated } = migrateSpecV8(spec); expect(migrateSpecV8(migrated)).toEqual({ spec: migrated, repairs: [] }); - // The approved end-of-line rewrite deliberately changes placement. - if (repairs.some((repair) => repair.reason.includes('end-of-line'))) return; + expect(JSON.stringify(spec)).toBe(before); for (const width of [390, 1280]) { - // Layouts contain formatter/scale closures with fresh identities. - // Compare all serialized geometry, text, colors and layout metadata. - expect(JSON.stringify(compile(migrated, width))).toBe(JSON.stringify(compile(spec, width))); + // v9 deliberately retunes placement. Migration preserves authored styles, + // not pixel geometry; every collected legacy example must still compile. + const result = compile(migrated, width); + expect(result).toBeDefined(); + expect(JSON.stringify(result)).toBe(JSON.stringify(compile(migrated, width))); } }); } diff --git a/examples/src/__tests__/migration-v8-approved-changes.ts b/examples/src/__tests__/migration-v8-approved-changes.ts new file mode 100644 index 00000000..a2ceec94 --- /dev/null +++ b/examples/src/__tests__/migration-v8-approved-changes.ts @@ -0,0 +1,9346 @@ +import type { GeometryValue } from './parity-signature'; + +/** Approved pre-RFC v9 fixes, verified against source commit 93112314. + * The released v8 capture stays unchanged. Only these exact before/after + * path values are exempted; no fixture or geometry category is exempted. */ +export const APPROVED_PRE_RFC_LAYOUT: Record< + string, + { + reason: string; + changes: Record>; + } +> = { + '../charts/mobile-regression.stories.tsx.inlineYTitleSpec @390': { + reason: + '93112314 frame: point-scale x labels reserve their actual flat extent; source numeric domain unchanged.', + changes: { + area: { + 'rect.height': [118.68, 148.65], + }, + chrome: { + bottomAnchorY: [314.43, 344.4], + }, + axes: { + 'x.end.y': [279.43, 309.4], + 'x.start.y': [279.43, 309.4], + 'y.end.y': [279.43, 309.4], + 'y.tick.0.position': [279.43, 309.4], + 'y.tick.1.position': [239.87, 259.85], + 'y.tick.2.position': [200.31, 210.3], + 'y.titlePosition.y': [220.09, 235.08], + }, + marks: { + '0.height': [49.45, 61.94], + '0.y': [180.53, 185.52], + '1.cy': [196.35, 205.34], + '2.cy': [190.42, 197.91], + '3.cy': [204.27, 215.26], + '4.cy': [186.46, 192.96], + '5.cy': [180.53, 185.52], + '6.cy': [229.98, 247.46], + }, + }, + }, + '../gallery/charts-bar-column.stories.tsx.columnsSpec @390': { + reason: + 'Pre-RFC v9 mark-anchor correction places annotation connector tails on compiled column bounds.', + changes: { + annotations: { + 'a0.connector.to.y': [241.28, 226.03], + }, + }, + }, + '../gallery/charts-bar-column.stories.tsx.columnsSpec @1280': { + reason: + 'Pre-RFC v9 mark-anchor correction places annotation connector tails on compiled column bounds.', + changes: { + annotations: { + 'a0.connector.to.y': [249.59, 234.34], + }, + }, + }, + '../gallery/charts-building-blocks.stories.tsx.directLabelSpec @1280': { + reason: + 'Pre-RFC v9 shared field precision removes redundant trailing zeroes from numeric axis ticks.', + changes: { + axes: { + 'x.tick.1.label': ['1.50', '1.5'], + 'x.tick.3.label': ['2.50', '2.5'], + 'x.tick.5.label': ['3.50', '3.5'], + }, + }, + }, + '../gallery/charts-building-blocks.stories.tsx.scatterLayer @1280': { + reason: + 'Pre-RFC v9 shared field precision removes redundant trailing zeroes from numeric axis ticks.', + changes: { + axes: { + 'x.tick.1.label': ['1.50', '1.5'], + 'x.tick.3.label': ['2.50', '2.5'], + 'x.tick.5.label': ['3.50', '3.5'], + }, + }, + }, + '../gallery/charts-building-blocks.stories.tsx.labelLayer @1280': { + reason: + 'Pre-RFC v9 shared field precision removes redundant trailing zeroes from numeric axis ticks.', + changes: { + axes: { + 'x.tick.1.label': ['1.50', '1.5'], + 'x.tick.3.label': ['2.50', '2.5'], + 'x.tick.5.label': ['3.50', '3.5'], + }, + }, + }, + '../gallery/charts-building-blocks.stories.tsx.composedSpecForPanel @1280': { + reason: + 'Pre-RFC v9 shared field precision removes redundant trailing zeroes from numeric axis ticks.', + changes: { + axes: { + 'x.tick.1.label': ['1.50', '1.5'], + 'x.tick.3.label': ['2.50', '2.5'], + 'x.tick.5.label': ['3.50', '3.5'], + }, + }, + }, + '../testing/fixtures-misc.stories.tsx.textMarkLabelSpec @1280': { + reason: + 'Pre-RFC v9 shared field precision removes redundant trailing zeroes from numeric axis ticks.', + changes: { + axes: { + 'x.tick.1.label': ['1.50', '1.5'], + 'x.tick.3.label': ['2.50', '2.5'], + 'x.tick.5.label': ['3.50', '3.5'], + }, + }, + }, + '../gallery/charts-building-blocks.stories.tsx.dualAxisSpec @390': { + reason: + '93112314 shared figure frame aligns independent-axis marks and y2 ticks to the same plot.', + changes: { + axes: { + 'y2.tick.0.position': [271.97, 283.66], + 'y2.tick.1.position': [232.2, 240.24], + 'y2.tick.2.position': [192.42, 196.81], + 'y2.tick.3.position': [152.65, 153.39], + }, + marks: { + '11.height': [96.24, 105.09], + '11.y': [173.33, 175.97], + '12.cy': [182.88, 186.39], + '13.cy': [173.33, 175.97], + '14.cy': [180.49, 183.78], + '15.cy': [190.04, 194.2], + '16.cy': [201.17, 206.36], + '17.cy': [215.49, 222], + '18.cy': [229.01, 236.76], + '19.cy': [238.56, 247.18], + '20.cy': [249.69, 259.34], + '21.cy': [259.24, 269.76], + '22.cy': [269.58, 281.05], + }, + }, + }, + '../testing/fixtures-dual-axis.stories.tsx.dualAxisSpec @390': { + reason: + '93112314 shared figure frame aligns independent-axis marks and y2 ticks to the same plot.', + changes: { + axes: { + 'y2.tick.0.position': [271.97, 283.66], + 'y2.tick.1.position': [232.2, 240.24], + 'y2.tick.2.position': [192.42, 196.81], + 'y2.tick.3.position': [152.65, 153.39], + }, + marks: { + '11.height': [96.24, 105.09], + '11.y': [173.33, 175.97], + '12.cy': [182.88, 186.39], + '13.cy': [173.33, 175.97], + '14.cy': [180.49, 183.78], + '15.cy': [190.04, 194.2], + '16.cy': [201.17, 206.36], + '17.cy': [215.49, 222], + '18.cy': [229.01, 236.76], + '19.cy': [238.56, 247.18], + '20.cy': [249.69, 259.34], + '21.cy': [259.24, 269.76], + '22.cy': [269.58, 281.05], + }, + }, + }, + '../gallery/charts-building-blocks.stories.tsx.spanSpec @390': { + reason: '93112314 frame: point-scale x labels reserve their actual flat extent.', + changes: { + area: { + 'rect.height': [143.68, 158.3], + }, + chrome: { + bottomAnchorY: [297.38, 312], + }, + axes: { + 'x.end.y': [271.38, 286], + 'x.start.y': [271.38, 286], + 'y.end.y': [271.38, 286], + 'y.tick.0.position': [271.38, 286], + 'y.tick.1.position': [241.45, 253.02], + 'y.tick.2.position': [211.51, 220.04], + 'y.tick.3.position': [181.58, 187.06], + 'y.tick.4.position': [151.65, 154.08], + 'y.titlePosition.y': [199.54, 206.85], + }, + marks: { + '0.y1': [250.43, 262.91], + '0.y2': [215.71, 224.66], + '1.y1': [265.99, 280.06], + '1.y2': [216.3, 225.32], + '10.y1': [244.44, 256.32], + '10.y2': [200.74, 208.17], + '11.y1': [246.24, 258.3], + '11.y2': [212.71, 221.36], + '2.y1': [252.22, 264.89], + '2.y2': [206.73, 214.77], + '3.y1': [215.11, 224], + '3.y2': [157.63, 160.68], + '4.y1': [199.54, 206.85], + '4.y2': [139.07, 140.23], + '5.y1': [170.8, 175.19], + '5.y2': [119.32, 118.47], + '6.y1': [139.07, 140.23], + '6.y2': [90.58, 86.81], + '7.y1': [150.45, 152.76], + '7.y2': [106.15, 103.95], + '8.y1': [167.81, 171.89], + '8.y2': [125.9, 125.72], + '9.y1': [197.15, 204.21], + '9.y2': [155.84, 158.7], + }, + }, + }, + '../gallery/dashboards.layouts.tsx.funnelConversionSpec @390': { + reason: '93112314 frame: point-scale x labels reserve their actual flat extent.', + changes: { + area: { + 'rect.height': [265.93, 280.55], + }, + chrome: { + bottomAnchorY: [369.38, 384], + }, + axes: { + 'x.end.y': [343.38, 358], + 'x.start.y': [343.38, 358], + 'y.end.y': [343.38, 358], + 'y.tick.0.position': [318.06, 331.28], + 'y.tick.1.position': [254.74, 264.48], + 'y.tick.2.position': [191.42, 197.69], + 'y.tick.3.position': [128.1, 130.89], + }, + marks: { + '0.height': [22.79, 24.05], + '0.y': [319.32, 332.62], + '1.height': [70.92, 74.81], + '1.y': [86.31, 86.8], + }, + }, + }, + '../gallery/features-animation.stories.tsx.annotationDelaySpec @390': { + reason: 'Pre-RFC approved UTC scale for date-only fields fixes tick identity and position.', + changes: { + axes: { + 'x.tick.0.label': ['2024', 'Jul 2023'], + 'x.tick.0.position': [170.74, 58], + 'x.tick.1.label': [undefined, 'Apr 2024'], + 'x.tick.1.position': [undefined, 226.5], + 'x.tick.2.label': [undefined, 'Oct 2024'], + 'x.tick.2.position': [undefined, 338.62], + }, + }, + }, + '../testing/fixtures-bars.stories.tsx.simpleColumnSpec @390': { + reason: + 'Pre-RFC v9 mark-anchor correction places annotation connector tails on compiled column bounds.', + changes: { + annotations: { + 'a0.connector.to.x': [302.35, 297.3], + 'a0.connector.to.y': [242.27, 233.29], + }, + }, + }, + '../testing/fixtures-bars.stories.tsx.simpleColumnSpec @1280': { + reason: + 'Pre-RFC v9 mark-anchor correction places annotation connector tails on compiled column bounds.', + changes: { + annotations: { + 'a0.connector.to.x': [1000.47, 994.45], + 'a0.connector.to.y': [250.12, 234.64], + }, + }, + }, + '../testing/fixtures-bars.stories.tsx.simpleBarSpec @390': { + reason: + 'Pre-RFC v9 mark-anchor correction places annotation connector tails on compiled horizontal bar bounds.', + changes: { + annotations: { + 'a0.connector.to.x': [368.85, 353.04], + 'a0.connector.to.y': [209.99, 203.38], + 'a1.connector.to.x': [363.6, 345.93], + 'a1.connector.to.y': [204.53, 198.95], + }, + }, + }, + '../testing/fixtures-bars.stories.tsx.simpleBarSpec @1280': { + reason: + 'Pre-RFC v9 mark-anchor correction places annotation connector tails on compiled horizontal bar bounds.', + changes: { + annotations: { + 'a0.connector.to.x': [1251.32, 1246.65], + 'a0.connector.to.y': [199.12, 194.79], + 'a1.connector.to.x': [1225.31, 1207.65], + 'a1.connector.to.y': [189.86, 184.24], + }, + }, + }, + '../testing/fixtures-bars.stories.tsx.tempSpec @390': { + reason: + 'Pre-RFC v9 shared field precision changes tick strings/gutters; existing D14 annotation placement remains separately allowlisted.', + changes: { + area: { + 'rect.width': [317.76, 323.88], + 'rect.x': [58.24, 52.12], + }, + axes: { + 'x.start.x': [58.24, 52.12], + 'x.tick.0.position': [72.17, 66.33], + 'x.tick.1.position': [94.47, 89.05], + 'x.tick.10.position': [295.17, 293.61], + 'x.tick.11.position': [317.46, 316.34], + 'x.tick.12.position': [339.76, 339.07], + 'x.tick.13.position': [362.06, 361.79], + 'x.tick.2.position': [116.77, 111.78], + 'x.tick.3.position': [139.07, 134.51], + 'x.tick.4.position': [161.37, 157.24], + 'x.tick.5.position': [183.67, 179.97], + 'x.tick.6.position': [205.97, 202.7], + 'x.tick.7.position': [228.27, 225.42], + 'x.tick.8.position': [250.57, 248.15], + 'x.tick.9.position': [272.87, 270.88], + 'y.end.x': [58.24, 52.12], + 'y.start.x': [58.24, 52.12], + 'y.tick.0.label': ['\u22120.50', '\u22120.5'], + 'y.tick.2.label': ['0.50', '0.5'], + }, + marks: { + '0.width': [16.72, 17.05], + '0.x': [63.81, 57.8], + '1.width': [16.72, 17.05], + '1.x': [86.11, 80.53], + '10.width': [16.72, 17.05], + '10.x': [286.8, 285.09], + '11.width': [16.72, 17.05], + '11.x': [309.1, 307.81], + '12.width': [16.72, 17.05], + '12.x': [331.4, 330.54], + '13.width': [16.72, 17.05], + '13.x': [353.7, 353.27], + '2.width': [16.72, 17.05], + '2.x': [108.41, 103.26], + '3.width': [16.72, 17.05], + '3.x': [130.71, 125.99], + '4.width': [16.72, 17.05], + '4.x': [153.01, 148.72], + '5.width': [16.72, 17.05], + '5.x': [175.31, 171.44], + '6.width': [16.72, 17.05], + '6.x': [197.61, 194.17], + '7.width': [16.72, 17.05], + '7.x': [219.91, 216.9], + '8.width': [16.72, 17.05], + '8.x': [242.2, 239.63], + '9.width': [16.72, 17.05], + '9.x': [264.5, 262.36], + }, + annotations: { + 'a0.connector.from.x': [156.27, 150.85], + 'a0.connector.to.x': [102.22, 96.8], + 'a0.dot.x': [94.47, 89.05], + 'a0.label.x': [164.27, 158.85], + 'a1.connector.from.x': [162.04, 161.77], + 'a1.connector.to.x': [354.34, 354.07], + 'a1.dot.x': [362.06, 361.79], + 'a1.label.x': [154.06, 153.79], + 'a2.line.start.x': [58.24, 52.12], + }, + legend: { + 'legends.0.bounds.x': [58.24, 52.12], + 'legends.0.entry.0.x': [58.24, 52.12], + 'legends.0.entry.1.x': [118.63, 112.52], + }, + }, + }, + '../testing/fixtures-bars.stories.tsx.tempSpec @1280': { + reason: + 'Pre-RFC v9 shared field precision changes tick strings/gutters; existing D14 annotation placement remains separately allowlisted.', + changes: { + axes: { + 'y.tick.0.label': ['\u22120.50', '\u22120.5'], + 'y.tick.2.label': ['0.50', '0.5'], + }, + annotations: { + 'a0.connector.from.x': [291.2, 208.02], + 'a0.connector.from.y': [197.88, 180.6], + 'a0.connector.to.x': [214.85, 208.02], + 'a0.connector.to.y': [238.74, 234.65], + 'a0.label.x': [257.37, 133.59], + 'a0.label.y': [172.24, 151.8], + }, + }, + }, + '../testing/fixtures-refresh.stories.tsx.flatColumnsSpec @1280': { + reason: 'Pre-RFC v9 shared field precision changes tick strings and measured y-label gutter.', + changes: { + axes: { + 'y.tick.1.label': ['0.50', '0.5'], + 'y.tick.3.label': ['1.50', '1.5'], + }, + }, + }, + '../testing/fixtures-misc.stories.tsx.rotatedSpec @1280': { + reason: + '93112314 frame reserves actual rotated categorical labels, keeping footer within the fixed figure.', + changes: { + area: { + 'rect.height': [229.2, 156.86], + }, + chrome: { + bottomAnchorY: [414.74, 342.4], + }, + axes: { + 'x.end.y': [316.4, 244.06], + 'x.start.y': [316.4, 244.06], + 'y.end.y': [316.4, 244.06], + 'y.gridlines': [8, 4], + 'y.tick.0.position': [316.4, 244.06], + 'y.tick.1.label': ['5', '10'], + 'y.tick.1.position': [283.66, 199.24], + 'y.tick.2.label': ['10', '20'], + 'y.tick.2.position': [250.91, 154.42], + 'y.tick.3.label': ['15', '30'], + 'y.tick.3.position': [218.17, 109.61], + 'y.tick.4.label': ['20', undefined], + 'y.tick.4.position': [185.43, undefined], + 'y.tick.5.label': ['25', undefined], + 'y.tick.5.position': [152.69, undefined], + 'y.tick.6.label': ['30', undefined], + 'y.tick.6.position': [119.94, undefined], + 'y.tick.7.label': ['35', undefined], + 'y.tick.7.position': [87.2, undefined], + 'y.titlePosition.y': [201.8, 165.63], + }, + marks: { + '0.height': [212.17, 145.2], + '0.y': [104.23, 98.85], + '1.height': [85.79, 58.71], + '1.y': [230.61, 185.35], + '2.height': [83.82, 57.36], + '2.y': [232.58, 186.69], + '3.height': [68.76, 47.06], + '3.y': [247.64, 197], + '4.height': [58.28, 39.89], + '4.y': [258.12, 204.17], + '5.height': [55.01, 37.65], + '5.y': [261.39, 206.41], + }, + labels: { + '0.label.y': [92.23, 86.85], + '1.label.y': [218.61, 173.35], + '2.label.y': [220.58, 174.69], + '3.label.y': [235.64, 185], + '4.label.y': [246.12, 192.17], + '5.label.y': [249.39, 194.41], + }, + }, + }, + '../testing/fixtures-refresh.stories.tsx.flatColumnsSpec @390': { + reason: 'Pre-RFC v9 shared field precision changes tick strings and measured y-label gutter.', + changes: { + area: { + 'rect.width': [323.59, 326], + 'rect.x': [52.41, 50], + }, + axes: { + 'x.start.x': [52.41, 50], + 'x.tick.0.position': [76.92, 74.7], + 'x.tick.1.position': [116.14, 114.21], + 'x.tick.2.position': [155.37, 153.73], + 'x.tick.3.position': [194.59, 193.24], + 'x.tick.4.position': [233.81, 232.76], + 'x.tick.5.position': [273.04, 272.27], + 'x.tick.6.position': [312.26, 311.79], + 'x.tick.7.position': [351.49, 351.3], + 'y.end.x': [52.41, 50], + 'y.start.x': [52.41, 50], + 'y.tick.1.label': ['0.50', '0.5'], + 'y.tick.3.label': ['1.50', '1.5'], + }, + marks: { + '0.width': [29.42, 29.64], + '0.x': [62.21, 59.88], + '1.width': [29.42, 29.64], + '1.x': [101.44, 99.39], + '2.width': [29.42, 29.64], + '2.x': [140.66, 138.91], + '3.width': [29.42, 29.64], + '3.x': [179.88, 178.42], + '4.width': [29.42, 29.64], + '4.x': [219.11, 217.94], + '5.width': [29.42, 29.64], + '5.x': [258.33, 257.45], + '6.width': [29.42, 29.64], + '6.x': [297.55, 296.97], + '7.width': [29.42, 29.64], + '7.x': [336.78, 336.48], + }, + labels: { + '0.label.x': [76.92, 74.7], + '1.label.x': [116.14, 114.21], + '2.label.x': [155.37, 153.73], + '3.label.x': [194.59, 193.24], + '4.label.x': [233.81, 232.76], + '5.label.x': [273.04, 272.27], + '6.label.x': [312.26, 311.79], + '7.label.x': [351.49, 351.3], + }, + }, + }, +}; + +/** B1 endpoint correctness: reserve the 18px painted gap (formerly 16px), + * measure every displayed string and apply shared precision without losing + * compact magnitude formatting. Exact released-v8/current values only. */ +export const APPROVED_RFC_B1_LAYOUT: typeof APPROVED_PRE_RFC_LAYOUT = { + '../charts/mobile-regression.stories.tsx.autoHeightChromeGrowthSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1094.18, 1092.18], + }, + axes: { + 'x.end.x': [1138.18, 1136.18], + 'x.tick.1.position': [284.44, 284.04], + 'x.tick.2.position': [497.87, 497.07], + 'x.tick.3.position': [711.31, 710.11], + 'x.tick.4.position': [924.74, 923.14], + 'x.tick.5.position': [1138.18, 1136.18], + }, + marks: { + '0.width': [1067.18, 1065.18], + '10.cx': [497.87, 497.07], + '11.cx': [711.31, 710.11], + '12.cx': [924.74, 923.14], + '13.cx': [1138.18, 1136.18], + '14.width': [1067.18, 1065.18], + '16.cx': [284.44, 284.04], + '17.cx': [497.87, 497.07], + '18.cx': [711.31, 710.11], + '19.cx': [924.74, 923.14], + '2.cx': [284.44, 284.04], + '20.cx': [1138.18, 1136.18], + '3.cx': [497.87, 497.07], + '4.cx': [711.31, 710.11], + '5.cx': [924.74, 923.14], + '6.cx': [1138.18, 1136.18], + '7.width': [1067.18, 1065.18], + '9.cx': [284.44, 284.04], + }, + endpointLabels: { + 'bounds.x': [1156.18, 1154.18], + }, + }, + }, + '../gallery/charts-line-area.stories.tsx.multiSeriesSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1085.06, 1083.06], + }, + axes: { + 'x.end.x': [1129.06, 1127.06], + 'x.tick.1.position': [419.52, 418.86], + 'x.tick.2.position': [774.53, 773.2], + 'x.tick.3.position': [1129.06, 1127.06], + }, + marks: { + '0.width': [1064.06, 1062.06], + '1.width': [1064.06, 1062.06], + '2.width': [1064.06, 1062.06], + }, + annotations: { + 'a0.line.end.x': [1129.06, 1127.06], + 'a1.label.x': [426.81, 426.13], + 'a1.rect.width': [133.07, 132.82], + 'a1.rect.x': [360.28, 359.72], + }, + endpointLabels: { + 'bounds.x': [1147.06, 1145.06], + }, + }, + }, + '../gallery/charts-line-area.stories.tsx.interactiveSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1111.64, 1109.64], + }, + axes: { + 'x.end.x': [1155.64, 1153.64], + 'x.tick.1.position': [287.81, 287.41], + 'x.tick.2.position': [505.21, 504.41], + 'x.tick.3.position': [722.02, 720.82], + 'x.tick.4.position': [938.83, 937.23], + 'x.tick.5.position': [1155.64, 1153.64], + }, + marks: { + '0.width': [1084.64, 1082.64], + '1.width': [1084.64, 1082.64], + '2.width': [1084.64, 1082.64], + '3.width': [1084.64, 1082.64], + '4.width': [1084.64, 1082.64], + }, + endpointLabels: { + 'bounds.x': [1173.64, 1171.64], + }, + }, + }, + '../gallery/dashboards.layouts.tsx.marketsCompareSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1088.1, 1086.1], + }, + axes: { + 'x.end.x': [1132.1, 1130.1], + 'x.tick.1.position': [353.91, 353.38], + 'x.tick.2.position': [636.82, 635.75], + 'x.tick.3.position': [920.5, 918.9], + }, + marks: { + '0.width': [1061.1, 1059.1], + '1.width': [1061.1, 1059.1], + '2.width': [1061.1, 1059.1], + '3.width': [1061.1, 1059.1], + }, + annotations: { + 'a0.label.x': [1128.1, 1126.1], + 'a0.line.end.x': [1132.1, 1130.1], + }, + endpointLabels: { + 'bounds.x': [1150.1, 1148.1], + }, + }, + }, + '../gallery/dashboards.stories.tsx.crosshairSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1088.1, 1086.1], + }, + axes: { + 'x.end.x': [1132.1, 1130.1], + 'x.tick.1.position': [353.91, 353.38], + 'x.tick.2.position': [636.82, 635.75], + 'x.tick.3.position': [920.5, 918.9], + }, + marks: { + '0.width': [1061.1, 1059.1], + '1.width': [1061.1, 1059.1], + '2.width': [1061.1, 1059.1], + '3.width': [1061.1, 1059.1], + }, + annotations: { + 'a0.label.x': [1128.1, 1126.1], + 'a0.line.end.x': [1132.1, 1130.1], + }, + endpointLabels: { + 'bounds.x': [1150.1, 1148.1], + }, + }, + }, + '../gallery/dashboards.layouts.tsx.funnelConversionSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1103.37, 1101.37], + }, + axes: { + 'x.end.x': [1126.37, 1124.37], + 'x.tick.1.position': [346.46, 345.92], + 'x.tick.2.position': [638.93, 637.84], + 'x.tick.3.position': [931.39, 929.76], + }, + marks: { + '0.width': [1072.37, 1070.37], + '1.width': [1072.37, 1070.37], + }, + endpointLabels: { + 'bounds.x': [1144.37, 1142.37], + }, + }, + }, + '../gallery/dashboards.layouts.tsx.incidentTtrcSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1113.89, 1111.89], + }, + axes: { + 'x.end.x': [1157.89, 1155.89], + 'x.tick.1.position': [307.86, 307.42], + 'x.tick.2.position': [550.73, 549.84], + 'x.tick.3.position': [793.59, 792.26], + 'x.tick.4.position': [1036.46, 1034.68], + }, + marks: { + '0.width': [1092.89, 1090.89], + '1.width': [1092.89, 1090.89], + }, + endpointLabels: { + 'bounds.x': [1175.89, 1173.89], + }, + }, + }, + '../gallery/features-animation.stories.tsx.lineDrawSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1107.06, 1105.06], + }, + axes: { + 'x.end.x': [1151.06, 1149.06], + 'x.tick.1.position': [364.39, 363.85], + 'x.tick.2.position': [657.78, 656.69], + 'x.tick.3.position': [954.39, 952.76], + }, + marks: { + '0.width': [1080.06, 1078.06], + '10.cx': [954.39, 952.76], + '11.cx': [1054.34, 1052.52], + '12.cx': [1151.06, 1149.06], + '13.width': [1080.06, 1078.06], + '15.cx': [170.95, 170.76], + '16.cx': [264.44, 264.09], + '17.cx': [364.39, 363.85], + '18.cx': [461.11, 460.39], + '19.cx': [561.06, 560.15], + '2.cx': [170.95, 170.76], + '20.cx': [657.78, 656.69], + '21.cx': [757.73, 756.45], + '22.cx': [857.67, 856.22], + '23.cx': [954.39, 952.76], + '24.cx': [1054.34, 1052.52], + '25.cx': [1151.06, 1149.06], + '3.cx': [264.44, 264.09], + '4.cx': [364.39, 363.85], + '5.cx': [461.11, 460.39], + '6.cx': [561.06, 560.15], + '7.cx': [657.78, 656.69], + '8.cx': [757.73, 756.45], + '9.cx': [857.67, 856.22], + }, + endpointLabels: { + 'bounds.x': [1169.06, 1167.06], + }, + }, + }, + '../gallery/features-responsive.stories.tsx.flagshipSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1085.06, 1083.06], + }, + axes: { + 'x.end.x': [1129.06, 1127.06], + 'x.tick.1.position': [241.43, 241.1], + 'x.tick.2.position': [418.86, 418.19], + 'x.tick.3.position': [596.77, 595.77], + 'x.tick.4.position': [774.2, 772.87], + 'x.tick.5.position': [951.63, 949.96], + 'x.tick.6.position': [1129.06, 1127.06], + }, + marks: { + '0.width': [1065.06, 1063.06], + '1.width': [1065.06, 1063.06], + '2.width': [1065.06, 1063.06], + }, + endpointLabels: { + 'bounds.x': [1147.06, 1145.06], + }, + }, + }, + '../gallery/features-responsive.stories.tsx.ratioSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1106.06, 1104.06], + }, + axes: { + 'x.end.x': [1129.06, 1127.06], + 'x.tick.1.position': [223.93, 223.59], + 'x.tick.2.position': [404.85, 404.19], + 'x.tick.3.position': [586.28, 585.28], + 'x.tick.4.position': [767.2, 765.87], + 'x.tick.5.position': [948.13, 946.47], + 'x.tick.6.position': [1129.06, 1127.06], + }, + marks: { + '0.width': [1086.06, 1084.06], + '1.width': [1086.06, 1084.06], + '2.width': [1086.06, 1084.06], + }, + endpointLabels: { + 'bounds.x': [1147.06, 1145.06], + }, + }, + }, + '../gallery/showcase.stories.tsx.multiLineSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1111.64, 1109.64], + }, + axes: { + 'x.end.x': [1155.64, 1153.64], + 'x.tick.1.position': [287.81, 287.41], + 'x.tick.2.position': [505.21, 504.41], + 'x.tick.3.position': [722.02, 720.82], + 'x.tick.4.position': [938.83, 937.23], + 'x.tick.5.position': [1155.64, 1153.64], + }, + marks: { + '0.width': [1084.64, 1082.64], + '1.width': [1084.64, 1082.64], + '2.width': [1084.64, 1082.64], + '3.width': [1084.64, 1082.64], + '4.width': [1084.64, 1082.64], + }, + annotations: { + 'a0.dot.x': [505.21, 504.41], + 'a0.label.x': [517.21, 516.41], + }, + endpointLabels: { + 'bounds.x': [1173.64, 1171.64], + }, + }, + }, + '../testing/fixtures-lines.stories.tsx.gdpLineSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1085.06, 1083.06], + }, + axes: { + 'x.end.x': [1129.06, 1127.06], + 'x.tick.1.position': [241.43, 241.1], + 'x.tick.2.position': [418.86, 418.19], + 'x.tick.3.position': [596.77, 595.77], + 'x.tick.4.position': [774.2, 772.87], + 'x.tick.5.position': [951.63, 949.96], + 'x.tick.6.position': [1129.06, 1127.06], + }, + marks: { + '0.width': [1065.06, 1063.06], + '1.width': [1065.06, 1063.06], + '2.width': [1065.06, 1063.06], + }, + annotations: { + 'a0.label.x': [500.28, 499.46], + 'a0.rect.width': [162.85, 162.54], + 'a0.rect.x': [418.86, 418.19], + 'a1.line.end.x': [1129.06, 1127.06], + }, + endpointLabels: { + 'bounds.x': [1147.06, 1145.06], + }, + }, + }, + '../testing/fixtures-lines.stories.tsx.compactGdpSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1085.06, 1083.06], + }, + axes: { + 'x.end.x': [1129.06, 1127.06], + 'x.tick.1.position': [241.43, 241.1], + 'x.tick.2.position': [418.86, 418.19], + 'x.tick.3.position': [596.77, 595.77], + 'x.tick.4.position': [774.2, 772.87], + 'x.tick.5.position': [951.63, 949.96], + 'x.tick.6.position': [1129.06, 1127.06], + }, + marks: { + '0.width': [1065.06, 1063.06], + '1.width': [1065.06, 1063.06], + '2.width': [1065.06, 1063.06], + }, + annotations: { + 'a0.label.x': [500.28, 499.46], + 'a0.rect.width': [162.85, 162.54], + 'a0.rect.x': [418.86, 418.19], + 'a1.line.end.x': [1129.06, 1127.06], + }, + endpointLabels: { + 'bounds.x': [1147.06, 1145.06], + }, + }, + }, + '../testing/fixtures-lines.stories.tsx.fiveSeriesSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1111.64, 1109.64], + }, + axes: { + 'x.end.x': [1155.64, 1153.64], + 'x.tick.1.position': [259.52, 259.17], + 'x.tick.2.position': [448.56, 447.86], + 'x.tick.3.position': [637.08, 636.03], + 'x.tick.4.position': [825.6, 824.21], + 'x.tick.5.position': [1014.12, 1012.38], + }, + marks: { + '0.width': [1084.64, 1082.64], + '1.width': [1084.64, 1082.64], + '2.width': [1084.64, 1082.64], + '3.width': [1084.64, 1082.64], + '4.width': [1084.64, 1082.64], + }, + annotations: { + 'a0.connector.from.x': [290.97, 290.36], + 'a0.connector.to.x': [393.38, 392.77], + 'a0.dot.x': [401.04, 400.43], + 'a0.label.x': [283.04, 282.43], + }, + endpointLabels: { + 'bounds.x': [1173.64, 1171.64], + }, + }, + }, + '../testing/fixtures-lines.stories.tsx.multiSeriesAreaOverlapSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1138.31, 1136.31], + }, + axes: { + 'x.end.x': [1161.31, 1159.31], + 'x.tick.1.position': [331.4, 330.9], + 'x.tick.2.position': [608.04, 607.04], + 'x.tick.3.position': [884.67, 883.17], + 'x.tick.4.position': [1161.31, 1159.31], + }, + marks: { + '0.width': [1107.31, 1105.31], + '1.width': [1107.31, 1105.31], + '2.width': [1107.31, 1105.31], + '3.width': [1107.31, 1105.31], + '4.width': [1107.31, 1105.31], + '5.width': [1107.31, 1105.31], + '6.width': [1107.31, 1105.31], + '7.width': [1107.31, 1105.31], + }, + annotations: { + 'a0.connector.from.x': [1021.86, 1020.11], + 'a0.connector.to.x': [1021.86, 1020.11], + 'a0.dot.x': [1021.86, 1020.11], + 'a0.label.x': [950.14, 948.39], + 'a0.subtitle.x': [950.14, 948.39], + }, + endpointLabels: { + 'bounds.x': [1179.31, 1177.31], + }, + }, + }, + '../testing/fixtures-lines.stories.tsx.multiSeriesAreaStackedSpec @390': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [280.35, 273.98], + }, + axes: { + 'x.end.x': [294.35, 287.98], + 'x.tick.1.position': [183.11, 179.65], + }, + marks: { + '0.width': [244.35, 237.98], + '1.width': [244.35, 237.98], + '2.width': [244.35, 237.98], + '3.width': [244.35, 237.98], + '4.width': [244.35, 237.98], + '5.width': [244.35, 237.98], + }, + endpointLabels: { + 'bounds.x': [312.35, 305.98], + }, + }, + }, + '../testing/fixtures-lines.stories.tsx.multiSeriesAreaStackedSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1152.35, 1145.98], + }, + axes: { + 'x.end.x': [1175.35, 1168.98], + 'x.tick.1.position': [208.96, 208.1], + 'x.tick.2.position': [360.58, 358.86], + 'x.tick.3.position': [513.87, 511.28], + 'x.tick.4.position': [667.16, 663.69], + 'x.tick.5.position': [818.78, 814.45], + 'x.tick.6.position': [970.41, 965.21], + 'x.tick.7.position': [1123.69, 1117.62], + }, + marks: { + '0.width': [1116.35, 1109.98], + '1.width': [1116.35, 1109.98], + '2.width': [1116.35, 1109.98], + '3.width': [1116.35, 1109.98], + '4.width': [1116.35, 1109.98], + '5.width': [1116.35, 1109.98], + }, + endpointLabels: { + 'bounds.x': [1193.35, 1186.98], + }, + }, + }, + '../testing/fixtures-lines.stories.tsx.lineSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1015.41, 1013.41], + }, + axes: { + 'x.end.x': [1059.41, 1057.41], + 'x.tick.1.position': [211.93, 211.65], + 'x.tick.2.position': [352.4, 351.84], + 'x.tick.3.position': [494.42, 493.57], + 'x.tick.4.position': [636.44, 635.3], + 'x.tick.5.position': [776.91, 775.49], + 'x.tick.6.position': [917.39, 915.68], + 'x.tick.7.position': [1059.41, 1057.41], + }, + marks: { + '0.width': [986.41, 984.41], + '1.width': [986.41, 984.41], + '2.width': [986.41, 984.41], + }, + annotations: { + 'a0.connector.from.x': [742.02, 740.6], + 'a0.connector.to.x': [769.48, 768.05], + 'a0.dot.x': [776.91, 775.49], + 'a0.label.x': [748.91, 747.49], + 'a1.label.x': [297.68, 297.11], + }, + legend: { + 'legends.0.bounds.x': [1176.09, 1174.09], + 'legends.0.entry.0.x': [1176.09, 1174.09], + 'legends.0.entry.1.x': [1176.09, 1174.09], + 'legends.0.entry.2.x': [1176.09, 1174.09], + }, + endpointLabels: { + 'bounds.x': [1077.41, 1075.41], + }, + }, + }, + '../testing/fixtures-misc.stories.tsx.chromeSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1169.04, 1167.04], + }, + axes: { + 'x.end.x': [1192.04, 1190.04], + 'x.tick.1.position': [186.92, 186.67], + 'x.tick.2.position': [329.83, 329.33], + 'x.tick.3.position': [474.32, 473.57], + 'x.tick.4.position': [618.81, 617.8], + 'x.tick.5.position': [760.15, 758.9], + 'x.tick.6.position': [903.07, 901.57], + 'x.tick.7.position': [1047.55, 1045.81], + 'x.tick.8.position': [1192.04, 1190.04], + }, + marks: { + '0.width': [1148.04, 1146.04], + '1.width': [1148.04, 1146.04], + }, + endpointLabels: { + 'bounds.x': [1210.04, 1208.04], + }, + }, + }, + '../testing/fixtures-misc.stories.tsx.fullChromeSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1169.04, 1167.04], + }, + axes: { + 'x.end.x': [1192.04, 1190.04], + 'x.tick.1.position': [186.92, 186.67], + 'x.tick.2.position': [329.83, 329.33], + 'x.tick.3.position': [474.32, 473.57], + 'x.tick.4.position': [618.81, 617.8], + 'x.tick.5.position': [760.15, 758.9], + 'x.tick.6.position': [903.07, 901.57], + 'x.tick.7.position': [1047.55, 1045.81], + 'x.tick.8.position': [1192.04, 1190.04], + }, + marks: { + '0.width': [1148.04, 1146.04], + '1.width': [1148.04, 1146.04], + }, + endpointLabels: { + 'bounds.x': [1210.04, 1208.04], + }, + }, + }, + '../testing/fixtures-ranking.stories.tsx.slopeMarketShareSpec @390': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [92.47, 88.47], + 'rect.x': [148.77, 150.77], + }, + axes: { + 'x.end.x': [241.23, 239.23], + 'x.start.x': [148.77, 150.77], + 'x.tick.0.position': [148.77, 150.77], + 'x.tick.1.position': [241.23, 239.23], + }, + marks: { + '0.width': [92.47, 88.47], + '0.x': [148.77, 150.77], + '1.width': [92.47, 88.47], + '1.x': [148.77, 150.77], + '2.width': [92.47, 88.47], + '2.x': [148.77, 150.77], + '3.width': [92.47, 88.47], + '3.x': [148.77, 150.77], + '4.width': [92.47, 88.47], + '4.x': [148.77, 150.77], + }, + endpointLabels: { + 'bounds.x': [259.23, 257.23], + 'leadingBounds.x': [12, 14], + }, + }, + }, + '../testing/fixtures-ranking.stories.tsx.slopeMarketShareSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [964.47, 960.47], + 'rect.x': [157.77, 159.77], + }, + axes: { + 'x.end.x': [1122.23, 1120.23], + 'x.start.x': [157.77, 159.77], + 'x.tick.0.position': [157.77, 159.77], + 'x.tick.1.position': [1122.23, 1120.23], + }, + marks: { + '0.width': [964.47, 960.47], + '0.x': [157.77, 159.77], + '1.width': [964.47, 960.47], + '1.x': [157.77, 159.77], + '2.width': [964.47, 960.47], + '2.x': [157.77, 159.77], + '3.width': [964.47, 960.47], + '3.x': [157.77, 159.77], + '4.width': [964.47, 960.47], + '4.x': [157.77, 159.77], + }, + endpointLabels: { + 'bounds.x': [1140.23, 1138.23], + 'leadingBounds.x': [21, 23], + }, + }, + }, + '../testing/fixtures-ranking.stories.tsx.bumpConstructorsSpec @390': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [150.15, 146.15], + 'rect.x': [119.92, 121.92], + }, + axes: { + 'x.end.x': [270.08, 268.08], + 'x.start.x': [119.92, 121.92], + 'x.tick.0.position': [146.92, 148.92], + 'x.tick.1.position': [196.18, 196.58], + 'x.tick.2.position': [245.45, 244.25], + 'y.end.x': [119.92, 121.92], + 'y.start.x': [119.92, 121.92], + }, + marks: { + '0.width': [123.15, 119.15], + '0.x': [146.92, 148.92], + '1.cx': [146.92, 148.92], + '10.cx': [196.18, 196.58], + '11.cx': [220.82, 220.42], + '12.cx': [245.45, 244.25], + '13.cx': [270.08, 268.08], + '14.width': [123.15, 119.15], + '14.x': [146.92, 148.92], + '15.cx': [146.92, 148.92], + '16.cx': [171.55, 172.75], + '17.cx': [196.18, 196.58], + '18.cx': [220.82, 220.42], + '19.cx': [245.45, 244.25], + '2.cx': [171.55, 172.75], + '20.cx': [270.08, 268.08], + '21.width': [123.15, 119.15], + '21.x': [146.92, 148.92], + '22.cx': [146.92, 148.92], + '23.cx': [171.55, 172.75], + '24.cx': [196.18, 196.58], + '25.cx': [220.82, 220.42], + '26.cx': [245.45, 244.25], + '27.cx': [270.08, 268.08], + '28.width': [123.15, 119.15], + '28.x': [146.92, 148.92], + '29.cx': [146.92, 148.92], + '3.cx': [196.18, 196.58], + '30.cx': [171.55, 172.75], + '31.cx': [196.18, 196.58], + '32.cx': [220.82, 220.42], + '33.cx': [245.45, 244.25], + '34.cx': [270.08, 268.08], + '4.cx': [220.82, 220.42], + '5.cx': [245.45, 244.25], + '6.cx': [270.08, 268.08], + '7.width': [123.15, 119.15], + '7.x': [146.92, 148.92], + '8.cx': [146.92, 148.92], + '9.cx': [171.55, 172.75], + }, + endpointLabels: { + 'bounds.x': [288.08, 286.08], + 'leadingBounds.x': [12, 14], + }, + }, + }, + '../testing/fixtures-ranking.stories.tsx.bumpConstructorsSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1022.15, 1018.15], + 'rect.x': [128.92, 130.92], + }, + axes: { + 'x.end.x': [1151.08, 1149.08], + 'x.start.x': [128.92, 130.92], + 'x.tick.0.position': [155.92, 157.92], + 'x.tick.1.position': [354.95, 356.15], + 'x.tick.2.position': [553.98, 554.38], + 'x.tick.3.position': [753.02, 752.62], + 'x.tick.4.position': [952.05, 950.85], + 'x.tick.5.position': [1151.08, 1149.08], + 'y.end.x': [128.92, 130.92], + 'y.start.x': [128.92, 130.92], + }, + marks: { + '0.width': [995.15, 991.15], + '0.x': [155.92, 157.92], + '1.cx': [155.92, 157.92], + '10.cx': [553.98, 554.38], + '11.cx': [753.02, 752.62], + '12.cx': [952.05, 950.85], + '13.cx': [1151.08, 1149.08], + '14.width': [995.15, 991.15], + '14.x': [155.92, 157.92], + '15.cx': [155.92, 157.92], + '16.cx': [354.95, 356.15], + '17.cx': [553.98, 554.38], + '18.cx': [753.02, 752.62], + '19.cx': [952.05, 950.85], + '2.cx': [354.95, 356.15], + '20.cx': [1151.08, 1149.08], + '21.width': [995.15, 991.15], + '21.x': [155.92, 157.92], + '22.cx': [155.92, 157.92], + '23.cx': [354.95, 356.15], + '24.cx': [553.98, 554.38], + '25.cx': [753.02, 752.62], + '26.cx': [952.05, 950.85], + '27.cx': [1151.08, 1149.08], + '28.width': [995.15, 991.15], + '28.x': [155.92, 157.92], + '29.cx': [155.92, 157.92], + '3.cx': [553.98, 554.38], + '30.cx': [354.95, 356.15], + '31.cx': [553.98, 554.38], + '32.cx': [753.02, 752.62], + '33.cx': [952.05, 950.85], + '34.cx': [1151.08, 1149.08], + '4.cx': [753.02, 752.62], + '5.cx': [952.05, 950.85], + '6.cx': [1151.08, 1149.08], + '7.width': [995.15, 991.15], + '7.x': [155.92, 157.92], + '8.cx': [155.92, 157.92], + '9.cx': [354.95, 356.15], + }, + endpointLabels: { + 'bounds.x': [1169.08, 1167.08], + 'leadingBounds.x': [21, 23], + }, + }, + }, + '../testing/fixtures-refresh.stories.tsx.presetSpec @1280': { + reason: + 'B1 endpoint full-set width, shared precision and corrected 18px reservation of the already-painted gap; compared against released v8 and pre-RFC93112314 source.', + changes: { + area: { + 'rect.width': [1085.06, 1083.06], + }, + axes: { + 'x.end.x': [1129.06, 1127.06], + 'x.tick.1.position': [273.01, 272.61], + 'x.tick.2.position': [487.02, 486.22], + 'x.tick.3.position': [701.04, 699.84], + 'x.tick.4.position': [915.05, 913.45], + 'x.tick.5.position': [1129.06, 1127.06], + }, + marks: { + '0.width': [1070.06, 1068.06], + '1.width': [1070.06, 1068.06], + }, + endpointLabels: { + 'bounds.x': [1147.06, 1145.06], + }, + }, + }, +}; + +/** B1: point category keys paint in their resolved top reservation. Released + * v8 reserved the top band but painted the key at the bottom. */ +export const APPROVED_MAP_KEY_PLACEMENT: Record< + string, + (typeof APPROVED_RFC_B1_LAYOUT)[string] & { style: Record } +> = { + '../gallery/maps.stories.tsx.pointLayerSpec @390': { + reason: + 'B1: paint the point category key in its existing resolved top reservation; v8 incorrectly painted it at the bottom without reserving a bottom band.', + style: { 'legends.pointCategoricalLegend.position': ['bottom', 'top'] }, + changes: { + legend: { + 'pointCategoricalLegend.bounds.y': [327.4, 74.85], + 'pointCategoricalLegend.entry.0.x': [undefined, 10], + 'pointCategoricalLegend.entry.0.y': [undefined, 74.85], + 'pointCategoricalLegend.entry.1.x': [undefined, 49.34], + 'pointCategoricalLegend.entry.1.y': [undefined, 74.85], + 'pointCategoricalLegend.entry.2.x': [undefined, 88.67], + 'pointCategoricalLegend.entry.2.y': [undefined, 74.85], + }, + }, + }, + '../gallery/maps.stories.tsx.pointLayerSpec @1280': { + reason: + 'B1: paint the point category key in its existing resolved top reservation; v8 incorrectly painted it at the bottom without reserving a bottom band.', + style: { 'legends.pointCategoricalLegend.position': ['bottom', 'top'] }, + changes: { + legend: { + 'pointCategoricalLegend.bounds.y': [307.4, 97.2], + 'pointCategoricalLegend.entry.0.x': [undefined, 20], + 'pointCategoricalLegend.entry.0.y': [undefined, 97.2], + 'pointCategoricalLegend.entry.1.x': [undefined, 59.34], + 'pointCategoricalLegend.entry.1.y': [undefined, 97.2], + 'pointCategoricalLegend.entry.2.x': [undefined, 98.67], + 'pointCategoricalLegend.entry.2.y': [undefined, 97.2], + }, + }, + }, + '../gallery/maps.stories.tsx.readerZoomPointsSpec @390': { + reason: + 'B1: paint the point category key in its existing resolved top reservation; v8 incorrectly painted it at the bottom without reserving a bottom band.', + style: { 'legends.pointCategoricalLegend.position': ['bottom', 'top'] }, + changes: { + legend: { + 'pointCategoricalLegend.bounds.y': [327.4, 101.3], + 'pointCategoricalLegend.entry.0.x': [undefined, 10], + 'pointCategoricalLegend.entry.0.y': [undefined, 101.3], + 'pointCategoricalLegend.entry.1.x': [undefined, 49.34], + 'pointCategoricalLegend.entry.1.y': [undefined, 101.3], + 'pointCategoricalLegend.entry.2.x': [undefined, 88.67], + 'pointCategoricalLegend.entry.2.y': [undefined, 101.3], + }, + }, + }, + '../gallery/maps.stories.tsx.readerZoomPointsSpec @1280': { + reason: + 'B1: paint the point category key in its existing resolved top reservation; v8 incorrectly painted it at the bottom without reserving a bottom band.', + style: { 'legends.pointCategoricalLegend.position': ['bottom', 'top'] }, + changes: { + legend: { + 'pointCategoricalLegend.bounds.y': [307.4, 97.2], + 'pointCategoricalLegend.entry.0.x': [undefined, 20], + 'pointCategoricalLegend.entry.0.y': [undefined, 97.2], + 'pointCategoricalLegend.entry.1.x': [undefined, 59.34], + 'pointCategoricalLegend.entry.1.y': [undefined, 97.2], + 'pointCategoricalLegend.entry.2.x': [undefined, 98.67], + 'pointCategoricalLegend.entry.2.y': [undefined, 97.2], + }, + }, + }, +}; + +/** B1: alphabetic title baselines must leave room for rotated glyph ascent. */ +export const APPROVED_AXIS_TITLE_LAYOUT: typeof APPROVED_PRE_RFC_LAYOUT = { + '../charts/mobile-regression.stories.tsx.inlineYTitleSpec @390': { + reason: + 'B1 enlarged rotated title no longer clips beyond the viewport; marks, ticks and plot stay unchanged.', + changes: { axes: { 'y.titlePosition.x': [19, 21] } }, + }, + '../gallery/charts-scatter-distribution.stories.tsx.stripSpec @390': { + reason: + 'B1 rotated title no longer clips beyond the viewport; marks, ticks and plot stay unchanged.', + changes: { axes: { 'y.titlePosition.x': [5.87, 13] } }, + }, +}; + +/** B1 collision correction: clamp top-overflow anchors before the separation sweep. + * Values and marks are unchanged; only these label centers move into available space. */ +export const APPROVED_ENDPOINT_TOP_SWEEP: typeof APPROVED_PRE_RFC_LAYOUT = { + '../gallery/dashboards.layouts.tsx.marketsCompareSpec @1280': { + reason: + 'Clamp top-overflow endpoint anchors before separation so labels retain their minimum spacing.', + changes: { + endpointLabels: { + '0.labelY': [139.52, 145.45], + '2.labelY': [180.77, 186.7], + '3.labelY': [222.02, 227.95], + }, + }, + }, + '../gallery/dashboards.stories.tsx.crosshairSpec @1280': { + reason: + 'Clamp top-overflow endpoint anchors before separation so labels retain their minimum spacing.', + changes: { + endpointLabels: { + '0.labelY': [139.52, 145.45], + '2.labelY': [180.77, 186.7], + '3.labelY': [222.02, 227.95], + }, + }, + }, + '../testing/fixtures-lines.stories.tsx.multiSeriesAreaStackedSpec @390': { + reason: + 'Clamp top-overflow endpoint anchors before separation so labels retain their minimum spacing.', + changes: { endpointLabels: { '0.labelY': [226.2, 227.2], '1.labelY': [182.56, 185.95] } }, + }, + '../testing/fixtures-lines.stories.tsx.multiSeriesAreaStackedSpec @1280': { + reason: + 'Clamp top-overflow endpoint anchors before separation so labels retain their minimum spacing.', + changes: { endpointLabels: { '1.labelY': [142.77, 145.45] } }, + }, +}; + +/** Approved B3 map layout changes; every released path remains guarded exactly. */ +export const APPROVED_B3_MAP_LAYOUT: typeof APPROVED_MAP_KEY_PLACEMENT = { + '../gallery/maps.stories.tsx.worldEqualEarthSpec @390': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [166.7, 128.7], + }, + area: { + 'rect.height': [166.7, 128.7], + 'rect.y': [157.3, 195.3], + }, + marks: { + '0.height': [2.85, 2.2], + '0.width': [337.62, 260.66], + '0.x': [16.19, 54.67], + '0.y': [103.46, 79.87], + '1.height': [13.81, 10.66], + '1.width': [10.23, 7.9], + '1.x': [213, 206.62], + '1.y': [84.19, 65], + '2.height': [8.16, 6.3], + '2.width': [7.96, 6.15], + '2.x': [169.21, 172.81], + '2.y': [48.1, 37.13], + '3.height': [31.79, 24.54], + '3.width': [66.09, 51.03], + '3.x': [83.08, 106.31], + '3.y': [0.1, 0.08], + '4.height': [53.48, 41.29], + '4.width': [92.66, 71.54], + '4.x': [37.65, 71.24], + '4.y': [5.37, 4.14], + '5.height': [15.08, 11.64], + '5.width': [32.26, 24.9], + '5.x': [222.05, 213.6], + '5.y': [17.92, 13.84], + '6.height': [9.28, 7.16], + '6.width': [15.73, 12.14], + '6.x': [230.81, 220.37], + '6.y': [27.68, 21.37], + '7.height': [10.46, 8.07], + '7.width': [14.67, 11.33], + '7.x': [318.97, 288.43], + '7.y': [86.19, 66.54], + '8.height': [20.35, 15.71], + '8.width': [43.81, 33.83], + '8.x': [275.88, 255.16], + '8.y': [75.92, 58.61], + '9.height': [37.17, 28.7], + '9.width': [14.17, 10.94], + '9.x': [122.23, 136.54], + '9.y': [110.72, 85.48], + '10.height': [42.81, 33.05], + '10.width': [15.01, 11.59], + '10.x': [119.38, 134.34], + '10.y': [105.42, 81.39], + '11.height': [23.75, 18.34], + '11.width': [18.17, 14.03], + '11.x': [196.61, 193.97], + '11.y': [76.21, 58.84], + '12.height': [17.59, 13.58], + '12.width': [9.24, 7.13], + '12.x': [224.14, 215.22], + '12.y': [67.55, 52.15], + '13.height': [13.1, 10.11], + '13.width': [7.57, 5.84], + '13.x': [217.39, 210.01], + '13.y': [75.89, 58.59], + '14.height': [17.38, 13.42], + '14.width': [15.12, 11.68], + '14.x': [205.72, 201], + '14.y': [55.01, 42.47], + '15.height': [20.16, 15.56], + '15.width': [9.68, 7.47], + '15.x': [197.75, 194.84], + '15.y': [53.27, 41.13], + '16.height': [2.36, 1.82], + '16.width': [2.82, 2.18], + '16.x': [115.57, 131.4], + '16.y': [57.6, 44.47], + '17.height': [2.86, 2.21], + '17.width': [3.38, 2.61], + '17.x': [117.97, 133.25], + '17.y': [57.64, 44.5], + '18.height': [31.79, 24.55], + '18.width': [249.21, 192.4], + '18.x': [61.86, 89.93], + '18.y': [0.67, 0.52], + '19.height': [4.06, 3.14], + '19.width': [1.83, 1.41], + '19.x': [113.33, 129.67], + '19.y': [48.84, 37.71], + '20.height': [1.18, 0.91], + '20.width': [2.56, 1.98], + '20.x': [137.49, 148.32], + '20.y': [143.91, 111.1], + '21.height': [14.61, 11.28], + '21.width': [16.74, 12.93], + '21.x': [188.52, 187.72], + '21.y': [0.86, 0.67], + '22.height': [13.77, 10.63], + '22.width': [36.79, 28.4], + '22.x': [141.08, 151.09], + '23.height': [1.16, 0.9], + '23.width': [1.73, 1.33], + '23.x': [239.29, 226.92], + '23.y': [141.42, 109.18], + '24.height': [1.43, 1.11], + '24.width': [2.32, 1.79], + '24.x': [303.75, 276.68], + '24.y': [93.6, 72.27], + '25.height': [15.28, 11.8], + '25.width': [15.06, 11.62], + '25.x': [199.7, 196.35], + '25.y': [111.04, 85.73], + '26.height': [2.39, 1.84], + '26.width': [2.15, 1.66], + '26.x': [209.15, 203.64], + '26.y': [119.04, 91.9], + '27.height': [22.29, 17.21], + '27.width': [23.64, 18.25], + '27.x': [81.12, 104.8], + '27.y': [42.07, 32.48], + '28.height': [5.69, 4.39], + '28.width': [4.65, 3.59], + '28.x': [133.5, 145.24], + '28.y': [120.79, 93.25], + '29.height': [48.88, 37.73], + '29.width': [37.36, 28.84], + '29.x': [114.58, 130.63], + '29.y': [76.22, 58.85], + '30.height': [16.5, 12.74], + '30.width': [12.23, 9.45], + '30.x': [119.13, 134.14], + '30.y': [95.51, 73.74], + '31.height': [23.34, 18.02], + '31.width': [13.07, 10.09], + '31.x': [107.32, 125.03], + '31.y': [83.04, 64.11], + '32.height': [21.48, 16.58], + '32.width': [11.57, 8.93], + '32.x': [109.52, 126.73], + '32.y': [67.02, 51.74], + '33.height': [3.06, 2.36], + '33.width': [5.42, 4.18], + '33.x': [106.1, 124.09], + '33.y': [70.63, 54.53], + '34.height': [3.82, 2.95], + '34.width': [3.06, 2.36], + '34.x': [103.57, 122.13], + '34.y': [68.58, 52.94], + '35.height': [5.45, 4.21], + '35.width': [4.6, 3.55], + '35.x': [102.23, 121.09], + '35.y': [63.75, 49.22], + '36.height': [3.82, 2.95], + '36.width': [5.94, 4.59], + '36.x': [100.89, 120.06], + '36.y': [62.5, 48.26], + '37.height': [1.62, 1.25], + '37.width': [2.24, 1.73], + '37.x': [100.07, 119.43], + '37.y': [64.5, 49.8], + '38.height': [5.15, 3.98], + '38.width': [3.99, 3.08], + '38.x': [98.21, 117.99], + '38.y': [60.22, 46.49], + '39.height': [3.28, 2.54], + '39.width': [1.57, 1.21], + '39.x': [101.28, 120.37], + '39.y': [59.37, 45.84], + '40.height': [14.66, 11.32], + '40.width': [12.81, 9.89], + '40.x': [115.37, 131.24], + '40.y': [67.37, 52.02], + '41.height': [9.12, 7.04], + '41.width': [4.52, 3.49], + '41.x': [126.46, 139.8], + '41.y': [72.22, 55.76], + '42.height': [5.41, 4.18], + '42.width': [3.96, 3.06], + '42.x': [129.59, 142.22], + '42.y': [75.22, 58.07], + '43.height': [58.34, 45.04], + '43.width': [60.08, 46.38], + '43.x': [132.91, 144.78], + '43.y': [21.98, 16.97], + '44.height': [8.16, 6.3], + '44.width': [5.45, 4.21], + '44.x': [107.65, 125.28], + '44.y': [81.19, 62.68], + '45.height': [0.72, 0.56], + '45.width': [1.53, 1.18], + '45.x': [122.29, 136.58], + '45.y': [59.34, 45.82], + '46.height': [1.03, 0.8], + '46.width': [1.93, 1.49], + '46.x': [111.93, 128.59], + '46.y': [59.34, 45.81], + '47.height': [4.13, 3.19], + '47.width': [9.61, 7.42], + '47.x': [106.6, 124.47], + '47.y': [53.54, 41.34], + '48.height': [8.46, 6.53], + '48.width': [7.16, 5.53], + '48.x': [208.59, 203.22], + '48.y': [102.81, 79.37], + '49.height': [11.32, 8.74], + '49.width': [8.96, 6.92], + '49.x': [203.17, 199.03], + '49.y': [105.52, 81.47], + '50.height': [14.9, 11.5], + '50.width': [12.46, 9.62], + '50.x': [195.97, 193.47], + '50.y': [104.62, 80.77], + '51.height': [5.4, 4.17], + '51.width': [5.75, 4.44], + '51.x': [168.42, 172.2], + '51.y': [61.76, 47.68], + '52.height': [18.65, 14.4], + '52.width': [15.45, 11.93], + '52.x': [173.55, 176.16], + '52.y': [51.35, 39.65], + '53.height': [15.85, 12.23], + '53.width': [11.29, 8.72], + '53.x': [169.21, 172.81], + '53.y': [48.41, 37.37], + '54.height': [7.79, 6.01], + '54.width': [2.87, 2.21], + '54.x': [185.73, 185.57], + '54.y': [67.28, 51.94], + '55.height': [14.81, 11.44], + '55.width': [14.46, 11.17], + '55.x': [185.28, 185.22], + '55.y': [53.2, 41.07], + '56.height': [12.3, 9.5], + '56.width': [11.22, 8.66], + '56.x': [187.56, 186.98], + '56.y': [65.21, 50.34], + '57.height': [14.26, 11.01], + '57.width': [7.2, 5.56], + '57.x': [193.1, 191.25], + '57.y': [66.49, 51.33], + '58.height': [6.51, 5.03], + '58.width': [1.83, 1.41], + '58.x': [184.95, 184.96], + '58.y': [68.83, 53.14], + '59.height': [8.18, 6.32], + '59.width': [4.1, 3.17], + '59.x': [181.91, 182.61], + '59.y': [68.73, 53.06], + '60.height': [7.93, 6.12], + '60.width': [5.76, 4.45], + '60.x': [176.8, 178.67], + '60.y': [69.46, 53.63], + '61.height': [6.74, 5.2], + '61.width': [6.89, 5.32], + '61.x': [170.67, 173.94], + '61.y': [66.83, 51.6], + '62.height': [2.02, 1.56], + '62.width': [2.82, 2.18], + '62.x': [169.24, 172.83], + '62.y': [66.78, 51.56], + '63.height': [5.37, 4.15], + '63.width': [3.7, 2.86], + '63.x': [174.1, 176.59], + '63.y': [71.99, 55.58], + '64.height': [4.18, 3.22], + '64.width': [2.86, 2.21], + '64.x': [172.41, 175.28], + '64.y': [70.07, 54.1], + '65.height': [7, 5.41], + '65.width': [7.24, 5.59], + '65.x': [179.82, 181], + '65.y': [63.63, 49.12], + '66.height': [11.38, 8.79], + '66.width': [12.32, 9.51], + '66.x': [198.79, 195.65], + '66.y': [68.67, 53.02], + '67.height': [11.28, 8.71], + '67.width': [7.03, 5.43], + '67.x': [195.59, 193.18], + '67.y': [78.17, 60.35], + '68.height': [8.12, 6.27], + '68.width': [5.38, 4.15], + '68.x': [193.41, 191.49], + '68.y': [79.98, 61.75], + '69.height': [1.64, 1.27], + '69.width': [1.89, 1.46], + '69.x': [193.89, 191.86], + '69.y': [80.03, 61.79], + '70.height': [12.34, 9.53], + '70.width': [11.22, 8.66], + '70.x': [205.53, 200.85], + '70.y': [93.56, 72.23], + '71.height': [9.61, 7.42], + '71.width': [2.76, 2.13], + '71.x': [215.81, 208.79], + '71.y': [94.83, 73.21], + '72.height': [20.52, 15.84], + '72.width': [9.97, 7.7], + '72.x': [213.39, 206.92], + '72.y': [96.22, 74.28], + '73.height': [1.97, 1.52], + '73.width': [1.26, 0.97], + '73.x': [212.82, 206.47], + '73.y': [115.42, 89.11], + '74.height': [17.18, 13.26], + '74.width': [11.86, 9.16], + '74.x': [195.9, 193.42], + '74.y': [88.68, 68.47], + '75.height': [2.77, 2.14], + '75.width': [1.64, 1.27], + '75.x': [212.72, 206.4], + '75.y': [85.99, 66.39], + '76.height': [4.47, 3.45], + '76.width': [1.14, 0.88], + '76.x': [215.46, 208.52], + '76.y': [41.41, 31.97], + '77.height': [1.81, 1.4], + '77.width': [1.12, 0.87], + '77.x': [215.94, 208.89], + '77.y': [39.82, 30.74], + '78.height': [16.94, 13.08], + '78.width': [7.56, 5.83], + '78.x': [224.87, 215.79], + '78.y': [98.41, 75.98], + '79.height': [1.39, 1.07], + '79.width': [0.52, 0.4], + '79.x': [215.99, 208.93], + '79.y': [42.29, 32.65], + '80.height': [0.95, 0.73], + '80.width': [2.84, 2.19], + '80.x': [169.11, 172.73], + '80.y': [65.2, 50.33], + '81.height': [8.2, 6.33], + '81.width': [3.52, 2.72], + '81.x': [191.59, 190.09], + '81.y': [36.72, 28.35], + '82.height': [21.69, 16.75], + '82.width': [18.87, 14.56], + '82.x': [177.15, 178.94], + '82.y': [36.98, 28.55], + '83.height': [4.95, 3.82], + '83.width': [3.39, 2.62], + '83.x': [216.29, 209.16], + '83.y': [41.3, 31.88], + '84.height': [4.36, 3.37], + '84.width': [4.28, 3.3], + '84.x': [232.2, 221.44], + '84.y': [50.04, 38.63], + '85.height': [1.9, 1.47], + '85.width': [0.83, 0.64], + '85.x': [231.23, 220.69], + '85.y': [49.96, 38.57], + '86.height': [1.84, 1.42], + '86.width': [1.76, 1.36], + '86.x': [226.8, 217.27], + '86.y': [45.21, 34.91], + '87.height': [9.68, 7.48], + '87.width': [9.31, 7.19], + '87.x': [219.12, 211.34], + '87.y': [36.68, 28.32], + '88.height': [12.07, 9.32], + '88.width': [6.7, 5.17], + '88.x': [233.4, 222.37], + '88.y': [49.62, 38.31], + '89.height': [2.49, 1.92], + '89.width': [0.73, 0.56], + '89.x': [341.53, 305.85], + '89.y': [101.7, 78.51], + '90.height': [5.19, 4.01], + '90.width': [5.05, 3.9], + '90.x': [281.54, 259.53], + '90.y': [64.32, 49.66], + '91.height': [18.67, 14.42], + '91.width': [8.51, 6.57], + '91.x': [275.77, 255.08], + '91.y': [56.97, 43.99], + '92.height': [10.75, 8.3], + '92.width': [8.33, 6.43], + '92.x': [277.8, 256.64], + '92.y': [54.44, 42.03], + '93.height': [22.94, 17.71], + '93.width': [8.92, 6.89], + '93.x': [270.27, 250.84], + '93.y': [47.28, 36.5], + '94.height': [18.58, 14.34], + '94.width': [9.25, 7.14], + '94.x': [279.09, 257.64], + '94.y': [53.34, 41.18], + '95.height': [5.9, 4.55], + '95.width': [4.38, 3.38], + '95.x': [290.31, 266.3], + '95.y': [30.46, 23.52], + '96.height': [4.83, 3.73], + '96.width': [4.19, 3.23], + '96.x': [293.34, 268.64], + '96.y': [35.29, 27.25], + '97.height': [10.87, 8.39], + '97.width': [27.23, 21.03], + '97.x': [254.57, 238.71], + '97.y': [21.1, 16.29], + '98.height': [33.89, 26.16], + '98.width': [25.41, 19.62], + '98.x': [247.52, 233.27], + '98.y': [38.84, 29.99], + '99.height': [7.1, 5.48], + '99.width': [5.37, 4.15], + '99.x': [265.27, 246.97], + '99.y': [49.56, 38.26], + '100.height': [1.91, 1.47], + '100.width': [3.07, 2.37], + '100.x': [265.33, 247.02], + '100.y': [47.32, 36.54], + '101.height': [4.84, 3.74], + '101.width': [7.95, 6.14], + '101.x': [256.98, 240.57], + '101.y': [44.78, 34.57], + '102.height': [15.96, 12.32], + '102.width': [13.24, 10.22], + '102.x': [239.46, 227.05], + '102.y': [36.96, 28.54], + '103.height': [10.67, 8.23], + '103.width': [11.62, 8.97], + '103.x': [238.15, 226.04], + '103.y': [35.43, 27.36], + '104.height': [4.74, 3.66], + '104.width': [7.08, 5.46], + '104.x': [242.43, 229.34], + '104.y': [32.67, 25.22], + '105.height': [4.42, 3.41], + '105.width': [8.08, 6.24], + '105.x': [243.88, 230.46], + '105.y': [30.12, 23.25], + '106.height': [8.39, 6.48], + '106.width': [13.28, 10.26], + '106.x': [228.97, 218.94], + '106.y': [30.71, 23.71], + '107.height': [17.17, 13.26], + '107.width': [19.9, 15.36], + '107.x': [222.5, 213.95], + '107.y': [34.06, 26.29], + '108.height': [5.69, 4.39], + '108.width': [5.23, 4.04], + '108.x': [216.24, 209.12], + '108.y': [36.85, 28.45], + '109.height': [2.79, 2.15], + '109.width': [3.03, 2.34], + '109.x': [221.66, 213.31], + '109.y': [32.36, 24.98], + '110.height': [11.13, 8.59], + '110.width': [8.14, 6.29], + '110.x': [193.03, 191.2], + '110.y': [6.81, 5.26], + '111.height': [4.62, 3.57], + '111.width': [7.15, 5.52], + '111.x': [202.91, 198.83], + '111.y': [17.2, 13.28], + '112.height': [7.16, 5.53], + '112.width': [14.27, 11.02], + '112.x': [202.63, 198.61], + '112.y': [20.82, 16.07], + '113.height': [5.69, 4.39], + '113.width': [8.05, 6.22], + '113.x': [195.78, 193.32], + '113.y': [18.42, 14.22], + '114.height': [2.69, 2.07], + '114.width': [5.94, 4.59], + '114.x': [192.65, 190.9], + '114.y': [24.1, 18.6], + '115.height': [2.97, 2.3], + '115.width': [5.12, 3.95], + '115.x': [198.09, 195.11], + '115.y': [24.52, 18.93], + '116.height': [3.1, 2.39], + '116.width': [3.05, 2.36], + '116.x': [206.29, 201.43], + '116.y': [24.68, 19.05], + '117.height': [4.77, 3.68], + '117.width': [7.83, 6.05], + '117.x': [201.43, 197.68], + '117.y': [24.93, 19.25], + '118.height': [2.3, 1.78], + '118.width': [4.3, 3.32], + '118.x': [200.75, 197.16], + '118.y': [17.01, 13.13], + '119.height': [2.14, 1.65], + '119.width': [5.38, 4.16], + '119.x': [200.67, 197.09], + '119.y': [15.57, 12.02], + '120.height': [1.88, 1.45], + '120.width': [3.46, 2.67], + '120.x': [201.94, 198.08], + '120.y': [14.13, 10.91], + '121.height': [7.59, 5.86], + '121.width': [7.08, 5.47], + '121.x': [189.65, 188.59], + '121.y': [18.29, 14.12], + '122.height': [3.26, 2.52], + '122.width': [5.12, 3.95], + '122.x': [203.49, 199.27], + '122.y': [29.11, 22.48], + '123.height': [7.79, 6.01], + '123.width': [5.78, 4.46], + '123.x': [202.11, 198.21], + '123.y': [31.72, 24.49], + '124.height': [7.09, 5.47], + '124.width': [16.71, 12.9], + '124.x': [206.86, 201.88], + '124.y': [31.38, 24.22], + '125.height': [3.38, 2.61], + '125.width': [1.6, 1.24], + '125.x': [201.12, 197.45], + '125.y': [30.78, 23.76], + '126.height': [4.3, 3.32], + '126.width': [4.69, 3.62], + '126.x': [196.16, 193.62], + '126.y': [26.71, 20.62], + '127.height': [2.14, 1.65], + '127.width': [3.55, 2.74], + '127.x': [189.88, 188.77], + '127.y': [25.33, 19.56], + '128.height': [0.69, 0.53], + '128.width': [0.44, 0.34], + '128.x': [189.49, 188.47], + '128.y': [23, 17.76], + '129.height': [1.94, 1.5], + '129.width': [2.86, 2.21], + '129.x': [186.96, 186.52], + '129.y': [21.66, 16.72], + '130.height': [2.64, 2.04], + '130.width': [2.86, 2.21], + '130.x': [187.58, 186.99], + '130.y': [19.69, 15.2], + '131.height': [6.08, 4.69], + '131.width': [2.77, 2.14], + '131.x': [176.87, 178.72], + '131.y': [31.22, 24.11], + '132.height': [8.69, 6.71], + '132.width': [10.35, 7.99], + '132.x': [177.2, 178.98], + '132.y': [29.63, 22.88], + '133.height': [3.32, 2.56], + '133.width': [3.12, 2.41], + '133.x': [177.25, 179.02], + '133.y': [18.16, 14.02], + '134.height': [2.85, 2.2], + '134.width': [1.9, 1.47], + '134.x': [337.15, 302.47], + '134.y': [108.58, 83.83], + '135.height': [5.41, 4.18], + '135.width': [4.82, 3.72], + '135.x': [334.06, 300.08], + '135.y': [91.46, 70.61], + '136.height': [13.48, 10.41], + '136.width': [18.02, 13.91], + '136.x': [320.31, 289.47], + '136.y': [125.89, 97.2], + '137.height': [39.52, 30.51], + '137.width': [38.62, 29.82], + '137.x': [285.74, 262.77], + '137.y': [96.66, 74.63], + '138.height': [4.94, 3.81], + '138.width': [2.05, 1.58], + '138.x': [260.79, 243.52], + '138.y': [70.35, 54.32], + '139.height': [40.01, 30.89], + '139.width': [47.06, 36.33], + '139.x': [247.57, 233.31], + '139.y': [19.74, 15.24], + '140.height': [4.09, 3.16], + '140.width': [1.28, 0.98], + '140.x': [295.19, 270.07], + '140.y': [50.96, 39.34], + '141.height': [11.47, 8.86], + '141.width': [10.11, 7.81], + '141.x': [190.53, 189.27], + '141.y': [26.07, 20.13], + '142.height': [2.68, 2.07], + '142.width': [3.5, 2.71], + '142.x': [191.02, 189.65], + '142.y': [15.78, 12.19], + '143.height': [8.19, 6.32], + '143.width': [7.06, 5.45], + '143.x': [179.23, 180.55], + '143.y': [14.98, 11.57], + '144.height': [2.3, 1.78], + '144.width': [7.24, 5.59], + '144.x': [168.47, 172.24], + '144.y': [8.62, 6.65], + '145.height': [3.99, 3.08], + '145.width': [4.82, 3.72], + '145.x': [222.79, 214.18], + '145.y': [31.68, 24.46], + '146.height': [2.71, 2.1], + '146.width': [6.12, 4.72], + '146.x': [218.09, 210.55], + '146.y': [29.84, 23.04], + '147.height': [16.43, 12.68], + '147.width': [9.06, 7], + '147.x': [296.42, 271.02], + '147.y': [59.36, 45.83], + '148.height': [7.91, 6.11], + '148.width': [18.3, 14.13], + '148.x': [280.36, 258.62], + '148.y': [74.06, 57.18], + '149.height': [1.85, 1.43], + '149.width': [1.12, 0.86], + '149.x': [293.99, 269.14], + '149.y': [75.96, 58.65], + '150.height': [1.47, 1.13], + '150.width': [2.28, 1.76], + '150.x': [196.14, 193.6], + '150.y': [26.35, 20.34], + '151.height': [7.81, 6.03], + '151.width': [8.52, 6.58], + '151.x': [198.52, 195.44], + '151.y': [6.12, 4.72], + '152.height': [1.85, 1.43], + '152.width': [4.45, 3.43], + '152.x': [198.47, 195.4], + '152.y': [23.56, 18.19], + '153.height': [2.58, 1.99], + '153.width': [5.3, 4.09], + '153.x': [194.63, 192.43], + '153.y': [22.01, 17], + '154.height': [7, 5.4], + '154.width': [6.53, 5.04], + '154.x': [219.16, 211.37], + '154.y': [60, 46.32], + '155.height': [16.35, 12.62], + '155.width': [8.35, 6.45], + '155.x': [298.86, 272.91], + '155.y': [27.71, 21.4], + '156.height': [10.09, 7.79], + '156.width': [8.14, 6.28], + '156.x': [127.23, 140.4], + '156.y': [107.63, 83.09], + '157.height': [8.09, 6.25], + '157.width': [9.7, 7.49], + '157.x': [225.03, 215.91], + '157.y': [58.74, 45.35], + '158.height': [19.35, 14.94], + '158.width': [20.12, 15.53], + '158.x': [216.22, 209.11], + '158.y': [42.72, 32.99], + '159.height': [11.86, 9.16], + '159.width': [212.22, 163.85], + '159.x': [81.85, 105.36], + '159.y': [154.84, 119.54], + '160.height': [0.77, 0.6], + '160.width': [1.52, 1.17], + '160.x': [213.52, 207.02], + '160.y': [38.64, 29.83], + '161.height': [0.7, 0.54], + '161.width': [1.54, 1.19], + '161.x': [213.12, 206.71], + '161.y': [39.21, 30.27], + '162.height': [17.19, 13.27], + '162.width': [14.73, 11.37], + '162.x': [169.27, 172.86], + '162.y': [38.54, 29.75], + '163.height': [11.61, 8.96], + '163.width': [11.94, 9.22], + '163.x': [207.06, 202.03], + '163.y': [43.4, 33.51], + '164.height': [16.44, 12.69], + '164.width': [14.74, 11.38], + '164.x': [193.46, 191.53], + '164.y': [41.58, 32.1], + '165.height': [14.74, 11.38], + '165.width': [14.1, 10.89], + '165.x': [216.35, 209.21], + '165.y': [63.82, 49.28], + '166.height': [2.26, 1.74], + '166.width': [1.51, 1.17], + '166.x': [224.43, 215.44], + '166.y': [66.69, 51.49], + '167.height': [4.43, 3.42], + '167.width': [6.12, 4.73], + '167.x': [225.34, 216.15], + '167.y': [68.26, 52.7], + '168.height': [7.33, 5.66], + '168.width': [5.21, 4.02], + '168.x': [213.27, 206.82], + '168.y': [77.5, 59.83], + '169.height': [2.29, 1.77], + '169.width': [1.72, 1.33], + '169.x': [212.72, 206.4], + '169.y': [84.43, 65.19], + '170.height': [2.77, 2.14], + '170.width': [3.25, 2.51], + '170.x': [197.92, 194.97], + '170.y': [28.05, 21.65], + '171.height': [1.62, 1.25], + '171.width': [2.11, 1.63], + '171.x': [202.17, 198.25], + '171.y': [31.18, 24.07], + '172.height': [4.2, 3.25], + '172.width': [3.74, 2.89], + '172.x': [200.32, 196.83], + '172.y': [27.06, 20.89], + '173.height': [1.79, 1.38], + '173.width': [1.53, 1.18], + '173.x': [200.38, 196.87], + '173.y': [29.88, 23.07], + '174.height': [1.55, 1.2], + '174.width': [1.41, 1.09], + '174.x': [201.72, 197.91], + '174.y': [30.15, 23.27], + '175.height': [1.14, 0.88], + '175.width': [1.07, 0.82], + '175.x': [126.23, 139.63], + '175.y': [68.99, 53.27], + '176.height': [11.19, 8.64], + '176.width': [10.95, 8.46], + '176.x': [207.71, 202.53], + '176.y': [67.26, 51.93], + }, + legend: { + 'continuousLegend.bounds.height': [61, 99], + 'continuousLegend.bar.y': [111.3, 126.3], + }, + }, + style: { + 'legends.continuousLegend.title': ['gdp ($)', 'gdp'], + }, + }, + '../gallery/maps.stories.tsx.worldEqualEarthSpec @1280': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [162, 124], + }, + area: { + 'rect.height': [162, 124], + 'rect.y': [153.2, 191.2], + }, + marks: { + '0.height': [2.77, 2.12], + '0.width': [328.1, 251.14], + '0.x': [455.95, 494.43], + '0.y': [100.54, 76.96], + '1.height': [13.42, 10.27], + '1.width': [9.95, 7.61], + '1.x': [647.21, 640.83], + '1.y': [81.82, 62.63], + '2.height': [7.93, 6.07], + '2.width': [7.74, 5.92], + '2.x': [604.66, 608.26], + '2.y': [46.74, 35.78], + '3.height': [30.89, 23.64], + '3.width': [64.23, 49.16], + '3.x': [520.95, 544.18], + '3.y': [0.1, 0.07], + '4.height': [51.97, 39.78], + '4.width': [90.05, 68.93], + '4.x': [476.8, 510.39], + '4.y': [5.22, 3.99], + '5.height': [14.66, 11.22], + '5.width': [31.35, 24], + '5.x': [656, 647.56], + '5.y': [17.42, 13.33], + '6.height': [9.01, 6.9], + '6.width': [15.29, 11.7], + '6.x': [664.52, 654.08], + '6.y': [26.89, 20.59], + '7.height': [10.16, 7.78], + '7.width': [14.26, 10.92], + '7.x': [750.2, 719.66], + '7.y': [83.76, 64.11], + '8.height': [19.78, 15.14], + '8.width': [42.58, 32.59], + '8.x': [708.31, 687.6], + '8.y': [73.78, 56.47], + '9.height': [36.13, 27.65], + '9.width': [13.77, 10.54], + '9.x': [559, 573.31], + '9.y': [107.6, 82.36], + '10.height': [41.61, 31.85], + '10.width': [14.58, 11.16], + '10.x': [556.23, 571.19], + '10.y': [102.45, 78.42], + '11.height': [23.08, 17.67], + '11.width': [17.66, 13.52], + '11.x': [631.29, 628.64], + '11.y': [74.06, 56.69], + '12.height': [17.09, 13.08], + '12.width': [8.98, 6.87], + '12.x': [658.04, 649.12], + '12.y': [65.64, 50.25], + '13.height': [12.73, 9.75], + '13.width': [7.35, 5.63], + '13.x': [651.48, 644.09], + '13.y': [73.75, 56.45], + '14.height': [16.89, 12.93], + '14.width': [14.7, 11.25], + '14.x': [640.14, 635.42], + '14.y': [53.46, 40.92], + '15.height': [19.59, 14.99], + '15.width': [9.41, 7.2], + '15.x': [632.39, 629.48], + '15.y': [51.77, 39.63], + '16.height': [2.29, 1.75], + '16.width': [2.74, 2.1], + '16.x': [552.53, 568.36], + '16.y': [55.98, 42.85], + '17.height': [2.78, 2.13], + '17.width': [3.28, 2.51], + '17.x': [554.86, 570.14], + '17.y': [56.01, 42.87], + '18.height': [30.9, 23.65], + '18.width': [242.18, 185.37], + '18.x': [500.34, 528.41], + '18.y': [0.65, 0.5], + '19.height': [3.95, 3.02], + '19.width': [1.78, 1.36], + '19.x': [550.35, 566.69], + '19.y': [47.47, 36.33], + '20.height': [1.14, 0.88], + '20.width': [2.49, 1.91], + '20.x': [573.83, 584.66], + '20.y': [139.85, 107.05], + '21.height': [14.2, 10.87], + '21.width': [16.27, 12.45], + '21.x': [623.42, 622.62], + '21.y': [0.84, 0.64], + '22.height': [13.38, 10.24], + '22.width': [35.75, 27.36], + '22.x': [577.32, 587.33], + '23.height': [1.13, 0.87], + '23.width': [1.68, 1.28], + '23.x': [672.76, 660.39], + '23.y': [137.43, 105.2], + '24.height': [1.39, 1.07], + '24.width': [2.26, 1.73], + '24.x': [735.4, 708.33], + '24.y': [90.96, 69.63], + '25.height': [14.85, 11.36], + '25.width': [14.63, 11.2], + '25.x': [634.29, 630.94], + '25.y': [107.91, 82.6], + '26.height': [2.32, 1.77], + '26.width': [2.09, 1.6], + '26.x': [643.47, 637.96], + '26.y': [115.68, 88.55], + '27.height': [21.66, 16.58], + '27.width': [22.97, 17.58], + '27.x': [519.05, 542.73], + '27.y': [40.88, 31.29], + '28.height': [5.53, 4.23], + '28.width': [4.52, 3.46], + '28.x': [569.96, 581.7], + '28.y': [117.38, 89.85], + '29.height': [47.5, 36.36], + '29.width': [36.3, 27.79], + '29.x': [551.57, 567.62], + '29.y': [74.07, 56.7], + '30.height': [16.03, 12.27], + '30.width': [11.89, 9.1], + '30.x': [555.99, 571], + '30.y': [92.82, 71.04], + '31.height': [22.68, 17.36], + '31.width': [12.7, 9.72], + '31.x': [544.51, 562.22], + '31.y': [80.7, 61.77], + '32.height': [20.87, 15.98], + '32.width': [11.24, 8.61], + '32.x': [546.65, 563.86], + '32.y': [65.13, 49.85], + '33.height': [2.97, 2.28], + '33.width': [5.26, 4.03], + '33.x': [543.32, 561.31], + '33.y': [68.64, 52.54], + '34.height': [3.72, 2.84], + '34.width': [2.97, 2.28], + '34.x': [540.87, 559.43], + '34.y': [66.64, 51.01], + '35.height': [5.3, 4.05], + '35.width': [4.47, 3.42], + '35.x': [539.56, 558.43], + '35.y': [61.95, 47.42], + '36.height': [3.72, 2.84], + '36.width': [5.77, 4.42], + '36.x': [538.26, 557.44], + '36.y': [60.74, 46.49], + '37.height': [1.57, 1.2], + '37.width': [2.18, 1.67], + '37.x': [537.47, 556.83], + '37.y': [62.68, 47.98], + '38.height': [5.01, 3.83], + '38.width': [3.87, 2.97], + '38.x': [535.66, 555.44], + '38.y': [58.52, 44.8], + '39.height': [3.19, 2.44], + '39.width': [1.52, 1.16], + '39.x': [538.64, 557.73], + '39.y': [57.69, 44.16], + '40.height': [14.25, 10.91], + '40.width': [12.45, 9.53], + '40.x': [552.33, 568.2], + '40.y': [65.47, 50.12], + '41.height': [8.86, 6.78], + '41.width': [4.39, 3.36], + '41.x': [563.11, 576.45], + '41.y': [70.18, 53.72], + '42.height': [5.26, 4.02], + '42.width': [3.85, 2.95], + '42.x': [566.15, 578.78], + '42.y': [73.1, 55.95], + '43.height': [56.7, 43.4], + '43.width': [58.38, 44.69], + '43.x': [569.38, 581.25], + '43.y': [21.36, 16.35], + '44.height': [7.93, 6.07], + '44.width': [5.3, 4.06], + '44.x': [544.83, 562.46], + '44.y': [78.9, 60.39], + '45.height': [0.7, 0.53], + '45.width': [1.49, 1.14], + '45.x': [559.06, 573.35], + '45.y': [57.67, 44.14], + '46.height': [1, 0.77], + '46.width': [1.88, 1.44], + '46.x': [548.99, 565.65], + '46.y': [57.67, 44.14], + '47.height': [4.01, 3.07], + '47.width': [9.34, 7.15], + '47.x': [543.81, 561.68], + '47.y': [52.04, 39.83], + '48.height': [8.22, 6.29], + '48.width': [6.96, 5.33], + '48.x': [642.93, 637.55], + '48.y': [99.91, 76.48], + '49.height': [11, 8.42], + '49.width': [8.71, 6.67], + '49.x': [637.66, 633.52], + '49.y': [102.55, 78.49], + '50.height': [14.48, 11.08], + '50.width': [12.11, 9.27], + '50.x': [630.66, 628.16], + '50.y': [101.67, 77.82], + '51.height': [5.25, 4.02], + '51.width': [5.59, 4.28], + '51.x': [603.89, 607.67], + '51.y': [60.02, 45.94], + '52.height': [18.13, 13.87], + '52.width': [15.01, 11.49], + '52.x': [608.87, 611.48], + '52.y': [49.91, 38.2], + '53.height': [15.4, 11.79], + '53.width': [10.97, 8.4], + '53.x': [604.66, 608.26], + '53.y': [47.05, 36.01], + '54.height': [7.57, 5.8], + '54.width': [2.78, 2.13], + '54.x': [620.71, 620.54], + '54.y': [65.38, 50.05], + '55.height': [14.4, 11.02], + '55.width': [14.05, 10.76], + '55.x': [620.27, 620.21], + '55.y': [51.7, 39.57], + '56.height': [11.96, 9.15], + '56.width': [10.9, 8.35], + '56.x': [622.49, 621.91], + '56.y': [63.37, 48.51], + '57.height': [13.86, 10.61], + '57.width': [6.99, 5.35], + '57.x': [627.87, 626.02], + '57.y': [64.61, 49.46], + '58.height': [6.33, 4.85], + '58.width': [1.77, 1.36], + '58.x': [619.96, 619.97], + '58.y': [66.89, 51.2], + '59.height': [7.95, 6.09], + '59.width': [3.99, 3.05], + '59.x': [616.99, 617.7], + '59.y': [66.79, 51.12], + '60.height': [7.7, 5.9], + '60.width': [5.6, 4.28], + '60.x': [612.03, 613.9], + '60.y': [67.5, 51.67], + '61.height': [6.55, 5.01], + '61.width': [6.69, 5.12], + '61.x': [606.07, 609.34], + '61.y': [64.95, 49.71], + '62.height': [1.96, 1.5], + '62.width': [2.74, 2.1], + '62.x': [604.68, 608.28], + '62.y': [64.9, 49.67], + '63.height': [5.22, 4], + '63.width': [3.6, 2.76], + '63.x': [609.41, 611.9], + '63.y': [69.96, 53.55], + '64.height': [4.06, 3.11], + '64.width': [2.78, 2.13], + '64.x': [607.77, 610.64], + '64.y': [68.09, 52.12], + '65.height': [6.8, 5.21], + '65.width': [7.03, 5.38], + '65.x': [614.96, 616.15], + '65.y': [61.83, 47.33], + '66.height': [11.06, 8.47], + '66.width': [11.97, 9.16], + '66.x': [633.4, 630.26], + '66.y': [66.73, 51.08], + '67.height': [10.96, 8.39], + '67.width': [6.83, 5.23], + '67.x': [630.29, 627.88], + '67.y': [75.97, 58.15], + '68.height': [7.89, 6.04], + '68.width': [5.23, 4], + '68.x': [628.17, 626.25], + '68.y': [77.72, 59.49], + '69.height': [1.59, 1.22], + '69.width': [1.84, 1.41], + '69.x': [628.64, 626.61], + '69.y': [77.77, 59.53], + '70.height': [11.99, 9.18], + '70.width': [10.9, 8.35], + '70.x': [639.95, 635.27], + '70.y': [90.92, 69.59], + '71.height': [9.34, 7.15], + '71.width': [2.69, 2.06], + '71.x': [649.94, 642.92], + '71.y': [92.16, 70.54], + '72.height': [19.94, 15.27], + '72.width': [9.69, 7.42], + '72.x': [647.59, 641.12], + '72.y': [93.5, 71.57], + '73.height': [1.92, 1.47], + '73.width': [1.22, 0.94], + '73.x': [647.03, 640.69], + '73.y': [112.17, 85.86], + '74.height': [16.69, 12.78], + '74.width': [11.53, 8.82], + '74.x': [630.59, 628.11], + '74.y': [86.18, 65.97], + '75.height': [2.69, 2.06], + '75.width': [1.6, 1.22], + '75.x': [646.94, 640.62], + '75.y': [83.57, 63.97], + '76.height': [4.34, 3.32], + '76.width': [1.11, 0.85], + '76.x': [649.6, 642.66], + '76.y': [40.25, 30.81], + '77.height': [1.76, 1.35], + '77.width': [1.09, 0.83], + '77.x': [650.07, 643.01], + '77.y': [38.7, 29.62], + '78.height': [16.46, 12.6], + '78.width': [7.34, 5.62], + '78.x': [658.75, 649.66], + '78.y': [95.64, 73.21], + '79.height': [1.35, 1.03], + '79.width': [0.5, 0.38], + '79.x': [650.12, 643.05], + '79.y': [41.09, 31.46], + '80.height': [0.92, 0.7], + '80.width': [2.76, 2.11], + '80.x': [604.55, 608.18], + '80.y': [63.36, 48.5], + '81.height': [7.97, 6.1], + '81.width': [3.42, 2.62], + '81.x': [626.41, 624.91], + '81.y': [35.68, 27.31], + '82.height': [21.08, 16.13], + '82.width': [18.33, 14.03], + '82.x': [612.37, 614.16], + '82.y': [35.94, 27.51], + '83.height': [4.81, 3.68], + '83.width': [3.3, 2.52], + '83.x': [650.41, 643.27], + '83.y': [40.13, 30.72], + '84.height': [4.24, 3.25], + '84.width': [4.16, 3.18], + '84.x': [665.87, 655.11], + '84.y': [48.62, 37.22], + '85.height': [1.85, 1.41], + '85.width': [0.81, 0.62], + '85.x': [664.92, 654.39], + '85.y': [48.55, 37.17], + '86.height': [1.78, 1.37], + '86.width': [1.71, 1.31], + '86.x': [660.62, 651.09], + '86.y': [43.94, 33.63], + '87.height': [9.41, 7.2], + '87.width': [9.05, 6.93], + '87.x': [653.16, 645.38], + '87.y': [35.64, 27.28], + '88.height': [11.73, 8.98], + '88.width': [6.51, 4.99], + '88.x': [667.03, 656], + '88.y': [48.22, 36.91], + '89.height': [2.42, 1.85], + '89.width': [0.71, 0.54], + '89.x': [772.12, 736.44], + '89.y': [98.83, 75.65], + '90.height': [5.05, 3.86], + '90.width': [4.91, 3.76], + '90.x': [713.82, 691.81], + '90.y': [62.5, 47.84], + '91.height': [18.15, 13.89], + '91.width': [8.27, 6.33], + '91.x': [708.21, 687.52], + '91.y': [55.37, 42.38], + '92.height': [10.45, 8], + '92.width': [8.09, 6.2], + '92.x': [710.18, 689.03], + '92.y': [52.9, 40.49], + '93.height': [22.29, 17.06], + '93.width': [8.67, 6.64], + '93.x': [702.87, 683.43], + '93.y': [45.94, 35.17], + '94.height': [18.05, 13.82], + '94.width': [8.99, 6.88], + '94.x': [711.43, 689.99], + '94.y': [51.84, 39.68], + '95.height': [5.73, 4.39], + '95.width': [4.26, 3.26], + '95.x': [722.34, 698.33], + '95.y': [29.6, 22.66], + '96.height': [4.69, 3.59], + '96.width': [4.07, 3.11], + '96.x': [725.28, 700.59], + '96.y': [34.29, 26.25], + '97.height': [10.56, 8.09], + '97.width': [26.47, 20.26], + '97.x': [687.61, 671.75], + '97.y': [20.51, 15.7], + '98.height': [32.93, 25.21], + '98.width': [24.7, 18.9], + '98.x': [680.75, 666.5], + '98.y': [37.75, 28.89], + '99.height': [6.9, 5.28], + '99.width': [5.22, 3.99], + '99.x': [698.01, 679.71], + '99.y': [48.16, 36.87], + '100.height': [1.85, 1.42], + '100.width': [2.98, 2.28], + '100.x': [698.06, 679.75], + '100.y': [45.99, 35.2], + '101.height': [4.7, 3.6], + '101.width': [7.73, 5.91], + '101.x': [689.95, 673.54], + '101.y': [43.52, 33.31], + '102.height': [15.51, 11.87], + '102.width': [12.86, 9.85], + '102.x': [672.93, 660.51], + '102.y': [35.92, 27.5], + '103.height': [10.36, 7.93], + '103.width': [11.29, 8.64], + '103.x': [671.66, 659.54], + '103.y': [34.43, 26.36], + '104.height': [4.61, 3.53], + '104.width': [6.88, 5.26], + '104.x': [675.81, 662.72], + '104.y': [31.75, 24.3], + '105.height': [4.3, 3.29], + '105.width': [7.85, 6.01], + '105.x': [677.22, 663.8], + '105.y': [29.27, 22.4], + '106.height': [8.15, 6.24], + '106.width': [12.91, 9.88], + '106.x': [662.73, 652.7], + '106.y': [29.85, 22.85], + '107.height': [16.69, 12.77], + '107.width': [19.34, 14.8], + '107.x': [656.44, 647.89], + '107.y': [33.1, 25.33], + '108.height': [5.53, 4.23], + '108.width': [5.09, 3.89], + '108.x': [650.36, 643.24], + '108.y': [35.82, 27.41], + '109.height': [2.71, 2.07], + '109.width': [2.95, 2.25], + '109.x': [655.63, 647.27], + '109.y': [31.44, 24.07], + '110.height': [10.81, 8.28], + '110.width': [7.91, 6.06], + '110.x': [627.8, 625.97], + '110.y': [6.62, 5.07], + '111.height': [4.49, 3.44], + '111.width': [6.94, 5.32], + '111.x': [637.4, 633.32], + '111.y': [16.71, 12.79], + '112.height': [6.96, 5.33], + '112.width': [13.87, 10.61], + '112.x': [637.13, 633.11], + '112.y': [20.23, 15.49], + '113.height': [5.53, 4.23], + '113.width': [7.82, 5.99], + '113.x': [630.48, 628.02], + '113.y': [17.9, 13.7], + '114.height': [2.61, 2], + '114.width': [5.77, 4.42], + '114.x': [627.43, 625.69], + '114.y': [23.42, 17.93], + '115.height': [2.89, 2.21], + '115.width': [4.97, 3.81], + '115.x': [632.72, 629.74], + '115.y': [23.83, 18.24], + '116.height': [3.01, 2.3], + '116.width': [2.97, 2.27], + '116.x': [640.69, 635.83], + '116.y': [23.99, 18.36], + '117.height': [4.63, 3.55], + '117.width': [7.61, 5.83], + '117.x': [635.96, 632.22], + '117.y': [24.23, 18.55], + '118.height': [2.24, 1.71], + '118.width': [4.18, 3.2], + '118.x': [635.31, 631.72], + '118.y': [16.53, 12.65], + '119.height': [2.08, 1.59], + '119.width': [5.23, 4], + '119.x': [635.22, 631.65], + '119.y': [15.13, 11.58], + '120.height': [1.82, 1.4], + '120.width': [3.36, 2.57], + '120.x': [636.46, 632.6], + '120.y': [13.74, 10.51], + '121.height': [7.37, 5.64], + '121.width': [6.88, 5.27], + '121.x': [624.52, 623.46], + '121.y': [17.78, 13.61], + '122.height': [3.17, 2.42], + '122.width': [4.97, 3.81], + '122.x': [637.97, 633.75], + '122.y': [28.29, 21.65], + '123.height': [7.57, 5.79], + '123.width': [5.62, 4.3], + '123.x': [636.63, 632.73], + '123.y': [30.83, 23.59], + '124.height': [6.89, 5.27], + '124.width': [16.24, 12.43], + '124.x': [641.25, 636.26], + '124.y': [30.49, 23.34], + '125.height': [3.28, 2.51], + '125.width': [1.56, 1.19], + '125.x': [635.67, 631.99], + '125.y': [29.91, 22.9], + '126.height': [4.17, 3.19], + '126.width': [4.56, 3.49], + '126.x': [630.85, 628.3], + '126.y': [25.96, 19.87], + '127.height': [2.08, 1.59], + '127.width': [3.45, 2.64], + '127.x': [624.75, 623.63], + '127.y': [24.62, 18.84], + '128.height': [0.67, 0.51], + '128.width': [0.42, 0.32], + '128.x': [624.36, 623.34], + '128.y': [22.35, 17.11], + '129.height': [1.88, 1.44], + '129.width': [2.78, 2.13], + '129.x': [621.91, 621.46], + '129.y': [21.05, 16.11], + '130.height': [2.56, 1.96], + '130.width': [2.78, 2.13], + '130.x': [622.51, 621.92], + '130.y': [19.13, 14.64], + '131.height': [5.9, 4.52], + '131.width': [2.69, 2.06], + '131.x': [612.1, 613.95], + '131.y': [30.34, 23.23], + '132.height': [8.44, 6.46], + '132.width': [10.05, 7.7], + '132.x': [612.42, 614.2], + '132.y': [28.8, 22.04], + '133.height': [3.22, 2.47], + '133.width': [3.03, 2.32], + '133.x': [612.47, 614.24], + '133.y': [17.64, 13.5], + '134.height': [2.77, 2.12], + '134.width': [1.84, 1.41], + '134.x': [767.86, 733.18], + '134.y': [105.52, 80.77], + '135.height': [5.26, 4.02], + '135.width': [4.69, 3.59], + '135.x': [764.86, 730.88], + '135.y': [88.88, 68.03], + '136.height': [13.1, 10.03], + '136.width': [17.51, 13.41], + '136.x': [751.5, 720.65], + '136.y': [122.34, 93.65], + '137.height': [38.41, 29.4], + '137.width': [37.54, 28.73], + '137.x': [717.9, 694.93], + '137.y': [93.94, 71.9], + '138.height': [4.8, 3.67], + '138.width': [1.99, 1.52], + '138.x': [693.66, 676.38], + '138.y': [68.37, 52.33], + '139.height': [38.88, 29.76], + '139.width': [45.73, 35.01], + '139.x': [680.81, 666.54], + '139.y': [19.18, 14.68], + '140.height': [3.97, 3.04], + '140.width': [1.24, 0.95], + '140.x': [727.08, 701.96], + '140.y': [49.52, 37.91], + '141.height': [11.15, 8.54], + '141.width': [9.83, 7.52], + '141.x': [625.37, 624.11], + '141.y': [25.34, 19.4], + '142.height': [2.61, 2], + '142.width': [3.41, 2.61], + '142.x': [625.85, 624.48], + '142.y': [15.34, 11.74], + '143.height': [7.95, 6.09], + '143.width': [6.86, 5.25], + '143.x': [614.4, 615.71], + '143.y': [14.56, 11.15], + '144.height': [2.24, 1.71], + '144.width': [7.03, 5.38], + '144.x': [603.93, 607.7], + '144.y': [8.38, 6.41], + '145.height': [3.88, 2.97], + '145.width': [4.69, 3.59], + '145.x': [656.73, 648.11], + '145.y': [30.79, 23.57], + '146.height': [2.64, 2.02], + '146.width': [5.95, 4.55], + '146.x': [652.16, 644.61], + '146.y': [29, 22.2], + '147.height': [15.97, 12.22], + '147.width': [8.81, 6.74], + '147.x': [728.28, 702.88], + '147.y': [57.69, 44.16], + '148.height': [7.69, 5.89], + '148.width': [17.78, 13.61], + '148.x': [712.67, 690.94], + '148.y': [71.97, 55.09], + '149.height': [1.8, 1.38], + '149.width': [1.08, 0.83], + '149.x': [725.91, 701.07], + '149.y': [73.82, 56.5], + '150.height': [1.43, 1.09], + '150.width': [2.22, 1.7], + '150.x': [630.82, 628.28], + '150.y': [25.6, 19.6], + '151.height': [7.59, 5.81], + '151.width': [8.28, 6.34], + '151.x': [633.14, 630.05], + '151.y': [5.95, 4.55], + '152.height': [1.8, 1.38], + '152.width': [4.32, 3.31], + '152.x': [633.09, 630.02], + '152.y': [22.89, 17.52], + '153.height': [2.5, 1.92], + '153.width': [5.15, 3.94], + '153.x': [629.36, 627.16], + '153.y': [21.39, 16.38], + '154.height': [6.8, 5.21], + '154.width': [6.35, 4.86], + '154.x': [653.2, 645.41], + '154.y': [58.31, 44.63], + '155.height': [15.89, 12.16], + '155.width': [8.12, 6.21], + '155.x': [730.65, 704.7], + '155.y': [26.93, 20.61], + '156.height': [9.81, 7.51], + '156.width': [7.91, 6.05], + '156.x': [563.86, 577.03], + '156.y': [104.59, 80.06], + '157.height': [7.86, 6.02], + '157.width': [9.43, 7.22], + '157.x': [658.91, 649.78], + '157.y': [57.09, 43.7], + '158.height': [18.8, 14.39], + '158.width': [19.55, 14.96], + '158.x': [650.34, 643.23], + '158.y': [41.52, 31.78], + '159.height': [11.53, 8.82], + '159.width': [206.24, 157.86], + '159.x': [519.76, 543.27], + '159.y': [150.47, 115.18], + '160.height': [0.75, 0.57], + '160.width': [1.48, 1.13], + '160.x': [647.72, 641.22], + '160.y': [37.55, 28.74], + '161.height': [0.68, 0.52], + '161.width': [1.5, 1.15], + '161.x': [647.32, 640.91], + '161.y': [38.11, 29.17], + '162.height': [16.71, 12.79], + '162.width': [14.32, 10.96], + '162.x': [604.72, 608.3], + '162.y': [37.45, 28.67], + '163.height': [11.28, 8.63], + '163.width': [11.6, 8.88], + '163.x': [641.44, 636.41], + '163.y': [42.18, 32.29], + '164.height': [15.98, 12.23], + '164.width': [14.32, 10.96], + '164.x': [628.22, 626.3], + '164.y': [40.41, 30.93], + '165.height': [14.33, 10.97], + '165.width': [13.71, 10.49], + '165.x': [650.47, 643.32], + '165.y': [62.02, 47.48], + '166.height': [2.19, 1.68], + '166.width': [1.47, 1.13], + '166.x': [658.31, 649.33], + '166.y': [64.81, 49.61], + '167.height': [4.3, 3.29], + '167.width': [5.95, 4.55], + '167.x': [659.21, 650.01], + '167.y': [66.34, 50.78], + '168.height': [7.12, 5.45], + '168.width': [5.06, 3.88], + '168.x': [647.47, 641.03], + '168.y': [75.32, 57.65], + '169.height': [2.23, 1.71], + '169.width': [1.67, 1.28], + '169.x': [646.94, 640.62], + '169.y': [82.05, 62.81], + '170.height': [2.7, 2.06], + '170.width': [3.16, 2.42], + '170.x': [632.55, 629.61], + '170.y': [27.26, 20.86], + '171.height': [1.58, 1.21], + '171.width': [2.05, 1.57], + '171.x': [636.68, 632.77], + '171.y': [30.3, 23.19], + '172.height': [4.09, 3.13], + '172.width': [3.64, 2.78], + '172.x': [634.89, 631.4], + '172.y': [26.3, 20.13], + '173.height': [1.74, 1.33], + '173.width': [1.48, 1.14], + '173.x': [634.94, 631.44], + '173.y': [29.03, 22.22], + '174.height': [1.51, 1.15], + '174.width': [1.37, 1.05], + '174.x': [636.25, 632.44], + '174.y': [29.3, 22.42], + '175.height': [1.1, 0.85], + '175.width': [1.04, 0.79], + '175.x': [562.89, 576.28], + '175.y': [67.05, 51.32], + '176.height': [10.87, 8.32], + '176.width': [10.64, 8.15], + '176.x': [642.07, 636.89], + '176.y': [65.37, 50.03], + }, + legend: { + 'continuousLegend.bounds.height': [61, 99], + 'continuousLegend.bar.y': [107.2, 122.2], + }, + }, + style: { + 'legends.continuousLegend.title': ['gdp ($)', 'gdp'], + }, + }, + '../gallery/maps.stories.tsx.worldMercatorSpec @390': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [166.7, 128.7], + }, + area: { + 'rect.height': [166.7, 128.7], + 'rect.y': [157.3, 195.3], + }, + marks: { + '0.height': [1.7, 1.31], + '0.width': [257.72, 198.97], + '0.x': [56.14, 85.51], + '0.y': [130.21, 100.53], + '1.height': [7.77, 6], + '1.width': [7.86, 6.07], + '1.x': [206, 201.22], + '1.y': [119.27, 92.08], + '2.height': [5.23, 4.04], + '2.width': [6.01, 4.64], + '2.x': [172.79, 175.57], + '2.y': [97.97, 75.64], + '3.height': [83.13, 64.18], + '3.width': [63.25, 48.83], + '3.x': [84.06, 107.07], + '3.y': [2.58, 1.99], + '4.height': [60.32, 46.57], + '4.width': [75.04, 57.94], + '4.x': [62.02, 90.05], + '4.y': [44.47, 34.33], + '5.height': [15.91, 12.28], + '5.width': [29.27, 22.6], + '5.x': [218.27, 210.68], + '5.y': [70.76, 54.63], + '6.height': [8.07, 6.23], + '6.width': [12.26, 9.47], + '6.x': [225.04, 215.91], + '6.y': [81.84, 63.18], + '7.height': [5.88, 4.54], + '7.width': [10.75, 8.3], + '7.x': [285.94, 262.93], + '7.y': [120.38, 92.94], + '8.height': [11.39, 8.79], + '8.width': [32.74, 25.28], + '8.x': [253.22, 237.67], + '8.y': [114.66, 88.52], + '9.height': [31.63, 24.42], + '9.width': [14.16, 10.94], + '9.x': [132.44, 144.42], + '9.y': [134.61, 103.92], + '10.height': [35.33, 27.27], + '10.width': [6.22, 4.8], + '10.x': [130.85, 143.19], + '10.y': [131.37, 101.43], + '11.height': [13.34, 10.3], + '11.width': [13.6, 10.5], + '11.x': [193.72, 191.73], + '11.y': [114.82, 88.65], + '12.height': [9.88, 7.63], + '12.width': [7.27, 5.61], + '12.x': [214.34, 207.65], + '12.y': [109.91, 84.86], + '13.height': [7.3, 5.64], + '13.width': [5.7, 4.4], + '13.x': [209.26, 203.73], + '13.y': [114.64, 88.51], + '14.height': [10.24, 7.91], + '14.width': [11.79, 9.11], + '14.x': [200.7, 197.12], + '14.y': [102.43, 79.08], + '15.height': [11.92, 9.2], + '15.width': [7.41, 5.72], + '15.x': [194.69, 192.48], + '15.y': [101.34, 78.24], + '16.height': [1.43, 1.1], + '16.width': [2.03, 1.57], + '16.x': [131.7, 143.85], + '16.y': [104.03, 80.32], + '17.height': [1.73, 1.33], + '17.width': [2.6, 2], + '17.x': [133.5, 145.24], + '17.y': [104.06, 80.34], + '18.height': [73.05, 56.4], + '18.width': [257.72, 198.97], + '18.x': [56.14, 85.51], + '18.y': [13.16, 10.16], + '19.height': [2.64, 2.04], + '19.width': [1.42, 1.09], + '19.x': [128.46, 141.35], + '19.y': [98.47, 76.02], + '20.height': [1.39, 1.07], + '20.width': [2.47, 1.91], + '20.x': [141.19, 151.18], + '20.y': [161.28, 124.52], + '21.height': [51.39, 39.67], + '21.width': [18.83, 14.54], + '21.x': [188.57, 187.76], + '21.y': [15.85, 12.24], + '22.height': [64.51, 49.81], + '22.width': [43.73, 33.76], + '22.x': [132.53, 144.49], + '23.height': [1.26, 0.97], + '23.width': [1.32, 1.02], + '23.x': [234.2, 222.98], + '23.y': [158.53, 122.39], + '24.height': [0.81, 0.63], + '24.width': [1.69, 1.31], + '24.x': [274.46, 254.07], + '24.y': [124.53, 96.14], + '25.height': [10.4, 8.03], + '25.width': [11.8, 9.11], + '25.x': [196.7, 194.03], + '25.y': [134.81, 104.08], + '26.height': [1.65, 1.27], + '26.width': [1.66, 1.29], + '26.x': [204.33, 199.92], + '26.y': [140.01, 108.09], + '27.height': [14.29, 11.03], + '27.width': [21.7, 16.76], + '27.x': [101.15, 120.26], + '27.y': [93.77, 72.4], + '28.height': [4.11, 3.18], + '28.width': [3.73, 2.88], + '28.x': [143.17, 152.71], + '28.y': [141.21, 109.02], + '29.height': [29.47, 22.75], + '29.width': [28.1, 21.7], + '29.x': [132.03, 144.11], + '29.y': [114.83, 88.65], + '30.height': [9.8, 7.57], + '30.width': [8.66, 6.68], + '30.x': [135.18, 146.54], + '30.y': [125.61, 96.98], + '31.height': [13.33, 10.29], + '31.width': [9.12, 7.04], + '31.x': [126.72, 140.01], + '31.y': [118.63, 91.59], + '32.height': [12.05, 9.31], + '32.width': [8.67, 6.7], + '32.x': [128.45, 141.34], + '32.y': [109.61, 84.63], + '33.height': [1.73, 1.34], + '33.width': [4.1, 3.16], + '33.x': [125.61, 139.15], + '33.y': [111.67, 86.22], + '34.height': [2.17, 1.68], + '34.width': [2.43, 1.88], + '34.x': [123.48, 137.5], + '34.y': [110.5, 85.31], + '35.height': [3.15, 2.43], + '35.width': [3.24, 2.5], + '35.x': [122.24, 136.54], + '35.y': [107.71, 83.16], + '36.height': [2.23, 1.72], + '36.width': [4.44, 3.43], + '36.x': [121.03, 135.61], + '36.y': [106.98, 82.59], + '37.height': [0.94, 0.73], + '37.width': [1.7, 1.31], + '37.x': [120.5, 135.2], + '37.y': [108.15, 83.5], + '38.height': [3.04, 2.35], + '38.width': [2.87, 2.21], + '38.x': [118.98, 134.03], + '38.y': [105.62, 81.54], + '39.height': [1.96, 1.51], + '39.width': [0.8, 0.62], + '39.x': [121.12, 135.68], + '39.y': [105.11, 81.15], + '40.height': [8.25, 6.37], + '40.width': [9.7, 7.49], + '40.x': [132.52, 144.48], + '40.y': [109.81, 84.78], + '41.height': [5.1, 3.94], + '41.width': [3.49, 2.69], + '41.x': [141.04, 151.06], + '41.y': [112.58, 86.91], + '42.height': [3.02, 2.33], + '42.width': [2.93, 2.26], + '42.x': [143.45, 152.92], + '42.y': [114.26, 88.22], + '43.height': [41.28, 31.87], + '43.width': [45.88, 35.42], + '43.x': [145.97, 154.86], + '43.y': [75.84, 58.55], + '44.height': [4.54, 3.51], + '44.width': [4.1, 3.17], + '44.x': [127.04, 140.25], + '44.y': [117.6, 90.79], + '45.height': [0.43, 0.33], + '45.width': [1.18, 0.91], + '45.x': [136.86, 147.83], + '45.y': [105.09, 81.13], + '46.height': [0.62, 0.48], + '46.width': [1.53, 1.18], + '46.x': [128.92, 141.7], + '46.y': [105.09, 81.13], + '47.height': [2.57, 1.98], + '47.width': [7.73, 5.97], + '47.x': [124.17, 138.04], + '47.y': [101.51, 78.37], + '48.height': [5.12, 3.95], + '48.width': [5.43, 4.19], + '48.x': [203.09, 198.96], + '48.y': [129.83, 100.23], + '49.height': [7.1, 5.48], + '49.width': [6.83, 5.27], + '49.x': [199.24, 196], + '49.y': [131.44, 101.47], + '50.height': [9.44, 7.29], + '50.width': [9.56, 7.38], + '50.x': [193.4, 191.49], + '50.y': [130.9, 101.06], + '51.height': [3.15, 2.44], + '51.width': [4.41, 3.4], + '51.x': [172.38, 175.26], + '51.y': [106.53, 82.25], + '52.height': [11.21, 8.65], + '52.width': [11.77, 9.09], + '52.x': [176.29, 178.27], + '52.y': [100.11, 77.29], + '53.height': [9.83, 7.59], + '53.width': [8.69, 6.71], + '53.x': [172.79, 175.57], + '53.y': [98.18, 75.8], + '54.height': [4.42, 3.41], + '54.width': [2.16, 1.67], + '54.x': [185.55, 185.43], + '54.y': [109.76, 84.74], + '55.height': [8.89, 6.86], + '55.width': [11.17, 8.63], + '55.x': [185.21, 185.16], + '55.y': [101.29, 78.2], + '56.height': [6.99, 5.39], + '56.width': [8.51, 6.57], + '56.x': [186.93, 186.49], + '56.y': [108.56, 83.81], + '57.height': [8.05, 6.21], + '57.width': [5.39, 4.16], + '57.x': [191.08, 189.69], + '57.y': [109.3, 84.39], + '58.height': [3.69, 2.85], + '58.width': [1.37, 1.06], + '58.y': [110.65, 85.43], + '59.height': [4.62, 3.57], + '59.width': [3.08, 2.38], + '59.x': [182.68, 183.21], + '59.y': [110.59, 85.38], + '60.height': [4.47, 3.45], + '60.width': [4.32, 3.34], + '60.x': [178.84, 180.25], + '60.y': [111.01, 85.7], + '61.height': [3.84, 2.96], + '61.width': [5.22, 4.03], + '61.x': [174.17, 176.64], + '61.y': [109.5, 84.54], + '62.height': [1.16, 0.9], + '62.width': [2.13, 1.65], + '62.x': [173.06, 175.78], + '62.y': [109.47, 84.52], + '63.height': [3.02, 2.33], + '63.width': [2.79, 2.15], + '63.x': [176.81, 178.68], + '63.y': [112.45, 86.82], + '64.height': [2.36, 1.82], + '64.width': [2.16, 1.67], + '64.x': [175.52, 177.68], + '64.y': [111.36, 85.97], + '65.height': [4.04, 3.12], + '65.width': [5.47, 4.23], + '65.x': [181.08, 181.98], + '65.y': [107.64, 83.1], + '66.height': [6.4, 4.94], + '66.width': [9.24, 7.14], + '66.x': [195.35, 192.99], + '66.y': [110.56, 85.36], + '67.height': [6.28, 4.85], + '67.width': [5.27, 4.07], + '67.x': [192.94, 191.13], + '67.y': [115.92, 89.49], + '68.height': [4.52, 3.49], + '68.width': [4.03, 3.11], + '68.x': [191.3, 189.86], + '68.y': [116.92, 90.27], + '69.height': [0.91, 0.7], + '69.width': [1.42, 1.09], + '69.x': [191.66, 190.14], + '69.y': [116.95, 90.29], + '70.height': [7.16, 5.52], + '70.width': [8.3, 6.41], + '70.x': [200.67, 197.1], + '70.y': [124.51, 96.12], + '71.height': [5.57, 4.3], + '71.width': [2.21, 1.71], + '71.x': [208.4, 203.07], + '71.y': [125.22, 96.68], + '72.height': [12.45, 9.61], + '72.width': [7.58, 5.86], + '72.x': [206.61, 201.68], + '72.y': [126.01, 97.29], + '73.height': [1.3, 1], + '73.width': [1, 0.77], + '73.x': [206.96, 201.96], + '73.y': [137.6, 106.24], + '74.height': [9.87, 7.62], + '74.width': [8.9, 6.87], + '74.x': [193.33, 191.43], + '74.y': [121.77, 94.01], + '75.height': [1.54, 1.19], + '75.width': [1.24, 0.96], + '75.x': [205.78, 201.04], + '75.y': [120.27, 92.85], + '76.height': [3.17, 2.45], + '76.width': [1.12, 0.87], + '76.x': [209.53, 203.94], + '76.y': [93.3, 72.03], + '77.height': [1.34, 1.04], + '77.width': [1.06, 0.82], + '77.x': [210.15, 204.41], + '77.y': [92.12, 71.12], + '78.height': [10.29, 7.94], + '78.width': [5.17, 3.99], + '78.x': [215.96, 208.91], + '78.y': [127.27, 98.26], + '79.height': [1, 0.77], + '79.width': [0.44, 0.34], + '79.x': [210, 204.3], + '79.y': [93.93, 72.52], + '80.height': [0.55, 0.42], + '80.width': [2.15, 1.66], + '80.x': [172.94, 175.69], + '80.y': [108.55, 83.81], + '81.height': [6.08, 4.69], + '81.width': [2.84, 2.19], + '81.x': [190.39, 189.16], + '81.y': [89.72, 69.27], + '82.height': [14.75, 11.39], + '82.width': [14.81, 11.43], + '82.x': [178.78, 180.2], + '82.y': [89.93, 69.43], + '83.height': [3.5, 2.71], + '83.width': [3.06, 2.36], + '83.x': [210, 204.3], + '83.y': [93.21, 71.96], + '84.height': [2.8, 2.16], + '84.width': [3.45, 2.66], + '84.x': [221.93, 213.51], + '84.y': [99.26, 76.63], + '85.height': [1.23, 0.95], + '85.width': [0.62, 0.48], + '85.x': [221.33, 213.05], + '85.y': [99.21, 76.59], + '86.height': [1.26, 0.97], + '86.width': [1.32, 1.02], + '86.x': [218.34, 210.74], + '86.y': [96.01, 74.12], + '87.height': [7.1, 5.49], + '87.width': [7, 5.4], + '87.x': [212.77, 206.44], + '87.y': [89.69, 69.25], + '88.height': [7.51, 5.8], + '88.width': [5.59, 4.32], + '88.x': [222.23, 213.74], + '88.y': [98.98, 76.42], + '89.height': [1.47, 1.13], + '89.width': [0.87, 0.67], + '89.x': [304.29, 277.1], + '89.y': [129.17, 99.73], + '90.height': [3, 2.31], + '90.width': [3.77, 2.91], + '90.x': [258.27, 241.57], + '90.y': [108.04, 83.41], + '91.height': [10.86, 8.38], + '91.width': [5.88, 4.54], + '91.x': [254.71, 238.82], + '91.y': [103.65, 80.02], + '92.height': [6.47, 5], + '92.width': [5.33, 4.12], + '92.x': [256.67, 240.33], + '92.y': [102.08, 78.81], + '93.height': [14.02, 10.82], + '93.width': [6.36, 4.91], + '93.x': [251.08, 236.02], + '93.y': [97.42, 75.21], + '94.height': [11.02, 8.51], + '94.width': [5.13, 3.96], + '94.x': [258.14, 241.47], + '94.y': [101.39, 78.27], + '95.height': [5, 3.86], + '95.width': [4.66, 3.6], + '95.x': [273.96, 253.68], + '95.y': [84.44, 65.19], + '96.height': [3.76, 2.9], + '96.width': [2.4, 1.85], + '96.x': [275.29, 254.71], + '96.y': [88.58, 68.39], + '97.height': [10.98, 8.48], + '97.width': [22.92, 17.7], + '97.x': [247.82, 233.5], + '97.y': [74.8, 57.75], + '98.height': [21.49, 16.59], + '98.width': [20.92, 16.15], + '98.x': [233.81, 222.68], + '98.y': [91.38, 70.55], + '99.height': [4.51, 3.49], + '99.width': [3.29, 2.54], + '99.x': [248.06, 233.68], + '99.y': [98.94, 76.39], + '100.height': [1.27, 0.98], + '100.width': [2.36, 1.82], + '100.x': [248.58, 234.09], + '100.y': [97.45, 75.24], + '101.height': [3.28, 2.53], + '101.width': [5.79, 4.47], + '101.x': [242.33, 229.26], + '101.y': [95.71, 73.89], + '102.height': [11.2, 8.65], + '102.width': [12.14, 9.38], + '102.x': [228.58, 218.65], + '102.y': [89.92, 69.42], + '103.height': [7.92, 6.12], + '103.width': [10.47, 8.09], + '103.x': [228.33, 218.45], + '103.y': [88.69, 68.48], + '104.height': [3.88, 3], + '104.width': [5.4, 4.17], + '104.x': [233.28, 222.27], + '104.y': [86.39, 66.7], + '105.height': [3.83, 2.96], + '105.width': [7.73, 5.97], + '105.x': [234.73, 223.39], + '105.y': [84.13, 64.95], + '106.height': [6.9, 5.33], + '106.width': [10.05, 7.76], + '106.x': [222.59, 214.02], + '106.y': [84.67, 65.37], + '107.height': [12.47, 9.63], + '107.width': [13.75, 10.62], + '107.x': [216.58, 209.38], + '107.y': [87.56, 67.6], + '108.height': [4.29, 3.31], + '108.width': [4.76, 3.68], + '108.x': [210.56, 204.73], + '108.y': [89.83, 69.35], + '109.height': [2.34, 1.81], + '109.width': [2.09, 1.62], + '109.x': [216.2, 209.09], + '109.y': [86.12, 66.49], + '110.height': [21.55, 16.64], + '110.width': [9.22, 7.12], + '110.x': [192.9, 191.1], + '110.y': [49.24, 38.01], + '111.height': [5.88, 4.54], + '111.width': [6.8, 5.25], + '111.x': [201.61, 197.82], + '111.y': [69.76, 53.86], + '112.height': [7.67, 5.92], + '112.width': [12.88, 9.95], + '112.x': [200.81, 197.21], + '112.y': [74.47, 57.49], + '113.height': [6.78, 5.23], + '113.width': [7.13, 5.5], + '113.x': [195.08, 192.78], + '113.y': [71.43, 55.15], + '114.height': [2.78, 2.14], + '114.width': [5.37, 4.14], + '114.x': [191.79, 190.24], + '114.y': [78.19, 60.37], + '115.height': [3.02, 2.33], + '115.width': [4.66, 3.6], + '115.x': [196.6, 193.95], + '115.y': [78.64, 60.71], + '116.height': [3.13, 2.41], + '116.width': [2.44, 1.88], + '116.x': [204.06, 199.71], + '116.y': [78.81, 60.85], + '117.height': [4.67, 3.61], + '117.width': [6.73, 5.2], + '117.x': [199.48, 196.18], + '117.y': [79.08, 61.05], + '118.height': [3.09, 2.39], + '118.width': [3.96, 3.06], + '118.x': [200.07, 196.64], + '118.y': [69.5, 53.66], + '119.height': [3.08, 2.38], + '119.width': [5.1, 3.94], + '119.x': [200.07, 196.64], + '119.y': [67.39, 52.03], + '120.height': [2.93, 2.26], + '120.width': [3.43, 2.65], + '120.x': [201.71, 197.9], + '120.y': [65.12, 50.28], + '121.height': [8.79, 6.79], + '121.width': [6.46, 4.99], + '121.x': [189.29, 188.31], + '121.y': [71.26, 55.02], + '122.height': [2.93, 2.26], + '122.width': [4.42, 3.41], + '122.x': [201.02, 197.37], + '122.y': [83.2, 64.24], + '123.height': [6.32, 4.88], + '123.width': [4.62, 3.57], + '123.x': [199.43, 196.14], + '123.y': [85.56, 66.06], + '124.height': [5.83, 4.5], + '124.width': [13.42, 10.36], + '124.x': [203.64, 199.39], + '124.y': [85.26, 65.82], + '125.height': [2.91, 2.25], + '125.width': [1.23, 0.95], + '125.x': [198.82, 195.67], + '125.y': [84.73, 65.42], + '126.height': [4.04, 3.12], + '126.width': [4.11, 3.17], + '126.x': [194.78, 192.55], + '126.y': [80.89, 62.45], + '127.height': [2.15, 1.66], + '127.width': [3.16, 2.44], + '127.x': [189.31, 188.33], + '127.y': [79.49, 61.37], + '128.height': [0.76, 0.59], + '128.width': [0.41, 0.31], + '128.x': [189.06, 188.14], + '128.y': [76.99, 59.44], + '129.height': [2.19, 1.69], + '129.width': [2.61, 2.01], + '129.x': [186.8, 186.39], + '129.y': [75.46, 58.26], + '130.height': [3.16, 2.44], + '130.width': [2.7, 2.09], + '130.x': [187.37, 186.83], + '130.y': [73.07, 56.41], + '131.height': [5.06, 3.9], + '131.width': [2.25, 1.74], + '131.x': [178.18, 179.73], + '131.y': [85.13, 65.72], + '132.height': [7.29, 5.63], + '132.width': [8.9, 6.87], + '132.x': [178.27, 179.81], + '132.y': [83.69, 64.61], + '133.height': [4.16, 3.21], + '133.width': [2.82, 2.18], + '133.x': [177.86, 179.49], + '133.y': [71.08, 54.88], + '134.height': [1.76, 1.36], + '134.width': [2.21, 1.71], + '134.x': [302.43, 275.66], + '134.y': [133.28, 102.9], + '135.height': [3.06, 2.36], + '135.width': [4.23, 3.27], + '135.x': [297.03, 271.49], + '135.y': [123.32, 95.21], + '136.height': [11.54, 8.91], + '136.width': [8.6, 6.64], + '136.x': [304.2, 277.03], + '136.y': [144.89, 111.86], + '137.height': [27.1, 20.93], + '137.width': [28.8, 22.24], + '137.x': [266.14, 247.64], + '137.y': [126.27, 97.48], + '138.height': [2.79, 2.15], + '138.width': [1.5, 1.16], + '138.x': [242.05, 229.05], + '138.y': [111.52, 86.1], + '139.height': [32.2, 24.86], + '139.width': [43.92, 33.91], + '139.x': [237.74, 225.72], + '139.y': [73.13, 56.46], + '140.height': [2.6, 2.01], + '140.width': [1.32, 1.02], + '140.x': [270.98, 251.38], + '140.y': [99.86, 77.1], + '141.height': [10.13, 7.82], + '141.width': [8.4, 6.48], + '141.x': [189.83, 188.73], + '141.y': [80.25, 61.96], + '142.height': [3.78, 2.92], + '142.width': [3.29, 2.54], + '142.x': [190.79, 189.47], + '142.y': [67.71, 52.28], + '143.height': [10.69, 8.25], + '143.width': [6.63, 5.12], + '143.x': [179.58, 180.81], + '143.y': [66.48, 51.33], + '144.height': [5.14, 3.97], + '144.width': [7.67, 5.92], + '144.x': [167.58, 171.55], + '144.y': [54.13, 41.79], + '145.height': [3.36, 2.59], + '145.width': [4.01, 3.09], + '145.x': [217.07, 209.76], + '145.y': [85.53, 66.03], + '146.height': [2.41, 1.86], + '146.width': [4.78, 3.69], + '146.x': [213.6, 207.08], + '146.y': [83.88, 64.76], + '147.height': [9.48, 7.32], + '147.width': [6.7, 5.17], + '147.x': [268.88, 249.76], + '147.y': [105.1, 81.14], + '148.height': [4.42, 3.41], + '148.width': [13.67, 10.55], + '148.x': [256.65, 240.32], + '148.y': [113.61, 87.72], + '149.height': [1.03, 0.8], + '149.width': [0.89, 0.69], + '149.x': [266.76, 248.12], + '149.y': [114.68, 88.54], + '150.height': [1.45, 1.12], + '150.width': [2.05, 1.59], + '150.x': [194.81, 192.57], + '150.y': [80.53, 62.17], + '151.height': [17.73, 13.69], + '151.width': [7.78, 6.01], + '151.x': [199.78, 196.41], + '151.y': [47.06, 36.33], + '152.height': [1.97, 1.52], + '152.width': [4.07, 3.14], + '152.x': [197.08, 194.33], + '152.y': [77.61, 59.91], + '153.height': [2.85, 2.2], + '153.width': [4.73, 3.66], + '153.x': [193.76, 191.76], + '153.y': [75.87, 58.58], + '154.height': [4.11, 3.18], + '154.width': [4.84, 3.73], + '154.x': [211, 205.08], + '154.y': [105.49, 81.44], + '155.height': [13.32, 10.29], + '155.width': [11.55, 8.92], + '155.x': [277.64, 256.52], + '155.y': [81.87, 63.21], + '156.height': [6.41, 4.95], + '156.width': [6.01, 4.64], + '156.x': [140.12, 150.35], + '156.y': [132.7, 102.45], + '157.height': [4.77, 3.69], + '157.width': [7.52, 5.81], + '157.x': [215.5, 208.55], + '157.y': [104.73, 80.86], + '158.height': [12.47, 9.63], + '158.width': [15.06, 11.63], + '158.x': [209.79, 204.14], + '158.y': [94.25, 72.76], + '159.height': [69.91, 53.97], + '159.width': [257.72, 198.97], + '159.x': [56.14, 85.51], + '159.y': [177.54, 137.07], + '160.height': [0.59, 0.45], + '160.width': [1.32, 1.02], + '160.x': [208.43, 203.09], + '160.y': [91.22, 70.43], + '161.height': [0.53, 0.41], + '161.width': [1.25, 0.97], + '161.x': [208.09, 202.83], + '161.y': [91.66, 70.76], + '162.height': [11.74, 9.06], + '162.width': [11.38, 8.78], + '162.x': [172.82, 175.59], + '162.y': [91.14, 70.37], + '163.height': [7.7, 5.95], + '163.width': [8.71, 6.72], + '163.x': [202.68, 198.65], + '163.y': [94.73, 73.14], + '164.height': [10.87, 8.39], + '164.width': [11.34, 8.76], + '164.x': [191.67, 190.15], + '164.y': [93.42, 72.12], + '165.height': [8.38, 6.47], + '165.width': [10.62, 8.2], + '165.x': [208.59, 203.21], + '165.y': [107.75, 83.19], + '166.height': [1.3, 1], + '166.width': [1.19, 0.92], + '166.x': [214.82, 208.03], + '166.y': [109.42, 84.48], + '167.height': [2.52, 1.94], + '167.width': [4.57, 3.53], + '167.x': [215.47, 208.52], + '167.y': [110.33, 85.18], + '168.height': [4.08, 3.15], + '168.width': [3.91, 3.02], + '168.x': [206.18, 201.35], + '168.y': [115.54, 89.2], + '169.height': [1.28, 0.99], + '169.width': [1.28, 0.99], + '169.x': [205.78, 201.04], + '169.y': [119.4, 92.18], + '170.height': [2.57, 1.98], + '170.width': [2.76, 2.13], + '170.x': [196.27, 193.7], + '170.y': [82.2, 63.46], + '171.height': [1.41, 1.09], + '171.width': [1.78, 1.37], + '171.x': [199.65, 196.31], + '171.y': [85.09, 65.69], + '172.height': [3.92, 3.03], + '172.width': [2.97, 2.3], + '172.x': [198.48, 195.41], + '172.y': [81.24, 62.72], + '173.height': [1.6, 1.24], + '173.width': [1.35, 1.04], + '173.x': [198.21, 195.2], + '173.y': [83.91, 64.78], + '174.height': [1.39, 1.07], + '174.width': [1.22, 0.94], + '174.x': [199.37, 196.09], + '174.y': [84.16, 64.97], + '175.height': [0.65, 0.5], + '175.width': [0.76, 0.58], + '175.x': [140.65, 150.76], + '175.y': [110.74, 85.5], + '176.height': [6.32, 4.88], + '176.width': [8.17, 6.31], + '176.x': [202.1, 198.2], + '176.y': [109.75, 84.73], + }, + legend: { + 'continuousLegend.bounds.height': [61, 99], + 'continuousLegend.bar.y': [111.3, 126.3], + }, + }, + style: { + 'legends.continuousLegend.title': ['gdp ($)', 'gdp'], + }, + }, + '../gallery/maps.stories.tsx.worldMercatorSpec @1280': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [162, 124], + }, + area: { + 'rect.height': [162, 124], + 'rect.y': [153.2, 191.2], + }, + marks: { + '0.height': [1.65, 1.26], + '0.width': [250.45, 191.71], + '0.x': [494.77, 524.15], + '0.y': [126.54, 96.86], + '1.height': [7.55, 5.78], + '1.width': [7.64, 5.85], + '1.x': [640.41, 635.62], + '1.y': [115.9, 88.72], + '2.height': [5.09, 3.89], + '2.width': [5.84, 4.47], + '2.x': [608.13, 610.91], + '2.y': [95.21, 72.88], + '3.height': [80.79, 61.84], + '3.width': [61.46, 47.05], + '3.x': [521.91, 544.92], + '3.y': [2.51, 1.92], + '4.height': [58.62, 44.87], + '4.width': [72.93, 55.82], + '4.x': [500.48, 528.52], + '4.y': [43.21, 33.08], + '5.height': [15.46, 11.84], + '5.width': [28.45, 21.78], + '5.x': [652.33, 644.74], + '5.y': [68.77, 52.64], + '6.height': [7.84, 6], + '6.width': [11.91, 9.12], + '6.x': [658.91, 649.78], + '6.y': [79.53, 60.88], + '7.height': [5.71, 4.37], + '7.width': [10.45, 8], + '7.x': [718.1, 695.09], + '7.y': [116.98, 89.54], + '8.height': [11.06, 8.47], + '8.width': [31.82, 24.36], + '8.x': [686.3, 670.75], + '8.y': [111.43, 85.29], + '9.height': [30.74, 23.53], + '9.width': [13.77, 10.54], + '9.x': [568.93, 580.91], + '9.y': [130.81, 100.13], + '10.height': [34.33, 26.28], + '10.width': [6.04, 4.63], + '10.x': [567.37, 579.72], + '10.y': [127.67, 97.72], + '11.height': [12.97, 9.93], + '11.width': [13.21, 10.11], + '11.x': [628.47, 626.49], + '11.y': [111.58, 85.41], + '12.height': [9.6, 7.35], + '12.width': [7.06, 5.41], + '12.x': [648.51, 641.82], + '12.y': [106.82, 81.76], + '13.height': [7.09, 5.43], + '13.width': [5.54, 4.24], + '13.x': [643.58, 638.05], + '13.y': [111.41, 85.27], + '14.height': [9.95, 7.62], + '14.width': [11.46, 8.77], + '14.x': [635.26, 631.68], + '14.y': [99.55, 76.2], + '15.height': [11.58, 8.86], + '15.width': [7.2, 5.51], + '15.x': [629.42, 627.21], + '15.y': [98.48, 75.38], + '16.height': [1.39, 1.06], + '16.width': [1.97, 1.51], + '16.x': [568.2, 580.35], + '16.y': [101.1, 77.39], + '17.height': [1.68, 1.29], + '17.width': [2.52, 1.93], + '17.x': [569.95, 581.69], + '17.y': [101.12, 77.4], + '18.height': [70.99, 54.34], + '18.width': [250.45, 191.71], + '18.x': [494.77, 524.15], + '18.y': [12.78, 9.79], + '19.height': [2.56, 1.96], + '19.width': [1.38, 1.05], + '19.x': [565.05, 577.94], + '19.y': [95.69, 73.25], + '20.height': [1.35, 1.03], + '20.width': [2.4, 1.84], + '20.x': [577.42, 587.41], + '20.y': [156.73, 119.97], + '21.height': [49.94, 38.23], + '21.width': [18.3, 14.01], + '21.x': [623.47, 622.66], + '21.y': [15.41, 11.79], + '22.height': [62.7, 47.99], + '22.width': [42.5, 32.53], + '22.x': [569.01, 580.97], + '23.height': [1.22, 0.94], + '23.width': [1.28, 0.98], + '23.x': [667.81, 656.59], + '23.y': [154.06, 117.92], + '24.height': [0.79, 0.6], + '24.width': [1.65, 1.26], + '24.x': [706.94, 686.55], + '24.y': [121.02, 92.63], + '25.height': [10.1, 7.73], + '25.width': [11.47, 8.78], + '25.x': [631.37, 628.7], + '25.y': [131.01, 100.28], + '26.height': [1.6, 1.22], + '26.width': [1.62, 1.24], + '26.x': [638.78, 634.38], + '26.y': [136.06, 104.14], + '27.height': [13.89, 10.63], + '27.width': [21.09, 16.14], + '27.x': [538.51, 557.63], + '27.y': [91.13, 69.75], + '28.height': [4, 3.06], + '28.width': [3.63, 2.78], + '28.x': [579.35, 588.89], + '28.y': [137.23, 105.04], + '29.height': [28.64, 21.92], + '29.width': [27.31, 20.9], + '29.x': [568.53, 580.6], + '29.y': [111.59, 85.41], + '30.height': [9.53, 7.29], + '30.width': [8.41, 6.44], + '30.x': [571.59, 582.94], + '30.y': [122.07, 93.43], + '31.height': [12.95, 9.91], + '31.width': [8.87, 6.79], + '31.x': [563.36, 576.65], + '31.y': [115.28, 88.24], + '32.height': [11.71, 8.97], + '32.width': [8.43, 6.45], + '32.x': [565.05, 577.94], + '32.y': [106.52, 81.54], + '33.height': [1.68, 1.29], + '33.width': [3.98, 3.05], + '33.x': [562.28, 575.82], + '33.y': [108.53, 83.07], + '34.height': [2.11, 1.62], + '34.width': [2.36, 1.81], + '34.x': [560.21, 574.23], + '34.y': [107.39, 82.2], + '35.height': [3.06, 2.34], + '35.width': [3.15, 2.41], + '35.x': [559.01, 573.31], + '35.y': [104.67, 80.12], + '36.height': [2.17, 1.66], + '36.width': [4.32, 3.31], + '36.x': [557.84, 572.42], + '36.y': [103.96, 79.57], + '37.height': [0.91, 0.7], + '37.width': [1.65, 1.26], + '37.x': [557.32, 572.02], + '37.y': [105.1, 80.45], + '38.height': [2.95, 2.26], + '38.width': [2.79, 2.13], + '38.x': [555.84, 570.89], + '38.y': [102.64, 78.56], + '39.height': [1.9, 1.46], + '39.width': [0.78, 0.6], + '39.x': [557.92, 572.48], + '39.y': [102.14, 78.18], + '40.height': [8.02, 6.14], + '40.width': [9.42, 7.21], + '40.x': [569, 580.96], + '40.y': [106.72, 81.69], + '41.height': [4.96, 3.8], + '41.width': [3.39, 2.59], + '41.x': [577.28, 587.3], + '41.y': [109.4, 83.74], + '42.height': [2.93, 2.25], + '42.width': [2.84, 2.18], + '42.x': [579.62, 589.09], + '42.y': [111.04, 85], + '43.height': [40.12, 30.71], + '43.width': [44.58, 34.13], + '43.x': [582.07, 590.96], + '43.y': [73.7, 56.41], + '44.height': [4.42, 3.38], + '44.width': [3.99, 3.05], + '44.x': [563.67, 576.88], + '44.y': [114.28, 87.48], + '45.height': [0.42, 0.32], + '45.width': [1.15, 0.88], + '45.x': [573.22, 584.19], + '45.y': [102.13, 78.17], + '46.height': [0.6, 0.46], + '46.width': [1.49, 1.14], + '46.x': [565.5, 578.28], + '46.y': [102.13, 78.17], + '47.height': [2.49, 1.91], + '47.width': [7.51, 5.75], + '47.x': [560.88, 574.75], + '47.y': [98.65, 75.51], + '48.height': [4.98, 3.81], + '48.width': [5.28, 4.04], + '48.x': [637.58, 633.45], + '48.y': [126.17, 96.57], + '49.height': [6.9, 5.28], + '49.width': [6.63, 5.08], + '49.x': [633.84, 630.59], + '49.y': [127.73, 97.77], + '50.height': [9.17, 7.02], + '50.width': [9.29, 7.11], + '50.x': [628.16, 626.25], + '50.y': [127.21, 97.37], + '51.height': [3.07, 2.35], + '51.width': [4.28, 3.28], + '51.x': [607.74, 610.61], + '51.y': [103.53, 79.25], + '52.height': [10.89, 8.34], + '52.width': [11.44, 8.76], + '52.x': [611.53, 613.52], + '52.y': [97.29, 74.47], + '53.height': [9.55, 7.31], + '53.width': [8.45, 6.46], + '53.x': [608.13, 610.91], + '53.y': [95.41, 73.03], + '54.height': [4.3, 3.29], + '54.width': [2.1, 1.61], + '54.x': [620.54, 620.41], + '54.y': [106.67, 81.64], + '55.height': [8.64, 6.61], + '55.width': [10.86, 8.31], + '55.x': [620.21, 620.16], + '55.y': [98.44, 75.35], + '56.height': [6.79, 5.2], + '56.width': [8.27, 6.33], + '56.x': [621.87, 621.43], + '56.y': [105.5, 80.75], + '57.height': [7.82, 5.99], + '57.width': [5.23, 4.01], + '57.x': [625.9, 624.52], + '57.y': [106.22, 81.31], + '58.height': [3.58, 2.74], + '58.width': [1.33, 1.02], + '58.y': [107.53, 82.31], + '59.height': [4.49, 3.44], + '59.width': [3, 2.29], + '59.x': [617.74, 618.27], + '59.y': [107.47, 82.26], + '60.height': [4.34, 3.32], + '60.width': [4.2, 3.22], + '60.x': [614.02, 615.42], + '60.y': [107.88, 82.57], + '61.height': [3.73, 2.85], + '61.width': [5.08, 3.89], + '61.x': [609.47, 611.94], + '61.y': [106.42, 81.45], + '62.height': [1.13, 0.86], + '62.width': [2.07, 1.59], + '62.x': [608.4, 611.12], + '62.y': [106.39, 81.43], + '63.height': [2.93, 2.24], + '63.width': [2.71, 2.08], + '63.x': [612.04, 613.91], + '63.y': [109.28, 83.65], + '64.height': [2.29, 1.76], + '64.width': [2.1, 1.61], + '64.x': [610.78, 612.95], + '64.y': [108.22, 82.83], + '65.height': [3.92, 3], + '65.width': [5.32, 4.07], + '65.x': [616.19, 617.09], + '65.y': [104.6, 80.07], + '66.height': [6.22, 4.76], + '66.width': [8.98, 6.88], + '66.x': [630.06, 627.7], + '66.y': [107.44, 82.24], + '67.height': [6.1, 4.67], + '67.width': [5.12, 3.92], + '67.x': [627.72, 625.91], + '67.y': [112.65, 86.22], + '68.height': [4.39, 3.36], + '68.width': [3.92, 3], + '68.x': [626.12, 624.68], + '68.y': [113.62, 86.97], + '69.height': [0.89, 0.68], + '69.width': [1.38, 1.05], + '69.x': [626.47, 624.95], + '69.y': [113.65, 86.99], + '70.height': [6.95, 5.32], + '70.width': [8.07, 6.18], + '70.x': [635.23, 631.65], + '70.y': [120.99, 92.61], + '71.height': [5.41, 4.14], + '71.width': [2.15, 1.64], + '71.x': [642.74, 637.41], + '71.y': [121.69, 93.15], + '72.height': [12.1, 9.26], + '72.width': [7.37, 5.64], + '72.x': [641, 636.07], + '72.y': [122.46, 93.73], + '73.height': [1.26, 0.97], + '73.width': [0.97, 0.74], + '73.x': [641.34, 636.34], + '73.y': [133.72, 102.36], + '74.height': [9.59, 7.34], + '74.width': [8.65, 6.62], + '74.x': [628.1, 626.2], + '74.y': [118.33, 90.58], + '75.height': [1.5, 1.15], + '75.width': [1.2, 0.92], + '75.x': [640.19, 635.46], + '75.y': [116.88, 89.46], + '76.height': [3.08, 2.36], + '76.width': [1.09, 0.84], + '76.x': [643.84, 638.25], + '76.y': [90.67, 69.4], + '77.height': [1.3, 1], + '77.width': [1.03, 0.79], + '77.x': [644.44, 638.71], + '77.y': [89.52, 68.52], + '78.height': [10, 7.65], + '78.width': [5.03, 3.85], + '78.x': [650.09, 643.03], + '78.y': [123.68, 94.67], + '79.height': [0.97, 0.74], + '79.width': [0.43, 0.33], + '79.x': [644.3, 638.6], + '79.y': [91.29, 69.87], + '80.height': [0.53, 0.41], + '80.width': [2.09, 1.6], + '80.x': [608.28, 611.03], + '80.y': [105.49, 80.75], + '81.height': [5.91, 4.52], + '81.width': [2.76, 2.11], + '81.x': [625.24, 624.01], + '81.y': [87.19, 66.74], + '82.height': [14.34, 10.97], + '82.width': [14.39, 11.02], + '82.x': [613.96, 615.38], + '82.y': [87.4, 66.9], + '83.height': [3.41, 2.61], + '83.width': [2.97, 2.28], + '83.x': [644.3, 638.6], + '83.y': [90.58, 69.34], + '84.height': [2.72, 2.08], + '84.width': [3.35, 2.57], + '84.x': [655.88, 647.47], + '84.y': [96.46, 73.83], + '85.height': [1.2, 0.92], + '85.width': [0.6, 0.46], + '85.x': [655.3, 647.02], + '85.y': [96.41, 73.8], + '86.height': [1.22, 0.94], + '86.width': [1.28, 0.98], + '86.x': [652.4, 644.8], + '86.y': [93.3, 71.41], + '87.height': [6.9, 5.28], + '87.width': [6.8, 5.2], + '87.x': [646.99, 640.66], + '87.y': [87.16, 66.72], + '88.height': [7.3, 5.59], + '88.width': [5.43, 4.16], + '88.x': [656.18, 647.69], + '88.y': [96.19, 73.63], + '89.height': [1.42, 1.09], + '89.width': [0.85, 0.65], + '89.x': [735.93, 708.73], + '89.y': [125.53, 96.09], + '90.height': [2.91, 2.23], + '90.width': [3.66, 2.8], + '90.x': [691.2, 674.5], + '90.y': [105, 80.37], + '91.height': [10.55, 8.08], + '91.width': [5.71, 4.37], + '91.x': [687.74, 671.85], + '91.y': [100.73, 77.1], + '92.height': [6.29, 4.82], + '92.width': [5.18, 3.97], + '92.x': [689.65, 673.31], + '92.y': [99.2, 75.93], + '93.height': [13.62, 10.43], + '93.width': [6.18, 4.73], + '93.x': [684.22, 669.15], + '93.y': [94.67, 72.47], + '94.height': [10.71, 8.2], + '94.width': [4.98, 3.81], + '94.x': [691.08, 674.41], + '94.y': [98.53, 75.42], + '95.height': [4.86, 3.72], + '95.width': [4.53, 3.47], + '95.x': [706.45, 686.17], + '95.y': [82.06, 62.81], + '96.height': [3.66, 2.8], + '96.width': [2.33, 1.78], + '96.x': [707.74, 687.16], + '96.y': [86.08, 65.89], + '97.height': [10.67, 8.17], + '97.width': [22.28, 17.05], + '97.x': [681.05, 666.73], + '97.y': [72.69, 55.64], + '98.height': [20.88, 15.98], + '98.width': [20.33, 15.56], + '98.x': [667.43, 656.3], + '98.y': [88.8, 67.97], + '99.height': [4.39, 3.36], + '99.width': [3.19, 2.44], + '99.x': [681.28, 666.91], + '99.y': [96.15, 73.6], + '100.height': [1.24, 0.95], + '100.width': [2.29, 1.75], + '100.x': [681.79, 667.3], + '100.y': [94.7, 72.49], + '101.height': [3.18, 2.44], + '101.width': [5.63, 4.31], + '101.x': [675.72, 662.65], + '101.y': [93.01, 71.19], + '102.height': [10.89, 8.33], + '102.width': [11.8, 9.03], + '102.x': [662.35, 652.42], + '102.y': [87.38, 66.89], + '103.height': [7.7, 5.89], + '103.width': [10.18, 7.79], + '103.x': [662.11, 652.23], + '103.y': [86.19, 65.97], + '104.height': [3.77, 2.89], + '104.width': [5.24, 4.01], + '104.x': [666.92, 655.91], + '104.y': [83.95, 64.26], + '105.height': [3.72, 2.85], + '105.width': [7.51, 5.75], + '105.x': [668.33, 656.99], + '105.y': [81.76, 62.58], + '106.height': [6.71, 5.14], + '106.width': [9.77, 7.48], + '106.x': [656.53, 647.96], + '106.y': [82.28, 62.98], + '107.height': [12.12, 9.28], + '107.width': [13.36, 10.23], + '107.x': [650.69, 643.49], + '107.y': [85.09, 65.13], + '108.height': [4.17, 3.19], + '108.width': [4.63, 3.54], + '108.x': [644.84, 639.01], + '108.y': [87.3, 66.82], + '109.height': [2.28, 1.74], + '109.width': [2.03, 1.56], + '109.x': [650.32, 643.21], + '109.y': [83.69, 64.06], + '110.height': [20.94, 16.03], + '110.width': [8.96, 6.86], + '110.x': [627.67, 625.87], + '110.y': [47.85, 36.62], + '111.height': [5.71, 4.37], + '111.width': [6.6, 5.06], + '111.x': [636.14, 632.35], + '111.y': [67.79, 51.89], + '112.height': [7.46, 5.71], + '112.width': [12.52, 9.58], + '112.x': [635.36, 631.76], + '112.y': [72.37, 55.39], + '113.height': [6.58, 5.04], + '113.width': [6.93, 5.3], + '113.x': [629.79, 627.49], + '113.y': [69.41, 53.13], + '114.height': [2.7, 2.06], + '114.width': [5.22, 3.99], + '114.x': [626.6, 625.05], + '114.y': [75.99, 58.16], + '115.height': [2.93, 2.25], + '115.width': [4.53, 3.47], + '115.x': [631.27, 628.63], + '115.y': [76.42, 58.5], + '116.height': [3.04, 2.33], + '116.width': [2.37, 1.81], + '116.x': [638.52, 634.18], + '116.y': [76.59, 58.62], + '117.height': [4.54, 3.47], + '117.width': [6.54, 5.01], + '117.x': [634.07, 630.77], + '117.y': [76.85, 58.82], + '118.height': [3, 2.3], + '118.width': [3.85, 2.95], + '118.x': [634.65, 631.21], + '118.y': [67.54, 51.7], + '119.height': [2.99, 2.29], + '119.width': [4.95, 3.79], + '119.x': [634.65, 631.21], + '119.y': [65.49, 50.13], + '120.height': [2.85, 2.18], + '120.width': [3.33, 2.55], + '120.x': [636.24, 632.43], + '120.y': [63.29, 48.44], + '121.height': [8.54, 6.54], + '121.width': [6.28, 4.81], + '121.x': [624.17, 623.19], + '121.y': [69.25, 53.01], + '122.height': [2.84, 2.18], + '122.width': [4.3, 3.29], + '122.x': [635.57, 631.92], + '122.y': [80.86, 61.89], + '123.height': [6.14, 4.7], + '123.width': [4.49, 3.44], + '123.x': [634.02, 630.73], + '123.y': [83.15, 63.65], + '124.height': [5.66, 4.33], + '124.width': [13.04, 9.98], + '124.x': [638.12, 633.87], + '124.y': [82.86, 63.42], + '125.height': [2.83, 2.17], + '125.width': [1.19, 0.91], + '125.x': [633.43, 630.28], + '125.y': [82.34, 63.03], + '126.height': [3.93, 3.01], + '126.width': [3.99, 3.05], + '126.x': [629.5, 627.27], + '126.y': [78.61, 60.17], + '127.height': [2.09, 1.6], + '127.width': [3.08, 2.35], + '127.x': [624.19, 623.21], + '127.y': [77.25, 59.13], + '128.height': [0.74, 0.57], + '128.width': [0.4, 0.3], + '128.x': [623.95, 623.02], + '128.y': [74.82, 57.27], + '129.height': [2.13, 1.63], + '129.width': [2.53, 1.94], + '129.x': [621.75, 621.34], + '129.y': [73.34, 56.13], + '130.height': [3.07, 2.35], + '130.width': [2.63, 2.01], + '130.x': [622.31, 621.76], + '130.y': [71.01, 54.35], + '131.height': [4.91, 3.76], + '131.width': [2.18, 1.67], + '131.x': [613.37, 614.93], + '131.y': [82.73, 63.32], + '132.height': [7.08, 5.42], + '132.width': [8.65, 6.62], + '132.x': [613.46, 615], + '132.y': [81.33, 62.25], + '133.height': [4.04, 3.1], + '133.width': [2.75, 2.1], + '133.x': [613.06, 614.69], + '133.y': [69.07, 52.87], + '134.height': [1.71, 1.31], + '134.width': [2.15, 1.64], + '134.x': [734.12, 707.35], + '134.y': [129.53, 99.14], + '135.height': [2.98, 2.28], + '135.width': [4.11, 3.15], + '135.x': [728.87, 703.33], + '135.y': [119.84, 91.73], + '136.height': [11.21, 8.58], + '136.width': [8.35, 6.39], + '136.x': [735.84, 708.67], + '136.y': [140.8, 107.77], + '137.height': [26.34, 20.16], + '137.width': [27.99, 21.42], + '137.x': [698.85, 680.35], + '137.y': [122.71, 93.92], + '138.height': [2.71, 2.07], + '138.width': [1.46, 1.11], + '138.x': [675.44, 662.44], + '138.y': [108.37, 82.95], + '139.height': [31.3, 23.95], + '139.width': [42.68, 32.67], + '139.x': [671.26, 659.23], + '139.y': [71.07, 54.4], + '140.height': [2.53, 1.93], + '140.width': [1.28, 0.98], + '140.x': [703.56, 683.96], + '140.y': [97.04, 74.28], + '141.height': [9.84, 7.53], + '141.width': [8.16, 6.25], + '141.x': [624.69, 623.59], + '141.y': [77.99, 59.7], + '142.height': [3.67, 2.81], + '142.width': [3.2, 2.45], + '142.x': [625.63, 624.31], + '142.y': [65.8, 50.37], + '143.height': [10.39, 7.95], + '143.width': [6.44, 4.93], + '143.x': [614.73, 615.97], + '143.y': [64.61, 49.45], + '144.height': [5, 3.82], + '144.width': [7.46, 5.71], + '144.x': [603.08, 607.05], + '144.y': [52.61, 40.27], + '145.height': [3.26, 2.5], + '145.width': [3.89, 2.98], + '145.x': [651.16, 643.85], + '145.y': [83.12, 63.62], + '146.height': [2.34, 1.79], + '146.width': [4.65, 3.56], + '146.x': [647.8, 641.28], + '146.y': [81.52, 62.4], + '147.height': [9.22, 7.05], + '147.width': [6.51, 4.98], + '147.x': [701.52, 682.4], + '147.y': [102.14, 78.18], + '148.height': [4.29, 3.29], + '148.width': [13.28, 10.17], + '148.x': [689.63, 673.3], + '148.y': [110.41, 84.51], + '149.height': [1.01, 0.77], + '149.width': [0.87, 0.66], + '149.x': [699.45, 680.82], + '149.y': [111.45, 85.31], + '150.height': [1.41, 1.08], + '150.width': [2, 1.53], + '150.x': [629.53, 627.29], + '150.y': [78.26, 59.9], + '151.height': [17.23, 13.19], + '151.width': [7.56, 5.79], + '151.x': [634.36, 630.99], + '151.y': [45.73, 35.01], + '152.height': [1.91, 1.46], + '152.width': [3.95, 3.03], + '152.x': [631.74, 628.99], + '152.y': [75.42, 57.73], + '153.height': [2.76, 2.12], + '153.width': [4.6, 3.52], + '153.x': [628.51, 626.52], + '153.y': [73.73, 56.44], + '154.height': [4, 3.06], + '154.width': [4.7, 3.6], + '154.x': [645.27, 639.34], + '154.y': [102.51, 78.47], + '155.height': [12.95, 9.91], + '155.width': [11.23, 8.59], + '155.x': [710.03, 688.91], + '155.y': [79.57, 60.9], + '156.height': [6.23, 4.77], + '156.width': [5.84, 4.47], + '156.x': [576.39, 586.62], + '156.y': [128.96, 98.71], + '157.height': [4.64, 3.55], + '157.width': [7.31, 5.59], + '157.x': [649.64, 642.69], + '157.y': [101.78, 77.9], + '158.height': [12.12, 9.28], + '158.width': [14.63, 11.2], + '158.x': [644.09, 638.44], + '158.y': [91.59, 70.11], + '159.height': [67.94, 52], + '159.width': [250.45, 191.71], + '159.x': [494.77, 524.15], + '159.y': [172.53, 132.06], + '160.height': [0.57, 0.44], + '160.width': [1.28, 0.98], + '160.x': [642.77, 637.43], + '160.y': [88.65, 67.85], + '161.height': [0.51, 0.39], + '161.width': [1.21, 0.93], + '161.x': [642.44, 637.18], + '161.y': [89.07, 68.18], + '162.height': [11.41, 8.73], + '162.width': [11.06, 8.46], + '162.x': [608.16, 610.94], + '162.y': [88.57, 67.8], + '163.height': [7.48, 5.73], + '163.width': [8.46, 6.48], + '163.x': [637.19, 633.15], + '163.y': [92.06, 70.47], + '164.height': [10.56, 8.09], + '164.width': [11.03, 8.44], + '164.x': [626.48, 624.96], + '164.y': [90.78, 69.49], + '165.height': [8.15, 6.24], + '165.width': [10.32, 7.9], + '165.x': [642.93, 637.55], + '165.y': [104.72, 80.15], + '166.height': [1.26, 0.97], + '166.width': [1.15, 0.88], + '166.x': [648.98, 642.19], + '166.y': [106.33, 81.39], + '167.height': [2.45, 1.87], + '167.width': [4.45, 3.4], + '167.x': [649.61, 642.66], + '167.y': [107.21, 82.07], + '168.height': [3.96, 3.03], + '168.width': [3.8, 2.91], + '168.x': [640.58, 635.75], + '168.y': [112.28, 85.95], + '169.height': [1.24, 0.95], + '169.width': [1.24, 0.95], + '169.x': [640.19, 635.46], + '169.y': [116.03, 88.82], + '170.height': [2.5, 1.91], + '170.width': [2.68, 2.05], + '170.x': [630.96, 628.39], + '170.y': [79.88, 61.14], + '171.height': [1.37, 1.05], + '171.width': [1.73, 1.32], + '171.x': [634.24, 630.9], + '171.y': [82.69, 63.29], + '172.height': [3.81, 2.92], + '172.width': [2.89, 2.21], + '172.x': [633.1, 630.03], + '172.y': [78.95, 60.43], + '173.height': [1.56, 1.19], + '173.width': [1.31, 1.01], + '173.x': [632.83, 629.82], + '173.y': [81.55, 62.42], + '174.height': [1.35, 1.03], + '174.width': [1.18, 0.91], + '174.x': [633.96, 630.69], + '174.y': [81.79, 62.6], + '175.height': [0.63, 0.48], + '175.width': [0.73, 0.56], + '175.x': [576.9, 587.01], + '175.y': [107.62, 82.38], + '176.height': [6.14, 4.7], + '176.width': [7.94, 6.08], + '176.x': [636.62, 632.72], + '176.y': [106.66, 81.64], + }, + legend: { + 'continuousLegend.bounds.height': [61, 99], + 'continuousLegend.bar.y': [107.2, 122.2], + }, + }, + style: { + 'legends.continuousLegend.title': ['gdp ($)', 'gdp'], + }, + }, + '../gallery/maps.stories.tsx.pointLayerSpec @390': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [257.55, 242.55], + }, + area: { + 'rect.height': [257.55, 242.55], + 'rect.y': [98.85, 113.85], + }, + marks: { + '0.y': [151.51, 144.01], + '1.y': [179.12, 171.62], + '2.y': [129.92, 122.42], + '3.y': [105.17, 97.67], + '4.y': [179.21, 171.71], + '5.y': [149.56, 142.06], + '6.y': [100.85, 93.35], + '7.y': [116.45, 108.95], + '8.y': [42.85, 35.35], + '9.y': [78.36, 70.86], + '10.y': [48.24, 40.74], + '11.y': [94.38, 86.88], + '12.y': [130.77, 123.27], + '13.y': [49.39, 41.89], + '14.y': [138.39, 130.89], + '15.y': [90.52, 83.02], + '16.y': [71.71, 64.21], + '17.y': [142.09, 134.59], + '18.y': [74.23, 66.73], + '19.y': [85.82, 78.32], + '20.y': [112.45, 104.95], + '21.y': [105.81, 98.31], + '22.y': [97.11, 89.61], + '23.y': [134.69, 127.19], + '24.y': [142.58, 135.08], + '25.y': [80.05, 72.55], + '26.y': [106.42, 98.92], + '27.y': [114.34, 106.84], + '28.y': [199.8, 192.3], + '29.y': [90.89, 83.39], + '30.y': [120.13, 112.63], + '31.y': [107.58, 100.08], + '32.y': [55.47, 47.97], + '33.y': [152.91, 145.41], + '34.y': [40.73, 33.23], + '35.y': [61.33, 53.83], + '36.y': [66.35, 58.85], + '37.y': [95.98, 88.48], + '38.y': [50.36, 42.86], + '39.y': [136.44, 128.94], + '40.y': [93.42, 85.92], + '41.y': [112.3, 104.8], + '42.y': [32.25, 24.75], + '43.y': [64.3, 56.8], + '44.y': [93.41, 85.91], + '45.y': [146.66, 139.16], + '46.y': [39.71, 32.21], + '47.y': [86.3, 78.8], + '48.y': [63.97, 56.47], + '49.y': [168.88, 161.38], + '50.y': [85.27, 77.77], + '51.cy': [193.65, 186.15], + '52.cy': [195.96, 188.46], + '53.cy': [171.28, 163.78], + '54.cy': [189.79, 182.29], + '55.cy': [175.28, 167.78], + }, + legend: { + 'pointCategoricalLegend.bounds.height': [16, 31], + 'pointSizeLegend.bounds.height': [71.48, 72], + 'pointSizeLegend.bounds.width': [66.79, 69], + 'pointSizeLegend.bounds.x': [295.21, 293], + 'pointSizeLegend.bounds.y': [266.92, 266.4], + 'pointCategoricalLegend.entry.0.y': [undefined, 89.85], + 'pointCategoricalLegend.entry.1.y': [undefined, 89.85], + 'pointCategoricalLegend.entry.2.y': [undefined, 89.85], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.pointLayerSpec @1280': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [215.2, 200.2], + }, + area: { + 'rect.height': [215.2, 200.2], + 'rect.y': [121.2, 136.2], + }, + marks: { + '0.height': [33.34, 30.49], + '0.width': [20.42, 18.68], + '0.x': [676.62, 671.77], + '0.y': [128.23, 118.97], + '1.height': [41.2, 37.67], + '1.width': [76.9, 70.32], + '1.x': [470.26, 483.08], + '1.y': [153.29, 141.88], + '2.height': [42.19, 38.58], + '2.width': [36.1, 33.01], + '2.x': [529.28, 537.04], + '2.y': [108.64, 101.05], + '3.height': [30.56, 27.94], + '3.width': [38.56, 35.26], + '3.x': [565.38, 570.05], + '3.y': [86.17, 80.51], + '4.height': [41.83, 38.25], + '4.width': [48.35, 44.21], + '4.x': [682.15, 676.83], + '4.y': [153.37, 141.95], + '5.height': [30.21, 27.63], + '5.width': [28.84, 26.38], + '5.x': [690.69, 684.63], + '5.y': [126.46, 117.35], + '6.height': [28.43, 26], + '6.width': [16.48, 15.07], + '6.x': [675.56, 670.8], + '6.y': [82.26, 76.93], + '7.height': [21.29, 19.47], + '7.width': [39.3, 35.93], + '7.x': [602.27, 603.79], + '7.y': [96.41, 89.87], + '8.height': [30.87, 28.23], + '8.width': [19.54, 17.86], + '8.x': [750.21, 739.06], + '8.y': [29.62, 28.79], + '9.height': [10.17, 9.3], + '9.width': [18.44, 16.86], + '9.x': [744.23, 733.6], + '9.y': [61.85, 58.27], + '10.height': [39.29, 35.92], + '10.width': [34.9, 31.91], + '10.x': [628.74, 627.99], + '10.y': [34.51, 33.27], + '11.height': [16.27, 14.88], + '11.width': [7.09, 6.49], + '11.x': [737.9, 727.8], + '11.y': [76.39, 71.56], + '12.height': [20.72, 18.95], + '12.width': [46.82, 42.81], + '12.x': [697.6, 690.96], + '12.y': [109.41, 101.76], + '13.height': [21.9, 20.02], + '13.width': [34.87, 31.88], + '13.x': [596.79, 598.78], + '13.y': [35.56, 34.23], + '14.height': [24.16, 22.09], + '14.width': [45.79, 41.87], + '14.x': [596.94, 598.92], + '14.y': [116.33, 108.08], + '15.height': [20, 18.29], + '15.width': [30.87, 28.22], + '15.x': [710.43, 702.69], + '15.y': [72.88, 68.35], + '16.height': [24.82, 22.7], + '16.width': [37.05, 33.88], + '16.x': [595.09, 597.22], + '16.y': [55.81, 52.75], + '17.height': [72.88, 66.64], + '17.width': [74.33, 67.96], + '17.x': [574.13, 578.06], + '17.y': [119.68, 111.15], + '18.height': [30.85, 28.21], + '18.width': [37.04, 33.87], + '18.x': [559.15, 564.36], + '18.y': [58.1, 54.83], + '19.height': [9.04, 8.26], + '19.width': [9.16, 8.37], + '19.x': [744.39, 733.74], + '19.y': [68.62, 64.45], + '20.height': [30.81, 28.17], + '20.width': [35.37, 32.34], + '20.x': [635.43, 634.11], + '20.y': [92.78, 86.55], + '21.height': [23.88, 21.84], + '21.width': [23.81, 21.77], + '21.x': [703.67, 696.51], + '21.y': [86.76, 81.05], + '22.height': [37.74, 34.51], + '22.width': [21.2, 19.39], + '22.x': [656.99, 653.83], + '22.y': [78.86, 73.82], + '23.height': [38.49, 35.2], + '23.width': [37.08, 33.91], + '23.x': [560.13, 565.25], + '23.y': [112.97, 105.01], + '24.height': [24.33, 22.25], + '24.width': [26.72, 24.43], + '24.x': [641.62, 639.77], + '24.y': [120.13, 111.56], + '25.height': [72.94, 66.7], + '25.width': [42.59, 38.94], + '25.x': [492.72, 503.62], + '25.y': [63.38, 59.66], + '26.height': [9.29, 8.49], + '26.width': [5.56, 5.09], + '26.x': [736.62, 726.63], + '26.y': [87.32, 81.55], + '27.height': [1.34, 1.23], + '27.width': [1.11, 1.01], + '27.x': [731.03, 721.53], + '27.y': [94.5, 88.12], + '28.height': [22.13, 20.24], + '28.width': [34.24, 31.31], + '28.x': [551.08, 556.98], + '28.y': [172.05, 159.04], + '29.height': [21.08, 19.27], + '29.width': [32.03, 29.29], + '29.x': [631.16, 630.21], + '29.y': [73.22, 68.66], + '30.height': [20.16, 18.44], + '30.width': [39.3, 35.94], + '30.x': [668.48, 664.33], + '30.y': [99.76, 92.93], + '31.height': [12.04, 11.01], + '31.width': [24.06, 22], + '31.x': [718.16, 709.75], + '31.y': [88.37, 82.51], + '32.height': [42.25, 38.64], + '32.width': [40.19, 36.75], + '32.x': [660.03, 656.61], + '32.y': [41.08, 39.27], + '33.height': [32.9, 30.09], + '33.width': [19.01, 17.38], + '33.x': [659.11, 655.76], + '33.y': [129.51, 120.13], + '34.height': [34.43, 31.48], + '34.width': [54.18, 49.54], + '34.x': [544.32, 550.8], + '34.y': [27.7, 27.04], + '35.height': [18.43, 16.86], + '35.width': [8.74, 7.99], + '35.x': [747.17, 736.28], + '35.y': [46.39, 44.13], + '36.height': [30.58, 27.96], + '36.width': [40.07, 36.64], + '36.x': [713.79, 705.76], + '36.y': [50.94, 48.29], + '37.height': [25.4, 23.23], + '37.width': [22.22, 20.31], + '37.x': [689.68, 683.72], + '37.y': [77.84, 72.89], + '38.height': [36.02, 32.94], + '38.width': [42.64, 38.99], + '38.x': [496.45, 507.03], + '38.y': [36.44, 35.03], + '39.height': [15.76, 14.41], + '39.width': [45.19, 41.32], + '39.x': [665.2, 661.33], + '39.y': [114.56, 106.46], + '40.height': [37.45, 34.25], + '40.width': [29.85, 27.29], + '40.x': [539.21, 546.13], + '40.y': [75.52, 70.76], + '41.height': [23.5, 21.48], + '41.width': [42.13, 38.53], + '41.x': [699.7, 692.88], + '41.y': [92.65, 86.43], + '42.height': [26.38, 24.12], + '42.width': [35.6, 32.55], + '42.x': [505.86, 515.63], + '43.height': [30.66, 28.03], + '43.width': [28.5, 26.06], + '43.x': [648.83, 646.36], + '43.y': [49.08, 46.59], + '44.height': [21.91, 20.03], + '44.width': [43.83, 40.07], + '44.x': [593.95, 596.18], + '44.y': [75.5, 70.75], + '45.height': [20.61, 18.85], + '45.width': [27.01, 24.7], + '45.x': [703.1, 695.99], + '45.y': [123.83, 114.94], + '46.height': [51.25, 46.86], + '46.width': [31.64, 28.93], + '46.x': [531.2, 538.8], + '46.y': [26.77, 26.19], + '47.height': [52.25, 47.78], + '47.width': [33.77, 30.88], + '47.x': [511.86, 521.12], + '47.y': [69.05, 64.85], + '48.height': [16.86, 15.42], + '48.width': [8.96, 8.19], + '48.x': [740.38, 730.07], + '48.y': [48.79, 46.32], + '49.height': [26.71, 24.43], + '49.width': [30.69, 28.06], + '49.x': [645.18, 643.03], + '49.y': [143.99, 133.38], + '50.height': [5.9, 5.39], + '50.width': [4.13, 3.78], + '50.x': [752.54, 741.2], + '50.y': [68.12, 64], + '51.cx': [637.92, 636.38], + '51.cy': [166.47, 153.93], + '52.cx': [619.73, 619.76], + '52.cy': [168.57, 155.85], + '53.cx': [629.78, 628.94], + '53.cy': [146.17, 135.37], + '54.cx': [624.21, 623.85], + '54.cy': [162.97, 150.73], + '55.cx': [575.19, 579.03], + '55.cy': [149.81, 138.7], + }, + legend: { + 'pointCategoricalLegend.bounds.height': [16, 31], + 'pointSizeLegend.bounds.height': [71.48, 72], + 'pointSizeLegend.bounds.width': [66.79, 69], + 'pointSizeLegend.bounds.x': [1175.21, 1173], + 'pointSizeLegend.bounds.y': [246.92, 246.4], + 'pointCategoricalLegend.entry.0.y': [undefined, 112.2], + 'pointCategoricalLegend.entry.1.y': [undefined, 112.2], + 'pointCategoricalLegend.entry.2.y': [undefined, 112.2], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.readerZoomPointsSpec @390': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [231.1, 216.1], + }, + area: { + 'rect.height': [231.1, 216.1], + 'rect.y': [125.3, 140.3], + }, + marks: { + '0.height': [36.37, 33.51], + '0.width': [22.28, 20.53], + '0.x': [246.76, 241.91], + '0.y': [138.05, 128.79], + '1.height': [44.93, 41.41], + '1.width': [83.88, 77.29], + '1.x': [21.67, 34.49], + '1.y': [165.39, 153.97], + '2.height': [46.02, 42.41], + '2.width': [39.38, 36.29], + '2.x': [86.04, 93.81], + '2.y': [116.68, 109.1], + '3.height': [33.33, 30.71], + '3.width': [42.06, 38.76], + '3.x': [125.42, 130.1], + '3.y': [92.18, 86.51], + '4.height': [45.62, 42.04], + '4.width': [52.73, 48.6], + '4.x': [252.79, 247.47], + '4.y': [165.48, 154.06], + '5.height': [32.96, 30.37], + '5.width': [31.46, 28.99], + '5.x': [262.1, 256.05], + '5.y': [136.12, 127.01], + '6.height': [31.01, 28.58], + '6.width': [17.97, 16.56], + '6.x': [245.6, 240.85], + '6.y': [87.91, 82.58], + '7.height': [23.22, 21.4], + '7.width': [42.86, 39.5], + '7.x': [165.66, 167.18], + '7.y': [103.35, 96.81], + '8.height': [33.67, 31.03], + '8.width': [21.31, 19.64], + '8.x': [327.02, 315.88], + '8.y': [30.49, 29.67], + '9.height': [11.09, 10.22], + '9.width': [20.11, 18.53], + '9.x': [320.51, 309.87], + '9.y': [65.65, 62.06], + '10.height': [42.85, 39.49], + '10.width': [38.07, 35.08], + '10.x': [194.53, 193.79], + '10.y': [35.83, 34.59], + '11.height': [17.75, 16.36], + '11.width': [7.74, 7.13], + '11.x': [313.6, 303.5], + '11.y': [81.5, 76.67], + '12.height': [22.61, 20.83], + '12.width': [51.07, 47.06], + '12.x': [269.65, 263], + '12.y': [117.53, 109.87], + '13.height': [23.88, 22.01], + '13.width': [38.03, 35.05], + '13.x': [159.69, 161.67], + '13.y': [36.97, 35.64], + '14.height': [26.35, 24.28], + '14.width': [49.95, 46.03], + '14.x': [159.85, 161.83], + '14.y': [125.07, 116.82], + '15.height': [21.81, 20.1], + '15.width': [33.67, 31.02], + '15.x': [283.64, 275.9], + '15.y': [77.68, 73.15], + '16.height': [27.07, 24.95], + '16.width': [40.41, 37.24], + '16.x': [157.83, 159.96], + '16.y': [59.06, 56], + '17.height': [79.49, 73.25], + '17.width': [81.07, 74.71], + '17.x': [134.97, 138.9], + '17.y': [128.73, 120.19], + '18.height': [33.65, 31], + '18.width': [40.41, 37.23], + '18.x': [118.62, 123.83], + '18.y': [61.55, 58.29], + '19.height': [9.86, 9.08], + '19.width': [9.99, 9.2], + '19.x': [320.68, 310.03], + '19.y': [73.03, 68.87], + '20.height': [33.61, 30.97], + '20.width': [38.58, 35.55], + '20.x': [201.83, 200.51], + '20.y': [99.39, 93.16], + '21.height': [26.05, 24], + '21.width': [25.97, 23.93], + '21.x': [276.27, 269.1], + '21.y': [92.82, 87.1], + '22.height': [41.16, 37.93], + '22.width': [23.13, 21.31], + '22.x': [225.35, 222.18], + '22.y': [84.2, 79.16], + '23.height': [41.99, 38.69], + '23.width': [40.45, 37.28], + '23.x': [119.69, 124.82], + '23.y': [121.41, 113.45], + '24.height': [26.54, 24.46], + '24.width': [29.15, 26.86], + '24.x': [208.58, 206.73], + '24.y': [129.22, 120.65], + '25.height': [79.56, 73.32], + '25.width': [46.45, 42.81], + '25.x': [46.17, 57.07], + '25.y': [67.32, 63.6], + '26.height': [10.13, 9.33], + '26.width': [6.07, 5.59], + '26.x': [312.2, 302.22], + '26.y': [93.42, 87.66], + '27.height': [1.46, 1.35], + '27.width': [1.21, 1.11], + '27.x': [306.11, 296.6], + '27.y': [101.26, 94.88], + '28.height': [24.14, 22.25], + '28.width': [37.35, 34.42], + '28.x': [109.83, 115.73], + '28.y': [185.85, 172.84], + '29.height': [22.99, 21.19], + '29.width': [34.93, 32.19], + '29.x': [197.18, 196.22], + '29.y': [78.05, 73.49], + '30.height': [21.99, 20.27], + '30.width': [42.87, 39.5], + '30.x': [237.88, 233.73], + '30.y': [107, 100.17], + '31.height': [13.14, 12.11], + '31.width': [26.24, 24.18], + '31.x': [292.07, 283.66], + '31.y': [94.57, 88.72], + '32.height': [46.09, 42.47], + '32.width': [43.84, 40.4], + '32.x': [228.67, 225.24], + '32.y': [42.99, 41.18], + '33.height': [35.89, 33.07], + '33.width': [20.73, 19.11], + '33.x': [227.65, 224.31], + '33.y': [139.44, 130.07], + '34.height': [37.56, 34.61], + '34.width': [59.1, 54.46], + '34.x': [102.45, 108.93], + '34.y': [28.4, 27.74], + '35.height': [20.11, 18.53], + '35.width': [9.53, 8.78], + '35.x': [323.71, 312.82], + '35.y': [48.79, 46.53], + '36.height': [33.36, 30.74], + '36.width': [43.7, 40.27], + '36.x': [287.3, 279.27], + '36.y': [53.75, 51.1], + '37.height': [27.71, 25.53], + '37.width': [24.23, 22.33], + '37.x': [261.01, 255.04], + '37.y': [83.09, 78.14], + '38.height': [39.29, 36.21], + '38.width': [46.51, 42.86], + '38.x': [50.24, 60.82], + '38.y': [37.93, 36.52], + '39.height': [17.19, 15.84], + '39.width': [49.29, 45.42], + '39.x': [234.3, 230.43], + '39.y': [123.14, 115.05], + '40.height': [40.85, 37.65], + '40.width': [32.55, 30], + '40.x': [96.88, 103.8], + '40.y': [80.56, 75.8], + '41.height': [25.63, 23.62], + '41.width': [45.96, 42.35], + '41.x': [271.94, 265.11], + '41.y': [99.24, 93.02], + '42.height': [28.78, 26.52], + '42.width': [38.83, 35.78], + '42.x': [60.5, 70.27], + '43.height': [33.44, 30.81], + '43.width': [31.08, 28.64], + '43.x': [216.44, 213.98], + '43.y': [51.72, 49.23], + '44.height': [23.9, 22.02], + '44.width': [47.8, 44.05], + '44.x': [156.58, 158.81], + '44.y': [80.54, 75.79], + '45.height': [22.49, 20.72], + '45.width': [29.46, 27.15], + '45.x': [275.64, 268.53], + '45.y': [133.25, 124.36], + '46.height': [55.9, 51.51], + '46.width': [34.51, 31.8], + '46.x': [88.14, 95.74], + '46.y': [27.39, 26.81], + '47.height': [57, 52.52], + '47.width': [36.84, 33.95], + '47.x': [67.05, 76.31], + '47.y': [73.5, 69.3], + '48.height': [18.39, 16.95], + '48.width': [9.78, 9.01], + '48.x': [316.3, 306], + '48.y': [51.4, 48.94], + '49.height': [29.14, 26.85], + '49.width': [33.47, 30.85], + '49.x': [212.47, 210.31], + '49.y': [155.25, 144.63], + '50.height': [6.43, 5.93], + '50.width': [4.51, 4.15], + '50.x': [329.57, 318.22], + '50.y': [72.49, 68.37], + '51.cx': [204.54, 203.01], + '51.cy': [179.76, 167.22], + '52.cx': [184.71, 184.73], + '52.cy': [182.05, 169.33], + '53.cx': [195.67, 194.83], + '53.cy': [157.62, 146.82], + '54.cx': [189.59, 189.23], + '54.cy': [175.95, 163.71], + '55.cx': [136.13, 139.96], + '55.cy': [161.59, 150.48], + }, + legend: { + 'pointCategoricalLegend.bounds.height': [16, 31], + 'pointSizeLegend.bounds.height': [71.48, 72], + 'pointSizeLegend.bounds.width': [66.79, 69], + 'pointSizeLegend.bounds.x': [295.21, 293], + 'pointSizeLegend.bounds.y': [266.92, 266.4], + 'pointCategoricalLegend.entry.0.y': [undefined, 116.3], + 'pointCategoricalLegend.entry.1.y': [undefined, 116.3], + 'pointCategoricalLegend.entry.2.y': [undefined, 116.3], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.readerZoomPointsSpec @1280': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [215.2, 200.2], + }, + area: { + 'rect.height': [215.2, 200.2], + 'rect.y': [121.2, 136.2], + }, + marks: { + '0.height': [33.34, 30.49], + '0.width': [20.42, 18.68], + '0.x': [676.62, 671.77], + '0.y': [128.23, 118.97], + '1.height': [41.2, 37.67], + '1.width': [76.9, 70.32], + '1.x': [470.26, 483.08], + '1.y': [153.29, 141.88], + '2.height': [42.19, 38.58], + '2.width': [36.1, 33.01], + '2.x': [529.28, 537.04], + '2.y': [108.64, 101.05], + '3.height': [30.56, 27.94], + '3.width': [38.56, 35.26], + '3.x': [565.38, 570.05], + '3.y': [86.17, 80.51], + '4.height': [41.83, 38.25], + '4.width': [48.35, 44.21], + '4.x': [682.15, 676.83], + '4.y': [153.37, 141.95], + '5.height': [30.21, 27.63], + '5.width': [28.84, 26.38], + '5.x': [690.69, 684.63], + '5.y': [126.46, 117.35], + '6.height': [28.43, 26], + '6.width': [16.48, 15.07], + '6.x': [675.56, 670.8], + '6.y': [82.26, 76.93], + '7.height': [21.29, 19.47], + '7.width': [39.3, 35.93], + '7.x': [602.27, 603.79], + '7.y': [96.41, 89.87], + '8.height': [30.87, 28.23], + '8.width': [19.54, 17.86], + '8.x': [750.21, 739.06], + '8.y': [29.62, 28.79], + '9.height': [10.17, 9.3], + '9.width': [18.44, 16.86], + '9.x': [744.23, 733.6], + '9.y': [61.85, 58.27], + '10.height': [39.29, 35.92], + '10.width': [34.9, 31.91], + '10.x': [628.74, 627.99], + '10.y': [34.51, 33.27], + '11.height': [16.27, 14.88], + '11.width': [7.09, 6.49], + '11.x': [737.9, 727.8], + '11.y': [76.39, 71.56], + '12.height': [20.72, 18.95], + '12.width': [46.82, 42.81], + '12.x': [697.6, 690.96], + '12.y': [109.41, 101.76], + '13.height': [21.9, 20.02], + '13.width': [34.87, 31.88], + '13.x': [596.79, 598.78], + '13.y': [35.56, 34.23], + '14.height': [24.16, 22.09], + '14.width': [45.79, 41.87], + '14.x': [596.94, 598.92], + '14.y': [116.33, 108.08], + '15.height': [20, 18.29], + '15.width': [30.87, 28.22], + '15.x': [710.43, 702.69], + '15.y': [72.88, 68.35], + '16.height': [24.82, 22.7], + '16.width': [37.05, 33.88], + '16.x': [595.09, 597.22], + '16.y': [55.81, 52.75], + '17.height': [72.88, 66.64], + '17.width': [74.33, 67.96], + '17.x': [574.13, 578.06], + '17.y': [119.68, 111.15], + '18.height': [30.85, 28.21], + '18.width': [37.04, 33.87], + '18.x': [559.15, 564.36], + '18.y': [58.1, 54.83], + '19.height': [9.04, 8.26], + '19.width': [9.16, 8.37], + '19.x': [744.39, 733.74], + '19.y': [68.62, 64.45], + '20.height': [30.81, 28.17], + '20.width': [35.37, 32.34], + '20.x': [635.43, 634.11], + '20.y': [92.78, 86.55], + '21.height': [23.88, 21.84], + '21.width': [23.81, 21.77], + '21.x': [703.67, 696.51], + '21.y': [86.76, 81.05], + '22.height': [37.74, 34.51], + '22.width': [21.2, 19.39], + '22.x': [656.99, 653.83], + '22.y': [78.86, 73.82], + '23.height': [38.49, 35.2], + '23.width': [37.08, 33.91], + '23.x': [560.13, 565.25], + '23.y': [112.97, 105.01], + '24.height': [24.33, 22.25], + '24.width': [26.72, 24.43], + '24.x': [641.62, 639.77], + '24.y': [120.13, 111.56], + '25.height': [72.94, 66.7], + '25.width': [42.59, 38.94], + '25.x': [492.72, 503.62], + '25.y': [63.38, 59.66], + '26.height': [9.29, 8.49], + '26.width': [5.56, 5.09], + '26.x': [736.62, 726.63], + '26.y': [87.32, 81.55], + '27.height': [1.34, 1.23], + '27.width': [1.11, 1.01], + '27.x': [731.03, 721.53], + '27.y': [94.5, 88.12], + '28.height': [22.13, 20.24], + '28.width': [34.24, 31.31], + '28.x': [551.08, 556.98], + '28.y': [172.05, 159.04], + '29.height': [21.08, 19.27], + '29.width': [32.03, 29.29], + '29.x': [631.16, 630.21], + '29.y': [73.22, 68.66], + '30.height': [20.16, 18.44], + '30.width': [39.3, 35.94], + '30.x': [668.48, 664.33], + '30.y': [99.76, 92.93], + '31.height': [12.04, 11.01], + '31.width': [24.06, 22], + '31.x': [718.16, 709.75], + '31.y': [88.37, 82.51], + '32.height': [42.25, 38.64], + '32.width': [40.19, 36.75], + '32.x': [660.03, 656.61], + '32.y': [41.08, 39.27], + '33.height': [32.9, 30.09], + '33.width': [19.01, 17.38], + '33.x': [659.11, 655.76], + '33.y': [129.51, 120.13], + '34.height': [34.43, 31.48], + '34.width': [54.18, 49.54], + '34.x': [544.32, 550.8], + '34.y': [27.7, 27.04], + '35.height': [18.43, 16.86], + '35.width': [8.74, 7.99], + '35.x': [747.17, 736.28], + '35.y': [46.39, 44.13], + '36.height': [30.58, 27.96], + '36.width': [40.07, 36.64], + '36.x': [713.79, 705.76], + '36.y': [50.94, 48.29], + '37.height': [25.4, 23.23], + '37.width': [22.22, 20.31], + '37.x': [689.68, 683.72], + '37.y': [77.84, 72.89], + '38.height': [36.02, 32.94], + '38.width': [42.64, 38.99], + '38.x': [496.45, 507.03], + '38.y': [36.44, 35.03], + '39.height': [15.76, 14.41], + '39.width': [45.19, 41.32], + '39.x': [665.2, 661.33], + '39.y': [114.56, 106.46], + '40.height': [37.45, 34.25], + '40.width': [29.85, 27.29], + '40.x': [539.21, 546.13], + '40.y': [75.52, 70.76], + '41.height': [23.5, 21.48], + '41.width': [42.13, 38.53], + '41.x': [699.7, 692.88], + '41.y': [92.65, 86.43], + '42.height': [26.38, 24.12], + '42.width': [35.6, 32.55], + '42.x': [505.86, 515.63], + '43.height': [30.66, 28.03], + '43.width': [28.5, 26.06], + '43.x': [648.83, 646.36], + '43.y': [49.08, 46.59], + '44.height': [21.91, 20.03], + '44.width': [43.83, 40.07], + '44.x': [593.95, 596.18], + '44.y': [75.5, 70.75], + '45.height': [20.61, 18.85], + '45.width': [27.01, 24.7], + '45.x': [703.1, 695.99], + '45.y': [123.83, 114.94], + '46.height': [51.25, 46.86], + '46.width': [31.64, 28.93], + '46.x': [531.2, 538.8], + '46.y': [26.77, 26.19], + '47.height': [52.25, 47.78], + '47.width': [33.77, 30.88], + '47.x': [511.86, 521.12], + '47.y': [69.05, 64.85], + '48.height': [16.86, 15.42], + '48.width': [8.96, 8.19], + '48.x': [740.38, 730.07], + '48.y': [48.79, 46.32], + '49.height': [26.71, 24.43], + '49.width': [30.69, 28.06], + '49.x': [645.18, 643.03], + '49.y': [143.99, 133.38], + '50.height': [5.9, 5.39], + '50.width': [4.13, 3.78], + '50.x': [752.54, 741.2], + '50.y': [68.12, 64], + '51.cx': [637.92, 636.38], + '51.cy': [166.47, 153.93], + '52.cx': [619.73, 619.76], + '52.cy': [168.57, 155.85], + '53.cx': [629.78, 628.94], + '53.cy': [146.17, 135.37], + '54.cx': [624.21, 623.85], + '54.cy': [162.97, 150.73], + '55.cx': [575.19, 579.03], + '55.cy': [149.81, 138.7], + }, + legend: { + 'pointCategoricalLegend.bounds.height': [16, 31], + 'pointSizeLegend.bounds.height': [71.48, 72], + 'pointSizeLegend.bounds.width': [66.79, 69], + 'pointSizeLegend.bounds.x': [1175.21, 1173], + 'pointSizeLegend.bounds.y': [246.92, 246.4], + 'pointCategoricalLegend.entry.0.y': [undefined, 112.2], + 'pointCategoricalLegend.entry.1.y': [undefined, 112.2], + 'pointCategoricalLegend.entry.2.y': [undefined, 112.2], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.worldMapSpec @390': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [149.3, 111.3], + }, + area: { + 'rect.height': [149.3, 111.3], + 'rect.y': [174.7, 212.7], + }, + marks: { + '0.height': [2.55, 1.9], + '0.width': [302.38, 225.42], + '0.x': [33.81, 72.29], + '0.y': [92.66, 69.08], + '1.height': [12.37, 9.22], + '1.width': [9.17, 6.83], + '1.x': [210.08, 203.69], + '1.y': [75.41, 56.21], + '2.height': [7.3, 5.45], + '2.width': [7.13, 5.31], + '2.x': [170.86, 174.46], + '2.y': [43.08, 32.11], + '3.height': [28.47, 21.22], + '3.width': [59.19, 44.13], + '3.x': [93.72, 116.95], + '3.y': [0.09, 0.07], + '4.height': [47.9, 35.71], + '4.width': [82.99, 61.87], + '4.x': [53.03, 86.62], + '4.y': [4.81, 3.58], + '5.height': [13.51, 10.07], + '5.width': [28.89, 21.54], + '5.x': [218.18, 209.74], + '5.y': [16.05, 11.96], + '6.height': [8.31, 6.19], + '6.width': [14.09, 10.5], + '6.x': [226.03, 215.59], + '6.y': [24.79, 18.48], + '7.height': [9.37, 6.98], + '7.width': [13.14, 9.8], + '7.x': [304.99, 274.45], + '7.y': [77.19, 57.55], + '8.height': [18.23, 13.59], + '8.width': [39.24, 29.25], + '8.x': [266.39, 245.67], + '8.y': [68, 50.69], + '9.height': [33.29, 24.82], + '9.width': [12.69, 9.46], + '9.x': [128.78, 143.09], + '9.y': [99.16, 73.93], + '10.height': [38.34, 28.58], + '10.width': [13.44, 10.02], + '10.x': [126.23, 141.19], + '10.y': [94.42, 70.39], + '11.height': [21.27, 15.86], + '11.width': [16.27, 12.13], + '11.x': [195.4, 192.75], + '11.y': [68.25, 50.88], + '12.height': [15.75, 11.74], + '12.width': [8.28, 6.17], + '12.x': [220.06, 211.14], + '12.y': [60.5, 45.1], + '13.height': [11.73, 8.75], + '13.width': [6.78, 5.05], + '13.x': [214.01, 206.63], + '13.y': [67.97, 50.67], + '14.height': [15.57, 11.61], + '14.width': [13.55, 10.1], + '14.x': [203.56, 198.84], + '14.y': [49.27, 36.73], + '15.height': [18.05, 13.46], + '15.width': [8.67, 6.46], + '15.x': [196.42, 193.51], + '15.y': [47.71, 35.57], + '16.height': [2.11, 1.57], + '16.width': [2.52, 1.88], + '16.x': [122.82, 138.65], + '16.y': [51.59, 38.46], + '17.height': [2.56, 1.91], + '17.width': [3.02, 2.25], + '17.x': [124.96, 140.24], + '17.y': [51.62, 38.48], + '18.height': [28.48, 21.23], + '18.width': [223.2, 166.39], + '18.x': [74.72, 102.79], + '18.y': [0.6, 0.45], + '19.height': [3.64, 2.71], + '19.width': [1.64, 1.22], + '19.x': [120.81, 137.15], + '19.y': [43.74, 32.61], + '20.height': [1.05, 0.79], + '20.width': [2.3, 1.71], + '20.x': [142.45, 153.28], + '20.y': [128.89, 96.08], + '21.height': [13.08, 9.75], + '21.width': [15, 11.18], + '21.x': [188.16, 187.35], + '21.y': [0.77, 0.58], + '22.height': [12.33, 9.19], + '22.width': [32.95, 24.56], + '22.x': [145.66, 155.68], + '23.height': [1.04, 0.78], + '23.width': [1.55, 1.15], + '23.x': [233.63, 221.25], + '23.y': [126.66, 94.42], + '24.height': [1.28, 0.96], + '24.width': [2.08, 1.55], + '24.x': [291.35, 264.28], + '24.y': [83.83, 62.5], + '25.height': [13.68, 10.2], + '25.width': [13.48, 10.05], + '25.x': [198.17, 194.82], + '25.y': [99.45, 74.14], + '26.height': [2.14, 1.59], + '26.width': [1.93, 1.44], + '26.x': [206.63, 201.12], + '26.y': [106.61, 79.48], + '27.height': [19.96, 14.88], + '27.width': [21.17, 15.78], + '27.x': [91.96, 115.64], + '27.y': [37.68, 28.09], + '28.height': [5.09, 3.8], + '28.width': [4.16, 3.1], + '28.x': [138.88, 150.62], + '28.y': [108.18, 80.65], + '29.height': [43.77, 32.63], + '29.width': [33.46, 24.94], + '29.x': [121.93, 137.98], + '29.y': [68.27, 50.89], + '30.height': [14.78, 11.02], + '30.width': [10.96, 8.17], + '30.x': [126, 141.02], + '30.y': [85.54, 63.77], + '31.height': [20.9, 15.58], + '31.width': [11.71, 8.73], + '31.x': [115.43, 133.14], + '31.y': [74.38, 55.45], + '32.height': [19.24, 14.34], + '32.width': [10.36, 7.72], + '32.x': [117.4, 134.61], + '32.y': [60.03, 44.75], + '33.height': [2.74, 2.04], + '33.width': [4.85, 3.62], + '33.x': [114.33, 132.32], + '33.y': [63.25, 47.15], + '34.height': [3.42, 2.55], + '34.width': [2.74, 2.04], + '34.x': [112.07, 130.63], + '34.y': [61.42, 45.79], + '35.height': [4.88, 3.64], + '35.width': [4.12, 3.07], + '35.x': [110.87, 129.73], + '35.y': [57.1, 42.56], + '36.height': [3.43, 2.55], + '36.width': [5.32, 3.97], + '36.x': [109.67, 128.84], + '36.y': [55.98, 41.73], + '37.height': [1.45, 1.08], + '37.width': [2.01, 1.5], + '37.x': [108.94, 128.3], + '37.y': [57.77, 43.07], + '38.height': [4.62, 3.44], + '38.width': [3.57, 2.66], + '38.x': [107.27, 127.05], + '38.y': [53.94, 40.21], + '39.height': [2.94, 2.19], + '39.width': [1.4, 1.05], + '39.x': [110.02, 129.11], + '39.y': [53.17, 39.64], + '40.height': [13.13, 9.79], + '40.width': [11.47, 8.55], + '40.x': [122.64, 138.51], + '40.y': [60.34, 44.98], + '41.height': [8.17, 6.09], + '41.width': [4.05, 3.02], + '41.x': [132.57, 145.91], + '41.y': [64.68, 48.22], + '42.height': [4.85, 3.61], + '42.width': [3.55, 2.65], + '42.x': [135.38, 148.01], + '42.y': [67.37, 50.22], + '43.height': [52.25, 38.95], + '43.width': [53.8, 40.11], + '43.x': [138.35, 150.22], + '43.y': [19.69, 14.68], + '44.height': [7.31, 5.45], + '44.width': [4.88, 3.64], + '44.x': [115.72, 133.35], + '44.y': [72.72, 54.21], + '45.height': [0.64, 0.48], + '45.width': [1.37, 1.02], + '45.x': [128.83, 143.13], + '45.y': [53.15, 39.62], + '46.height': [0.92, 0.69], + '46.width': [1.73, 1.29], + '46.x': [119.56, 136.21], + '46.y': [53.14, 39.62], + '47.height': [3.7, 2.76], + '47.width': [8.61, 6.42], + '47.x': [114.79, 132.66], + '47.y': [47.96, 35.75], + '48.height': [7.57, 5.65], + '48.width': [6.42, 4.78], + '48.x': [206.13, 200.75], + '48.y': [92.08, 68.64], + '49.height': [10.14, 7.56], + '49.width': [8.03, 5.98], + '49.x': [201.28, 197.13], + '49.y': [94.51, 70.45], + '50.height': [13.34, 9.95], + '50.width': [11.16, 8.32], + '50.x': [194.83, 192.33], + '50.y': [93.7, 69.85], + '51.height': [4.84, 3.6], + '51.width': [5.15, 3.84], + '51.x': [170.15, 173.93], + '51.y': [55.31, 41.23], + '52.height': [16.7, 12.45], + '52.width': [13.84, 10.31], + '52.x': [174.74, 177.35], + '52.y': [45.99, 34.29], + '53.height': [14.19, 10.58], + '53.width': [10.11, 7.54], + '53.x': [170.86, 174.46], + '53.y': [43.36, 32.32], + '54.height': [6.98, 5.2], + '54.width': [2.57, 1.91], + '54.x': [185.66, 185.49], + '54.y': [60.26, 44.92], + '55.height': [13.27, 9.89], + '55.width': [12.95, 9.66], + '55.x': [185.25, 185.19], + '55.y': [47.64, 35.52], + '56.height': [11.02, 8.22], + '56.width': [10.05, 7.49], + '56.x': [187.3, 186.71], + '56.y': [58.4, 43.54], + '57.height': [12.77, 9.52], + '57.width': [6.45, 4.81], + '57.x': [192.25, 190.41], + '57.y': [59.55, 44.39], + '58.height': [5.83, 4.35], + '58.width': [1.63, 1.22], + '58.x': [184.96, 184.97], + '58.y': [61.64, 45.95], + '59.height': [7.33, 5.46], + '59.width': [3.68, 2.74], + '59.x': [182.23, 182.93], + '59.y': [61.55, 45.89], + '60.height': [7.1, 5.29], + '60.width': [5.16, 3.85], + '60.x': [177.66, 179.53], + '60.y': [62.21, 46.38], + '61.height': [6.04, 4.5], + '61.width': [6.17, 4.6], + '61.x': [172.16, 175.43], + '61.y': [59.86, 44.62], + '62.height': [1.81, 1.35], + '62.width': [2.52, 1.88], + '62.x': [170.88, 174.48], + '62.y': [59.81, 44.59], + '63.height': [4.81, 3.59], + '63.width': [3.32, 2.47], + '63.x': [175.24, 177.73], + '63.y': [64.48, 48.07], + '64.height': [3.74, 2.79], + '64.width': [2.56, 1.91], + '64.x': [173.73, 176.6], + '64.y': [62.75, 46.78], + '65.height': [6.27, 4.67], + '65.width': [6.48, 4.83], + '65.x': [180.36, 181.54], + '65.y': [56.98, 42.48], + '66.height': [10.19, 7.6], + '66.width': [11.03, 8.23], + '66.x': [197.35, 194.21], + '66.y': [61.5, 45.85], + '67.height': [10.1, 7.53], + '67.width': [6.3, 4.69], + '67.x': [194.48, 192.07], + '67.y': [70.01, 52.19], + '68.height': [7.27, 5.42], + '68.width': [4.82, 3.59], + '68.x': [192.53, 190.61], + '68.y': [71.63, 53.4], + '69.height': [1.47, 1.1], + '69.width': [1.69, 1.26], + '69.x': [192.96, 190.94], + '69.y': [71.68, 53.43], + '70.height': [11.05, 8.24], + '70.width': [10.05, 7.49], + '70.x': [203.38, 198.7], + '70.y': [83.79, 62.47], + '71.height': [8.61, 6.42], + '71.width': [2.48, 1.85], + '71.x': [212.6, 205.57], + '71.y': [84.93, 63.31], + '72.height': [18.38, 13.7], + '72.width': [8.93, 6.66], + '72.x': [210.42, 203.95], + '72.y': [86.17, 64.24], + '73.height': [1.77, 1.32], + '73.width': [1.13, 0.84], + '73.x': [209.91, 203.57], + '73.y': [103.38, 77.07], + '74.height': [15.38, 11.47], + '74.width': [10.62, 7.92], + '74.x': [194.76, 192.28], + '74.y': [79.42, 59.21], + '75.height': [2.48, 1.85], + '75.width': [1.47, 1.1], + '75.x': [209.83, 203.51], + '75.y': [77.02, 57.42], + '76.height': [4, 2.98], + '76.width': [1.02, 0.76], + '76.x': [212.28, 205.34], + '76.y': [37.09, 27.65], + '77.height': [1.62, 1.21], + '77.width': [1.01, 0.75], + '77.x': [212.71, 205.66], + '77.y': [35.67, 26.59], + '78.height': [15.17, 11.31], + '78.width': [6.77, 5.05], + '78.x': [220.71, 211.62], + '78.y': [88.14, 65.71], + '79.height': [1.25, 0.93], + '79.width': [0.46, 0.35], + '79.x': [212.76, 205.69], + '79.y': [37.87, 28.23], + '80.height': [0.85, 0.63], + '80.width': [2.54, 1.9], + '80.x': [170.76, 174.39], + '80.y': [58.39, 43.53], + '81.height': [7.34, 5.48], + '81.width': [3.16, 2.35], + '81.x': [190.91, 189.4], + '81.y': [32.89, 24.52], + '82.height': [19.43, 14.48], + '82.width': [16.9, 12.6], + '82.x': [177.97, 179.76], + '82.y': [33.12, 24.69], + '83.height': [4.43, 3.3], + '83.width': [3.04, 2.27], + '83.x': [213.02, 205.89], + '83.y': [36.98, 27.57], + '84.height': [3.91, 2.91], + '84.width': [3.83, 2.86], + '84.x': [227.28, 216.52], + '84.y': [44.81, 33.41], + '85.height': [1.7, 1.27], + '85.width': [0.75, 0.56], + '85.x': [226.4, 215.86], + '85.y': [44.75, 33.36], + '86.height': [1.64, 1.23], + '86.width': [1.58, 1.18], + '86.x': [222.43, 212.91], + '86.y': [40.5, 30.19], + '87.height': [8.67, 6.47], + '87.width': [8.34, 6.22], + '87.x': [215.56, 207.78], + '87.y': [32.85, 24.49], + '88.height': [10.81, 8.06], + '88.width': [6, 4.48], + '88.x': [228.35, 217.31], + '88.y': [44.44, 33.13], + '89.height': [2.23, 1.66], + '89.width': [0.65, 0.49], + '89.x': [325.2, 289.51], + '89.y': [91.08, 67.9], + '90.height': [4.65, 3.47], + '90.width': [4.53, 3.37], + '90.x': [271.46, 249.46], + '90.y': [57.6, 42.94], + '91.height': [16.73, 12.47], + '91.width': [7.62, 5.68], + '91.x': [266.3, 245.6], + '91.y': [51.03, 38.04], + '92.height': [9.63, 7.18], + '92.width': [7.46, 5.56], + '92.x': [268.11, 246.96], + '92.y': [48.76, 36.35], + '93.height': [20.54, 15.31], + '93.width': [7.99, 5.96], + '93.x': [261.37, 241.94], + '93.y': [42.34, 31.57], + '94.height': [16.64, 12.4], + '94.width': [8.28, 6.17], + '94.x': [269.27, 247.82], + '94.y': [47.77, 35.62], + '95.height': [5.28, 3.94], + '95.width': [3.92, 2.92], + '95.x': [279.31, 255.31], + '95.y': [27.28, 20.34], + '96.height': [4.32, 3.22], + '96.width': [3.75, 2.79], + '96.x': [282.03, 257.33], + '96.y': [31.61, 23.56], + '97.height': [9.74, 7.26], + '97.width': [24.39, 18.18], + '97.x': [247.31, 231.45], + '97.y': [18.9, 14.09], + '98.height': [30.35, 22.63], + '98.width': [22.76, 16.97], + '98.x': [240.99, 226.74], + '98.y': [34.79, 25.93], + '99.height': [6.36, 4.74], + '99.width': [4.81, 3.58], + '99.x': [256.89, 238.59], + '99.y': [44.39, 33.09], + '100.height': [1.71, 1.27], + '100.width': [2.75, 2.05], + '100.x': [256.94, 238.63], + '100.y': [42.38, 31.6], + '101.height': [4.33, 3.23], + '101.width': [7.12, 5.31], + '101.x': [249.47, 233.06], + '101.y': [40.11, 29.9], + '102.height': [14.3, 10.66], + '102.width': [11.85, 8.84], + '102.x': [233.78, 221.36], + '102.y': [33.11, 24.68], + '103.height': [9.55, 7.12], + '103.width': [10.4, 7.76], + '103.x': [232.61, 220.49], + '103.y': [31.73, 23.66], + '104.height': [4.25, 3.17], + '104.width': [6.34, 4.72], + '104.x': [236.44, 223.34], + '104.y': [29.26, 21.81], + '105.height': [3.96, 2.95], + '105.width': [7.23, 5.39], + '105.x': [237.74, 224.31], + '105.y': [26.98, 20.11], + '106.height': [7.51, 5.6], + '106.width': [11.9, 8.87], + '106.x': [224.38, 214.35], + '106.y': [27.51, 20.51], + '107.height': [15.38, 11.46], + '107.width': [17.82, 13.28], + '107.x': [218.58, 210.03], + '107.y': [30.5, 22.74], + '108.height': [5.1, 3.8], + '108.width': [4.69, 3.49], + '108.x': [212.98, 205.86], + '108.y': [33.01, 24.61], + '109.height': [2.5, 1.86], + '109.width': [2.71, 2.02], + '109.x': [217.84, 209.48], + '109.y': [28.98, 21.6], + '110.height': [9.96, 7.43], + '110.width': [7.29, 5.44], + '110.x': [192.19, 190.36], + '110.y': [6.1, 4.55], + '111.height': [4.14, 3.08], + '111.width': [6.4, 4.77], + '111.x': [201.04, 196.96], + '111.y': [15.4, 11.48], + '112.height': [6.42, 4.78], + '112.width': [12.78, 9.53], + '112.x': [200.79, 196.77], + '112.y': [18.65, 13.9], + '113.height': [5.1, 3.8], + '113.width': [7.21, 5.38], + '113.x': [194.66, 192.2], + '113.y': [16.5, 12.3], + '114.height': [2.41, 1.79], + '114.width': [5.32, 3.97], + '114.x': [191.85, 190.11], + '114.y': [21.58, 16.09], + '115.height': [2.66, 1.98], + '115.width': [4.58, 3.42], + '115.x': [196.72, 193.74], + '115.y': [21.96, 16.37], + '116.height': [2.77, 2.07], + '116.width': [2.74, 2.04], + '116.x': [204.06, 199.21], + '116.y': [22.1, 16.48], + '117.height': [4.27, 3.18], + '117.width': [7.02, 5.23], + '117.x': [199.71, 195.97], + '117.y': [22.33, 16.65], + '118.height': [2.06, 1.54], + '118.width': [3.85, 2.87], + '118.x': [199.11, 195.52], + '118.y': [15.23, 11.36], + '119.height': [1.91, 1.43], + '119.width': [4.82, 3.59], + '119.x': [199.03, 195.46], + '119.y': [13.94, 10.4], + '120.height': [1.68, 1.25], + '120.width': [3.09, 2.31], + '120.x': [200.17, 196.31], + '120.y': [12.66, 9.44], + '121.height': [6.79, 5.06], + '121.width': [6.34, 4.73], + '121.x': [189.16, 188.1], + '121.y': [16.38, 12.21], + '122.height': [2.92, 2.18], + '122.width': [4.58, 3.42], + '122.x': [201.56, 197.34], + '122.y': [26.07, 19.44], + '123.height': [6.97, 5.2], + '123.width': [5.18, 3.86], + '123.x': [200.32, 196.42], + '123.y': [28.41, 21.18], + '124.height': [6.35, 4.73], + '124.width': [14.97, 11.16], + '124.x': [204.58, 199.6], + '124.y': [28.1, 20.95], + '125.height': [3.02, 2.25], + '125.width': [1.43, 1.07], + '125.x': [199.44, 195.76], + '125.y': [27.57, 20.55], + '126.height': [3.85, 2.87], + '126.width': [4.2, 3.13], + '126.x': [195, 192.45], + '126.y': [23.92, 17.83], + '127.height': [1.92, 1.43], + '127.width': [3.18, 2.37], + '127.x': [189.37, 188.26], + '127.y': [22.69, 16.91], + '128.height': [0.62, 0.46], + '128.width': [0.39, 0.29], + '128.x': [189.02, 188], + '128.y': [20.6, 15.36], + '129.height': [1.74, 1.29], + '129.width': [2.56, 1.91], + '129.x': [186.76, 186.31], + '129.y': [19.4, 14.46], + '130.height': [2.36, 1.76], + '130.width': [2.56, 1.91], + '130.x': [187.31, 186.72], + '130.y': [17.63, 13.14], + '131.height': [5.44, 4.06], + '131.width': [2.48, 1.85], + '131.x': [177.72, 179.57], + '131.y': [27.96, 20.85], + '132.height': [7.78, 5.8], + '132.width': [9.27, 6.91], + '132.x': [178.01, 179.79], + '132.y': [26.54, 19.79], + '133.height': [2.97, 2.21], + '133.width': [2.79, 2.08], + '133.x': [178.06, 179.83], + '133.y': [16.26, 12.12], + '134.height': [2.55, 1.9], + '134.width': [1.7, 1.27], + '134.x': [321.27, 286.59], + '134.y': [97.24, 72.49], + '135.height': [4.85, 3.61], + '135.width': [4.32, 3.22], + '135.x': [318.5, 284.52], + '135.y': [81.91, 61.06], + '136.height': [12.07, 9], + '136.width': [16.14, 12.03], + '136.x': [306.19, 275.34], + '136.y': [112.75, 84.06], + '137.height': [35.4, 26.39], + '137.width': [34.59, 25.79], + '137.x': [275.22, 252.26], + '137.y': [86.57, 64.54], + '138.height': [4.42, 3.3], + '138.width': [1.84, 1.37], + '138.x': [252.88, 235.61], + '138.y': [63.01, 46.97], + '139.height': [35.83, 26.71], + '139.width': [42.15, 31.42], + '139.x': [241.04, 226.78], + '139.y': [17.68, 13.18], + '140.height': [3.66, 2.73], + '140.width': [1.14, 0.85], + '140.x': [283.69, 258.57], + '140.y': [45.64, 34.03], + '141.height': [10.28, 7.66], + '141.width': [9.06, 6.75], + '141.x': [189.95, 188.69], + '141.y': [23.35, 17.41], + '142.height': [2.4, 1.79], + '142.width': [3.14, 2.34], + '142.x': [190.39, 189.02], + '142.y': [14.14, 10.54], + '143.height': [7.33, 5.46], + '143.width': [6.33, 4.72], + '143.x': [179.84, 181.15], + '143.y': [13.42, 10], + '144.height': [2.06, 1.54], + '144.width': [6.48, 4.83], + '144.x': [170.19, 173.96], + '144.y': [7.72, 5.76], + '145.height': [3.58, 2.67], + '145.width': [4.32, 3.22], + '145.x': [218.85, 210.23], + '145.y': [28.38, 21.15], + '146.height': [2.43, 1.81], + '146.width': [5.48, 4.09], + '146.x': [214.64, 207.09], + '146.y': [26.73, 19.93], + '147.height': [14.71, 10.97], + '147.width': [8.12, 6.05], + '147.x': [284.79, 259.39], + '147.y': [53.17, 39.63], + '148.height': [7.09, 5.28], + '148.width': [16.39, 12.22], + '148.x': [270.41, 248.67], + '148.y': [66.33, 49.45], + '149.height': [1.66, 1.24], + '149.width': [1, 0.74], + '149.x': [282.61, 257.77], + '149.y': [68.03, 50.72], + '150.height': [1.32, 0.98], + '150.width': [2.05, 1.53], + '150.x': [194.97, 192.44], + '150.y': [23.6, 17.59], + '151.height': [7, 5.22], + '151.width': [7.63, 5.69], + '151.x': [197.11, 194.02], + '151.y': [5.48, 4.09], + '152.height': [1.66, 1.24], + '152.width': [3.98, 2.97], + '152.x': [197.06, 193.99], + '152.y': [21.1, 15.73], + '153.height': [2.31, 1.72], + '153.width': [4.74, 3.54], + '153.x': [193.62, 191.43], + '153.y': [19.72, 14.7], + '154.height': [6.27, 4.67], + '154.width': [5.85, 4.36], + '154.x': [215.6, 207.81], + '154.y': [53.74, 40.06], + '155.height': [14.64, 10.91], + '155.width': [7.48, 5.58], + '155.x': [286.98, 261.02], + '155.y': [24.82, 18.5], + '156.height': [9.04, 6.74], + '156.width': [7.29, 5.43], + '156.x': [133.26, 146.43], + '156.y': [96.39, 71.86], + '157.height': [7.25, 5.4], + '157.width': [8.69, 6.48], + '157.x': [220.86, 211.73], + '157.y': [52.61, 39.22], + '158.height': [17.33, 12.92], + '158.width': [18.02, 13.43], + '158.x': [212.96, 205.85], + '158.y': [38.27, 28.53], + '159.height': [10.62, 7.92], + '159.width': [190.07, 141.7], + '159.x': [92.62, 116.13], + '159.y': [138.68, 103.38], + '160.height': [0.69, 0.52], + '160.width': [1.36, 1.01], + '160.x': [210.55, 204.04], + '160.y': [34.6, 25.8], + '161.height': [0.62, 0.47], + '161.width': [1.38, 1.03], + '161.x': [210.18, 203.77], + '161.y': [35.12, 26.18], + '162.height': [15.4, 11.48], + '162.width': [13.2, 9.84], + '162.x': [170.92, 174.5], + '162.y': [34.51, 25.73], + '163.height': [10.4, 7.75], + '163.width': [10.69, 7.97], + '163.x': [204.76, 199.73], + '163.y': [38.87, 28.98], + '164.height': [14.72, 10.98], + '164.width': [13.2, 9.84], + '164.x': [192.58, 190.65], + '164.y': [37.24, 27.76], + '165.height': [13.2, 9.84], + '165.width': [12.63, 9.42], + '165.x': [213.08, 205.93], + '165.y': [57.16, 42.61], + '166.height': [2.02, 1.51], + '166.width': [1.35, 1.01], + '166.x': [220.31, 211.32], + '166.y': [59.73, 44.53], + '167.height': [3.97, 2.96], + '167.width': [5.48, 4.09], + '167.x': [221.13, 211.94], + '167.y': [61.14, 45.58], + '168.height': [6.56, 4.89], + '168.width': [4.67, 3.48], + '168.x': [210.32, 203.87], + '168.y': [69.41, 51.74], + '169.height': [2.05, 1.53], + '169.width': [1.54, 1.15], + '169.x': [209.83, 203.51], + '169.y': [75.62, 56.37], + '170.height': [2.49, 1.85], + '170.width': [2.91, 2.17], + '170.x': [196.57, 193.62], + '170.y': [25.12, 18.73], + '171.height': [1.45, 1.08], + '171.width': [1.89, 1.41], + '171.x': [200.38, 196.46], + '171.y': [27.93, 20.82], + '172.height': [3.77, 2.81], + '172.width': [3.35, 2.5], + '172.x': [198.72, 195.23], + '172.y': [24.23, 18.07], + '173.height': [1.6, 1.19], + '173.width': [1.37, 1.02], + '173.x': [198.77, 195.27], + '173.y': [26.76, 19.95], + '174.height': [1.39, 1.04], + '174.width': [1.26, 0.94], + '174.x': [199.97, 196.16], + '174.y': [27, 20.13], + '175.height': [1.02, 0.76], + '175.width': [0.96, 0.71], + '175.x': [132.36, 145.76], + '175.y': [61.79, 46.06], + '176.height': [10.02, 7.47], + '176.width': [9.81, 7.31], + '176.x': [205.34, 200.16], + '176.y': [60.24, 44.91], + }, + legend: { + 'continuousLegend.bounds.height': [61, 99], + 'continuousLegend.bar.y': [128.7, 143.7], + }, + }, + style: { + 'legends.continuousLegend.title': ['GDP per capita (US$) ($)', 'GDP per capita (US$)'], + }, + }, + '../gallery/showcase.stories.tsx.worldMapSpec @1280': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [162, 124], + }, + area: { + 'rect.height': [162, 124], + 'rect.y': [153.2, 191.2], + }, + marks: { + '0.height': [2.77, 2.12], + '0.width': [328.1, 251.14], + '0.x': [455.95, 494.43], + '0.y': [100.54, 76.96], + '1.height': [13.42, 10.27], + '1.width': [9.95, 7.61], + '1.x': [647.21, 640.83], + '1.y': [81.82, 62.63], + '2.height': [7.93, 6.07], + '2.width': [7.74, 5.92], + '2.x': [604.66, 608.26], + '2.y': [46.74, 35.78], + '3.height': [30.89, 23.64], + '3.width': [64.23, 49.16], + '3.x': [520.95, 544.18], + '3.y': [0.1, 0.07], + '4.height': [51.97, 39.78], + '4.width': [90.05, 68.93], + '4.x': [476.8, 510.39], + '4.y': [5.22, 3.99], + '5.height': [14.66, 11.22], + '5.width': [31.35, 24], + '5.x': [656, 647.56], + '5.y': [17.42, 13.33], + '6.height': [9.01, 6.9], + '6.width': [15.29, 11.7], + '6.x': [664.52, 654.08], + '6.y': [26.89, 20.59], + '7.height': [10.16, 7.78], + '7.width': [14.26, 10.92], + '7.x': [750.2, 719.66], + '7.y': [83.76, 64.11], + '8.height': [19.78, 15.14], + '8.width': [42.58, 32.59], + '8.x': [708.31, 687.6], + '8.y': [73.78, 56.47], + '9.height': [36.13, 27.65], + '9.width': [13.77, 10.54], + '9.x': [559, 573.31], + '9.y': [107.6, 82.36], + '10.height': [41.61, 31.85], + '10.width': [14.58, 11.16], + '10.x': [556.23, 571.19], + '10.y': [102.45, 78.42], + '11.height': [23.08, 17.67], + '11.width': [17.66, 13.52], + '11.x': [631.29, 628.64], + '11.y': [74.06, 56.69], + '12.height': [17.09, 13.08], + '12.width': [8.98, 6.87], + '12.x': [658.04, 649.12], + '12.y': [65.64, 50.25], + '13.height': [12.73, 9.75], + '13.width': [7.35, 5.63], + '13.x': [651.48, 644.09], + '13.y': [73.75, 56.45], + '14.height': [16.89, 12.93], + '14.width': [14.7, 11.25], + '14.x': [640.14, 635.42], + '14.y': [53.46, 40.92], + '15.height': [19.59, 14.99], + '15.width': [9.41, 7.2], + '15.x': [632.39, 629.48], + '15.y': [51.77, 39.63], + '16.height': [2.29, 1.75], + '16.width': [2.74, 2.1], + '16.x': [552.53, 568.36], + '16.y': [55.98, 42.85], + '17.height': [2.78, 2.13], + '17.width': [3.28, 2.51], + '17.x': [554.86, 570.14], + '17.y': [56.01, 42.87], + '18.height': [30.9, 23.65], + '18.width': [242.18, 185.37], + '18.x': [500.34, 528.41], + '18.y': [0.65, 0.5], + '19.height': [3.95, 3.02], + '19.width': [1.78, 1.36], + '19.x': [550.35, 566.69], + '19.y': [47.47, 36.33], + '20.height': [1.14, 0.88], + '20.width': [2.49, 1.91], + '20.x': [573.83, 584.66], + '20.y': [139.85, 107.05], + '21.height': [14.2, 10.87], + '21.width': [16.27, 12.45], + '21.x': [623.42, 622.62], + '21.y': [0.84, 0.64], + '22.height': [13.38, 10.24], + '22.width': [35.75, 27.36], + '22.x': [577.32, 587.33], + '23.height': [1.13, 0.87], + '23.width': [1.68, 1.28], + '23.x': [672.76, 660.39], + '23.y': [137.43, 105.2], + '24.height': [1.39, 1.07], + '24.width': [2.26, 1.73], + '24.x': [735.4, 708.33], + '24.y': [90.96, 69.63], + '25.height': [14.85, 11.36], + '25.width': [14.63, 11.2], + '25.x': [634.29, 630.94], + '25.y': [107.91, 82.6], + '26.height': [2.32, 1.77], + '26.width': [2.09, 1.6], + '26.x': [643.47, 637.96], + '26.y': [115.68, 88.55], + '27.height': [21.66, 16.58], + '27.width': [22.97, 17.58], + '27.x': [519.05, 542.73], + '27.y': [40.88, 31.29], + '28.height': [5.53, 4.23], + '28.width': [4.52, 3.46], + '28.x': [569.96, 581.7], + '28.y': [117.38, 89.85], + '29.height': [47.5, 36.36], + '29.width': [36.3, 27.79], + '29.x': [551.57, 567.62], + '29.y': [74.07, 56.7], + '30.height': [16.03, 12.27], + '30.width': [11.89, 9.1], + '30.x': [555.99, 571], + '30.y': [92.82, 71.04], + '31.height': [22.68, 17.36], + '31.width': [12.7, 9.72], + '31.x': [544.51, 562.22], + '31.y': [80.7, 61.77], + '32.height': [20.87, 15.98], + '32.width': [11.24, 8.61], + '32.x': [546.65, 563.86], + '32.y': [65.13, 49.85], + '33.height': [2.97, 2.28], + '33.width': [5.26, 4.03], + '33.x': [543.32, 561.31], + '33.y': [68.64, 52.54], + '34.height': [3.72, 2.84], + '34.width': [2.97, 2.28], + '34.x': [540.87, 559.43], + '34.y': [66.64, 51.01], + '35.height': [5.3, 4.05], + '35.width': [4.47, 3.42], + '35.x': [539.56, 558.43], + '35.y': [61.95, 47.42], + '36.height': [3.72, 2.84], + '36.width': [5.77, 4.42], + '36.x': [538.26, 557.44], + '36.y': [60.74, 46.49], + '37.height': [1.57, 1.2], + '37.width': [2.18, 1.67], + '37.x': [537.47, 556.83], + '37.y': [62.68, 47.98], + '38.height': [5.01, 3.83], + '38.width': [3.87, 2.97], + '38.x': [535.66, 555.44], + '38.y': [58.52, 44.8], + '39.height': [3.19, 2.44], + '39.width': [1.52, 1.16], + '39.x': [538.64, 557.73], + '39.y': [57.69, 44.16], + '40.height': [14.25, 10.91], + '40.width': [12.45, 9.53], + '40.x': [552.33, 568.2], + '40.y': [65.47, 50.12], + '41.height': [8.86, 6.78], + '41.width': [4.39, 3.36], + '41.x': [563.11, 576.45], + '41.y': [70.18, 53.72], + '42.height': [5.26, 4.02], + '42.width': [3.85, 2.95], + '42.x': [566.15, 578.78], + '42.y': [73.1, 55.95], + '43.height': [56.7, 43.4], + '43.width': [58.38, 44.69], + '43.x': [569.38, 581.25], + '43.y': [21.36, 16.35], + '44.height': [7.93, 6.07], + '44.width': [5.3, 4.06], + '44.x': [544.83, 562.46], + '44.y': [78.9, 60.39], + '45.height': [0.7, 0.53], + '45.width': [1.49, 1.14], + '45.x': [559.06, 573.35], + '45.y': [57.67, 44.14], + '46.height': [1, 0.77], + '46.width': [1.88, 1.44], + '46.x': [548.99, 565.65], + '46.y': [57.67, 44.14], + '47.height': [4.01, 3.07], + '47.width': [9.34, 7.15], + '47.x': [543.81, 561.68], + '47.y': [52.04, 39.83], + '48.height': [8.22, 6.29], + '48.width': [6.96, 5.33], + '48.x': [642.93, 637.55], + '48.y': [99.91, 76.48], + '49.height': [11, 8.42], + '49.width': [8.71, 6.67], + '49.x': [637.66, 633.52], + '49.y': [102.55, 78.49], + '50.height': [14.48, 11.08], + '50.width': [12.11, 9.27], + '50.x': [630.66, 628.16], + '50.y': [101.67, 77.82], + '51.height': [5.25, 4.02], + '51.width': [5.59, 4.28], + '51.x': [603.89, 607.67], + '51.y': [60.02, 45.94], + '52.height': [18.13, 13.87], + '52.width': [15.01, 11.49], + '52.x': [608.87, 611.48], + '52.y': [49.91, 38.2], + '53.height': [15.4, 11.79], + '53.width': [10.97, 8.4], + '53.x': [604.66, 608.26], + '53.y': [47.05, 36.01], + '54.height': [7.57, 5.8], + '54.width': [2.78, 2.13], + '54.x': [620.71, 620.54], + '54.y': [65.38, 50.05], + '55.height': [14.4, 11.02], + '55.width': [14.05, 10.76], + '55.x': [620.27, 620.21], + '55.y': [51.7, 39.57], + '56.height': [11.96, 9.15], + '56.width': [10.9, 8.35], + '56.x': [622.49, 621.91], + '56.y': [63.37, 48.51], + '57.height': [13.86, 10.61], + '57.width': [6.99, 5.35], + '57.x': [627.87, 626.02], + '57.y': [64.61, 49.46], + '58.height': [6.33, 4.85], + '58.width': [1.77, 1.36], + '58.x': [619.96, 619.97], + '58.y': [66.89, 51.2], + '59.height': [7.95, 6.09], + '59.width': [3.99, 3.05], + '59.x': [616.99, 617.7], + '59.y': [66.79, 51.12], + '60.height': [7.7, 5.9], + '60.width': [5.6, 4.28], + '60.x': [612.03, 613.9], + '60.y': [67.5, 51.67], + '61.height': [6.55, 5.01], + '61.width': [6.69, 5.12], + '61.x': [606.07, 609.34], + '61.y': [64.95, 49.71], + '62.height': [1.96, 1.5], + '62.width': [2.74, 2.1], + '62.x': [604.68, 608.28], + '62.y': [64.9, 49.67], + '63.height': [5.22, 4], + '63.width': [3.6, 2.76], + '63.x': [609.41, 611.9], + '63.y': [69.96, 53.55], + '64.height': [4.06, 3.11], + '64.width': [2.78, 2.13], + '64.x': [607.77, 610.64], + '64.y': [68.09, 52.12], + '65.height': [6.8, 5.21], + '65.width': [7.03, 5.38], + '65.x': [614.96, 616.15], + '65.y': [61.83, 47.33], + '66.height': [11.06, 8.47], + '66.width': [11.97, 9.16], + '66.x': [633.4, 630.26], + '66.y': [66.73, 51.08], + '67.height': [10.96, 8.39], + '67.width': [6.83, 5.23], + '67.x': [630.29, 627.88], + '67.y': [75.97, 58.15], + '68.height': [7.89, 6.04], + '68.width': [5.23, 4], + '68.x': [628.17, 626.25], + '68.y': [77.72, 59.49], + '69.height': [1.59, 1.22], + '69.width': [1.84, 1.41], + '69.x': [628.64, 626.61], + '69.y': [77.77, 59.53], + '70.height': [11.99, 9.18], + '70.width': [10.9, 8.35], + '70.x': [639.95, 635.27], + '70.y': [90.92, 69.59], + '71.height': [9.34, 7.15], + '71.width': [2.69, 2.06], + '71.x': [649.94, 642.92], + '71.y': [92.16, 70.54], + '72.height': [19.94, 15.27], + '72.width': [9.69, 7.42], + '72.x': [647.59, 641.12], + '72.y': [93.5, 71.57], + '73.height': [1.92, 1.47], + '73.width': [1.22, 0.94], + '73.x': [647.03, 640.69], + '73.y': [112.17, 85.86], + '74.height': [16.69, 12.78], + '74.width': [11.53, 8.82], + '74.x': [630.59, 628.11], + '74.y': [86.18, 65.97], + '75.height': [2.69, 2.06], + '75.width': [1.6, 1.22], + '75.x': [646.94, 640.62], + '75.y': [83.57, 63.97], + '76.height': [4.34, 3.32], + '76.width': [1.11, 0.85], + '76.x': [649.6, 642.66], + '76.y': [40.25, 30.81], + '77.height': [1.76, 1.35], + '77.width': [1.09, 0.83], + '77.x': [650.07, 643.01], + '77.y': [38.7, 29.62], + '78.height': [16.46, 12.6], + '78.width': [7.34, 5.62], + '78.x': [658.75, 649.66], + '78.y': [95.64, 73.21], + '79.height': [1.35, 1.03], + '79.width': [0.5, 0.38], + '79.x': [650.12, 643.05], + '79.y': [41.09, 31.46], + '80.height': [0.92, 0.7], + '80.width': [2.76, 2.11], + '80.x': [604.55, 608.18], + '80.y': [63.36, 48.5], + '81.height': [7.97, 6.1], + '81.width': [3.42, 2.62], + '81.x': [626.41, 624.91], + '81.y': [35.68, 27.31], + '82.height': [21.08, 16.13], + '82.width': [18.33, 14.03], + '82.x': [612.37, 614.16], + '82.y': [35.94, 27.51], + '83.height': [4.81, 3.68], + '83.width': [3.3, 2.52], + '83.x': [650.41, 643.27], + '83.y': [40.13, 30.72], + '84.height': [4.24, 3.25], + '84.width': [4.16, 3.18], + '84.x': [665.87, 655.11], + '84.y': [48.62, 37.22], + '85.height': [1.85, 1.41], + '85.width': [0.81, 0.62], + '85.x': [664.92, 654.39], + '85.y': [48.55, 37.17], + '86.height': [1.78, 1.37], + '86.width': [1.71, 1.31], + '86.x': [660.62, 651.09], + '86.y': [43.94, 33.63], + '87.height': [9.41, 7.2], + '87.width': [9.05, 6.93], + '87.x': [653.16, 645.38], + '87.y': [35.64, 27.28], + '88.height': [11.73, 8.98], + '88.width': [6.51, 4.99], + '88.x': [667.03, 656], + '88.y': [48.22, 36.91], + '89.height': [2.42, 1.85], + '89.width': [0.71, 0.54], + '89.x': [772.12, 736.44], + '89.y': [98.83, 75.65], + '90.height': [5.05, 3.86], + '90.width': [4.91, 3.76], + '90.x': [713.82, 691.81], + '90.y': [62.5, 47.84], + '91.height': [18.15, 13.89], + '91.width': [8.27, 6.33], + '91.x': [708.21, 687.52], + '91.y': [55.37, 42.38], + '92.height': [10.45, 8], + '92.width': [8.09, 6.2], + '92.x': [710.18, 689.03], + '92.y': [52.9, 40.49], + '93.height': [22.29, 17.06], + '93.width': [8.67, 6.64], + '93.x': [702.87, 683.43], + '93.y': [45.94, 35.17], + '94.height': [18.05, 13.82], + '94.width': [8.99, 6.88], + '94.x': [711.43, 689.99], + '94.y': [51.84, 39.68], + '95.height': [5.73, 4.39], + '95.width': [4.26, 3.26], + '95.x': [722.34, 698.33], + '95.y': [29.6, 22.66], + '96.height': [4.69, 3.59], + '96.width': [4.07, 3.11], + '96.x': [725.28, 700.59], + '96.y': [34.29, 26.25], + '97.height': [10.56, 8.09], + '97.width': [26.47, 20.26], + '97.x': [687.61, 671.75], + '97.y': [20.51, 15.7], + '98.height': [32.93, 25.21], + '98.width': [24.7, 18.9], + '98.x': [680.75, 666.5], + '98.y': [37.75, 28.89], + '99.height': [6.9, 5.28], + '99.width': [5.22, 3.99], + '99.x': [698.01, 679.71], + '99.y': [48.16, 36.87], + '100.height': [1.85, 1.42], + '100.width': [2.98, 2.28], + '100.x': [698.06, 679.75], + '100.y': [45.99, 35.2], + '101.height': [4.7, 3.6], + '101.width': [7.73, 5.91], + '101.x': [689.95, 673.54], + '101.y': [43.52, 33.31], + '102.height': [15.51, 11.87], + '102.width': [12.86, 9.85], + '102.x': [672.93, 660.51], + '102.y': [35.92, 27.5], + '103.height': [10.36, 7.93], + '103.width': [11.29, 8.64], + '103.x': [671.66, 659.54], + '103.y': [34.43, 26.36], + '104.height': [4.61, 3.53], + '104.width': [6.88, 5.26], + '104.x': [675.81, 662.72], + '104.y': [31.75, 24.3], + '105.height': [4.3, 3.29], + '105.width': [7.85, 6.01], + '105.x': [677.22, 663.8], + '105.y': [29.27, 22.4], + '106.height': [8.15, 6.24], + '106.width': [12.91, 9.88], + '106.x': [662.73, 652.7], + '106.y': [29.85, 22.85], + '107.height': [16.69, 12.77], + '107.width': [19.34, 14.8], + '107.x': [656.44, 647.89], + '107.y': [33.1, 25.33], + '108.height': [5.53, 4.23], + '108.width': [5.09, 3.89], + '108.x': [650.36, 643.24], + '108.y': [35.82, 27.41], + '109.height': [2.71, 2.07], + '109.width': [2.95, 2.25], + '109.x': [655.63, 647.27], + '109.y': [31.44, 24.07], + '110.height': [10.81, 8.28], + '110.width': [7.91, 6.06], + '110.x': [627.8, 625.97], + '110.y': [6.62, 5.07], + '111.height': [4.49, 3.44], + '111.width': [6.94, 5.32], + '111.x': [637.4, 633.32], + '111.y': [16.71, 12.79], + '112.height': [6.96, 5.33], + '112.width': [13.87, 10.61], + '112.x': [637.13, 633.11], + '112.y': [20.23, 15.49], + '113.height': [5.53, 4.23], + '113.width': [7.82, 5.99], + '113.x': [630.48, 628.02], + '113.y': [17.9, 13.7], + '114.height': [2.61, 2], + '114.width': [5.77, 4.42], + '114.x': [627.43, 625.69], + '114.y': [23.42, 17.93], + '115.height': [2.89, 2.21], + '115.width': [4.97, 3.81], + '115.x': [632.72, 629.74], + '115.y': [23.83, 18.24], + '116.height': [3.01, 2.3], + '116.width': [2.97, 2.27], + '116.x': [640.69, 635.83], + '116.y': [23.99, 18.36], + '117.height': [4.63, 3.55], + '117.width': [7.61, 5.83], + '117.x': [635.96, 632.22], + '117.y': [24.23, 18.55], + '118.height': [2.24, 1.71], + '118.width': [4.18, 3.2], + '118.x': [635.31, 631.72], + '118.y': [16.53, 12.65], + '119.height': [2.08, 1.59], + '119.width': [5.23, 4], + '119.x': [635.22, 631.65], + '119.y': [15.13, 11.58], + '120.height': [1.82, 1.4], + '120.width': [3.36, 2.57], + '120.x': [636.46, 632.6], + '120.y': [13.74, 10.51], + '121.height': [7.37, 5.64], + '121.width': [6.88, 5.27], + '121.x': [624.52, 623.46], + '121.y': [17.78, 13.61], + '122.height': [3.17, 2.42], + '122.width': [4.97, 3.81], + '122.x': [637.97, 633.75], + '122.y': [28.29, 21.65], + '123.height': [7.57, 5.79], + '123.width': [5.62, 4.3], + '123.x': [636.63, 632.73], + '123.y': [30.83, 23.59], + '124.height': [6.89, 5.27], + '124.width': [16.24, 12.43], + '124.x': [641.25, 636.26], + '124.y': [30.49, 23.34], + '125.height': [3.28, 2.51], + '125.width': [1.56, 1.19], + '125.x': [635.67, 631.99], + '125.y': [29.91, 22.9], + '126.height': [4.17, 3.19], + '126.width': [4.56, 3.49], + '126.x': [630.85, 628.3], + '126.y': [25.96, 19.87], + '127.height': [2.08, 1.59], + '127.width': [3.45, 2.64], + '127.x': [624.75, 623.63], + '127.y': [24.62, 18.84], + '128.height': [0.67, 0.51], + '128.width': [0.42, 0.32], + '128.x': [624.36, 623.34], + '128.y': [22.35, 17.11], + '129.height': [1.88, 1.44], + '129.width': [2.78, 2.13], + '129.x': [621.91, 621.46], + '129.y': [21.05, 16.11], + '130.height': [2.56, 1.96], + '130.width': [2.78, 2.13], + '130.x': [622.51, 621.92], + '130.y': [19.13, 14.64], + '131.height': [5.9, 4.52], + '131.width': [2.69, 2.06], + '131.x': [612.1, 613.95], + '131.y': [30.34, 23.23], + '132.height': [8.44, 6.46], + '132.width': [10.05, 7.7], + '132.x': [612.42, 614.2], + '132.y': [28.8, 22.04], + '133.height': [3.22, 2.47], + '133.width': [3.03, 2.32], + '133.x': [612.47, 614.24], + '133.y': [17.64, 13.5], + '134.height': [2.77, 2.12], + '134.width': [1.84, 1.41], + '134.x': [767.86, 733.18], + '134.y': [105.52, 80.77], + '135.height': [5.26, 4.02], + '135.width': [4.69, 3.59], + '135.x': [764.86, 730.88], + '135.y': [88.88, 68.03], + '136.height': [13.1, 10.03], + '136.width': [17.51, 13.41], + '136.x': [751.5, 720.65], + '136.y': [122.34, 93.65], + '137.height': [38.41, 29.4], + '137.width': [37.54, 28.73], + '137.x': [717.9, 694.93], + '137.y': [93.94, 71.9], + '138.height': [4.8, 3.67], + '138.width': [1.99, 1.52], + '138.x': [693.66, 676.38], + '138.y': [68.37, 52.33], + '139.height': [38.88, 29.76], + '139.width': [45.73, 35.01], + '139.x': [680.81, 666.54], + '139.y': [19.18, 14.68], + '140.height': [3.97, 3.04], + '140.width': [1.24, 0.95], + '140.x': [727.08, 701.96], + '140.y': [49.52, 37.91], + '141.height': [11.15, 8.54], + '141.width': [9.83, 7.52], + '141.x': [625.37, 624.11], + '141.y': [25.34, 19.4], + '142.height': [2.61, 2], + '142.width': [3.41, 2.61], + '142.x': [625.85, 624.48], + '142.y': [15.34, 11.74], + '143.height': [7.95, 6.09], + '143.width': [6.86, 5.25], + '143.x': [614.4, 615.71], + '143.y': [14.56, 11.15], + '144.height': [2.24, 1.71], + '144.width': [7.03, 5.38], + '144.x': [603.93, 607.7], + '144.y': [8.38, 6.41], + '145.height': [3.88, 2.97], + '145.width': [4.69, 3.59], + '145.x': [656.73, 648.11], + '145.y': [30.79, 23.57], + '146.height': [2.64, 2.02], + '146.width': [5.95, 4.55], + '146.x': [652.16, 644.61], + '146.y': [29, 22.2], + '147.height': [15.97, 12.22], + '147.width': [8.81, 6.74], + '147.x': [728.28, 702.88], + '147.y': [57.69, 44.16], + '148.height': [7.69, 5.89], + '148.width': [17.78, 13.61], + '148.x': [712.67, 690.94], + '148.y': [71.97, 55.09], + '149.height': [1.8, 1.38], + '149.width': [1.08, 0.83], + '149.x': [725.91, 701.07], + '149.y': [73.82, 56.5], + '150.height': [1.43, 1.09], + '150.width': [2.22, 1.7], + '150.x': [630.82, 628.28], + '150.y': [25.6, 19.6], + '151.height': [7.59, 5.81], + '151.width': [8.28, 6.34], + '151.x': [633.14, 630.05], + '151.y': [5.95, 4.55], + '152.height': [1.8, 1.38], + '152.width': [4.32, 3.31], + '152.x': [633.09, 630.02], + '152.y': [22.89, 17.52], + '153.height': [2.5, 1.92], + '153.width': [5.15, 3.94], + '153.x': [629.36, 627.16], + '153.y': [21.39, 16.38], + '154.height': [6.8, 5.21], + '154.width': [6.35, 4.86], + '154.x': [653.2, 645.41], + '154.y': [58.31, 44.63], + '155.height': [15.89, 12.16], + '155.width': [8.12, 6.21], + '155.x': [730.65, 704.7], + '155.y': [26.93, 20.61], + '156.height': [9.81, 7.51], + '156.width': [7.91, 6.05], + '156.x': [563.86, 577.03], + '156.y': [104.59, 80.06], + '157.height': [7.86, 6.02], + '157.width': [9.43, 7.22], + '157.x': [658.91, 649.78], + '157.y': [57.09, 43.7], + '158.height': [18.8, 14.39], + '158.width': [19.55, 14.96], + '158.x': [650.34, 643.23], + '158.y': [41.52, 31.78], + '159.height': [11.53, 8.82], + '159.width': [206.24, 157.86], + '159.x': [519.76, 543.27], + '159.y': [150.47, 115.18], + '160.height': [0.75, 0.57], + '160.width': [1.48, 1.13], + '160.x': [647.72, 641.22], + '160.y': [37.55, 28.74], + '161.height': [0.68, 0.52], + '161.width': [1.5, 1.15], + '161.x': [647.32, 640.91], + '161.y': [38.11, 29.17], + '162.height': [16.71, 12.79], + '162.width': [14.32, 10.96], + '162.x': [604.72, 608.3], + '162.y': [37.45, 28.67], + '163.height': [11.28, 8.63], + '163.width': [11.6, 8.88], + '163.x': [641.44, 636.41], + '163.y': [42.18, 32.29], + '164.height': [15.98, 12.23], + '164.width': [14.32, 10.96], + '164.x': [628.22, 626.3], + '164.y': [40.41, 30.93], + '165.height': [14.33, 10.97], + '165.width': [13.71, 10.49], + '165.x': [650.47, 643.32], + '165.y': [62.02, 47.48], + '166.height': [2.19, 1.68], + '166.width': [1.47, 1.13], + '166.x': [658.31, 649.33], + '166.y': [64.81, 49.61], + '167.height': [4.3, 3.29], + '167.width': [5.95, 4.55], + '167.x': [659.21, 650.01], + '167.y': [66.34, 50.78], + '168.height': [7.12, 5.45], + '168.width': [5.06, 3.88], + '168.x': [647.47, 641.03], + '168.y': [75.32, 57.65], + '169.height': [2.23, 1.71], + '169.width': [1.67, 1.28], + '169.x': [646.94, 640.62], + '169.y': [82.05, 62.81], + '170.height': [2.7, 2.06], + '170.width': [3.16, 2.42], + '170.x': [632.55, 629.61], + '170.y': [27.26, 20.86], + '171.height': [1.58, 1.21], + '171.width': [2.05, 1.57], + '171.x': [636.68, 632.77], + '171.y': [30.3, 23.19], + '172.height': [4.09, 3.13], + '172.width': [3.64, 2.78], + '172.x': [634.89, 631.4], + '172.y': [26.3, 20.13], + '173.height': [1.74, 1.33], + '173.width': [1.48, 1.14], + '173.x': [634.94, 631.44], + '173.y': [29.03, 22.22], + '174.height': [1.51, 1.15], + '174.width': [1.37, 1.05], + '174.x': [636.25, 632.44], + '174.y': [29.3, 22.42], + '175.height': [1.1, 0.85], + '175.width': [1.04, 0.79], + '175.x': [562.89, 576.28], + '175.y': [67.05, 51.32], + '176.height': [10.87, 8.32], + '176.width': [10.64, 8.15], + '176.x': [642.07, 636.89], + '176.y': [65.37, 50.03], + }, + legend: { + 'continuousLegend.bounds.height': [61, 99], + 'continuousLegend.bar.y': [107.2, 122.2], + }, + }, + style: { + 'legends.continuousLegend.title': ['GDP per capita (US$) ($)', 'GDP per capita (US$)'], + }, + }, + '../testing/fixtures-maps.stories.tsx.worldEqualEarthSpec @390': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [292.4, 269.4], + }, + area: { + 'rect.height': [292.4, 269.4], + 'rect.y': [64, 87], + }, + marks: { + '0.y': [168.24, 156.74], + '1.y': [147.13, 135.63], + '2.y': [107.56, 96.06], + '3.y': [54.97, 43.47], + '4.y': [60.74, 49.24], + '5.y': [74.49, 62.99], + '6.y': [85.19, 73.69], + '7.y': [149.31, 137.81], + '8.y': [138.06, 126.56], + '9.y': [176.2, 164.7], + '10.y': [170.39, 158.89], + '11.y': [138.37, 126.87], + '12.y': [128.88, 117.38], + '13.y': [138.02, 126.52], + '14.y': [115.14, 103.64], + '15.y': [113.24, 101.74], + '16.y': [117.98, 106.48], + '17.y': [118.02, 106.52], + '18.y': [55.59, 44.09], + '19.y': [108.38, 96.88], + '20.y': [212.57, 201.07], + '21.y': [55.8, 44.3], + '22.y': [54.86, 43.36], + '23.y': [209.84, 198.34], + '24.y': [157.44, 145.94], + '25.y': [176.55, 165.05], + '26.y': [185.31, 173.81], + '27.y': [100.96, 89.46], + '28.y': [187.23, 175.73], + '29.y': [138.39, 126.89], + '30.y': [159.52, 148.02], + '31.y': [145.86, 134.36], + '32.y': [128.31, 116.81], + '33.y': [132.26, 120.76], + '34.y': [130.01, 118.51], + '35.y': [124.72, 113.22], + '36.y': [123.35, 111.85], + '37.y': [125.54, 114.04], + '38.y': [120.85, 109.35], + '39.y': [119.92, 108.42], + '40.y': [128.69, 117.19], + '41.y': [134, 122.5], + '42.y': [137.29, 125.79], + '43.y': [78.95, 67.45], + '44.y': [143.83, 132.33], + '45.y': [119.89, 108.39], + '46.y': [119.89, 108.39], + '47.y': [113.54, 102.04], + '48.y': [167.53, 156.03], + '49.y': [170.5, 159], + '50.y': [169.51, 158.01], + '51.y': [122.54, 111.04], + '52.y': [111.14, 99.64], + '53.y': [107.91, 96.41], + '54.y': [128.59, 117.09], + '55.y': [113.15, 101.65], + '56.y': [126.32, 114.82], + '57.y': [127.72, 116.22], + '58.y': [130.29, 118.79], + '59.y': [130.17, 118.67], + '60.y': [130.98, 119.48], + '61.y': [128.1, 116.6], + '62.y': [128.04, 116.54], + '63.y': [133.76, 122.26], + '64.y': [131.64, 120.14], + '65.y': [124.58, 113.08], + '66.y': [130.11, 118.61], + '67.y': [140.53, 129.03], + '68.y': [142.5, 131], + '69.y': [142.56, 131.06], + '70.y': [157.39, 145.89], + '71.y': [158.78, 147.28], + '72.y': [160.3, 148.8], + '73.y': [181.35, 169.85], + '74.y': [152.04, 140.54], + '75.y': [149.1, 137.6], + '76.y': [100.24, 88.74], + '77.y': [98.5, 87], + '78.y': [162.71, 151.21], + '79.y': [101.2, 89.7], + '80.y': [126.3, 114.8], + '81.y': [95.1, 83.6], + '82.y': [95.38, 83.88], + '83.y': [100.11, 88.61], + '84.y': [109.69, 98.19], + '85.y': [109.61, 98.11], + '86.y': [104.41, 92.91], + '87.y': [95.05, 83.55], + '88.y': [109.24, 97.74], + '89.y': [166.31, 154.81], + '90.y': [125.34, 113.84], + '91.y': [117.29, 105.79], + '92.y': [114.52, 103.02], + '93.y': [106.67, 95.17], + '94.y': [113.31, 101.81], + '95.y': [88.24, 76.74], + '96.y': [93.53, 82.03], + '97.y': [77.98, 66.48], + '98.y': [97.42, 85.92], + '99.y': [109.17, 97.67], + '100.y': [106.72, 95.22], + '101.y': [103.93, 92.43], + '102.y': [95.37, 83.87], + '103.y': [93.69, 82.19], + '104.y': [90.66, 79.16], + '105.y': [87.86, 76.36], + '106.y': [88.51, 77.01], + '107.y': [92.18, 80.68], + '108.y': [95.25, 83.75], + '109.y': [90.31, 78.81], + '110.y': [62.32, 50.82], + '111.y': [73.7, 62.2], + '112.y': [77.67, 66.17], + '113.y': [75.04, 63.54], + '114.y': [81.27, 69.77], + '115.y': [81.73, 70.23], + '116.y': [81.9, 70.4], + '117.y': [82.18, 70.68], + '118.y': [73.5, 62], + '119.y': [71.92, 60.42], + '120.y': [70.35, 58.85], + '121.y': [74.9, 63.4], + '122.y': [86.76, 75.26], + '123.y': [89.62, 78.12], + '124.y': [89.24, 77.74], + '125.y': [88.59, 77.09], + '126.y': [84.13, 72.63], + '127.y': [82.62, 71.12], + '128.y': [80.06, 68.56], + '129.y': [78.6, 67.1], + '130.y': [76.43, 64.93], + '131.y': [89.07, 77.57], + '132.y': [87.33, 75.83], + '133.y': [74.75, 63.25], + '134.y': [173.85, 162.35], + '135.y': [155.08, 143.58], + '136.y': [192.82, 181.32], + '137.y': [160.79, 149.29], + '138.y': [131.96, 120.46], + '139.y': [76.49, 64.99], + '140.y': [110.7, 99.2], + '141.y': [83.43, 71.93], + '142.y': [72.15, 60.65], + '143.y': [71.28, 59.78], + '144.y': [64.3, 52.8], + '145.y': [89.58, 78.08], + '146.y': [87.56, 76.06], + '147.y': [119.91, 108.41], + '148.y': [136.02, 124.52], + '149.y': [138.1, 126.6], + '150.y': [83.73, 72.23], + '151.y': [61.56, 50.06], + '152.y': [80.67, 69.17], + '153.y': [78.98, 67.48], + '154.y': [120.61, 109.11], + '155.y': [85.23, 73.73], + '156.y': [172.8, 161.3], + '157.y': [119.23, 107.73], + '158.y': [101.68, 90.18], + '159.y': [224.55, 213.05], + '160.y': [97.2, 85.7], + '161.y': [97.83, 86.33], + '162.y': [97.09, 85.59], + '163.y': [102.42, 90.92], + '164.y': [100.42, 88.92], + '165.y': [124.8, 113.3], + '166.y': [127.94, 116.44], + '167.y': [129.67, 118.17], + '168.y': [139.79, 128.29], + '169.y': [147.39, 135.89], + '170.y': [85.59, 74.09], + '171.y': [89.03, 77.53], + '172.y': [84.51, 73.01], + '173.y': [87.6, 76.1], + '174.y': [87.89, 76.39], + '175.y': [130.47, 118.97], + '176.y': [128.57, 117.07], + }, + legend: { + 'continuousLegend.bounds.height': [46, 69], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.worldEqualEarthSpec @1280': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [262.4, 239.4], + }, + area: { + 'rect.height': [262.4, 239.4], + 'rect.y': [74, 97], + }, + marks: { + '0.height': [4.48, 4.09], + '0.width': [531.44, 484.86], + '0.x': [354.28, 377.57], + '0.y': [162.85, 148.58], + '1.height': [21.74, 19.84], + '1.width': [16.11, 14.7], + '1.x': [664.07, 660.21], + '1.y': [132.53, 120.91], + '2.height': [12.84, 11.71], + '2.width': [12.53, 11.43], + '2.x': [595.15, 597.33], + '2.y': [75.71, 69.07], + '3.height': [50.03, 45.65], + '3.width': [104.03, 94.92], + '3.x': [459.56, 473.63], + '3.y': [0.16, 0.14], + '4.height': [84.18, 76.8], + '4.width': [145.86, 133.08], + '4.x': [388.06, 408.39], + '4.y': [8.45, 7.71], + '5.height': [23.74, 21.66], + '5.width': [50.78, 46.33], + '5.x': [678.32, 673.21], + '5.y': [28.21, 25.74], + '6.height': [14.6, 13.32], + '6.width': [24.76, 22.59], + '6.x': [692.11, 685.79], + '6.y': [43.56, 39.74], + '7.height': [16.46, 15.02], + '7.width': [23.1, 21.07], + '7.x': [830.89, 812.4], + '7.y': [135.67, 123.78], + '8.height': [32.03, 29.23], + '8.width': [68.97, 62.92], + '8.x': [763.05, 750.51], + '8.y': [119.51, 109.03], + '9.height': [58.52, 53.39], + '9.width': [22.3, 20.35], + '9.x': [521.2, 529.86], + '9.y': [174.29, 159.01], + '10.height': [67.39, 61.48], + '10.width': [23.62, 21.55], + '10.x': [516.72, 525.77], + '10.y': [165.94, 151.39], + '11.height': [37.39, 34.11], + '11.width': [28.6, 26.09], + '11.x': [638.28, 636.68], + '11.y': [119.96, 109.44], + '12.height': [27.69, 25.26], + '12.width': [14.55, 13.27], + '12.x': [681.62, 676.22], + '12.y': [106.33, 97.01], + '13.height': [20.62, 18.82], + '13.width': [11.91, 10.87], + '13.x': [670.99, 666.52], + '13.y': [119.45, 108.98], + '14.height': [27.36, 24.96], + '14.width': [23.81, 21.72], + '14.x': [652.62, 649.76], + '14.y': [86.59, 79], + '15.height': [31.73, 28.95], + '15.width': [15.24, 13.9], + '15.x': [640.07, 638.31], + '15.y': [83.85, 76.5], + '16.height': [3.71, 3.38], + '16.width': [4.44, 4.05], + '16.x': [510.72, 520.3], + '16.y': [90.67, 82.72], + '17.height': [4.5, 4.11], + '17.width': [5.32, 4.85], + '17.x': [514.48, 523.73], + '17.y': [90.73, 82.78], + '18.height': [50.05, 45.66], + '18.width': [392.28, 357.89], + '18.x': [426.17, 443.16], + '18.y': [1.05, 0.96], + '19.height': [6.39, 5.83], + '19.width': [2.88, 2.63], + '19.x': [507.18, 517.07], + '19.y': [76.88, 70.14], + '20.height': [1.85, 1.69], + '20.width': [4.04, 3.68], + '20.x': [545.22, 551.77], + '20.y': [226.52, 206.67], + '21.height': [23, 20.98], + '21.width': [26.36, 24.05], + '21.x': [625.55, 625.06], + '21.y': [1.36, 1.24], + '22.height': [21.67, 19.77], + '22.width': [57.91, 52.83], + '22.x': [550.87, 556.93], + '23.height': [1.83, 1.67], + '23.width': [2.72, 2.48], + '23.x': [705.46, 697.97], + '23.y': [222.61, 203.1], + '24.height': [2.26, 2.06], + '24.width': [3.66, 3.34], + '24.x': [806.92, 790.54], + '24.y': [147.34, 134.42], + '25.height': [24.05, 21.94], + '25.width': [23.7, 21.62], + '25.x': [643.15, 641.12], + '25.y': [174.79, 159.47], + '26.height': [3.75, 3.43], + '26.width': [3.39, 3.09], + '26.x': [658.01, 654.68], + '26.y': [187.38, 170.95], + '27.height': [35.09, 32.01], + '27.width': [37.21, 33.95], + '27.x': [456.49, 470.82], + '27.y': [66.22, 60.41], + '28.height': [8.95, 8.17], + '28.width': [7.32, 6.68], + '28.x': [538.94, 546.05], + '28.y': [190.13, 173.46], + '29.height': [76.93, 70.19], + '29.width': [58.8, 53.65], + '29.x': [509.16, 518.87], + '29.y': [119.98, 109.47], + '30.height': [25.97, 23.69], + '30.width': [19.26, 17.57], + '30.x': [516.31, 525.4], + '30.y': [150.34, 137.16], + '31.height': [36.74, 33.52], + '31.width': [20.58, 18.77], + '31.x': [497.73, 508.45], + '31.y': [130.72, 119.26], + '32.height': [33.81, 30.85], + '32.width': [18.21, 16.61], + '32.x': [501.19, 511.61], + '32.y': [105.5, 96.25], + '33.height': [4.82, 4.39], + '33.width': [8.52, 7.78], + '33.x': [495.8, 506.69], + '33.y': [111.17, 101.43], + '34.height': [6.02, 5.49], + '34.width': [4.82, 4.4], + '34.x': [491.83, 503.06], + '34.y': [107.94, 98.48], + '35.height': [8.58, 7.83], + '35.width': [7.25, 6.61], + '35.x': [489.71, 501.13], + '35.y': [100.35, 91.55], + '36.height': [6.02, 5.49], + '36.width': [9.35, 8.53], + '36.x': [487.61, 499.21], + '36.y': [98.39, 89.76], + '37.height': [2.55, 2.32], + '37.width': [3.53, 3.22], + '37.x': [486.32, 498.03], + '37.y': [101.53, 92.63], + '38.height': [8.11, 7.4], + '38.width': [6.28, 5.73], + '38.x': [483.38, 495.36], + '38.y': [94.79, 86.48], + '39.height': [5.17, 4.72], + '39.width': [2.46, 2.25], + '39.x': [488.22, 499.77], + '39.y': [93.45, 85.26], + '40.height': [23.08, 21.06], + '40.width': [20.17, 18.4], + '40.x': [510.39, 520], + '40.y': [106.05, 96.76], + '41.height': [14.36, 13.1], + '41.width': [7.11, 6.49], + '41.x': [527.85, 535.93], + '41.y': [113.68, 103.71], + '42.height': [8.52, 7.77], + '42.width': [6.24, 5.69], + '42.x': [532.78, 540.43], + '42.y': [118.4, 108.02], + '43.height': [91.84, 83.79], + '43.width': [94.56, 86.28], + '43.x': [538.01, 545.19], + '43.y': [34.61, 31.57], + '44.height': [12.84, 11.72], + '44.width': [8.58, 7.83], + '44.x': [498.24, 508.91], + '44.y': [127.8, 116.6], + '45.height': [1.13, 1.03], + '45.width': [2.42, 2.2], + '45.x': [521.29, 529.94], + '45.y': [93.41, 85.22], + '46.height': [1.62, 1.48], + '46.width': [3.04, 2.77], + '46.x': [504.98, 515.07], + '46.y': [93.4, 85.22], + '47.height': [6.5, 5.93], + '47.width': [15.13, 13.81], + '47.x': [496.6, 507.41], + '47.y': [84.28, 76.9], + '48.height': [13.31, 12.14], + '48.width': [11.28, 10.29], + '48.x': [657.14, 653.88], + '48.y': [161.83, 147.65], + '49.height': [17.82, 16.26], + '49.width': [14.11, 12.87], + '49.x': [648.61, 646.1], + '49.y': [166.1, 151.54], + '50.height': [23.45, 21.4], + '50.width': [19.61, 17.89], + '50.x': [637.27, 635.76], + '50.y': [164.68, 150.24], + '51.height': [8.5, 7.75], + '51.width': [9.05, 8.25], + '51.x': [593.9, 596.19], + '51.y': [97.21, 88.69], + '52.height': [29.36, 26.79], + '52.width': [24.32, 22.19], + '52.x': [601.98, 603.56], + '52.y': [80.84, 73.75], + '53.height': [24.94, 22.76], + '53.width': [17.78, 16.22], + '53.x': [595.15, 597.33], + '53.y': [76.2, 69.52], + '54.height': [12.26, 11.19], + '54.width': [4.51, 4.12], + '54.x': [621.15, 621.05], + '54.y': [105.9, 96.62], + '55.height': [23.32, 21.28], + '55.width': [22.77, 20.77], + '55.x': [620.44, 620.4], + '55.y': [83.74, 76.4], + '56.height': [19.37, 17.67], + '56.width': [17.66, 16.11], + '56.x': [624.04, 623.68], + '56.y': [102.64, 93.65], + '57.height': [22.45, 20.48], + '57.width': [11.33, 10.34], + '57.x': [632.75, 631.63], + '57.y': [104.66, 95.48], + '58.height': [10.25, 9.36], + '58.width': [2.87, 2.62], + '58.y': [108.34, 98.85], + '59.height': [12.88, 11.75], + '59.width': [6.46, 5.89], + '59.x': [615.13, 615.56], + '59.y': [108.18, 98.7], + '60.height': [12.48, 11.39], + '60.width': [9.07, 8.27], + '60.x': [607.1, 608.23], + '60.y': [109.33, 99.75], + '61.height': [10.61, 9.68], + '61.width': [10.84, 9.89], + '61.x': [597.44, 599.42], + '61.y': [105.2, 95.98], + '62.height': [3.18, 2.9], + '62.width': [4.44, 4.05], + '62.x': [595.19, 597.37], + '62.y': [105.12, 95.9], + '63.height': [8.45, 7.71], + '63.width': [5.83, 5.32], + '63.x': [602.85, 604.35], + '63.y': [113.33, 103.39], + '64.height': [6.57, 6], + '64.width': [4.5, 4.11], + '64.x': [600.19, 601.92], + '64.y': [110.29, 100.63], + '65.height': [11.02, 10.05], + '65.width': [11.39, 10.39], + '65.x': [611.84, 612.56], + '65.y': [100.15, 91.37], + '66.height': [17.91, 16.34], + '66.width': [19.39, 17.69], + '66.x': [641.71, 639.8], + '66.y': [108.09, 98.62], + '67.height': [17.76, 16.2], + '67.width': [11.06, 10.09], + '67.x': [636.67, 635.21], + '67.y': [123.05, 112.27], + '68.height': [12.77, 11.65], + '68.width': [8.47, 7.73], + '68.x': [633.23, 632.07], + '68.y': [125.89, 114.85], + '69.height': [2.58, 2.36], + '69.width': [2.98, 2.72], + '69.x': [634, 632.77], + '69.y': [125.97, 114.93], + '70.height': [19.42, 17.72], + '70.width': [17.66, 16.11], + '70.x': [652.31, 649.48], + '70.y': [147.27, 134.36], + '71.height': [15.13, 13.8], + '71.width': [4.35, 3.97], + '71.x': [668.5, 664.25], + '71.y': [149.27, 136.19], + '72.height': [32.3, 29.47], + '72.width': [15.7, 14.32], + '72.x': [664.68, 660.77], + '72.y': [151.45, 138.18], + '73.height': [3.1, 2.83], + '73.width': [1.98, 1.81], + '73.x': [663.78, 659.95], + '73.y': [181.69, 165.76], + '74.height': [27.04, 24.67], + '74.width': [18.67, 17.04], + '74.x': [637.16, 635.66], + '74.y': [139.59, 127.36], + '75.height': [4.36, 3.97], + '75.width': [2.59, 2.36], + '75.x': [663.64, 659.81], + '75.y': [135.36, 123.5], + '76.height': [7.03, 6.41], + '76.width': [1.79, 1.64], + '76.x': [667.95, 663.74], + '76.y': [65.19, 59.48], + '77.height': [2.85, 2.6], + '77.width': [1.77, 1.61], + '77.x': [668.7, 664.43], + '77.y': [62.68, 57.19], + '78.height': [26.66, 24.33], + '78.width': [11.9, 10.85], + '78.x': [682.77, 677.26], + '78.y': [154.91, 141.33], + '79.height': [2.19, 2], + '79.width': [0.81, 0.74], + '79.x': [668.79, 664.51], + '79.y': [66.56, 60.73], + '80.height': [1.49, 1.36], + '80.width': [4.47, 4.08], + '80.x': [594.98, 597.17], + '80.y': [102.62, 93.63], + '81.height': [12.91, 11.78], + '81.width': [5.55, 5.06], + '81.x': [630.38, 629.47], + '81.y': [57.8, 52.73], + '82.height': [34.14, 31.15], + '82.width': [29.7, 27.09], + '82.x': [607.64, 608.72], + '82.y': [58.21, 53.11], + '83.height': [7.79, 7.11], + '83.width': [5.34, 4.87], + '83.x': [669.25, 664.93], + '83.y': [65, 59.3], + '84.height': [6.87, 6.27], + '84.width': [6.74, 6.15], + '84.x': [694.3, 687.79], + '84.y': [78.76, 71.86], + '85.height': [2.99, 2.73], + '85.width': [1.31, 1.2], + '85.x': [692.77, 686.39], + '85.y': [78.65, 71.75], + '86.height': [2.89, 2.64], + '86.width': [2.77, 2.53], + '86.x': [685.79, 680.03], + '86.y': [71.17, 64.93], + '87.height': [15.24, 13.91], + '87.width': [14.66, 13.37], + '87.x': [673.7, 669], + '87.y': [57.73, 52.67], + '88.height': [19, 17.33], + '88.width': [10.55, 9.63], + '88.x': [696.18, 689.51], + '88.y': [78.11, 71.26], + '89.height': [3.92, 3.57], + '89.width': [1.14, 1.04], + '89.x': [866.4, 844.8], + '89.y': [160.08, 146.05], + '90.height': [8.17, 7.46], + '90.width': [7.96, 7.26], + '90.x': [771.96, 758.64], + '90.y': [101.24, 92.37], + '91.height': [29.4, 26.82], + '91.width': [13.4, 12.23], + '91.x': [762.88, 750.36], + '91.y': [89.68, 81.82], + '92.height': [16.92, 15.44], + '92.width': [13.11, 11.96], + '92.x': [766.07, 753.27], + '92.y': [85.69, 78.18], + '93.height': [36.11, 32.94], + '93.width': [14.05, 12.82], + '93.x': [754.23, 742.46], + '93.y': [74.42, 67.9], + '94.height': [29.24, 26.68], + '94.width': [14.56, 13.28], + '94.x': [768.1, 755.12], + '94.y': [83.97, 76.61], + '95.height': [9.28, 8.47], + '95.width': [6.89, 6.29], + '95.x': [785.76, 771.23], + '95.y': [47.94, 43.74], + '96.height': [7.6, 6.93], + '96.width': [6.59, 6.01], + '96.x': [790.54, 775.59], + '96.y': [55.55, 50.68], + '97.height': [17.11, 15.61], + '97.width': [42.87, 39.11], + '97.x': [729.51, 719.91], + '97.y': [33.22, 30.3], + '98.height': [53.34, 48.67], + '98.width': [40, 36.5], + '98.x': [718.41, 709.78], + '98.y': [61.14, 55.78], + '99.height': [11.18, 10.2], + '99.width': [8.45, 7.71], + '99.x': [746.35, 735.28], + '99.y': [78.01, 71.17], + '100.height': [3, 2.74], + '100.width': [4.83, 4.41], + '100.x': [746.44, 735.36], + '100.y': [74.49, 67.96], + '101.height': [7.62, 6.95], + '101.width': [12.51, 11.42], + '101.x': [733.3, 723.37], + '101.y': [70.49, 64.31], + '102.height': [25.13, 22.92], + '102.width': [20.83, 19.01], + '102.x': [705.73, 698.21], + '102.y': [58.18, 53.08], + '103.height': [16.79, 15.32], + '103.width': [18.28, 16.68], + '103.x': [703.67, 696.34], + '103.y': [55.77, 50.89], + '104.height': [7.47, 6.81], + '104.width': [11.14, 10.16], + '104.x': [710.4, 702.48], + '104.y': [51.43, 46.92], + '105.height': [6.96, 6.35], + '105.width': [12.72, 11.6], + '105.x': [712.69, 704.56], + '105.y': [47.41, 43.26], + '106.height': [13.2, 12.05], + '106.width': [20.91, 19.08], + '106.x': [689.21, 683.14], + '106.y': [48.34, 44.11], + '107.height': [27.03, 24.66], + '107.width': [31.32, 28.57], + '107.x': [679.02, 673.85], + '107.y': [53.61, 48.91], + '108.height': [8.96, 8.17], + '108.width': [8.24, 7.52], + '108.x': [669.18, 664.87], + '108.y': [58.01, 52.93], + '109.height': [4.39, 4.01], + '109.width': [4.77, 4.35], + '109.x': [677.71, 672.65], + '109.y': [50.93, 46.47], + '110.height': [17.51, 15.98], + '110.width': [12.82, 11.7], + '110.x': [632.64, 631.53], + '110.y': [10.73, 9.79], + '111.height': [7.27, 6.64], + '111.width': [11.25, 10.26], + '111.x': [648.19, 645.72], + '111.y': [27.07, 24.69], + '112.height': [11.28, 10.29], + '112.width': [22.46, 20.49], + '112.x': [647.75, 645.32], + '112.y': [32.77, 29.9], + '113.height': [8.96, 8.17], + '113.width': [12.67, 11.56], + '113.x': [636.97, 635.49], + '113.y': [28.99, 26.45], + '114.height': [4.23, 3.86], + '114.width': [9.35, 8.53], + '114.x': [632.04, 630.98], + '114.y': [37.93, 34.61], + '115.height': [4.68, 4.27], + '115.width': [8.05, 7.35], + '115.x': [640.61, 638.8], + '115.y': [38.6, 35.21], + '116.height': [4.88, 4.45], + '116.width': [4.81, 4.39], + '116.x': [653.5, 650.57], + '116.y': [38.85, 35.44], + '117.height': [7.5, 6.84], + '117.width': [12.33, 11.25], + '117.x': [645.86, 643.59], + '117.y': [39.25, 35.81], + '118.height': [3.62, 3.3], + '118.width': [6.76, 6.17], + '118.x': [644.79, 642.62], + '118.y': [26.77, 24.43], + '119.height': [3.36, 3.07], + '119.width': [8.47, 7.73], + '119.x': [644.66, 642.5], + '119.y': [24.51, 22.36], + '120.height': [2.96, 2.7], + '120.width': [5.44, 4.96], + '120.x': [646.67, 644.33], + '120.y': [22.25, 20.3], + '121.height': [11.94, 10.89], + '121.width': [11.15, 10.17], + '121.x': [627.32, 626.68], + '121.y': [28.8, 26.27], + '122.height': [5.13, 4.68], + '122.width': [8.06, 7.35], + '122.x': [649.1, 646.55], + '122.y': [45.82, 41.81], + '123.height': [12.25, 11.18], + '123.width': [9.1, 8.3], + '123.x': [646.93, 644.57], + '123.y': [49.93, 45.55], + '124.height': [11.16, 10.18], + '124.width': [26.3, 24], + '124.x': [654.42, 651.4], + '124.y': [49.39, 45.06], + '125.height': [5.31, 4.85], + '125.width': [2.52, 2.3], + '125.x': [645.38, 643.15], + '125.y': [48.45, 44.2], + '126.height': [6.76, 6.17], + '126.width': [7.39, 6.74], + '126.x': [637.57, 636.03], + '126.y': [42.05, 38.36], + '127.height': [3.37, 3.07], + '127.width': [5.59, 5.1], + '127.x': [627.69, 627.01], + '127.y': [39.88, 36.38], + '128.height': [1.09, 0.99], + '128.width': [0.69, 0.63], + '128.x': [627.07, 626.45], + '128.y': [36.2, 33.03], + '129.height': [3.05, 2.78], + '129.width': [4.5, 4.11], + '129.x': [623.09, 622.82], + '129.y': [34.1, 31.11], + '130.height': [4.15, 3.79], + '130.width': [4.5, 4.11], + '130.x': [624.07, 623.71], + '130.y': [30.99, 28.27], + '131.height': [9.56, 8.73], + '131.width': [4.36, 3.98], + '131.x': [607.2, 608.32], + '131.y': [49.15, 44.84], + '132.height': [13.67, 12.47], + '132.width': [16.29, 14.86], + '132.x': [607.72, 608.8], + '132.y': [46.65, 42.56], + '133.height': [5.22, 4.76], + '133.width': [4.91, 4.48], + '133.x': [607.8, 608.87], + '133.y': [28.58, 26.07], + '134.height': [4.48, 4.09], + '134.width': [2.99, 2.73], + '134.x': [859.5, 838.51], + '134.y': [170.91, 155.93], + '135.height': [8.52, 7.77], + '135.width': [7.59, 6.93], + '135.x': [854.64, 834.07], + '135.y': [143.96, 131.34], + '136.height': [21.22, 19.36], + '136.width': [28.37, 25.88], + '136.x': [833, 814.33], + '136.y': [198.17, 180.8], + '137.height': [62.21, 56.76], + '137.width': [60.8, 55.47], + '137.x': [778.57, 764.67], + '137.y': [152.16, 138.82], + '138.height': [7.77, 7.09], + '138.width': [3.23, 2.94], + '138.x': [739.31, 728.85], + '138.y': [110.74, 101.04], + '139.height': [62.98, 57.46], + '139.width': [74.08, 67.58], + '139.x': [718.49, 709.86], + '139.y': [31.07, 28.34], + '140.height': [6.43, 5.87], + '140.width': [2.01, 1.83], + '140.x': [793.45, 778.25], + '140.y': [80.22, 73.19], + '141.height': [18.06, 16.48], + '141.width': [15.92, 14.52], + '141.x': [628.7, 627.94], + '141.y': [41.04, 37.45], + '142.height': [4.22, 3.85], + '142.width': [5.52, 5.03], + '142.x': [629.48, 628.65], + '142.y': [24.84, 22.67], + '143.height': [12.88, 11.75], + '143.width': [11.12, 10.14], + '143.x': [610.92, 611.72], + '143.y': [23.59, 21.52], + '144.height': [3.62, 3.31], + '144.width': [11.39, 10.39], + '144.x': [593.98, 596.26], + '144.y': [13.57, 12.38], + '145.height': [6.28, 5.73], + '145.width': [7.59, 6.93], + '145.x': [679.49, 674.28], + '145.y': [49.87, 45.5], + '146.height': [4.27, 3.9], + '146.width': [9.63, 8.79], + '146.x': [672.08, 667.52], + '146.y': [46.98, 42.86], + '147.height': [25.86, 23.59], + '147.width': [14.26, 13.01], + '147.x': [795.38, 780.01], + '147.y': [93.44, 85.25], + '148.height': [12.46, 11.37], + '148.width': [28.8, 26.28], + '148.x': [770.11, 756.95], + '148.y': [116.58, 106.36], + '149.height': [2.91, 2.66], + '149.width': [1.76, 1.6], + '149.x': [791.55, 776.52], + '149.y': [119.57, 109.09], + '150.height': [2.31, 2.11], + '150.width': [3.6, 3.28], + '150.x': [637.53, 635.99], + '150.y': [41.47, 37.84], + '151.height': [12.3, 11.22], + '151.width': [13.42, 12.24], + '151.x': [641.28, 639.41], + '151.y': [9.63, 8.79], + '152.height': [2.91, 2.66], + '152.width': [7, 6.39], + '152.x': [641.2, 639.34], + '152.y': [37.08, 33.83], + '153.height': [4.06, 3.7], + '153.width': [8.33, 7.6], + '153.x': [635.15, 633.83], + '153.y': [34.65, 31.62], + '154.height': [11.02, 10.05], + '154.width': [10.28, 9.38], + '154.x': [673.77, 669.06], + '154.y': [94.44, 86.16], + '155.height': [25.73, 23.48], + '155.width': [13.15, 12], + '155.x': [799.23, 783.52], + '155.y': [43.62, 39.8], + '156.height': [15.88, 14.49], + '156.width': [12.81, 11.69], + '156.x': [529.07, 537.04], + '156.y': [169.41, 154.56], + '157.height': [12.73, 11.62], + '157.width': [15.27, 13.94], + '157.x': [683.02, 677.49], + '157.y': [92.47, 84.36], + '158.height': [30.46, 27.79], + '158.width': [31.67, 28.89], + '158.x': [669.15, 664.84], + '158.y': [67.25, 61.36], + '159.height': [18.67, 17.03], + '159.width': [334.06, 304.78], + '159.x': [457.64, 471.87], + '159.y': [243.73, 222.37], + '160.height': [1.22, 1.11], + '160.width': [2.39, 2.18], + '160.x': [664.9, 660.96], + '160.y': [60.82, 55.49], + '161.height': [1.1, 1], + '161.width': [2.43, 2.21], + '161.x': [664.26, 660.38], + '161.y': [61.72, 56.31], + '162.height': [27.06, 24.69], + '162.width': [23.19, 21.16], + '162.x': [595.25, 597.42], + '162.y': [60.66, 55.34], + '163.height': [18.27, 16.67], + '163.width': [18.8, 17.15], + '163.x': [654.72, 651.68], + '163.y': [68.32, 62.33], + '164.height': [25.88, 23.61], + '164.width': [23.2, 21.17], + '164.x': [633.32, 632.15], + '164.y': [65.45, 59.71], + '165.height': [23.21, 21.17], + '165.width': [22.2, 20.26], + '165.x': [669.36, 665.03], + '165.y': [100.46, 91.66], + '166.height': [3.55, 3.24], + '166.width': [2.38, 2.17], + '166.x': [682.06, 676.62], + '166.y': [104.97, 95.77], + '167.height': [6.97, 6.36], + '167.width': [9.64, 8.79], + '167.x': [683.5, 677.94], + '167.y': [107.45, 98.03], + '168.height': [11.54, 10.52], + '168.width': [8.2, 7.48], + '168.x': [664.49, 660.59], + '168.y': [121.99, 111.3], + '169.height': [3.61, 3.29], + '169.width': [2.71, 2.47], + '169.x': [663.64, 659.81], + '169.y': [132.9, 121.25], + '170.height': [4.37, 3.98], + '170.width': [5.11, 4.66], + '170.x': [640.33, 638.55], + '170.y': [44.15, 40.28], + '171.height': [2.55, 2.33], + '171.width': [3.32, 3.03], + '171.x': [647.02, 644.65], + '171.y': [49.08, 44.78], + '172.height': [6.62, 6.04], + '172.width': [5.89, 5.37], + '172.x': [644.12, 642], + '172.y': [42.59, 38.86], + '173.height': [2.81, 2.57], + '173.width': [2.4, 2.19], + '173.x': [644.21, 642.08], + '173.y': [47.03, 42.91], + '174.height': [2.44, 2.23], + '174.width': [2.21, 2.02], + '174.x': [646.32, 644.01], + '174.y': [47.45, 43.29], + '175.height': [1.79, 1.63], + '175.width': [1.68, 1.53], + '175.x': [527.49, 535.6], + '175.y': [108.6, 99.08], + '176.height': [17.61, 16.07], + '176.width': [17.24, 15.73], + '176.x': [655.74, 652.61], + '176.y': [105.88, 96.6], + }, + legend: { + 'continuousLegend.bounds.height': [46, 69], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.usBubblesSpec @390': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + legend: { + 'pointSizeLegend.bounds.height': [68.6, 69], + 'pointSizeLegend.bounds.width': [83.57, 84], + 'pointSizeLegend.bounds.x': [278.43, 278], + 'pointSizeLegend.bounds.y': [257.4, 257], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.usBubblesSpec @1280': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + legend: { + 'pointSizeLegend.bounds.height': [68.6, 69], + 'pointSizeLegend.bounds.width': [83.57, 84], + 'pointSizeLegend.bounds.x': [1158.43, 1158], + 'pointSizeLegend.bounds.y': [249.8, 249.4], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.worldDivergingSpec @390': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [199.1, 150.1], + }, + area: { + 'rect.height': [199.1, 150.1], + 'rect.y': [157.3, 206.3], + }, + marks: { + '0.height': [3.12, 2.57], + '0.width': [370, 304], + '0.x': [0, 33], + '0.y': [121.59, 93.16], + '1.height': [15.14, 12.44], + '1.width': [11.22, 9.21], + '1.x': [215.68, 210.21], + '1.y': [100.48, 75.81], + '2.height': [8.94, 7.34], + '2.width': [8.72, 7.17], + '2.x': [167.7, 170.79], + '2.y': [60.91, 43.31], + '3.height': [34.84, 28.62], + '3.width': [72.43, 59.51], + '3.x': [73.3, 93.23], + '3.y': [8.32, 0.09], + '4.height': [58.61, 48.15], + '4.width': [101.55, 83.44], + '4.x': [23.52, 52.32], + '4.y': [14.09, 4.83], + '5.height': [16.53, 13.58], + '5.width': [35.35, 29.05], + '5.x': [225.6, 218.36], + '5.y': [27.84, 16.14], + '6.height': [10.17, 8.35], + '6.width': [17.24, 14.16], + '6.x': [235.21, 226.25], + '6.y': [38.54, 24.92], + '7.height': [11.46, 9.42], + '7.width': [16.08, 13.21], + '7.x': [331.82, 305.63], + '7.y': [102.66, 77.61], + '8.height': [22.3, 18.32], + '8.width': [48.02, 39.45], + '8.x': [284.59, 266.83], + '8.y': [91.41, 68.36], + '9.height': [40.74, 33.47], + '9.width': [15.53, 12.76], + '9.x': [116.21, 128.48], + '9.y': [129.55, 99.7], + '10.height': [46.92, 38.55], + '10.width': [16.45, 13.51], + '10.x': [113.09, 125.92], + '10.y': [123.74, 94.92], + '11.height': [26.03, 21.39], + '11.width': [19.91, 16.36], + '11.x': [197.73, 195.46], + '11.y': [91.72, 68.62], + '12.height': [19.28, 15.84], + '12.width': [10.13, 8.32], + '12.x': [227.9, 220.25], + '12.y': [82.23, 60.82], + '13.height': [14.36, 11.8], + '13.width': [8.29, 6.81], + '13.x': [220.5, 214.17], + '13.y': [91.37, 68.33], + '14.height': [19.05, 15.65], + '14.width': [16.57, 13.62], + '14.x': [207.71, 203.66], + '14.y': [68.49, 49.53], + '15.height': [22.09, 18.15], + '15.width': [10.61, 8.71], + '15.x': [198.97, 196.48], + '15.y': [66.59, 47.97], + '16.height': [2.58, 2.12], + '16.width': [3.09, 2.54], + '16.x': [108.91, 122.49], + '16.y': [71.33, 51.86], + '17.height': [3.14, 2.58], + '17.width': [3.7, 3.04], + '17.x': [111.54, 124.64], + '17.y': [71.37, 51.9], + '18.height': [34.84, 28.63], + '18.width': [273.11, 224.39], + '18.x': [50.05, 74.13], + '18.y': [8.94, 0.6], + '19.height': [4.45, 3.66], + '19.width': [2, 1.65], + '19.x': [106.46, 120.47], + '19.y': [61.73, 43.98], + '20.height': [1.29, 1.06], + '20.width': [2.81, 2.31], + '20.x': [132.93, 142.22], + '20.y': [165.92, 129.58], + '21.height': [16.01, 13.16], + '21.width': [18.35, 15.08], + '21.x': [188.86, 188.17], + '21.y': [9.15, 0.78], + '22.height': [15.09, 12.4], + '22.width': [40.31, 33.12], + '22.x': [136.87, 145.45], + '22.y': [8.21, 0], + '23.height': [1.28, 1.05], + '23.width': [1.89, 1.55], + '23.x': [244.5, 233.89], + '23.y': [163.19, 127.34], + '24.height': [1.57, 1.29], + '24.width': [2.55, 2.09], + '24.x': [315.14, 291.92], + '24.y': [110.79, 84.28], + '25.height': [16.74, 13.76], + '25.width': [16.5, 13.56], + '25.x': [201.12, 198.24], + '25.y': [129.9, 99.98], + '26.height': [2.61, 2.15], + '26.width': [2.36, 1.94], + '26.x': [211.46, 206.74], + '26.y': [138.66, 107.18], + '27.height': [24.43, 20.07], + '27.width': [25.91, 21.29], + '27.x': [71.16, 91.46], + '27.y': [54.31, 37.88], + '28.height': [6.23, 5.12], + '28.width': [5.09, 4.19], + '28.x': [128.57, 138.63], + '28.y': [140.58, 108.76], + '29.height': [53.56, 44.01], + '29.width': [40.94, 33.64], + '29.x': [107.83, 121.59], + '29.y': [91.74, 68.63], + '30.height': [18.08, 14.86], + '30.width': [13.41, 11.02], + '30.x': [112.81, 125.69], + '30.y': [112.87, 86], + '31.height': [25.58, 21.01], + '31.width': [14.32, 11.77], + '31.x': [99.87, 115.06], + '31.y': [99.21, 74.77], + '32.height': [23.54, 19.34], + '32.width': [12.68, 10.42], + '32.x': [102.28, 117.04], + '32.y': [81.66, 60.35], + '33.height': [3.35, 2.75], + '33.width': [5.93, 4.88], + '33.x': [98.53, 113.96], + '33.y': [85.61, 63.59], + '34.height': [4.19, 3.44], + '34.width': [3.35, 2.76], + '34.x': [95.76, 111.68], + '34.y': [83.36, 61.75], + '35.height': [5.97, 4.91], + '35.width': [5.05, 4.15], + '35.x': [94.29, 110.47], + '35.y': [78.07, 57.4], + '36.height': [4.19, 3.44], + '36.width': [6.51, 5.35], + '36.x': [92.82, 109.27], + '36.y': [76.7, 56.28], + '37.height': [1.77, 1.46], + '37.width': [2.46, 2.02], + '37.x': [91.93, 108.53], + '37.y': [78.89, 58.08], + '38.height': [5.65, 4.64], + '38.width': [4.37, 3.59], + '38.x': [89.88, 106.85], + '38.y': [74.2, 54.22], + '39.height': [3.6, 2.96], + '39.width': [1.72, 1.41], + '39.x': [93.25, 109.62], + '39.y': [73.27, 53.46], + '40.height': [16.07, 13.2], + '40.width': [14.04, 11.54], + '40.x': [108.69, 122.3], + '40.y': [82.04, 60.66], + '41.height': [9.99, 8.21], + '41.width': [4.95, 4.07], + '41.x': [120.85, 132.29], + '41.y': [87.35, 65.03], + '42.height': [5.93, 4.87], + '42.width': [4.34, 3.57], + '42.x': [124.28, 135.11], + '42.y': [90.64, 67.73], + '43.height': [63.94, 52.53], + '43.width': [65.84, 54.09], + '43.x': [127.91, 138.1], + '43.y': [32.3, 19.8], + '44.height': [8.94, 7.35], + '44.width': [5.98, 4.91], + '44.x': [100.23, 115.35], + '44.y': [97.18, 73.11], + '45.height': [0.79, 0.65], + '45.width': [1.68, 1.38], + '45.x': [116.27, 128.53], + '45.y': [73.24, 53.43], + '46.height': [1.13, 0.93], + '46.width': [2.12, 1.74], + '46.x': [104.92, 119.21], + '46.y': [73.24, 53.43], + '47.height': [4.53, 3.72], + '47.width': [10.54, 8.66], + '47.x': [99.08, 114.41], + '47.y': [66.89, 48.21], + '48.height': [9.27, 7.61], + '48.width': [7.85, 6.45], + '48.x': [210.86, 206.24], + '48.y': [120.88, 92.57], + '49.height': [12.41, 10.19], + '49.width': [9.82, 8.07], + '49.x': [204.92, 201.36], + '49.y': [123.85, 95.01], + '50.height': [16.33, 13.41], + '50.width': [13.65, 11.22], + '50.x': [197.02, 194.88], + '50.y': [122.86, 94.2], + '51.height': [5.92, 4.86], + '51.width': [6.3, 5.18], + '51.x': [166.83, 170.07], + '51.y': [75.89, 55.61], + '52.height': [20.44, 16.79], + '52.width': [16.93, 13.91], + '52.x': [172.45, 174.69], + '52.y': [64.49, 46.24], + '53.height': [17.37, 14.27], + '53.width': [12.38, 10.17], + '53.x': [167.7, 170.79], + '53.y': [61.26, 43.59], + '54.height': [8.54, 7.01], + '54.width': [3.14, 2.58], + '54.x': [185.8, 185.66], + '54.y': [81.94, 60.58], + '55.height': [16.24, 13.34], + '55.width': [15.85, 13.02], + '55.x': [185.31, 185.25], + '55.y': [66.5, 47.9], + '56.height': [13.48, 11.08], + '56.width': [12.3, 10.1], + '56.x': [187.81, 187.31], + '56.y': [79.67, 58.72], + '57.height': [15.63, 12.84], + '57.width': [7.89, 6.48], + '57.x': [193.88, 192.29], + '57.y': [81.07, 59.87], + '58.height': [7.14, 5.87], + '58.width': [2, 1.64], + '58.x': [184.95, 184.96], + '58.y': [83.64, 61.97], + '59.height': [8.97, 7.37], + '59.width': [4.5, 3.69], + '59.x': [181.61, 182.22], + '59.y': [83.52, 61.88], + '60.height': [8.69, 7.14], + '60.width': [6.31, 5.19], + '60.x': [176.02, 177.62], + '60.y': [84.33, 62.54], + '61.height': [7.39, 6.07], + '61.width': [7.55, 6.2], + '61.x': [169.29, 172.1], + '61.y': [81.45, 60.18], + '62.height': [2.22, 1.82], + '62.width': [3.09, 2.54], + '62.x': [167.73, 170.81], + '62.y': [81.39, 60.13], + '63.height': [5.89, 4.84], + '63.width': [4.06, 3.34], + '63.x': [173.06, 175.19], + '63.y': [87.11, 64.83], + '64.height': [4.58, 3.76], + '64.width': [3.13, 2.58], + '64.x': [171.21, 173.67], + '64.y': [84.99, 63.09], + '65.height': [7.67, 6.3], + '65.width': [7.93, 6.52], + '65.x': [179.32, 180.33], + '65.y': [77.93, 57.29], + '66.height': [12.47, 10.25], + '66.width': [13.5, 11.09], + '66.x': [200.11, 197.42], + '66.y': [83.46, 61.83], + '67.height': [12.36, 10.16], + '67.width': [7.7, 6.33], + '67.x': [196.61, 194.54], + '67.y': [93.88, 70.39], + '68.height': [8.89, 7.31], + '68.width': [5.9, 4.84], + '68.x': [194.21, 192.57], + '68.y': [95.85, 72.01], + '69.height': [1.8, 1.48], + '69.width': [2.07, 1.7], + '69.x': [194.74, 193.01], + '69.y': [95.91, 72.06], + '70.height': [13.52, 11.11], + '70.width': [12.3, 10.1], + '70.x': [207.49, 203.48], + '70.y': [110.74, 84.24], + '71.height': [10.53, 8.65], + '71.width': [3.03, 2.49], + '71.x': [218.77, 212.74], + '71.y': [112.13, 85.39], + '72.height': [22.49, 18.48], + '72.width': [10.93, 8.98], + '72.x': [216.11, 210.56], + '72.y': [113.65, 86.64], + '73.height': [2.16, 1.78], + '73.width': [1.38, 1.13], + '73.x': [215.48, 210.05], + '73.y': [134.7, 103.93], + '74.height': [18.83, 15.47], + '74.width': [13, 10.68], + '74.x': [196.95, 194.82], + '74.y': [105.39, 79.85], + '75.height': [3.03, 2.49], + '75.width': [1.8, 1.48], + '75.x': [215.38, 209.96], + '75.y': [102.45, 77.43], + '76.height': [4.89, 4.02], + '76.width': [1.25, 1.03], + '76.x': [218.38, 212.43], + '76.y': [53.59, 37.29], + '77.height': [1.99, 1.63], + '77.width': [1.23, 1.01], + '77.x': [218.91, 212.86], + '77.y': [51.85, 35.86], + '78.height': [18.56, 15.25], + '78.width': [8.28, 6.8], + '78.x': [228.7, 220.9], + '78.y': [116.06, 88.61], + '79.height': [1.52, 1.25], + '79.width': [0.57, 0.47], + '79.x': [218.97, 212.91], + '79.y': [54.55, 38.08], + '80.height': [1.04, 0.85], + '80.width': [3.11, 2.56], + '80.x': [167.58, 170.69], + '80.y': [79.65, 58.7], + '81.height': [8.99, 7.38], + '81.width': [3.86, 3.17], + '81.x': [192.23, 190.94], + '81.y': [48.45, 33.06], + '82.height': [23.77, 19.53], + '82.width': [20.67, 16.99], + '82.x': [176.39, 177.93], + '82.y': [48.73, 33.3], + '83.height': [5.42, 4.46], + '83.width': [3.72, 3.06], + '83.x': [219.29, 213.17], + '83.y': [53.46, 37.18], + '84.height': [4.78, 3.93], + '84.width': [4.69, 3.85], + '84.x': [236.73, 227.5], + '84.y': [63.04, 45.05], + '85.height': [2.08, 1.71], + '85.width': [0.91, 0.75], + '85.x': [235.66, 226.62], + '85.y': [62.96, 44.99], + '86.height': [2.01, 1.65], + '86.width': [1.93, 1.59], + '86.x': [230.81, 222.64], + '86.y': [57.76, 40.71], + '87.height': [10.61, 8.72], + '87.width': [10.21, 8.39], + '87.x': [222.39, 215.72], + '87.y': [48.4, 33.03], + '88.height': [13.23, 10.87], + '88.width': [7.35, 6.04], + '88.x': [238.04, 228.58], + '88.y': [62.59, 44.68], + '89.height': [2.73, 2.24], + '89.width': [0.8, 0.65], + '89.x': [356.55, 325.95], + '89.y': [119.66, 91.57], + '90.height': [5.69, 4.67], + '90.width': [5.54, 4.55], + '90.x': [290.8, 271.93], + '90.y': [78.69, 57.91], + '91.height': [20.47, 16.82], + '91.width': [9.33, 7.67], + '91.x': [284.48, 266.73], + '91.y': [70.64, 51.3], + '92.height': [11.78, 9.68], + '92.width': [9.13, 7.5], + '92.x': [286.7, 268.56], + '92.y': [67.87, 49.02], + '93.height': [25.14, 20.65], + '93.width': [9.78, 8.04], + '93.x': [278.45, 261.78], + '93.y': [60.02, 42.57], + '94.height': [20.36, 16.73], + '94.width': [10.13, 8.33], + '94.x': [288.11, 269.72], + '94.y': [66.66, 48.03], + '95.height': [6.46, 5.31], + '95.width': [4.8, 3.94], + '95.x': [300.41, 279.82], + '95.y': [41.59, 27.43], + '96.height': [5.29, 4.35], + '96.width': [4.59, 3.77], + '96.x': [303.73, 282.55], + '96.y': [46.88, 31.78], + '97.height': [11.91, 9.79], + '97.width': [29.85, 24.52], + '97.x': [261.24, 247.64], + '97.y': [31.33, 19], + '98.height': [37.14, 30.51], + '98.width': [27.85, 22.88], + '98.x': [253.51, 241.29], + '98.y': [50.77, 34.97], + '99.height': [7.78, 6.39], + '99.width': [5.88, 4.83], + '99.x': [272.97, 257.28], + '99.y': [62.52, 44.63], + '100.height': [2.09, 1.72], + '100.width': [3.36, 2.76], + '100.x': [273.03, 257.33], + '100.y': [60.07, 42.61], + '101.height': [5.3, 4.36], + '101.width': [8.71, 7.16], + '101.x': [263.88, 249.81], + '101.y': [57.28, 40.32], + '102.height': [17.49, 14.37], + '102.width': [14.51, 11.92], + '102.x': [244.68, 234.04], + '102.y': [48.72, 33.28], + '103.height': [11.69, 9.6], + '103.width': [12.73, 10.46], + '103.x': [243.25, 232.86], + '103.y': [47.04, 31.9], + '104.height': [5.2, 4.27], + '104.width': [7.76, 6.37], + '104.x': [247.94, 236.71], + '104.y': [44.01, 29.42], + '105.height': [4.85, 3.98], + '105.width': [8.85, 7.27], + '105.x': [249.53, 238.02], + '105.y': [41.21, 27.12], + '106.height': [9.19, 7.55], + '106.width': [14.56, 11.96], + '106.x': [233.18, 224.59], + '106.y': [41.86, 27.65], + '107.height': [18.82, 15.46], + '107.width': [21.8, 17.92], + '107.x': [226.09, 218.76], + '107.y': [45.53, 30.67], + '108.height': [6.24, 5.12], + '108.width': [5.73, 4.71], + '108.x': [219.24, 213.13], + '108.y': [48.6, 33.18], + '109.height': [3.06, 2.51], + '109.width': [3.32, 2.73], + '109.x': [225.18, 218.01], + '109.y': [43.66, 29.13], + '110.height': [12.19, 10.02], + '110.width': [8.93, 7.33], + '110.x': [193.8, 192.23], + '110.y': [15.67, 6.14], + '111.height': [5.06, 4.16], + '111.width': [7.83, 6.43], + '111.x': [204.63, 201.12], + '111.y': [27.05, 15.48], + '112.height': [7.85, 6.45], + '112.width': [15.64, 12.85], + '112.x': [204.32, 200.87], + '112.y': [31.02, 18.75], + '113.height': [6.24, 5.13], + '113.width': [8.82, 7.25], + '113.x': [196.82, 194.71], + '113.y': [28.39, 16.58], + '114.height': [2.95, 2.42], + '114.width': [6.51, 5.35], + '114.x': [193.38, 191.88], + '114.y': [34.62, 21.7], + '115.height': [3.26, 2.68], + '115.width': [5.61, 4.61], + '115.x': [199.35, 196.79], + '115.y': [35.08, 22.08], + '116.height': [3.39, 2.79], + '116.width': [3.35, 2.75], + '116.x': [208.33, 204.17], + '116.y': [35.25, 22.22], + '117.height': [5.22, 4.29], + '117.width': [8.59, 7.05], + '117.x': [203, 199.79], + '117.y': [35.53, 22.45], + '118.height': [2.52, 2.07], + '118.width': [4.71, 3.87], + '118.x': [202.26, 199.18], + '118.y': [26.85, 15.32], + '119.height': [2.34, 1.92], + '119.width': [5.9, 4.85], + '119.x': [202.17, 199.11], + '119.y': [25.27, 14.02], + '120.height': [2.06, 1.69], + '120.width': [3.79, 3.11], + '120.x': [203.57, 200.25], + '120.y': [23.7, 12.73], + '121.height': [8.31, 6.83], + '121.width': [7.76, 6.38], + '121.x': [190.09, 189.19], + '121.y': [28.25, 16.47], + '122.height': [3.57, 2.93], + '122.width': [5.61, 4.61], + '122.x': [205.26, 201.65], + '122.y': [40.11, 26.21], + '123.height': [8.53, 7.01], + '123.width': [6.33, 5.2], + '123.x': [203.75, 200.41], + '123.y': [42.97, 28.56], + '124.height': [7.77, 6.38], + '124.width': [18.31, 15.05], + '124.x': [208.96, 204.69], + '124.y': [42.59, 28.25], + '125.height': [3.7, 3.04], + '125.width': [1.76, 1.44], + '125.x': [202.67, 199.52], + '125.y': [41.94, 27.71], + '126.height': [4.71, 3.87], + '126.width': [5.14, 4.22], + '126.x': [197.24, 195.05], + '126.y': [37.48, 24.05], + '127.height': [2.34, 1.93], + '127.width': [3.89, 3.2], + '127.x': [190.35, 189.4], + '127.y': [35.97, 22.81], + '128.height': [0.76, 0.62], + '128.width': [0.48, 0.39], + '128.x': [189.92, 189.04], + '128.y': [33.41, 20.71], + '129.height': [2.12, 1.75], + '129.width': [3.13, 2.57], + '129.x': [187.15, 186.77], + '129.y': [31.95, 19.51], + '130.height': [2.89, 2.38], + '130.width': [3.13, 2.58], + '130.x': [187.83, 187.33], + '130.y': [29.78, 17.73], + '131.height': [6.66, 5.47], + '131.width': [3.04, 2.49], + '131.x': [176.09, 177.68], + '131.y': [42.42, 28.11], + '132.height': [9.52, 7.82], + '132.width': [11.34, 9.32], + '132.x': [176.45, 177.98], + '132.y': [40.68, 26.68], + '133.height': [3.63, 2.99], + '133.width': [3.42, 2.81], + '133.x': [176.51, 178.02], + '133.y': [28.1, 16.35], + '134.height': [3.12, 2.56], + '134.width': [2.08, 1.71], + '134.x': [351.75, 322], + '134.y': [127.2, 97.77], + '135.height': [5.93, 4.87], + '135.width': [5.28, 4.34], + '135.x': [348.36, 319.22], + '135.y': [108.43, 82.35], + '136.height': [14.77, 12.14], + '136.width': [19.75, 16.23], + '136.x': [333.29, 306.84], + '136.y': [146.17, 113.36], + '137.height': [43.31, 35.59], + '137.width': [42.33, 34.78], + '137.x': [295.4, 275.71], + '137.y': [114.14, 87.04], + '138.height': [5.41, 4.45], + '138.width': [2.25, 1.85], + '138.x': [268.06, 253.25], + '138.y': [85.31, 63.35], + '139.height': [43.85, 36.03], + '139.width': [51.57, 42.37], + '139.x': [253.57, 241.34], + '139.y': [29.84, 17.77], + '140.height': [4.48, 3.68], + '140.width': [1.4, 1.15], + '140.x': [305.76, 284.22], + '140.y': [64.05, 45.89], + '141.height': [12.58, 10.33], + '141.width': [11.08, 9.1], + '141.x': [191.06, 189.98], + '141.y': [36.78, 23.48], + '142.height': [2.94, 2.41], + '142.width': [3.84, 3.16], + '142.x': [191.6, 190.42], + '142.y': [25.5, 14.21], + '143.height': [8.97, 7.37], + '143.width': [7.74, 6.36], + '143.x': [178.68, 179.81], + '143.y': [24.63, 13.49], + '144.height': [2.52, 2.07], + '144.width': [7.93, 6.51], + '144.x': [166.88, 170.11], + '144.y': [17.65, 7.76], + '145.height': [4.38, 3.59], + '145.width': [5.28, 4.34], + '145.x': [226.42, 219.03], + '145.y': [42.93, 28.53], + '146.height': [2.98, 2.44], + '146.width': [6.71, 5.51], + '146.x': [221.26, 214.79], + '146.y': [40.91, 26.87], + '147.height': [18, 14.79], + '147.width': [9.93, 8.16], + '147.x': [307.1, 285.32], + '147.y': [73.26, 53.45], + '148.height': [8.67, 7.13], + '148.width': [20.05, 16.48], + '148.x': [289.51, 270.87], + '148.y': [89.37, 66.69], + '149.height': [2.03, 1.67], + '149.width': [1.22, 1], + '149.x': [304.44, 283.13], + '149.y': [91.45, 68.4], + '150.height': [1.61, 1.32], + '150.width': [2.5, 2.06], + '150.x': [197.2, 195.03], + '150.y': [37.08, 23.72], + '151.height': [8.56, 7.03], + '151.width': [9.34, 7.68], + '151.x': [199.81, 197.17], + '151.y': [14.91, 5.51], + '152.height': [2.03, 1.67], + '152.width': [4.87, 4], + '152.x': [199.76, 197.13], + '152.y': [34.02, 21.21], + '153.height': [2.82, 2.32], + '153.width': [5.8, 4.77], + '153.x': [195.55, 193.67], + '153.y': [32.33, 19.82], + '154.height': [7.67, 6.3], + '154.width': [7.16, 5.88], + '154.x': [222.44, 215.76], + '154.y': [73.96, 54.02], + '155.height': [17.92, 14.72], + '155.width': [9.15, 7.52], + '155.x': [309.78, 287.52], + '155.y': [38.58, 24.95], + '156.height': [11.06, 9.09], + '156.width': [8.92, 7.33], + '156.x': [121.69, 132.99], + '156.y': [126.15, 96.91], + '157.height': [8.87, 7.28], + '157.width': [10.63, 8.74], + '157.x': [228.87, 221.05], + '157.y': [72.58, 52.89], + '158.height': [21.2, 17.42], + '158.width': [22.05, 18.11], + '158.x': [219.22, 213.11], + '158.y': [55.03, 38.47], + '159.height': [13, 10.68], + '159.width': [232.58, 191.09], + '159.x': [71.96, 92.12], + '159.y': [177.9, 139.42], + '160.height': [0.85, 0.7], + '160.width': [1.66, 1.37], + '160.x': [216.26, 210.68], + '160.y': [50.55, 34.79], + '161.height': [0.76, 0.63], + '161.width': [1.69, 1.39], + '161.x': [215.81, 210.32], + '161.y': [51.18, 35.31], + '162.height': [18.84, 15.48], + '162.width': [16.15, 13.27], + '162.x': [167.77, 170.84], + '162.y': [50.44, 34.7], + '163.height': [12.72, 10.45], + '163.width': [13.09, 10.75], + '163.x': [209.18, 204.86], + '163.y': [55.77, 39.08], + '164.height': [18.02, 14.8], + '164.width': [16.15, 13.27], + '164.x': [194.28, 192.62], + '164.y': [53.77, 37.44], + '165.height': [16.16, 13.27], + '165.width': [15.46, 12.7], + '165.x': [219.36, 213.23], + '165.y': [78.15, 57.47], + '166.height': [2.47, 2.03], + '166.width': [1.66, 1.36], + '166.x': [228.21, 220.5], + '166.y': [81.29, 60.05], + '167.height': [4.85, 3.99], + '167.width': [6.71, 5.51], + '167.x': [229.21, 221.33], + '167.y': [83.02, 61.47], + '168.height': [8.03, 6.6], + '168.width': [5.71, 4.69], + '168.x': [215.98, 210.45], + '168.y': [93.14, 69.78], + '169.height': [2.51, 2.07], + '169.width': [1.89, 1.55], + '169.x': [215.38, 209.96], + '169.y': [100.74, 76.02], + '170.height': [3.04, 2.5], + '170.width': [3.56, 2.92], + '170.x': [199.15, 196.63], + '170.y': [38.94, 25.25], + '171.height': [1.78, 1.46], + '171.width': [2.31, 1.9], + '171.x': [203.81, 200.46], + '171.y': [42.38, 28.08], + '172.height': [4.61, 3.79], + '172.width': [4.1, 3.37], + '172.x': [201.79, 198.8], + '172.y': [37.86, 24.36], + '173.height': [1.96, 1.61], + '173.width': [1.67, 1.38], + '173.x': [201.85, 198.85], + '173.y': [40.95, 26.9], + '174.height': [1.7, 1.4], + '174.width': [1.54, 1.27], + '174.x': [203.32, 200.05], + '174.y': [41.24, 27.15], + '175.height': [1.25, 1.02], + '175.width': [1.17, 0.96], + '175.x': [120.59, 132.08], + '175.y': [83.82, 62.12], + '176.height': [12.26, 10.08], + '176.width': [12, 9.86], + '176.x': [209.88, 205.45], + '176.y': [81.92, 60.57], + }, + legend: { + 'continuousLegend.bounds.height': [61, 110], + 'continuousLegend.bar.height': [12, 15], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.worldDivergingSpec @1280': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [198.2, 149.2], + }, + area: { + 'rect.height': [198.2, 149.2], + 'rect.y': [138.2, 187.2], + }, + marks: { + '0.height': [3.39, 2.55], + '0.width': [401.42, 302.18], + '0.x': [419.29, 468.91], + '0.y': [123.01, 92.6], + '1.height': [16.42, 12.36], + '1.width': [12.17, 9.16], + '1.x': [653.29, 645.06], + '1.y': [100.1, 75.36], + '2.height': [9.7, 7.3], + '2.width': [9.46, 7.12], + '2.x': [601.23, 605.87], + '2.y': [57.18, 43.05], + '3.height': [37.79, 28.45], + '3.width': [78.58, 59.15], + '3.x': [498.82, 528.78], + '3.y': [0.12, 0.09], + '4.height': [63.59, 47.87], + '4.width': [110.17, 82.94], + '4.x': [444.8, 488.12], + '4.y': [6.38, 4.8], + '5.height': [17.93, 13.5], + '5.width': [38.35, 28.87], + '5.x': [664.05, 653.16], + '5.y': [21.31, 16.04], + '6.height': [11.03, 8.3], + '6.width': [18.7, 14.08], + '6.x': [674.47, 661], + '6.y': [32.9, 24.77], + '7.height': [12.43, 9.36], + '7.width': [17.45, 13.13], + '7.x': [779.29, 739.91], + '7.y': [102.47, 77.14], + '8.height': [24.2, 18.21], + '8.width': [52.09, 39.21], + '8.x': [728.05, 701.34], + '8.y': [90.27, 67.95], + '9.height': [44.2, 33.27], + '9.width': [16.85, 12.68], + '9.x': [545.37, 563.82], + '9.y': [131.64, 99.1], + '10.height': [50.9, 38.32], + '10.width': [17.84, 13.43], + '10.x': [541.99, 561.27], + '10.y': [125.34, 94.35], + '11.height': [28.24, 21.26], + '11.width': [21.6, 16.26], + '11.x': [633.81, 630.39], + '11.y': [90.61, 68.21], + '12.height': [20.91, 15.74], + '12.width': [10.99, 8.27], + '12.x': [666.54, 655.03], + '12.y': [80.31, 60.46], + '13.height': [15.58, 11.73], + '13.width': [9, 6.77], + '13.x': [658.51, 648.99], + '13.y': [90.23, 67.92], + '14.height': [20.67, 15.56], + '14.width': [17.98, 13.54], + '14.x': [644.64, 638.55], + '14.y': [65.41, 49.24], + '15.height': [23.96, 18.04], + '15.width': [11.51, 8.66], + '15.x': [635.16, 631.41], + '15.y': [63.34, 47.68], + '16.height': [2.8, 2.11], + '16.width': [3.35, 2.52], + '16.x': [537.45, 557.86], + '16.y': [68.48, 51.55], + '17.height': [3.4, 2.56], + '17.width': [4.01, 3.02], + '17.x': [540.3, 560], + '17.y': [68.53, 51.59], + '18.height': [37.8, 28.46], + '18.width': [296.3, 223.05], + '18.x': [473.6, 509.79], + '18.y': [0.79, 0.6], + '19.height': [4.83, 3.63], + '19.width': [2.17, 1.64], + '19.x': [534.79, 555.85], + '19.y': [58.07, 43.71], + '20.height': [1.4, 1.05], + '20.width': [3.05, 2.29], + '20.x': [563.51, 577.48], + '20.y': [171.1, 128.8], + '21.height': [17.37, 13.08], + '21.width': [19.91, 14.99], + '21.x': [624.19, 623.15], + '21.y': [1.03, 0.77], + '22.height': [16.37, 12.32], + '22.width': [43.74, 32.92], + '22.x': [567.78, 580.69], + '23.height': [1.38, 1.04], + '23.width': [2.05, 1.54], + '23.x': [684.55, 668.59], + '23.y': [168.15, 126.58], + '24.height': [1.7, 1.28], + '24.width': [2.76, 2.08], + '24.x': [761.19, 726.28], + '24.y': [111.29, 83.78], + '25.height': [18.16, 13.67], + '25.width': [17.9, 13.48], + '25.x': [637.48, 633.16], + '25.y': [132.02, 99.38], + '26.height': [2.84, 2.14], + '26.width': [2.56, 1.93], + '26.x': [648.71, 641.61], + '26.y': [141.53, 106.54], + '27.height': [26.5, 19.95], + '27.width': [28.11, 21.16], + '27.x': [496.49, 527.03], + '27.y': [50.02, 37.65], + '28.height': [6.76, 5.09], + '28.width': [5.53, 4.16], + '28.x': [558.77, 573.91], + '28.y': [143.61, 108.11], + '29.height': [58.11, 43.74], + '29.width': [44.41, 33.43], + '29.x': [536.27, 556.97], + '29.y': [90.63, 68.22], + '30.height': [19.62, 14.77], + '30.width': [14.55, 10.95], + '30.x': [541.68, 561.04], + '30.y': [113.56, 85.48], + '31.height': [27.75, 20.89], + '31.width': [15.54, 11.7], + '31.x': [527.64, 550.48], + '31.y': [98.74, 74.33], + '32.height': [25.54, 19.23], + '32.width': [13.76, 10.35], + '32.x': [530.26, 552.45], + '32.y': [79.69, 59.99], + '33.height': [3.64, 2.74], + '33.width': [6.44, 4.85], + '33.x': [526.19, 549.38], + '33.y': [83.97, 63.21], + '34.height': [4.55, 3.42], + '34.width': [3.64, 2.74], + '34.x': [523.19, 547.12], + '34.y': [81.53, 61.38], + '35.height': [6.48, 4.88], + '35.width': [5.47, 4.12], + '35.x': [521.59, 545.92], + '35.y': [75.8, 57.06], + '36.height': [4.55, 3.42], + '36.width': [7.06, 5.32], + '36.x': [520, 544.72], + '36.y': [74.31, 55.94], + '37.height': [1.92, 1.45], + '37.width': [2.67, 2.01], + '37.x': [519.02, 543.99], + '37.y': [76.69, 57.73], + '38.height': [6.13, 4.61], + '38.width': [4.74, 3.57], + '38.x': [516.81, 542.32], + '38.y': [71.6, 53.9], + '39.height': [3.91, 2.94], + '39.width': [1.86, 1.4], + '39.x': [520.46, 545.07], + '39.y': [70.59, 53.14], + '40.height': [17.43, 13.12], + '40.width': [15.23, 11.47], + '40.x': [537.21, 557.68], + '40.y': [80.1, 60.3], + '41.height': [10.84, 8.16], + '41.width': [5.37, 4.04], + '41.x': [550.4, 567.61], + '41.y': [85.86, 64.64], + '42.height': [6.43, 4.84], + '42.width': [4.71, 3.55], + '42.x': [554.12, 570.41], + '42.y': [89.43, 67.32], + '43.height': [69.37, 52.22], + '43.width': [71.43, 53.77], + '43.x': [558.07, 573.38], + '43.y': [26.14, 19.68], + '44.height': [9.7, 7.3], + '44.width': [6.48, 4.88], + '44.x': [528.03, 550.77], + '44.y': [96.53, 72.67], + '45.height': [0.85, 0.64], + '45.width': [1.82, 1.37], + '45.x': [545.44, 563.87], + '45.y': [70.56, 53.11], + '46.height': [1.23, 0.92], + '46.width': [2.3, 1.73], + '46.x': [533.12, 554.6], + '46.y': [70.55, 53.11], + '47.height': [4.91, 3.7], + '47.width': [11.43, 8.61], + '47.x': [526.79, 549.83], + '47.y': [63.66, 47.92], + '48.height': [10.05, 7.57], + '48.width': [8.52, 6.41], + '48.x': [648.05, 641.12], + '48.y': [122.24, 92.02], + '49.height': [13.46, 10.13], + '49.width': [10.66, 8.02], + '49.x': [641.61, 636.27], + '49.y': [125.46, 94.44], + '50.height': [17.71, 13.33], + '50.width': [14.81, 11.15], + '50.x': [633.04, 629.82], + '50.y': [124.39, 93.63], + '51.height': [6.42, 4.83], + '51.width': [6.83, 5.14], + '51.x': [600.29, 605.16], + '51.y': [73.43, 55.27], + '52.height': [22.18, 16.69], + '52.width': [18.37, 13.83], + '52.x': [606.39, 609.75], + '52.y': [61.06, 45.96], + '53.height': [18.84, 14.18], + '53.width': [13.43, 10.11], + '53.x': [601.23, 605.87], + '53.y': [57.56, 43.33], + '54.height': [9.26, 6.97], + '54.width': [3.41, 2.56], + '54.x': [620.87, 620.66], + '54.y': [79.99, 60.22], + '55.height': [17.61, 13.26], + '55.width': [17.2, 12.94], + '55.x': [620.33, 620.25], + '55.y': [63.25, 47.61], + '56.height': [14.63, 11.01], + '56.width': [13.34, 10.04], + '56.x': [623.05, 622.3], + '56.y': [77.53, 58.36], + '57.height': [16.96, 12.76], + '57.width': [8.56, 6.44], + '57.x': [629.63, 627.25], + '57.y': [79.05, 59.51], + '58.height': [7.75, 5.83], + '58.width': [2.17, 1.63], + '58.x': [619.95, 619.96], + '58.y': [81.83, 61.6], + '59.height': [9.73, 7.32], + '59.width': [4.88, 3.67], + '59.x': [616.32, 617.23], + '59.y': [81.71, 61.51], + '60.height': [9.43, 7.1], + '60.width': [6.85, 5.16], + '60.x': [610.25, 612.66], + '60.y': [82.58, 62.17], + '61.height': [8.01, 6.03], + '61.width': [8.19, 6.16], + '61.x': [602.96, 607.17], + '61.y': [79.46, 59.82], + '62.height': [2.4, 1.81], + '62.width': [3.35, 2.52], + '62.x': [601.26, 605.89], + '62.y': [79.4, 59.77], + '63.height': [6.39, 4.81], + '63.width': [4.4, 3.32], + '63.x': [607.05, 610.25], + '63.y': [85.6, 64.44], + '64.height': [4.96, 3.74], + '64.width': [3.4, 2.56], + '64.x': [605.03, 608.73], + '64.y': [83.31, 62.71], + '65.height': [8.32, 6.27], + '65.width': [8.61, 6.48], + '65.x': [613.84, 615.36], + '65.y': [75.65, 56.95], + '66.height': [13.53, 10.19], + '66.width': [14.65, 11.03], + '66.x': [636.39, 632.34], + '66.y': [81.65, 61.46], + '67.height': [13.41, 10.1], + '67.width': [8.36, 6.29], + '67.x': [632.59, 629.48], + '67.y': [92.94, 69.97], + '68.height': [9.65, 7.26], + '68.width': [6.4, 4.82], + '68.x': [629.99, 627.52], + '68.y': [95.09, 71.58], + '69.height': [1.95, 1.47], + '69.width': [2.25, 1.69], + '69.x': [630.57, 627.96], + '69.y': [95.15, 71.63], + '70.height': [14.67, 11.04], + '70.width': [13.34, 10.04], + '70.x': [644.4, 638.37], + '70.y': [111.24, 83.74], + '71.height': [11.43, 8.6], + '71.width': [3.29, 2.47], + '71.x': [656.64, 647.58], + '71.y': [112.75, 84.87], + '72.height': [24.4, 18.37], + '72.width': [11.86, 8.93], + '72.x': [653.75, 645.41], + '72.y': [114.4, 86.12], + '73.height': [2.34, 1.77], + '73.width': [1.5, 1.13], + '73.x': [653.07, 644.9], + '73.y': [137.24, 103.31], + '74.height': [20.42, 15.37], + '74.width': [14.1, 10.62], + '74.x': [632.96, 629.76], + '74.y': [105.44, 79.37], + '75.height': [3.29, 2.48], + '75.width': [1.95, 1.47], + '75.x': [652.96, 644.81], + '75.y': [102.24, 76.97], + '76.height': [5.31, 4], + '76.width': [1.36, 1.02], + '76.x': [656.22, 647.26], + '76.y': [49.24, 37.07], + '77.height': [2.16, 1.62], + '77.width': [1.33, 1], + '77.x': [656.79, 647.69], + '77.y': [47.35, 35.64], + '78.height': [20.14, 15.16], + '78.width': [8.98, 6.76], + '78.x': [667.41, 655.69], + '78.y': [117.01, 88.08], + '79.height': [1.65, 1.24], + '79.width': [0.61, 0.46], + '79.x': [656.85, 647.74], + '79.y': [50.28, 37.85], + '80.height': [1.13, 0.85], + '80.width': [3.38, 2.54], + '80.x': [601.1, 605.77], + '80.y': [77.52, 58.35], + '81.height': [9.75, 7.34], + '81.width': [4.19, 3.15], + '81.x': [627.84, 625.9], + '81.y': [43.66, 32.86], + '82.height': [25.79, 19.41], + '82.width': [22.43, 16.88], + '82.x': [610.66, 612.97], + '82.y': [43.97, 33.1], + '83.height': [5.88, 4.43], + '83.width': [4.04, 3.04], + '83.x': [657.2, 648], + '83.y': [49.1, 36.96], + '84.height': [5.19, 3.9], + '84.width': [5.09, 3.83], + '84.x': [676.12, 662.25], + '84.y': [59.49, 44.78], + '85.height': [2.26, 1.7], + '85.width': [0.99, 0.75], + '85.x': [674.96, 661.37], + '85.y': [59.4, 44.72], + '86.height': [2.18, 1.64], + '86.width': [2.09, 1.58], + '86.x': [669.7, 657.41], + '86.y': [53.76, 40.47], + '87.height': [11.51, 8.67], + '87.width': [11.07, 8.34], + '87.x': [660.56, 650.54], + '87.y': [43.61, 32.83], + '88.height': [14.35, 10.8], + '88.width': [7.97, 6], + '88.x': [677.54, 663.32], + '88.y': [59, 44.41], + '89.height': [2.96, 2.23], + '89.width': [0.86, 0.65], + '89.x': [806.11, 760.1], + '89.y': [120.91, 91.02], + '90.height': [6.17, 4.65], + '90.width': [6.01, 4.52], + '90.x': [734.78, 706.41], + '90.y': [76.47, 57.56], + '91.height': [22.2, 16.71], + '91.width': [10.12, 7.62], + '91.x': [727.92, 701.24], + '91.y': [67.74, 50.99], + '92.height': [12.78, 9.62], + '92.width': [9.9, 7.46], + '92.x': [730.33, 703.05], + '92.y': [64.72, 48.72], + '93.height': [27.27, 20.53], + '93.width': [10.61, 7.99], + '93.x': [721.39, 696.32], + '93.y': [56.21, 42.31], + '94.height': [22.09, 16.63], + '94.width': [10.99, 8.28], + '94.x': [731.87, 704.21], + '94.y': [63.42, 47.74], + '95.height': [7.01, 5.28], + '95.width': [5.21, 3.92], + '95.x': [745.21, 714.25], + '95.y': [36.21, 27.26], + '96.height': [5.74, 4.32], + '96.width': [4.98, 3.75], + '96.x': [748.81, 716.97], + '96.y': [41.96, 31.58], + '97.height': [12.92, 9.73], + '97.width': [32.38, 24.37], + '97.x': [702.72, 682.27], + '97.y': [25.09, 18.89], + '98.height': [40.29, 30.33], + '98.width': [30.22, 22.75], + '98.x': [694.33, 675.95], + '98.y': [46.18, 34.76], + '99.height': [8.44, 6.36], + '99.width': [6.38, 4.81], + '99.x': [715.44, 691.84], + '99.y': [58.93, 44.36], + '100.height': [2.27, 1.71], + '100.width': [3.65, 2.75], + '100.x': [715.51, 691.9], + '100.y': [56.27, 42.36], + '101.height': [5.75, 4.33], + '101.width': [9.45, 7.12], + '101.x': [705.58, 684.42], + '101.y': [53.24, 40.08], + '102.height': [18.98, 14.29], + '102.width': [15.74, 11.85], + '102.x': [684.75, 668.74], + '102.y': [43.95, 33.08], + '103.height': [12.68, 9.55], + '103.width': [13.81, 10.4], + '103.x': [683.2, 667.57], + '103.y': [42.13, 31.71], + '104.height': [5.64, 4.25], + '104.width': [8.41, 6.33], + '104.x': [688.28, 671.4], + '104.y': [38.85, 29.24], + '105.height': [5.26, 3.96], + '105.width': [9.6, 7.23], + '105.x': [690.01, 672.7], + '105.y': [35.81, 26.96], + '106.height': [9.97, 7.51], + '106.width': [15.79, 11.89], + '106.x': [672.27, 659.35], + '106.y': [36.52, 27.49], + '107.height': [20.42, 15.37], + '107.width': [23.66, 17.81], + '107.x': [664.58, 653.56], + '107.y': [40.49, 30.48], + '108.height': [6.77, 5.09], + '108.width': [6.22, 4.68], + '108.x': [657.14, 647.96], + '108.y': [43.82, 32.99], + '109.height': [3.32, 2.5], + '109.width': [3.6, 2.71], + '109.x': [663.59, 652.81], + '109.y': [38.47, 28.96], + '110.height': [13.23, 9.96], + '110.width': [9.68, 7.29], + '110.x': [629.55, 627.19], + '110.y': [8.1, 6.1], + '111.height': [5.49, 4.14], + '111.width': [8.5, 6.4], + '111.x': [641.29, 636.03], + '111.y': [20.44, 15.39], + '112.height': [8.52, 6.41], + '112.width': [16.96, 12.77], + '112.x': [640.96, 635.78], + '112.y': [24.76, 18.64], + '113.height': [6.77, 5.09], + '113.width': [9.57, 7.21], + '113.x': [632.82, 629.65], + '113.y': [21.9, 16.48], + '114.height': [3.2, 2.41], + '114.width': [7.06, 5.32], + '114.x': [629.09, 626.84], + '114.y': [28.65, 21.57], + '115.height': [3.53, 2.66], + '115.width': [6.08, 4.58], + '115.x': [635.57, 631.72], + '115.y': [29.15, 21.95], + '116.height': [3.68, 2.77], + '116.width': [3.63, 2.73], + '116.x': [645.31, 639.05], + '116.y': [29.34, 22.09], + '117.height': [5.67, 4.27], + '117.width': [9.31, 7.01], + '117.x': [639.53, 634.7], + '117.y': [29.64, 22.31], + '118.height': [2.74, 2.06], + '118.width': [5.11, 3.85], + '118.x': [638.73, 634.1], + '118.y': [20.22, 15.22], + '119.height': [2.54, 1.91], + '119.width': [6.4, 4.82], + '119.x': [638.63, 634.02], + '119.y': [18.51, 13.93], + '120.height': [2.23, 1.68], + '120.width': [4.11, 3.09], + '120.x': [640.14, 635.16], + '120.y': [16.8, 12.65], + '121.height': [9.02, 6.79], + '121.width': [8.42, 6.34], + '121.x': [625.53, 624.16], + '121.y': [21.75, 16.37], + '122.height': [3.88, 2.92], + '122.width': [6.09, 4.58], + '122.x': [641.98, 636.55], + '122.y': [34.61, 26.06], + '123.height': [9.26, 6.97], + '123.width': [6.87, 5.17], + '123.x': [640.34, 635.31], + '123.y': [37.71, 28.39], + '124.height': [8.43, 6.35], + '124.width': [19.87, 14.96], + '124.x': [646, 639.57], + '124.y': [37.3, 28.08], + '125.height': [4.01, 3.02], + '125.width': [1.9, 1.43], + '125.x': [639.17, 634.43], + '125.y': [36.6, 27.55], + '126.height': [5.11, 3.84], + '126.width': [5.58, 4.2], + '126.x': [633.27, 629.99], + '126.y': [31.76, 23.91], + '127.height': [2.54, 1.91], + '127.width': [4.22, 3.18], + '127.x': [625.81, 624.37], + '127.y': [30.12, 22.67], + '128.height': [0.82, 0.62], + '128.width': [0.52, 0.39], + '128.x': [625.34, 624.02], + '128.y': [27.35, 20.59], + '129.height': [2.3, 1.74], + '129.width': [3.4, 2.56], + '129.x': [622.33, 621.76], + '129.y': [25.76, 19.39], + '130.height': [3.14, 2.36], + '130.width': [3.4, 2.56], + '130.x': [623.07, 622.31], + '130.y': [23.41, 17.62], + '131.height': [7.22, 5.44], + '131.width': [3.29, 2.48], + '131.x': [610.33, 612.72], + '131.y': [37.12, 27.95], + '132.height': [10.33, 7.77], + '132.width': [12.3, 9.26], + '132.x': [610.72, 613.02], + '132.y': [35.23, 26.52], + '133.height': [3.94, 2.97], + '133.width': [3.71, 2.79], + '133.x': [610.79, 613.07], + '133.y': [21.59, 16.25], + '134.height': [3.38, 2.55], + '134.width': [2.26, 1.7], + '134.x': [800.9, 756.18], + '134.y': [129.09, 97.18], + '135.height': [6.43, 4.84], + '135.width': [5.73, 4.32], + '135.x': [797.23, 753.42], + '135.y': [108.74, 81.86], + '136.height': [16.03, 12.06], + '136.width': [21.43, 16.13], + '136.x': [780.88, 741.11], + '136.y': [149.68, 112.68], + '137.height': [46.99, 35.37], + '137.width': [45.92, 34.57], + '137.x': [739.77, 710.16], + '137.y': [114.93, 86.52], + '138.height': [5.87, 4.42], + '138.width': [2.44, 1.83], + '138.x': [710.12, 687.84], + '138.y': [83.65, 62.97], + '139.height': [47.57, 35.81], + '139.width': [55.95, 42.12], + '139.x': [694.4, 676], + '139.y': [23.47, 17.66], + '140.height': [4.86, 3.66], + '140.width': [1.52, 1.14], + '140.x': [751.01, 718.62], + '140.y': [60.59, 45.61], + '141.height': [13.64, 10.27], + '141.width': [12.02, 9.05], + '141.x': [626.57, 624.95], + '141.y': [31, 23.34], + '142.height': [3.19, 2.4], + '142.width': [4.17, 3.14], + '142.x': [627.16, 625.39], + '142.y': [18.77, 14.13], + '143.height': [9.73, 7.33], + '143.width': [8.4, 6.32], + '143.x': [613.14, 614.84], + '143.y': [17.81, 13.41], + '144.height': [2.74, 2.06], + '144.width': [8.6, 6.48], + '144.x': [600.34, 605.2], + '144.y': [10.25, 7.71], + '145.height': [4.75, 3.57], + '145.width': [5.73, 4.32], + '145.x': [664.93, 653.83], + '145.y': [37.67, 28.36], + '146.height': [3.23, 2.43], + '146.width': [7.28, 5.48], + '146.x': [659.34, 649.62], + '146.y': [35.48, 26.71], + '147.height': [19.53, 14.7], + '147.width': [10.77, 8.11], + '147.x': [752.47, 719.72], + '147.y': [70.58, 53.13], + '148.height': [9.41, 7.08], + '148.width': [21.75, 16.38], + '148.x': [733.38, 705.35], + '148.y': [88.06, 66.29], + '149.height': [2.2, 1.66], + '149.width': [1.33, 1], + '149.x': [749.58, 717.54], + '149.y': [90.32, 67.99], + '150.height': [1.75, 1.31], + '150.width': [2.72, 2.04], + '150.x': [633.24, 629.97], + '150.y': [31.33, 23.58], + '151.height': [9.29, 6.99], + '151.width': [10.13, 7.63], + '151.x': [636.07, 632.1], + '151.y': [7.28, 5.48], + '152.height': [2.2, 1.66], + '152.width': [5.29, 3.98], + '152.x': [636.02, 632.06], + '152.y': [28.01, 21.09], + '153.height': [3.06, 2.31], + '153.width': [6.3, 4.74], + '153.x': [631.45, 628.62], + '153.y': [26.17, 19.7], + '154.height': [8.32, 6.27], + '154.width': [7.76, 5.84], + '154.x': [660.62, 650.57], + '154.y': [71.34, 53.7], + '155.height': [19.44, 14.63], + '155.width': [9.93, 7.48], + '155.x': [755.38, 721.91], + '155.y': [32.95, 24.8], + '156.height': [12, 9.03], + '156.width': [9.67, 7.28], + '156.x': [551.32, 568.3], + '156.y': [127.96, 96.33], + '157.height': [9.62, 7.24], + '157.width': [11.54, 8.68], + '157.x': [667.6, 655.83], + '157.y': [69.84, 52.58], + '158.height': [23, 17.32], + '158.width': [23.92, 18.01], + '158.x': [657.12, 647.94], + '158.y': [50.8, 38.24], + '159.height': [14.1, 10.61], + '159.width': [252.33, 189.95], + '159.x': [497.36, 527.68], + '159.y': [184.1, 138.59], + '160.height': [0.92, 0.69], + '160.width': [1.81, 1.36], + '160.x': [653.91, 645.53], + '160.y': [45.94, 34.58], + '161.height': [0.83, 0.62], + '161.width': [1.83, 1.38], + '161.x': [653.43, 645.16], + '161.y': [46.62, 35.1], + '162.height': [20.44, 15.39], + '162.width': [17.52, 13.19], + '162.x': [601.3, 605.92], + '162.y': [45.82, 34.49], + '163.height': [13.8, 10.39], + '163.width': [14.2, 10.69], + '163.x': [646.23, 639.74], + '163.y': [51.6, 38.85], + '164.height': [19.55, 14.71], + '164.width': [17.52, 13.19], + '164.x': [630.06, 627.57], + '164.y': [49.44, 37.21], + '165.height': [17.53, 13.2], + '165.width': [16.77, 12.62], + '165.x': [657.28, 648.06], + '165.y': [75.88, 57.12], + '166.height': [2.69, 2.02], + '166.width': [1.8, 1.35], + '166.x': [666.88, 655.29], + '166.y': [79.29, 59.69], + '167.height': [5.27, 3.96], + '167.width': [7.28, 5.48], + '167.x': [667.97, 656.11], + '167.y': [81.16, 61.1], + '168.height': [8.71, 6.56], + '168.width': [6.2, 4.66], + '168.x': [653.61, 645.3], + '168.y': [92.15, 69.36], + '169.height': [2.73, 2.05], + '169.width': [2.05, 1.54], + '169.x': [652.96, 644.81], + '169.y': [100.39, 75.57], + '170.height': [3.3, 2.48], + '170.width': [3.86, 2.91], + '170.x': [635.36, 631.56], + '170.y': [33.35, 25.1], + '171.height': [1.93, 1.45], + '171.width': [2.51, 1.89], + '171.x': [640.41, 635.37], + '171.y': [37.07, 27.91], + '172.height': [5, 3.76], + '172.width': [4.45, 3.35], + '172.x': [638.22, 633.71], + '172.y': [32.17, 24.22], + '173.height': [2.13, 1.6], + '173.width': [1.82, 1.37], + '173.x': [638.28, 633.76], + '173.y': [35.52, 26.74], + '174.height': [1.84, 1.39], + '174.width': [1.67, 1.26], + '174.x': [639.88, 634.96], + '174.y': [35.84, 26.98], + '175.height': [1.35, 1.02], + '175.width': [1.27, 0.96], + '175.x': [550.12, 567.4], + '175.y': [82.03, 61.75], + '176.height': [13.3, 10.02], + '176.width': [13.02, 9.8], + '176.x': [647, 640.32], + '176.y': [79.97, 60.2], + }, + legend: { + 'continuousLegend.bounds.height': [46, 95], + 'continuousLegend.bar.height': [12, 15], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.usStatesCategoricalSpec @390': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [265.55, 250.55], + }, + area: { + 'rect.height': [265.55, 250.55], + 'rect.y': [90.85, 105.85], + }, + marks: { + '0.y': [158.26, 150.76], + '1.y': [189.39, 181.89], + '2.y': [134.06, 126.56], + '3.y': [106.3, 98.8], + '4.y': [189.33, 181.83], + '5.y': [156.08, 148.58], + '6.y': [101.47, 93.97], + '7.y': [118.95, 111.45], + '8.y': [36.53, 29.03], + '9.y': [76.25, 68.75], + '10.y': [42.48, 34.98], + '11.y': [94.21, 86.71], + '12.y': [135.02, 127.52], + '13.y': [43.77, 36.27], + '14.y': [143.56, 136.06], + '15.y': [89.88, 82.38], + '16.y': [68.79, 61.29], + '17.y': [147.7, 140.2], + '18.y': [71.61, 64.11], + '19.y': [84.61, 77.11], + '20.y': [114.47, 106.97], + '21.y': [107.03, 99.53], + '22.y': [97.27, 89.77], + '23.y': [139.41, 131.91], + '24.y': [148.26, 140.76], + '25.y': [78.14, 70.64], + '26.y': [107.72, 100.22], + '27.y': [116.57, 109.07], + '28.y': [212.4, 204.9], + '29.y': [90.3, 82.8], + '30.y': [123.08, 115.58], + '31.y': [109.01, 101.51], + '32.y': [50.58, 43.08], + '33.y': [159.83, 152.33], + '34.y': [34.05, 26.55], + '35.y': [57.16, 49.66], + '36.y': [62.78, 55.28], + '37.y': [96.01, 88.51], + '38.y': [44.88, 37.38], + '39.y': [141.38, 133.88], + '40.y': [93.14, 85.64], + '41.y': [114.31, 106.81], + '42.y': [24.55, 17.05], + '43.y': [60.48, 52.98], + '44.y': [93.12, 85.62], + '45.y': [152.82, 145.32], + '46.y': [32.91, 25.41], + '47.y': [85.15, 77.65], + '48.y': [60.12, 52.62], + '49.y': [177.74, 170.24], + '50.y': [84, 76.5], + }, + legend: { + 'categoricalLegend.bounds.height': [16, 31], + 'categoricalLegend.entry.0.y': [69.85, 84.85], + 'categoricalLegend.entry.1.y': [69.85, 84.85], + 'categoricalLegend.entry.2.y': [69.85, 84.85], + 'categoricalLegend.entry.3.y': [69.85, 84.85], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.usStatesCategoricalSpec @1280': { + reason: + 'Approved B3 static map captions and neutral-class context reserve measured key space; occupied-bounds size-key placement has no legacy layout opt-out.', + changes: { + dims: { + 'mapSize.height': [223.2, 208.2], + }, + area: { + 'rect.height': [223.2, 208.2], + 'rect.y': [113.2, 128.2], + }, + marks: { + '0.height': [42.48, 39.63], + '0.width': [26.04, 24.29], + '0.x': [692.13, 687.28], + '0.y': [137.88, 128.61], + '1.height': [52.3, 48.79], + '1.width': [97.97, 91.38], + '1.x': [429.23, 442.05], + '1.y': [169.98, 158.56], + '2.height': [53.75, 50.14], + '2.width': [45.99, 42.9], + '2.x': [504.42, 512.18], + '2.y': [112.93, 105.34], + '3.height': [38.93, 36.31], + '3.width': [49.14, 45.84], + '3.x': [550.41, 555.09], + '3.y': [84.3, 78.63], + '4.height': [53.28, 49.7], + '4.width': [61.55, 57.41], + '4.x': [699.17, 693.85], + '4.y': [169.92, 158.5], + '5.height': [38.49, 35.91], + '5.width': [36.74, 34.27], + '5.x': [710.07, 704.01], + '5.y': [135.63, 126.51], + '6.height': [36.19, 33.76], + '6.width': [20.95, 19.54], + '6.x': [690.8, 686.04], + '6.y': [79.32, 73.99], + '7.height': [27.12, 25.3], + '7.width': [50.08, 46.71], + '7.x': [597.42, 598.93], + '7.y': [97.35, 90.81], + '8.height': [39.22, 36.58], + '8.width': [24.88, 23.21], + '8.x': [785.89, 774.74], + '8.y': [12.35, 11.52], + '9.height': [12.96, 12.09], + '9.width': [23.46, 21.88], + '9.x': [778.27, 767.63], + '9.y': [53.31, 49.73], + '10.height': [50.05, 46.69], + '10.width': [44.47, 41.48], + '10.x': [631.14, 630.39], + '10.y': [18.49, 17.25], + '11.height': [20.73, 19.34], + '11.width': [9.02, 8.42], + '11.x': [770.21, 760.11], + '11.y': [71.83, 67.01], + '12.height': [26.41, 24.63], + '12.width': [59.65, 55.64], + '12.x': [718.86, 712.22], + '12.y': [113.91, 106.26], + '13.height': [27.9, 26.02], + '13.width': [44.44, 41.46], + '13.x': [590.44, 592.42], + '13.y': [19.82, 18.49], + '14.height': [30.78, 28.71], + '14.width': [58.34, 54.42], + '14.x': [590.64, 592.61], + '14.y': [122.72, 114.48], + '15.height': [25.47, 23.76], + '15.width': [39.29, 36.65], + '15.x': [735.22, 727.48], + '15.y': [67.37, 62.84], + '16.height': [31.64, 29.52], + '16.width': [47.2, 44.03], + '16.x': [588.26, 590.39], + '16.y': [45.62, 42.55], + '17.height': [92.85, 86.61], + '17.width': [94.69, 88.32], + '17.x': [561.57, 565.5], + '17.y': [127, 118.46], + '18.height': [39.3, 36.66], + '18.width': [47.2, 44.03], + '18.x': [542.48, 547.69], + '18.y': [48.53, 45.27], + '19.height': [11.52, 10.74], + '19.width': [11.68, 10.89], + '19.x': [778.47, 767.82], + '19.y': [61.93, 57.77], + '20.height': [39.25, 36.62], + '20.width': [45.05, 42.02], + '20.x': [639.67, 638.35], + '20.y': [92.72, 86.49], + '21.height': [30.43, 28.39], + '21.width': [30.36, 28.32], + '21.x': [726.59, 719.42], + '21.y': [85.05, 79.33], + '22.height': [48.01, 44.78], + '22.width': [26.94, 25.13], + '22.x': [667.16, 663.99], + '22.y': [74.98, 69.94], + '23.height': [49.04, 45.74], + '23.width': [47.25, 44.07], + '23.x': [543.71, 548.84], + '23.y': [118.44, 110.48], + '24.height': [31, 28.92], + '24.width': [34.1, 31.8], + '24.x': [647.55, 645.7], + '24.y': [127.57, 118.99], + '25.height': [92.93, 86.68], + '25.width': [54.25, 50.61], + '25.x': [457.85, 468.75], + '25.y': [55.26, 51.55], + '26.height': [11.83, 11.03], + '26.width': [7.09, 6.61], + '26.x': [768.58, 758.6], + '26.y': [85.76, 80], + '27.height': [1.72, 1.6], + '27.width': [1.43, 1.33], + '27.x': [761.45, 751.94], + '27.y': [94.89, 88.52], + '28.height': [28.2, 26.3], + '28.width': [43.57, 40.65], + '28.x': [532.2, 538.1], + '28.y': [193.71, 180.69], + '29.height': [26.86, 25.05], + '29.width': [40.81, 38.06], + '29.x': [634.22, 633.27], + '29.y': [67.8, 63.24], + '30.height': [25.7, 23.97], + '30.width': [50.06, 46.69], + '30.x': [681.77, 677.62], + '30.y': [101.6, 94.77], + '31.height': [15.29, 14.26], + '31.width': [30.62, 28.56], + '31.x': [745.05, 736.65], + '31.y': [87.09, 81.24], + '32.height': [53.84, 50.22], + '32.width': [51.22, 47.78], + '32.x': [670.99, 667.56], + '32.y': [26.84, 25.04], + '33.height': [41.92, 39.11], + '33.width': [24.17, 22.54], + '33.x': [669.82, 666.47], + '33.y': [139.5, 130.13], + '34.height': [43.87, 40.92], + '34.width': [69.03, 64.39], + '34.x': [523.57, 530.05], + '34.y': [9.8, 9.14], + '35.height': [23.48, 21.9], + '35.width': [11.13, 10.38], + '35.x': [782.01, 771.13], + '35.y': [33.62, 31.36], + '36.height': [38.95, 36.34], + '36.width': [50.97, 47.55], + '36.x': [739.5, 731.47], + '36.y': [39.42, 36.77], + '37.height': [32.36, 30.18], + '37.width': [28.31, 26.41], + '37.x': [708.78, 702.81], + '37.y': [73.69, 68.74], + '38.height': [45.88, 42.8], + '38.width': [54.37, 50.72], + '38.x': [462.58, 473.16], + '38.y': [20.96, 19.55], + '39.height': [20.07, 18.72], + '39.width': [57.58, 53.71], + '39.x': [677.58, 673.71], + '39.y': [120.47, 112.37], + '40.height': [47.72, 44.51], + '40.width': [38.01, 35.45], + '40.x': [517.09, 524.01], + '40.y': [70.72, 65.97], + '41.height': [29.93, 27.92], + '41.width': [53.67, 50.06], + '41.x': [721.54, 714.72], + '41.y': [92.56, 86.34], + '42.height': [33.61, 31.35], + '42.width': [45.35, 42.3], + '42.x': [474.58, 484.36], + '43.height': [39.06, 36.43], + '43.width': [36.29, 33.85], + '43.x': [656.73, 654.27], + '43.y': [37.05, 34.56], + '44.height': [27.91, 26.03], + '44.width': [55.84, 52.09], + '44.x': [586.8, 589.03], + '44.y': [70.71, 65.96], + '45.height': [26.26, 24.49], + '45.width': [34.42, 32.11], + '45.x': [725.85, 718.74], + '45.y': [132.27, 123.38], + '46.height': [65.3, 60.91], + '46.width': [40.29, 37.58], + '46.x': [506.88, 514.48], + '46.y': [8.62, 8.04], + '47.height': [66.56, 62.09], + '47.width': [43.04, 40.14], + '47.x': [482.22, 491.48], + '47.y': [62.49, 58.29], + '48.height': [21.48, 20.04], + '48.width': [11.41, 10.64], + '48.x': [773.36, 763.05], + '48.y': [36.68, 34.21], + '49.height': [34.03, 31.74], + '49.width': [39.1, 36.47], + '49.x': [652.08, 649.92], + '49.y': [157.97, 147.35], + '50.height': [7.51, 7.01], + '50.width': [5.26, 4.91], + '50.x': [788.86, 777.51], + '50.y': [61.3, 57.18], + }, + legend: { + 'categoricalLegend.bounds.height': [16, 31], + 'categoricalLegend.entry.0.y': [92.2, 107.2], + 'categoricalLegend.entry.1.y': [92.2, 107.2], + 'categoricalLegend.entry.2.y': [92.2, 107.2], + 'categoricalLegend.entry.3.y': [92.2, 107.2], + }, + }, + style: {}, + }, +}; diff --git a/examples/src/__tests__/migration-v8-attribution-changes.ts b/examples/src/__tests__/migration-v8-attribution-changes.ts new file mode 100644 index 00000000..13102069 --- /dev/null +++ b/examples/src/__tests__/migration-v8-attribution-changes.ts @@ -0,0 +1,10117 @@ +import type { GeometryValue } from './parity-signature'; + +/** C7 measured attribution, relative to the verified B3/P3 output. + * Exact released-v8/final-v9 pairs only; the v8 capture is never regenerated. + * A narrower measured brand reserve can enlarge the plot and change automatic + * label fitting. Every affected path remains guarded independently. */ +export const APPROVED_C7_ATTRIBUTION: Record< + string, + { + reason: string; + changes: Record>; + style: Record; + } +> = { + '../charts/mobile-regression.stories.tsx.longTitleSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [106.3, 118.7], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [260.45, 272.85], + 'x.start.y': [260.45, 272.85], + 'y.end.y': [260.45, 272.85], + 'y.tick.0.position': [260.45, 272.85], + 'y.tick.1.position': [239.19, 249.11], + 'y.tick.2.position': [217.93, 225.37], + 'y.tick.3.position': [196.67, 201.63], + 'y.tick.4.position': [175.41, 177.89], + 'y.titlePosition.y': [207.3, 213.5], + }, + marks: { + '0.height': [17.11, 19.11], + '0.y': [243.34, 253.74], + '1.height': [44.11, 49.26], + '1.y': [216.34, 223.59], + '2.height': [78.13, 87.25], + '2.y': [182.32, 185.61], + '3.height': [89.29, 99.71], + '3.y': [171.16, 173.14], + '4.height': [96.41, 107.66], + '4.y': [164.04, 165.19], + }, + labels: { + '0.label.y': [231.34, 241.74], + '1.label.y': [204.34, 211.59], + '2.label.y': [170.32, 173.61], + '3.label.y': [159.16, 161.14], + '4.label.y': [152.04, 153.19], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.longTitleSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.groupedLabelsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.groupedLabelsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.manyRowsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.manyRowsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.domainScoresSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.domainScoresSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.oneWideLabelSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.oneWideLabelSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.oneWideLabelThemedSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.oneWideLabelThemedSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.percentBucketsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.percentBucketsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.inlineYTitleSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.inlineYTitleSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.autoHeightChromeGrowthSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.chromeGrowSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.height': [600.6, 588.2], + }, + chrome: { + bottomHeight: [52, 39.6], + grownHeight: [200.6, 188.2], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.chromeGrowSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.chromeMaxLinesSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [195.7, 208.1], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [306, 318.4], + 'x.start.y': [306, 318.4], + 'y.end.y': [306, 318.4], + 'y.tick.0.position': [306, 318.4], + 'y.tick.1.position': [266.86, 276.78], + 'y.tick.2.position': [227.72, 235.16], + 'y.tick.3.position': [188.58, 193.54], + 'y.tick.4.position': [149.44, 151.92], + 'y.titlePosition.y': [208.15, 214.35], + }, + marks: { + '0.height': [31.51, 33.5], + '0.y': [274.49, 284.9], + '1.height': [81.22, 86.36], + '1.y': [224.78, 232.04], + '2.height': [143.84, 152.95], + '2.y': [162.16, 165.45], + '3.height': [164.39, 174.8], + '3.y': [141.61, 143.6], + '4.height': [177.5, 188.75], + '4.y': [128.5, 129.65], + }, + labels: { + '0.label.y': [262.49, 272.9], + '1.label.y': [212.78, 220.04], + '2.label.y': [150.16, 153.45], + '3.label.y': [129.61, 131.6], + '4.label.y': [116.5, 117.65], + }, + }, + style: {}, + }, + '../charts/mobile-regression.stories.tsx.chromeMaxLinesSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.simpleBarsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.simpleBarsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.columnsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.columnsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.groupedColumnsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.groupedColumnsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.stackedBarsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.stackedBarsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.normalizedBarsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.normalizedBarsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.divergingColumnsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.divergingColumnsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.negativeValuesSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.negativeValuesSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.barListSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.barListSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.longLabelsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.longLabelsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.interactiveSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-bar-column.stories.tsx.interactiveSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.directLabelSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [136.3, 150.3], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [264, 278], + 'x.start.y': [264, 278], + 'x.titlePosition.y': [299, 313], + 'y.end.y': [264, 278], + 'y.tick.0.position': [246.07, 258.22], + 'y.tick.1.position': [210.2, 218.67], + 'y.tick.2.position': [174.33, 179.12], + 'y.tick.3.position': [138.46, 139.57], + 'y.titlePosition.y': [195.85, 202.85], + }, + marks: { + '0.cy': [142.05, 143.52], + '1.cy': [172.54, 177.14], + '10.y': [128.05, 129.52], + '11.y': [158.54, 163.14], + '12.y': [197.63, 206.25], + '13.y': [186.87, 194.39], + '14.y': [223.1, 234.34], + '2.cy': [211.63, 220.25], + '3.cy': [200.87, 208.39], + '4.cy': [237.1, 248.34], + '5.cy': [235.66, 246.75], + '6.cy': [239.61, 251.1], + '7.cy': [242.48, 254.27], + '8.cy': [248.58, 260.99], + '9.cy': [253.96, 266.93], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.directLabelSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.ruleMarkSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [138.3, 152.3], + }, + chrome: { + bottomAnchorY: [286, 300], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'y.end.y': [286, 300], + 'y.tick.0.position': [286, 300], + 'y.tick.1.position': [260.85, 272.31], + 'y.tick.2.position': [235.71, 244.62], + 'y.tick.3.position': [210.56, 216.93], + 'y.tick.4.position': [185.42, 189.24], + 'y.tick.5.position': [160.27, 161.55], + 'y.titlePosition.y': [216.85, 223.85], + }, + marks: { + '0.y1': [151.97, 152.41], + '0.y2': [151.97, 152.41], + '1.y1': [179.13, 182.31], + '1.y2': [179.13, 182.31], + '2.y1': [197.99, 203.08], + '2.y2': [197.99, 203.08], + '3.y1': [235.71, 244.62], + '3.y2': [235.71, 244.62], + '4.y1': [286, 300], + '4.y2': [286, 300], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.ruleMarkSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.tickMarkSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.tickMarkSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.layerSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.layerSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.dualAxisSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.dualAxisSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.temporalDualAxisSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.temporalDualAxisSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.spanSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [143.68, 172.3], + }, + chrome: { + bottomAnchorY: [297.38, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [271.38, 300], + 'x.start.y': [271.38, 300], + 'y.end.y': [271.38, 300], + 'y.tick.0.position': [271.38, 300], + 'y.tick.1.position': [241.45, 264.1], + 'y.tick.2.position': [211.51, 228.21], + 'y.tick.3.position': [181.58, 192.31], + 'y.tick.4.position': [151.65, 156.42], + 'y.titlePosition.y': [199.54, 213.85], + }, + marks: { + '0.y1': [250.43, 274.87], + '0.y2': [215.71, 233.23], + '1.y1': [265.99, 293.54], + '1.y2': [216.3, 233.95], + '10.y1': [244.44, 267.69], + '10.y2': [200.74, 215.29], + '11.y1': [246.24, 269.85], + '11.y2': [212.71, 229.64], + '2.y1': [252.22, 277.03], + '2.y2': [206.73, 222.47], + '3.y1': [215.11, 232.52], + '3.y2': [157.63, 163.6], + '4.y1': [199.54, 213.85], + '4.y2': [139.07, 141.34], + '5.y1': [170.8, 179.39], + '5.y2': [119.32, 117.65], + '6.y1': [139.07, 141.34], + '6.y2': [90.58, 83.19], + '7.y1': [150.45, 154.98], + '7.y2': [106.15, 101.85], + '8.y1': [167.81, 175.8], + '8.y2': [125.9, 125.55], + '9.y1': [197.15, 210.98], + '9.y2': [155.84, 161.44], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.spanSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.composedSpecForPanel @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [173.7, 186.1], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [284, 296.4], + 'x.start.y': [284, 296.4], + 'x.titlePosition.y': [319, 331.4], + 'y.end.y': [284, 296.4], + 'y.tick.0.position': [261.14, 271.91], + 'y.tick.1.position': [215.43, 222.94], + 'y.tick.2.position': [169.72, 173.97], + 'y.tick.3.position': [124.01, 124.99], + 'y.titlePosition.y': [197.15, 203.35], + }, + marks: { + '0.cy': [128.58, 129.89], + '1.cy': [167.44, 171.52], + '10.y': [114.58, 115.89], + '11.y': [153.44, 157.52], + '12.y': [203.26, 210.9], + '13.y': [189.55, 196.21], + '14.y': [235.72, 245.67], + '15.y': [233.89, 243.71], + '16.y': [238.92, 249.1], + '17.y': [242.57, 253.02], + '18.y': [250.34, 261.34], + '19.y': [257.2, 268.69], + '2.cy': [217.26, 224.9], + '3.cy': [203.55, 210.21], + '4.cy': [249.72, 259.67], + '5.cy': [247.89, 257.71], + '6.cy': [252.92, 263.1], + '7.cy': [256.57, 267.02], + '8.cy': [264.34, 275.34], + '9.cy': [271.2, 282.69], + }, + }, + style: {}, + }, + '../gallery/charts-building-blocks.stories.tsx.composedSpecForPanel @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.singleLineSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.singleLineSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.multiSeriesSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [138.7, 152.7], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [286, 300], + 'x.start.y': [286, 300], + 'y.end.y': [286, 300], + 'y.tick.0.position': [268.66, 280.91], + 'y.tick.1.position': [225.32, 233.19], + 'y.tick.2.position': [181.98, 185.48], + 'y.titlePosition.y': [216.65, 223.65], + }, + marks: { + '0.height': [71.95, 79.21], + '0.y': [172.44, 174.98], + '1.height': [104.02, 114.52], + '1.y': [174.17, 176.89], + '2.height': [53.75, 59.17], + '2.y': [152.5, 153.03], + }, + annotations: { + 'a0.line.end.y': [225.32, 233.19], + 'a0.line.start.y': [225.32, 233.19], + 'a1.rect.height': [138.7, 152.7], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.multiSeriesSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.fiveSeriesSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [138.7, 152.7], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [286, 300], + 'x.start.y': [286, 300], + 'y.end.y': [286, 300], + 'y.tick.0.position': [252.52, 263.14], + 'y.tick.1.position': [204.69, 210.49], + 'y.tick.2.position': [156.87, 157.83], + 'y.titlePosition.y': [216.65, 223.65], + }, + marks: { + '0.height': [85.61, 94.25], + '0.y': [147.78, 147.83], + '1.height': [30.61, 33.7], + '1.y': [205.65, 211.54], + '2.height': [45.2, 49.76], + '2.y': [216.65, 223.65], + '3.height': [30.37, 33.44], + '3.y': [237.69, 246.82], + '4.height': [22.24, 24.48], + '4.y': [261.13, 272.62], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.fiveSeriesSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.singleAreaSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.singleAreaSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.stackedAreaSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.stackedAreaSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.timeAxisSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.timeAxisSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.logScaleSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.logScaleSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.interactiveSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [161.3, 173.7], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [306, 318.4], + 'x.start.y': [306, 318.4], + 'y.end.y': [306, 318.4], + 'y.tick.0.position': [267.07, 276.47], + 'y.tick.1.position': [211.44, 216.58], + 'y.tick.2.position': [155.82, 156.68], + 'y.titlePosition.y': [225.35, 231.55], + }, + marks: { + '0.height': [99.56, 107.21], + '0.y': [145.26, 145.3], + '1.height': [35.6, 38.33], + '1.y': [212.56, 217.77], + '2.height': [52.56, 56.6], + '2.y': [225.35, 231.55], + '3.height': [35.32, 38.03], + '3.y': [249.82, 257.9], + '4.height': [25.86, 27.85], + '4.y': [277.08, 287.25], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.interactiveSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.seriesSearchSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-line-area.stories.tsx.seriesSearchSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.basicPieSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.basicPieSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.donutSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.donutSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.smallSliceSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.smallSliceSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.manyCategoriesSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.manyCategoriesSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.leaderLineSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [201.7, 215.7], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + marks: { + '0.cy': [211.15, 218.15], + '0.innerRadius': [51.43, 55], + '0.outerRadius': [85.72, 91.67], + '1.cy': [211.15, 218.15], + '1.innerRadius': [51.43, 55], + '1.outerRadius': [85.72, 91.67], + '2.cy': [211.15, 218.15], + '2.innerRadius': [51.43, 55], + '2.outerRadius': [85.72, 91.67], + '3.cy': [211.15, 218.15], + '3.innerRadius': [51.43, 55], + '3.outerRadius': [85.72, 91.67], + '4.cy': [211.15, 218.15], + '4.innerRadius': [51.43, 55], + '4.outerRadius': [85.72, 91.67], + '5.cy': [211.15, 218.15], + '5.innerRadius': [51.43, 55], + '5.outerRadius': [85.72, 91.67], + '6.cy': [211.15, 218.15], + '6.innerRadius': [51.43, 55], + '6.outerRadius': [85.72, 91.67], + }, + labels: { + '0.label.x': [259.4, 263.32], + '0.label.y': [131.05, 133.58], + '1.label.x': [278.76, 283.86], + '1.label.y': [254.89, 264.95], + '2.label.x': [107.88, 107.02], + '2.label.y': [301.24, 314.13], + '3.label.x': [48.62, 43.35], + '3.label.y': [249.98, 259.74], + '4.label.x': [31.51, 25.74], + '4.label.y': [181.22, 186.8], + '5.label.x': [77.91, 73.74], + '5.label.y': [134.81, 137.57], + '6.label.x': [118.73, 117.24], + '6.label.y': [109.95, 111.19], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.leaderLineSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.interactiveSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.interactiveSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.waffleSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.waffleSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.parliamentSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.parliamentSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.halfDonutSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-pie-donut.stories.tsx.halfDonutSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.basicScatterSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [62.95, 76.95], + }, + chrome: { + bottomAnchorY: [265.1, 279.1], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [217.1, 231.1], + 'x.start.y': [217.1, 231.1], + 'x.titlePosition.y': [252.1, 266.1], + 'y.end.y': [217.1, 231.1], + 'y.tick.0.position': [210.8, 223.41], + 'y.tick.1.position': [195.07, 204.17], + 'y.tick.2.position': [179.33, 184.93], + 'y.tick.3.position': [163.59, 165.69], + 'y.titlePosition.y': [185.63, 192.63], + }, + marks: { + '0.height': [34.3, 41.92], + '0.y': [170.03, 173.56], + '1.cy': [155.72, 156.07], + '10.cy': [182.79, 189.16], + '11.cy': [182.79, 189.16], + '12.cy': [183.42, 189.93], + '13.cy': [184.37, 191.09], + '14.cy': [187.2, 194.55], + '15.cy': [187.51, 194.93], + '16.cy': [188.46, 196.09], + '17.cy': [189.4, 197.24], + '18.cy': [190.35, 198.4], + '19.cy': [192.55, 201.09], + '2.cy': [168, 171.08], + '20.cy': [207.03, 218.79], + '21.cy': [212.38, 225.33], + '22.cy': [216.16, 229.95], + '3.cy': [170.83, 174.54], + '4.cy': [176.18, 181.08], + '5.cy': [176.81, 181.85], + '6.cy': [180.27, 186.08], + '7.cy': [181.53, 187.62], + '8.cy': [181.85, 188.01], + '9.cy': [182.79, 189.16], + }, + annotations: { + 'a0.connector.from.x': [279.93, 279.91], + 'a0.connector.from.y': [155.3, 157.88], + 'a0.connector.to.x': [295.93, 295.95], + 'a0.connector.to.y': [155.64, 156.43], + 'a0.label.y': [158.15, 164.15], + 'a1.connector.from.x': [318.05, 317.66], + 'a1.connector.from.y': [196.76, 204.61], + 'a1.connector.to.x': [299.43, 299.44], + 'a1.connector.to.y': [191.44, 199.48], + 'a1.label.y': [210.4, 218.24], + 'a2.connector.from.y': [174.95, 179.85], + 'a2.connector.to.y': [175.82, 180.72], + 'a2.label.y': [176.18, 181.08], + 'a3.label.y': [184.14, 191.7], + 'a3.line.end.y': [188.14, 195.7], + 'a3.line.start.y': [188.14, 195.7], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.basicScatterSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.bubbleSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.bubbleSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.colorScatterSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.colorScatterSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.trendScatterSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.dotPlotSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [136.3, 150.3], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [264, 278], + 'x.start.y': [264, 278], + 'x.titlePosition.y': [299, 313], + 'y.end.y': [264, 278], + 'y.tick.0.position': [257.05, 270.33], + 'y.tick.1.position': [245.92, 258.06], + 'y.tick.10.position': [145.78, 147.64], + 'y.tick.11.position': [134.65, 135.37], + 'y.tick.2.position': [234.79, 245.79], + 'y.tick.3.position': [223.67, 233.52], + 'y.tick.4.position': [212.54, 221.25], + 'y.tick.5.position': [201.41, 208.98], + 'y.tick.6.position': [190.29, 196.72], + 'y.tick.7.position': [179.16, 184.45], + 'y.tick.8.position': [168.03, 172.18], + 'y.tick.9.position': [156.91, 159.91], + }, + marks: { + '0.y': [256.05, 269.33], + '1.cy': [257.05, 270.33], + '10.y': [200.41, 207.98], + '11.cy': [201.41, 208.98], + '12.y': [189.29, 195.72], + '13.cy': [190.29, 196.72], + '14.y': [178.16, 183.45], + '15.cy': [179.16, 184.45], + '16.y': [167.03, 171.18], + '17.cy': [168.03, 172.18], + '18.y': [155.91, 158.91], + '19.cy': [156.91, 159.91], + '2.y': [244.92, 257.06], + '20.y': [144.78, 146.64], + '21.cy': [145.78, 147.64], + '22.y': [133.65, 134.37], + '23.cy': [134.65, 135.37], + '3.cy': [245.92, 258.06], + '4.y': [233.79, 244.79], + '5.cy': [234.79, 245.79], + '6.y': [222.67, 232.52], + '7.cy': [223.67, 233.52], + '8.y': [211.54, 220.25], + '9.cy': [212.54, 221.25], + }, + labels: { + '1.label.y': [250.45, 263.73], + '11.label.y': [194.81, 202.38], + '13.label.y': [167.85, 174.28], + '15.label.y': [172.56, 177.85], + '17.label.y': [145.59, 149.74], + '19.label.y': [150.31, 153.31], + '21.label.y': [123.34, 125.2], + '23.label.y': [128.05, 128.77], + '3.label.y': [239.32, 251.46], + '5.label.y': [212.35, 223.35], + '7.label.y': [217.07, 226.92], + '9.label.y': [190.1, 198.81], + }, + annotations: { + 'a0.label.y': [274.05, 287.33], + 'a0.line.end.y': [264, 278], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.dotPlotSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.lollipopSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [162.75, 176.75], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [264, 278], + 'x.start.y': [264, 278], + 'x.titlePosition.y': [299, 313], + 'y.end.y': [264, 278], + 'y.tick.0.position': [256.32, 269.66], + 'y.tick.1.position': [244.04, 256.32], + 'y.tick.10.position': [133.49, 136.27], + 'y.tick.11.position': [121.21, 122.93], + 'y.tick.12.position': [108.93, 109.59], + 'y.tick.2.position': [231.76, 242.98], + 'y.tick.3.position': [219.47, 229.64], + 'y.tick.4.position': [207.19, 216.3], + 'y.tick.5.position': [194.91, 202.96], + 'y.tick.6.position': [182.63, 189.62], + 'y.tick.7.position': [170.34, 176.29], + 'y.tick.8.position': [158.06, 162.95], + 'y.tick.9.position': [145.78, 149.61], + }, + marks: { + '0.cy': [256.32, 269.66], + '1.cy': [244.04, 256.32], + '10.cy': [133.49, 136.27], + '11.cy': [121.21, 122.93], + '12.cy': [108.93, 109.59], + '2.cy': [231.76, 242.98], + '3.cy': [219.47, 229.64], + '4.cy': [207.19, 216.3], + '5.cy': [194.91, 202.96], + '6.cy': [182.63, 189.62], + '7.cy': [170.34, 176.29], + '8.cy': [158.06, 162.95], + '9.cy': [145.78, 149.61], + }, + labels: { + '0.label.y': [249.72, 263.06], + '1.label.y': [237.44, 249.72], + '10.label.x': [113.05, 126.85], + '10.label.y': [126.89, 129.67], + '11.label.y': [98.77, 116.33], + '12.label.x': [147.26, 115.8], + '12.label.y': [102.33, 102.99], + '2.label.y': [209.32, 236.38], + '3.label.y': [212.87, 223.04], + '4.label.y': [184.75, 209.7], + '5.label.y': [204.15, 196.36], + '6.label.y': [176.03, 183.02], + '7.label.y': [147.9, 169.69], + '8.label.y': [151.46, 156.35], + '9.label.y': [123.34, 143.01], + }, + annotations: { + 'a0.line.end.y': [264, 278], + }, + }, + style: { + 'marks.12.label.connector': [undefined, null], + 'marks.12.label.connector.arrow': [false, undefined], + 'marks.12.label.connector.stroke': ['#d1495b', undefined], + 'marks.12.label.connector.style': ['straight', undefined], + }, + }, + '../gallery/charts-scatter-distribution.stories.tsx.lollipopSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.dumbbellSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [89.85, 103.85], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [264, 278], + 'x.start.y': [264, 278], + 'x.titlePosition.y': [299, 313], + 'y.end.y': [264, 278], + 'y.tick.0.position': [259.42, 272.7], + 'y.tick.1.position': [252.08, 264.22], + 'y.tick.10.position': [186.07, 187.93], + 'y.tick.11.position': [178.73, 179.45], + 'y.tick.2.position': [244.75, 255.75], + 'y.tick.3.position': [237.41, 247.27], + 'y.tick.4.position': [230.08, 238.79], + 'y.tick.5.position': [222.74, 230.31], + 'y.tick.6.position': [215.41, 221.84], + 'y.tick.7.position': [208.07, 213.36], + 'y.tick.8.position': [200.74, 204.88], + 'y.tick.9.position': [193.4, 196.4], + }, + marks: { + '0.y': [258.42, 271.7], + '1.cy': [259.42, 272.7], + '10.cy': [237.41, 247.27], + '11.cy': [237.41, 247.27], + '12.y': [229.08, 237.79], + '13.cy': [230.08, 238.79], + '14.cy': [230.08, 238.79], + '15.y': [221.74, 229.31], + '16.cy': [222.74, 230.31], + '17.cy': [222.74, 230.31], + '18.y': [214.41, 220.84], + '19.cy': [215.41, 221.84], + '2.cy': [259.42, 272.7], + '20.cy': [215.41, 221.84], + '21.y': [207.07, 212.36], + '22.cy': [208.07, 213.36], + '23.cy': [208.07, 213.36], + '24.y': [199.74, 203.88], + '25.cy': [200.74, 204.88], + '26.cy': [200.74, 204.88], + '27.y': [192.4, 195.4], + '28.cy': [193.4, 196.4], + '29.cy': [193.4, 196.4], + '3.y': [251.08, 263.22], + '30.y': [185.07, 186.93], + '31.cy': [186.07, 187.93], + '32.cy': [186.07, 187.93], + '33.y': [177.73, 178.45], + '34.cy': [178.73, 179.45], + '35.cy': [178.73, 179.45], + '4.cy': [252.08, 264.22], + '5.cy': [252.08, 264.22], + '6.y': [243.75, 254.75], + '7.cy': [244.75, 255.75], + '8.cy': [244.75, 255.75], + '9.y': [236.41, 246.27], + }, + labels: { + '1.label.y': [252.82, 266.1], + '10.label.y': [214.97, 224.83], + '11.label.y': [214.97, 224.83], + '13.label.y': [223.48, 232.19], + '14.label.y': [207.64, 216.35], + '16.label.y': [200.3, 207.87], + '17.label.y': [200.3, 207.87], + '19.label.y': [208.81, 215.24], + '2.label.y': [252.82, 266.1], + '20.label.y': [192.97, 199.4], + '22.label.y': [201.47, 206.76], + '23.label.y': [185.63, 190.92], + '25.label.y': [178.3, 182.44], + '26.label.y': [178.3, 182.44], + '28.label.y': [186.8, 189.8], + '29.label.y': [186.8, 189.8], + '31.label.y': [179.47, 181.33], + '32.label.y': [163.63, 165.49], + '34.label.y': [156.29, 157.01], + '35.label.y': [172.13, 172.85], + '4.label.y': [229.64, 241.78], + '5.label.y': [245.48, 257.62], + '7.label.y': [238.15, 249.15], + '8.label.y': [222.31, 233.31], + }, + annotations: { + 'a0.connector.from.y': [180.32, 181.04], + 'a0.connector.to.y': [178.94, 179.65], + 'a0.dot.y': [178.73, 179.45], + 'a0.label.y': [178.73, 179.45], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.dumbbellSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.stripSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.stripSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.rangeDumbbellSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.rangeDumbbellSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.arrowPlotSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.arrowPlotSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.rangeBarSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [143.68, 157.68], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [271.38, 285.38], + 'x.start.y': [271.38, 285.38], + 'y.end.y': [271.38, 285.38], + 'y.tick.0.position': [271.38, 285.38], + 'y.tick.1.position': [226.48, 236.11], + 'y.tick.2.position': [181.58, 186.83], + 'y.tick.3.position': [136.68, 137.56], + 'y.titlePosition.y': [199.54, 206.54], + }, + marks: { + '0.height': [26.04, 28.58], + '0.y': [229.62, 239.56], + '1.height': [37.27, 40.9], + '1.y': [230.07, 240.05], + '10.height': [32.78, 35.97], + '10.y': [218.4, 227.24], + '11.height': [25.14, 27.59], + '11.y': [227.38, 237.09], + '2.height': [34.12, 37.45], + '2.y': [222.89, 232.16], + '3.height': [43.1, 47.3], + '3.y': [186.07, 191.76], + '4.height': [45.35, 49.77], + '4.y': [172.15, 176.48], + '5.height': [38.61, 42.38], + '5.y': [157.33, 160.22], + '6.height': [36.37, 39.91], + '6.y': [135.78, 136.57], + '7.height': [33.23, 36.46], + '7.y': [147.46, 149.38], + '8.height': [31.43, 34.49], + '8.y': [162.27, 165.64], + '9.height': [30.98, 34], + '9.y': [184.72, 190.28], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.rangeBarSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.interactiveSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.interactiveSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.beeswarmSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.beeswarmSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.calendarSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.calendarSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.heatmapSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [129.3, 143.3], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [286, 300], + 'x.start.y': [286, 300], + 'y.end.y': [286, 300], + 'y.tick.0.position': [274.87, 287.66], + 'y.tick.1.position': [253.46, 263.94], + 'y.tick.2.position': [232.05, 240.21], + 'y.tick.3.position': [210.65, 216.49], + 'y.tick.4.position': [189.24, 192.76], + 'y.tick.5.position': [167.83, 169.04], + }, + marks: { + '0.height': [20.55, 22.78], + '0.y': [264.59, 276.27], + '1.height': [20.55, 22.78], + '1.y': [243.19, 252.55], + '10.height': [20.55, 22.78], + '10.y': [178.96, 181.37], + '11.height': [20.55, 22.78], + '11.y': [157.56, 157.65], + '12.height': [20.55, 22.78], + '12.y': [264.59, 276.27], + '13.height': [20.55, 22.78], + '13.y': [243.19, 252.55], + '14.height': [20.55, 22.78], + '14.y': [221.78, 228.82], + '15.height': [20.55, 22.78], + '15.y': [200.37, 205.1], + '16.height': [20.55, 22.78], + '16.y': [178.96, 181.37], + '17.height': [20.55, 22.78], + '17.y': [157.56, 157.65], + '18.height': [20.55, 22.78], + '18.y': [264.59, 276.27], + '19.height': [20.55, 22.78], + '19.y': [243.19, 252.55], + '2.height': [20.55, 22.78], + '2.y': [221.78, 228.82], + '20.height': [20.55, 22.78], + '20.y': [221.78, 228.82], + '21.height': [20.55, 22.78], + '21.y': [200.37, 205.1], + '22.height': [20.55, 22.78], + '22.y': [178.96, 181.37], + '23.height': [20.55, 22.78], + '23.y': [157.56, 157.65], + '24.height': [20.55, 22.78], + '24.y': [264.59, 276.27], + '25.height': [20.55, 22.78], + '25.y': [243.19, 252.55], + '26.height': [20.55, 22.78], + '26.y': [221.78, 228.82], + '27.height': [20.55, 22.78], + '27.y': [200.37, 205.1], + '28.height': [20.55, 22.78], + '28.y': [178.96, 181.37], + '29.height': [20.55, 22.78], + '29.y': [157.56, 157.65], + '3.height': [20.55, 22.78], + '3.y': [200.37, 205.1], + '30.height': [20.55, 22.78], + '30.y': [264.59, 276.27], + '31.height': [20.55, 22.78], + '31.y': [243.19, 252.55], + '32.height': [20.55, 22.78], + '32.y': [221.78, 228.82], + '33.height': [20.55, 22.78], + '33.y': [200.37, 205.1], + '34.height': [20.55, 22.78], + '34.y': [178.96, 181.37], + '35.height': [20.55, 22.78], + '35.y': [157.56, 157.65], + '36.height': [20.55, 22.78], + '36.y': [264.59, 276.27], + '37.height': [20.55, 22.78], + '37.y': [243.19, 252.55], + '38.height': [20.55, 22.78], + '38.y': [221.78, 228.82], + '39.height': [20.55, 22.78], + '39.y': [200.37, 205.1], + '4.height': [20.55, 22.78], + '4.y': [178.96, 181.37], + '40.height': [20.55, 22.78], + '40.y': [178.96, 181.37], + '41.height': [20.55, 22.78], + '41.y': [157.56, 157.65], + '42.height': [20.55, 22.78], + '42.y': [264.59, 276.27], + '43.height': [20.55, 22.78], + '43.y': [243.19, 252.55], + '44.height': [20.55, 22.78], + '44.y': [221.78, 228.82], + '45.height': [20.55, 22.78], + '45.y': [200.37, 205.1], + '46.height': [20.55, 22.78], + '46.y': [178.96, 181.37], + '47.height': [20.55, 22.78], + '47.y': [157.56, 157.65], + '5.height': [20.55, 22.78], + '5.y': [157.56, 157.65], + '6.height': [20.55, 22.78], + '6.y': [264.59, 276.27], + '7.height': [20.55, 22.78], + '7.y': [243.19, 252.55], + '8.height': [20.55, 22.78], + '8.y': [221.78, 228.82], + '9.height': [20.55, 22.78], + '9.y': [200.37, 205.1], + }, + }, + style: {}, + }, + '../gallery/charts-scatter-distribution.stories.tsx.heatmapSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.saasMrrSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.saasMrrSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.saasAccountsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.saasAccountsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.opsErrorSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.opsErrorSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.marketsCompareSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.marketsCompareSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.funnelSankeySpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.funnelSankeySpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.incidentErrorSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.incidentErrorSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.incidentActivitySpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + }, + style: {}, + }, + '../gallery/dashboards.layouts.tsx.incidentActivitySpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + }, + style: {}, + }, + '../gallery/dashboards.stories.tsx.kpiSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.stories.tsx.kpiSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.stories.tsx.moversSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.stories.tsx.moversSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.stories.tsx.crosshairSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.stories.tsx.crosshairSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.stories.tsx.sectorSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/dashboards.stories.tsx.sectorSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.pieSweepSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [230.75, 243.15], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + marks: { + '0.cy': [216.63, 222.83], + '0.outerRadius': [98.07, 103.34], + '1.cy': [216.63, 222.83], + '1.outerRadius': [98.07, 103.34], + '2.cy': [216.63, 222.83], + '2.outerRadius': [98.07, 103.34], + '3.cy': [216.63, 222.83], + '3.outerRadius': [98.07, 103.34], + '4.cy': [216.63, 222.83], + '4.outerRadius': [98.07, 103.34], + '5.cy': [216.63, 222.83], + '5.outerRadius': [98.07, 103.34], + '6.cy': [216.63, 222.83], + '6.outerRadius': [98.07, 103.34], + }, + labels: { + '0.label.x': [267.54, 271.01], + '0.label.y': [127.24, 129.48], + '1.label.x': [289.34, 293.86], + '1.label.y': [266.72, 275.64], + '2.label.x': [106.1, 105.33], + '2.label.y': [318.93, 330.35], + '3.label.x': [37.69, 33.02], + '3.label.y': [261.19, 269.84], + '4.label.x': [19.53, 14.41], + '4.label.y': [183.75, 188.69], + '5.label.x': [69.26, 65.57], + '5.label.y': [131.48, 133.91], + '6.label.x': [115.63, 114.31], + '6.label.y': [103.47, 104.57], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.pieSweepSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.donutSweepSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [230.75, 243.15], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + marks: { + '0.cy': [216.63, 222.83], + '0.innerRadius': [58.84, 62], + '0.outerRadius': [98.07, 103.34], + '1.cy': [216.63, 222.83], + '1.innerRadius': [58.84, 62], + '1.outerRadius': [98.07, 103.34], + '2.cy': [216.63, 222.83], + '2.innerRadius': [58.84, 62], + '2.outerRadius': [98.07, 103.34], + '3.cy': [216.63, 222.83], + '3.innerRadius': [58.84, 62], + '3.outerRadius': [98.07, 103.34], + '4.cy': [216.63, 222.83], + '4.innerRadius': [58.84, 62], + '4.outerRadius': [98.07, 103.34], + '5.cy': [216.63, 222.83], + '5.innerRadius': [58.84, 62], + '5.outerRadius': [98.07, 103.34], + '6.cy': [216.63, 222.83], + '6.innerRadius': [58.84, 62], + '6.outerRadius': [98.07, 103.34], + }, + labels: { + '0.label.x': [267.54, 271.01], + '0.label.y': [127.24, 129.48], + '1.label.x': [289.34, 293.86], + '1.label.y': [266.72, 275.64], + '2.label.x': [106.1, 105.33], + '2.label.y': [318.93, 330.35], + '3.label.x': [37.69, 33.02], + '3.label.y': [261.19, 269.84], + '4.label.x': [19.53, 14.41], + '4.label.y': [183.75, 188.69], + '5.label.x': [69.26, 65.57], + '5.label.y': [131.48, 133.91], + '6.label.x': [115.63, 114.31], + '6.label.y': [103.47, 104.57], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.donutSweepSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.stackedChainSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.stackedChainSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.annotationDelaySpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.annotationDelaySpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.updateSpecForPanel @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.updateSpecForPanel @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.enterExitSpecForPanel @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-animation.stories.tsx.enterExitSpecForPanel @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.textAnnotationSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.textAnnotationSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.connectorsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.connectorsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.richTextSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.richTextSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.ledeSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.ledeSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.rangeSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.rangeSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.rectangleRangeSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.rectangleRangeSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.reflineSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.reflineSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.stabilitySpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.stabilitySpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.thinningSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.thinningSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.thinningDisabledSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-annotations.stories.tsx.thinningDisabledSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.filterBaseSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.filterBaseSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.filterOffSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.filterOffSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.binSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.binSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.calculateSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.calculateSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.timeUnitSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.timeUnitSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.conditionalSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.conditionalSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.linearGradientSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.linearGradientSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.areaGradientSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.areaGradientSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.facetSharedSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.height': [714.7, 700.7], + }, + chrome: { + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.facetSharedSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.facetIndependentSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.height': [714.7, 700.7], + }, + chrome: { + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.facetIndependentSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.rowFacetSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.rowFacetSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.formatSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.formatSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.fillPatternSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.fillPatternSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.dashEncodingSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [141.3, 155.3], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [286, 300], + 'x.start.y': [286, 300], + 'y.end.y': [286, 300], + 'y.tick.0.position': [268.34, 280.59], + 'y.tick.1.position': [224.18, 232.06], + 'y.tick.2.position': [180.02, 183.52], + 'y.titlePosition.y': [215.35, 222.35], + }, + marks: { + '0.height': [73.3, 80.56], + '0.y': [170.31, 172.85], + '1.height': [105.98, 116.48], + '1.y': [172.08, 174.79], + '2.height': [54.75, 60.18], + '2.y': [150, 150.52], + }, + endpointLabels: { + '0.labelY': [undefined, 199.27], + '1.labelY': [undefined, 221.52], + '2.labelY': [undefined, 177.02], + 'bounds.height': [undefined, 155.3], + }, + }, + style: {}, + }, + '../gallery/features-data-encoding.stories.tsx.dashEncodingSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-responsive.stories.tsx.flagshipSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [147.75, 161.75], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [286, 300], + 'x.start.y': [286, 300], + 'y.end.y': [286, 300], + 'y.tick.0.position': [267.53, 279.78], + 'y.tick.1.position': [221.36, 229.23], + 'y.tick.2.position': [175.19, 178.69], + 'y.titlePosition.y': [212.13, 219.13], + }, + marks: { + '0.height': [76.65, 83.91], + '0.y': [165.03, 167.57], + '1.height': [110.81, 121.31], + '1.y': [166.88, 169.59], + '2.height': [57.25, 62.68], + '2.y': [143.79, 144.32], + }, + }, + style: {}, + }, + '../gallery/features-responsive.stories.tsx.flagshipSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-responsive.stories.tsx.autoHeightSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-responsive.stories.tsx.autoHeightSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-responsive.stories.tsx.rotationSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-responsive.stories.tsx.rotationSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-responsive.stories.tsx.ratioSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [208.55, 220.95], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [306, 318.4], + 'x.start.y': [306, 318.4], + 'y.end.y': [306, 318.4], + 'y.gridlines': [3, 8], + 'y.tick.0.label': ['−5', '−6'], + 'y.tick.0.position': [279.93, 304.59], + 'y.tick.1.label': ['0', '−4'], + 'y.tick.1.position': [214.76, 276.97], + 'y.tick.2.label': ['5', '−2'], + 'y.tick.2.position': [149.59, 249.35], + 'y.tick.3.label': [undefined, '0'], + 'y.tick.3.position': [undefined, 221.73], + 'y.tick.4.label': [undefined, '2'], + 'y.tick.4.position': [undefined, 194.12], + 'y.tick.5.label': [undefined, '4'], + 'y.tick.5.position': [undefined, 166.5], + 'y.tick.6.label': [undefined, '6'], + 'y.tick.6.position': [undefined, 138.88], + 'y.tick.7.label': [undefined, '8'], + 'y.tick.7.position': [undefined, 111.26], + }, + marks: { + '0.height': [108.19, 114.62], + '0.y': [135.25, 137.5], + '1.height': [156.41, 165.71], + '1.y': [137.86, 140.26], + '2.height': [80.81, 85.62], + '2.y': [105.27, 105.74], + }, + }, + style: {}, + }, + '../gallery/features-responsive.stories.tsx.ratioSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-responsive.stories.tsx.facetSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-responsive.stories.tsx.facetSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/features-theming.stories.tsx.lineSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-theming.stories.tsx.lineSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-theming.stories.tsx.barSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-theming.stories.tsx.barSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-theming.stories.tsx.presetSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-theming.stories.tsx.presetSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/features-theming.stories.tsx.darkModeSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/features-theming.stories.tsx.darkModeSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.usStateSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [235, 304.58], + 'source.maxWidth': [235, 304.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.usStateSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.usCountySpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [235, 304.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.usCountySpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.worldEqualEarthSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'mapSize.height': [166.7, 142.7], + }, + area: { + 'rect.height': [166.7, 142.7], + }, + chrome: { + bottomAnchorY: [324, 338], + bottomHeight: [66, 52], + 'byline.maxWidth': [235, 304.58], + 'byline.y': [42, 28], + 'source.maxWidth': [235, 304.58], + }, + marks: { + '0.height': [2.85, 2.44], + '0.width': [337.62, 289.01], + '0.x': [16.19, 40.49], + '0.y': [103.46, 88.56], + '1.height': [13.81, 11.82], + '1.width': [10.23, 8.76], + '1.x': [213, 208.97], + '1.y': [84.19, 72.07], + '10.height': [42.81, 36.65], + '10.width': [15.01, 12.85], + '10.x': [119.38, 128.83], + '10.y': [105.42, 90.24], + '100.height': [1.91, 1.63], + '100.width': [3.07, 2.63], + '100.x': [265.33, 253.76], + '100.y': [47.32, 40.51], + '101.height': [4.84, 4.14], + '101.width': [7.95, 6.81], + '101.x': [256.98, 246.62], + '101.y': [44.78, 38.33], + '102.height': [15.96, 13.66], + '102.width': [13.24, 11.33], + '102.x': [239.46, 231.62], + '102.y': [36.96, 31.64], + '103.height': [10.67, 9.13], + '103.width': [11.62, 9.94], + '103.x': [238.15, 230.5], + '103.y': [35.43, 30.33], + '104.height': [4.74, 4.06], + '104.width': [7.08, 6.06], + '104.x': [242.43, 234.16], + '104.y': [32.67, 27.97], + '105.height': [4.42, 3.78], + '105.width': [8.08, 6.91], + '105.x': [243.88, 235.4], + '105.y': [30.12, 25.78], + '106.height': [8.39, 7.18], + '106.width': [13.28, 11.37], + '106.x': [228.97, 222.64], + '106.y': [30.71, 26.29], + '107.height': [17.17, 14.7], + '107.width': [19.9, 17.03], + '107.x': [222.5, 217.1], + '107.y': [34.06, 29.15], + '108.height': [5.69, 4.87], + '108.width': [5.23, 4.48], + '108.x': [216.24, 211.74], + '108.y': [36.85, 31.55], + '109.height': [2.79, 2.39], + '109.width': [3.03, 2.59], + '109.x': [221.66, 216.38], + '109.y': [32.36, 27.7], + '11.height': [23.75, 20.33], + '11.width': [18.17, 15.55], + '11.x': [196.61, 194.94], + '11.y': [76.21, 65.24], + '110.height': [11.13, 9.52], + '110.width': [8.14, 6.97], + '110.x': [193.03, 191.87], + '110.y': [6.81, 5.83], + '111.height': [4.62, 3.96], + '111.width': [7.15, 6.12], + '111.x': [202.91, 200.33], + '111.y': [17.2, 14.72], + '112.height': [7.16, 6.13], + '112.width': [14.27, 12.21], + '112.x': [202.63, 200.09], + '112.y': [20.82, 17.82], + '113.height': [5.69, 4.87], + '113.width': [8.05, 6.89], + '113.x': [195.78, 194.23], + '113.y': [18.42, 15.77], + '114.height': [2.69, 2.3], + '114.width': [5.94, 5.09], + '114.x': [192.65, 191.55], + '114.y': [24.1, 20.63], + '115.height': [2.97, 2.54], + '115.width': [5.12, 4.38], + '115.x': [198.09, 196.21], + '115.y': [24.52, 20.99], + '116.height': [3.1, 2.65], + '116.width': [3.05, 2.61], + '116.x': [206.29, 203.22], + '116.y': [24.68, 21.13], + '117.height': [4.77, 4.08], + '117.width': [7.83, 6.71], + '117.x': [201.43, 199.06], + '117.y': [24.93, 21.34], + '118.height': [2.3, 1.97], + '118.width': [4.3, 3.68], + '118.x': [200.75, 198.48], + '118.y': [17.01, 14.56], + '119.height': [2.14, 1.83], + '119.width': [5.38, 4.61], + '119.x': [200.67, 198.41], + '119.y': [15.57, 13.33], + '12.height': [17.59, 15.06], + '12.width': [9.24, 7.91], + '12.x': [224.14, 218.51], + '12.y': [67.55, 57.82], + '120.height': [1.88, 1.61], + '120.width': [3.46, 2.96], + '120.x': [201.94, 199.5], + '120.y': [14.13, 12.1], + '121.height': [7.59, 6.49], + '121.width': [7.08, 6.06], + '121.x': [189.65, 188.98], + '121.y': [18.29, 15.66], + '122.height': [3.26, 2.79], + '122.width': [5.12, 4.38], + '122.x': [203.49, 200.83], + '122.y': [29.11, 24.92], + '123.height': [7.79, 6.66], + '123.width': [5.78, 4.95], + '123.x': [202.11, 199.65], + '123.y': [31.72, 27.15], + '124.height': [7.09, 6.07], + '124.width': [16.71, 14.3], + '124.x': [206.86, 203.72], + '124.y': [31.38, 26.86], + '125.height': [3.38, 2.89], + '125.width': [1.6, 1.37], + '125.x': [201.12, 198.8], + '125.y': [30.78, 26.35], + '126.height': [4.3, 3.68], + '126.width': [4.69, 4.02], + '126.x': [196.16, 194.56], + '126.y': [26.71, 22.87], + '127.height': [2.14, 1.83], + '127.width': [3.55, 3.04], + '127.x': [189.88, 189.18], + '127.y': [25.33, 21.69], + '128.height': [0.69, 0.59], + '128.width': [0.44, 0.37], + '128.x': [189.49, 188.84], + '128.y': [23, 19.69], + '129.height': [1.94, 1.66], + '129.width': [2.86, 2.45], + '129.x': [186.96, 186.68], + '129.y': [21.66, 18.54], + '13.height': [13.1, 11.22], + '13.width': [7.57, 6.48], + '13.x': [217.39, 212.73], + '13.y': [75.89, 64.96], + '130.height': [2.64, 2.26], + '130.width': [2.86, 2.45], + '130.x': [187.58, 187.21], + '130.y': [19.69, 16.85], + '131.height': [6.08, 5.2], + '131.width': [2.77, 2.37], + '131.x': [176.87, 178.04], + '131.y': [31.22, 26.73], + '132.height': [8.69, 7.44], + '132.width': [10.35, 8.86], + '132.x': [177.2, 178.32], + '132.y': [29.63, 25.37], + '133.height': [3.32, 2.84], + '133.width': [3.12, 2.67], + '133.x': [177.25, 178.37], + '133.y': [18.16, 15.54], + '134.height': [2.85, 2.44], + '134.width': [1.9, 1.62], + '134.x': [337.15, 315.25], + '134.y': [108.58, 92.95], + '135.height': [5.41, 4.63], + '135.width': [4.82, 4.13], + '135.x': [334.06, 312.6], + '135.y': [91.46, 78.29], + '136.height': [13.48, 11.54], + '136.width': [18.02, 15.43], + '136.x': [320.31, 300.83], + '136.y': [125.89, 107.77], + '137.height': [39.52, 33.83], + '137.width': [38.62, 33.06], + '137.x': [285.74, 271.23], + '137.y': [96.66, 82.75], + '138.height': [4.94, 4.23], + '138.width': [2.05, 1.75], + '138.x': [260.79, 249.88], + '138.y': [70.35, 60.22], + '139.height': [40.01, 34.25], + '139.width': [47.06, 40.28], + '139.x': [247.57, 238.56], + '139.y': [19.74, 16.9], + '14.height': [17.38, 14.88], + '14.width': [15.12, 12.95], + '14.x': [205.72, 202.74], + '14.y': [55.01, 47.09], + '140.height': [4.09, 3.5], + '140.width': [1.28, 1.09], + '140.x': [295.19, 279.33], + '140.y': [50.96, 43.62], + '141.height': [11.47, 9.82], + '141.width': [10.11, 8.66], + '141.x': [190.53, 189.73], + '141.y': [26.07, 22.32], + '142.height': [2.68, 2.3], + '142.width': [3.5, 3], + '142.x': [191.02, 190.16], + '142.y': [15.78, 13.51], + '143.height': [8.19, 7.01], + '143.width': [7.06, 6.05], + '143.x': [179.23, 180.06], + '143.y': [14.98, 12.83], + '144.height': [2.3, 1.97], + '144.width': [7.24, 6.19], + '144.x': [168.47, 170.85], + '144.y': [8.62, 7.38], + '145.height': [3.99, 3.42], + '145.width': [4.82, 4.13], + '145.x': [222.79, 217.35], + '145.y': [31.68, 27.12], + '146.height': [2.71, 2.32], + '146.width': [6.12, 5.24], + '146.x': [218.09, 213.33], + '146.y': [29.84, 25.55], + '147.height': [16.43, 14.06], + '147.width': [9.06, 7.76], + '147.x': [296.42, 280.38], + '147.y': [59.36, 50.82], + '148.height': [7.91, 6.78], + '148.width': [18.3, 15.66], + '148.x': [280.36, 266.63], + '148.y': [74.06, 63.4], + '149.height': [1.85, 1.58], + '149.width': [1.12, 0.95], + '149.x': [293.99, 278.29], + '149.y': [75.96, 65.03], + '15.height': [20.16, 17.25], + '15.width': [9.68, 8.29], + '15.x': [197.75, 195.91], + '15.y': [53.27, 45.6], + '150.height': [1.47, 1.26], + '150.width': [2.28, 1.96], + '150.x': [196.14, 194.53], + '150.y': [26.35, 22.55], + '151.height': [7.81, 6.69], + '151.width': [8.52, 7.3], + '151.x': [198.52, 196.57], + '151.y': [6.12, 5.24], + '152.height': [1.85, 1.58], + '152.width': [4.45, 3.81], + '152.x': [198.47, 196.53], + '152.y': [23.56, 20.17], + '153.height': [2.58, 2.21], + '153.width': [5.3, 4.53], + '153.x': [194.63, 193.24], + '153.y': [22.01, 18.85], + '154.height': [7, 5.99], + '154.width': [6.53, 5.59], + '154.x': [219.16, 214.24], + '154.y': [60, 51.36], + '155.height': [16.35, 13.99], + '155.width': [8.35, 7.15], + '155.x': [298.86, 282.47], + '155.y': [27.71, 23.72], + '156.height': [10.09, 8.64], + '156.width': [8.14, 6.97], + '156.x': [127.23, 135.55], + '156.y': [107.63, 92.13], + '157.height': [8.09, 6.92], + '157.width': [9.7, 8.31], + '157.x': [225.03, 219.27], + '157.y': [58.74, 50.29], + '158.height': [19.35, 16.56], + '158.width': [20.12, 17.22], + '158.x': [216.22, 211.73], + '158.y': [42.72, 36.57], + '159.height': [11.86, 10.15], + '159.width': [212.22, 181.67], + '159.x': [81.85, 96.7], + '159.y': [154.84, 132.55], + '16.height': [2.36, 2.02], + '16.width': [2.82, 2.41], + '16.x': [115.57, 125.57], + '16.y': [57.6, 49.31], + '160.height': [0.77, 0.66], + '160.width': [1.52, 1.3], + '160.x': [213.52, 209.42], + '160.y': [38.64, 33.08], + '161.height': [0.7, 0.6], + '161.width': [1.54, 1.32], + '161.x': [213.12, 209.07], + '161.y': [39.21, 33.57], + '162.height': [17.19, 14.72], + '162.width': [14.73, 12.61], + '162.x': [169.27, 171.54], + '162.y': [38.54, 32.99], + '163.height': [11.61, 9.94], + '163.width': [11.94, 10.22], + '163.x': [207.06, 203.88], + '163.y': [43.4, 37.15], + '164.height': [16.44, 14.07], + '164.width': [14.74, 12.62], + '164.x': [193.46, 192.24], + '164.y': [41.58, 35.59], + '165.height': [14.74, 12.62], + '165.width': [14.1, 12.07], + '165.x': [216.35, 211.84], + '165.y': [63.82, 54.64], + '166.height': [2.26, 1.93], + '166.width': [1.51, 1.29], + '166.x': [224.43, 218.75], + '166.y': [66.69, 57.09], + '167.height': [4.43, 3.79], + '167.width': [6.12, 5.24], + '167.x': [225.34, 219.53], + '167.y': [68.26, 58.44], + '168.height': [7.33, 6.27], + '168.width': [5.21, 4.46], + '168.x': [213.27, 209.2], + '168.y': [77.5, 66.34], + '169.height': [2.29, 1.96], + '169.width': [1.72, 1.47], + '169.x': [212.72, 208.73], + '169.y': [84.43, 72.28], + '17.height': [2.86, 2.45], + '17.width': [3.38, 2.89], + '17.x': [117.97, 127.62], + '17.y': [57.64, 49.34], + '170.height': [2.77, 2.38], + '170.width': [3.25, 2.78], + '170.x': [197.92, 196.06], + '170.y': [28.05, 24.01], + '171.height': [1.62, 1.39], + '171.width': [2.11, 1.81], + '171.x': [202.17, 199.7], + '171.y': [31.18, 26.69], + '172.height': [4.2, 3.6], + '172.width': [3.74, 3.2], + '172.x': [200.32, 198.12], + '172.y': [27.06, 23.16], + '173.height': [1.79, 1.53], + '173.width': [1.53, 1.31], + '173.x': [200.38, 198.16], + '173.y': [29.88, 25.58], + '174.height': [1.55, 1.33], + '174.width': [1.41, 1.2], + '174.x': [201.72, 199.31], + '174.y': [30.15, 25.81], + '175.height': [1.14, 0.97], + '175.width': [1.07, 0.91], + '175.x': [126.23, 134.69], + '175.y': [68.99, 59.06], + '176.height': [11.19, 9.58], + '176.width': [10.95, 9.38], + '176.x': [207.71, 204.44], + '176.y': [67.26, 57.58], + '18.height': [31.79, 27.22], + '18.width': [249.21, 213.33], + '18.x': [61.86, 79.59], + '18.y': [0.67, 0.57], + '19.height': [4.06, 3.48], + '19.width': [1.83, 1.57], + '19.x': [113.33, 123.65], + '19.y': [48.84, 41.81], + '2.height': [8.16, 6.98], + '2.width': [7.96, 6.81], + '2.x': [169.21, 171.49], + '2.y': [48.1, 41.17], + '20.height': [1.18, 1.01], + '20.width': [2.56, 2.19], + '20.x': [137.49, 144.33], + '20.y': [143.91, 123.19], + '21.height': [14.61, 12.51], + '21.width': [16.74, 14.33], + '21.x': [188.52, 188.02], + '21.y': [0.86, 0.74], + '22.height': [13.77, 11.79], + '22.width': [36.79, 31.49], + '22.x': [141.08, 147.4], + '23.height': [1.16, 1], + '23.width': [1.73, 1.48], + '23.x': [239.29, 231.48], + '23.y': [141.42, 121.06], + '24.height': [1.43, 1.23], + '24.width': [2.32, 1.99], + '24.x': [303.75, 286.65], + '24.y': [93.6, 80.13], + '25.height': [15.28, 13.08], + '25.width': [15.06, 12.89], + '25.x': [199.7, 197.59], + '25.y': [111.04, 95.06], + '26.height': [2.39, 2.04], + '26.width': [2.15, 1.84], + '26.x': [209.15, 205.67], + '26.y': [119.04, 101.9], + '27.height': [22.29, 19.08], + '27.width': [23.64, 20.24], + '27.x': [81.12, 96.08], + '27.y': [42.07, 36.01], + '28.height': [5.69, 4.87], + '28.width': [4.65, 3.98], + '28.x': [133.5, 140.92], + '28.y': [120.79, 103.4], + '29.height': [48.88, 41.84], + '29.width': [37.36, 31.98], + '29.x': [114.58, 124.72], + '29.y': [76.22, 65.25], + '3.height': [31.79, 27.21], + '3.width': [66.09, 56.58], + '3.x': [83.08, 97.75], + '3.y': [0.1, 0.09], + '30.height': [16.5, 14.12], + '30.width': [12.23, 10.47], + '30.x': [119.13, 128.61], + '30.y': [95.51, 81.76], + '31.height': [23.34, 19.98], + '31.width': [13.07, 11.19], + '31.x': [107.32, 118.51], + '31.y': [83.04, 71.09], + '32.height': [21.48, 18.39], + '32.width': [11.57, 9.9], + '32.x': [109.52, 120.39], + '32.y': [67.02, 57.37], + '33.height': [3.06, 2.62], + '33.width': [5.42, 4.64], + '33.x': [106.1, 117.46], + '33.y': [70.63, 60.46], + '34.height': [3.82, 3.27], + '34.width': [3.06, 2.62], + '34.x': [103.57, 115.3], + '34.y': [68.58, 58.7], + '35.height': [5.45, 4.67], + '35.width': [4.6, 3.94], + '35.x': [102.23, 114.14], + '35.y': [63.75, 54.57], + '36.height': [3.82, 3.27], + '36.width': [5.94, 5.08], + '36.x': [100.89, 113], + '36.y': [62.5, 53.5], + '37.height': [1.62, 1.39], + '37.width': [2.24, 1.92], + '37.x': [100.07, 112.3], + '37.y': [64.5, 55.21], + '38.height': [5.15, 4.41], + '38.width': [3.99, 3.41], + '38.x': [98.21, 110.7], + '38.y': [60.22, 51.55], + '39.height': [3.28, 2.81], + '39.width': [1.57, 1.34], + '39.x': [101.28, 113.34], + '39.y': [59.37, 50.82], + '4.height': [53.48, 45.78], + '4.width': [92.66, 79.32], + '4.x': [37.65, 58.86], + '4.y': [5.37, 4.59], + '40.height': [14.66, 12.55], + '40.width': [12.81, 10.97], + '40.x': [115.37, 125.39], + '40.y': [67.37, 57.67], + '41.height': [9.12, 7.81], + '41.width': [4.52, 3.87], + '41.x': [126.46, 134.89], + '41.y': [72.22, 61.82], + '42.height': [5.41, 4.63], + '42.width': [3.96, 3.39], + '42.x': [129.59, 137.57], + '42.y': [75.22, 64.39], + '43.height': [58.34, 49.94], + '43.width': [60.08, 51.43], + '43.x': [132.91, 140.41], + '43.y': [21.98, 18.82], + '44.height': [8.16, 6.98], + '44.width': [5.45, 4.67], + '44.x': [107.65, 118.78], + '44.y': [81.19, 69.5], + '45.height': [0.72, 0.62], + '45.width': [1.53, 1.31], + '45.x': [122.29, 131.32], + '45.y': [59.34, 50.8], + '46.height': [1.03, 0.88], + '46.width': [1.93, 1.65], + '46.x': [111.93, 122.45], + '46.y': [59.34, 50.8], + '47.height': [4.13, 3.54], + '47.width': [9.61, 8.23], + '47.x': [106.6, 117.89], + '47.y': [53.54, 45.84], + '48.height': [8.46, 7.24], + '48.width': [7.16, 6.13], + '48.x': [208.59, 205.2], + '48.y': [102.81, 88.01], + '49.height': [11.32, 9.69], + '49.width': [8.96, 7.67], + '49.x': [203.17, 200.56], + '49.y': [105.52, 90.33], + '5.height': [15.08, 12.91], + '5.width': [32.26, 27.61], + '5.x': [222.05, 216.71], + '5.y': [17.92, 15.34], + '50.height': [14.9, 12.75], + '50.width': [12.46, 10.67], + '50.x': [195.97, 194.39], + '50.y': [104.62, 89.56], + '51.height': [5.4, 4.62], + '51.width': [5.75, 4.92], + '51.x': [168.42, 170.81], + '51.y': [61.76, 52.87], + '52.height': [18.65, 15.97], + '52.width': [15.45, 13.22], + '52.x': [173.55, 175.2], + '52.y': [51.35, 43.96], + '53.height': [15.85, 13.57], + '53.width': [11.29, 9.67], + '53.x': [169.21, 171.49], + '53.y': [48.41, 41.44], + '54.height': [7.79, 6.67], + '54.width': [2.87, 2.45], + '54.x': [185.73, 185.63], + '54.y': [67.28, 57.59], + '55.height': [14.81, 12.68], + '55.width': [14.46, 12.38], + '55.x': [185.28, 185.24], + '55.y': [53.2, 45.54], + '56.height': [12.3, 10.53], + '56.width': [11.22, 9.61], + '56.x': [187.56, 187.2], + '56.y': [65.21, 55.82], + '57.height': [14.26, 12.21], + '57.width': [7.2, 6.16], + '57.x': [193.1, 191.93], + '57.y': [66.49, 56.91], + '58.height': [6.51, 5.58], + '58.width': [1.83, 1.56], + '58.y': [68.83, 58.92], + '59.height': [8.18, 7], + '59.width': [4.1, 3.51], + '59.x': [181.91, 182.35], + '59.y': [68.73, 58.83], + '6.height': [9.28, 7.94], + '6.width': [15.73, 13.47], + '6.x': [230.81, 224.22], + '6.y': [27.68, 23.69], + '60.height': [7.93, 6.79], + '60.width': [5.76, 4.93], + '60.x': [176.8, 177.98], + '60.y': [69.46, 59.46], + '61.height': [6.74, 5.77], + '61.width': [6.89, 5.89], + '61.x': [170.67, 172.73], + '61.y': [66.83, 57.21], + '62.height': [2.02, 1.73], + '62.width': [2.82, 2.41], + '62.x': [169.24, 171.51], + '62.y': [66.78, 57.17], + '63.height': [5.37, 4.6], + '63.width': [3.7, 3.17], + '63.x': [174.1, 175.67], + '63.y': [71.99, 61.63], + '64.height': [4.18, 3.57], + '64.width': [2.86, 2.45], + '64.x': [172.41, 174.23], + '64.y': [70.07, 59.98], + '65.height': [7, 5.99], + '65.width': [7.24, 6.2], + '65.x': [179.82, 180.56], + '65.y': [63.63, 54.47], + '66.height': [11.38, 9.74], + '66.width': [12.32, 10.55], + '66.x': [198.79, 196.8], + '66.y': [68.67, 58.78], + '67.height': [11.28, 9.66], + '67.width': [7.03, 6.02], + '67.x': [195.59, 194.07], + '67.y': [78.17, 66.92], + '68.height': [8.12, 6.95], + '68.width': [5.38, 4.61], + '68.x': [193.41, 192.2], + '68.y': [79.98, 68.46], + '69.height': [1.64, 1.4], + '69.width': [1.89, 1.62], + '69.x': [193.89, 192.61], + '69.y': [80.03, 68.51], + '7.height': [10.46, 8.95], + '7.width': [14.67, 12.56], + '7.x': [318.97, 299.68], + '7.y': [86.19, 73.78], + '70.height': [12.34, 10.56], + '70.width': [11.22, 9.6], + '70.x': [205.53, 202.57], + '70.y': [93.56, 80.09], + '71.height': [9.61, 8.23], + '71.width': [2.76, 2.37], + '71.x': [215.81, 211.38], + '71.y': [94.83, 81.18], + '72.height': [20.52, 17.57], + '72.width': [9.97, 8.54], + '72.x': [213.39, 209.3], + '72.y': [96.22, 82.36], + '73.height': [1.97, 1.69], + '73.width': [1.26, 1.08], + '73.x': [212.82, 208.81], + '73.y': [115.42, 98.81], + '74.height': [17.18, 14.7], + '74.width': [11.86, 10.16], + '74.x': [195.9, 194.33], + '74.y': [88.68, 75.91], + '75.height': [2.77, 2.37], + '75.width': [1.64, 1.41], + '75.x': [212.72, 208.73], + '75.y': [85.99, 73.61], + '76.height': [4.47, 3.82], + '76.width': [1.14, 0.98], + '76.x': [215.46, 211.07], + '76.y': [41.41, 35.45], + '77.height': [1.81, 1.55], + '77.width': [1.12, 0.96], + '77.x': [215.94, 211.49], + '77.y': [39.82, 34.09], + '78.height': [16.94, 14.5], + '78.width': [7.56, 6.47], + '78.x': [224.87, 219.13], + '78.y': [98.41, 84.24], + '79.height': [1.39, 1.19], + '79.width': [0.52, 0.44], + '79.x': [215.99, 211.53], + '79.y': [42.29, 36.2], + '8.height': [20.35, 17.42], + '8.width': [43.81, 37.51], + '8.x': [275.88, 262.79], + '8.y': [75.92, 64.99], + '80.height': [0.95, 0.81], + '80.width': [2.84, 2.43], + '80.x': [169.11, 171.39], + '80.y': [65.2, 55.81], + '81.height': [8.2, 7.02], + '81.width': [3.52, 3.02], + '81.x': [191.59, 190.65], + '81.y': [36.72, 31.43], + '82.height': [21.69, 18.57], + '82.width': [18.87, 16.15], + '82.x': [177.15, 178.28], + '82.y': [36.98, 31.66], + '83.height': [4.95, 4.24], + '83.width': [3.39, 2.91], + '83.x': [216.29, 211.78], + '83.y': [41.3, 35.35], + '84.height': [4.36, 3.73], + '84.width': [4.28, 3.66], + '84.x': [232.2, 225.41], + '84.y': [50.04, 42.83], + '85.height': [1.9, 1.63], + '85.width': [0.83, 0.71], + '85.x': [231.23, 224.57], + '85.y': [49.96, 42.77], + '86.height': [1.84, 1.57], + '86.width': [1.76, 1.51], + '86.x': [226.8, 220.78], + '86.y': [45.21, 38.71], + '87.height': [9.68, 8.29], + '87.width': [9.31, 7.97], + '87.x': [219.12, 214.21], + '87.y': [36.68, 31.4], + '88.height': [12.07, 10.33], + '88.width': [6.7, 5.74], + '88.x': [233.4, 226.43], + '88.y': [49.62, 42.48], + '89.height': [2.49, 2.13], + '89.width': [0.73, 0.62], + '89.x': [341.53, 319], + '89.y': [101.7, 87.05], + '9.height': [37.17, 31.82], + '9.width': [14.17, 12.13], + '9.x': [122.23, 131.27], + '9.y': [110.72, 94.78], + '90.height': [5.19, 4.44], + '90.width': [5.05, 4.33], + '90.x': [281.54, 267.64], + '90.y': [64.32, 55.06], + '91.height': [18.67, 15.99], + '91.width': [8.51, 7.29], + '91.x': [275.77, 262.7], + '91.y': [56.97, 48.77], + '92.height': [10.75, 9.2], + '92.width': [8.33, 7.13], + '92.x': [277.8, 264.44], + '92.y': [54.44, 46.6], + '93.height': [22.94, 19.64], + '93.width': [8.92, 7.64], + '93.x': [270.27, 258], + '93.y': [47.28, 40.47], + '94.height': [18.58, 15.9], + '94.width': [9.25, 7.92], + '94.x': [279.09, 265.54], + '94.y': [53.34, 45.66], + '95.height': [5.9, 5.05], + '95.width': [4.38, 3.75], + '95.x': [290.31, 275.15], + '95.y': [30.46, 26.07], + '96.height': [4.83, 4.13], + '96.width': [4.19, 3.58], + '96.x': [293.34, 277.74], + '96.y': [35.29, 30.21], + '97.height': [10.87, 9.31], + '97.width': [27.23, 23.31], + '97.x': [254.57, 244.56], + '97.y': [21.1, 18.06], + '98.height': [33.89, 29.01], + '98.width': [25.41, 21.75], + '98.x': [247.52, 238.52], + '98.y': [38.84, 33.25], + '99.height': [7.1, 6.08], + '99.width': [5.37, 4.6], + '99.x': [265.27, 253.71], + '99.y': [49.56, 42.43], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.worldEqualEarthSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.worldMercatorSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'mapSize.height': [166.7, 142.7], + }, + area: { + 'rect.height': [166.7, 142.7], + }, + chrome: { + bottomAnchorY: [324, 338], + bottomHeight: [66, 52], + 'byline.maxWidth': [235, 304.58], + 'byline.y': [42, 28], + 'source.maxWidth': [235, 304.58], + }, + marks: { + '0.height': [1.7, 1.45], + '0.width': [257.72, 220.62], + '0.x': [56.14, 74.69], + '0.y': [130.21, 111.46], + '1.height': [7.77, 6.65], + '1.width': [7.86, 6.73], + '1.x': [206, 202.98], + '1.y': [119.27, 102.1], + '10.height': [35.33, 30.24], + '10.width': [6.22, 5.32], + '10.x': [130.85, 138.64], + '10.y': [131.37, 112.46], + '100.height': [1.27, 1.09], + '100.width': [2.36, 2.02], + '100.x': [248.58, 239.43], + '100.y': [97.45, 83.42], + '101.height': [3.28, 2.81], + '101.width': [5.79, 4.96], + '101.x': [242.33, 234.08], + '101.y': [95.71, 81.93], + '102.height': [11.2, 9.59], + '102.width': [12.14, 10.4], + '102.x': [228.58, 222.31], + '102.y': [89.92, 76.97], + '103.height': [7.92, 6.78], + '103.width': [10.47, 8.97], + '103.x': [228.33, 222.09], + '103.y': [88.69, 75.92], + '104.height': [3.88, 3.32], + '104.width': [5.4, 4.62], + '104.x': [233.28, 226.33], + '104.y': [86.39, 73.95], + '105.height': [3.83, 3.28], + '105.width': [7.73, 6.62], + '105.x': [234.73, 227.57], + '105.y': [84.13, 72.02], + '106.height': [6.9, 5.91], + '106.width': [10.05, 8.61], + '106.x': [222.59, 217.17], + '106.y': [84.67, 72.48], + '107.height': [12.47, 10.67], + '107.width': [13.75, 11.77], + '107.x': [216.58, 212.03], + '107.y': [87.56, 74.96], + '108.height': [4.29, 3.67], + '108.width': [4.76, 4.07], + '108.x': [210.56, 206.88], + '108.y': [89.83, 76.9], + '109.height': [2.34, 2.01], + '109.width': [2.09, 1.79], + '109.x': [216.2, 211.71], + '109.y': [86.12, 73.72], + '11.height': [13.34, 11.42], + '11.width': [13.6, 11.64], + '11.x': [193.72, 192.46], + '11.y': [114.82, 98.29], + '110.height': [21.55, 18.45], + '110.width': [9.22, 7.89], + '110.x': [192.9, 191.76], + '110.y': [49.24, 42.15], + '111.height': [5.88, 5.03], + '111.width': [6.8, 5.82], + '111.x': [201.61, 199.22], + '111.y': [69.76, 59.72], + '112.height': [7.67, 6.57], + '112.width': [12.88, 11.03], + '112.x': [200.81, 198.53], + '112.y': [74.47, 63.74], + '113.height': [6.78, 5.8], + '113.width': [7.13, 6.1], + '113.x': [195.08, 193.63], + '113.y': [71.43, 61.14], + '114.height': [2.78, 2.38], + '114.width': [5.37, 4.6], + '114.x': [191.79, 190.81], + '114.y': [78.19, 66.93], + '115.height': [3.02, 2.59], + '115.width': [4.66, 3.99], + '115.x': [196.6, 194.93], + '115.y': [78.64, 67.32], + '116.height': [3.13, 2.68], + '116.width': [2.44, 2.09], + '116.x': [204.06, 201.31], + '116.y': [78.81, 67.47], + '117.height': [4.67, 4], + '117.width': [6.73, 5.76], + '117.x': [199.48, 197.39], + '117.y': [79.08, 67.69], + '118.height': [3.09, 2.65], + '118.width': [3.96, 3.39], + '118.x': [200.07, 197.9], + '118.y': [69.5, 59.49], + '119.height': [3.08, 2.64], + '119.width': [5.1, 4.36], + '119.x': [200.07, 197.9], + '119.y': [67.39, 57.69], + '12.height': [9.88, 8.46], + '12.width': [7.27, 6.22], + '12.x': [214.34, 210.11], + '12.y': [109.91, 94.09], + '120.height': [2.93, 2.51], + '120.width': [3.43, 2.94], + '120.x': [201.71, 199.3], + '120.y': [65.12, 55.75], + '121.height': [8.79, 7.53], + '121.width': [6.46, 5.53], + '121.x': [189.29, 188.67], + '121.y': [71.26, 61], + '122.height': [2.93, 2.5], + '122.width': [4.42, 3.79], + '122.x': [201.02, 198.71], + '122.y': [83.2, 71.22], + '123.height': [6.32, 5.41], + '123.width': [4.62, 3.95], + '123.x': [199.43, 197.35], + '123.y': [85.56, 73.24], + '124.height': [5.83, 4.99], + '124.width': [13.42, 11.49], + '124.x': [203.64, 200.96], + '124.y': [85.26, 72.98], + '125.height': [2.91, 2.49], + '125.width': [1.23, 1.05], + '125.x': [198.82, 196.83], + '125.y': [84.73, 72.53], + '126.height': [4.04, 3.46], + '126.width': [4.11, 3.51], + '126.x': [194.78, 193.37], + '126.y': [80.89, 69.25], + '127.height': [2.15, 1.84], + '127.width': [3.16, 2.71], + '127.x': [189.31, 188.69], + '127.y': [79.49, 68.05], + '128.height': [0.76, 0.65], + '128.width': [0.41, 0.35], + '128.x': [189.06, 188.48], + '128.y': [76.99, 65.9], + '129.height': [2.19, 1.87], + '129.width': [2.61, 2.23], + '129.x': [186.8, 186.54], + '129.y': [75.46, 64.6], + '13.height': [7.3, 6.25], + '13.width': [5.7, 4.88], + '13.x': [209.26, 205.77], + '13.y': [114.64, 98.13], + '130.height': [3.16, 2.7], + '130.width': [2.7, 2.31], + '130.x': [187.37, 187.03], + '130.y': [73.07, 62.55], + '131.height': [5.06, 4.33], + '131.width': [2.25, 1.92], + '131.x': [178.18, 179.16], + '131.y': [85.13, 72.87], + '132.height': [7.29, 6.24], + '132.width': [8.9, 7.62], + '132.x': [178.27, 179.24], + '132.y': [83.69, 71.64], + '133.height': [4.16, 3.56], + '133.width': [2.82, 2.42], + '133.x': [177.86, 178.89], + '133.y': [71.08, 60.84], + '134.height': [1.76, 1.51], + '134.width': [2.21, 1.89], + '134.x': [302.43, 285.52], + '134.y': [133.28, 114.1], + '135.height': [3.06, 2.62], + '135.width': [4.23, 3.62], + '135.x': [297.03, 280.9], + '135.y': [123.32, 105.57], + '136.height': [11.54, 9.88], + '136.width': [8.6, 7.36], + '136.x': [304.2, 287.04], + '136.y': [144.89, 124.03], + '137.height': [27.1, 23.2], + '137.width': [28.8, 24.65], + '137.x': [266.14, 254.46], + '137.y': [126.27, 108.09], + '138.height': [2.79, 2.39], + '138.width': [1.5, 1.28], + '138.x': [242.05, 233.84], + '138.y': [111.52, 95.46], + '139.height': [32.2, 27.57], + '139.width': [43.92, 37.6], + '139.x': [237.74, 230.15], + '139.y': [73.13, 62.6], + '14.height': [10.24, 8.77], + '14.width': [11.79, 10.1], + '14.x': [200.7, 198.44], + '14.y': [102.43, 87.69], + '140.height': [2.6, 2.23], + '140.width': [1.32, 1.13], + '140.x': [270.98, 258.6], + '140.y': [99.86, 85.48], + '141.height': [10.13, 8.67], + '141.width': [8.4, 7.19], + '141.x': [189.83, 189.14], + '141.y': [80.25, 68.7], + '142.height': [3.78, 3.23], + '142.width': [3.29, 2.82], + '142.x': [190.79, 189.96], + '142.y': [67.71, 57.96], + '143.height': [10.69, 9.15], + '143.width': [6.63, 5.67], + '143.x': [179.58, 180.36], + '143.y': [66.48, 56.91], + '144.height': [5.14, 4.4], + '144.width': [7.67, 6.57], + '144.x': [167.58, 170.09], + '144.y': [54.13, 46.34], + '145.height': [3.36, 2.88], + '145.width': [4.01, 3.43], + '145.x': [217.07, 212.45], + '145.y': [85.53, 73.22], + '146.height': [2.41, 2.06], + '146.width': [4.78, 4.09], + '146.x': [213.6, 209.49], + '146.y': [83.88, 71.8], + '147.height': [9.48, 8.12], + '147.width': [6.7, 5.74], + '147.x': [268.88, 256.81], + '147.y': [105.1, 89.97], + '148.height': [4.42, 3.78], + '148.width': [13.67, 11.7], + '148.x': [256.65, 246.34], + '148.y': [113.61, 97.26], + '149.height': [1.03, 0.89], + '149.width': [0.89, 0.76], + '149.x': [266.76, 254.99], + '149.y': [114.68, 98.17], + '15.height': [11.92, 10.2], + '15.width': [7.41, 6.34], + '15.x': [194.69, 193.3], + '15.y': [101.34, 86.75], + '150.height': [1.45, 1.24], + '150.width': [2.05, 1.76], + '150.x': [194.81, 193.39], + '150.y': [80.53, 68.93], + '151.height': [17.73, 15.18], + '151.width': [7.78, 6.66], + '151.x': [199.78, 197.65], + '151.y': [47.06, 40.28], + '152.height': [1.97, 1.68], + '152.width': [4.07, 3.48], + '152.x': [197.08, 195.34], + '152.y': [77.61, 66.43], + '153.height': [2.85, 2.44], + '153.width': [4.73, 4.05], + '153.x': [193.76, 192.5], + '153.y': [75.87, 64.95], + '154.height': [4.11, 3.52], + '154.width': [4.84, 4.14], + '154.x': [211, 207.26], + '154.y': [105.49, 90.3], + '155.height': [13.32, 11.41], + '155.width': [11.55, 9.89], + '155.x': [277.64, 264.3], + '155.y': [81.87, 70.09], + '156.height': [6.41, 5.49], + '156.width': [6.01, 5.14], + '156.x': [140.12, 146.58], + '156.y': [132.7, 113.6], + '157.height': [4.77, 4.09], + '157.width': [7.52, 6.44], + '157.x': [215.5, 211.11], + '157.y': [104.73, 89.65], + '158.height': [12.47, 10.68], + '158.width': [15.06, 12.89], + '158.x': [209.79, 206.22], + '158.y': [94.25, 80.68], + '159.height': [69.91, 59.84], + '159.width': [257.72, 220.62], + '159.x': [56.14, 74.69], + '159.y': [177.54, 151.98], + '16.height': [1.43, 1.22], + '16.width': [2.03, 1.74], + '16.x': [131.7, 139.37], + '16.y': [104.03, 89.06], + '160.height': [0.59, 0.5], + '160.width': [1.32, 1.13], + '160.x': [208.43, 205.06], + '160.y': [91.22, 78.09], + '161.height': [0.53, 0.45], + '161.width': [1.25, 1.07], + '161.x': [208.09, 204.77], + '161.y': [91.66, 78.46], + '162.height': [11.74, 10.05], + '162.width': [11.38, 9.74], + '162.x': [172.82, 174.57], + '162.y': [91.14, 78.02], + '163.height': [7.7, 6.59], + '163.width': [8.71, 7.45], + '163.x': [202.68, 200.14], + '163.y': [94.73, 81.1], + '164.height': [10.87, 9.3], + '164.width': [11.34, 9.71], + '164.x': [191.67, 190.71], + '164.y': [93.42, 79.97], + '165.height': [8.38, 7.18], + '165.width': [10.62, 9.09], + '165.x': [208.59, 205.19], + '165.y': [107.75, 92.24], + '166.height': [1.3, 1.11], + '166.width': [1.19, 1.01], + '166.x': [214.82, 210.53], + '166.y': [109.42, 93.67], + '167.height': [2.52, 2.16], + '167.width': [4.57, 3.92], + '167.x': [215.47, 211.08], + '167.y': [110.33, 94.44], + '168.height': [4.08, 3.49], + '168.width': [3.91, 3.34], + '168.x': [206.18, 203.13], + '168.y': [115.54, 98.91], + '169.height': [1.28, 1.09], + '169.width': [1.28, 1.1], + '169.x': [205.78, 202.79], + '169.y': [119.4, 102.21], + '17.height': [1.73, 1.48], + '17.width': [2.6, 2.22], + '17.x': [133.5, 140.91], + '17.y': [104.06, 89.08], + '170.height': [2.57, 2.2], + '170.width': [2.76, 2.36], + '170.x': [196.27, 194.65], + '170.y': [82.2, 70.36], + '171.height': [1.41, 1.21], + '171.width': [1.78, 1.52], + '171.x': [199.65, 197.54], + '171.y': [85.09, 72.84], + '172.height': [3.92, 3.36], + '172.width': [2.97, 2.55], + '172.x': [198.48, 196.54], + '172.y': [81.24, 69.54], + '173.height': [1.6, 1.37], + '173.width': [1.35, 1.16], + '173.x': [198.21, 196.31], + '173.y': [83.91, 71.83], + '174.height': [1.39, 1.19], + '174.width': [1.22, 1.04], + '174.x': [199.37, 197.3], + '174.y': [84.16, 72.04], + '175.height': [0.65, 0.55], + '175.width': [0.76, 0.65], + '175.x': [140.65, 147.03], + '175.y': [110.74, 94.8], + '176.height': [6.32, 5.41], + '176.width': [8.17, 6.99], + '176.x': [202.1, 199.64], + '176.y': [109.75, 93.95], + '18.height': [73.05, 62.54], + '18.width': [257.72, 220.62], + '18.x': [56.14, 74.69], + '18.y': [13.16, 11.26], + '19.height': [2.64, 2.26], + '19.width': [1.42, 1.21], + '19.x': [128.46, 136.6], + '19.y': [98.47, 84.29], + '2.height': [5.23, 4.48], + '2.width': [6.01, 5.15], + '2.x': [172.79, 174.54], + '2.y': [97.97, 83.87], + '20.height': [1.39, 1.19], + '20.width': [2.47, 2.11], + '20.x': [141.19, 147.5], + '20.y': [161.28, 138.06], + '21.height': [51.39, 43.99], + '21.width': [18.83, 16.12], + '21.x': [188.57, 188.06], + '21.y': [15.85, 13.57], + '22.height': [64.51, 55.23], + '22.width': [43.73, 37.44], + '22.x': [132.53, 140.08], + '23.height': [1.26, 1.08], + '23.width': [1.32, 1.13], + '23.x': [234.2, 227.11], + '23.y': [158.53, 135.71], + '24.height': [0.81, 0.69], + '24.width': [1.69, 1.45], + '24.x': [274.46, 261.58], + '24.y': [124.53, 106.6], + '25.height': [10.4, 8.9], + '25.width': [11.8, 10.1], + '25.x': [196.7, 195.02], + '25.y': [134.81, 115.4], + '26.height': [1.65, 1.41], + '26.width': [1.66, 1.43], + '26.x': [204.33, 201.55], + '26.y': [140.01, 119.85], + '27.height': [14.29, 12.23], + '27.width': [21.7, 18.58], + '27.x': [101.15, 113.22], + '27.y': [93.77, 80.27], + '28.height': [4.11, 3.52], + '28.width': [3.73, 3.2], + '28.x': [143.17, 149.19], + '28.y': [141.21, 120.88], + '29.height': [29.47, 25.23], + '29.width': [28.1, 24.06], + '29.x': [132.03, 139.66], + '29.y': [114.83, 98.3], + '3.height': [83.13, 71.16], + '3.width': [63.25, 54.14], + '3.x': [84.06, 98.59], + '3.y': [2.58, 2.21], + '30.height': [9.8, 8.39], + '30.width': [8.66, 7.41], + '30.x': [135.18, 142.35], + '30.y': [125.61, 107.53], + '31.height': [13.33, 11.41], + '31.width': [9.12, 7.81], + '31.x': [126.72, 135.11], + '31.y': [118.63, 101.55], + '32.height': [12.05, 10.32], + '32.width': [8.67, 7.42], + '32.x': [128.45, 136.59], + '32.y': [109.61, 93.83], + '33.height': [1.73, 1.48], + '33.width': [4.1, 3.51], + '33.x': [125.61, 134.16], + '33.y': [111.67, 95.6], + '34.height': [2.17, 1.86], + '34.width': [2.43, 2.08], + '34.x': [123.48, 132.33], + '34.y': [110.5, 94.6], + '35.height': [3.15, 2.7], + '35.width': [3.24, 2.77], + '35.x': [122.24, 131.27], + '35.y': [107.71, 92.2], + '36.height': [2.23, 1.91], + '36.width': [4.44, 3.8], + '36.x': [121.03, 130.24], + '36.y': [106.98, 91.58], + '37.height': [0.94, 0.81], + '37.width': [1.7, 1.45], + '37.x': [120.5, 129.79], + '37.y': [108.15, 92.58], + '38.height': [3.04, 2.6], + '38.width': [2.87, 2.45], + '38.x': [118.98, 128.48], + '38.y': [105.62, 90.41], + '39.height': [1.96, 1.68], + '39.width': [0.8, 0.69], + '39.x': [121.12, 130.32], + '39.y': [105.11, 89.97], + '4.height': [60.32, 51.64], + '4.width': [75.04, 64.24], + '4.x': [62.02, 79.72], + '4.y': [44.47, 38.06], + '40.height': [8.25, 7.07], + '40.width': [9.7, 8.3], + '40.x': [132.52, 140.08], + '40.y': [109.81, 94], + '41.height': [5.1, 4.37], + '41.width': [3.49, 2.98], + '41.x': [141.04, 147.37], + '41.y': [112.58, 96.37], + '42.height': [3.02, 2.59], + '42.width': [2.93, 2.5], + '42.x': [143.45, 149.43], + '42.y': [114.26, 97.81], + '43.height': [41.28, 35.34], + '43.width': [45.88, 39.27], + '43.x': [145.97, 151.59], + '43.y': [75.84, 64.92], + '44.height': [4.54, 3.89], + '44.width': [4.1, 3.51], + '44.x': [127.04, 135.38], + '44.y': [117.6, 100.67], + '45.height': [0.43, 0.37], + '45.width': [1.18, 1.01], + '45.x': [136.86, 143.79], + '45.y': [105.09, 89.96], + '46.height': [0.62, 0.53], + '46.width': [1.53, 1.31], + '46.x': [128.92, 136.99], + '46.y': [105.09, 89.96], + '47.height': [2.57, 2.2], + '47.width': [7.73, 6.62], + '47.x': [124.17, 132.93], + '47.y': [101.51, 86.9], + '48.height': [5.12, 4.38], + '48.width': [5.43, 4.65], + '48.x': [203.09, 200.48], + '48.y': [129.83, 111.14], + '49.height': [7.1, 6.08], + '49.width': [6.83, 5.84], + '49.x': [199.24, 197.19], + '49.y': [131.44, 112.51], + '5.height': [15.91, 13.62], + '5.width': [29.27, 25.06], + '5.x': [218.27, 213.48], + '5.y': [70.76, 60.57], + '50.height': [9.44, 8.08], + '50.width': [9.56, 8.18], + '50.x': [193.4, 192.19], + '50.y': [130.9, 112.05], + '51.height': [3.15, 2.7], + '51.width': [4.41, 3.77], + '51.x': [172.38, 174.2], + '51.y': [106.53, 91.2], + '52.height': [11.21, 9.59], + '52.width': [11.77, 10.08], + '52.x': [176.29, 177.54], + '52.y': [100.11, 85.7], + '53.height': [9.83, 8.41], + '53.width': [8.69, 7.44], + '53.x': [172.79, 174.54], + '53.y': [98.18, 84.05], + '54.height': [4.42, 3.78], + '54.width': [2.16, 1.85], + '54.x': [185.55, 185.47], + '54.y': [109.76, 93.96], + '55.height': [8.89, 7.61], + '55.width': [11.17, 9.56], + '55.x': [185.21, 185.18], + '55.y': [101.29, 86.71], + '56.height': [6.99, 5.98], + '56.width': [8.51, 7.28], + '56.x': [186.93, 186.65], + '56.y': [108.56, 92.93], + '57.height': [8.05, 6.89], + '57.width': [5.39, 4.61], + '57.x': [191.08, 190.2], + '57.y': [109.3, 93.57], + '58.height': [3.69, 3.15], + '58.width': [1.37, 1.17], + '58.y': [110.65, 94.72], + '59.height': [4.62, 3.95], + '59.width': [3.08, 2.64], + '59.x': [182.68, 183.01], + '59.y': [110.59, 94.67], + '6.height': [8.07, 6.91], + '6.width': [12.26, 10.49], + '6.x': [225.04, 219.27], + '6.y': [81.84, 70.06], + '60.height': [4.47, 3.83], + '60.width': [4.32, 3.7], + '60.x': [178.84, 179.73], + '60.y': [111.01, 95.03], + '61.height': [3.84, 3.28], + '61.width': [5.22, 4.47], + '61.x': [174.17, 175.73], + '61.y': [109.5, 93.74], + '62.height': [1.16, 0.99], + '62.width': [2.13, 1.82], + '62.x': [173.06, 174.78], + '62.y': [109.47, 93.71], + '63.height': [3.02, 2.58], + '63.width': [2.79, 2.39], + '63.x': [176.81, 177.99], + '63.y': [112.45, 96.26], + '64.height': [2.36, 2.02], + '64.width': [2.16, 1.85], + '64.x': [175.52, 176.88], + '64.y': [111.36, 95.32], + '65.height': [4.04, 3.46], + '65.width': [5.47, 4.69], + '65.x': [181.08, 181.65], + '65.y': [107.64, 92.14], + '66.height': [6.4, 5.48], + '66.width': [9.24, 7.91], + '66.x': [195.35, 193.86], + '66.y': [110.56, 94.64], + '67.height': [6.28, 5.38], + '67.width': [5.27, 4.51], + '67.x': [192.94, 191.8], + '67.y': [115.92, 99.23], + '68.height': [4.52, 3.87], + '68.width': [4.03, 3.45], + '68.x': [191.3, 190.39], + '68.y': [116.92, 100.09], + '69.height': [0.91, 0.78], + '69.width': [1.42, 1.21], + '69.x': [191.66, 190.7], + '69.y': [116.95, 100.11], + '7.height': [5.88, 5.03], + '7.width': [10.75, 9.2], + '7.x': [285.94, 271.41], + '7.y': [120.38, 103.05], + '70.height': [7.16, 6.13], + '70.width': [8.3, 7.11], + '70.x': [200.67, 198.41], + '70.y': [124.51, 106.58], + '71.height': [5.57, 4.77], + '71.width': [2.21, 1.89], + '71.x': [208.4, 205.03], + '71.y': [125.22, 107.2], + '72.height': [12.45, 10.66], + '72.width': [7.58, 6.49], + '72.x': [206.61, 203.5], + '72.y': [126.01, 107.87], + '73.height': [1.3, 1.11], + '73.width': [1, 0.85], + '73.x': [206.96, 203.8], + '73.y': [137.6, 117.79], + '74.height': [9.87, 8.45], + '74.width': [8.9, 7.62], + '74.x': [193.33, 192.13], + '74.y': [121.77, 104.24], + '75.height': [1.54, 1.32], + '75.width': [1.24, 1.06], + '75.x': [205.78, 202.79], + '75.y': [120.27, 102.95], + '76.height': [3.17, 2.71], + '76.width': [1.12, 0.96], + '76.x': [209.53, 206], + '76.y': [93.3, 79.87], + '77.height': [1.34, 1.15], + '77.width': [1.06, 0.91], + '77.x': [210.15, 206.53], + '77.y': [92.12, 78.86], + '78.height': [10.29, 8.81], + '78.width': [5.17, 4.43], + '78.x': [215.96, 211.51], + '78.y': [127.27, 108.95], + '79.height': [1, 0.85], + '79.width': [0.44, 0.38], + '79.x': [210, 206.4], + '79.y': [93.93, 80.41], + '8.height': [11.39, 9.75], + '8.width': [32.74, 28.03], + '8.x': [253.22, 243.4], + '8.y': [114.66, 98.15], + '80.height': [0.55, 0.47], + '80.width': [2.15, 1.84], + '80.x': [172.94, 174.68], + '80.y': [108.55, 92.93], + '81.height': [6.08, 5.2], + '81.width': [2.84, 2.43], + '81.x': [190.39, 189.61], + '81.y': [89.72, 76.81], + '82.height': [14.75, 12.63], + '82.width': [14.81, 12.68], + '82.x': [178.78, 179.68], + '82.y': [89.93, 76.99], + '83.height': [3.5, 3], + '83.width': [3.06, 2.62], + '83.x': [210, 206.4], + '83.y': [93.21, 79.79], + '84.height': [2.8, 2.39], + '84.width': [3.45, 2.95], + '84.x': [221.93, 216.61], + '84.y': [99.26, 84.97], + '85.height': [1.23, 1.06], + '85.width': [0.62, 0.53], + '85.x': [221.33, 216.1], + '85.y': [99.21, 84.92], + '86.height': [1.26, 1.08], + '86.width': [1.32, 1.13], + '86.x': [218.34, 213.54], + '86.y': [96.01, 82.18], + '87.height': [7.1, 6.08], + '87.width': [7, 5.99], + '87.x': [212.77, 208.77], + '87.y': [89.69, 76.78], + '88.height': [7.51, 6.43], + '88.width': [5.59, 4.79], + '88.x': [222.23, 216.87], + '88.y': [98.98, 84.73], + '89.height': [1.47, 1.25], + '89.width': [0.87, 0.75], + '89.x': [304.29, 287.11], + '89.y': [129.17, 110.58], + '9.height': [31.63, 27.08], + '9.width': [14.16, 12.13], + '9.x': [132.44, 140.01], + '9.y': [134.61, 115.23], + '90.height': [3, 2.56], + '90.width': [3.77, 3.23], + '90.x': [258.27, 247.72], + '90.y': [108.04, 92.49], + '91.height': [10.86, 9.29], + '91.width': [5.88, 5.03], + '91.x': [254.71, 244.67], + '91.y': [103.65, 88.73], + '92.height': [6.47, 5.54], + '92.width': [5.33, 4.56], + '92.x': [256.67, 246.35], + '92.y': [102.08, 87.38], + '93.height': [14.02, 12], + '93.width': [6.36, 5.44], + '93.x': [251.08, 241.57], + '93.y': [97.42, 83.39], + '94.height': [11.02, 9.43], + '94.width': [5.13, 4.39], + '94.x': [258.14, 247.61], + '94.y': [101.39, 86.79], + '95.height': [5, 4.28], + '95.width': [4.66, 3.99], + '95.x': [273.96, 261.15], + '95.y': [84.44, 72.28], + '96.height': [3.76, 3.22], + '96.width': [2.4, 2.05], + '96.x': [275.29, 262.29], + '96.y': [88.58, 75.82], + '97.height': [10.98, 9.4], + '97.width': [22.92, 19.62], + '97.x': [247.82, 238.78], + '97.y': [74.8, 64.03], + '98.height': [21.49, 18.4], + '98.width': [20.92, 17.91], + '98.x': [233.81, 226.78], + '98.y': [91.38, 78.22], + '99.height': [4.51, 3.86], + '99.width': [3.29, 2.81], + '99.x': [248.06, 238.98], + '99.y': [98.94, 84.7], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.worldMercatorSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.interactiveSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [235, 304.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.interactiveSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.mapStoryBase @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [235, 304.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.mapStoryBase @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.readerZoomCountySpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [235, 304.58], + }, + }, + style: {}, + }, + '../gallery/maps.stories.tsx.readerZoomCountySpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.energyFlowSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.energyFlowSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.budgetSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.budgetSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.userJourneySpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.userJourneySpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.linkStyleSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.linkStyleSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.unemploymentSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 313.3], + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.unemploymentSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 309.2], + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.categoricalSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 325.75], + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.categoricalSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 311.2], + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.partialSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 306.7], + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.partialSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 309.2], + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.paletteSpecs.0 @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 319.45], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.paletteSpecs.0 @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 330.9], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.paletteSpecs.1 @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 319.45], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.paletteSpecs.1 @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 330.9], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.paletteSpecs.2 @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 319.45], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.paletteSpecs.2 @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 330.9], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.paletteSpecs.3 @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 319.45], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.paletteSpecs.3 @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 330.9], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.paletteSpecs.4 @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 319.45], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.paletteSpecs.4 @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 330.9], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.interactiveSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 329.3], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/sankey-tilemaps.stories.tsx.interactiveSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 333.2], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.multiLineSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [121.3, 135.3], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [286, 300], + 'x.start.y': [286, 300], + 'y.end.y': [286, 300], + 'y.tick.0.position': [256.72, 267.34], + 'y.tick.1.position': [214.89, 220.69], + 'y.tick.2.position': [173.07, 174.03], + 'y.titlePosition.y': [225.35, 232.35], + }, + marks: { + '0.height': [74.87, 83.51], + '0.y': [165.12, 165.17], + '1.height': [26.77, 29.86], + '1.y': [215.73, 221.62], + '2.height': [39.53, 44.09], + '2.y': [225.35, 232.35], + '3.height': [26.56, 29.63], + '3.y': [243.75, 252.88], + '4.height': [19.45, 21.69], + '4.y': [264.25, 275.74], + }, + annotations: { + 'a0.dot.y': [200.25, 204.36], + 'a0.label.y': [188.25, 192.36], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.multiLineSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.fullChromeSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'footer.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.fullChromeSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'footer.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.stackedAreaSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.stackedAreaSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.tableSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.tableSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.worldMapSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'mapSize.height': [149.3, 125.3], + }, + area: { + 'rect.height': [149.3, 125.3], + }, + chrome: { + bottomAnchorY: [324, 338], + bottomHeight: [66, 52], + 'byline.maxWidth': [235, 304.58], + 'byline.y': [42, 28], + 'source.maxWidth': [235, 304.58], + }, + marks: { + '0.height': [2.55, 2.14], + '0.width': [302.38, 253.77], + '0.x': [33.81, 58.11], + '0.y': [92.66, 77.76], + '1.height': [12.37, 10.38], + '1.width': [9.17, 7.69], + '1.x': [210.08, 206.04], + '1.y': [75.41, 63.28], + '10.height': [38.34, 32.18], + '10.width': [13.44, 11.28], + '10.x': [126.23, 135.68], + '10.y': [94.42, 79.24], + '100.height': [1.71, 1.43], + '100.width': [2.75, 2.31], + '100.x': [256.94, 245.38], + '100.y': [42.38, 35.57], + '101.height': [4.33, 3.64], + '101.width': [7.12, 5.98], + '101.x': [249.47, 239.1], + '101.y': [40.11, 33.66], + '102.height': [14.3, 12], + '102.width': [11.85, 9.95], + '102.x': [233.78, 225.94], + '102.y': [33.11, 27.78], + '103.height': [9.55, 8.02], + '103.width': [10.4, 8.73], + '103.x': [232.61, 224.95], + '103.y': [31.73, 26.63], + '104.height': [4.25, 3.57], + '104.width': [6.34, 5.32], + '104.x': [236.44, 228.17], + '104.y': [29.26, 24.56], + '105.height': [3.96, 3.32], + '105.width': [7.23, 6.07], + '105.x': [237.74, 229.26], + '105.y': [26.98, 22.64], + '106.height': [7.51, 6.31], + '106.width': [11.9, 9.98], + '106.x': [224.38, 218.05], + '106.y': [27.51, 23.08], + '107.height': [15.38, 12.91], + '107.width': [17.82, 14.96], + '107.x': [218.58, 213.18], + '107.y': [30.5, 25.6], + '108.height': [5.1, 4.28], + '108.width': [4.69, 3.93], + '108.x': [212.98, 208.48], + '108.y': [33.01, 27.7], + '109.height': [2.5, 2.1], + '109.width': [2.71, 2.28], + '109.x': [217.84, 212.56], + '109.y': [28.98, 24.32], + '11.height': [21.27, 17.85], + '11.width': [16.27, 13.66], + '11.x': [195.4, 193.73], + '11.y': [68.25, 57.28], + '110.height': [9.96, 8.36], + '110.width': [7.29, 6.12], + '110.x': [192.19, 191.04], + '110.y': [6.1, 5.12], + '111.height': [4.14, 3.47], + '111.width': [6.4, 5.37], + '111.x': [201.04, 198.46], + '111.y': [15.4, 12.92], + '112.height': [6.42, 5.38], + '112.width': [12.78, 10.72], + '112.x': [200.79, 198.25], + '112.y': [18.65, 15.65], + '113.height': [5.1, 4.28], + '113.width': [7.21, 6.05], + '113.x': [194.66, 193.1], + '113.y': [16.5, 13.84], + '114.height': [2.41, 2.02], + '114.width': [5.32, 4.47], + '114.x': [191.85, 190.75], + '114.y': [21.58, 18.11], + '115.height': [2.66, 2.23], + '115.width': [4.58, 3.85], + '115.x': [196.72, 194.84], + '115.y': [21.96, 18.43], + '116.height': [2.77, 2.33], + '116.width': [2.74, 2.3], + '116.x': [204.06, 201], + '116.y': [22.1, 18.55], + '117.height': [4.27, 3.58], + '117.width': [7.02, 5.89], + '117.x': [199.71, 197.35], + '117.y': [22.33, 18.74], + '118.height': [2.06, 1.73], + '118.width': [3.85, 3.23], + '118.x': [199.11, 196.84], + '118.y': [15.23, 12.79], + '119.height': [1.91, 1.61], + '119.width': [4.82, 4.05], + '119.x': [199.03, 196.78], + '119.y': [13.94, 11.7], + '12.height': [15.75, 13.22], + '12.width': [8.28, 6.95], + '12.x': [220.06, 214.42], + '12.y': [60.5, 50.77], + '120.height': [1.68, 1.41], + '120.width': [3.09, 2.6], + '120.x': [200.17, 197.73], + '120.y': [12.66, 10.62], + '121.height': [6.79, 5.7], + '121.width': [6.34, 5.32], + '121.x': [189.16, 188.49], + '121.y': [16.38, 13.75], + '122.height': [2.92, 2.45], + '122.width': [4.58, 3.85], + '122.x': [201.56, 198.9], + '122.y': [26.07, 21.88], + '123.height': [6.97, 5.85], + '123.width': [5.18, 4.34], + '123.x': [200.32, 197.86], + '123.y': [28.41, 23.84], + '124.height': [6.35, 5.33], + '124.width': [14.97, 12.56], + '124.x': [204.58, 201.43], + '124.y': [28.1, 23.58], + '125.height': [3.02, 2.54], + '125.width': [1.43, 1.2], + '125.x': [199.44, 197.12], + '125.y': [27.57, 23.14], + '126.height': [3.85, 3.23], + '126.width': [4.2, 3.53], + '126.x': [195, 193.39], + '126.y': [23.92, 20.08], + '127.height': [1.92, 1.61], + '127.width': [3.18, 2.67], + '127.x': [189.37, 188.67], + '127.y': [22.69, 19.04], + '128.height': [0.62, 0.52], + '128.width': [0.39, 0.33], + '128.x': [189.02, 188.38], + '128.y': [20.6, 17.29], + '129.height': [1.74, 1.46], + '129.width': [2.56, 2.15], + '129.x': [186.76, 186.48], + '129.y': [19.4, 16.28], + '13.height': [11.73, 9.85], + '13.width': [6.78, 5.69], + '13.x': [214.01, 209.35], + '13.y': [67.97, 57.04], + '130.height': [2.36, 1.98], + '130.width': [2.56, 2.15], + '130.x': [187.31, 186.94], + '130.y': [17.63, 14.8], + '131.height': [5.44, 4.57], + '131.width': [2.48, 2.08], + '131.x': [177.72, 178.89], + '131.y': [27.96, 23.47], + '132.height': [7.78, 6.53], + '132.width': [9.27, 7.78], + '132.x': [178.01, 179.14], + '132.y': [26.54, 22.27], + '133.height': [2.97, 2.49], + '133.width': [2.79, 2.34], + '133.x': [178.06, 179.18], + '133.y': [16.26, 13.65], + '134.height': [2.55, 2.14], + '134.width': [1.7, 1.43], + '134.x': [321.27, 299.37], + '134.y': [97.24, 81.61], + '135.height': [4.85, 4.07], + '135.width': [4.32, 3.62], + '135.x': [318.5, 297.04], + '135.y': [81.91, 68.74], + '136.height': [12.07, 10.13], + '136.width': [16.14, 13.55], + '136.x': [306.19, 286.71], + '136.y': [112.75, 94.63], + '137.height': [35.4, 29.71], + '137.width': [34.59, 29.03], + '137.x': [275.22, 260.72], + '137.y': [86.57, 72.66], + '138.height': [4.42, 3.71], + '138.width': [1.84, 1.54], + '138.x': [252.88, 241.97], + '138.y': [63.01, 52.88], + '139.height': [35.83, 30.07], + '139.width': [42.15, 35.37], + '139.x': [241.04, 232.03], + '139.y': [17.68, 14.84], + '14.height': [15.57, 13.07], + '14.width': [13.55, 11.37], + '14.x': [203.56, 200.58], + '14.y': [49.27, 41.35], + '140.height': [3.66, 3.07], + '140.width': [1.14, 0.96], + '140.x': [283.69, 267.82], + '140.y': [45.64, 38.31], + '141.height': [10.28, 8.62], + '141.width': [9.06, 7.6], + '141.x': [189.95, 189.15], + '141.y': [23.35, 19.6], + '142.height': [2.4, 2.02], + '142.width': [3.14, 2.63], + '142.x': [190.39, 189.53], + '142.y': [14.14, 11.86], + '143.height': [7.33, 6.15], + '143.width': [6.33, 5.31], + '143.x': [179.84, 180.67], + '143.y': [13.42, 11.26], + '144.height': [2.06, 1.73], + '144.width': [6.48, 5.44], + '144.x': [170.19, 172.57], + '144.y': [7.72, 6.48], + '145.height': [3.58, 3], + '145.width': [4.32, 3.62], + '145.x': [218.85, 213.41], + '145.y': [28.38, 23.81], + '146.height': [2.43, 2.04], + '146.width': [5.48, 4.6], + '146.x': [214.64, 209.87], + '146.y': [26.73, 22.43], + '147.height': [14.71, 12.35], + '147.width': [8.12, 6.81], + '147.x': [284.79, 268.75], + '147.y': [53.17, 44.62], + '148.height': [7.09, 5.95], + '148.width': [16.39, 13.75], + '148.x': [270.41, 256.68], + '148.y': [66.33, 55.67], + '149.height': [1.66, 1.39], + '149.width': [1, 0.84], + '149.x': [282.61, 266.92], + '149.y': [68.03, 57.1], + '15.height': [18.05, 15.15], + '15.width': [8.67, 7.27], + '15.x': [196.42, 194.58], + '15.y': [47.71, 40.04], + '150.height': [1.32, 1.1], + '150.width': [2.05, 1.72], + '150.x': [194.97, 193.37], + '150.y': [23.6, 19.8], + '151.height': [7, 5.87], + '151.width': [7.63, 6.41], + '151.x': [197.11, 195.16], + '151.y': [5.48, 4.6], + '152.height': [1.66, 1.39], + '152.width': [3.98, 3.34], + '152.x': [197.06, 195.12], + '152.y': [21.1, 17.71], + '153.height': [2.31, 1.94], + '153.width': [4.74, 3.98], + '153.x': [193.62, 192.24], + '153.y': [19.72, 16.55], + '154.height': [6.27, 5.26], + '154.width': [5.85, 4.91], + '154.x': [215.6, 210.68], + '154.y': [53.74, 45.1], + '155.height': [14.64, 12.29], + '155.width': [7.48, 6.28], + '155.x': [286.98, 270.58], + '155.y': [24.82, 20.83], + '156.height': [9.04, 7.58], + '156.width': [7.29, 6.12], + '156.x': [133.26, 141.58], + '156.y': [96.39, 80.9], + '157.height': [7.25, 6.08], + '157.width': [8.69, 7.29], + '157.x': [220.86, 215.09], + '157.y': [52.61, 44.15], + '158.height': [17.33, 14.54], + '158.width': [18.02, 15.12], + '158.x': [212.96, 208.47], + '158.y': [38.27, 32.11], + '159.height': [10.62, 8.91], + '159.width': [190.07, 159.52], + '159.x': [92.62, 107.47], + '159.y': [138.68, 116.39], + '16.height': [2.11, 1.77], + '16.width': [2.52, 2.12], + '16.x': [122.82, 132.82], + '16.y': [51.59, 43.3], + '160.height': [0.69, 0.58], + '160.width': [1.36, 1.14], + '160.x': [210.55, 206.44], + '160.y': [34.6, 29.04], + '161.height': [0.62, 0.52], + '161.width': [1.38, 1.16], + '161.x': [210.18, 206.13], + '161.y': [35.12, 29.47], + '162.height': [15.4, 12.92], + '162.width': [13.2, 11.07], + '162.x': [170.92, 173.18], + '162.y': [34.51, 28.97], + '163.height': [10.4, 8.73], + '163.width': [10.69, 8.98], + '163.x': [204.76, 201.58], + '163.y': [38.87, 32.62], + '164.height': [14.72, 12.36], + '164.width': [13.2, 11.08], + '164.x': [192.58, 191.36], + '164.y': [37.24, 31.25], + '165.height': [13.2, 11.08], + '165.width': [12.63, 10.6], + '165.x': [213.08, 208.57], + '165.y': [57.16, 47.97], + '166.height': [2.02, 1.7], + '166.width': [1.35, 1.14], + '166.x': [220.31, 214.63], + '166.y': [59.73, 50.13], + '167.height': [3.97, 3.33], + '167.width': [5.48, 4.6], + '167.x': [221.13, 215.32], + '167.y': [61.14, 51.31], + '168.height': [6.56, 5.51], + '168.width': [4.67, 3.92], + '168.x': [210.32, 206.25], + '168.y': [69.41, 58.25], + '169.height': [2.05, 1.72], + '169.width': [1.54, 1.29], + '169.x': [209.83, 205.84], + '169.y': [75.62, 63.46], + '17.height': [2.56, 2.15], + '17.width': [3.02, 2.54], + '17.x': [124.96, 134.61], + '17.y': [51.62, 43.32], + '170.height': [2.49, 2.09], + '170.width': [2.91, 2.44], + '170.x': [196.57, 194.71], + '170.y': [25.12, 21.08], + '171.height': [1.45, 1.22], + '171.width': [1.89, 1.59], + '171.x': [200.38, 197.9], + '171.y': [27.93, 23.44], + '172.height': [3.77, 3.16], + '172.width': [3.35, 2.81], + '172.x': [198.72, 196.52], + '172.y': [24.23, 20.34], + '173.height': [1.6, 1.34], + '173.width': [1.37, 1.15], + '173.x': [198.77, 196.56], + '173.y': [26.76, 22.46], + '174.height': [1.39, 1.17], + '174.width': [1.26, 1.06], + '174.x': [199.97, 197.57], + '174.y': [27, 22.66], + '175.height': [1.02, 0.85], + '175.width': [0.96, 0.8], + '175.x': [132.36, 140.83], + '175.y': [61.79, 51.86], + '176.height': [10.02, 8.41], + '176.width': [9.81, 8.23], + '176.x': [205.34, 202.07], + '176.y': [60.24, 50.56], + '18.height': [28.48, 23.9], + '18.width': [223.2, 187.32], + '18.x': [74.72, 92.45], + '18.y': [0.6, 0.5], + '19.height': [3.64, 3.05], + '19.width': [1.64, 1.37], + '19.x': [120.81, 131.13], + '19.y': [43.74, 36.71], + '2.height': [7.3, 6.13], + '2.width': [7.13, 5.98], + '2.x': [170.86, 173.13], + '2.y': [43.08, 36.15], + '20.height': [1.05, 0.88], + '20.width': [2.3, 1.93], + '20.x': [142.45, 149.29], + '20.y': [128.89, 108.17], + '21.height': [13.08, 10.98], + '21.width': [15, 12.59], + '21.x': [188.16, 187.65], + '21.y': [0.77, 0.65], + '22.height': [12.33, 10.35], + '22.width': [32.95, 27.65], + '22.x': [145.66, 151.99], + '23.height': [1.04, 0.88], + '23.width': [1.55, 1.3], + '23.x': [233.63, 225.81], + '23.y': [126.66, 106.3], + '24.height': [1.28, 1.08], + '24.width': [2.08, 1.75], + '24.x': [291.35, 274.26], + '24.y': [83.83, 70.36], + '25.height': [13.68, 11.48], + '25.width': [13.48, 11.32], + '25.x': [198.17, 196.05], + '25.y': [99.45, 83.46], + '26.height': [2.14, 1.79], + '26.width': [1.93, 1.62], + '26.x': [206.63, 203.15], + '26.y': [106.61, 89.48], + '27.height': [19.96, 16.75], + '27.width': [21.17, 17.77], + '27.x': [91.96, 106.92], + '27.y': [37.68, 31.62], + '28.height': [5.09, 4.27], + '28.width': [4.16, 3.49], + '28.x': [138.88, 146.29], + '28.y': [108.18, 90.79], + '29.height': [43.77, 36.74], + '29.width': [33.46, 28.08], + '29.x': [121.93, 132.07], + '29.y': [68.27, 57.29], + '3.height': [28.47, 23.89], + '3.width': [59.19, 49.68], + '3.x': [93.72, 108.39], + '3.y': [0.09, 0.08], + '30.height': [14.78, 12.4], + '30.width': [10.96, 9.2], + '30.x': [126, 135.49], + '30.y': [85.54, 71.79], + '31.height': [20.9, 17.54], + '31.width': [11.71, 9.82], + '31.x': [115.43, 126.61], + '31.y': [74.38, 62.42], + '32.height': [19.24, 16.15], + '32.width': [10.36, 8.7], + '32.x': [117.4, 128.27], + '32.y': [60.03, 50.38], + '33.height': [2.74, 2.3], + '33.width': [4.85, 4.07], + '33.x': [114.33, 125.69], + '33.y': [63.25, 53.09], + '34.height': [3.42, 2.87], + '34.width': [2.74, 2.3], + '34.x': [112.07, 123.79], + '34.y': [61.42, 51.55], + '35.height': [4.88, 4.1], + '35.width': [4.12, 3.46], + '35.x': [110.87, 122.78], + '35.y': [57.1, 47.92], + '36.height': [3.43, 2.87], + '36.width': [5.32, 4.46], + '36.x': [109.67, 121.78], + '36.y': [55.98, 46.98], + '37.height': [1.45, 1.22], + '37.width': [2.01, 1.69], + '37.x': [108.94, 121.16], + '37.y': [57.77, 48.48], + '38.height': [4.62, 3.87], + '38.width': [3.57, 3], + '38.x': [107.27, 119.76], + '38.y': [53.94, 45.27], + '39.height': [2.94, 2.47], + '39.width': [1.4, 1.18], + '39.x': [110.02, 122.07], + '39.y': [53.17, 44.62], + '4.height': [47.9, 40.2], + '4.width': [82.99, 69.65], + '4.x': [53.03, 74.24], + '4.y': [4.81, 4.03], + '40.height': [13.13, 11.02], + '40.width': [11.47, 9.63], + '40.x': [122.64, 132.66], + '40.y': [60.34, 50.64], + '41.height': [8.17, 6.86], + '41.width': [4.05, 3.4], + '41.x': [132.57, 141], + '41.y': [64.68, 54.28], + '42.height': [4.85, 4.07], + '42.width': [3.55, 2.98], + '42.x': [135.38, 143.35], + '42.y': [67.37, 56.54], + '43.height': [52.25, 43.85], + '43.width': [53.8, 45.16], + '43.x': [138.35, 145.85], + '43.y': [19.69, 16.52], + '44.height': [7.31, 6.13], + '44.width': [4.88, 4.1], + '44.x': [115.72, 126.86], + '44.y': [72.72, 61.03], + '45.height': [0.64, 0.54], + '45.width': [1.37, 1.15], + '45.x': [128.83, 137.86], + '45.y': [53.15, 44.61], + '46.height': [0.92, 0.78], + '46.width': [1.73, 1.45], + '46.x': [119.56, 130.08], + '46.y': [53.14, 44.6], + '47.height': [3.7, 3.1], + '47.width': [8.61, 7.23], + '47.x': [114.79, 126.07], + '47.y': [47.96, 40.25], + '48.height': [7.57, 6.36], + '48.width': [6.42, 5.38], + '48.x': [206.13, 202.73], + '48.y': [92.08, 77.28], + '49.height': [10.14, 8.51], + '49.width': [8.03, 6.74], + '49.x': [201.28, 198.66], + '49.y': [94.51, 79.32], + '5.height': [13.51, 11.34], + '5.width': [28.89, 24.25], + '5.x': [218.18, 212.85], + '5.y': [16.05, 13.47], + '50.height': [13.34, 11.2], + '50.width': [11.16, 9.37], + '50.x': [194.83, 193.25], + '50.y': [93.7, 78.64], + '51.height': [4.84, 4.06], + '51.width': [5.15, 4.32], + '51.x': [170.15, 172.54], + '51.y': [55.31, 46.42], + '52.height': [16.7, 14.02], + '52.width': [13.84, 11.61], + '52.x': [174.74, 176.39], + '52.y': [45.99, 38.6], + '53.height': [14.19, 11.91], + '53.width': [10.11, 8.49], + '53.x': [170.86, 173.13], + '53.y': [43.36, 36.39], + '54.height': [6.98, 5.86], + '54.width': [2.57, 2.15], + '54.x': [185.66, 185.55], + '54.y': [60.26, 50.57], + '55.height': [13.27, 11.14], + '55.width': [12.95, 10.87], + '55.x': [185.25, 185.21], + '55.y': [47.64, 39.99], + '56.height': [11.02, 9.25], + '56.width': [10.05, 8.43], + '56.x': [187.3, 186.93], + '56.y': [58.4, 49.01], + '57.height': [12.77, 10.72], + '57.width': [6.45, 5.41], + '57.x': [192.25, 191.09], + '57.y': [59.55, 49.97], + '58.height': [5.83, 4.9], + '58.width': [1.63, 1.37], + '58.y': [61.64, 51.74], + '59.height': [7.33, 6.15], + '59.width': [3.68, 3.08], + '59.x': [182.23, 182.68], + '59.y': [61.55, 51.66], + '6.height': [8.31, 6.97], + '6.width': [14.09, 11.82], + '6.x': [226.03, 219.43], + '6.y': [24.79, 20.8], + '60.height': [7.1, 5.96], + '60.width': [5.16, 4.33], + '60.x': [177.66, 178.84], + '60.y': [62.21, 52.21], + '61.height': [6.04, 5.07], + '61.width': [6.17, 5.18], + '61.x': [172.16, 174.23], + '61.y': [59.86, 50.24], + '62.height': [1.81, 1.52], + '62.width': [2.52, 2.12], + '62.x': [170.88, 173.15], + '62.y': [59.81, 50.19], + '63.height': [4.81, 4.04], + '63.width': [3.32, 2.78], + '63.x': [175.24, 176.81], + '63.y': [64.48, 54.11], + '64.height': [3.74, 3.14], + '64.width': [2.56, 2.15], + '64.x': [173.73, 175.54], + '64.y': [62.75, 52.67], + '65.height': [6.27, 5.26], + '65.width': [6.48, 5.44], + '65.x': [180.36, 181.1], + '65.y': [56.98, 47.82], + '66.height': [10.19, 8.55], + '66.width': [11.03, 9.26], + '66.x': [197.35, 195.36], + '66.y': [61.5, 51.62], + '67.height': [10.1, 8.48], + '67.width': [6.3, 5.28], + '67.x': [194.48, 192.96], + '67.y': [70.01, 58.76], + '68.height': [7.27, 6.1], + '68.width': [4.82, 4.04], + '68.x': [192.53, 191.32], + '68.y': [71.63, 60.11], + '69.height': [1.47, 1.23], + '69.width': [1.69, 1.42], + '69.x': [192.96, 191.68], + '69.y': [71.68, 60.15], + '7.height': [9.37, 7.86], + '7.width': [13.14, 11.03], + '7.x': [304.99, 285.7], + '7.y': [77.19, 64.78], + '70.height': [11.05, 9.27], + '70.width': [10.05, 8.43], + '70.x': [203.38, 200.43], + '70.y': [83.79, 70.32], + '71.height': [8.61, 7.22], + '71.width': [2.48, 2.08], + '71.x': [212.6, 208.16], + '71.y': [84.93, 71.28], + '72.height': [18.38, 15.43], + '72.width': [8.93, 7.5], + '72.x': [210.42, 206.34], + '72.y': [86.17, 72.32], + '73.height': [1.77, 1.48], + '73.width': [1.13, 0.95], + '73.x': [209.91, 205.91], + '73.y': [103.38, 86.76], + '74.height': [15.38, 12.91], + '74.width': [10.62, 8.92], + '74.x': [194.76, 193.19], + '74.y': [79.42, 66.66], + '75.height': [2.48, 2.08], + '75.width': [1.47, 1.24], + '75.x': [209.83, 205.84], + '75.y': [77.02, 64.64], + '76.height': [4, 3.36], + '76.width': [1.02, 0.86], + '76.x': [212.28, 207.9], + '76.y': [37.09, 31.13], + '77.height': [1.62, 1.36], + '77.width': [1.01, 0.84], + '77.x': [212.71, 208.26], + '77.y': [35.67, 29.93], + '78.height': [15.17, 12.73], + '78.width': [6.77, 5.68], + '78.x': [220.71, 214.97], + '78.y': [88.14, 73.97], + '79.height': [1.25, 1.05], + '79.width': [0.46, 0.39], + '79.x': [212.76, 208.3], + '79.y': [37.87, 31.78], + '8.height': [18.23, 15.3], + '8.width': [39.24, 32.93], + '8.x': [266.39, 253.31], + '8.y': [68, 57.07], + '80.height': [0.85, 0.71], + '80.width': [2.54, 2.13], + '80.x': [170.76, 173.05], + '80.y': [58.39, 49], + '81.height': [7.34, 6.16], + '81.width': [3.16, 2.65], + '81.x': [190.91, 189.96], + '81.y': [32.89, 27.6], + '82.height': [19.43, 16.3], + '82.width': [16.9, 14.18], + '82.x': [177.97, 179.1], + '82.y': [33.12, 27.8], + '83.height': [4.43, 3.72], + '83.width': [3.04, 2.55], + '83.x': [213.02, 208.52], + '83.y': [36.98, 31.04], + '84.height': [3.91, 3.28], + '84.width': [3.83, 3.22], + '84.x': [227.28, 220.48], + '84.y': [44.81, 37.61], + '85.height': [1.7, 1.43], + '85.width': [0.75, 0.63], + '85.x': [226.4, 219.75], + '85.y': [44.75, 37.56], + '86.height': [1.64, 1.38], + '86.width': [1.58, 1.32], + '86.x': [222.43, 216.42], + '86.y': [40.5, 33.99], + '87.height': [8.67, 7.28], + '87.width': [8.34, 7], + '87.x': [215.56, 210.64], + '87.y': [32.85, 27.57], + '88.height': [10.81, 9.07], + '88.width': [6, 5.04], + '88.x': [228.35, 221.38], + '88.y': [44.44, 37.3], + '89.height': [2.23, 1.87], + '89.width': [0.65, 0.55], + '89.x': [325.2, 302.66], + '89.y': [91.08, 76.44], + '9.height': [33.29, 27.94], + '9.width': [12.69, 10.65], + '9.x': [128.78, 137.82], + '9.y': [99.16, 83.22], + '90.height': [4.65, 3.9], + '90.width': [4.53, 3.8], + '90.x': [271.46, 257.57], + '90.y': [57.6, 48.34], + '91.height': [16.73, 14.04], + '91.width': [7.62, 6.4], + '91.x': [266.3, 253.23], + '91.y': [51.03, 42.82], + '92.height': [9.63, 8.08], + '92.width': [7.46, 6.26], + '92.x': [268.11, 254.75], + '92.y': [48.76, 40.92], + '93.height': [20.54, 17.24], + '93.width': [7.99, 6.71], + '93.x': [261.37, 249.1], + '93.y': [42.34, 35.54], + '94.height': [16.64, 13.96], + '94.width': [8.28, 6.95], + '94.x': [269.27, 255.72], + '94.y': [47.77, 40.09], + '95.height': [5.28, 4.43], + '95.width': [3.92, 3.29], + '95.x': [279.31, 264.15], + '95.y': [27.28, 22.89], + '96.height': [4.32, 3.63], + '96.width': [3.75, 3.15], + '96.x': [282.03, 266.43], + '96.y': [31.61, 26.53], + '97.height': [9.74, 8.17], + '97.width': [24.39, 20.47], + '97.x': [247.31, 237.29], + '97.y': [18.9, 15.86], + '98.height': [30.35, 25.47], + '98.width': [22.76, 19.1], + '98.x': [240.99, 231.99], + '98.y': [34.79, 29.2], + '99.height': [6.36, 5.34], + '99.width': [4.81, 4.04], + '99.x': [256.89, 245.33], + '99.y': [44.39, 37.25], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.worldMapSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.sankeySpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.sankeySpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.scatterSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.scatterSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.keyboardSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/showcase.stories.tsx.keyboardSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.basicSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.basicSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.heatmapSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.heatmapSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.inlineBarSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.inlineBarSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.sparklineSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.sparklineSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.flagsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.flagsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.imageSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.imageSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.categorySpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.categorySpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.builtinSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.builtinSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.controlledSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.controlledSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.deltaSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.deltaSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.totalsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.totalsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.relaxedSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../gallery/tables.stories.tsx.relaxedSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../gallery/welcome.stories.tsx.heroSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [138.7, 152.7], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [286, 300], + 'x.start.y': [286, 300], + 'y.end.y': [286, 300], + 'y.tick.0.position': [252.52, 263.14], + 'y.tick.1.position': [204.69, 210.49], + 'y.tick.2.position': [156.87, 157.83], + 'y.titlePosition.y': [216.65, 223.65], + }, + marks: { + '0.height': [85.61, 94.25], + '0.y': [147.78, 147.83], + '1.height': [30.61, 33.7], + '1.y': [205.65, 211.54], + '2.height': [45.2, 49.76], + '2.y': [216.65, 223.65], + '3.height': [30.37, 33.44], + '3.y': [237.69, 246.82], + '4.height': [22.24, 24.48], + '4.y': [261.13, 272.62], + }, + annotations: { + 'a0.connector.from.y': [140.44, 140.49], + 'a0.connector.to.y': [146.05, 146.1], + 'a0.dot.y': [147.78, 147.83], + 'a0.label.y': [123.78, 123.83], + }, + }, + style: {}, + }, + '../gallery/welcome.stories.tsx.heroSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../gallery/welcome.stories.tsx.quickStartSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../gallery/welcome.stories.tsx.quickStartSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/a11y.stories.tsx.patternStackedSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/a11y.stories.tsx.patternStackedSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.simpleColumnSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.simpleColumnSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.longLabelsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.longLabelsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.simpleBarSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.simpleBarSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.energyColumnSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.energyColumnSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.tempSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.tempSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.populationBarSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.populationBarSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.compactPopSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-bars.stories.tsx.compactPopSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-beeswarm.stories.tsx.beeswarmBasicSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-beeswarm.stories.tsx.beeswarmBasicSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-beeswarm.stories.tsx.beeswarmGroupedSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-beeswarm.stories.tsx.beeswarmGroupedSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-beeswarm.stories.tsx.beeswarmSizedSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-beeswarm.stories.tsx.beeswarmSizedSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-calendar.stories.tsx.calendarDivergingSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-calendar.stories.tsx.calendarDivergingSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-calendar.stories.tsx.calendarTwoYearSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [203.3, 201.7], + }, + chrome: { + bottomAnchorY: [331, 329.4], + bottomHeight: [53, 54.6], + 'source.maxWidth': [223, 292.58], + }, + marks: { + '0.y': [213.35, 212.55], + '1.y': [159.35, 158.55], + '10.y': [177.35, 176.55], + '100.y': [168.35, 167.55], + '101.y': [177.35, 176.55], + '102.y': [186.35, 185.55], + '103.y': [195.35, 194.55], + '104.y': [204.35, 203.55], + '105.y': [213.35, 212.55], + '106.y': [159.35, 158.55], + '107.y': [168.35, 167.55], + '108.y': [177.35, 176.55], + '109.y': [186.35, 185.55], + '11.y': [186.35, 185.55], + '110.y': [195.35, 194.55], + '111.y': [204.35, 203.55], + '112.y': [213.35, 212.55], + '113.y': [159.35, 158.55], + '114.y': [168.35, 167.55], + '115.y': [177.35, 176.55], + '116.y': [186.35, 185.55], + '117.y': [195.35, 194.55], + '118.y': [204.35, 203.55], + '119.y': [213.35, 212.55], + '12.y': [195.35, 194.55], + '120.y': [159.35, 158.55], + '121.y': [168.35, 167.55], + '122.y': [177.35, 176.55], + '123.y': [186.35, 185.55], + '124.y': [195.35, 194.55], + '125.y': [204.35, 203.55], + '126.y': [213.35, 212.55], + '127.y': [159.35, 158.55], + '128.y': [168.35, 167.55], + '129.y': [177.35, 176.55], + '13.y': [204.35, 203.55], + '130.y': [186.35, 185.55], + '131.y': [195.35, 194.55], + '132.y': [204.35, 203.55], + '133.y': [213.35, 212.55], + '134.y': [159.35, 158.55], + '135.y': [168.35, 167.55], + '136.y': [177.35, 176.55], + '137.y': [186.35, 185.55], + '138.y': [195.35, 194.55], + '139.y': [204.35, 203.55], + '14.y': [213.35, 212.55], + '140.y': [213.35, 212.55], + '141.y': [159.35, 158.55], + '142.y': [168.35, 167.55], + '143.y': [177.35, 176.55], + '144.y': [186.35, 185.55], + '145.y': [195.35, 194.55], + '146.y': [204.35, 203.55], + '147.y': [213.35, 212.55], + '148.y': [159.35, 158.55], + '149.y': [168.35, 167.55], + '15.y': [159.35, 158.55], + '150.y': [177.35, 176.55], + '151.y': [186.35, 185.55], + '152.y': [195.35, 194.55], + '153.y': [204.35, 203.55], + '154.y': [213.35, 212.55], + '155.y': [159.35, 158.55], + '156.y': [168.35, 167.55], + '157.y': [177.35, 176.55], + '158.y': [186.35, 185.55], + '159.y': [195.35, 194.55], + '16.y': [168.35, 167.55], + '160.y': [204.35, 203.55], + '161.y': [213.35, 212.55], + '162.y': [159.35, 158.55], + '163.y': [168.35, 167.55], + '164.y': [177.35, 176.55], + '165.y': [186.35, 185.55], + '166.y': [195.35, 194.55], + '167.y': [204.35, 203.55], + '168.y': [213.35, 212.55], + '169.y': [159.35, 158.55], + '17.y': [177.35, 176.55], + '170.y': [168.35, 167.55], + '171.y': [177.35, 176.55], + '172.y': [186.35, 185.55], + '173.y': [195.35, 194.55], + '174.y': [204.35, 203.55], + '175.y': [213.35, 212.55], + '176.y': [159.35, 158.55], + '177.y': [168.35, 167.55], + '178.y': [177.35, 176.55], + '179.y': [186.35, 185.55], + '18.y': [186.35, 185.55], + '180.y': [195.35, 194.55], + '181.y': [204.35, 203.55], + '182.y': [213.35, 212.55], + '183.y': [159.35, 158.55], + '184.y': [168.35, 167.55], + '185.y': [177.35, 176.55], + '186.y': [186.35, 185.55], + '187.y': [195.35, 194.55], + '188.y': [204.35, 203.55], + '189.y': [213.35, 212.55], + '19.y': [195.35, 194.55], + '190.y': [159.35, 158.55], + '191.y': [168.35, 167.55], + '192.y': [177.35, 176.55], + '193.y': [186.35, 185.55], + '194.y': [195.35, 194.55], + '195.y': [204.35, 203.55], + '196.y': [213.35, 212.55], + '197.y': [159.35, 158.55], + '198.y': [168.35, 167.55], + '199.y': [177.35, 176.55], + '2.y': [168.35, 167.55], + '20.y': [204.35, 203.55], + '200.y': [186.35, 185.55], + '201.y': [195.35, 194.55], + '202.y': [204.35, 203.55], + '203.y': [213.35, 212.55], + '204.y': [159.35, 158.55], + '205.y': [168.35, 167.55], + '206.y': [177.35, 176.55], + '207.y': [186.35, 185.55], + '208.y': [195.35, 194.55], + '209.y': [204.35, 203.55], + '21.y': [213.35, 212.55], + '210.y': [213.35, 212.55], + '211.y': [159.35, 158.55], + '212.y': [168.35, 167.55], + '213.y': [177.35, 176.55], + '214.y': [186.35, 185.55], + '215.y': [195.35, 194.55], + '216.y': [204.35, 203.55], + '217.y': [213.35, 212.55], + '218.y': [159.35, 158.55], + '219.y': [168.35, 167.55], + '22.y': [159.35, 158.55], + '220.y': [177.35, 176.55], + '221.y': [186.35, 185.55], + '222.y': [195.35, 194.55], + '223.y': [204.35, 203.55], + '224.y': [213.35, 212.55], + '225.y': [159.35, 158.55], + '226.y': [168.35, 167.55], + '227.y': [177.35, 176.55], + '228.y': [186.35, 185.55], + '229.y': [195.35, 194.55], + '23.y': [168.35, 167.55], + '230.y': [204.35, 203.55], + '231.y': [213.35, 212.55], + '232.y': [159.35, 158.55], + '233.y': [168.35, 167.55], + '234.y': [177.35, 176.55], + '235.y': [186.35, 185.55], + '236.y': [195.35, 194.55], + '237.y': [204.35, 203.55], + '238.y': [213.35, 212.55], + '239.y': [159.35, 158.55], + '24.y': [177.35, 176.55], + '240.y': [168.35, 167.55], + '241.y': [177.35, 176.55], + '242.y': [186.35, 185.55], + '243.y': [195.35, 194.55], + '244.y': [204.35, 203.55], + '245.y': [213.35, 212.55], + '246.y': [159.35, 158.55], + '247.y': [168.35, 167.55], + '248.y': [177.35, 176.55], + '249.y': [186.35, 185.55], + '25.y': [186.35, 185.55], + '250.y': [195.35, 194.55], + '251.y': [204.35, 203.55], + '252.y': [213.35, 212.55], + '253.y': [159.35, 158.55], + '254.y': [168.35, 167.55], + '255.y': [177.35, 176.55], + '256.y': [186.35, 185.55], + '257.y': [195.35, 194.55], + '258.y': [204.35, 203.55], + '259.y': [213.35, 212.55], + '26.y': [195.35, 194.55], + '260.y': [159.35, 158.55], + '261.y': [168.35, 167.55], + '262.y': [177.35, 176.55], + '263.y': [186.35, 185.55], + '264.y': [195.35, 194.55], + '265.y': [204.35, 203.55], + '266.y': [213.35, 212.55], + '267.y': [159.35, 158.55], + '268.y': [168.35, 167.55], + '269.y': [177.35, 176.55], + '27.y': [204.35, 203.55], + '270.y': [186.35, 185.55], + '271.y': [195.35, 194.55], + '272.y': [204.35, 203.55], + '273.y': [213.35, 212.55], + '274.y': [159.35, 158.55], + '275.y': [168.35, 167.55], + '276.y': [177.35, 176.55], + '277.y': [186.35, 185.55], + '278.y': [195.35, 194.55], + '279.y': [204.35, 203.55], + '28.y': [213.35, 212.55], + '280.y': [213.35, 212.55], + '281.y': [159.35, 158.55], + '282.y': [168.35, 167.55], + '283.y': [177.35, 176.55], + '284.y': [186.35, 185.55], + '285.y': [195.35, 194.55], + '286.y': [204.35, 203.55], + '287.y': [213.35, 212.55], + '288.y': [159.35, 158.55], + '289.y': [168.35, 167.55], + '29.y': [159.35, 158.55], + '290.y': [177.35, 176.55], + '291.y': [186.35, 185.55], + '292.y': [195.35, 194.55], + '293.y': [204.35, 203.55], + '294.y': [213.35, 212.55], + '295.y': [159.35, 158.55], + '296.y': [168.35, 167.55], + '297.y': [177.35, 176.55], + '298.y': [186.35, 185.55], + '299.y': [195.35, 194.55], + '3.y': [177.35, 176.55], + '30.y': [168.35, 167.55], + '300.y': [204.35, 203.55], + '301.y': [213.35, 212.55], + '302.y': [159.35, 158.55], + '303.y': [168.35, 167.55], + '304.y': [177.35, 176.55], + '305.y': [186.35, 185.55], + '306.y': [195.35, 194.55], + '307.y': [204.35, 203.55], + '308.y': [213.35, 212.55], + '309.y': [159.35, 158.55], + '31.y': [177.35, 176.55], + '310.y': [168.35, 167.55], + '311.y': [177.35, 176.55], + '312.y': [186.35, 185.55], + '313.y': [195.35, 194.55], + '314.y': [204.35, 203.55], + '315.y': [213.35, 212.55], + '316.y': [159.35, 158.55], + '317.y': [168.35, 167.55], + '318.y': [177.35, 176.55], + '319.y': [186.35, 185.55], + '32.y': [186.35, 185.55], + '320.y': [195.35, 194.55], + '321.y': [204.35, 203.55], + '322.y': [213.35, 212.55], + '323.y': [159.35, 158.55], + '324.y': [168.35, 167.55], + '325.y': [177.35, 176.55], + '326.y': [186.35, 185.55], + '327.y': [195.35, 194.55], + '328.y': [204.35, 203.55], + '329.y': [213.35, 212.55], + '33.y': [195.35, 194.55], + '330.y': [159.35, 158.55], + '331.y': [168.35, 167.55], + '332.y': [177.35, 176.55], + '333.y': [186.35, 185.55], + '334.y': [195.35, 194.55], + '335.y': [204.35, 203.55], + '336.y': [213.35, 212.55], + '337.y': [159.35, 158.55], + '338.y': [168.35, 167.55], + '339.y': [177.35, 176.55], + '34.y': [204.35, 203.55], + '340.y': [186.35, 185.55], + '341.y': [195.35, 194.55], + '342.y': [204.35, 203.55], + '343.y': [213.35, 212.55], + '344.y': [159.35, 158.55], + '345.y': [168.35, 167.55], + '346.y': [177.35, 176.55], + '347.y': [186.35, 185.55], + '348.y': [195.35, 194.55], + '349.y': [204.35, 203.55], + '35.y': [213.35, 212.55], + '350.y': [213.35, 212.55], + '351.y': [159.35, 158.55], + '352.y': [168.35, 167.55], + '353.y': [177.35, 176.55], + '354.y': [186.35, 185.55], + '355.y': [195.35, 194.55], + '356.y': [204.35, 203.55], + '357.y': [213.35, 212.55], + '358.y': [159.35, 158.55], + '359.y': [168.35, 167.55], + '36.y': [159.35, 158.55], + '360.y': [177.35, 176.55], + '361.y': [186.35, 185.55], + '362.y': [195.35, 194.55], + '363.y': [204.35, 203.55], + '364.y': [213.35, 212.55], + '365.y': [255.35, 254.55], + '366.y': [264.35, 263.55], + '367.y': [273.35, 272.55], + '368.y': [282.35, 281.55], + '369.y': [291.35, 290.55], + '37.y': [168.35, 167.55], + '370.y': [300.35, 299.55], + '371.y': [309.35, 308.55], + '372.y': [255.35, 254.55], + '373.y': [264.35, 263.55], + '374.y': [273.35, 272.55], + '375.y': [282.35, 281.55], + '376.y': [291.35, 290.55], + '377.y': [300.35, 299.55], + '378.y': [309.35, 308.55], + '379.y': [255.35, 254.55], + '38.y': [177.35, 176.55], + '380.y': [264.35, 263.55], + '381.y': [273.35, 272.55], + '382.y': [282.35, 281.55], + '383.y': [291.35, 290.55], + '384.y': [300.35, 299.55], + '385.y': [309.35, 308.55], + '386.y': [255.35, 254.55], + '387.y': [264.35, 263.55], + '388.y': [273.35, 272.55], + '389.y': [282.35, 281.55], + '39.y': [186.35, 185.55], + '390.y': [291.35, 290.55], + '391.y': [300.35, 299.55], + '392.y': [309.35, 308.55], + '393.y': [255.35, 254.55], + '394.y': [264.35, 263.55], + '395.y': [273.35, 272.55], + '396.y': [282.35, 281.55], + '397.y': [291.35, 290.55], + '398.y': [300.35, 299.55], + '399.y': [309.35, 308.55], + '4.y': [186.35, 185.55], + '40.y': [195.35, 194.55], + '400.y': [255.35, 254.55], + '401.y': [264.35, 263.55], + '402.y': [273.35, 272.55], + '403.y': [282.35, 281.55], + '404.y': [291.35, 290.55], + '405.y': [300.35, 299.55], + '406.y': [309.35, 308.55], + '407.y': [255.35, 254.55], + '408.y': [264.35, 263.55], + '409.y': [273.35, 272.55], + '41.y': [204.35, 203.55], + '410.y': [282.35, 281.55], + '411.y': [291.35, 290.55], + '412.y': [300.35, 299.55], + '413.y': [309.35, 308.55], + '414.y': [255.35, 254.55], + '415.y': [264.35, 263.55], + '416.y': [273.35, 272.55], + '417.y': [282.35, 281.55], + '418.y': [291.35, 290.55], + '419.y': [300.35, 299.55], + '42.y': [213.35, 212.55], + '420.y': [309.35, 308.55], + '421.y': [255.35, 254.55], + '422.y': [264.35, 263.55], + '423.y': [273.35, 272.55], + '424.y': [282.35, 281.55], + '425.y': [291.35, 290.55], + '426.y': [300.35, 299.55], + '427.y': [309.35, 308.55], + '428.y': [255.35, 254.55], + '429.y': [264.35, 263.55], + '43.y': [159.35, 158.55], + '430.y': [273.35, 272.55], + '431.y': [282.35, 281.55], + '432.y': [291.35, 290.55], + '433.y': [300.35, 299.55], + '434.y': [309.35, 308.55], + '435.y': [255.35, 254.55], + '436.y': [264.35, 263.55], + '437.y': [273.35, 272.55], + '438.y': [282.35, 281.55], + '439.y': [291.35, 290.55], + '44.y': [168.35, 167.55], + '440.y': [300.35, 299.55], + '441.y': [309.35, 308.55], + '442.y': [255.35, 254.55], + '443.y': [264.35, 263.55], + '444.y': [273.35, 272.55], + '445.y': [282.35, 281.55], + '446.y': [291.35, 290.55], + '447.y': [300.35, 299.55], + '448.y': [309.35, 308.55], + '449.y': [255.35, 254.55], + '45.y': [177.35, 176.55], + '450.y': [264.35, 263.55], + '451.y': [273.35, 272.55], + '452.y': [282.35, 281.55], + '453.y': [291.35, 290.55], + '454.y': [300.35, 299.55], + '455.y': [309.35, 308.55], + '456.y': [255.35, 254.55], + '457.y': [264.35, 263.55], + '458.y': [273.35, 272.55], + '459.y': [282.35, 281.55], + '46.y': [186.35, 185.55], + '460.y': [291.35, 290.55], + '461.y': [300.35, 299.55], + '462.y': [309.35, 308.55], + '463.y': [255.35, 254.55], + '464.y': [264.35, 263.55], + '465.y': [273.35, 272.55], + '466.y': [282.35, 281.55], + '467.y': [291.35, 290.55], + '468.y': [300.35, 299.55], + '469.y': [309.35, 308.55], + '47.y': [195.35, 194.55], + '470.y': [255.35, 254.55], + '471.y': [264.35, 263.55], + '472.y': [273.35, 272.55], + '473.y': [282.35, 281.55], + '474.y': [291.35, 290.55], + '475.y': [300.35, 299.55], + '476.y': [309.35, 308.55], + '477.y': [255.35, 254.55], + '478.y': [264.35, 263.55], + '479.y': [273.35, 272.55], + '48.y': [204.35, 203.55], + '480.y': [282.35, 281.55], + '481.y': [291.35, 290.55], + '482.y': [300.35, 299.55], + '483.y': [309.35, 308.55], + '484.y': [255.35, 254.55], + '485.y': [264.35, 263.55], + '486.y': [273.35, 272.55], + '487.y': [282.35, 281.55], + '488.y': [291.35, 290.55], + '489.y': [300.35, 299.55], + '49.y': [213.35, 212.55], + '490.y': [309.35, 308.55], + '491.y': [255.35, 254.55], + '492.y': [264.35, 263.55], + '493.y': [273.35, 272.55], + '494.y': [282.35, 281.55], + '495.y': [291.35, 290.55], + '496.y': [300.35, 299.55], + '497.y': [309.35, 308.55], + '498.y': [255.35, 254.55], + '499.y': [264.35, 263.55], + '5.y': [195.35, 194.55], + '50.y': [159.35, 158.55], + '500.y': [273.35, 272.55], + '501.y': [282.35, 281.55], + '502.y': [291.35, 290.55], + '503.y': [300.35, 299.55], + '504.y': [309.35, 308.55], + '505.y': [255.35, 254.55], + '506.y': [264.35, 263.55], + '507.y': [273.35, 272.55], + '508.y': [282.35, 281.55], + '509.y': [291.35, 290.55], + '51.y': [168.35, 167.55], + '510.y': [300.35, 299.55], + '511.y': [309.35, 308.55], + '512.y': [255.35, 254.55], + '513.y': [264.35, 263.55], + '514.y': [273.35, 272.55], + '515.y': [282.35, 281.55], + '516.y': [291.35, 290.55], + '517.y': [300.35, 299.55], + '518.y': [309.35, 308.55], + '519.y': [255.35, 254.55], + '52.y': [177.35, 176.55], + '520.y': [264.35, 263.55], + '521.y': [273.35, 272.55], + '522.y': [282.35, 281.55], + '523.y': [291.35, 290.55], + '524.y': [300.35, 299.55], + '525.y': [309.35, 308.55], + '526.y': [255.35, 254.55], + '527.y': [264.35, 263.55], + '528.y': [273.35, 272.55], + '529.y': [282.35, 281.55], + '53.y': [186.35, 185.55], + '530.y': [291.35, 290.55], + '531.y': [300.35, 299.55], + '532.y': [309.35, 308.55], + '533.y': [255.35, 254.55], + '534.y': [264.35, 263.55], + '535.y': [273.35, 272.55], + '536.y': [282.35, 281.55], + '537.y': [291.35, 290.55], + '538.y': [300.35, 299.55], + '539.y': [309.35, 308.55], + '54.y': [195.35, 194.55], + '540.y': [255.35, 254.55], + '541.y': [264.35, 263.55], + '542.y': [273.35, 272.55], + '543.y': [282.35, 281.55], + '544.y': [291.35, 290.55], + '545.y': [300.35, 299.55], + '546.y': [309.35, 308.55], + '547.y': [255.35, 254.55], + '548.y': [264.35, 263.55], + '549.y': [273.35, 272.55], + '55.y': [204.35, 203.55], + '550.y': [282.35, 281.55], + '551.y': [291.35, 290.55], + '552.y': [300.35, 299.55], + '553.y': [309.35, 308.55], + '554.y': [255.35, 254.55], + '555.y': [264.35, 263.55], + '556.y': [273.35, 272.55], + '557.y': [282.35, 281.55], + '558.y': [291.35, 290.55], + '559.y': [300.35, 299.55], + '56.y': [213.35, 212.55], + '560.y': [309.35, 308.55], + '561.y': [255.35, 254.55], + '562.y': [264.35, 263.55], + '563.y': [273.35, 272.55], + '564.y': [282.35, 281.55], + '565.y': [291.35, 290.55], + '566.y': [300.35, 299.55], + '567.y': [309.35, 308.55], + '568.y': [255.35, 254.55], + '569.y': [264.35, 263.55], + '57.y': [159.35, 158.55], + '570.y': [273.35, 272.55], + '571.y': [282.35, 281.55], + '572.y': [291.35, 290.55], + '573.y': [300.35, 299.55], + '574.y': [309.35, 308.55], + '575.y': [255.35, 254.55], + '576.y': [264.35, 263.55], + '577.y': [273.35, 272.55], + '578.y': [282.35, 281.55], + '579.y': [291.35, 290.55], + '58.y': [168.35, 167.55], + '580.y': [300.35, 299.55], + '581.y': [309.35, 308.55], + '582.y': [255.35, 254.55], + '583.y': [264.35, 263.55], + '584.y': [273.35, 272.55], + '585.y': [282.35, 281.55], + '586.y': [291.35, 290.55], + '587.y': [300.35, 299.55], + '588.y': [309.35, 308.55], + '589.y': [255.35, 254.55], + '59.y': [177.35, 176.55], + '590.y': [264.35, 263.55], + '591.y': [273.35, 272.55], + '592.y': [282.35, 281.55], + '593.y': [291.35, 290.55], + '594.y': [300.35, 299.55], + '595.y': [309.35, 308.55], + '596.y': [255.35, 254.55], + '597.y': [264.35, 263.55], + '598.y': [273.35, 272.55], + '599.y': [282.35, 281.55], + '6.y': [204.35, 203.55], + '60.y': [186.35, 185.55], + '600.y': [291.35, 290.55], + '601.y': [300.35, 299.55], + '602.y': [309.35, 308.55], + '603.y': [255.35, 254.55], + '604.y': [264.35, 263.55], + '605.y': [273.35, 272.55], + '606.y': [282.35, 281.55], + '607.y': [291.35, 290.55], + '608.y': [300.35, 299.55], + '609.y': [309.35, 308.55], + '61.y': [195.35, 194.55], + '610.y': [255.35, 254.55], + '611.y': [264.35, 263.55], + '612.y': [273.35, 272.55], + '613.y': [282.35, 281.55], + '614.y': [291.35, 290.55], + '615.y': [300.35, 299.55], + '616.y': [309.35, 308.55], + '617.y': [255.35, 254.55], + '618.y': [264.35, 263.55], + '619.y': [273.35, 272.55], + '62.y': [204.35, 203.55], + '620.y': [282.35, 281.55], + '621.y': [291.35, 290.55], + '622.y': [300.35, 299.55], + '623.y': [309.35, 308.55], + '624.y': [255.35, 254.55], + '625.y': [264.35, 263.55], + '626.y': [273.35, 272.55], + '627.y': [282.35, 281.55], + '628.y': [291.35, 290.55], + '629.y': [300.35, 299.55], + '63.y': [213.35, 212.55], + '630.y': [309.35, 308.55], + '631.y': [255.35, 254.55], + '632.y': [264.35, 263.55], + '633.y': [273.35, 272.55], + '634.y': [282.35, 281.55], + '635.y': [291.35, 290.55], + '636.y': [300.35, 299.55], + '637.y': [309.35, 308.55], + '638.y': [255.35, 254.55], + '639.y': [264.35, 263.55], + '64.y': [159.35, 158.55], + '640.y': [273.35, 272.55], + '641.y': [282.35, 281.55], + '642.y': [291.35, 290.55], + '643.y': [300.35, 299.55], + '644.y': [309.35, 308.55], + '645.y': [255.35, 254.55], + '646.y': [264.35, 263.55], + '647.y': [273.35, 272.55], + '648.y': [282.35, 281.55], + '649.y': [291.35, 290.55], + '65.y': [168.35, 167.55], + '650.y': [300.35, 299.55], + '651.y': [309.35, 308.55], + '652.y': [255.35, 254.55], + '653.y': [264.35, 263.55], + '654.y': [273.35, 272.55], + '655.y': [282.35, 281.55], + '656.y': [291.35, 290.55], + '657.y': [300.35, 299.55], + '658.y': [309.35, 308.55], + '659.y': [255.35, 254.55], + '66.y': [177.35, 176.55], + '660.y': [264.35, 263.55], + '661.y': [273.35, 272.55], + '662.y': [282.35, 281.55], + '663.y': [291.35, 290.55], + '664.y': [300.35, 299.55], + '665.y': [309.35, 308.55], + '666.y': [255.35, 254.55], + '667.y': [264.35, 263.55], + '668.y': [273.35, 272.55], + '669.y': [282.35, 281.55], + '67.y': [186.35, 185.55], + '670.y': [291.35, 290.55], + '671.y': [300.35, 299.55], + '672.y': [309.35, 308.55], + '673.y': [255.35, 254.55], + '674.y': [264.35, 263.55], + '675.y': [273.35, 272.55], + '676.y': [282.35, 281.55], + '677.y': [291.35, 290.55], + '678.y': [300.35, 299.55], + '679.y': [309.35, 308.55], + '68.y': [195.35, 194.55], + '680.y': [255.35, 254.55], + '681.y': [264.35, 263.55], + '682.y': [273.35, 272.55], + '683.y': [282.35, 281.55], + '684.y': [291.35, 290.55], + '685.y': [300.35, 299.55], + '686.y': [309.35, 308.55], + '687.y': [255.35, 254.55], + '688.y': [264.35, 263.55], + '689.y': [273.35, 272.55], + '69.y': [204.35, 203.55], + '690.y': [282.35, 281.55], + '691.y': [291.35, 290.55], + '692.y': [300.35, 299.55], + '693.y': [309.35, 308.55], + '694.y': [255.35, 254.55], + '695.y': [264.35, 263.55], + '696.y': [273.35, 272.55], + '697.y': [282.35, 281.55], + '698.y': [291.35, 290.55], + '699.y': [300.35, 299.55], + '7.y': [213.35, 212.55], + '70.y': [213.35, 212.55], + '700.y': [309.35, 308.55], + '701.y': [255.35, 254.55], + '702.y': [264.35, 263.55], + '703.y': [273.35, 272.55], + '704.y': [282.35, 281.55], + '705.y': [291.35, 290.55], + '706.y': [300.35, 299.55], + '707.y': [309.35, 308.55], + '708.y': [255.35, 254.55], + '709.y': [264.35, 263.55], + '71.y': [159.35, 158.55], + '710.y': [273.35, 272.55], + '711.y': [282.35, 281.55], + '712.y': [291.35, 290.55], + '713.y': [300.35, 299.55], + '714.y': [309.35, 308.55], + '715.y': [255.35, 254.55], + '716.y': [264.35, 263.55], + '717.y': [273.35, 272.55], + '718.y': [282.35, 281.55], + '719.y': [291.35, 290.55], + '72.y': [168.35, 167.55], + '720.y': [300.35, 299.55], + '721.y': [309.35, 308.55], + '722.y': [255.35, 254.55], + '723.y': [264.35, 263.55], + '724.y': [273.35, 272.55], + '725.y': [282.35, 281.55], + '726.y': [291.35, 290.55], + '727.y': [300.35, 299.55], + '728.y': [309.35, 308.55], + '729.y': [255.35, 254.55], + '73.y': [177.35, 176.55], + '730.y': [264.35, 263.55], + '731.y': [153.35, 152.55], + '732.y': [153.35, 152.55], + '733.y': [153.35, 152.55], + '734.y': [153.35, 152.55], + '735.y': [153.35, 152.55], + '736.y': [153.35, 152.55], + '737.y': [153.35, 152.55], + '738.y': [153.35, 152.55], + '739.y': [153.35, 152.55], + '74.y': [186.35, 185.55], + '740.y': [153.35, 152.55], + '741.y': [153.35, 152.55], + '742.y': [153.35, 152.55], + '743.y': [153.35, 152.55], + '744.y': [166.7, 165.9], + '745.y': [184.7, 183.9], + '746.y': [202.7, 201.9], + '747.y': [249.35, 248.55], + '748.y': [249.35, 248.55], + '749.y': [249.35, 248.55], + '75.y': [195.35, 194.55], + '750.y': [249.35, 248.55], + '751.y': [249.35, 248.55], + '752.y': [249.35, 248.55], + '753.y': [249.35, 248.55], + '754.y': [249.35, 248.55], + '755.y': [249.35, 248.55], + '756.y': [249.35, 248.55], + '757.y': [249.35, 248.55], + '758.y': [249.35, 248.55], + '759.y': [249.35, 248.55], + '76.y': [204.35, 203.55], + '760.y': [262.7, 261.9], + '761.y': [280.7, 279.9], + '762.y': [298.7, 297.9], + '77.y': [213.35, 212.55], + '78.y': [159.35, 158.55], + '79.y': [168.35, 167.55], + '8.y': [159.35, 158.55], + '80.y': [177.35, 176.55], + '81.y': [186.35, 185.55], + '82.y': [195.35, 194.55], + '83.y': [204.35, 203.55], + '84.y': [213.35, 212.55], + '85.y': [159.35, 158.55], + '86.y': [168.35, 167.55], + '87.y': [177.35, 176.55], + '88.y': [186.35, 185.55], + '89.y': [195.35, 194.55], + '9.y': [168.35, 167.55], + '90.y': [204.35, 203.55], + '91.y': [213.35, 212.55], + '92.y': [159.35, 158.55], + '93.y': [168.35, 167.55], + '94.y': [177.35, 176.55], + '95.y': [186.35, 185.55], + '96.y': [195.35, 194.55], + '97.y': [204.35, 203.55], + '98.y': [213.35, 212.55], + '99.y': [159.35, 158.55], + }, + legend: { + 'legends.0.bar.y': [331, 329.4], + 'legends.0.bounds.y': [331, 329.4], + }, + }, + style: {}, + }, + '../testing/fixtures-calendar.stories.tsx.calendarTwoYearSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [232.4, 232.2], + }, + chrome: { + bottomAnchorY: [319.6, 319.4], + bottomHeight: [63.4, 63.6], + 'source.maxWidth': [1111, 1180.58], + }, + marks: { + '0.y': [184.4, 184.3], + '1.y': [112.4, 112.3], + '10.y': [136.4, 136.3], + '100.y': [124.4, 124.3], + '101.y': [136.4, 136.3], + '102.y': [148.4, 148.3], + '103.y': [160.4, 160.3], + '104.y': [172.4, 172.3], + '105.y': [184.4, 184.3], + '106.y': [112.4, 112.3], + '107.y': [124.4, 124.3], + '108.y': [136.4, 136.3], + '109.y': [148.4, 148.3], + '11.y': [148.4, 148.3], + '110.y': [160.4, 160.3], + '111.y': [172.4, 172.3], + '112.y': [184.4, 184.3], + '113.y': [112.4, 112.3], + '114.y': [124.4, 124.3], + '115.y': [136.4, 136.3], + '116.y': [148.4, 148.3], + '117.y': [160.4, 160.3], + '118.y': [172.4, 172.3], + '119.y': [184.4, 184.3], + '12.y': [160.4, 160.3], + '120.y': [112.4, 112.3], + '121.y': [124.4, 124.3], + '122.y': [136.4, 136.3], + '123.y': [148.4, 148.3], + '124.y': [160.4, 160.3], + '125.y': [172.4, 172.3], + '126.y': [184.4, 184.3], + '127.y': [112.4, 112.3], + '128.y': [124.4, 124.3], + '129.y': [136.4, 136.3], + '13.y': [172.4, 172.3], + '130.y': [148.4, 148.3], + '131.y': [160.4, 160.3], + '132.y': [172.4, 172.3], + '133.y': [184.4, 184.3], + '134.y': [112.4, 112.3], + '135.y': [124.4, 124.3], + '136.y': [136.4, 136.3], + '137.y': [148.4, 148.3], + '138.y': [160.4, 160.3], + '139.y': [172.4, 172.3], + '14.y': [184.4, 184.3], + '140.y': [184.4, 184.3], + '141.y': [112.4, 112.3], + '142.y': [124.4, 124.3], + '143.y': [136.4, 136.3], + '144.y': [148.4, 148.3], + '145.y': [160.4, 160.3], + '146.y': [172.4, 172.3], + '147.y': [184.4, 184.3], + '148.y': [112.4, 112.3], + '149.y': [124.4, 124.3], + '15.y': [112.4, 112.3], + '150.y': [136.4, 136.3], + '151.y': [148.4, 148.3], + '152.y': [160.4, 160.3], + '153.y': [172.4, 172.3], + '154.y': [184.4, 184.3], + '155.y': [112.4, 112.3], + '156.y': [124.4, 124.3], + '157.y': [136.4, 136.3], + '158.y': [148.4, 148.3], + '159.y': [160.4, 160.3], + '16.y': [124.4, 124.3], + '160.y': [172.4, 172.3], + '161.y': [184.4, 184.3], + '162.y': [112.4, 112.3], + '163.y': [124.4, 124.3], + '164.y': [136.4, 136.3], + '165.y': [148.4, 148.3], + '166.y': [160.4, 160.3], + '167.y': [172.4, 172.3], + '168.y': [184.4, 184.3], + '169.y': [112.4, 112.3], + '17.y': [136.4, 136.3], + '170.y': [124.4, 124.3], + '171.y': [136.4, 136.3], + '172.y': [148.4, 148.3], + '173.y': [160.4, 160.3], + '174.y': [172.4, 172.3], + '175.y': [184.4, 184.3], + '176.y': [112.4, 112.3], + '177.y': [124.4, 124.3], + '178.y': [136.4, 136.3], + '179.y': [148.4, 148.3], + '18.y': [148.4, 148.3], + '180.y': [160.4, 160.3], + '181.y': [172.4, 172.3], + '182.y': [184.4, 184.3], + '183.y': [112.4, 112.3], + '184.y': [124.4, 124.3], + '185.y': [136.4, 136.3], + '186.y': [148.4, 148.3], + '187.y': [160.4, 160.3], + '188.y': [172.4, 172.3], + '189.y': [184.4, 184.3], + '19.y': [160.4, 160.3], + '190.y': [112.4, 112.3], + '191.y': [124.4, 124.3], + '192.y': [136.4, 136.3], + '193.y': [148.4, 148.3], + '194.y': [160.4, 160.3], + '195.y': [172.4, 172.3], + '196.y': [184.4, 184.3], + '197.y': [112.4, 112.3], + '198.y': [124.4, 124.3], + '199.y': [136.4, 136.3], + '2.y': [124.4, 124.3], + '20.y': [172.4, 172.3], + '200.y': [148.4, 148.3], + '201.y': [160.4, 160.3], + '202.y': [172.4, 172.3], + '203.y': [184.4, 184.3], + '204.y': [112.4, 112.3], + '205.y': [124.4, 124.3], + '206.y': [136.4, 136.3], + '207.y': [148.4, 148.3], + '208.y': [160.4, 160.3], + '209.y': [172.4, 172.3], + '21.y': [184.4, 184.3], + '210.y': [184.4, 184.3], + '211.y': [112.4, 112.3], + '212.y': [124.4, 124.3], + '213.y': [136.4, 136.3], + '214.y': [148.4, 148.3], + '215.y': [160.4, 160.3], + '216.y': [172.4, 172.3], + '217.y': [184.4, 184.3], + '218.y': [112.4, 112.3], + '219.y': [124.4, 124.3], + '22.y': [112.4, 112.3], + '220.y': [136.4, 136.3], + '221.y': [148.4, 148.3], + '222.y': [160.4, 160.3], + '223.y': [172.4, 172.3], + '224.y': [184.4, 184.3], + '225.y': [112.4, 112.3], + '226.y': [124.4, 124.3], + '227.y': [136.4, 136.3], + '228.y': [148.4, 148.3], + '229.y': [160.4, 160.3], + '23.y': [124.4, 124.3], + '230.y': [172.4, 172.3], + '231.y': [184.4, 184.3], + '232.y': [112.4, 112.3], + '233.y': [124.4, 124.3], + '234.y': [136.4, 136.3], + '235.y': [148.4, 148.3], + '236.y': [160.4, 160.3], + '237.y': [172.4, 172.3], + '238.y': [184.4, 184.3], + '239.y': [112.4, 112.3], + '24.y': [136.4, 136.3], + '240.y': [124.4, 124.3], + '241.y': [136.4, 136.3], + '242.y': [148.4, 148.3], + '243.y': [160.4, 160.3], + '244.y': [172.4, 172.3], + '245.y': [184.4, 184.3], + '246.y': [112.4, 112.3], + '247.y': [124.4, 124.3], + '248.y': [136.4, 136.3], + '249.y': [148.4, 148.3], + '25.y': [148.4, 148.3], + '250.y': [160.4, 160.3], + '251.y': [172.4, 172.3], + '252.y': [184.4, 184.3], + '253.y': [112.4, 112.3], + '254.y': [124.4, 124.3], + '255.y': [136.4, 136.3], + '256.y': [148.4, 148.3], + '257.y': [160.4, 160.3], + '258.y': [172.4, 172.3], + '259.y': [184.4, 184.3], + '26.y': [160.4, 160.3], + '260.y': [112.4, 112.3], + '261.y': [124.4, 124.3], + '262.y': [136.4, 136.3], + '263.y': [148.4, 148.3], + '264.y': [160.4, 160.3], + '265.y': [172.4, 172.3], + '266.y': [184.4, 184.3], + '267.y': [112.4, 112.3], + '268.y': [124.4, 124.3], + '269.y': [136.4, 136.3], + '27.y': [172.4, 172.3], + '270.y': [148.4, 148.3], + '271.y': [160.4, 160.3], + '272.y': [172.4, 172.3], + '273.y': [184.4, 184.3], + '274.y': [112.4, 112.3], + '275.y': [124.4, 124.3], + '276.y': [136.4, 136.3], + '277.y': [148.4, 148.3], + '278.y': [160.4, 160.3], + '279.y': [172.4, 172.3], + '28.y': [184.4, 184.3], + '280.y': [184.4, 184.3], + '281.y': [112.4, 112.3], + '282.y': [124.4, 124.3], + '283.y': [136.4, 136.3], + '284.y': [148.4, 148.3], + '285.y': [160.4, 160.3], + '286.y': [172.4, 172.3], + '287.y': [184.4, 184.3], + '288.y': [112.4, 112.3], + '289.y': [124.4, 124.3], + '29.y': [112.4, 112.3], + '290.y': [136.4, 136.3], + '291.y': [148.4, 148.3], + '292.y': [160.4, 160.3], + '293.y': [172.4, 172.3], + '294.y': [184.4, 184.3], + '295.y': [112.4, 112.3], + '296.y': [124.4, 124.3], + '297.y': [136.4, 136.3], + '298.y': [148.4, 148.3], + '299.y': [160.4, 160.3], + '3.y': [136.4, 136.3], + '30.y': [124.4, 124.3], + '300.y': [172.4, 172.3], + '301.y': [184.4, 184.3], + '302.y': [112.4, 112.3], + '303.y': [124.4, 124.3], + '304.y': [136.4, 136.3], + '305.y': [148.4, 148.3], + '306.y': [160.4, 160.3], + '307.y': [172.4, 172.3], + '308.y': [184.4, 184.3], + '309.y': [112.4, 112.3], + '31.y': [136.4, 136.3], + '310.y': [124.4, 124.3], + '311.y': [136.4, 136.3], + '312.y': [148.4, 148.3], + '313.y': [160.4, 160.3], + '314.y': [172.4, 172.3], + '315.y': [184.4, 184.3], + '316.y': [112.4, 112.3], + '317.y': [124.4, 124.3], + '318.y': [136.4, 136.3], + '319.y': [148.4, 148.3], + '32.y': [148.4, 148.3], + '320.y': [160.4, 160.3], + '321.y': [172.4, 172.3], + '322.y': [184.4, 184.3], + '323.y': [112.4, 112.3], + '324.y': [124.4, 124.3], + '325.y': [136.4, 136.3], + '326.y': [148.4, 148.3], + '327.y': [160.4, 160.3], + '328.y': [172.4, 172.3], + '329.y': [184.4, 184.3], + '33.y': [160.4, 160.3], + '330.y': [112.4, 112.3], + '331.y': [124.4, 124.3], + '332.y': [136.4, 136.3], + '333.y': [148.4, 148.3], + '334.y': [160.4, 160.3], + '335.y': [172.4, 172.3], + '336.y': [184.4, 184.3], + '337.y': [112.4, 112.3], + '338.y': [124.4, 124.3], + '339.y': [136.4, 136.3], + '34.y': [172.4, 172.3], + '340.y': [148.4, 148.3], + '341.y': [160.4, 160.3], + '342.y': [172.4, 172.3], + '343.y': [184.4, 184.3], + '344.y': [112.4, 112.3], + '345.y': [124.4, 124.3], + '346.y': [136.4, 136.3], + '347.y': [148.4, 148.3], + '348.y': [160.4, 160.3], + '349.y': [172.4, 172.3], + '35.y': [184.4, 184.3], + '350.y': [184.4, 184.3], + '351.y': [112.4, 112.3], + '352.y': [124.4, 124.3], + '353.y': [136.4, 136.3], + '354.y': [148.4, 148.3], + '355.y': [160.4, 160.3], + '356.y': [172.4, 172.3], + '357.y': [184.4, 184.3], + '358.y': [112.4, 112.3], + '359.y': [124.4, 124.3], + '36.y': [112.4, 112.3], + '360.y': [136.4, 136.3], + '361.y': [148.4, 148.3], + '362.y': [160.4, 160.3], + '363.y': [172.4, 172.3], + '364.y': [184.4, 184.3], + '365.y': [229.4, 229.3], + '366.y': [241.4, 241.3], + '367.y': [253.4, 253.3], + '368.y': [265.4, 265.3], + '369.y': [277.4, 277.3], + '37.y': [124.4, 124.3], + '370.y': [289.4, 289.3], + '371.y': [301.4, 301.3], + '372.y': [229.4, 229.3], + '373.y': [241.4, 241.3], + '374.y': [253.4, 253.3], + '375.y': [265.4, 265.3], + '376.y': [277.4, 277.3], + '377.y': [289.4, 289.3], + '378.y': [301.4, 301.3], + '379.y': [229.4, 229.3], + '38.y': [136.4, 136.3], + '380.y': [241.4, 241.3], + '381.y': [253.4, 253.3], + '382.y': [265.4, 265.3], + '383.y': [277.4, 277.3], + '384.y': [289.4, 289.3], + '385.y': [301.4, 301.3], + '386.y': [229.4, 229.3], + '387.y': [241.4, 241.3], + '388.y': [253.4, 253.3], + '389.y': [265.4, 265.3], + '39.y': [148.4, 148.3], + '390.y': [277.4, 277.3], + '391.y': [289.4, 289.3], + '392.y': [301.4, 301.3], + '393.y': [229.4, 229.3], + '394.y': [241.4, 241.3], + '395.y': [253.4, 253.3], + '396.y': [265.4, 265.3], + '397.y': [277.4, 277.3], + '398.y': [289.4, 289.3], + '399.y': [301.4, 301.3], + '4.y': [148.4, 148.3], + '40.y': [160.4, 160.3], + '400.y': [229.4, 229.3], + '401.y': [241.4, 241.3], + '402.y': [253.4, 253.3], + '403.y': [265.4, 265.3], + '404.y': [277.4, 277.3], + '405.y': [289.4, 289.3], + '406.y': [301.4, 301.3], + '407.y': [229.4, 229.3], + '408.y': [241.4, 241.3], + '409.y': [253.4, 253.3], + '41.y': [172.4, 172.3], + '410.y': [265.4, 265.3], + '411.y': [277.4, 277.3], + '412.y': [289.4, 289.3], + '413.y': [301.4, 301.3], + '414.y': [229.4, 229.3], + '415.y': [241.4, 241.3], + '416.y': [253.4, 253.3], + '417.y': [265.4, 265.3], + '418.y': [277.4, 277.3], + '419.y': [289.4, 289.3], + '42.y': [184.4, 184.3], + '420.y': [301.4, 301.3], + '421.y': [229.4, 229.3], + '422.y': [241.4, 241.3], + '423.y': [253.4, 253.3], + '424.y': [265.4, 265.3], + '425.y': [277.4, 277.3], + '426.y': [289.4, 289.3], + '427.y': [301.4, 301.3], + '428.y': [229.4, 229.3], + '429.y': [241.4, 241.3], + '43.y': [112.4, 112.3], + '430.y': [253.4, 253.3], + '431.y': [265.4, 265.3], + '432.y': [277.4, 277.3], + '433.y': [289.4, 289.3], + '434.y': [301.4, 301.3], + '435.y': [229.4, 229.3], + '436.y': [241.4, 241.3], + '437.y': [253.4, 253.3], + '438.y': [265.4, 265.3], + '439.y': [277.4, 277.3], + '44.y': [124.4, 124.3], + '440.y': [289.4, 289.3], + '441.y': [301.4, 301.3], + '442.y': [229.4, 229.3], + '443.y': [241.4, 241.3], + '444.y': [253.4, 253.3], + '445.y': [265.4, 265.3], + '446.y': [277.4, 277.3], + '447.y': [289.4, 289.3], + '448.y': [301.4, 301.3], + '449.y': [229.4, 229.3], + '45.y': [136.4, 136.3], + '450.y': [241.4, 241.3], + '451.y': [253.4, 253.3], + '452.y': [265.4, 265.3], + '453.y': [277.4, 277.3], + '454.y': [289.4, 289.3], + '455.y': [301.4, 301.3], + '456.y': [229.4, 229.3], + '457.y': [241.4, 241.3], + '458.y': [253.4, 253.3], + '459.y': [265.4, 265.3], + '46.y': [148.4, 148.3], + '460.y': [277.4, 277.3], + '461.y': [289.4, 289.3], + '462.y': [301.4, 301.3], + '463.y': [229.4, 229.3], + '464.y': [241.4, 241.3], + '465.y': [253.4, 253.3], + '466.y': [265.4, 265.3], + '467.y': [277.4, 277.3], + '468.y': [289.4, 289.3], + '469.y': [301.4, 301.3], + '47.y': [160.4, 160.3], + '470.y': [229.4, 229.3], + '471.y': [241.4, 241.3], + '472.y': [253.4, 253.3], + '473.y': [265.4, 265.3], + '474.y': [277.4, 277.3], + '475.y': [289.4, 289.3], + '476.y': [301.4, 301.3], + '477.y': [229.4, 229.3], + '478.y': [241.4, 241.3], + '479.y': [253.4, 253.3], + '48.y': [172.4, 172.3], + '480.y': [265.4, 265.3], + '481.y': [277.4, 277.3], + '482.y': [289.4, 289.3], + '483.y': [301.4, 301.3], + '484.y': [229.4, 229.3], + '485.y': [241.4, 241.3], + '486.y': [253.4, 253.3], + '487.y': [265.4, 265.3], + '488.y': [277.4, 277.3], + '489.y': [289.4, 289.3], + '49.y': [184.4, 184.3], + '490.y': [301.4, 301.3], + '491.y': [229.4, 229.3], + '492.y': [241.4, 241.3], + '493.y': [253.4, 253.3], + '494.y': [265.4, 265.3], + '495.y': [277.4, 277.3], + '496.y': [289.4, 289.3], + '497.y': [301.4, 301.3], + '498.y': [229.4, 229.3], + '499.y': [241.4, 241.3], + '5.y': [160.4, 160.3], + '50.y': [112.4, 112.3], + '500.y': [253.4, 253.3], + '501.y': [265.4, 265.3], + '502.y': [277.4, 277.3], + '503.y': [289.4, 289.3], + '504.y': [301.4, 301.3], + '505.y': [229.4, 229.3], + '506.y': [241.4, 241.3], + '507.y': [253.4, 253.3], + '508.y': [265.4, 265.3], + '509.y': [277.4, 277.3], + '51.y': [124.4, 124.3], + '510.y': [289.4, 289.3], + '511.y': [301.4, 301.3], + '512.y': [229.4, 229.3], + '513.y': [241.4, 241.3], + '514.y': [253.4, 253.3], + '515.y': [265.4, 265.3], + '516.y': [277.4, 277.3], + '517.y': [289.4, 289.3], + '518.y': [301.4, 301.3], + '519.y': [229.4, 229.3], + '52.y': [136.4, 136.3], + '520.y': [241.4, 241.3], + '521.y': [253.4, 253.3], + '522.y': [265.4, 265.3], + '523.y': [277.4, 277.3], + '524.y': [289.4, 289.3], + '525.y': [301.4, 301.3], + '526.y': [229.4, 229.3], + '527.y': [241.4, 241.3], + '528.y': [253.4, 253.3], + '529.y': [265.4, 265.3], + '53.y': [148.4, 148.3], + '530.y': [277.4, 277.3], + '531.y': [289.4, 289.3], + '532.y': [301.4, 301.3], + '533.y': [229.4, 229.3], + '534.y': [241.4, 241.3], + '535.y': [253.4, 253.3], + '536.y': [265.4, 265.3], + '537.y': [277.4, 277.3], + '538.y': [289.4, 289.3], + '539.y': [301.4, 301.3], + '54.y': [160.4, 160.3], + '540.y': [229.4, 229.3], + '541.y': [241.4, 241.3], + '542.y': [253.4, 253.3], + '543.y': [265.4, 265.3], + '544.y': [277.4, 277.3], + '545.y': [289.4, 289.3], + '546.y': [301.4, 301.3], + '547.y': [229.4, 229.3], + '548.y': [241.4, 241.3], + '549.y': [253.4, 253.3], + '55.y': [172.4, 172.3], + '550.y': [265.4, 265.3], + '551.y': [277.4, 277.3], + '552.y': [289.4, 289.3], + '553.y': [301.4, 301.3], + '554.y': [229.4, 229.3], + '555.y': [241.4, 241.3], + '556.y': [253.4, 253.3], + '557.y': [265.4, 265.3], + '558.y': [277.4, 277.3], + '559.y': [289.4, 289.3], + '56.y': [184.4, 184.3], + '560.y': [301.4, 301.3], + '561.y': [229.4, 229.3], + '562.y': [241.4, 241.3], + '563.y': [253.4, 253.3], + '564.y': [265.4, 265.3], + '565.y': [277.4, 277.3], + '566.y': [289.4, 289.3], + '567.y': [301.4, 301.3], + '568.y': [229.4, 229.3], + '569.y': [241.4, 241.3], + '57.y': [112.4, 112.3], + '570.y': [253.4, 253.3], + '571.y': [265.4, 265.3], + '572.y': [277.4, 277.3], + '573.y': [289.4, 289.3], + '574.y': [301.4, 301.3], + '575.y': [229.4, 229.3], + '576.y': [241.4, 241.3], + '577.y': [253.4, 253.3], + '578.y': [265.4, 265.3], + '579.y': [277.4, 277.3], + '58.y': [124.4, 124.3], + '580.y': [289.4, 289.3], + '581.y': [301.4, 301.3], + '582.y': [229.4, 229.3], + '583.y': [241.4, 241.3], + '584.y': [253.4, 253.3], + '585.y': [265.4, 265.3], + '586.y': [277.4, 277.3], + '587.y': [289.4, 289.3], + '588.y': [301.4, 301.3], + '589.y': [229.4, 229.3], + '59.y': [136.4, 136.3], + '590.y': [241.4, 241.3], + '591.y': [253.4, 253.3], + '592.y': [265.4, 265.3], + '593.y': [277.4, 277.3], + '594.y': [289.4, 289.3], + '595.y': [301.4, 301.3], + '596.y': [229.4, 229.3], + '597.y': [241.4, 241.3], + '598.y': [253.4, 253.3], + '599.y': [265.4, 265.3], + '6.y': [172.4, 172.3], + '60.y': [148.4, 148.3], + '600.y': [277.4, 277.3], + '601.y': [289.4, 289.3], + '602.y': [301.4, 301.3], + '603.y': [229.4, 229.3], + '604.y': [241.4, 241.3], + '605.y': [253.4, 253.3], + '606.y': [265.4, 265.3], + '607.y': [277.4, 277.3], + '608.y': [289.4, 289.3], + '609.y': [301.4, 301.3], + '61.y': [160.4, 160.3], + '610.y': [229.4, 229.3], + '611.y': [241.4, 241.3], + '612.y': [253.4, 253.3], + '613.y': [265.4, 265.3], + '614.y': [277.4, 277.3], + '615.y': [289.4, 289.3], + '616.y': [301.4, 301.3], + '617.y': [229.4, 229.3], + '618.y': [241.4, 241.3], + '619.y': [253.4, 253.3], + '62.y': [172.4, 172.3], + '620.y': [265.4, 265.3], + '621.y': [277.4, 277.3], + '622.y': [289.4, 289.3], + '623.y': [301.4, 301.3], + '624.y': [229.4, 229.3], + '625.y': [241.4, 241.3], + '626.y': [253.4, 253.3], + '627.y': [265.4, 265.3], + '628.y': [277.4, 277.3], + '629.y': [289.4, 289.3], + '63.y': [184.4, 184.3], + '630.y': [301.4, 301.3], + '631.y': [229.4, 229.3], + '632.y': [241.4, 241.3], + '633.y': [253.4, 253.3], + '634.y': [265.4, 265.3], + '635.y': [277.4, 277.3], + '636.y': [289.4, 289.3], + '637.y': [301.4, 301.3], + '638.y': [229.4, 229.3], + '639.y': [241.4, 241.3], + '64.y': [112.4, 112.3], + '640.y': [253.4, 253.3], + '641.y': [265.4, 265.3], + '642.y': [277.4, 277.3], + '643.y': [289.4, 289.3], + '644.y': [301.4, 301.3], + '645.y': [229.4, 229.3], + '646.y': [241.4, 241.3], + '647.y': [253.4, 253.3], + '648.y': [265.4, 265.3], + '649.y': [277.4, 277.3], + '65.y': [124.4, 124.3], + '650.y': [289.4, 289.3], + '651.y': [301.4, 301.3], + '652.y': [229.4, 229.3], + '653.y': [241.4, 241.3], + '654.y': [253.4, 253.3], + '655.y': [265.4, 265.3], + '656.y': [277.4, 277.3], + '657.y': [289.4, 289.3], + '658.y': [301.4, 301.3], + '659.y': [229.4, 229.3], + '66.y': [136.4, 136.3], + '660.y': [241.4, 241.3], + '661.y': [253.4, 253.3], + '662.y': [265.4, 265.3], + '663.y': [277.4, 277.3], + '664.y': [289.4, 289.3], + '665.y': [301.4, 301.3], + '666.y': [229.4, 229.3], + '667.y': [241.4, 241.3], + '668.y': [253.4, 253.3], + '669.y': [265.4, 265.3], + '67.y': [148.4, 148.3], + '670.y': [277.4, 277.3], + '671.y': [289.4, 289.3], + '672.y': [301.4, 301.3], + '673.y': [229.4, 229.3], + '674.y': [241.4, 241.3], + '675.y': [253.4, 253.3], + '676.y': [265.4, 265.3], + '677.y': [277.4, 277.3], + '678.y': [289.4, 289.3], + '679.y': [301.4, 301.3], + '68.y': [160.4, 160.3], + '680.y': [229.4, 229.3], + '681.y': [241.4, 241.3], + '682.y': [253.4, 253.3], + '683.y': [265.4, 265.3], + '684.y': [277.4, 277.3], + '685.y': [289.4, 289.3], + '686.y': [301.4, 301.3], + '687.y': [229.4, 229.3], + '688.y': [241.4, 241.3], + '689.y': [253.4, 253.3], + '69.y': [172.4, 172.3], + '690.y': [265.4, 265.3], + '691.y': [277.4, 277.3], + '692.y': [289.4, 289.3], + '693.y': [301.4, 301.3], + '694.y': [229.4, 229.3], + '695.y': [241.4, 241.3], + '696.y': [253.4, 253.3], + '697.y': [265.4, 265.3], + '698.y': [277.4, 277.3], + '699.y': [289.4, 289.3], + '7.y': [184.4, 184.3], + '70.y': [184.4, 184.3], + '700.y': [301.4, 301.3], + '701.y': [229.4, 229.3], + '702.y': [241.4, 241.3], + '703.y': [253.4, 253.3], + '704.y': [265.4, 265.3], + '705.y': [277.4, 277.3], + '706.y': [289.4, 289.3], + '707.y': [301.4, 301.3], + '708.y': [229.4, 229.3], + '709.y': [241.4, 241.3], + '71.y': [112.4, 112.3], + '710.y': [253.4, 253.3], + '711.y': [265.4, 265.3], + '712.y': [277.4, 277.3], + '713.y': [289.4, 289.3], + '714.y': [301.4, 301.3], + '715.y': [229.4, 229.3], + '716.y': [241.4, 241.3], + '717.y': [253.4, 253.3], + '718.y': [265.4, 265.3], + '719.y': [277.4, 277.3], + '72.y': [124.4, 124.3], + '720.y': [289.4, 289.3], + '721.y': [301.4, 301.3], + '722.y': [229.4, 229.3], + '723.y': [241.4, 241.3], + '724.y': [253.4, 253.3], + '725.y': [265.4, 265.3], + '726.y': [277.4, 277.3], + '727.y': [289.4, 289.3], + '728.y': [301.4, 301.3], + '729.y': [229.4, 229.3], + '73.y': [136.4, 136.3], + '730.y': [241.4, 241.3], + '731.y': [106.4, 106.3], + '732.y': [106.4, 106.3], + '733.y': [106.4, 106.3], + '734.y': [106.4, 106.3], + '735.y': [106.4, 106.3], + '736.y': [106.4, 106.3], + '737.y': [106.4, 106.3], + '738.y': [106.4, 106.3], + '739.y': [106.4, 106.3], + '74.y': [148.4, 148.3], + '740.y': [106.4, 106.3], + '741.y': [106.4, 106.3], + '742.y': [106.4, 106.3], + '743.y': [106.4, 106.3], + '744.y': [121.25, 121.15], + '745.y': [145.25, 145.15], + '746.y': [169.25, 169.15], + '747.y': [223.4, 223.3], + '748.y': [223.4, 223.3], + '749.y': [223.4, 223.3], + '75.y': [160.4, 160.3], + '750.y': [223.4, 223.3], + '751.y': [223.4, 223.3], + '752.y': [223.4, 223.3], + '753.y': [223.4, 223.3], + '754.y': [223.4, 223.3], + '755.y': [223.4, 223.3], + '756.y': [223.4, 223.3], + '757.y': [223.4, 223.3], + '758.y': [223.4, 223.3], + '759.y': [223.4, 223.3], + '76.y': [172.4, 172.3], + '760.y': [238.25, 238.15], + '761.y': [262.25, 262.15], + '762.y': [286.25, 286.15], + '77.y': [184.4, 184.3], + '78.y': [112.4, 112.3], + '79.y': [124.4, 124.3], + '8.y': [112.4, 112.3], + '80.y': [136.4, 136.3], + '81.y': [148.4, 148.3], + '82.y': [160.4, 160.3], + '83.y': [172.4, 172.3], + '84.y': [184.4, 184.3], + '85.y': [112.4, 112.3], + '86.y': [124.4, 124.3], + '87.y': [136.4, 136.3], + '88.y': [148.4, 148.3], + '89.y': [160.4, 160.3], + '9.y': [124.4, 124.3], + '90.y': [172.4, 172.3], + '91.y': [184.4, 184.3], + '92.y': [112.4, 112.3], + '93.y': [124.4, 124.3], + '94.y': [136.4, 136.3], + '95.y': [148.4, 148.3], + '96.y': [160.4, 160.3], + '97.y': [172.4, 172.3], + '98.y': [184.4, 184.3], + '99.y': [112.4, 112.3], + }, + legend: { + 'legends.0.bar.y': [327.6, 327.4], + 'legends.0.bounds.y': [327.6, 327.4], + }, + }, + style: {}, + }, + '../testing/fixtures-calendar.stories.tsx.calendarCompactSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-calendar.stories.tsx.calendarCompactSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-color-legend.stories.tsx.hotDaysSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-color-legend.stories.tsx.hotDaysSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-color-legend.stories.tsx.aqiSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-color-legend.stories.tsx.aqiSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-color-legend.stories.tsx.tradeBalanceSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-color-legend.stories.tsx.tradeBalanceSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-distribution.stories.tsx.histogramSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-distribution.stories.tsx.histogramSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-distribution.stories.tsx.densitySpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-distribution.stories.tsx.densitySpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-donuts.stories.tsx.donutSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [221.7, 234.1], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + marks: { + '0.cy': [221.15, 227.35], + '0.innerRadius': [56.53, 59.7], + '0.outerRadius': [94.22, 99.49], + '1.cy': [221.15, 227.35], + '1.innerRadius': [56.53, 59.7], + '1.outerRadius': [94.22, 99.49], + '2.cy': [221.15, 227.35], + '2.innerRadius': [56.53, 59.7], + '2.outerRadius': [94.22, 99.49], + '3.cy': [221.15, 227.35], + '3.innerRadius': [56.53, 59.7], + '3.outerRadius': [94.22, 99.49], + '4.cy': [221.15, 227.35], + '4.innerRadius': [56.53, 59.7], + '4.outerRadius': [94.22, 99.49], + '5.cy': [221.15, 227.35], + '5.innerRadius': [56.53, 59.7], + '5.outerRadius': [94.22, 99.49], + '6.cy': [221.15, 227.35], + '6.innerRadius': [56.53, 59.7], + '6.outerRadius': [94.22, 99.49], + }, + labels: { + '0.label.x': [265, 268.48], + '0.label.y': [134.66, 136.89], + '1.label.x': [286.04, 290.56], + '1.label.y': [269.27, 278.18], + '2.label.x': [106.65, 105.89], + '2.label.y': [319.65, 331.07], + '3.label.x': [41.09, 36.43], + '3.label.y': [263.93, 272.58], + '4.label.x': [23.26, 18.14], + '4.label.y': [189.19, 194.14], + '5.label.x': [71.95, 68.26], + '5.label.y': [138.75, 141.18], + '6.label.x': [116.6, 115.28], + '6.label.y': [111.72, 112.82], + }, + }, + style: {}, + }, + '../testing/fixtures-donuts.stories.tsx.donutSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-dual-axis.stories.tsx.dualAxisSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-dual-axis.stories.tsx.dualAxisSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-dual-axis.stories.tsx.scatterTrendlineSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-dual-axis.stories.tsx.scatterTrendlineSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.gdpLineSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [132.25, 144.65], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [306, 318.4], + 'x.start.y': [306, 318.4], + 'y.end.y': [306, 318.4], + 'y.tick.0.position': [289.47, 300.32], + 'y.tick.1.position': [248.14, 255.12], + 'y.tick.2.position': [206.81, 209.91], + 'y.titlePosition.y': [239.88, 246.08], + }, + marks: { + '0.height': [76.87, 84.08], + '0.y': [199.37, 201.78], + '1.height': [96.71, 105.78], + '1.y': [204.33, 207.2], + '2.height': [123.16, 134.71], + '2.y': [181.19, 181.89], + }, + annotations: { + 'a0.rect.height': [132.25, 144.65], + 'a1.line.end.y': [248.14, 255.12], + 'a1.line.start.y': [248.14, 255.12], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.gdpLineSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.compactGdpSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [185.15, 197.55], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [306, 318.4], + 'x.start.y': [306, 318.4], + 'y.end.y': [306, 318.4], + 'y.tick.0.position': [282.86, 293.71], + 'y.tick.1.position': [225, 231.97], + 'y.tick.2.position': [167.14, 170.24], + 'y.titlePosition.y': [213.43, 219.63], + }, + marks: { + '0.height': [107.62, 114.83], + '0.y': [156.72, 159.13], + '1.height': [135.39, 144.46], + '1.y': [163.67, 166.53], + '2.height': [172.42, 183.97], + '2.y': [131.26, 131.96], + }, + annotations: { + 'a0.rect.height': [185.15, 197.55], + 'a1.line.end.y': [225, 231.97], + 'a1.line.start.y': [225, 231.97], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.compactGdpSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.fiveSeriesSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.multiSeriesAreaOverlapSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [87.9, 101.9], + }, + chrome: { + bottomAnchorY: [276, 290], + bottomHeight: [108, 94], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [78, 64], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [250, 264], + 'x.start.y': [250, 264], + 'y.end.y': [250, 264], + 'y.tick.0.position': [250, 264], + 'y.tick.1.position': [232.42, 243.62], + 'y.tick.2.position': [214.84, 223.24], + 'y.tick.3.position': [197.26, 202.86], + 'y.tick.4.position': [179.68, 182.48], + }, + marks: { + '0.height': [73.84, 85.6], + '0.y': [176.16, 178.4], + '1.height': [45.71, 52.99], + '1.y': [204.29, 211.01], + '2.height': [40.43, 46.87], + '2.y': [209.57, 217.13], + '3.height': [52.74, 61.14], + '3.y': [197.26, 202.86], + '4.height': [31.64, 36.68], + '4.y': [176.16, 178.4], + '5.height': [7.03, 8.15], + '5.y': [204.29, 211.01], + '6.height': [1.76, 2.04], + '6.y': [209.57, 217.13], + '7.height': [42.19, 48.91], + '7.y': [197.26, 202.86], + }, + annotations: { + 'a0.connector.from.x': [324.5, 323.26], + 'a0.connector.from.y': [181.86, 181.95], + 'a0.connector.to.x': [331.4, 331.72], + 'a0.connector.to.y': [198.87, 205.75], + 'a0.dot.y': [206.05, 213.05], + }, + legend: { + 'legends.0.bounds.y': [276, 290], + 'legends.0.entry.0.y': [276, 290], + 'legends.0.entry.1.y': [276, 290], + 'legends.0.entry.2.y': [276, 290], + 'legends.0.entry.3.y': [292, 306], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.multiSeriesAreaOverlapSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.multiSeriesAreaStackedSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.multiSeriesAreaStackedSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.editorialSingleLineDarkSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'brand.maxWidth': [130, 74.2], + 'byline.maxWidth': [223, 271.8], + 'source.maxWidth': [223, 271.8], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.editorialSingleLineDarkSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'brand.maxWidth': [130, 81.62], + 'byline.maxWidth': [1111, 1152.38], + 'source.maxWidth': [1111, 1152.38], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.lineSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-lines.stories.tsx.lineSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.usBubblesSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [235, 304.58], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.usBubblesSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.worldDivergingSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [235, 304.58], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.worldDivergingSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.usStatesCategoricalSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [235, 304.58], + }, + }, + style: {}, + }, + '../testing/fixtures-maps.stories.tsx.usStatesCategoricalSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-misc.stories.tsx.energyFlowSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../testing/fixtures-misc.stories.tsx.energyFlowSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-misc.stories.tsx.chromeSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-misc.stories.tsx.chromeSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-misc.stories.tsx.fullChromeSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [223, 292.58], + 'footer.maxWidth': [223, 292.58], + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-misc.stories.tsx.fullChromeSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'footer.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-misc.stories.tsx.rotatedSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-misc.stories.tsx.rotatedSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-parliament.stories.tsx.usHouseSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-parliament.stories.tsx.usHouseSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-parliament.stories.tsx.euSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-parliament.stories.tsx.euSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-parliament.stories.tsx.electionDonutSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-parliament.stories.tsx.electionDonutSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-parliament.stories.tsx.resultsBarSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-parliament.stories.tsx.resultsBarSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-ranges.stories.tsx.rangeDumbbellSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-ranges.stories.tsx.rangeDumbbellSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-ranges.stories.tsx.rangeArrowSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [156.3, 168.7], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [284, 296.4], + 'x.start.y': [284, 296.4], + 'x.titlePosition.y': [319, 331.4], + 'y.end.y': [284, 296.4], + 'y.tick.0.position': [268.37, 279.53], + 'y.tick.1.position': [243.36, 252.54], + 'y.tick.2.position': [218.35, 225.55], + 'y.tick.3.position': [193.35, 198.55], + 'y.tick.4.position': [168.34, 171.56], + 'y.tick.5.position': [143.33, 144.57], + }, + marks: { + '0.y1': [193.35, 198.55], + '0.y2': [193.35, 198.55], + '1.y1': [189.35, 194.55], + '1.y2': [193.35, 198.55], + '10.y1': [222.35, 229.55], + '10.y2': [218.35, 225.55], + '11.y1': [214.35, 221.55], + '11.y2': [218.35, 225.55], + '12.y1': [268.37, 279.53], + '12.y2': [268.37, 279.53], + '13.y1': [264.37, 275.53], + '13.y2': [268.37, 279.53], + '14.y1': [272.37, 283.53], + '14.y2': [268.37, 279.53], + '15.y1': [243.36, 252.54], + '15.y2': [243.36, 252.54], + '16.y1': [247.36, 256.54], + '16.y2': [243.36, 252.54], + '17.y1': [239.36, 248.54], + '17.y2': [243.36, 252.54], + '2.y1': [197.35, 202.55], + '2.y2': [193.35, 198.55], + '3.y1': [143.33, 144.57], + '3.y2': [143.33, 144.57], + '4.y1': [147.33, 148.57], + '4.y2': [143.33, 144.57], + '5.y1': [139.33, 140.57], + '5.y2': [143.33, 144.57], + '6.y1': [168.34, 171.56], + '6.y2': [168.34, 171.56], + '7.y1': [164.34, 167.56], + '7.y2': [168.34, 171.56], + '8.y1': [172.34, 175.56], + '8.y2': [168.34, 171.56], + '9.y1': [218.35, 225.55], + '9.y2': [218.35, 225.55], + }, + }, + style: {}, + }, + '../testing/fixtures-ranges.stories.tsx.rangeArrowSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-ranges.stories.tsx.rangeBarSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [163.68, 176.08], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [291.38, 303.78], + 'x.start.y': [291.38, 303.78], + 'y.end.y': [291.38, 303.78], + 'y.tick.0.position': [291.38, 303.78], + 'y.tick.1.position': [240.23, 248.76], + 'y.tick.2.position': [189.08, 193.73], + 'y.tick.3.position': [137.93, 138.71], + 'y.titlePosition.y': [209.54, 215.74], + }, + marks: { + '0.height': [29.67, 31.91], + '0.y': [243.81, 252.61], + '1.height': [42.45, 45.67], + '1.y': [244.32, 253.16], + '10.height': [37.34, 40.17], + '10.y': [231.02, 238.85], + '11.height': [28.64, 30.81], + '11.y': [241.25, 249.86], + '2.height': [38.87, 41.82], + '2.y': [236.14, 244.35], + '3.height': [49.1, 52.82], + '3.y': [194.2, 199.23], + '4.height': [51.66, 55.58], + '4.y': [178.34, 182.18], + '5.height': [43.99, 47.32], + '5.y': [161.46, 164.02], + '6.height': [41.43, 44.57], + '6.y': [136.91, 137.6], + '7.height': [37.85, 40.72], + '7.y': [150.21, 151.91], + '8.height': [35.81, 38.52], + '8.y': [167.09, 170.07], + '9.height': [35.29, 37.97], + '9.y': [192.66, 197.58], + }, + }, + style: {}, + }, + '../testing/fixtures-ranges.stories.tsx.rangeBarSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-ranking.stories.tsx.slopeMarketShareSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [178.7, 191.1], + }, + chrome: { + bottomAnchorY: [332, 344.4], + bottomHeight: [52, 39.6], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [306, 318.4], + 'x.start.y': [306, 318.4], + }, + marks: { + '0.height': [25.81, 27.6], + '0.y': [131.27, 131.55], + '1.height': [132.04, 141.2], + '1.y': [170.98, 174.01], + '2.height': [47.65, 50.96], + '2.y': [160.06, 162.34], + '3.height': [43.68, 46.71], + '3.y': [210.69, 216.48], + '4.height': [3.97, 4.25], + '4.y': [259.34, 268.5], + }, + endpointLabels: { + '0.labelY': [150.58, 152.65], + '1.labelY': [283.75, 296.15], + '2.labelY': [172.83, 174.9], + '3.labelY': [204.19, 209.98], + '4.labelY': [252.84, 262], + 'bounds.height': [178.7, 191.1], + 'leadingBounds.height': [178.7, 191.1], + }, + }, + style: {}, + }, + '../testing/fixtures-ranking.stories.tsx.slopeMarketShareSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-ranking.stories.tsx.bumpConstructorsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-ranking.stories.tsx.bumpConstructorsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-refresh.stories.tsx.flatColumnsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + area: { + 'rect.height': [142.13, 156.13], + }, + chrome: { + bottomAnchorY: [312, 326], + bottomHeight: [72, 58], + 'byline.maxWidth': [223, 292.58], + 'byline.y': [42, 28], + 'source.maxWidth': [223, 292.58], + }, + axes: { + 'x.end.y': [269.83, 283.83], + 'x.start.y': [269.83, 283.83], + 'y.end.y': [269.83, 283.83], + 'y.tick.0.position': [269.83, 283.83], + 'y.tick.1.position': [225.41, 235.04], + 'y.tick.2.position': [181, 186.25], + 'y.tick.3.position': [136.58, 137.46], + 'y.titlePosition.y': [198.76, 205.76], + }, + marks: { + '0.height': [126.14, 138.56], + '0.y': [143.69, 145.26], + '1.height': [128.8, 141.49], + '1.y': [141.02, 142.34], + '2.height': [122.59, 134.66], + '2.y': [147.24, 149.17], + '3.height': [132.36, 145.4], + '3.y': [137.47, 138.43], + '4.height': [135.02, 148.32], + '4.y': [134.81, 135.51], + '5.height': [119.92, 131.73], + '5.y': [149.91, 152.1], + '6.height': [114.59, 125.88], + '6.y': [155.24, 157.95], + '7.height': [118.14, 129.78], + '7.y': [151.68, 154.05], + }, + labels: { + '0.label.y': [131.69, 133.26], + '1.label.y': [129.02, 130.34], + '2.label.y': [135.24, 137.17], + '3.label.y': [125.47, 126.43], + '4.label.y': [122.81, 123.51], + '5.label.y': [137.91, 140.1], + '6.label.y': [143.24, 145.95], + '7.label.y': [139.68, 142.05], + }, + }, + style: {}, + }, + '../testing/fixtures-refresh.stories.tsx.flatColumnsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1111, 1180.58], + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-refresh.stories.tsx.centerLabelSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-refresh.stories.tsx.centerLabelSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-refresh.stories.tsx.presetSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-refresh.stories.tsx.presetSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-sankey.stories.tsx.baseSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../testing/fixtures-sankey.stories.tsx.baseSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-sankey.stories.tsx.otherSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../testing/fixtures-sankey.stories.tsx.otherSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-search.stories.tsx.findYourCountrySpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-search.stories.tsx.findYourCountrySpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.basicSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + bottomHeight: [56, 43.6], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.basicSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.deltaSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + bottomHeight: [56, 43.6], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.deltaSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.heatmapSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + bottomHeight: [56, 43.6], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.heatmapSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.sparklineSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.sparklineSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.cardsSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + chrome: { + bottomHeight: [56, 43.6], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.cardsSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + chrome: { + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.explicitWidthSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 390], + }, + }, + style: {}, + }, + '../testing/fixtures-tables.stories.tsx.explicitWidthSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.width': [undefined, 1280], + }, + }, + style: {}, + }, + '../testing/fixtures-tilemaps.stories.tsx.quantitativeSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 313.3], + 'byline.maxWidth': [215, 284.58], + 'source.maxWidth': [215, 284.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tilemaps.stories.tsx.quantitativeSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 309.2], + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-tilemaps.stories.tsx.categoricalDarkSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + dims: { + 'size.height': [411.75, 397.75], + }, + area: { + 'rect.height': [199.25, 213.25], + }, + chrome: { + bottomAnchorY: [undefined, 325.75], + bottomHeight: [76, 62], + 'byline.maxWidth': [215, 284.58], + 'byline.y': [42, 28], + 'source.maxWidth': [215, 284.58], + }, + marks: { + '0.size': [17, 19], + '0.x': [285.5, 293.5], + '1.size': [17, 19], + '1.x': [263.5, 269.5], + '1.y': [136.75, 138.75], + '10.size': [17, 19], + '10.x': [241.5, 245.5], + '10.y': [158.75, 162.75], + '11.size': [17, 19], + '11.x': [263.5, 269.5], + '11.y': [158.75, 162.75], + '12.size': [17, 19], + '12.x': [65.5, 53.5], + '12.y': [180.75, 186.75], + '13.size': [17, 19], + '13.x': [87.5, 77.5], + '13.y': [180.75, 186.75], + '14.size': [17, 19], + '14.x': [109.5, 101.5], + '14.y': [180.75, 186.75], + '15.size': [17, 19], + '15.x': [131.5, 125.5], + '15.y': [180.75, 186.75], + '16.size': [17, 19], + '16.x': [153.5, 149.5], + '16.y': [180.75, 186.75], + '17.size': [17, 19], + '17.x': [175.5, 173.5], + '17.y': [180.75, 186.75], + '18.size': [17, 19], + '18.y': [180.75, 186.75], + '19.size': [17, 19], + '19.x': [219.5, 221.5], + '19.y': [180.75, 186.75], + '2.size': [17, 19], + '2.x': [285.5, 293.5], + '2.y': [136.75, 138.75], + '20.size': [17, 19], + '20.x': [241.5, 245.5], + '20.y': [180.75, 186.75], + '21.size': [17, 19], + '21.x': [263.5, 269.5], + '21.y': [180.75, 186.75], + '22.size': [17, 19], + '22.x': [285.5, 293.5], + '22.y': [180.75, 186.75], + '23.size': [17, 19], + '23.x': [65.5, 53.5], + '23.y': [202.75, 210.75], + '24.size': [17, 19], + '24.x': [87.5, 77.5], + '24.y': [202.75, 210.75], + '25.size': [17, 19], + '25.x': [109.5, 101.5], + '25.y': [202.75, 210.75], + '26.size': [17, 19], + '26.x': [131.5, 125.5], + '26.y': [202.75, 210.75], + '27.size': [17, 19], + '27.x': [153.5, 149.5], + '27.y': [202.75, 210.75], + '28.size': [17, 19], + '28.x': [175.5, 173.5], + '28.y': [202.75, 210.75], + '29.size': [17, 19], + '29.y': [202.75, 210.75], + '3.size': [17, 19], + '3.x': [65.5, 53.5], + '3.y': [158.75, 162.75], + '30.size': [17, 19], + '30.x': [219.5, 221.5], + '30.y': [202.75, 210.75], + '31.size': [17, 19], + '31.x': [241.5, 245.5], + '31.y': [202.75, 210.75], + '32.size': [17, 19], + '32.x': [263.5, 269.5], + '32.y': [202.75, 210.75], + '33.size': [17, 19], + '33.x': [285.5, 293.5], + '33.y': [202.75, 210.75], + '34.size': [17, 19], + '34.x': [87.5, 77.5], + '34.y': [224.75, 234.75], + '35.size': [17, 19], + '35.x': [109.5, 101.5], + '35.y': [224.75, 234.75], + '36.size': [17, 19], + '36.x': [131.5, 125.5], + '36.y': [224.75, 234.75], + '37.size': [17, 19], + '37.x': [153.5, 149.5], + '37.y': [224.75, 234.75], + '38.size': [17, 19], + '38.x': [175.5, 173.5], + '38.y': [224.75, 234.75], + '39.size': [17, 19], + '39.y': [224.75, 234.75], + '4.size': [17, 19], + '4.x': [87.5, 77.5], + '4.y': [158.75, 162.75], + '40.size': [17, 19], + '40.x': [219.5, 221.5], + '40.y': [224.75, 234.75], + '41.size': [17, 19], + '41.x': [241.5, 245.5], + '41.y': [224.75, 234.75], + '42.size': [17, 19], + '42.x': [65.5, 53.5], + '42.y': [246.75, 258.75], + '43.size': [17, 19], + '43.x': [131.5, 125.5], + '43.y': [246.75, 258.75], + '44.size': [17, 19], + '44.x': [153.5, 149.5], + '44.y': [246.75, 258.75], + '45.size': [17, 19], + '45.x': [175.5, 173.5], + '45.y': [246.75, 258.75], + '46.size': [17, 19], + '46.y': [246.75, 258.75], + '47.size': [17, 19], + '47.x': [219.5, 221.5], + '47.y': [246.75, 258.75], + '48.size': [17, 19], + '48.x': [87.5, 77.5], + '48.y': [268.75, 282.75], + '49.size': [17, 19], + '49.x': [131.5, 125.5], + '49.y': [268.75, 282.75], + '5.size': [17, 19], + '5.x': [109.5, 101.5], + '5.y': [158.75, 162.75], + '50.size': [17, 19], + '50.x': [219.5, 221.5], + '50.y': [268.75, 282.75], + '6.size': [17, 19], + '6.x': [131.5, 125.5], + '6.y': [158.75, 162.75], + '7.size': [17, 19], + '7.x': [153.5, 149.5], + '7.y': [158.75, 162.75], + '8.size': [17, 19], + '8.x': [175.5, 173.5], + '8.y': [158.75, 162.75], + '9.size': [17, 19], + '9.y': [158.75, 162.75], + }, + labels: { + '0.label.x': [294, 303], + '0.label.y': [123.25, 124.25], + '1.label.x': [272, 279], + '1.label.y': [145.25, 148.25], + '10.label.x': [250, 255], + '10.label.y': [167.25, 172.25], + '11.label.x': [272, 279], + '11.label.y': [167.25, 172.25], + '12.label.x': [74, 63], + '12.label.y': [189.25, 196.25], + '13.label.x': [96, 87], + '13.label.y': [189.25, 196.25], + '14.label.x': [118, 111], + '14.label.y': [189.25, 196.25], + '15.label.x': [140, 135], + '15.label.y': [189.25, 196.25], + '16.label.x': [162, 159], + '16.label.y': [189.25, 196.25], + '17.label.x': [184, 183], + '17.label.y': [189.25, 196.25], + '18.label.x': [206, 207], + '18.label.y': [189.25, 196.25], + '19.label.x': [228, 231], + '19.label.y': [189.25, 196.25], + '2.label.x': [294, 303], + '2.label.y': [145.25, 148.25], + '20.label.x': [250, 255], + '20.label.y': [189.25, 196.25], + '21.label.x': [272, 279], + '21.label.y': [189.25, 196.25], + '22.label.x': [294, 303], + '22.label.y': [189.25, 196.25], + '23.label.x': [74, 63], + '23.label.y': [211.25, 220.25], + '24.label.x': [96, 87], + '24.label.y': [211.25, 220.25], + '25.label.x': [118, 111], + '25.label.y': [211.25, 220.25], + '26.label.x': [140, 135], + '26.label.y': [211.25, 220.25], + '27.label.x': [162, 159], + '27.label.y': [211.25, 220.25], + '28.label.x': [184, 183], + '28.label.y': [211.25, 220.25], + '29.label.x': [206, 207], + '29.label.y': [211.25, 220.25], + '3.label.x': [74, 63], + '3.label.y': [167.25, 172.25], + '30.label.x': [228, 231], + '30.label.y': [211.25, 220.25], + '31.label.x': [250, 255], + '31.label.y': [211.25, 220.25], + '32.label.x': [272, 279], + '32.label.y': [211.25, 220.25], + '33.label.x': [294, 303], + '33.label.y': [211.25, 220.25], + '34.label.x': [96, 87], + '34.label.y': [233.25, 244.25], + '35.label.x': [118, 111], + '35.label.y': [233.25, 244.25], + '36.label.x': [140, 135], + '36.label.y': [233.25, 244.25], + '37.label.x': [162, 159], + '37.label.y': [233.25, 244.25], + '38.label.x': [184, 183], + '38.label.y': [233.25, 244.25], + '39.label.x': [206, 207], + '39.label.y': [233.25, 244.25], + '4.label.x': [96, 87], + '4.label.y': [167.25, 172.25], + '40.label.x': [228, 231], + '40.label.y': [233.25, 244.25], + '41.label.x': [250, 255], + '41.label.y': [233.25, 244.25], + '42.label.x': [74, 63], + '42.label.y': [255.25, 268.25], + '43.label.x': [140, 135], + '43.label.y': [255.25, 268.25], + '44.label.x': [162, 159], + '44.label.y': [255.25, 268.25], + '45.label.x': [184, 183], + '45.label.y': [255.25, 268.25], + '46.label.x': [206, 207], + '46.label.y': [255.25, 268.25], + '47.label.x': [228, 231], + '47.label.y': [255.25, 268.25], + '48.label.x': [96, 87], + '48.label.y': [277.25, 292.25], + '49.label.x': [140, 135], + '49.label.y': [277.25, 292.25], + '5.label.x': [118, 111], + '5.label.y': [167.25, 172.25], + '50.label.x': [228, 231], + '50.label.y': [277.25, 292.25], + '6.label.x': [140, 135], + '6.label.y': [167.25, 172.25], + '7.label.x': [162, 159], + '7.label.y': [167.25, 172.25], + '8.label.x': [184, 183], + '8.label.y': [167.25, 172.25], + '9.label.x': [206, 207], + '9.label.y': [167.25, 172.25], + }, + legend: { + 'categoricalLegend.bounds.height': [32, 16], + 'categoricalLegend.bounds.width': [259, 283], + 'categoricalLegend.bounds.x': [65.5, 53.5], + 'categoricalLegend.bounds.y': [293.75, 309.75], + }, + }, + style: { + 'marks.0.label.style.fontSize': [8.5, 9.5], + 'marks.0.valueLabel.style.fontSize': [7.1, 8], + 'marks.1.label.style.fontSize': [8.5, 9.5], + 'marks.1.valueLabel.style.fontSize': [7.1, 8], + 'marks.10.label.style.fontSize': [8.5, 9.5], + 'marks.10.valueLabel.style.fontSize': [7.1, 8], + 'marks.11.label.style.fontSize': [8.5, 9.5], + 'marks.11.valueLabel.style.fontSize': [7.1, 8], + 'marks.12.label.style.fontSize': [8.5, 9.5], + 'marks.12.valueLabel.style.fontSize': [7.1, 8], + 'marks.13.label.style.fontSize': [8.5, 9.5], + 'marks.13.valueLabel.style.fontSize': [7.1, 8], + 'marks.14.label.style.fontSize': [8.5, 9.5], + 'marks.14.valueLabel.style.fontSize': [7.1, 8], + 'marks.15.label.style.fontSize': [8.5, 9.5], + 'marks.15.valueLabel.style.fontSize': [7.1, 8], + 'marks.16.label.style.fontSize': [8.5, 9.5], + 'marks.16.valueLabel.style.fontSize': [7.1, 8], + 'marks.17.label.style.fontSize': [8.5, 9.5], + 'marks.17.valueLabel.style.fontSize': [7.1, 8], + 'marks.18.label.style.fontSize': [8.5, 9.5], + 'marks.18.valueLabel.style.fontSize': [7.1, 8], + 'marks.19.label.style.fontSize': [8.5, 9.5], + 'marks.19.valueLabel.style.fontSize': [7.1, 8], + 'marks.2.label.style.fontSize': [8.5, 9.5], + 'marks.2.valueLabel.style.fontSize': [7.1, 8], + 'marks.20.label.style.fontSize': [8.5, 9.5], + 'marks.20.valueLabel.style.fontSize': [7.1, 8], + 'marks.21.label.style.fontSize': [8.5, 9.5], + 'marks.21.valueLabel.style.fontSize': [7.1, 8], + 'marks.22.label.style.fontSize': [8.5, 9.5], + 'marks.22.valueLabel.style.fontSize': [7.1, 8], + 'marks.23.label.style.fontSize': [8.5, 9.5], + 'marks.23.valueLabel.style.fontSize': [7.1, 8], + 'marks.24.label.style.fontSize': [8.5, 9.5], + 'marks.24.valueLabel.style.fontSize': [7.1, 8], + 'marks.25.label.style.fontSize': [8.5, 9.5], + 'marks.25.valueLabel.style.fontSize': [7.1, 8], + 'marks.26.label.style.fontSize': [8.5, 9.5], + 'marks.26.valueLabel.style.fontSize': [7.1, 8], + 'marks.27.label.style.fontSize': [8.5, 9.5], + 'marks.27.valueLabel.style.fontSize': [7.1, 8], + 'marks.28.label.style.fontSize': [8.5, 9.5], + 'marks.28.valueLabel.style.fontSize': [7.1, 8], + 'marks.29.label.style.fontSize': [8.5, 9.5], + 'marks.29.valueLabel.style.fontSize': [7.1, 8], + 'marks.3.label.style.fontSize': [8.5, 9.5], + 'marks.3.valueLabel.style.fontSize': [7.1, 8], + 'marks.30.label.style.fontSize': [8.5, 9.5], + 'marks.30.valueLabel.style.fontSize': [7.1, 8], + 'marks.31.label.style.fontSize': [8.5, 9.5], + 'marks.31.valueLabel.style.fontSize': [7.1, 8], + 'marks.32.label.style.fontSize': [8.5, 9.5], + 'marks.32.valueLabel.style.fontSize': [7.1, 8], + 'marks.33.label.style.fontSize': [8.5, 9.5], + 'marks.33.valueLabel.style.fontSize': [7.1, 8], + 'marks.34.label.style.fontSize': [8.5, 9.5], + 'marks.34.valueLabel.style.fontSize': [7.1, 8], + 'marks.35.label.style.fontSize': [8.5, 9.5], + 'marks.35.valueLabel.style.fontSize': [7.1, 8], + 'marks.36.label.style.fontSize': [8.5, 9.5], + 'marks.36.valueLabel.style.fontSize': [7.1, 8], + 'marks.37.label.style.fontSize': [8.5, 9.5], + 'marks.37.valueLabel.style.fontSize': [7.1, 8], + 'marks.38.label.style.fontSize': [8.5, 9.5], + 'marks.38.valueLabel.style.fontSize': [7.1, 8], + 'marks.39.label.style.fontSize': [8.5, 9.5], + 'marks.39.valueLabel.style.fontSize': [7.1, 8], + 'marks.4.label.style.fontSize': [8.5, 9.5], + 'marks.4.valueLabel.style.fontSize': [7.1, 8], + 'marks.40.label.style.fontSize': [8.5, 9.5], + 'marks.40.valueLabel.style.fontSize': [7.1, 8], + 'marks.41.label.style.fontSize': [8.5, 9.5], + 'marks.41.valueLabel.style.fontSize': [7.1, 8], + 'marks.42.label.style.fontSize': [8.5, 9.5], + 'marks.42.valueLabel.style.fontSize': [7.1, 8], + 'marks.43.label.style.fontSize': [8.5, 9.5], + 'marks.43.valueLabel.style.fontSize': [7.1, 8], + 'marks.44.label.style.fontSize': [8.5, 9.5], + 'marks.44.valueLabel.style.fontSize': [7.1, 8], + 'marks.45.label.style.fontSize': [8.5, 9.5], + 'marks.45.valueLabel.style.fontSize': [7.1, 8], + 'marks.46.label.style.fontSize': [8.5, 9.5], + 'marks.46.valueLabel.style.fontSize': [7.1, 8], + 'marks.47.label.style.fontSize': [8.5, 9.5], + 'marks.47.valueLabel.style.fontSize': [7.1, 8], + 'marks.48.label.style.fontSize': [8.5, 9.5], + 'marks.48.valueLabel.style.fontSize': [7.1, 8], + 'marks.49.label.style.fontSize': [8.5, 9.5], + 'marks.49.valueLabel.style.fontSize': [7.1, 8], + 'marks.5.label.style.fontSize': [8.5, 9.5], + 'marks.5.valueLabel.style.fontSize': [7.1, 8], + 'marks.50.label.style.fontSize': [8.5, 9.5], + 'marks.50.valueLabel.style.fontSize': [7.1, 8], + 'marks.6.label.style.fontSize': [8.5, 9.5], + 'marks.6.valueLabel.style.fontSize': [7.1, 8], + 'marks.7.label.style.fontSize': [8.5, 9.5], + 'marks.7.valueLabel.style.fontSize': [7.1, 8], + 'marks.8.label.style.fontSize': [8.5, 9.5], + 'marks.8.valueLabel.style.fontSize': [7.1, 8], + 'marks.9.label.style.fontSize': [8.5, 9.5], + 'marks.9.valueLabel.style.fontSize': [7.1, 8], + }, + }, + '../testing/fixtures-tilemaps.stories.tsx.categoricalDarkSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + bottomAnchorY: [undefined, 311.2], + 'byline.maxWidth': [1105, 1174.58], + 'source.maxWidth': [1105, 1174.58], + }, + }, + style: {}, + }, + '../testing/fixtures-waffle.stories.tsx.waffleBasicSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-waffle.stories.tsx.waffleBasicSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-waffle.stories.tsx.waffleHighlightSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-waffle.stories.tsx.waffleHighlightSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/fixtures-you-draw-it.stories.tsx.youDrawItSpec @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/fixtures-you-draw-it.stories.tsx.youDrawItSpec @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/histogram-formatting.stories.tsx.pooled @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/histogram-formatting.stories.tsx.pooled @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, + '../testing/histogram-formatting.stories.tsx.percentages @390': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [223, 292.58], + }, + }, + style: {}, + }, + '../testing/histogram-formatting.stories.tsx.percentages @1280': { + reason: + 'C7 shared measured footer replaces the fixed brand reserve; attribution is complete and automatic geometry uses the remaining frame.', + changes: { + chrome: { + 'source.maxWidth': [1111, 1180.58], + }, + }, + style: {}, + }, +}; diff --git a/examples/src/__tests__/migration-v8-parity.test.ts b/examples/src/__tests__/migration-v8-parity.test.ts new file mode 100644 index 00000000..ea9c942f --- /dev/null +++ b/examples/src/__tests__/migration-v8-parity.test.ts @@ -0,0 +1,549 @@ +/// +/** + * v8 -> v9 migration parity, measured against real v8.9.1 compile output. + * + * Fixtures come from `bun run test:parity:capture` (scripts/capture-v8-parity.mjs): + * every authored v8.9.1 example spec compiled by v8.9.1 at 390px and 1280px. + * Here each spec goes through `migrateSpecV8()` and the v9 engine at the same size, + * and both layouts are reduced by the shared `parity-signature.ts` extractor. + * + * Gate (RFC section 7 acceptance: "migrated v8 specs keep v8 styling; layout is + * not promised pixel-identical"): + * - style equals v8 except the exact additive control metadata and B1 font fixes + * listed below (every other flattened field compares in both directions). + * - geometry must be identical unless a D14 layout heuristic applies. Of the D14 + * items, only placement order, connector-crossing scoring, source-order note + * numbering and wrapped rich-text notes can move geometry, and all four act on + * text annotations (the color and refline/range size items are style, which + * migration materializes; token stamping is renderer-only; inferFieldType moved + * nothing in this corpus; the gallery `labelPlacement` rewrites only touch v9 + * examples). So a spec without text annotations must match v8 exactly. A spec + * with them may move only in the categories its GEOMETRY_ALLOWLIST entry names, + * and the entry cites the D14 item. Entries must have text annotations and must + * move in every listed category, so the list cannot go stale silently. + * + * PARITY_REPORT=1 prints a summary table; PARITY_DUMP= also writes every + * fixture's v8/v9 signatures and deltas as JSON for investigation. + */ +process.env.TZ = 'UTC'; + +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { gunzipSync } from 'node:zlib'; +import usCountiesAlbers from 'us-atlas/counties-albers-10m.json'; +import usStates from 'us-atlas/states-10m.json'; +import usStatesAlbers from 'us-atlas/states-albers-10m.json'; +import { describe, expect, it } from 'vitest'; +import worldCountries from 'world-atlas/countries-110m.json'; +import { + compileBarList, + compileChart, + compileGeoMap, + compileGraph, + compileLayer, + compileSankey, + compileTable, + compileTileMap, +} from '../../../packages/engine/src/compile'; +import { migrateSpecV8 } from '../../../packages/engine/src/migration/v8'; +import { + APPROVED_AXIS_TITLE_LAYOUT, + APPROVED_B3_MAP_LAYOUT, + APPROVED_ENDPOINT_TOP_SWEEP, + APPROVED_MAP_KEY_PLACEMENT, + APPROVED_PRE_RFC_LAYOUT, + APPROVED_RFC_B1_LAYOUT, +} from './migration-v8-approved-changes'; +import { APPROVED_C7_ATTRIBUTION } from './migration-v8-attribution-changes'; +import { + flatten, + GEOMETRY_CATEGORIES, + type Geometry, + type Signature, + signature, +} from './parity-signature'; + +interface Entry { + name: string; + width: number; + spec: unknown; + signature: Signature; +} +const capture = JSON.parse( + gunzipSync( + readFileSync( + path.join(path.dirname(fileURLToPath(import.meta.url)), '__fixtures__/v8-parity.json.gz'), + ), + ).toString(), +) as { tag: string; commit: string; entries: Entry[]; skipped: unknown[] }; + +const topologies: Record = { + 'us-atlas/counties-albers-10m.json': usCountiesAlbers, + 'us-atlas/states-10m.json': usStates, + 'us-atlas/states-albers-10m.json': usStatesAlbers, + 'world-atlas/countries-110m.json': worldCountries, +}; +const hydrate = (value: unknown): unknown => + JSON.parse(JSON.stringify(value), (_key, child) => + child && typeof child === 'object' && typeof child.$topology === 'string' + ? topologies[child.$topology] + : child, + ); + +// biome-ignore lint/suspicious/noExplicitAny: fixtures are untyped v8 JSON. +function compile(spec: any, width: number) { + const options = { width, height: 400, onWarn: () => {} }; + if ('layer' in spec) return compileLayer(spec, options); + if ('mark' in spec) return compileChart(spec, options); + switch (spec.type) { + case 'table': + return compileTable(spec, options); + case 'graph': + return compileGraph(spec, options); + case 'sankey': + return compileSankey(spec, options); + case 'map': + return compileGeoMap(spec, options); + case 'barlist': + return compileBarList(spec, options); + case 'tilemap': + return compileTileMap(spec, options); + } + throw new Error(`Unknown spec kind for ${JSON.stringify(Object.keys(spec))}`); +} + +interface StyleDiff { + path: string; + v8: unknown; + v9: unknown; +} +function styleDiff(v8: Signature['style'], v9: Signature['style']): StyleDiff[] { + const before = flatten(v8); + const after = flatten(v9); + const diffs: StyleDiff[] = []; + for (const [path, value] of Object.entries(before)) + if (!(path in after) || after[path] !== value) diffs.push({ path, v8: value, v9: after[path] }); + for (const [path, value] of Object.entries(after)) + if (!(path in before)) diffs.push({ path, v8: undefined, v9: value }); + return diffs; +} + +interface CategoryDelta { + /** Largest absolute px difference over numeric values present on both sides. */ + maxAbs: number; + /** Values added, removed, or changed in kind or text (tick labels, note text). */ + structural: number; +} +function geometryDelta(v8: Geometry, v9: Geometry) { + const out: Record = {}; + for (const category of GEOMETRY_CATEGORIES) { + const before = v8[category] ?? {}; + const after = v9[category] ?? {}; + const delta = { maxAbs: 0, structural: 0 }; + for (const path of new Set([...Object.keys(before), ...Object.keys(after)])) { + const a = before[path]; + const b = after[path]; + if (typeof a === 'number' && typeof b === 'number') + delta.maxAbs = Math.max(delta.maxAbs, Math.round(Math.abs(a - b) * 100) / 100); + else if (a !== b) delta.structural++; + } + out[category] = delta; + } + return out; +} + +type Category = (typeof GEOMETRY_CATEGORIES)[number]; +/** Plot shrink from a taller reserved note band moves everything below the chrome. */ +const NOTE_BAND: Category[] = ['area', 'chrome', 'axes', 'marks', 'annotations', 'notes']; +const NUMBERING = 'D14 source-order note numbering (RFC section 4 "Numbering (v9, D14)")'; +const WRAPPED = + 'D14 wrapped rich-text notes: the subtitle gets its own note line, and the reserved ' + + 'note band (8.11 stabilization) grows, shrinking the plot (RFC section 4 "Note content")'; +const PLAN_HEIGHT = + 'v9 layout plan sizes y ticks against the final plot height (v8 left the subtract-mode ' + + 'note band out and picked ticks for a taller plot: 8 ticks 16px apart at 130px) ' + + '(RFC section 7: layout is not promised pixel-identical)'; +const CURVE_TAIL = + 'curve connectors are shaped to the data point and shortened along their end tangent, ' + + 'so the tail aims at the marker (v8 shortened along the chord)'; +const PLACEMENT = + 'D14 placement order and connector-crossing scoring (RFC section 4 "Placement order ' + + 'and scoring (v9, D14)")'; + +/** + * Specs whose geometry moves under v9 because of a D14 heuristic (RFC section 2 + * D14; section 9 phase 5 "D14 retunes"), with the categories allowed to move. + * Keyed by fixture name; applies to both widths. + */ +const GEOMETRY_ALLOWLIST: Record = { + '../gallery/charts-scatter-distribution.stories.tsx.bubbleSpec': { + d14: NUMBERING, + categories: ['notes'], + }, + '../gallery/charts-scatter-distribution.stories.tsx.colorScatterSpec': { + d14: NUMBERING, + categories: ['notes'], + }, + // v9 also emits display lines for one-line notes (wrapped notes). + '../gallery/charts-scatter-distribution.stories.tsx.trendScatterSpec': { + d14: `${NUMBERING}; ${WRAPPED}`, + categories: ['notes'], + }, + '../gallery/features-annotations.stories.tsx.textAnnotationSpec': { + d14: WRAPPED, + categories: NOTE_BAND, + }, + '../gallery/features-annotations.stories.tsx.ledeSpec': { d14: WRAPPED, categories: NOTE_BAND }, + // At 1280 the new candidate scoring also demotes "Straight, no arrow" to a note. + '../gallery/features-annotations.stories.tsx.connectorsSpec': { + d14: `${WRAPPED}; ${PLACEMENT}`, + categories: NOTE_BAND, + }, + '../gallery/features-annotations.stories.tsx.thinningSpec': { + d14: `${NUMBERING}; ${PLACEMENT}`, + categories: ['annotations', 'notes'], + }, + '../gallery/features-annotations.stories.tsx.richTextSpec': { + d14: CURVE_TAIL, + categories: ['annotations'], + }, + '../gallery/showcase.stories.tsx.scatterSpec': { + d14: CURVE_TAIL, + categories: ['annotations'], + }, + '../testing/fixtures-lines.stories.tsx.lineSpec': { + d14: PLAN_HEIGHT, + categories: ['axes'], + }, + '../testing/fixtures-bars.stories.tsx.tempSpec': { + d14: PLACEMENT, + categories: ['annotations'], + }, +}; + +const RETIRED_LABELS = + 'RFC 8.1 "End-of-line labels": v9 retires per-mark line-end labels and migration ' + + 'rewrites them to a label-only endpoint column, which has no per-label font settings ' + + 'and reserves its own column beside the plot'; + +/** + * Specs whose STYLE differs from v8 because a documented migration rewrite has + * no style-preserving v9 equivalent. Keyed by fixture name; applies to both + * widths. `style` lists flattened style path prefixes that may differ (exact + * path or a `prefix.` descendant); `geometry` lists categories that may move. + * Every listed prefix and category must differ at some width. + */ +const STYLE_ALLOWLIST: Record = { + '../gallery/features-data-encoding.stories.tsx.dashEncodingSpec': { + reason: RETIRED_LABELS, + style: ['endpointLabels', 'marks.0.label', 'marks.1.label', 'marks.2.label'], + geometry: ['area', 'axes', 'marks', 'labels', 'endpointLabels'], + }, +}; +/** + * Style paths allowed to differ in every fixture, each with its reason. Endpoint + * markers are centered on the line's last point (where hover dots, the + * crosshair and annotation anchors sit) instead of offset by their radius, so + * their fill must be opaque to cover the line end. + */ +const CORPUS_STYLE_CHANGES: Array<{ pattern: RegExp; reason: string }> = [ + { + pattern: /^endpointLabels\.(entries|leading)\.\d+\.marker\.fill$/, + reason: 'endpoint markers center on the data point with an opaque knockout fill', + }, +]; +// These are additive resolved metadata, not a license to change existing style. +const ENDPOINT_CONTROL_METADATA: Record = { + 'theme.fonts.sizes.endpointLabel': 13, + 'theme.fonts.sizes.endpointValue': 12, + 'theme.spacing.endpointEntryGap': 6, + 'theme.spacing.endpointValueGap': 4, + 'theme.spacing.endpointColumnGap': 18, +}; +const VALUE_FONT_PATH = /^marks(?:\.facet\[[^\]]+\])?\.\d+\.label\.style\.fontFamily$/; +const VALUE_FONT_REASON = + 'B1: bar/column, dot and range value labels follow the resolved theme font instead of hardcoded system-ui; pie already did so.'; +function sanctionedValueFontChange(diff: StyleDiff, next: Signature | undefined): boolean { + if ( + !next || + !VALUE_FONT_PATH.test(diff.path) || + diff.v8 !== 'system-ui, -apple-system, sans-serif' + ) + return false; + const fields = flatten(next.style); + const mark = diff.path.slice(0, -'.label.style.fontFamily'.length); + return ( + ['rect', 'point'].includes(String(fields[`${mark}.type`])) && + diff.v9 === fields['theme.fonts.family'] + ); +} +const sanctionedEndpointPrecisionChange = (diff: StyleDiff) => { + if ( + !/^endpointLabels\.(entries|leading)\.\d+\.value$/.test(diff.path) || + typeof diff.v8 !== 'string' || + typeof diff.v9 !== 'string' + ) + return false; + if (!/^[+−-]?\d+(?:\.\d+)?$/.test(diff.v8) || !/^[+−-]?\d+(?:\.\d+)?$/.test(diff.v9)) + return false; + const trimPrecision = (value: string) => + value.includes('.') ? value.replace(/0+$/, '').replace(/\.$/, '') : value; + return trimPrecision(diff.v8) === trimPrecision(diff.v9); +}; +const additiveEndpointMetadata = (diff: StyleDiff) => + diff.v8 === undefined && + Object.hasOwn(ENDPOINT_CONTROL_METADATA, diff.path) && + diff.v9 === ENDPOINT_CONTROL_METADATA[diff.path]; + +const additiveV8ScaffoldingMetadata = ( + diff: StyleDiff, + next: Signature | undefined, + isMap: boolean, +) => { + if (diff.v8 !== undefined || !next) return false; + const fields = flatten(next.style); + if (diff.path === 'theme.colors.gridlineZero') return diff.v9 === fields['theme.colors.gridline']; + return ( + (diff.path === 'theme.colors.mapInteriorBorder' && + diff.v9 === (isMap ? 'rgba(0,0,0,0.25)' : 'rgba(0,0,0,0.14)')) || + (diff.path === 'theme.colors.mapOutlineBorder' && + diff.v9 === (isMap ? 'rgba(0,0,0,0.55)' : 'rgba(0,0,0,0.40)')) + ); +}; + +const underPrefix = (path: string, prefix: string) => + path === prefix || path.startsWith(`${prefix}.`); + +/** Whether any spec level (root, layer, override) authors a text annotation. */ +function hasTextAnnotation(value: unknown): boolean { + if (!value || typeof value !== 'object') return false; + const record = value as Record; + if ( + Array.isArray(record.annotations) && + record.annotations.some((annotation) => (annotation as { type?: string })?.type === 'text') + ) + return true; + return Object.values(record).some(hasTextAnnotation); +} + +const results = capture.entries.map((entry) => { + const { spec: migrated } = migrateSpecV8(hydrate(entry.spec)); + let v9: Signature | undefined; + let error: string | undefined; + try { + v9 = signature(compile(migrated, entry.width)); + } catch (caught) { + error = (caught as Error).message; + } + return { + ...entry, + v9, + error, + style: v9 ? styleDiff(entry.signature.style, v9.style) : [], + geometry: v9 ? geometryDelta(entry.signature.geometry, v9.geometry) : undefined, + }; +}); +const moved = (result: (typeof results)[number]) => + Object.values(result.geometry ?? {}).some((delta) => delta.maxAbs > 0 || delta.structural > 0); + +if (process.env.PARITY_REPORT) { + const rows = GEOMETRY_CATEGORIES.map((category) => { + const deltas = results.map((result) => result.geometry?.[category]); + return { + category, + fixturesMoved: deltas.filter((delta) => delta && (delta.maxAbs > 0 || delta.structural > 0)) + .length, + maxAbsPx: Math.max(0, ...deltas.map((delta) => delta?.maxAbs ?? 0)), + structural: deltas.reduce((sum, delta) => sum + (delta?.structural ?? 0), 0), + }; + }); + console.log( + `v8 parity vs ${capture.tag} (${capture.commit.slice(0, 8)}): ${results.length} fixtures, ` + + `${results.filter((result) => result.error).length} v9 compile errors, ` + + `${results.filter((result) => result.style.length).length} with style mismatches, ` + + `${results.filter(moved).length} with geometry diffs, ${capture.skipped.length} skipped at capture`, + ); + console.table(rows); + if (process.env.PARITY_DUMP) + writeFileSync(process.env.PARITY_DUMP, JSON.stringify(results, null, 1)); +} + +describe(`v8 migration parity against ${capture.tag}`, () => { + it('has a v8 corpus', () => { + expect(new Date(0).getTimezoneOffset()).toBe(0); + expect(new Set(capture.entries.map((entry) => entry.name)).size).toBeGreaterThan(200); + }); + + it('adds only released endpoint control values and narrowly scoped B1 value fonts', () => { + expect(VALUE_FONT_REASON).toContain('B1'); + for (const result of results) { + if (!result.v9) continue; + const fields = flatten(result.v9.style); + for (const [path, value] of Object.entries(ENDPOINT_CONTROL_METADATA)) + expect(fields[path]).toBe(value); + } + expect( + results.some((result) => + result.style.some((diff) => sanctionedValueFontChange(diff, result.v9)), + ), + ).toBe(true); + }); + + it('allowlist only names text-annotated fixtures that move in every listed category', () => { + const stale = Object.entries(GEOMETRY_ALLOWLIST).flatMap(([name, { categories }]) => { + const mine = results.filter((result) => result.name === name); + if (!mine.length) return [`${name}: no such fixture`]; + if (!hasTextAnnotation(mine[0].spec)) + return [`${name}: no text annotations, D14 cannot apply`]; + return categories + .filter((category) => + mine.every(({ geometry }) => { + const delta = geometry?.[category]; + return !delta || (delta.maxAbs === 0 && delta.structural === 0); + }), + ) + .map((category) => `${name}: ${category} never moves`); + }); + expect(stale).toEqual([]); + }); + + it('approved geometry exceptions match every exact before/final path value', () => { + for (const [key, approval] of [ + ...Object.entries(APPROVED_C7_ATTRIBUTION), + ...Object.entries(APPROVED_B3_MAP_LAYOUT), + ...Object.entries(APPROVED_PRE_RFC_LAYOUT), + ...Object.entries(APPROVED_RFC_B1_LAYOUT), + ...Object.entries(APPROVED_MAP_KEY_PLACEMENT), + ...Object.entries(APPROVED_AXIS_TITLE_LAYOUT), + ...Object.entries(APPROVED_ENDPOINT_TOP_SWEEP), + ]) { + const result = results.find((result) => `${result.name} @${result.width}` === key)!; + expect(result, key).toBeDefined(); + expect(approval.reason.length).toBeGreaterThan(20); + for (const [category, paths] of Object.entries(approval.changes)) { + for (const [path, [before, after]] of Object.entries(paths)) { + expect( + result.signature.geometry[category][path], + `${key} before ${category}.${path}`, + ).toBe(before); + // Later B3 and C7 reservations can move a previously corrected path. + // The new approval still guards the original v8 value and final v9 value. + const latestPair = + APPROVED_C7_ATTRIBUTION[key]?.changes[category]?.[path] ?? + APPROVED_B3_MAP_LAYOUT[key]?.changes[category]?.[path]; + const finalAfter = latestPair ? latestPair[1] : after; + expect(result.v9!.geometry[category][path], `${key} after ${category}.${path}`).toBe( + finalAfter, + ); + expect(before).not.toBe(after); + } + } + } + }); + + it('map key corrections match exact before/after style values', () => { + for (const [key, approval] of [ + ...Object.entries(APPROVED_MAP_KEY_PLACEMENT), + ...Object.entries(APPROVED_C7_ATTRIBUTION), + ...Object.entries(APPROVED_B3_MAP_LAYOUT), + ]) { + const result = results.find((result) => `${result.name} @${result.width}` === key)!; + const before = flatten(result.signature.style); + const after = flatten(result.v9!.style); + for (const [path, pair] of Object.entries(approval.style)) { + expect(before[path]).toBe(pair[0]); + expect(after[path]).toBe(pair[1]); + expect(pair[0]).not.toBe(pair[1]); + } + } + }); + + it('style allowlist only names prefixes and categories that actually differ', () => { + const stale = Object.entries(STYLE_ALLOWLIST).flatMap(([name, entry]) => { + const mine = results.filter((result) => result.name === name); + if (!mine.length) return [`${name}: no such fixture`]; + return [ + ...entry.style + .filter((prefix) => + mine.every(({ style }) => !style.some((diff) => underPrefix(diff.path, prefix))), + ) + .map((prefix) => `${name}: style ${prefix} never differs`), + ...entry.geometry + .filter((category) => + mine.every(({ geometry }) => { + const delta = geometry?.[category]; + return !delta || (delta.maxAbs === 0 && delta.structural === 0); + }), + ) + .map((category) => `${name}: ${category} never moves`), + ]; + }); + expect(stale).toEqual([]); + }); + + for (const result of results) { + describe(`${result.name} @${result.width}`, () => { + it('compiles after migration', () => { + expect(result.error).toBeUndefined(); + }); + it('keeps v8 styling', () => { + const allowed = STYLE_ALLOWLIST[result.name]?.style ?? []; + expect( + result.style.filter( + (diff) => + !allowed.some((prefix) => underPrefix(diff.path, prefix)) && + !CORPUS_STYLE_CHANGES.some(({ pattern }) => pattern.test(diff.path)) && + !additiveEndpointMetadata(diff) && + !additiveV8ScaffoldingMetadata( + diff, + result.v9, + (result.spec as { type?: string }).type === 'map', + ) && + !sanctionedValueFontChange(diff, result.v9) && + !sanctionedEndpointPrecisionChange(diff) && + !Object.entries({ + ...APPROVED_MAP_KEY_PLACEMENT[`${result.name} @${result.width}`]?.style, + ...APPROVED_B3_MAP_LAYOUT[`${result.name} @${result.width}`]?.style, + ...APPROVED_C7_ATTRIBUTION[`${result.name} @${result.width}`]?.style, + }).some( + ([path, pair]) => path === diff.path && pair[0] === diff.v8 && pair[1] === diff.v9, + ), + ), + ).toEqual([]); + }); + it('keeps v8 geometry outside D14-allowlisted categories', () => { + const allowed = new Set([ + ...(GEOMETRY_ALLOWLIST[result.name]?.categories ?? []), + ...(STYLE_ALLOWLIST[result.name]?.geometry ?? []), + ]); + const approved = [ + APPROVED_C7_ATTRIBUTION[`${result.name} @${result.width}`], + APPROVED_B3_MAP_LAYOUT[`${result.name} @${result.width}`], + APPROVED_PRE_RFC_LAYOUT[`${result.name} @${result.width}`], + APPROVED_RFC_B1_LAYOUT[`${result.name} @${result.width}`], + APPROVED_MAP_KEY_PLACEMENT[`${result.name} @${result.width}`], + APPROVED_AXIS_TITLE_LAYOUT[`${result.name} @${result.width}`], + APPROVED_ENDPOINT_TOP_SWEEP[`${result.name} @${result.width}`], + ]; + const unexpected: Record = {}; + for (const [category, delta] of Object.entries(result.geometry ?? {})) { + if (allowed.has(category as Category) || (!delta.maxAbs && !delta.structural)) continue; + const before = result.signature.geometry[category]; + const after = result.v9!.geometry[category]; + for (const path of new Set([...Object.keys(before), ...Object.keys(after)])) { + if (before[path] === after[path]) continue; + const matches = approved.some((approval) => { + const pair = approval?.changes[category]?.[path]; + return pair && pair[0] === before[path] && pair[1] === after[path]; + }); + if (!matches) { + unexpected[`${category}.${path}`] = { before: before[path], after: after[path] }; + } + } + } + expect(unexpected).toEqual({}); + }); + }); + } +}); diff --git a/examples/src/__tests__/parity-signature.ts b/examples/src/__tests__/parity-signature.ts new file mode 100644 index 00000000..3faa2707 --- /dev/null +++ b/examples/src/__tests__/parity-signature.ts @@ -0,0 +1,516 @@ +/** + * Layout signature for the v8 -> v9 migration parity test. + * + * Shared verbatim by `scripts/capture-v8-parity.mjs` (which copies this file into + * a temporary v8.9.1 worktree) and `migration-v8-parity.test.ts`, so both sides + * extract with identical code. Keep it dependency-free: it reads layouts loosely + * because it runs against two engine versions and every compiled layout kind + * (chart/layer/facet, table, graph, sankey, tilemap, geo map, barlist). + * + * Field mapping 8.9.1 -> v9: the layout types are identical for everything read + * here. v9 adds `AnnotationFootnote.subtitle/spans` (not read; notes compare + * `index`, `text` and `lines`) and drops `TableLayout.compact` (not read). + * + * - `style`: everything the RFC promises migration keeps (fonts, colors, text, + * weights, mark paint, annotation ink, connectors and arrows). Compared exactly. + * - `geometry`: flattened `category -> path -> value` maps. Numbers are rounded to + * 0.01px; strings (tick labels, note text) are content whose placement depends + * on layout, so they count as geometry differences rather than style. + */ + +// biome-ignore lint/suspicious/noExplicitAny: layouts are read loosely across two engine versions. +type Any = any; + +export type GeometryValue = number | string | null; +export type Geometry = Record>; +export interface Signature { + style: Record; + geometry: Geometry; +} + +export const GEOMETRY_CATEGORIES = [ + 'dims', + 'area', + 'chrome', + 'axes', + 'marks', + 'labels', + 'annotations', + 'legend', + 'endpointLabels', + 'notes', +] as const; + +const round = (value: unknown, places: number): unknown => { + if (typeof value === 'number') { + if (!Number.isFinite(value)) return String(value); + const factor = 10 ** places; + const rounded = Math.round(value * factor) / factor; + return Object.is(rounded, -0) ? 0 : rounded; + } + if (Array.isArray(value)) return value.map((item) => round(item, places)); + if (value && typeof value === 'object') { + if (value instanceof Map) return round(Object.fromEntries(value), places); + const out: Record = {}; + for (const key of Object.keys(value).sort()) { + const child = (value as Record)[key]; + if (child !== undefined && typeof child !== 'function') out[key] = round(child, places); + } + return out; + } + return value === undefined ? null : value; +}; +const clean = (value: unknown) => round(value, 3); + +const textStyle = (style: Any) => + style + ? clean({ + fontFamily: style.fontFamily, + fontSize: style.fontSize, + fontWeight: style.fontWeight, + fill: style.fill, + lineHeight: style.lineHeight, + fontVariant: style.fontVariant, + }) + : null; + +const connectorStyle = (connector: Any) => + connector + ? { + style: connector.style ?? null, + arrow: connector.arrow ?? null, + stroke: connector.stroke ?? null, + } + : null; + +const labelStyle = (label: Any) => + label + ? { + text: label.text ?? null, + style: textStyle(label.style), + background: label.background ?? null, + halo: label.halo ?? null, + connector: connectorStyle(label.connector), + } + : null; + +function markStyle(mark: Any) { + return clean({ + type: mark.type ?? null, + key: mark.key ?? mark.nodeId ?? mark.stateCode ?? mark.id ?? null, + series: mark.seriesKey ?? null, + fill: mark.fill ?? mark.bar?.fill ?? null, + stroke: mark.stroke ?? null, + strokeWidth: mark.strokeWidth ?? null, + strokeDasharray: mark.strokeDasharray ?? null, + opacity: mark.opacity ?? null, + fillOpacity: mark.fillOpacity ?? null, + strokeOpacity: mark.strokeOpacity ?? null, + pattern: mark.pattern ?? null, + cornerRadius: mark.cornerRadius ?? mark.bar?.cornerRadius ?? null, + sourceColor: mark.sourceColor ?? null, + targetColor: mark.targetColor ?? null, + noData: mark.noData ?? null, + text: mark.type === 'textMark' ? mark.text : null, + font: + mark.type === 'textMark' + ? { fontSize: mark.fontSize, fontWeight: mark.fontWeight, fontFamily: mark.fontFamily } + : null, + label: labelStyle(mark.label), + subtitle: labelStyle(mark.subtitle), + valueLabel: mark.valueLabel + ? { text: mark.valueLabel.text ?? null, style: textStyle(mark.valueLabel.style) } + : null, + }); +} + +/** Bounding box of the first two coordinates of every path command (no arcs). */ +function pathBox(path: unknown) { + if (typeof path !== 'string' || /[aA]/.test(path)) return null; + const numbers = path.match(/-?\d*\.?\d+(?:e-?\d+)?/g)?.map(Number) ?? []; + const xs: number[] = []; + const ys: number[] = []; + for (let i = 0; i + 1 < numbers.length; i += 2) { + xs.push(numbers[i]); + ys.push(numbers[i + 1]); + } + return pointsBox(xs.map((x, i) => ({ x, y: ys[i] }))); +} + +function pointsBox(points: Any[] | undefined) { + const finite = (points ?? []).filter( + (point) => point && Number.isFinite(point.x) && Number.isFinite(point.y), + ); + if (!finite.length) return null; + const xs = finite.map((point) => point.x); + const ys = finite.map((point) => point.y); + const x = Math.min(...xs); + const y = Math.min(...ys); + return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y }; +} + +function markBounds(mark: Any): Record | null { + switch (mark.type) { + case 'rect': + case 'sankeyNode': + return { x: mark.x, y: mark.y, width: mark.width, height: mark.height }; + case 'point': + case 'map-point': + return { cx: mark.cx, cy: mark.cy, r: mark.r }; + case 'line': + return pointsBox(mark.points) ?? pathBox(mark.path); + case 'area': + return pointsBox([...(mark.topPoints ?? []), ...(mark.bottomPoints ?? [])]); + case 'arc': + return { + cx: mark.center?.x, + cy: mark.center?.y, + innerRadius: mark.innerRadius, + outerRadius: mark.outerRadius, + startAngle: mark.startAngle, + endAngle: mark.endAngle, + }; + case 'textMark': + return { x: mark.x, y: mark.y }; + case 'rule': + return { x1: mark.x1, y1: mark.y1, x2: mark.x2, y2: mark.y2 }; + case 'tick': + return { x: mark.x, y: mark.y, length: mark.length }; + case 'sankeyLink': + return { width: mark.width, ...pathBox(mark.path) }; + case 'tile': + return { x: mark.x, y: mark.y, size: mark.size }; + case 'map-feature': + return mark.bounds ?? null; + case 'barlist-row': + return { bar: mark.bar, track: mark.track, y: mark.y, height: mark.height }; + default: + return null; + } +} + +function legendsOf(layout: Any): Array<[string, Any]> { + const named: Array<[string, Any]> = []; + if (Array.isArray(layout.legends) && layout.legends.length) + for (const [i, legend] of layout.legends.entries()) named.push([`legends.${i}`, legend]); + else if (layout.legend) named.push(['legend', layout.legend]); + for (const key of [ + 'gradientLegend', + 'categoricalLegend', + 'continuousLegend', + 'pointCategoricalLegend', + 'pointContinuousLegend', + 'pointSizeLegend', + ]) + if (layout[key]) named.push([key, layout[key]]); + return named; +} + +function legendStyle(legend: Any) { + return clean({ + type: legend.type ?? 'categorical', + channel: legend.channel ?? null, + position: legend.position ?? null, + labelStyle: textStyle(legend.labelStyle), + titleStyle: textStyle(legend.titleStyle), + title: legend.title ?? null, + entries: (legend.entries ?? []).map((entry: Any) => ({ + label: entry.label, + color: entry.color, + shape: entry.shape, + active: entry.active ?? null, + overflow: entry.overflow ?? null, + })), + swatchChipFill: legend.swatchChipFill ?? null, + colorStops: legend.colorStops ?? null, + bins: (legend.bins ?? []).map((bin: Any) => bin.color), + ticks: (legend.ticks ?? []).map((tick: Any) => tick.label), + circles: (legend.circles ?? []).map((circle: Any) => circle.label), + minLabel: legend.minLabel ?? null, + maxLabel: legend.maxLabel ?? null, + stroke: legend.stroke ?? null, + noData: legend.noData + ? { fill: legend.noData.fill, label: legend.noData.label, pattern: legend.noData.pattern } + : null, + }); +} + +function annotationStyle(annotation: Any) { + return clean({ + type: annotation.type, + id: annotation.id ?? null, + label: labelStyle(annotation.label), + subtitle: annotation.subtitle + ? { text: annotation.subtitle.text, style: textStyle(annotation.subtitle.style) } + : null, + fill: annotation.fill ?? null, + stroke: annotation.stroke ?? null, + opacity: annotation.opacity ?? null, + strokeDasharray: annotation.strokeDasharray ?? null, + strokeWidth: annotation.strokeWidth ?? null, + dot: annotation.dot + ? { + fill: annotation.dot.fill, + stroke: annotation.dot.stroke, + strokeWidth: annotation.dot.strokeWidth, + radius: annotation.dot.radius, + } + : null, + }); +} + +const annotationKey = (annotation: Any, index: number) => + `a${annotation.specIndex ?? `#${index}`}${annotation.id ? `:${annotation.id}` : ''}`; + +function axesStyle(axes: Any) { + const out: Record = {}; + for (const name of ['x', 'y', 'y2']) { + const axis = axes?.[name]; + if (!axis) continue; + out[name] = { + title: axis.label ?? null, + titleStyle: textStyle(axis.labelStyle), + tickStyle: textStyle(axis.tickLabelStyle), + }; + } + return out; +} + +const CHROME_KEYS = ['eyebrow', 'title', 'subtitle', 'source', 'byline', 'footer', 'brand']; + +/** Extract the parity signature from any compiled layout. */ +export function signature(layout: Any): Signature { + const geometry: Geometry = {}; + for (const category of GEOMETRY_CATEGORIES) geometry[category] = {}; + const put = (category: string, path: string, value: unknown) => { + const rounded = round(value, 2); + if (rounded && typeof rounded === 'object') { + for (const [key, child] of Object.entries(rounded as Record)) + put(category, `${path}.${key}`, child); + return; + } + geometry[category][path] = rounded as GeometryValue; + }; + + const theme = layout.theme ?? {}; + const style: Record = { + theme: clean({ + colors: theme.colors, + fonts: theme.fonts, + chrome: theme.chrome, + rule: theme.rule, + spacing: theme.spacing, + borderRadius: theme.borderRadius, + isDark: theme.isDark, + seriesStrategy: theme.seriesStrategy, + }), + }; + + // Dimensions and plot area. + put('dims', 'size', layout.dimensions ?? { width: layout.width, height: layout.height }); + if (layout.mapSize) put('dims', 'mapSize', layout.mapSize); + if (layout.area) put('area', 'rect', layout.area); + + // Chrome. + const chrome = layout.chrome ?? {}; + const chromeStyle: Record = {}; + for (const key of CHROME_KEYS) { + const element = chrome[key]; + if (!element) continue; + chromeStyle[key] = { text: element.text, style: textStyle(element.style) }; + put('chrome', key, { x: element.x, y: element.y, maxWidth: element.maxWidth }); + } + if (chrome.rule) { + chromeStyle.rule = clean({ color: chrome.rule.color, thickness: chrome.rule.thickness }); + put('chrome', 'rule', { x: chrome.rule.x, y: chrome.rule.y, width: chrome.rule.width }); + } + chromeStyle.seriesSummary = clean( + (chrome.seriesSummary ?? []).map((entry: Any) => ({ key: entry.key, color: entry.color })), + ); + style.chrome = chromeStyle; + for (const key of ['topHeight', 'bottomHeight', 'noteBandHeight', 'grownHeight', 'bottomAnchorY']) + if (chrome[key] !== undefined) put('chrome', key, chrome[key]); + (chrome.footnotes ?? []).forEach((note: Any, i: number) => { + put('notes', `${i}.index`, note.index); + put('notes', `${i}.text`, note.text); + put('notes', `${i}.lines`, (note.lines ?? []).join('\n')); + }); + for (const [i, entry] of (chrome.seriesSummary ?? []).entries()) + put('notes', `summary.${i}`, (entry.lines ?? [entry.text]).join('\n')); + + // Axes, marks, annotations: the chart body and every facet panel. + const bodies: Array<[string, Any]> = [['', layout]]; + for (const panel of layout.facet?.panels ?? []) bodies.push([`facet[${panel.key}].`, panel]); + if (layout.facet) { + style.facetHeaders = clean( + layout.facet.panels.map((panel: Any) => ({ + text: panel.header?.text, + fontSize: panel.header?.fontSize, + fontWeight: panel.header?.fontWeight, + })), + ); + for (const panel of layout.facet.panels) { + put('area', `facet[${panel.key}]`, panel.area); + put('chrome', `facet[${panel.key}].header`, { x: panel.header?.x, y: panel.header?.y }); + } + } + + const axesStyles: Record = {}; + const markStyles: Record = {}; + const annotationStyles: Record = {}; + for (const [prefix, body] of bodies) { + if (body.axes) { + axesStyles[prefix || 'root'] = axesStyle(body.axes); + for (const name of ['x', 'y', 'y2']) { + const axis = body.axes[name]; + if (!axis) continue; + const at = `${prefix}${name}`; + put('axes', `${at}.start`, axis.start); + put('axes', `${at}.end`, axis.end); + put('axes', `${at}.tickAngle`, axis.tickAngle ?? 0); + put('axes', `${at}.titlePosition`, axis.titlePosition ?? null); + put('axes', `${at}.gridlines`, axis.gridlines?.length ?? 0); + (axis.ticks ?? []).forEach((tick: Any, i: number) => { + put('axes', `${at}.tick.${i}.position`, tick.position); + put('axes', `${at}.tick.${i}.label`, tick.label); + }); + } + } + + const marks: Any[] = [ + ...(body.marks ?? []), + ...(prefix ? [] : [...(layout.nodes ?? []), ...(layout.links ?? [])]), + ...(prefix ? [] : [...(layout.tiles ?? []), ...(layout.features ?? [])]), + ...(prefix ? [] : [...(layout.pointMarks ?? []), ...(layout.rows ?? [])]), + ].filter((mark) => mark && typeof mark === 'object' && typeof mark.type === 'string'); + marks.forEach((mark, i) => { + const at = `${prefix}${i}`; + markStyles[at] = markStyle(mark); + const bounds = markBounds(mark); + if (bounds) put('marks', at, bounds); + for (const key of ['label', 'subtitle', 'valueLabel']) + if (mark[key] && typeof mark[key].x === 'number') + put('labels', `${at}.${key}`, { x: mark[key].x, y: mark[key].y }); + }); + + (body.annotations ?? []).forEach((annotation: Any, i: number) => { + const at = `${prefix}${annotationKey(annotation, i)}`; + annotationStyles[at] = annotationStyle(annotation); + if (annotation.label) { + put('annotations', `${at}.label`, { x: annotation.label.x, y: annotation.label.y }); + put('annotations', `${at}.visible`, annotation.label.visible ? 1 : 0); + put('annotations', `${at}.lines`, (annotation.label.lines ?? []).join('\n')); + const connector = annotation.label.connector; + if (connector) + put('annotations', `${at}.connector`, { from: connector.from, to: connector.to }); + } + if (annotation.subtitle) + put('annotations', `${at}.subtitle`, { + x: annotation.subtitle.x, + y: annotation.subtitle.y, + }); + if (annotation.rect) put('annotations', `${at}.rect`, annotation.rect); + if (annotation.line) put('annotations', `${at}.line`, annotation.line); + if (annotation.dot) + put('annotations', `${at}.dot`, { x: annotation.dot.x, y: annotation.dot.y }); + }); + } + style.axes = axesStyles; + style.marks = markStyles; + style.annotations = annotationStyles; + + // Legends. + const legendStyles: Record = {}; + for (const [name, legend] of legendsOf(layout)) { + legendStyles[name] = legendStyle(legend); + if (legend.bounds) put('legend', `${name}.bounds`, legend.bounds); + for (const [i, entry] of (legend.entryPositions ?? []).entries()) + put('legend', `${name}.entry.${i}`, { x: entry.x, y: entry.y }); + if (legend.bar) put('legend', `${name}.bar`, legend.bar); + } + style.legends = legendStyles; + + // Endpoint labels. + const endpoint = layout.endpointLabels; + if (endpoint) { + const entryStyle = (entry: Any) => ({ + series: entry.seriesKey, + label: (entry.labelLines ?? []).join(' '), + value: entry.value, + color: entry.color, + marker: entry.marker + ? { + fill: entry.marker.fill, + stroke: entry.marker.stroke, + strokeWidth: entry.marker.strokeWidth, + radius: entry.marker.radius, + } + : null, + }); + style.endpointLabels = clean({ + labelStyle: textStyle(endpoint.labelStyle), + valueStyle: textStyle(endpoint.valueStyle), + swatchChipFill: endpoint.swatchChipFill, + entries: (endpoint.entries ?? []).map(entryStyle), + leading: (endpoint.leading ?? []).map(entryStyle), + }); + put('endpointLabels', 'bounds', endpoint.bounds); + if (endpoint.leadingBounds) put('endpointLabels', 'leadingBounds', endpoint.leadingBounds); + (endpoint.entries ?? []).forEach((entry: Any, i: number) => { + put('endpointLabels', `${i}.labelY`, entry.labelY); + put('endpointLabels', `${i}.lines`, (entry.labelLines ?? []).join('\n')); + }); + } + + // Tables: paint per cell, widths as geometry. + if (Array.isArray(layout.columns)) { + style.table = clean({ + density: layout.density, + striped: layout.striped, + columns: layout.columns.map((column: Any) => ({ + key: column.key, + label: column.label, + cellType: column.cellType, + align: column.align, + })), + rows: (layout.rows ?? []).map((row: Any) => + (row.cells ?? []).map((cell: Any) => [cell.formattedValue, cell.style ?? null]), + ), + }); + for (const column of layout.columns) put('marks', `column.${column.key}`, column.width); + } + + // Graphs: nodes and edges carry no positions until the force simulation runs. + if (Array.isArray(layout.edges)) { + style.graph = clean({ + nodes: (layout.nodes ?? []).map((node: Any) => ({ + id: node.id, + fill: node.fill, + stroke: node.stroke, + strokeWidth: node.strokeWidth, + opacity: node.opacity, + label: node.label ?? null, + })), + edges: layout.edges.map((edge: Any) => ({ + stroke: edge.stroke, + strokeWidth: edge.strokeWidth, + style: edge.style, + })), + }); + for (const node of layout.nodes ?? []) put('marks', `node.${node.id}.radius`, node.radius); + } + + return { style: clean(style) as Record, geometry }; +} + +/** Flatten a nested value into `path -> leaf` for diff reporting. */ +export function flatten(value: unknown, path = '', out: Record = {}) { + if (value && typeof value === 'object') { + const entries = Array.isArray(value) + ? value.map((child, i) => [String(i), child] as const) + : Object.entries(value); + if (!entries.length) out[path] = Array.isArray(value) ? '[]' : '{}'; + for (const [key, child] of entries) flatten(child, path ? `${path}.${key}` : key, out); + } else out[path] = value; + return out; +} diff --git a/examples/src/__tests__/v9-editorial-examples.test.ts b/examples/src/__tests__/v9-editorial-examples.test.ts new file mode 100644 index 00000000..7f5bd2bd --- /dev/null +++ b/examples/src/__tests__/v9-editorial-examples.test.ts @@ -0,0 +1,100 @@ +/// +import type { ChartSpec, LineMark, RectMark } from '@opendata-ai/openchart-core'; +import { describe, expect, it } from 'vitest'; +import { compileChart } from '../../../packages/engine/src/compile'; + +const modules = import.meta.glob( + [ + '../gallery/charts-bar-column.stories.tsx', + '../gallery/charts-line-area.stories.tsx', + '../gallery/features-annotations.stories.tsx', + '../gallery/showcase.stories.tsx', + '../gallery/welcome.stories.tsx', + '../testing/fixtures-bars.stories.tsx', + ], + { eager: true }, +) as Record }>; +const specFor = (file: string, name: string) => + modules[`../${file}.stories.tsx`].__authoredValues[name]; + +const populationExamples = [ + ['gallery/charts-bar-column', 'simpleBarsSpec'], + ['gallery/showcase', 'fullChromeSpec'], + ['testing/fixtures-bars', 'populationBarSpec'], +] as const; +const amazonExamples = [ + ['gallery/charts-line-area', 'fiveSeriesSpec'], + ['gallery/showcase', 'multiLineSpec'], + ['gallery/welcome', 'heroSpec'], +] as const; + +describe('v9 authored editorial choices', () => { + it.each( + populationExamples, + )('%s uses flat ranked population bars with explicit India/China emphasis', (file, name) => { + const original = specFor(file, name); + const spec = { ...original, data: [...original.data].reverse() } as ChartSpec; + const before = JSON.stringify(spec.data); + expect(spec.encoding.color).toMatchObject({ field: 'country', highlight: ['India', 'China'] }); + const layout = compileChart(spec, { width: 700, height: 500, onWarn: () => {} }); + expect(JSON.stringify(spec.data)).toBe(before); + const bars = layout.marks + .filter((mark): mark is RectMark => mark.type === 'rect') + .sort((a, b) => a.y - b.y); + expect(bars.map((bar) => bar.data.population)).toEqual( + [...bars.map((bar) => Number(bar.data.population))].sort((a, b) => b - a), + ); + expect(bars.map((bar) => bar.data.country).slice(0, 2)).toEqual(['India', 'China']); + expect(bars.every((bar) => typeof bar.fill === 'string')).toBe(true); + expect(bars[0].fill).not.toBe(bars[2].fill); + expect(bars[1].fill).not.toBe(bars[2].fill); + }); + + it.each( + amazonExamples, + )('%s explicitly focuses Amazon and labels every comparison series', (file, name) => { + const spec = specFor(file, name); + expect(spec.encoding.color).toMatchObject({ + field: 'company', + scale: { domain: ['Amazon', 'Apple', 'Alphabet', 'Microsoft', 'Meta'] }, + }); + expect(spec.seriesStyles).toMatchObject({ Amazon: { strokeWidth: 3 } }); + for (const width of [390, 1280]) { + const layout = compileChart(spec, { width, height: 460, onWarn: () => {} }); + const lines = layout.marks.filter((mark): mark is LineMark => mark.type === 'line'); + const amazon = lines.find((line) => line.seriesKey === 'Amazon')!; + expect(lines).toHaveLength(5); + expect( + lines + .filter((line) => line.seriesKey !== 'Amazon') + .every((line) => line.stroke !== amazon.stroke && line.strokeWidth < amazon.strokeWidth), + ).toBe(true); + expect(layout.endpointLabels?.entries.map((entry) => entry.seriesKey).sort()).toEqual([ + 'Alphabet', + 'Amazon', + 'Apple', + 'Meta', + 'Microsoft', + ]); + } + }); + + it('uses rule-relative placement instead of pixel offsets in reference-line examples', () => { + for (const spec of [ + specFor('gallery/charts-bar-column', 'simpleBarsSpec'), + specFor('gallery/showcase', 'fullChromeSpec'), + specFor('testing/fixtures-bars', 'populationBarSpec'), + specFor('gallery/charts-bar-column', 'columnsSpec'), + specFor('gallery/features-annotations', 'reflineSpec'), + ]) { + const rules = spec.annotations!.filter( + (annotation) => annotation.type === 'refline' && annotation.label, + ); + expect(rules.length).toBeGreaterThan(0); + for (const rule of rules) { + expect(rule).not.toHaveProperty('labelOffset'); + expect(rule).toHaveProperty('labelPlacement'); + } + } + }); +}); diff --git a/examples/src/charts/mobile-regression.stories.tsx b/examples/src/charts/mobile-regression.stories.tsx index 4feb8fc4..bc1e7b8f 100644 --- a/examples/src/charts/mobile-regression.stories.tsx +++ b/examples/src/charts/mobile-regression.stories.tsx @@ -468,3 +468,58 @@ export const ChromeMaxLines = () => (
); + +// Outside reference labels in a short, narrow figure (v9 review, Oct 2026). +// Three wrapped event labels plus a wrapped threshold label cannot all fit in +// the lanes above and beside a 400px-tall plot at ~358px wide. The top lane +// packs labels whose extents don't overlap into one row (2017 and 2022 share +// it), takes at most 25% of the height, and yields before chrome: at 400px the +// subtitle stays, one row sits above the plot, and the 2020 label falls back +// inside the plot on its own. Every label stays on canvas. +const referenceLaneOverflowSpec: ChartSpec = { + mark: 'line', + data: [2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024].map((year, i) => ({ + year: String(year), + rate: 4 + Math.sin(i / 1.5) * 1.6 + i * 0.25, + })), + encoding: { + x: { field: 'year', type: 'temporal', axis: { title: undefined } }, + y: { field: 'rate', type: 'quantitative', axis: { title: 'Unemployment rate (%)' } }, + }, + chrome: { + title: 'Three policy changes, one labor market', + subtitle: 'Unemployment rate around each policy event', + }, + annotations: [ + { + type: 'refline', + x: '2017', + label: 'Minimum wage increase takes effect statewide', + labelPlacement: 'outside', + }, + { + type: 'refline', + x: '2020', + label: 'Pandemic emergency declaration and closures', + labelPlacement: 'outside', + }, + { + type: 'refline', + x: '2022', + label: 'Expanded child tax credit expires nationwide', + labelPlacement: 'outside', + }, + { + type: 'refline', + y: 6, + label: 'Long-run average across the full period', + labelPlacement: 'outside', + }, + ], +}; + +export const ReferenceLaneOverflow = () => ( +
+ +
+); diff --git a/examples/src/gallery/attribution.stories.tsx b/examples/src/gallery/attribution.stories.tsx new file mode 100644 index 00000000..f32ff9ae --- /dev/null +++ b/examples/src/gallery/attribution.stories.tsx @@ -0,0 +1,139 @@ +import type { Chrome } from '@opendata-ai/openchart-core'; +import { + BarList, + Chart, + DataTable, + GeoMap, + Graph, + Sankey, + TileMap, +} from '@opendata-ai/openchart-react'; +import usStates from 'us-atlas/states-10m.json'; + +export default { title: 'Gallery / Attribution' }; +const values = [ + { name: 'North', value: 42 }, + { name: 'South', value: 31 }, + { name: 'West', value: 17 }, +]; +function Matrix({ custom = false, large = false }: { custom?: boolean; large?: boolean }) { + const chrome: Chrome = { + source: { + text: 'Source: County research office and administrative records, 2020–2025. Values are illustrative.', + ...(large ? { style: { fontSize: 24 } } : {}), + }, + byline: { text: 'Analysis: Open research team', ...(large ? { style: { fontSize: 24 } } : {}) }, + footer: 'Methods and coverage remain visible alongside the attribution.', + ...(custom + ? { brand: { text: 'Local research\nOpen methods', style: { fontSize: large ? 28 : 16 } } } + : {}), + }; + const card = { width: '100%', height: large ? 650 : 500 }; + return ( +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ ); +} +export const AllVisualizations = () => ; +export const CustomBrand = () => ; +export const LargeText = () => ; diff --git a/examples/src/gallery/charts-bar-column.stories.tsx b/examples/src/gallery/charts-bar-column.stories.tsx index 11a6f427..4bc81402 100644 --- a/examples/src/gallery/charts-bar-column.stories.tsx +++ b/examples/src/gallery/charts-bar-column.stories.tsx @@ -30,14 +30,24 @@ const ACCENT = '#0e7490'; const simpleBarsSpec: ChartSpec = { animation: true, - mark: { type: 'bar', fill: hBarGradient(ACCENT) }, + mark: 'bar', data: [...populationByCountry.data], encoding: { x: { field: 'population', type: 'quantitative', axis: { title: 'Population', format: '.2~s' } }, - y: { field: 'country', type: 'nominal' }, + y: { field: 'country', type: 'nominal', sort: 'x' }, + color: { field: 'country', type: 'nominal', highlight: ['India', 'China'] }, }, + legend: { show: false }, + labels: { color: 'var(--oc-text)' }, annotations: [ - { type: 'refline', x: 1_000_000_000, label: '1 billion', style: 'dashed', stroke: '#cc4444' }, + { + type: 'refline', + x: 1_000_000_000, + label: '1 billion', + labelPlacement: 'outside', + style: 'dashed', + stroke: '#cc4444', + }, ], chrome: { title: 'India Has Overtaken China as the Most Populous Country', @@ -76,7 +86,7 @@ const columnsSpec: ChartSpec = { style: 'dashed', stroke: '#64748b', strokeWidth: 1, - labelOffset: { dx: -560, dy: -10 }, + labelPlacement: 'outside', }, ], labels: { density: 'all', format: ',.0f' }, @@ -489,3 +499,140 @@ export const BarAndColumn = () => ( ); + +/** Explicit candidates for the desktop craft review; established defaults stay intact. */ +export const ValuePlacement = () => { + const ranked: ChartSpec = { + mark: { type: 'bar', size: 16 }, + data: [ + { name: 'Research', value: 128.4 }, + { name: 'Operations', value: 75.2 }, + { name: 'Training', value: 8.6 }, + { name: 'Contingency', value: 0 }, + { name: 'Adjustments', value: -24.3 }, + ], + encoding: { + x: { field: 'value', type: 'quantitative', axis: false }, + y: { + field: 'name', + type: 'nominal', + sort: null, + scale: { paddingInner: 0.35 }, + axis: { grid: false }, + }, + }, + labels: { + placement: 'column', + density: 'all', + format: '.1f', + suffix: 'M', + color: 'var(--oc-text)', + }, + legend: { show: false }, + chrome: { + title: 'Every budget adjustment has a place', + subtitle: 'Illustrative budget allocations, millions', + }, + }; + const signed: ChartSpec = { + ...ranked, + mark: { type: 'bar', size: 28 }, + encoding: { + x: { field: 'name', type: 'nominal', sort: null, scale: { paddingInner: 0.4 } }, + y: { field: 'value', type: 'quantitative', axis: { title: 'Millions' } }, + }, + labels: { + placement: 'outside', + density: 'all', + format: '.1f', + suffix: 'M', + color: 'var(--oc-text)', + }, + chrome: { + title: 'Positive and negative values follow their endpoints', + subtitle: 'The same observations, with explicit outside labels', + }, + }; + return ( + +
+ + + +
+
+ ); +}; + +export const FacetedValues = () => ( + +
+ +
+
+); diff --git a/examples/src/gallery/charts-line-area.stories.tsx b/examples/src/gallery/charts-line-area.stories.tsx index f410dc87..4c0f10df 100644 --- a/examples/src/gallery/charts-line-area.stories.tsx +++ b/examples/src/gallery/charts-line-area.stories.tsx @@ -146,7 +146,7 @@ const multiSeriesSpec: ChartSpec = { opacity: 0.06, }, ], - labels: { density: 'endpoints', format: '.1f' }, + endpointLabels: { format: '+.1f' }, chrome: { title: 'Three Economies, Three Recoveries', subtitle: 'Annual real GDP growth rate, 2018-2024', @@ -156,7 +156,7 @@ const multiSeriesSpec: ChartSpec = { }; // --------------------------------------------------------------------------- -// 3. Five series with legend — when direct labels stop working +// 3. Five series with explicit focus and readable comparison labels // --------------------------------------------------------------------------- const fiveSeriesSpec: ChartSpec = { @@ -170,13 +170,19 @@ const fiveSeriesSpec: ChartSpec = { type: 'quantitative', axis: { title: 'Annual revenue ($B)', format: ',.0f', grid: true }, }, - color: { field: 'company', type: 'nominal' }, + color: { + field: 'company', + type: 'nominal', + scale: { + domain: ['Amazon', 'Apple', 'Alphabet', 'Microsoft', 'Meta'], + range: ['#0e7490', '#7a858f', '#7a858f', '#7a858f', '#7a858f'], + }, + }, }, - // legend.position implies show:true; endpointLabels:false hands series - // identification to the legend alone (see the suppression truth table in - // packages/core/src/types/spec.ts) so the two keys don't duplicate. - legend: { position: 'top' }, - endpointLabels: false, + // Explicit focus mutes comparison strokes; direct labels keep every company identifiable. + legend: { show: false }, + endpointLabels: { content: 'label', showMarker: true }, + seriesStyles: { Amazon: { strokeWidth: 3 } }, labels: { density: 'none' }, chrome: { title: 'Amazon Pulls Away at the Top of Big Tech', @@ -235,8 +241,7 @@ const stackedAreaSpec: ChartSpec = { y: { field: 'energy', type: 'quantitative', - // Multi-series areas default to overlap; opt back into stacking with - // `stack: 'zero'` on the position channel when the story is parts-of-a-whole. + // Explicit zero stacking makes the composition over time clear. stack: 'zero', axis: { title: 'Share of primary energy (%)', format: '.0f', grid: true }, }, @@ -465,7 +470,7 @@ export const LineAndArea = () => (
( /> @@ -500,12 +505,12 @@ export const LineAndArea = () => (
@@ -558,3 +563,48 @@ export const LineAndArea = () => (
); + +/** Opt-in prototype: boundary geometry and source values remain unchanged. */ +export const StackedBandLabels = () => ( +
+ +
+); + +/** Candidate spacing comparison only: the library default remains 6px. */ +export const EndpointSpacingCandidate = () => ( +
+ {[6, 8].map((endpointEntryGap) => ( +
+ [ + { date: '2020-01-01', value: 5 + index * 3, series }, + { date: '2021-01-01', value: 10 + index * 0.1, series }, + ]), + encoding: { + x: { field: 'date', type: 'temporal' }, + y: { field: 'value', type: 'quantitative', scale: { domain: [0, 20] } }, + color: { field: 'series', type: 'nominal' }, + }, + endpointLabels: true, + animation: false, + theme: { spacing: { endpointEntryGap } }, + chrome: { + subtitle: 'Synthetic fixture with close final values; typography stays unchanged.', + title: `Endpoint block separation: ${endpointEntryGap}px`, + }, + }} + /> +
+ ))} +
+); diff --git a/examples/src/gallery/design-chart-candidates.stories.tsx b/examples/src/gallery/design-chart-candidates.stories.tsx new file mode 100644 index 00000000..51c62135 --- /dev/null +++ b/examples/src/gallery/design-chart-candidates.stories.tsx @@ -0,0 +1,224 @@ +/** Review-only B3 plates. Query variant=before|after, surface=light|dark, text=2. */ +import type { ChartSpec, ThemeConfig } from '@opendata-ai/openchart-core'; +import { compileChart } from '@opendata-ai/openchart-engine'; +import { Chart } from '@opendata-ai/openchart-react'; +import { useLayoutEffect, useRef, useState } from 'react'; +import { + energyMix, + populationByCountry, + renewableCapacityAdditions, + temperatureAnomaly, + usPayrolls, +} from '../data'; + +export default { title: 'Design Chart Craft' }; + +type Case = 'grid' | 'rows' | 'columns' | 'grouped' | 'endpoint' | 'band'; + +function chartCraftSpec(kind: Case, candidate: boolean, _dark: boolean, textScale = 1): ChartSpec { + const theme: ThemeConfig = { + fonts: { + sizes: { + title: 26 * textScale, + subtitle: 14 * textScale, + small: 12 * textScale, + body: 13 * textScale, + axisTick: 12 * textScale, + endpointLabel: 13 * textScale, + endpointValue: 12 * textScale, + }, + }, + }; + if (kind === 'grid') + theme.colors = { + gridline: { + light: candidate ? 'rgba(0,0,0,0.05)' : 'rgba(0,0,0,0.08)', + dark: 'rgba(255,255,255,0.06)', + }, + gridlineZero: { + light: candidate ? 'rgba(0,0,0,0.22)' : 'rgba(0,0,0,0.08)', + dark: candidate ? 'rgba(255,255,255,0.24)' : 'rgba(255,255,255,0.06)', + }, + }; + const shared: Partial = { animation: false, theme }; + if (kind === 'endpoint') + return { + ...shared, + mark: 'line', + data: ['A', 'B', 'C', 'D'].flatMap((series, index) => [ + { date: '2020-01-01', value: 5 + index * 3, series }, + { date: '2021-01-01', value: 10 + index * 0.1, series }, + ]), + encoding: { + x: { field: 'date', type: 'temporal' }, + y: { field: 'value', type: 'quantitative', scale: { domain: [0, 20] } }, + color: { field: 'series', type: 'nominal' }, + }, + endpointLabels: true, + theme: { ...theme, spacing: { endpointEntryGap: candidate ? 8 : 6 } }, + chrome: { + title: 'Close endpoints retain their identities', + subtitle: 'Existing synthetic gallery fixture; values and typography unchanged', + }, + }; + if (kind === 'band') + return { + ...shared, + mark: 'area', + data: [...energyMix.data], + encoding: { + x: { field: 'year', type: 'ordinal' }, + y: { + field: 'energy', + type: 'quantitative', + stack: 'zero', + axis: { title: 'Share of primary energy (%)', format: '.0f' }, + }, + color: { field: 'source', type: 'nominal' }, + }, + endpointLabels: { anchor: candidate ? 'band' : 'boundary' }, + legend: { show: false }, + chrome: { + title: 'Fossil fuels still dominate the mix', + subtitle: 'Global primary energy mix, 2015–2022 (% of total)', + source: energyMix.source, + }, + }; + if (kind === 'rows') + return { + ...shared, + mark: 'bar', + data: [...populationByCountry.data], + encoding: { + x: { + field: 'population', + type: 'quantitative', + axis: { title: 'Population', format: '.2~s' }, + }, + y: { + field: 'country', + type: 'nominal', + sort: 'x', + scale: candidate ? { paddingInner: 3 / 7, paddingOuter: 3 / 14 } : undefined, + }, + }, + labels: { density: 'all', format: '.2~s', fontSize: 13 * textScale }, + chrome: { + title: 'India leads the population ranking', + subtitle: 'Population by country, 2025 estimates', + source: populationByCountry.source, + }, + }; + if (kind === 'grouped') + return { + ...shared, + mark: 'bar', + data: [...renewableCapacityAdditions.data], + encoding: { + x: { + field: 'year', + type: 'nominal', + scale: candidate ? { paddingInner: 0.4, paddingOuter: 0.2 } : undefined, + }, + y: { + field: 'capacity', + type: 'quantitative', + stack: null, + axis: { title: 'Capacity added (GW)' }, + }, + color: { field: 'type', type: 'nominal' }, + }, + labels: { density: 'none' }, + chrome: { + title: 'Solar additions pull away from wind', + subtitle: 'Renewable capacity added, 2019–2023', + source: renewableCapacityAdditions.source, + }, + }; + if (kind === 'columns') + return { + ...shared, + mark: 'bar', + data: [...usPayrolls.data], + encoding: { + x: { + field: 'month', + type: 'nominal', + scale: candidate ? { paddingInner: 0.45, paddingOuter: 0.225 } : undefined, + }, + y: { field: 'jobs', type: 'quantitative', axis: { title: 'Jobs added (thousands)' } }, + }, + labels: { density: 'auto', format: ',.0f', fontSize: 13 * textScale }, + chrome: { + title: 'Hiring slowed during 2024', + subtitle: 'Monthly US nonfarm payroll additions', + source: usPayrolls.source, + }, + }; + return { + ...shared, + mark: 'bar', + data: [...temperatureAnomaly.data], + encoding: { + x: { field: 'year', type: 'ordinal' }, + y: { + field: 'anomaly', + type: 'quantitative', + axis: { title: 'Temperature anomaly (°C)', format: '+.1f' }, + }, + color: { field: 'trend', type: 'nominal' }, + }, + labels: { density: 'none' }, + chrome: { + title: 'Recent decades exceed the average', + subtitle: 'Global temperature relative to the 20th century', + source: temperatureAnomaly.source, + }, + }; +} + +function Plate({ kind }: { kind: Case }) { + const params = new URLSearchParams(window.location.search); + const candidate = params.get('variant') === 'after'; + const dark = params.get('surface') === 'dark'; + const textScale = params.get('text') === '2' ? 2 : 1; + const host = useRef(null); + const [width, setWidth] = useState(1024); + useLayoutEffect(() => { + const node = host.current; + if (!node) return; + const observer = new ResizeObserver(([entry]) => setWidth(entry.contentRect.width)); + observer.observe(node); + return () => observer.disconnect(); + }, []); + const spec = chartCraftSpec(kind, candidate, dark, textScale); + let height = 480 * textScale; + if (kind === 'rows' && candidate) { + const measured = compileChart(spec, { width, height }); + // Auto-height prototype: retain measured chrome/axis bands, change only + // the ten-row plot. With this padding denominator, step is exactly28px. + height = height - measured.area.height + populationByCountry.data.length * 28 * textScale; + } + return ( +
+ +
+ ); +} + +export const GridHierarchy = () => ; +export const BarRowRhythm = () => ; +export const ColumnRhythm = () => ; +export const GroupedColumnRhythm = () => ; + +export const EndpointBlocks = () => ; +export const StackedBandAnchors = () => ; diff --git a/examples/src/gallery/features-annotations.stories.tsx b/examples/src/gallery/features-annotations.stories.tsx index 590b5c36..2f0e2323 100644 --- a/examples/src/gallery/features-annotations.stories.tsx +++ b/examples/src/gallery/features-annotations.stories.tsx @@ -184,8 +184,7 @@ const richTextSpec: ChartSpec = { }, }; -// The lede stack: set `subtitle` and the primary line takes bold automatically, -// with the subtitle in muted regular below it. No fontWeight authoring. +// Primary text and subtitle are regular by default; author emphasis explicitly. const ledeSpec: ChartSpec = { animation: true, mark: 'line', @@ -220,7 +219,7 @@ const ledeSpec: ChartSpec = { ], chrome: { title: 'A Lede, Then the Context', - subtitle: 'Global surface temperature anomaly — subtitle promotes the first line to bold', + subtitle: 'Global surface temperature anomaly — a primary line with supporting context', source: temperatureAnomaly.source, byline: 'Chart: OpenChart', }, @@ -328,9 +327,7 @@ const reflineSpec: ChartSpec = { }, labels: { density: 'none' }, annotations: [ - // Horizontal target line, dashed. At the right edge the label sat on the - // Nov/Dec bars; slide it into the Jun–Aug valley, where the line runs - // clear above every bar top. + // Auto placement keeps the average label beside its rule as the chart resizes. { type: 'refline', y: 216, @@ -338,14 +335,9 @@ const reflineSpec: ChartSpec = { style: 'dashed', stroke: '#64748b', strokeWidth: 1, - labelAnchor: 'right', - labelOffset: { dx: -245 }, + labelPlacement: 'auto', }, - // Horizontal threshold, dotted, styled as a soft floor. Every bar except - // October crosses the 100K line, and October's gap has the storm-marker - // line running through it, so there is no bar-free stretch at label height. - // Park the label in the Jun–Aug valley above the bar tops instead; the red - // text ties it to the red dotted line below it. + // A reserved right gutter keeps the low threshold label clear of the bars. { type: 'refline', y: 100, @@ -353,10 +345,9 @@ const reflineSpec: ChartSpec = { style: 'dotted', stroke: '#d1495b', strokeWidth: 1, - labelAnchor: 'left', - labelOffset: { dx: 381, dy: -30 }, + labelPlacement: 'outside', }, - // Vertical marker with a raw strokeDash override (takes precedence over style). + // The event label uses the top lane; strokeDash takes precedence over style. { type: 'refline', x: 'Oct', @@ -364,7 +355,7 @@ const reflineSpec: ChartSpec = { strokeDash: [2, 3], stroke: '#94a3b8', strokeWidth: 1, - labelAnchor: 'top', + labelPlacement: 'outside', }, ], chrome: { @@ -629,7 +620,7 @@ export const Annotations = () => (
( @@ -715,9 +706,10 @@ export function AnnotationGestures() { let spec = structuredClone(annotationGestureSpec); let revision = 0; const chart = createChart(host.current, spec, { - editable: true, + interaction: 'edit', + darkMode: 'auto', revision, - onEditTransaction: (tx) => { + onEdit: (tx) => { const result = applyEditTransaction(spec, tx); if (!result.ok) throw new Error(result.error.reason); spec = result.spec; diff --git a/examples/src/gallery/features-edit-mode.demos.ts b/examples/src/gallery/features-edit-mode.demos.ts index 3389215a..8e4b0a2d 100644 --- a/examples/src/gallery/features-edit-mode.demos.ts +++ b/examples/src/gallery/features-edit-mode.demos.ts @@ -15,6 +15,6 @@ export const page: PageEntry = { export: 'Edit Mode', demos: [ { id: 'editor', title: 'The editor' }, - { id: 'editable-toggle', title: 'The editable prop' }, + { id: 'interaction-mode', title: 'The interaction prop' }, ], }; diff --git a/examples/src/gallery/features-edit-mode.stories.tsx b/examples/src/gallery/features-edit-mode.stories.tsx index 0b11e06b..9d31db2a 100644 --- a/examples/src/gallery/features-edit-mode.stories.tsx +++ b/examples/src/gallery/features-edit-mode.stories.tsx @@ -1,3 +1,4 @@ +import { applyEditTransaction } from '@opendata-ai/openchart-core'; /** * Features / Edit Mode — the interactive editing experience. * @@ -12,15 +13,8 @@ * Absorbs and replaces the old annotation-editing story. */ -import type { - AnnotationOffset, - ChartSpec, - ElementEdit, - ElementRef, - RangeAnnotation, - RefLineAnnotation, -} from '@opendata-ai/openchart-core'; -import { Chart, type ChartHandle } from '@opendata-ai/openchart-react'; +import type { ChartSpec, EditTransaction, ElementRef } from '@opendata-ai/openchart-core'; +import { Chart, type ChartHandle, type InteractionMode } from '@opendata-ai/openchart-react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { GalleryPage, Section } from '../components'; import { segmentRevenue } from '../data'; @@ -255,7 +249,7 @@ function StudioStyles() { // The editable spec surface (the parts a host app persists back) // --------------------------------------------------------------------------- -type EditableState = Pick; +type EditableState = Pick; function makePristineState(): EditableState { return { @@ -282,9 +276,7 @@ function makePristineState(): EditableState { y: 71.42, text: 'Holiday peak:\n$71.4B devices', fontSize: 11, - anchor: 'left', connector: true, - offset: { dx: -110, dy: -50 }, }, { type: 'text', @@ -292,9 +284,8 @@ function makePristineState(): EditableState { y: 22.17, text: 'Cloud overtakes\n2022 devices floor', fontSize: 11, - anchor: 'left', + anchor: 'top', connector: true, - offset: { dx: -30, dy: -34 }, }, ], chrome: { @@ -323,7 +314,7 @@ function buildSpec(state: EditableState): ChartSpec { }, color: { field: 'segment', type: 'nominal' }, }, - legend: { position: 'top' }, + legend: state.legend ?? { position: 'top' }, annotations: state.annotations, chrome: state.chrome, }; @@ -334,7 +325,7 @@ function buildSpec(state: EditableState): ChartSpec { // --------------------------------------------------------------------------- type LogEntry = { - callback: 'onSelect' | 'onDeselect' | 'onEdit' | 'onAnnotationEdit' | 'onTextEdit'; + callback: 'onSelect' | 'onDeselect' | 'onEdit'; detail: string; ts: number; }; @@ -343,22 +334,14 @@ const CALLBACK_COLOR: Record = { onSelect: '#06b6d4', onDeselect: '#94a3b8', onEdit: '#6366f1', - onAnnotationEdit: '#8b5cf6', - onTextEdit: '#ec4899', }; -const oneLine = (s: string) => s.replace(/\n/g, ' '); -const fmtOffset = (o?: AnnotationOffset) => - `{ dx: ${Math.round(o?.dx ?? 0)}, dy: ${Math.round(o?.dy ?? 0)} }`; - function describeRef(ref: ElementRef): string { switch (ref.type) { case 'annotation': return `annotation[${ref.index}]`; case 'chrome': return `chrome.${ref.key}`; - case 'series-label': - return `series "${ref.series}"`; case 'legend': return 'legend'; case 'legend-entry': @@ -458,130 +441,19 @@ function EditModeStudio() { [pushLog], ); - // Unified edit callback: covers connector drags, range/refline label drags, - // chrome/series/legend moves, and text edits. We persist the ones that map to - // our editable surface (annotations + chrome). + // Persist all authored operations atomically, including add/remove and legend edits. const handleEdit = useCallback( - (edit: ElementEdit) => { - switch (edit.type) { - case 'annotation': - setState((prev) => ({ - ...prev, - annotations: prev.annotations?.map((annotation, index) => - edit.element.type === 'annotation' && - index === edit.element.index && - annotation.type === 'text' - ? { - ...annotation, - offset: edit.offset, - ...(edit.anchor !== undefined ? { anchor: edit.anchor } : {}), - ...(edit.responsive !== undefined ? { responsive: edit.responsive } : {}), - } - : annotation, - ), - })); - pushLog( - 'onEdit', - `annotation[${'index' in edit.element ? edit.element.index : '?'}] "${oneLine(edit.annotation.text)}" → ${fmtOffset(edit.offset)}`, - ); - break; - case 'annotation-connector': - setState((prev) => ({ - ...prev, - annotations: prev.annotations?.map((a) => { - if (a.type === 'text' && a.text === edit.annotation.text) { - return { - ...a, - connectorOffset: { ...a.connectorOffset, [edit.endpoint]: edit.offset }, - }; - } - return a; - }), - })); - pushLog( - 'onEdit', - `connector[${'index' in edit.element ? edit.element.index : '?'}] ${edit.endpoint} → ${fmtOffset(edit.offset)}`, - ); - break; - case 'annotation-anchor': - { - const anchorIdx = edit.element.type === 'annotation' ? edit.element.index : -1; - setState((prev) => ({ - ...prev, - annotations: prev.annotations?.map((a, i) => - a.type === 'text' && i === anchorIdx ? { ...a, x: edit.x, y: edit.y } : a, - ), - })); - pushLog('onEdit', `anchor → x: ${edit.x}, y: ${String(edit.y).slice(0, 6)}`); - } - break; - case 'range-label': - setState((prev) => ({ - ...prev, - annotations: prev.annotations?.map((a) => - a.type === 'range' && (a as RangeAnnotation).label === edit.annotation.label - ? { ...a, labelOffset: edit.labelOffset } - : a, - ), - })); - pushLog( - 'onEdit', - `range label[${'index' in edit.element ? edit.element.index : '?'}] → ${fmtOffset(edit.labelOffset)}`, - ); - break; - case 'refline-label': - setState((prev) => ({ - ...prev, - annotations: prev.annotations?.map((a) => - a.type === 'refline' && (a as RefLineAnnotation).label === edit.annotation.label - ? { ...a, labelOffset: edit.labelOffset } - : a, - ), - })); - pushLog( - 'onEdit', - `refline label[${'index' in edit.element ? edit.element.index : '?'}] → ${fmtOffset(edit.labelOffset)}`, - ); - break; - case 'chrome': - setState((prev) => ({ - ...prev, - chrome: { ...prev.chrome, [edit.key]: { text: edit.text, offset: edit.offset } }, - })); - pushLog('onEdit', `chrome.${edit.key} → ${fmtOffset(edit.offset)}`); - break; - case 'text-edit': - setState((prev) => { - const annotations = [...(prev.annotations ?? [])]; - const chrome = { ...prev.chrome }; - if (edit.element.type === 'annotation') { - const ann = annotations[edit.element.index]; - if (ann?.type === 'text') - annotations[edit.element.index] = { ...ann, text: edit.newText }; - else if (ann?.type === 'range') - annotations[edit.element.index] = { ...ann, label: edit.newText }; - else if (ann?.type === 'refline') - annotations[edit.element.index] = { ...ann, label: edit.newText }; - } else if (edit.element.type === 'chrome') { - const cur = chrome[edit.element.key]; - chrome[edit.element.key] = - cur && typeof cur === 'object' ? { ...cur, text: edit.newText } : edit.newText; - } - return { ...prev, annotations, chrome }; - }); - pushLog('onEdit', `text "${oneLine(edit.oldText)}" → "${oneLine(edit.newText)}"`); - break; - case 'add': - setState((prev) => ({ - ...prev, - annotations: [...(prev.annotations ?? []), edit.annotation], - })); - pushLog('onEdit', `add annotation "${oneLine(edit.annotation.text)}"`); - break; - default: - pushLog('onEdit', edit.type); - break; - } + (transaction: EditTransaction) => { + setState((previous) => { + const result = applyEditTransaction(buildSpec(previous), transaction); + if (!result.ok) return previous; + return { + annotations: result.spec.annotations, + chrome: result.spec.chrome, + legend: result.spec.legend, + }; + }); + pushLog('onEdit', transaction.ops.map((op) => `${op.op} ${op.path}`).join(', ')); }, [pushLog], ); @@ -619,7 +491,7 @@ function EditModeStudio() {
{/* Editor */}
-
+
Esc to deselect. + annotation. Use arrows to nudge, Shift+arrow for 10px, and Tab/Shift+Tab to select. + Press Esc to deselect.

@@ -735,8 +608,14 @@ const TOGGLE_CSS = ` } `; -function EditableToggleDemo() { - const [editable, setEditable] = useState(false); +const MODE_STATUS: Record = { + read: 'No selection or editing; arrow keys move between data points', + select: 'Click or Tab selects; arrows still navigate data; nothing is edited', + edit: 'Select, drag, nudge, retitle, and delete; arrows nudge the selection', +}; + +function InteractionModeDemo() { + const [mode, setMode] = useState('read'); const [eventLog, setEventLog] = useState>([]); const spec: ChartSpec = { @@ -760,14 +639,12 @@ function EditableToggleDemo() { y: 71.42, text: 'Holiday peak', fontSize: 11, - anchor: 'left', connector: true, - offset: { dx: -90, dy: -40 }, }, ], chrome: { - title: 'Editable Toggle Demo', - subtitle: 'Toggle editable to enable/disable editing', + title: 'Interaction Mode Demo', + subtitle: 'Switch between read, select, and edit', }, }; @@ -777,8 +654,16 @@ function EditableToggleDemo() { ); }, []); - const handleEdit = useCallback((edit: ElementEdit) => { - setEventLog((prev) => [{ text: `onEdit: ${edit.type}`, ts: Date.now() }, ...prev].slice(0, 20)); + const handleEdit = useCallback((edit: EditTransaction) => { + setEventLog((prev) => + [ + { + text: `onEdit: ${edit.ops.map((op) => `${op.op} ${op.path}`).join(', ')}`, + ts: Date.now(), + }, + ...prev, + ].slice(0, 20), + ); }, []); return ( @@ -786,27 +671,28 @@ function EditableToggleDemo() { {/* biome-ignore lint/security/noDangerouslySetInnerHtml: static CSS constant, no user input */}