Per-chart export: copy/download spec and PNG/SVG from the preview header

This commit is contained in:
2026-06-10 18:30:31 +03:00
parent cad19445b0
commit 1791ee9f8d
15 changed files with 921 additions and 33 deletions
+36 -15
View File
@@ -25,7 +25,26 @@
Newest first. The at-a-glance build-order tracker is §4; per-item detail is §3. This log is
the quick "where are we" — read it first.
- **2026-06-10** — **Up next: 1B (per-chart export).**
- **2026-06-10** — **Up next: 1C (filter + calculate transforms), paired with 1D (data preview).**
- **1B · Per-chart export** shipped: an **Export** disclosure in the Live Preview header
(distinct from the workspace Export) — **Copy spec** + **Download JSON** (`.vl.json`) of
the shown text, and **Download PNG/SVG** of the live chart. Image output rides a new
`RenderHandle.toImageURL(format, { scale, background })` (PNG via `view.toCanvas`
`blob:` URL; SVG via `view.toSVG``data:` URL), so no component touches the Vega
`view`. Filenames derive from the snippet name — filesystem-safe, script-preserving
(pure `core/chart-export.ts`, tested). Home: the **preview header**, not the plan's
"library row / editor toolbar" — image export needs the live view; the
disclosure-of-controls (not an ARIA menu) mirrors `SettingsPopover`.
- **Export options (from first-round feedback):** PNG **Resolution** `1×/2×/3×` is a
multiplier of `devicePixelRatio`, so the default `1×` is Retina-crisp — the soft-1×
export was a dpr bug (raw `toImageURL` scaleFactor ignores dpr). **Background**
`Theme`(default)/`White`/`None` fixes transparent PNGs (the chart config is
transparent so the on-screen pane colour shows; export composites the chosen colour
under the PNG / adds an SVG `<rect>`). **Referenced data** `Inline`(default)/`Keep
refs` (shown only when the spec references saved datasets) inlines dataset values so
the exported spec renders standalone (`inlineReferencedDatasets`, tested).
- Spec §08 gained a _Per-chart export_ section (with the options); §04 cross-references
it; `architecture/05` §2 records the handle's dpr-aware scale + background compositing.
- **1A · Actionable hints** shipped: one-click fixes on guidance warnings
(`BuilderWarning.fixes` + `applyWarningFix`), council-reviewed, with focus/announce a11y.
- **Builder UX/perf batch** (from dogfooding the Superstore dataset) shipped: near-fullscreen
@@ -116,20 +135,22 @@ ghost buttons, remedy-in-button, polite "Applied: …" announcement, focus moved
removed button — resolution recorded in `architecture/10` §5. §06 "Guidance" amended to
document the one-click fixes.
**1B · Per-chart export**_highest value-to-effort overall_
Today export is workspace-backup only (§08); there is **no way to get one chart out**.
Source: Lyra §3.8. The renderer already holds the live Vega `view`
(`services/chart-renderer.ts`), so this is small:
**1B · Per-chart export**_done (2026-06-10)_
Today export was workspace-backup only (§08); there was **no way to get one chart out**.
Source: Lyra §3.8. Shipped as an **Export disclosure in the Live Preview header**:
- **Copy spec** (clipboard) + **Download `.vl.json`** for the active snippet (trivial — the
snippet _is_ the spec)
- **Download PNG / SVG** via `view.toImageURL('png' | 'svg')`
- _(optional)_ standalone HTML (ties to the BYO-cloud "private-move" direction)
- **Copy spec** (clipboard) + **Download `.vl.json`** of the currently-shown text.
- **Download PNG / SVG** of the live chart via a new `RenderHandle.toImageURL` wrapping
`view.toImageURL` (PNG at 2×`blob:` URL, revoked after download; SVG → `data:` URL),
so the embedding boundary holds — no component touches the raw view.
- Filenames from the snippet name, filesystem-safe and script-preserving (pure
`core/chart-export.ts`, tested). Standalone HTML left out (the deferred optional).
Home: a **snippet-level** "Export / Share" affordance (library row action or editor
toolbar), distinct from the workspace Export. _Spec impact: new export surface in §08;
arguably §02/§03 (where the affordance lives)._ Note: not strictly a _builder_ feature, but
the biggest single miss adjacent to it — sequence it here.
Home decision: the **preview header**, not the plan's original "library row / editor
toolbar" suggestion — the image formats need the live rendered view, and "export this
chart" reads best beside the chart. The widget is a disclosure-of-action-buttons (not an
ARIA menu), mirroring `SettingsPopover` and sharing its single-open registry. _Spec impact:
new §08 "Per-chart export" section; §04 cross-reference; `architecture/05` §2 handle note._
**1C · Filter (+ Calculate) dataset transforms**_closes the loop the builder's own warnings open_
The transform layer the builder doesn't touch: top-level `transform: []`. Source: Lyra
@@ -292,8 +313,8 @@ guardrail: _promote a control only when it is **both common AND awkward in JSON*
```
Phase 1 1A actionable hints ✓ done
1B per-chart export ← next: highest value-to-effort
1C filter (+ calculate) ← closes the loop on warnings the builder already emits
1B per-chart export ✓ done
1C filter (+ calculate) ← next: closes the loop on warnings the builder already emits
1D data preview ← pairs with 1C
1E expr-validate + autocomplete (with 1C)
Phase 2 2A value-or-field channels (Property model)