@opendata-ai/openchart-vanilla 8.3.1 → 8.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-ERRV4WFS.js → chunk-3UIUANPI.js} +37 -5
- package/dist/chunk-3UIUANPI.js.map +1 -0
- package/dist/{chunk-GRA2NIRZ.js → chunk-5A2NLYUW.js} +510 -94
- package/dist/chunk-5A2NLYUW.js.map +1 -0
- package/dist/{chunk-RM5XS6NR.js → chunk-5RX6ZQGZ.js} +25 -11
- package/dist/chunk-5RX6ZQGZ.js.map +1 -0
- package/dist/{chunk-T32UHMZA.js → chunk-6B5OBGIO.js} +2 -2
- package/dist/{chunk-W76C53MC.js → chunk-KANNWAEA.js} +192 -22
- package/dist/chunk-KANNWAEA.js.map +1 -0
- package/dist/{chunk-DCODCLWI.js → chunk-RYVV3YIG.js} +3 -3
- package/dist/export-gif.js +3 -3
- package/dist/index.d.ts +6 -1
- package/dist/index.js +306 -103
- package/dist/index.js.map +1 -1
- package/dist/static.js +3 -3
- package/dist/story/index.js +4 -4
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-ERRV4WFS.js.map +0 -1
- package/dist/chunk-GRA2NIRZ.js.map +0 -1
- package/dist/chunk-RM5XS6NR.js.map +0 -1
- package/dist/chunk-W76C53MC.js.map +0 -1
- /package/dist/{chunk-T32UHMZA.js.map → chunk-6B5OBGIO.js.map} +0 -0
- /package/dist/{chunk-DCODCLWI.js.map → chunk-RYVV3YIG.js.map} +0 -0
|
@@ -9,6 +9,14 @@ function setAttrs(el, attrs) {
|
|
|
9
9
|
el.setAttribute(key, String(value));
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
+
function applyKnockoutHalo(el, color, fontSize) {
|
|
13
|
+
setAttrs(el, {
|
|
14
|
+
stroke: color,
|
|
15
|
+
"stroke-width": Math.round(fontSize * 0.3),
|
|
16
|
+
"stroke-linejoin": "round",
|
|
17
|
+
"paint-order": "stroke"
|
|
18
|
+
});
|
|
19
|
+
}
|
|
12
20
|
function applyTextStyle(el, style) {
|
|
13
21
|
const inline = el.style;
|
|
14
22
|
inline.setProperty("fill", style.fill);
|
|
@@ -30,7 +38,7 @@ function applyTextStyle(el, style) {
|
|
|
30
38
|
import { adaptForLightLineStroke, cssTokenDefault } from "@opendata-ai/openchart-core";
|
|
31
39
|
function buildThemeStyleBlock(theme) {
|
|
32
40
|
const accent = theme.colors.categorical[0] ?? cssTokenDefault("--oc-accent", "light");
|
|
33
|
-
const bg = theme.colors.
|
|
41
|
+
const bg = theme.colors.neutral.surface;
|
|
34
42
|
const props = [
|
|
35
43
|
`--oc-font-family: ${theme.fonts.family}`,
|
|
36
44
|
`--oc-font-mono: ${theme.fonts.mono}`,
|
|
@@ -48,9 +56,12 @@ function buildThemeStyleBlock(theme) {
|
|
|
48
56
|
`--oc-bg: ${bg}`,
|
|
49
57
|
`--oc-text: ${theme.colors.text}`,
|
|
50
58
|
`--oc-text-muted: ${theme.colors.axis}`,
|
|
51
|
-
`--oc-text-
|
|
59
|
+
`--oc-text-secondary: ${theme.colors.neutral.secondary}`,
|
|
60
|
+
`--oc-text-faint: ${theme.colors.neutral.faint}`,
|
|
61
|
+
`--oc-border: ${theme.colors.neutral.border}`,
|
|
52
62
|
`--oc-gridline: ${theme.colors.gridline}`,
|
|
53
|
-
|
|
63
|
+
// Hairline, not the tick-label ink.
|
|
64
|
+
`--oc-axis: ${theme.colors.hairline}`,
|
|
54
65
|
`--oc-border-radius: ${theme.borderRadius}px`,
|
|
55
66
|
`--oc-accent: ${accent}`,
|
|
56
67
|
`--oc-accent-strong: ${adaptForLightLineStroke(accent)}`,
|
|
@@ -61,27 +72,29 @@ function buildThemeStyleBlock(theme) {
|
|
|
61
72
|
`--oc-space-4: ${theme.spacing.padding}px`
|
|
62
73
|
];
|
|
63
74
|
const rules = [
|
|
64
|
-
|
|
75
|
+
// Tabular figures everywhere in the chart's own text: axis ticks, value
|
|
76
|
+
// labels and legend entries all line up column-wise.
|
|
77
|
+
`svg.oc-chart { ${props.join("; ")}; font-variant-numeric: tabular-nums; }`,
|
|
65
78
|
`.oc-chrome { font-family: var(--oc-font-family); }`,
|
|
66
79
|
`.oc-eyebrow { font-size: var(--oc-eyebrow-size); font-weight: var(--oc-eyebrow-weight); letter-spacing: var(--oc-eyebrow-tracking); text-transform: uppercase; fill: var(--oc-accent); }`,
|
|
67
80
|
`.oc-title { font-size: var(--oc-title-size); font-weight: var(--oc-title-weight); letter-spacing: var(--oc-title-tracking); fill: var(--oc-text); }`,
|
|
68
81
|
`.oc-subtitle { font-size: var(--oc-subtitle-size); font-weight: var(--oc-subtitle-weight); fill: var(--oc-text-muted); }`,
|
|
69
82
|
`.oc-source, .oc-byline, .oc-footer { font-size: var(--oc-source-size); font-weight: var(--oc-source-weight); fill: var(--oc-text-muted); }`,
|
|
70
|
-
`.oc-brand { font-size: 11px; font-weight:
|
|
83
|
+
`.oc-brand { font-size: 11px; font-weight: 500; letter-spacing: 0.02em; fill: var(--oc-text-faint); }`,
|
|
71
84
|
`.oc-brand-dot { fill: var(--oc-accent); }`,
|
|
72
85
|
`.oc-eyebrow-dot { fill: var(--oc-accent); }`,
|
|
73
86
|
`.oc-metrics { font-family: var(--oc-font-family); }`,
|
|
74
|
-
`.oc-metric-label { font-size:
|
|
75
|
-
`.oc-metric-value { font-size: 22px; font-weight:
|
|
76
|
-
`.oc-metric-delta-up { fill: var(--oc-positive); font-size: 12px; font-weight:
|
|
77
|
-
`.oc-metric-delta-down { fill: var(--oc-negative); font-size: 12px; font-weight:
|
|
87
|
+
`.oc-metric-label { font-size: 11px; font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; fill: var(--oc-text-muted); }`,
|
|
88
|
+
`.oc-metric-value { font-size: 22px; font-weight: 600; letter-spacing: -0.02em; fill: var(--oc-text); font-variant-numeric: tabular-nums; }`,
|
|
89
|
+
`.oc-metric-delta-up { fill: var(--oc-positive); font-size: 12px; font-weight: 500; }`,
|
|
90
|
+
`.oc-metric-delta-down { fill: var(--oc-negative); font-size: 12px; font-weight: 500; }`,
|
|
78
91
|
`.oc-axis-tick-inline { font-size: 11px; font-weight: 400; fill: var(--oc-text-muted); }`,
|
|
79
92
|
`.oc-endpoint-labels { font-family: var(--oc-font-family); }`,
|
|
80
93
|
`.oc-endpoint-label { fill: var(--oc-endpoint-label-color, var(--oc-text)); }`,
|
|
81
94
|
`.oc-endpoint-value { fill: var(--oc-endpoint-value-color, var(--oc-text-muted)); }`,
|
|
82
95
|
`.oc-endpoint-leader { stroke: var(--oc-endpoint-leader-color, currentColor); }`,
|
|
83
96
|
`.oc-annotation-subtitle { fill: var(--oc-annotation-subtitle-color, var(--oc-text-muted)); }`,
|
|
84
|
-
`.oc-metric-secondary { fill: var(--oc-
|
|
97
|
+
`.oc-metric-secondary { fill: var(--oc-text-muted); font-size: 12px; font-weight: 400; }`,
|
|
85
98
|
`.oc-legend { font-family: var(--oc-font-family); font-size: var(--oc-body-size); }`,
|
|
86
99
|
`.oc-legend-entry { cursor: default; }`,
|
|
87
100
|
`.oc-legend text { fill: var(--oc-legend-text); }`
|
|
@@ -106,8 +119,9 @@ export {
|
|
|
106
119
|
XLINK_NS,
|
|
107
120
|
createSVGElement,
|
|
108
121
|
setAttrs,
|
|
122
|
+
applyKnockoutHalo,
|
|
109
123
|
applyTextStyle,
|
|
110
124
|
buildThemeStyleBlock,
|
|
111
125
|
injectThemeStyleBlock
|
|
112
126
|
};
|
|
113
|
-
//# sourceMappingURL=chunk-
|
|
127
|
+
//# sourceMappingURL=chunk-5RX6ZQGZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/renderers/svg-dom.ts","../src/theme-style-block.ts"],"sourcesContent":["/**\n * Shared SVG DOM helpers used across the per-concern renderers.\n *\n * Pure, stateless utilities. No layout/theme knowledge.\n */\n\nimport type { TextStyle } from '@opendata-ai/openchart-core';\n\nexport const SVG_NS = 'http://www.w3.org/2000/svg';\nexport const XLINK_NS = 'http://www.w3.org/1999/xlink';\n\nexport function createSVGElement(tag: string): SVGElement {\n return document.createElementNS(SVG_NS, tag);\n}\n\nexport function setAttrs(el: SVGElement, attrs: Record<string, string | number>): void {\n for (const [key, value] of Object.entries(attrs)) {\n el.setAttribute(key, String(value));\n }\n}\n\n/**\n * Cut a knockout halo behind text so it stays legible where it crosses\n * gridlines, marks, or a neighbouring series: a surface-colored stroke painted\n * under the glyphs.\n *\n * Presentation attributes, not inline styles, so a stylesheet can still\n * override the halo. The width scales with the font size -- a fixed width rings\n * small glyphs and disappears behind large ones.\n */\nexport function applyKnockoutHalo(el: SVGElement, color: string, fontSize: number): void {\n setAttrs(el, {\n stroke: color,\n 'stroke-width': Math.round(fontSize * 0.3),\n 'stroke-linejoin': 'round',\n 'paint-order': 'stroke',\n });\n}\n\nexport function applyTextStyle(el: SVGElement, style: TextStyle): void {\n // Use inline styles so engine-computed values take priority over CSS class\n // defaults (e.g. .oc-title { font-size: var(--oc-title-size) } would otherwise\n // override the responsive scaling applied by the chrome layout).\n const inline = (el as SVGElement & ElementCSSInlineStyle).style;\n inline.setProperty('fill', style.fill);\n inline.setProperty('font-size', `${style.fontSize}px`);\n inline.setProperty('font-weight', String(style.fontWeight));\n inline.setProperty('font-family', style.fontFamily);\n if (style.textAnchor) {\n el.setAttribute('text-anchor', style.textAnchor);\n }\n if (style.dominantBaseline) {\n el.setAttribute('dominant-baseline', style.dominantBaseline);\n }\n if (style.fontVariant) {\n el.setAttribute('font-variant', style.fontVariant);\n }\n}\n","/**\n * Theme `<style>` block for self-contained SVG export.\n *\n * Charts render most fills as inline SVG attributes, but a handful of chrome\n * elements (metric cells, the brand watermark dot, legend text, endpoint labels)\n * take their fill from CSS classes in `chrome.css` via `--oc-*` variables. That\n * works on-screen because the live SVG inherits the page stylesheet — but a\n * serialized/rasterized export (PNG/JPG/GIF) is detached from the page, so those\n * class-based fills vanish. This module builds a `<style>` block that resolves\n * every such rule against a concrete `ResolvedTheme`, so injecting it into an\n * export clone makes the SVG fully self-contained.\n *\n * Both the headless renderer (`static.ts`) and the browser export path use this,\n * so class-based styling round-trips identically no matter which path produced\n * the SVG. Browser-safe (no Node imports) so the browser exporters can import it.\n */\n\nimport type { ResolvedTheme } from '@opendata-ai/openchart-core';\nimport { adaptForLightLineStroke, cssTokenDefault } from '@opendata-ai/openchart-core';\nimport { SVG_NS } from './renderers/svg-dom';\n\n/**\n * Build the theme `<style>` block CSS text for a resolved theme. Sets the\n * `--oc-*` custom properties on `svg.oc-chart` and defines every class-based\n * chrome rule against them.\n */\nexport function buildThemeStyleBlock(theme: ResolvedTheme): string {\n const accent = theme.colors.categorical[0] ?? cssTokenDefault('--oc-accent', 'light');\n const bg = theme.colors.neutral.surface;\n\n const props = [\n `--oc-font-family: ${theme.fonts.family}`,\n `--oc-font-mono: ${theme.fonts.mono}`,\n `--oc-title-size: ${theme.chrome.title.fontSize}px`,\n `--oc-title-weight: ${theme.chrome.title.fontWeight}`,\n `--oc-title-tracking: ${cssTokenDefault('--oc-title-tracking', 'light')}`,\n `--oc-subtitle-size: ${theme.chrome.subtitle.fontSize}px`,\n `--oc-subtitle-weight: ${theme.chrome.subtitle.fontWeight}`,\n `--oc-source-size: ${theme.chrome.source.fontSize}px`,\n `--oc-source-weight: ${theme.chrome.source.fontWeight}`,\n `--oc-body-size: ${theme.fonts.sizes.body}px`,\n `--oc-eyebrow-size: ${theme.chrome.eyebrow.fontSize}px`,\n `--oc-eyebrow-weight: ${theme.chrome.eyebrow.fontWeight}`,\n `--oc-eyebrow-tracking: ${cssTokenDefault('--oc-eyebrow-tracking', 'light')}`,\n `--oc-bg: ${bg}`,\n `--oc-text: ${theme.colors.text}`,\n `--oc-text-muted: ${theme.colors.axis}`,\n `--oc-text-secondary: ${theme.colors.neutral.secondary}`,\n `--oc-text-faint: ${theme.colors.neutral.faint}`,\n `--oc-border: ${theme.colors.neutral.border}`,\n `--oc-gridline: ${theme.colors.gridline}`,\n // Hairline, not the tick-label ink.\n `--oc-axis: ${theme.colors.hairline}`,\n `--oc-border-radius: ${theme.borderRadius}px`,\n `--oc-accent: ${accent}`,\n `--oc-accent-strong: ${adaptForLightLineStroke(accent)}`,\n `--oc-positive: ${theme.colors.positive}`,\n `--oc-negative: ${theme.colors.negative}`,\n `--oc-legend-text: ${theme.isDark ? cssTokenDefault('--oc-legend-text', 'dark') : cssTokenDefault('--oc-legend-text', 'light')}`,\n `--oc-space-2: ${theme.spacing.chromeGap * 2}px`,\n `--oc-space-4: ${theme.spacing.padding}px`,\n ];\n\n const rules = [\n // Tabular figures everywhere in the chart's own text: axis ticks, value\n // labels and legend entries all line up column-wise.\n `svg.oc-chart { ${props.join('; ')}; font-variant-numeric: tabular-nums; }`,\n `.oc-chrome { font-family: var(--oc-font-family); }`,\n `.oc-eyebrow { font-size: var(--oc-eyebrow-size); font-weight: var(--oc-eyebrow-weight); letter-spacing: var(--oc-eyebrow-tracking); text-transform: uppercase; fill: var(--oc-accent); }`,\n `.oc-title { font-size: var(--oc-title-size); font-weight: var(--oc-title-weight); letter-spacing: var(--oc-title-tracking); fill: var(--oc-text); }`,\n `.oc-subtitle { font-size: var(--oc-subtitle-size); font-weight: var(--oc-subtitle-weight); fill: var(--oc-text-muted); }`,\n `.oc-source, .oc-byline, .oc-footer { font-size: var(--oc-source-size); font-weight: var(--oc-source-weight); fill: var(--oc-text-muted); }`,\n `.oc-brand { font-size: 11px; font-weight: 500; letter-spacing: 0.02em; fill: var(--oc-text-faint); }`,\n `.oc-brand-dot { fill: var(--oc-accent); }`,\n `.oc-eyebrow-dot { fill: var(--oc-accent); }`,\n `.oc-metrics { font-family: var(--oc-font-family); }`,\n `.oc-metric-label { font-size: 11px; font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; fill: var(--oc-text-muted); }`,\n `.oc-metric-value { font-size: 22px; font-weight: 600; letter-spacing: -0.02em; fill: var(--oc-text); font-variant-numeric: tabular-nums; }`,\n `.oc-metric-delta-up { fill: var(--oc-positive); font-size: 12px; font-weight: 500; }`,\n `.oc-metric-delta-down { fill: var(--oc-negative); font-size: 12px; font-weight: 500; }`,\n `.oc-axis-tick-inline { font-size: 11px; font-weight: 400; fill: var(--oc-text-muted); }`,\n `.oc-endpoint-labels { font-family: var(--oc-font-family); }`,\n `.oc-endpoint-label { fill: var(--oc-endpoint-label-color, var(--oc-text)); }`,\n `.oc-endpoint-value { fill: var(--oc-endpoint-value-color, var(--oc-text-muted)); }`,\n `.oc-endpoint-leader { stroke: var(--oc-endpoint-leader-color, currentColor); }`,\n `.oc-annotation-subtitle { fill: var(--oc-annotation-subtitle-color, var(--oc-text-muted)); }`,\n `.oc-metric-secondary { fill: var(--oc-text-muted); font-size: 12px; font-weight: 400; }`,\n `.oc-legend { font-family: var(--oc-font-family); font-size: var(--oc-body-size); }`,\n `.oc-legend-entry { cursor: default; }`,\n `.oc-legend text { fill: var(--oc-legend-text); }`,\n ];\n\n return rules.join('\\n');\n}\n\n/**\n * Inject the theme style block into an SVG clone's `<defs>` so class-based fills\n * survive serialization. Idempotent-ish: adds one `<style data-oc-theme>` at the\n * front of `<defs>`; call once per clone before serializing. No-op if `theme` is\n * undefined (nothing to resolve against).\n */\nexport function injectThemeStyleBlock(svg: SVGElement, theme: ResolvedTheme | undefined): void {\n if (!theme) return;\n let defs = svg.querySelector('defs');\n if (!defs) {\n defs = document.createElementNS(SVG_NS, 'defs');\n svg.insertBefore(defs, svg.firstChild);\n }\n const style = document.createElementNS(SVG_NS, 'style');\n style.setAttribute('data-oc-theme', '');\n style.textContent = buildThemeStyleBlock(theme);\n defs.insertBefore(style, defs.firstChild);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
injectThemeStyleBlock
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5RX6ZQGZ.js";
|
|
4
4
|
|
|
5
5
|
// src/export.ts
|
|
6
6
|
function getSVGDimensions(svg) {
|
|
@@ -279,4 +279,4 @@ export {
|
|
|
279
279
|
exportJPG,
|
|
280
280
|
exportCSV
|
|
281
281
|
};
|
|
282
|
-
//# sourceMappingURL=chunk-
|
|
282
|
+
//# sourceMappingURL=chunk-6B5OBGIO.js.map
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SVG_NS,
|
|
3
3
|
XLINK_NS,
|
|
4
|
+
applyKnockoutHalo,
|
|
4
5
|
applyTextStyle,
|
|
5
6
|
createSVGElement,
|
|
6
7
|
setAttrs
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-5RX6ZQGZ.js";
|
|
8
9
|
|
|
9
10
|
// src/svg-ids.ts
|
|
10
11
|
var counter = 0;
|
|
@@ -156,15 +157,22 @@ function resolvePatternFill(pattern, patternMap) {
|
|
|
156
157
|
var currentAnimation;
|
|
157
158
|
var currentGradientMap = /* @__PURE__ */ new Map();
|
|
158
159
|
var currentPatternMap = /* @__PURE__ */ new Map();
|
|
160
|
+
var currentSurface = "";
|
|
159
161
|
function setMarkRenderState(state) {
|
|
160
162
|
currentAnimation = state.animation;
|
|
161
163
|
currentGradientMap = state.gradientMap;
|
|
162
164
|
currentPatternMap = state.patternMap ?? /* @__PURE__ */ new Map();
|
|
165
|
+
currentSurface = state.surface ?? "";
|
|
163
166
|
}
|
|
164
167
|
function resetMarkRenderState() {
|
|
165
168
|
currentAnimation = void 0;
|
|
166
169
|
currentGradientMap = /* @__PURE__ */ new Map();
|
|
167
170
|
currentPatternMap = /* @__PURE__ */ new Map();
|
|
171
|
+
currentSurface = "";
|
|
172
|
+
}
|
|
173
|
+
function applyLabelHalo(text, label) {
|
|
174
|
+
if (!currentSurface || label.halo === false) return;
|
|
175
|
+
applyKnockoutHalo(text, currentSurface, label.style.fontSize);
|
|
168
176
|
}
|
|
169
177
|
function resolveFillOrPattern(fill, pattern) {
|
|
170
178
|
if (pattern) return resolvePatternFill(pattern, currentPatternMap);
|
|
@@ -195,7 +203,11 @@ function renderLineMark(mark, index) {
|
|
|
195
203
|
d,
|
|
196
204
|
fill: "none",
|
|
197
205
|
stroke: mark.stroke,
|
|
198
|
-
"stroke-width": mark.strokeWidth
|
|
206
|
+
"stroke-width": mark.strokeWidth,
|
|
207
|
+
// Round joins/caps: at 2px a mitre on a sharp data spike renders as a
|
|
208
|
+
// spur past the vertex, and a butt cap leaves a squared-off line end.
|
|
209
|
+
"stroke-linejoin": "round",
|
|
210
|
+
"stroke-linecap": "round"
|
|
199
211
|
});
|
|
200
212
|
if (mark.strokeDasharray) {
|
|
201
213
|
path.setAttribute("stroke-dasharray", mark.strokeDasharray);
|
|
@@ -213,6 +225,7 @@ function renderLineMark(mark, index) {
|
|
|
213
225
|
}
|
|
214
226
|
setAttrs(label, { x: mark.label.x, y: mark.label.y });
|
|
215
227
|
applyTextStyle(label, mark.label.style);
|
|
228
|
+
applyLabelHalo(label, mark.label);
|
|
216
229
|
label.textContent = mark.label.text;
|
|
217
230
|
g.appendChild(label);
|
|
218
231
|
if (mark.label.connector) {
|
|
@@ -253,7 +266,9 @@ function renderAreaMark(mark, index) {
|
|
|
253
266
|
d: mark.topPath,
|
|
254
267
|
fill: "none",
|
|
255
268
|
stroke: mark.stroke,
|
|
256
|
-
"stroke-width": mark.strokeWidth ?? 1
|
|
269
|
+
"stroke-width": mark.strokeWidth ?? 1,
|
|
270
|
+
"stroke-linejoin": "round",
|
|
271
|
+
"stroke-linecap": "round"
|
|
257
272
|
});
|
|
258
273
|
g.appendChild(strokePath);
|
|
259
274
|
}
|
|
@@ -311,6 +326,9 @@ function renderRectMark(mark, index) {
|
|
|
311
326
|
if (mark.strokeWidth) {
|
|
312
327
|
shapeEl.setAttribute("stroke-width", String(mark.strokeWidth));
|
|
313
328
|
}
|
|
329
|
+
if (mark.shapeRendering) {
|
|
330
|
+
shapeEl.setAttribute("shape-rendering", mark.shapeRendering);
|
|
331
|
+
}
|
|
314
332
|
g.appendChild(shapeEl);
|
|
315
333
|
return g;
|
|
316
334
|
}
|
|
@@ -336,6 +354,7 @@ function renderArcMark(mark, index) {
|
|
|
336
354
|
y: mark.label.y - mark.center.y
|
|
337
355
|
});
|
|
338
356
|
applyTextStyle(label, mark.label.style);
|
|
357
|
+
applyLabelHalo(label, mark.label);
|
|
339
358
|
label.textContent = mark.label.text;
|
|
340
359
|
g.appendChild(label);
|
|
341
360
|
}
|
|
@@ -402,6 +421,9 @@ function renderRuleMark(mark, index) {
|
|
|
402
421
|
if (mark.strokeDasharray) {
|
|
403
422
|
line.setAttribute("stroke-dasharray", mark.strokeDasharray);
|
|
404
423
|
}
|
|
424
|
+
if (mark.strokeOpacity != null) {
|
|
425
|
+
line.setAttribute("stroke-opacity", String(mark.strokeOpacity));
|
|
426
|
+
}
|
|
405
427
|
if (mark.opacity != null) {
|
|
406
428
|
line.setAttribute("opacity", String(mark.opacity));
|
|
407
429
|
}
|
|
@@ -454,6 +476,10 @@ function getMarkSeries(mark) {
|
|
|
454
476
|
if (mark.type === "line" || mark.type === "area") {
|
|
455
477
|
return mark.seriesKey;
|
|
456
478
|
}
|
|
479
|
+
const explicitSeries = mark.seriesKey;
|
|
480
|
+
if (explicitSeries) {
|
|
481
|
+
return explicitSeries;
|
|
482
|
+
}
|
|
457
483
|
if (mark.type === "arc") {
|
|
458
484
|
const label = mark.aria.label;
|
|
459
485
|
if (!label) return void 0;
|
|
@@ -513,6 +539,7 @@ function renderMarks(parent, layout, opts) {
|
|
|
513
539
|
label.setAttribute("class", "oc-mark-label");
|
|
514
540
|
setAttrs(label, { x: rect.label.x, y: rect.label.y });
|
|
515
541
|
applyTextStyle(label, rect.label.style);
|
|
542
|
+
applyLabelHalo(label, rect.label);
|
|
516
543
|
label.textContent = rect.label.text;
|
|
517
544
|
if (currentAnimation?.enter) {
|
|
518
545
|
const idx = rect.animationIndex ?? i;
|
|
@@ -558,6 +585,61 @@ import {
|
|
|
558
585
|
DEFAULT_LINE_HEIGHT,
|
|
559
586
|
parseAnnotationSpans
|
|
560
587
|
} from "@opendata-ai/openchart-engine";
|
|
588
|
+
|
|
589
|
+
// src/theme-tokens.ts
|
|
590
|
+
import { adaptForLightLineStroke, cssTokenDefault } from "@opendata-ai/openchart-core";
|
|
591
|
+
function resolvedSurface(theme) {
|
|
592
|
+
return theme.colors.neutral.surface;
|
|
593
|
+
}
|
|
594
|
+
function stampThemeProperties(el, theme) {
|
|
595
|
+
const accent = theme.colors.categorical[0] ?? cssTokenDefault("--oc-accent", "light");
|
|
596
|
+
const bg = resolvedSurface(theme);
|
|
597
|
+
const n = theme.colors.neutral;
|
|
598
|
+
const props = [
|
|
599
|
+
["--oc-font-family", theme.fonts.family],
|
|
600
|
+
["--oc-font-mono", theme.fonts.mono],
|
|
601
|
+
["--oc-title-size", `${theme.chrome.title.fontSize}px`],
|
|
602
|
+
["--oc-title-weight", `${theme.chrome.title.fontWeight}`],
|
|
603
|
+
["--oc-subtitle-size", `${theme.chrome.subtitle.fontSize}px`],
|
|
604
|
+
["--oc-subtitle-weight", `${theme.chrome.subtitle.fontWeight}`],
|
|
605
|
+
["--oc-source-size", `${theme.chrome.source.fontSize}px`],
|
|
606
|
+
["--oc-source-weight", `${theme.chrome.source.fontWeight}`],
|
|
607
|
+
["--oc-body-size", `${theme.fonts.sizes.body}px`],
|
|
608
|
+
["--oc-eyebrow-size", `${theme.chrome.eyebrow.fontSize}px`],
|
|
609
|
+
["--oc-eyebrow-weight", `${theme.chrome.eyebrow.fontWeight}`],
|
|
610
|
+
["--oc-bg", bg],
|
|
611
|
+
["--oc-text", theme.colors.text],
|
|
612
|
+
["--oc-text-muted", theme.colors.axis],
|
|
613
|
+
// Secondary grays are derived from the theme's own text/background pair
|
|
614
|
+
// (ResolvedTheme.colors.neutral), so a warm or cool theme gets warm or
|
|
615
|
+
// cool grays instead of zinc. One direction only: theme -> CSS.
|
|
616
|
+
["--oc-text-secondary", n.secondary],
|
|
617
|
+
["--oc-text-faint", n.faint],
|
|
618
|
+
["--oc-border", n.border],
|
|
619
|
+
["--oc-gray-100", n[100]],
|
|
620
|
+
["--oc-gray-200", n[200]],
|
|
621
|
+
["--oc-gray-300", n[300]],
|
|
622
|
+
["--oc-gray-400", n[400]],
|
|
623
|
+
["--oc-gray-600", n[600]],
|
|
624
|
+
["--oc-gray-800", n[800]],
|
|
625
|
+
["--oc-gridline", theme.colors.gridline],
|
|
626
|
+
// --oc-axis is the hairline the axis line is drawn with, not the ink its
|
|
627
|
+
// tick labels take (that is --oc-text-muted, above).
|
|
628
|
+
["--oc-axis", theme.colors.hairline],
|
|
629
|
+
["--oc-border-radius", `${theme.borderRadius}px`],
|
|
630
|
+
["--oc-accent", accent],
|
|
631
|
+
["--oc-accent-strong", adaptForLightLineStroke(accent)],
|
|
632
|
+
["--oc-positive", theme.colors.positive],
|
|
633
|
+
["--oc-negative", theme.colors.negative],
|
|
634
|
+
["--oc-space-2", `${theme.spacing.chromeGap * 2}px`],
|
|
635
|
+
["--oc-space-4", `${theme.spacing.padding}px`]
|
|
636
|
+
];
|
|
637
|
+
for (const [name, value] of props) {
|
|
638
|
+
el.style.setProperty(name, value);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// src/renderers/annotations.ts
|
|
561
643
|
var CONNECTOR_STROKE_WIDTH = 1.25;
|
|
562
644
|
function renderArrowhead(parent, tipX, tipY, tangentX, tangentY, stroke) {
|
|
563
645
|
const head = computeArrowheadPoints(tipX, tipY, tangentX, tangentY);
|
|
@@ -785,10 +867,7 @@ function renderAnnotation(parent, annotation, index, bgColor) {
|
|
|
785
867
|
});
|
|
786
868
|
g.appendChild(bgRect);
|
|
787
869
|
} else if (bgColor && annotation.label.halo !== false) {
|
|
788
|
-
text
|
|
789
|
-
text.style.stroke = bgColor;
|
|
790
|
-
text.style.strokeWidth = `${Math.round(fontSize * 0.3)}px`;
|
|
791
|
-
text.style.strokeLinejoin = "round";
|
|
870
|
+
applyKnockoutHalo(text, bgColor, fontSize);
|
|
792
871
|
}
|
|
793
872
|
g.appendChild(text);
|
|
794
873
|
if (annotation.subtitle) {
|
|
@@ -808,7 +887,7 @@ function renderAnnotations(parent, layout) {
|
|
|
808
887
|
if (layout.annotations.length === 0) return;
|
|
809
888
|
const g = createSVGElement("g");
|
|
810
889
|
g.setAttribute("class", "oc-annotations");
|
|
811
|
-
const bgColor = layout.theme
|
|
890
|
+
const bgColor = resolvedSurface(layout.theme);
|
|
812
891
|
for (let i = 0; i < layout.annotations.length; i++) {
|
|
813
892
|
renderAnnotation(g, layout.annotations[i], i, bgColor);
|
|
814
893
|
}
|
|
@@ -1172,7 +1251,22 @@ function renderChrome(parent, layout) {
|
|
|
1172
1251
|
const g = createSVGElement("g");
|
|
1173
1252
|
g.setAttribute("class", "oc-chrome");
|
|
1174
1253
|
const { chrome, measureText } = layout;
|
|
1175
|
-
if (chrome.
|
|
1254
|
+
if (chrome.rule) {
|
|
1255
|
+
const rule = createSVGElement("rect");
|
|
1256
|
+
rule.setAttribute("class", "oc-chrome-rule");
|
|
1257
|
+
setAttrs(rule, {
|
|
1258
|
+
x: chrome.rule.x,
|
|
1259
|
+
y: chrome.rule.y,
|
|
1260
|
+
width: chrome.rule.width,
|
|
1261
|
+
height: chrome.rule.thickness
|
|
1262
|
+
});
|
|
1263
|
+
rule.setAttribute("fill", chrome.rule.color);
|
|
1264
|
+
rule.setAttribute("shape-rendering", "crispEdges");
|
|
1265
|
+
g.appendChild(rule);
|
|
1266
|
+
}
|
|
1267
|
+
if (chrome.eyebrow && chrome.rule) {
|
|
1268
|
+
renderChromeElement(g, chrome.eyebrow, "oc-eyebrow", "eyebrow", measureText, true);
|
|
1269
|
+
} else if (chrome.eyebrow) {
|
|
1176
1270
|
const eyebrow = chrome.eyebrow;
|
|
1177
1271
|
const dotR = 3;
|
|
1178
1272
|
const dotGap = 8;
|
|
@@ -1397,9 +1491,34 @@ function renderEndpointLabels(parent, layout) {
|
|
|
1397
1491
|
|
|
1398
1492
|
// src/renderers/legend.ts
|
|
1399
1493
|
import { estimateTextWidth as estimateTextWidth2 } from "@opendata-ai/openchart-core";
|
|
1494
|
+
var LEGEND_HIT_HEIGHT = 24;
|
|
1495
|
+
var LEGEND_HIT_PAD = 4;
|
|
1400
1496
|
function isCategorical(legend) {
|
|
1401
1497
|
return !legend.type || legend.type === "categorical";
|
|
1402
1498
|
}
|
|
1499
|
+
function renderNoDataSwatch(parent, noData, labelStyle, chip) {
|
|
1500
|
+
const swatch = createSVGElement("rect");
|
|
1501
|
+
swatch.setAttribute("class", "oc-legend-nodata");
|
|
1502
|
+
setAttrs(swatch, {
|
|
1503
|
+
x: noData.x,
|
|
1504
|
+
y: noData.y,
|
|
1505
|
+
width: noData.size,
|
|
1506
|
+
height: noData.size,
|
|
1507
|
+
fill: noData.fill,
|
|
1508
|
+
...chip ? { rx: chip.rx, ry: chip.rx } : { "shape-rendering": "crispEdges" }
|
|
1509
|
+
});
|
|
1510
|
+
parent.appendChild(swatch);
|
|
1511
|
+
const label = createSVGElement("text");
|
|
1512
|
+
setAttrs(label, {
|
|
1513
|
+
x: noData.labelX,
|
|
1514
|
+
y: noData.labelY,
|
|
1515
|
+
"text-anchor": "start",
|
|
1516
|
+
...chip ? { "dominant-baseline": chip.baseline } : {}
|
|
1517
|
+
});
|
|
1518
|
+
applyTextStyle(label, labelStyle);
|
|
1519
|
+
label.textContent = noData.label;
|
|
1520
|
+
parent.appendChild(label);
|
|
1521
|
+
}
|
|
1403
1522
|
function renderContinuousLegend(parent, legend) {
|
|
1404
1523
|
if (legend.bounds.width <= 0 || legend.bounds.height <= 0) return;
|
|
1405
1524
|
const g = createSVGElement("g");
|
|
@@ -1446,7 +1565,8 @@ function renderContinuousLegend(parent, legend) {
|
|
|
1446
1565
|
});
|
|
1447
1566
|
g.appendChild(bar);
|
|
1448
1567
|
} else {
|
|
1449
|
-
for (
|
|
1568
|
+
for (let i = 0; i < legend.bins.length; i++) {
|
|
1569
|
+
const bin = legend.bins[i];
|
|
1450
1570
|
const rect = createSVGElement("rect");
|
|
1451
1571
|
rect.setAttribute("class", "oc-legend-bin");
|
|
1452
1572
|
setAttrs(rect, {
|
|
@@ -1454,11 +1574,21 @@ function renderContinuousLegend(parent, legend) {
|
|
|
1454
1574
|
y: legend.bar.y,
|
|
1455
1575
|
width: bin.width,
|
|
1456
1576
|
height: legend.bar.height,
|
|
1457
|
-
fill: bin.color
|
|
1577
|
+
fill: bin.color,
|
|
1578
|
+
"shape-rendering": "crispEdges"
|
|
1458
1579
|
});
|
|
1580
|
+
rect.setAttribute("data-bin-index", String(i));
|
|
1459
1581
|
g.appendChild(rect);
|
|
1460
1582
|
}
|
|
1461
1583
|
}
|
|
1584
|
+
if (legend.title && legend.titleY !== void 0) {
|
|
1585
|
+
const title = createSVGElement("text");
|
|
1586
|
+
title.setAttribute("class", "oc-legend-title");
|
|
1587
|
+
setAttrs(title, { x: legend.bar.x, y: legend.titleY, "text-anchor": "start" });
|
|
1588
|
+
applyTextStyle(title, legend.titleStyle ?? legend.labelStyle);
|
|
1589
|
+
title.textContent = legend.title;
|
|
1590
|
+
g.appendChild(title);
|
|
1591
|
+
}
|
|
1462
1592
|
for (const tick of legend.ticks) {
|
|
1463
1593
|
const label = createSVGElement("text");
|
|
1464
1594
|
setAttrs(label, { x: tick.x, y: legend.labelY, "text-anchor": tick.anchor });
|
|
@@ -1466,6 +1596,9 @@ function renderContinuousLegend(parent, legend) {
|
|
|
1466
1596
|
label.textContent = tick.label;
|
|
1467
1597
|
g.appendChild(label);
|
|
1468
1598
|
}
|
|
1599
|
+
if (legend.noData) {
|
|
1600
|
+
renderNoDataSwatch(g, legend.noData, legend.labelStyle);
|
|
1601
|
+
}
|
|
1469
1602
|
parent.appendChild(g);
|
|
1470
1603
|
}
|
|
1471
1604
|
function renderSizeLegend(parent, legend) {
|
|
@@ -1477,6 +1610,14 @@ function renderSizeLegend(parent, legend) {
|
|
|
1477
1610
|
const oy = legend.bounds.y;
|
|
1478
1611
|
const labelX = ox + legend.circles[0].cx + legend.circles[0].radius + 8;
|
|
1479
1612
|
const leaderX = ox + legend.circles[0].cx + legend.circles[0].radius + 4;
|
|
1613
|
+
if (legend.title && legend.titleY !== void 0) {
|
|
1614
|
+
const title = createSVGElement("text");
|
|
1615
|
+
title.setAttribute("class", "oc-legend-title");
|
|
1616
|
+
setAttrs(title, { x: ox, y: oy + legend.titleY, "text-anchor": "start" });
|
|
1617
|
+
applyTextStyle(title, legend.titleStyle ?? legend.labelStyle);
|
|
1618
|
+
title.textContent = legend.title;
|
|
1619
|
+
g.appendChild(title);
|
|
1620
|
+
}
|
|
1480
1621
|
for (const circle of legend.circles) {
|
|
1481
1622
|
const c = createSVGElement("circle");
|
|
1482
1623
|
setAttrs(c, {
|
|
@@ -1522,7 +1663,7 @@ function renderLegend(parent, legend) {
|
|
|
1522
1663
|
if (!isCategorical(legend) || legend.entries.length === 0) return;
|
|
1523
1664
|
const g = createSVGElement("g");
|
|
1524
1665
|
g.setAttribute("class", "oc-legend");
|
|
1525
|
-
g.setAttribute("role", "
|
|
1666
|
+
g.setAttribute("role", "group");
|
|
1526
1667
|
g.setAttribute("aria-label", "Chart legend");
|
|
1527
1668
|
const isHorizontal = legend.position === "top" || legend.position === "top-left" || legend.position === "bottom";
|
|
1528
1669
|
const positions = "entryPositions" in legend ? legend.entryPositions : void 0;
|
|
@@ -1548,7 +1689,6 @@ function renderLegend(parent, legend) {
|
|
|
1548
1689
|
}
|
|
1549
1690
|
const entryG = createSVGElement("g");
|
|
1550
1691
|
entryG.setAttribute("class", "oc-legend-entry");
|
|
1551
|
-
entryG.setAttribute("role", "listitem");
|
|
1552
1692
|
entryG.setAttribute("data-legend-index", String(i));
|
|
1553
1693
|
entryG.setAttribute("data-legend-label", entry.label);
|
|
1554
1694
|
if (entry.overflow) {
|
|
@@ -1556,14 +1696,32 @@ function renderLegend(parent, legend) {
|
|
|
1556
1696
|
entryG.setAttribute("aria-label", entry.label);
|
|
1557
1697
|
entryG.setAttribute("opacity", "0.5");
|
|
1558
1698
|
} else {
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
);
|
|
1699
|
+
const visible = entry.active !== false;
|
|
1700
|
+
entryG.setAttribute("role", "button");
|
|
1701
|
+
entryG.setAttribute("tabindex", "0");
|
|
1702
|
+
entryG.setAttribute("aria-pressed", String(visible));
|
|
1703
|
+
entryG.setAttribute("data-legend-active", String(visible));
|
|
1704
|
+
entryG.setAttribute("aria-label", `${entry.label}: ${visible ? "visible" : "hidden"}`);
|
|
1563
1705
|
entryG.setAttribute("style", "cursor: pointer");
|
|
1564
|
-
if (
|
|
1706
|
+
if (!visible) {
|
|
1565
1707
|
entryG.setAttribute("opacity", "0.3");
|
|
1566
1708
|
}
|
|
1709
|
+
const labelWidth = estimateTextWidth2(
|
|
1710
|
+
entry.label,
|
|
1711
|
+
legend.labelStyle.fontSize,
|
|
1712
|
+
legend.labelStyle.fontWeight
|
|
1713
|
+
);
|
|
1714
|
+
const hit = createSVGElement("rect");
|
|
1715
|
+
hit.setAttribute("class", "oc-legend-hit");
|
|
1716
|
+
setAttrs(hit, {
|
|
1717
|
+
x: offsetX - LEGEND_HIT_PAD,
|
|
1718
|
+
y: offsetY + legend.swatchSize / 2 - LEGEND_HIT_HEIGHT / 2,
|
|
1719
|
+
width: legend.swatchSize + legend.swatchGap + labelWidth + LEGEND_HIT_PAD * 2,
|
|
1720
|
+
height: LEGEND_HIT_HEIGHT,
|
|
1721
|
+
rx: 2,
|
|
1722
|
+
fill: "transparent"
|
|
1723
|
+
});
|
|
1724
|
+
entryG.appendChild(hit);
|
|
1567
1725
|
}
|
|
1568
1726
|
const midX = offsetX + legend.swatchSize / 2;
|
|
1569
1727
|
const midY = offsetY + legend.swatchSize / 2;
|
|
@@ -1629,6 +1787,9 @@ function renderLegend(parent, legend) {
|
|
|
1629
1787
|
}
|
|
1630
1788
|
}
|
|
1631
1789
|
}
|
|
1790
|
+
if (legend.noData) {
|
|
1791
|
+
renderNoDataSwatch(g, legend.noData, legend.labelStyle, { rx: 2, baseline: "central" });
|
|
1792
|
+
}
|
|
1632
1793
|
parent.appendChild(g);
|
|
1633
1794
|
}
|
|
1634
1795
|
|
|
@@ -1763,7 +1924,12 @@ function renderChartSVG(layout, container, opts) {
|
|
|
1763
1924
|
defs
|
|
1764
1925
|
);
|
|
1765
1926
|
svg.appendChild(defs);
|
|
1766
|
-
setMarkRenderState({
|
|
1927
|
+
setMarkRenderState({
|
|
1928
|
+
animation,
|
|
1929
|
+
gradientMap,
|
|
1930
|
+
patternMap,
|
|
1931
|
+
surface: resolvedSurface(layout.theme)
|
|
1932
|
+
});
|
|
1767
1933
|
try {
|
|
1768
1934
|
if (layout.facet) {
|
|
1769
1935
|
renderFacetedPanels(svg, layout, layout.facet.panels, defs);
|
|
@@ -1837,10 +2003,10 @@ function renderChartSVG(layout, container, opts) {
|
|
|
1837
2003
|
clippedGroup.appendChild(dotsGroup);
|
|
1838
2004
|
}
|
|
1839
2005
|
svg.appendChild(clipGroup);
|
|
2006
|
+
renderAnnotations(svg, layout);
|
|
1840
2007
|
if (markLabelsOverlay) {
|
|
1841
2008
|
svg.appendChild(markLabelsOverlay);
|
|
1842
2009
|
}
|
|
1843
|
-
renderAnnotations(svg, layout);
|
|
1844
2010
|
renderEndpointLabels(svg, layout);
|
|
1845
2011
|
const epEntries = layout.endpointLabels?.entries ?? [];
|
|
1846
2012
|
if (epEntries.length > 0) {
|
|
@@ -1931,10 +2097,10 @@ function renderFacetedPanels(svg, layout, panels, defs) {
|
|
|
1931
2097
|
clippedGroup.setAttribute("clip-path", `url(#${panelClipId})`);
|
|
1932
2098
|
const panelLabelsOverlay = renderMarks(clippedGroup, panelLayout);
|
|
1933
2099
|
g.appendChild(clippedGroup);
|
|
2100
|
+
renderAnnotations(g, panelLayout);
|
|
1934
2101
|
if (panelLabelsOverlay) {
|
|
1935
2102
|
g.appendChild(panelLabelsOverlay);
|
|
1936
2103
|
}
|
|
1937
|
-
renderAnnotations(g, panelLayout);
|
|
1938
2104
|
svg.appendChild(g);
|
|
1939
2105
|
}
|
|
1940
2106
|
}
|
|
@@ -1945,6 +2111,10 @@ export {
|
|
|
1945
2111
|
resetSvgIdCounter,
|
|
1946
2112
|
buildGradientDefs,
|
|
1947
2113
|
resolveMarkFill,
|
|
2114
|
+
buildPatternDefs,
|
|
2115
|
+
resolvePatternFill,
|
|
2116
|
+
resolvedSurface,
|
|
2117
|
+
stampThemeProperties,
|
|
1948
2118
|
renderChromeElement,
|
|
1949
2119
|
renderLegend,
|
|
1950
2120
|
registerMarkRenderer,
|
|
@@ -1952,4 +2122,4 @@ export {
|
|
|
1952
2122
|
renderSingleMark,
|
|
1953
2123
|
renderChartSVG
|
|
1954
2124
|
};
|
|
1955
|
-
//# sourceMappingURL=chunk-
|
|
2125
|
+
//# sourceMappingURL=chunk-KANNWAEA.js.map
|