@opendata-ai/openchart-vanilla 7.9.0 → 7.9.2
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-QRE4FQQM.js → chunk-EQ6DYFO7.js} +3 -2
- package/dist/chunk-EQ6DYFO7.js.map +1 -0
- package/dist/index.js +15 -2
- package/dist/index.js.map +1 -1
- package/dist/static.js +1 -1
- package/package.json +3 -3
- package/src/__tests__/svg-renderer.test.ts +6 -1
- package/src/renderers/axes.ts +3 -0
- package/src/tilemap-mount.ts +43 -3
- package/dist/chunk-QRE4FQQM.js.map +0 -1
|
@@ -996,7 +996,8 @@ function renderAxis(parent, axis, orientation, layout) {
|
|
|
996
996
|
const titleOffset = axisTitleOffset(
|
|
997
997
|
maxTickLabelWidth,
|
|
998
998
|
axis.labelStyle.fontSize,
|
|
999
|
-
layout.dimensions.width
|
|
999
|
+
layout.dimensions.width,
|
|
1000
|
+
isInlineY
|
|
1000
1001
|
);
|
|
1001
1002
|
setAttrs(axisLabel, {
|
|
1002
1003
|
x: area.x - titleOffset,
|
|
@@ -2043,4 +2044,4 @@ export {
|
|
|
2043
2044
|
renderChartSVG,
|
|
2044
2045
|
renderTileMapSVG
|
|
2045
2046
|
};
|
|
2046
|
-
//# sourceMappingURL=chunk-
|
|
2047
|
+
//# sourceMappingURL=chunk-EQ6DYFO7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/svg-ids.ts","../src/renderers/svg-dom.ts","../src/gradient-utils.ts","../src/renderers/marks.ts","../src/svg-renderer.ts","../src/renderers/annotations.ts","../src/renderers/axes.ts","../src/renderers/brand.ts","../src/renderers/chrome.ts","../src/renderers/endpoint-labels.ts","../src/renderers/legend.ts","../src/renderers/metrics.ts","../src/tilemap-renderer.ts"],"sourcesContent":["/**\n * Monotonic SVG ID generator shared by gradient and clipPath defs.\n *\n * Why a single counter: SVG `url(#id)` references resolve against the full\n * document, so any ID collision (across charts on the same page) silently\n * cross-wires one chart's fill/clip into another. Random-hex suffixes have a\n * small-but-real collision probability that surfaced in production; a global\n * monotonic counter makes uniqueness unconditional.\n *\n * Gradient and clip-path IDs share one counter so we can't regress one half of\n * the system by accident. Consumers just pick a prefix.\n */\n\nlet counter = 0;\n\nexport function nextSvgId(prefix: string): string {\n return `${prefix}-${counter++}`;\n}\n\n/** @internal Used by static rendering only. Never call from browser-facing code. */\nexport function resetSvgIdCounter(): void {\n counter = 0;\n}\n","/**\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\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 * SVG gradient utilities: creates <linearGradient> and <radialGradient>\n * elements from GradientDef specs and resolves mark fills to url(#id) refs.\n */\n\nimport type { GradientDef, LinearGradient, RadialGradient } from '@opendata-ai/openchart-core';\nimport { isGradientDef } from '@opendata-ai/openchart-core';\nimport { nextSvgId } from './svg-ids';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\n\n/**\n * Produce a stable, deterministic key for a GradientDef.\n * Used for deduplication so identical gradients share one SVG element.\n * Recursively sorts object keys for stability across property order variations.\n */\nfunction gradientKey(def: GradientDef): string {\n return sortedStringify(def);\n}\n\nfunction sortedStringify(value: unknown): string {\n if (value === null || value === undefined) return String(value);\n if (Array.isArray(value)) return `[${value.map(sortedStringify).join(',')}]`;\n if (typeof value === 'object') {\n const sorted = Object.keys(value)\n .sort()\n .map((k) => `${JSON.stringify(k)}:${sortedStringify((value as Record<string, unknown>)[k])}`);\n return `{${sorted.join(',')}}`;\n }\n return JSON.stringify(value);\n}\n\n/**\n * Create a single SVG gradient element (<linearGradient> or <radialGradient>).\n * Uses gradientUnits=\"objectBoundingBox\" so coordinates are in [0,1] space.\n */\nfunction createGradientElement(def: GradientDef, id: string): SVGElement {\n if (def.gradient === 'linear') {\n return createLinearGradient(def, id);\n }\n return createRadialGradient(def, id);\n}\n\nfunction createLinearGradient(def: LinearGradient, id: string): SVGElement {\n const el = document.createElementNS(SVG_NS, 'linearGradient');\n el.setAttribute('id', id);\n el.setAttribute('gradientUnits', 'objectBoundingBox');\n el.setAttribute('x1', String(def.x1 ?? 0));\n el.setAttribute('y1', String(def.y1 ?? 0));\n el.setAttribute('x2', String(def.x2 ?? 0));\n el.setAttribute('y2', String(def.y2 ?? 1));\n\n for (const stop of def.stops) {\n appendStop(el, stop);\n }\n\n return el;\n}\n\nfunction createRadialGradient(def: RadialGradient, id: string): SVGElement {\n const el = document.createElementNS(SVG_NS, 'radialGradient');\n el.setAttribute('id', id);\n el.setAttribute('gradientUnits', 'objectBoundingBox');\n // SVG radialGradient: cx/cy/r = outer circle, fx/fy/fr = focal (inner) circle\n // Spec: x2/y2/r2 = outer, x1/y1/r1 = inner (focal)\n el.setAttribute('cx', String(def.x2 ?? 0.5));\n el.setAttribute('cy', String(def.y2 ?? 0.5));\n el.setAttribute('r', String(def.r2 ?? 0.5));\n el.setAttribute('fx', String(def.x1 ?? 0.5));\n el.setAttribute('fy', String(def.y1 ?? 0.5));\n el.setAttribute('fr', String(def.r1 ?? 0));\n\n for (const stop of def.stops) {\n appendStop(el, stop);\n }\n\n return el;\n}\n\nfunction appendStop(\n parent: SVGElement,\n stop: { offset: number; color: string; opacity?: number },\n): void {\n const stopEl = document.createElementNS(SVG_NS, 'stop');\n stopEl.setAttribute('offset', String(stop.offset));\n stopEl.setAttribute('stop-color', stop.color);\n if (stop.opacity !== undefined) {\n stopEl.setAttribute('stop-opacity', String(stop.opacity));\n }\n parent.appendChild(stopEl);\n}\n\n/**\n * Scan all marks for GradientDef fill values, create SVG gradient elements\n * in the provided <defs> node, and return a map from gradient key to element ID.\n *\n * Identical gradients (by key) share a single SVG element within one chart.\n * IDs come from `nextSvgId` so they're globally unique across charts and\n * share the counter with clip-path IDs (see svg-ids.ts). Gradient ID numbers\n * may skip values when clip-paths consume counter slots - still monotonic,\n * still unique.\n */\nexport function buildGradientDefs(\n marks: Array<{ fill?: unknown }>,\n defs: SVGElement,\n): Map<string, string> {\n const map = new Map<string, string>();\n\n for (const mark of marks) {\n const fill = mark.fill;\n if (fill && isGradientDef(fill)) {\n const key = gradientKey(fill);\n if (!map.has(key)) {\n const id = nextSvgId('oc-grad');\n const el = createGradientElement(fill, id);\n defs.appendChild(el);\n map.set(key, id);\n }\n }\n }\n\n return map;\n}\n\n/**\n * Resolve a mark's fill value to a CSS/SVG fill string.\n * Returns the color string directly for plain fills,\n * or \"url(#gradientId)\" for gradient fills.\n */\nexport function resolveMarkFill(\n fill: string | GradientDef,\n gradientMap: Map<string, string>,\n): string {\n if (typeof fill === 'string') return fill;\n const key = gradientKey(fill);\n const id = gradientMap.get(key);\n return id ? `url(#${id})` : '#000000';\n}\n","/**\n * Mark rendering: dispatches to per-mark-type sub-renderers (line, area, rect,\n * arc, point, text, rule, tick).\n *\n * Mark renderers read module-level animation and gradient state so their\n * signatures stay `(mark, index) => SVGElement`. Callers must invoke\n * `setMarkRenderState()` before `renderMarks()` and `resetMarkRenderState()`\n * after.\n */\n\nimport type {\n ArcMark,\n AreaMark,\n ChartLayout,\n LineMark,\n Mark,\n PointMark,\n RectMark,\n ResolvedAnimation,\n RuleMarkLayout,\n TextMarkLayout,\n TickMarkLayout,\n} from '@opendata-ai/openchart-core';\nimport { resolveMarkFill } from '../gradient-utils';\nimport { applyTextStyle, createSVGElement, setAttrs } from './svg-dom';\n\n/**\n * Module-level animation state. Set by the orchestrator before rendering marks\n * so mark renderers can read it without changing their function signatures.\n */\nlet currentAnimation: ResolvedAnimation | undefined;\n\n/**\n * Module-level gradient map. Set by the orchestrator after building gradient defs\n * so mark renderers can resolve gradient fills without signature changes.\n */\nlet currentGradientMap: Map<string, string> = new Map();\n\n/** Set animation + gradient state before rendering marks. */\nexport function setMarkRenderState(state: {\n animation: ResolvedAnimation | undefined;\n gradientMap: Map<string, string>;\n}): void {\n currentAnimation = state.animation;\n currentGradientMap = state.gradientMap;\n}\n\n/** Reset animation + gradient state after rendering. */\nexport function resetMarkRenderState(): void {\n currentAnimation = undefined;\n currentGradientMap = new Map();\n}\n\n/**\n * Stamp animation index attributes on a mark element when animation is enabled.\n * Sets `data-animation-index` (for querySelector) and `--oc-mark-index`\n * (for CSS calc-based stagger delay).\n */\nfunction stampAnimationAttrs(\n el: SVGElement,\n mark: { animationIndex?: number; key?: string },\n fallbackIndex: number,\n): void {\n // Stamp stable identity key for data-update transitions (always, not just enter)\n if (mark.key) {\n el.setAttribute('data-key', mark.key);\n }\n if (!currentAnimation?.enter) return;\n const idx = mark.animationIndex ?? fallbackIndex;\n el.setAttribute('data-animation-index', String(idx));\n (el as SVGElement & ElementCSSInlineStyle).style.setProperty('--oc-mark-index', String(idx));\n}\n\ntype MarkRenderer<T extends Mark> = (mark: T, index: number) => SVGElement;\n\nconst markRenderers: Record<string, MarkRenderer<Mark>> = {};\n\n/**\n * Register a mark renderer for a specific mark type.\n * Built-in renderers are registered below for all chart types.\n */\nexport function registerMarkRenderer<T extends Mark>(\n type: T['type'],\n renderer: MarkRenderer<T>,\n): void {\n markRenderers[type] = renderer as MarkRenderer<Mark>;\n}\n\nfunction renderLineMark(mark: LineMark, index: number): SVGElement {\n const g = createSVGElement('g');\n g.setAttribute('data-mark-id', `line-${mark.seriesKey ?? index}`);\n g.setAttribute('class', 'oc-mark oc-mark-line');\n stampAnimationAttrs(g, mark, index);\n\n if (mark.points.length > 1) {\n const path = createSVGElement('path');\n // Use the pre-computed D3 curve path when available (smooth monotone),\n // otherwise fall back to straight M/L segments.\n const d =\n mark.path ?? mark.points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`).join(' ');\n setAttrs(path, {\n d,\n fill: 'none',\n stroke: mark.stroke,\n 'stroke-width': mark.strokeWidth,\n });\n if (mark.strokeDasharray) {\n path.setAttribute('stroke-dasharray', mark.strokeDasharray);\n }\n if (mark.opacity != null) {\n path.setAttribute('opacity', String(mark.opacity));\n }\n // Note: line drawing animation is handled via CSS clip-path on the group,\n // no inline dasharray/dashoffset needed.\n g.appendChild(path);\n }\n\n // Render end-of-line label if present and visible\n if (mark.label?.visible) {\n const label = createSVGElement('text');\n label.setAttribute('class', 'oc-mark-label');\n if (mark.seriesKey) {\n label.setAttribute('data-series', mark.seriesKey);\n }\n setAttrs(label, { x: mark.label.x, y: mark.label.y });\n applyTextStyle(label, mark.label.style);\n label.textContent = mark.label.text;\n g.appendChild(label);\n\n // Render connector line if label was offset from anchor\n if (mark.label.connector) {\n const connector = createSVGElement('line');\n connector.setAttribute('class', 'oc-mark-connector');\n setAttrs(connector, {\n x1: mark.label.connector.from.x,\n y1: mark.label.connector.from.y,\n x2: mark.label.connector.to.x,\n y2: mark.label.connector.to.y,\n stroke: mark.label.connector.stroke,\n 'stroke-width': 1,\n 'stroke-opacity': 0.5,\n });\n g.appendChild(connector);\n }\n }\n\n return g;\n}\n\nfunction renderAreaMark(mark: AreaMark, index: number): SVGElement {\n const g = createSVGElement('g');\n g.setAttribute('data-mark-id', `area-${mark.seriesKey ?? index}`);\n g.setAttribute('class', 'oc-mark oc-mark-area');\n stampAnimationAttrs(g, mark, index);\n\n if (mark.path) {\n // Area fill: the full closed shape (top line + baseline), no stroke\n const fill = createSVGElement('path');\n setAttrs(fill, {\n d: mark.path,\n fill: resolveMarkFill(mark.fill, currentGradientMap),\n 'fill-opacity': mark.fillOpacity,\n stroke: 'none',\n });\n g.appendChild(fill);\n\n // Top-line stroke: only along the data points, not the baseline\n if (mark.stroke && mark.topPath) {\n const strokePath = createSVGElement('path');\n strokePath.setAttribute('class', 'oc-area-top');\n setAttrs(strokePath, {\n d: mark.topPath,\n fill: 'none',\n stroke: mark.stroke,\n 'stroke-width': mark.strokeWidth ?? 1,\n });\n // Note: area drawing animation is handled via CSS clip-path on the group,\n // no inline dasharray/dashoffset needed.\n g.appendChild(strokePath);\n }\n }\n\n return g;\n}\n\n/**\n * Build an SVG path describing a rectangle with selectively rounded corners.\n * Used by stacked segments where only the leading edge (top of a vertical\n * stack, right of a horizontal stack) should round so the seams between\n * adjacent segments stay flush.\n */\nexport function rectPathWithCorners(\n mark: RectMark,\n sides: NonNullable<RectMark['cornerRadiusSides']>,\n): string {\n const { x, y, width: w, height: h } = mark;\n // Clamp the radius so it never exceeds half of the shorter side, otherwise\n // the arcs would overlap and the path would render as a degenerate shape.\n const r = Math.max(0, Math.min(mark.cornerRadius ?? 0, w / 2, h / 2));\n const tl = sides.tl ? r : 0;\n const tr = sides.tr ? r : 0;\n const br = sides.br ? r : 0;\n const bl = sides.bl ? r : 0;\n return [\n `M${x + tl},${y}`,\n `H${x + w - tr}`,\n tr ? `A${tr},${tr} 0 0 1 ${x + w},${y + tr}` : '',\n `V${y + h - br}`,\n br ? `A${br},${br} 0 0 1 ${x + w - br},${y + h}` : '',\n `H${x + bl}`,\n bl ? `A${bl},${bl} 0 0 1 ${x},${y + h - bl}` : '',\n `V${y + tl}`,\n tl ? `A${tl},${tl} 0 0 1 ${x + tl},${y}` : '',\n 'Z',\n ]\n .filter(Boolean)\n .join(' ');\n}\n\nfunction renderRectMark(mark: RectMark, index: number): SVGElement {\n const g = createSVGElement('g');\n g.setAttribute('data-mark-id', `rect-${index}`);\n g.setAttribute('class', 'oc-mark oc-mark-rect');\n stampAnimationAttrs(g, mark, index);\n // Use engine-provided orientation for animation direction\n if (currentAnimation?.enter && mark.orient === 'horizontal') {\n g.setAttribute('data-orient', 'horizontal');\n }\n\n // When `cornerRadiusSides` selects a subset of corners (e.g. top-only for\n // the topmost segment of a stacked column), SVG's `rx`/`ry` won't do —\n // it rounds all four corners or none. Emit a `<path>` with per-corner\n // arcs in that case so the stacked segments stay flush at the seam.\n const sides = mark.cornerRadiusSides;\n const partialCorners =\n !!sides && (!sides.tl || !sides.tr || !sides.br || !sides.bl) && !!mark.cornerRadius;\n const shapeEl = partialCorners ? createSVGElement('path') : createSVGElement('rect');\n if (partialCorners) {\n shapeEl.setAttribute('d', rectPathWithCorners(mark, sides));\n } else {\n setAttrs(shapeEl, {\n x: mark.x,\n y: mark.y,\n width: mark.width,\n height: mark.height,\n });\n if (mark.cornerRadius) {\n setAttrs(shapeEl, { rx: mark.cornerRadius, ry: mark.cornerRadius });\n }\n }\n shapeEl.setAttribute('fill', String(resolveMarkFill(mark.fill, currentGradientMap)));\n if (mark.stroke) {\n shapeEl.setAttribute('stroke', mark.stroke);\n }\n if (mark.strokeWidth) {\n shapeEl.setAttribute('stroke-width', String(mark.strokeWidth));\n }\n g.appendChild(shapeEl);\n\n // Labels for rect marks are rendered in a dedicated overlay group by\n // renderMarks() so they always paint above all bars in SVG z-order.\n // See the two-pass logic in renderMarks() below.\n\n return g;\n}\n\nfunction renderArcMark(mark: ArcMark, index: number): SVGElement {\n const g = createSVGElement('g');\n g.setAttribute('data-mark-id', `arc-${index}`);\n g.setAttribute('class', 'oc-mark oc-mark-arc');\n g.setAttribute('transform', `translate(${mark.center.x},${mark.center.y})`);\n stampAnimationAttrs(g, mark, index);\n\n const path = createSVGElement('path');\n setAttrs(path, {\n d: mark.path,\n fill: resolveMarkFill(mark.fill, currentGradientMap),\n stroke: mark.stroke,\n 'stroke-width': mark.strokeWidth,\n });\n g.appendChild(path);\n\n // Render label if present and visible\n if (mark.label?.visible) {\n const label = createSVGElement('text');\n label.setAttribute('class', 'oc-mark-label');\n // Label position is in absolute coords, but we're in a translated group,\n // so subtract the center offset\n setAttrs(label, {\n x: mark.label.x - mark.center.x,\n y: mark.label.y - mark.center.y,\n });\n applyTextStyle(label, mark.label.style);\n label.textContent = mark.label.text;\n g.appendChild(label);\n }\n\n return g;\n}\n\nfunction renderPointMark(mark: PointMark, index: number): SVGElement {\n const circle = createSVGElement('circle');\n circle.setAttribute('data-mark-id', `point-${index}`);\n circle.setAttribute('class', 'oc-mark oc-mark-point');\n stampAnimationAttrs(circle, mark, index);\n\n setAttrs(circle, {\n cx: mark.cx,\n cy: mark.cy,\n r: mark.r,\n fill: resolveMarkFill(mark.fill, currentGradientMap),\n stroke: mark.stroke,\n 'stroke-width': mark.strokeWidth,\n });\n if (mark.fillOpacity !== undefined) {\n circle.setAttribute('fill-opacity', String(mark.fillOpacity));\n }\n return circle;\n}\n\nfunction renderTextMark(mark: TextMarkLayout, index: number): SVGElement {\n const text = createSVGElement('text');\n text.setAttribute('data-mark-id', `textMark-${index}`);\n text.setAttribute('class', 'oc-mark oc-mark-text');\n stampAnimationAttrs(text, mark, index);\n\n setAttrs(text, {\n x: mark.x,\n y: mark.y,\n 'font-size': mark.fontSize,\n 'text-anchor': mark.textAnchor,\n });\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', mark.fill);\n if (mark.fontWeight) {\n text.setAttribute('font-weight', String(mark.fontWeight));\n }\n if (mark.fontFamily) {\n text.setAttribute('font-family', mark.fontFamily);\n }\n if (mark.angle) {\n text.setAttribute('transform', `rotate(${mark.angle}, ${mark.x}, ${mark.y})`);\n }\n text.textContent = mark.text;\n return text;\n}\n\nfunction renderRuleMark(mark: RuleMarkLayout, index: number): SVGElement {\n const line = createSVGElement('line');\n line.setAttribute('data-mark-id', `rule-${index}`);\n line.setAttribute('class', 'oc-mark oc-mark-rule');\n stampAnimationAttrs(line, mark, index);\n\n setAttrs(line, {\n x1: mark.x1,\n y1: mark.y1,\n x2: mark.x2,\n y2: mark.y2,\n stroke: mark.stroke,\n 'stroke-width': mark.strokeWidth,\n });\n if (mark.strokeDasharray) {\n line.setAttribute('stroke-dasharray', mark.strokeDasharray);\n }\n if (mark.opacity != null) {\n line.setAttribute('opacity', String(mark.opacity));\n }\n return line;\n}\n\nfunction renderTickMark(mark: TickMarkLayout, index: number): SVGElement {\n const line = createSVGElement('line');\n line.setAttribute('data-mark-id', `tick-${index}`);\n line.setAttribute('class', 'oc-mark oc-mark-tick');\n stampAnimationAttrs(line, mark, index);\n\n // Tick is a short line segment centered at (x, y)\n const half = mark.length / 2;\n if (mark.orient === 'vertical') {\n setAttrs(line, {\n x1: mark.x,\n y1: mark.y - half,\n x2: mark.x,\n y2: mark.y + half,\n stroke: mark.stroke,\n 'stroke-width': mark.strokeWidth,\n });\n } else {\n setAttrs(line, {\n x1: mark.x - half,\n y1: mark.y,\n x2: mark.x + half,\n y2: mark.y,\n stroke: mark.stroke,\n 'stroke-width': mark.strokeWidth,\n });\n }\n\n if (mark.opacity != null) {\n line.setAttribute('opacity', String(mark.opacity));\n }\n return line;\n}\n\n// Register built-in renderers\nregisterMarkRenderer('line', renderLineMark as MarkRenderer<Mark>);\nregisterMarkRenderer('area', renderAreaMark as MarkRenderer<Mark>);\nregisterMarkRenderer('rect', renderRectMark as MarkRenderer<Mark>);\nregisterMarkRenderer('arc', renderArcMark as MarkRenderer<Mark>);\nregisterMarkRenderer('point', renderPointMark as MarkRenderer<Mark>);\nregisterMarkRenderer('textMark', renderTextMark as MarkRenderer<Mark>);\nregisterMarkRenderer('rule', renderRuleMark as MarkRenderer<Mark>);\nregisterMarkRenderer('tick', renderTickMark as MarkRenderer<Mark>);\n\n/**\n * Render a single mark to an SVG element without appending it anywhere.\n * Used by the transition module to create ghost elements for exiting marks.\n */\nexport function renderSingleMark(mark: Mark, index: number): SVGElement | undefined {\n const renderer = markRenderers[mark.type];\n if (!renderer) return undefined;\n return renderer(mark, index);\n}\n\n/** Extract series name from a mark for legend toggle matching. */\nfunction getMarkSeries(mark: Mark): string | undefined {\n // Line and area marks have an explicit seriesKey\n if (mark.type === 'line' || mark.type === 'area') {\n return mark.seriesKey;\n }\n // For arc marks, the category name is the first part of the aria label (before ':')\n if (mark.type === 'arc') {\n return mark.aria.label?.split(':')[0]?.trim();\n }\n // For rect/point, the aria label may be \"category: value\" or \"category, group: value\".\n // The series name is the category part (before the colon).\n if (mark.aria?.label) {\n const beforeColon = mark.aria.label.split(':')[0]?.trim();\n if (beforeColon) return beforeColon;\n }\n return undefined;\n}\n\n/**\n * Render chart marks into `parent`.\n *\n * Returns an optional overlay group containing rect mark value labels.\n * The caller should append this group to the outer SVG (outside any clip path)\n * so tall labels above near-full-height bars are not clipped by the chart-area\n * clip path that constrains the marks themselves.\n */\nexport function renderMarks(parent: SVGElement, layout: ChartLayout): SVGElement | undefined {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-marks');\n\n for (let i = 0; i < layout.marks.length; i++) {\n const mark = layout.marks[i];\n const renderer = markRenderers[mark.type];\n if (!renderer) continue;\n\n const el = renderer(mark, i);\n // Decorative marks (e.g. sparkline endpoint dots) are hidden from\n // assistive tech because they duplicate an existing data point.\n if (mark.aria?.decorative) {\n el.setAttribute('aria-hidden', 'true');\n } else if (mark.aria?.label) {\n el.setAttribute('aria-label', mark.aria.label);\n }\n // Add data-series attribute for legend toggle matching\n const series = getMarkSeries(mark);\n if (series) {\n el.setAttribute('data-series', series);\n }\n\n // For stacked segments, set stack position for sequential animation chaining.\n // stackPos is computed by the engine on RectMark during compilation.\n if (currentAnimation?.enter && mark.type === 'rect') {\n const rect = mark as RectMark;\n if (rect.stackGroup && rect.stackPos !== undefined) {\n el.setAttribute('data-stack-pos', String(rect.stackPos));\n (el as SVGElement & ElementCSSInlineStyle).style.setProperty(\n '--oc-stack-pos',\n String(rect.stackPos),\n );\n }\n }\n\n g.appendChild(el);\n }\n\n parent.appendChild(g);\n\n // Second pass: render rect mark labels in a dedicated overlay group so they\n // always paint above all bars in SVG z-order. On grouped column charts, a\n // later-rendered bar can otherwise paint over a label from an adjacent column\n // when the label extends into a neighbor's airspace.\n //\n // Each overlay label gets --oc-mark-index stamped directly on it so the CSS\n // animation delay calc (which reads that property) works without inheriting\n // from a parent group.\n let labelsGroup: SVGElement | undefined;\n for (let i = 0; i < layout.marks.length; i++) {\n const mark = layout.marks[i];\n if (mark.type !== 'rect') continue;\n const rect = mark as RectMark;\n if (!rect.label?.visible) continue;\n\n if (!labelsGroup) {\n labelsGroup = createSVGElement('g');\n labelsGroup.setAttribute('class', 'oc-mark-labels');\n }\n\n const label = createSVGElement('text');\n label.setAttribute('class', 'oc-mark-label');\n setAttrs(label, { x: rect.label.x, y: rect.label.y });\n applyTextStyle(label, rect.label.style);\n label.textContent = rect.label.text;\n\n // Stamp animation index so the CSS stagger delay works for overlay labels\n // (they're not children of a .oc-mark-rect group that carries --oc-mark-index).\n if (currentAnimation?.enter) {\n const idx = rect.animationIndex ?? i;\n label.setAttribute('data-animation-index', String(idx));\n (label as SVGElement & ElementCSSInlineStyle).style.setProperty(\n '--oc-mark-index',\n String(idx),\n );\n }\n\n labelsGroup.appendChild(label);\n }\n\n return labelsGroup;\n}\n","/**\n * SVG renderer: converts a ChartLayout into SVG DOM elements.\n *\n * Creates an <svg> element with viewBox matching layout dimensions,\n * renders chrome (title/subtitle/source), axes, marks, annotations,\n * and legend. All styling via inline SVG attributes from layout data.\n *\n * This file is the orchestrator only. Each rendering concern lives in its\n * own module under `./renderers/`.\n */\n\nimport type { ChartLayout, FacetPanelLayout, RectMark } from '@opendata-ai/openchart-core';\nimport { clampStaggerDelay } from '@opendata-ai/openchart-engine';\nimport { buildGradientDefs } from './gradient-utils';\nimport { renderAnnotations } from './renderers/annotations';\nimport { renderAxes } from './renderers/axes';\nimport { renderBrand } from './renderers/brand';\nimport { renderChrome } from './renderers/chrome';\nimport { renderEndpointLabels } from './renderers/endpoint-labels';\nimport { renderLegend } from './renderers/legend';\nimport { renderMarks, resetMarkRenderState, setMarkRenderState } from './renderers/marks';\nimport { renderMetrics } from './renderers/metrics';\nimport { createSVGElement, SVG_NS, setAttrs } from './renderers/svg-dom';\nimport { nextSvgId } from './svg-ids';\n\n// Re-export registerMarkRenderer so external consumers can still register\n// custom mark renderers via the vanilla package entry point.\nexport { registerMarkRenderer } from './renderers/marks';\n\n/** CSS easing preset map for inline style custom properties. */\nconst EASE_VAR_MAP: Record<string, string> = {\n smooth: 'var(--oc-ease-smooth)',\n snappy: 'var(--oc-ease-snappy)',\n};\n\n/**\n * Render a compiled ChartLayout into an SVG element and append it to a container.\n *\n * @param layout - Compiled ChartLayout from compileChart().\n * @param container - DOM element to mount the SVG into.\n * @returns The created SVG element.\n */\nexport function renderChartSVG(\n layout: ChartLayout,\n container: HTMLElement,\n opts?: { animate?: boolean; crosshair?: boolean },\n): SVGElement {\n const { width, height } = layout.dimensions;\n const animation = layout.animation;\n\n const svg = createSVGElement('svg') as SVGSVGElement;\n setAttrs(svg, {\n viewBox: `0 0 ${width} ${height}`,\n xmlns: SVG_NS,\n // The SVG spec default is overflow:\"hidden\", which clips anything a hair\n // outside the viewBox. We now position all text on the alphabetic/central\n // baseline (dominant-baseline:hanging was dropped because WebKit computed\n // it from different metrics), but WebKit/iOS still reports getBBox extents\n // with a few pixels of slack around tspans, so text touching an edge can\n // still get clipped. overflow:visible avoids that. Chart marks are already\n // constrained by a clipPath, so nothing bleeds out.\n overflow: 'visible',\n // Hint browsers to enable sub-pixel font hinting and kerning for chart text.\n 'text-rendering': 'optimizeLegibility',\n });\n // Set explicit pixel height via inline style. iOS Safari misresolves CSS\n // height:100% when the ancestor chain uses minHeight instead of height,\n // causing the top of the chart (title) to clip on real mobile devices.\n svg.style.height = `${height}px`;\n svg.setAttribute('role', layout.a11y.role);\n svg.setAttribute('aria-label', layout.a11y.altText);\n\n // Sparkline display mode: stamp a data attribute so consumers can target\n // sparkline-specific styles. Only set the attribute in sparkline mode so\n // regular charts keep an unchanged DOM signature.\n if (layout.display === 'sparkline') {\n svg.setAttribute('data-display', 'sparkline');\n }\n\n // oc-animate must be set before the SVG enters the DOM to prevent a flash\n // of the final state. mount.ts passes animate: true only on genuine first render.\n const classes = opts?.animate ? 'oc-chart oc-animate' : 'oc-chart';\n svg.setAttribute('class', classes);\n\n // Set animation CSS custom properties when the enter phase is enabled\n const enterPhase = animation?.enter;\n if (enterPhase) {\n const markCount = layout.marks.length;\n const stagger = clampStaggerDelay(enterPhase.staggerDelay, markCount);\n svg.style.setProperty('--oc-animation-duration', `${enterPhase.duration}ms`);\n svg.style.setProperty('--oc-animation-stagger', `${stagger}ms`);\n svg.style.setProperty('--oc-annotation-delay', `${animation!.annotationDelay}ms`);\n const easeVar = EASE_VAR_MAP[enterPhase.ease] || EASE_VAR_MAP.smooth;\n svg.style.setProperty('--oc-animation-ease', easeVar);\n\n // Compute per-segment duration for stacked bars so the total bar animation\n // time stays consistent regardless of segment count.\n // stackPos is set by the engine (0-indexed position within each stack group).\n let maxSegments = 0;\n for (const m of layout.marks) {\n if (m.type === 'rect') {\n const pos = (m as RectMark).stackPos;\n if (pos !== undefined && pos + 1 > maxSegments) {\n maxSegments = pos + 1;\n }\n }\n }\n if (maxSegments > 0) {\n const segDuration = Math.round(enterPhase.duration / maxSegments);\n svg.style.setProperty('--oc-stack-segment-duration', `${segDuration}ms`);\n }\n }\n\n // Background. Sparkline mode skips the background rect entirely so the\n // host page's surface color shows through — sparklines are drop-ins for\n // KPI cards, table cells, and inline contexts where the consumer owns\n // the background. Other display modes paint a fill so the chart is a\n // self-contained visual on any host surface.\n if (layout.display !== 'sparkline') {\n const bg = createSVGElement('rect');\n setAttrs(bg, {\n x: 0,\n y: 0,\n width,\n height,\n fill: layout.theme.colors.background,\n });\n svg.appendChild(bg);\n }\n\n // Clip path to prevent marks (especially area fills) from overflowing\n // into the chrome region (title/subtitle). Extends full width so\n // end-of-line labels aren't clipped, but constrains vertically.\n const clipId = nextSvgId('oc-clip');\n const defs = createSVGElement('defs');\n const clipPath = createSVGElement('clipPath');\n clipPath.setAttribute('id', clipId);\n const maxPointR = layout.marks.reduce(\n (max, m) =>\n m.type === 'point' && (m as { r?: number }).r ? Math.max(max, (m as { r?: number }).r!) : max,\n 0,\n );\n const clipPad = Math.max(maxPointR, 2);\n const clipRect = createSVGElement('rect');\n setAttrs(clipRect, {\n x: 0,\n y: layout.area.y - clipPad,\n width,\n height: layout.area.height + clipPad * 2,\n });\n clipPath.appendChild(clipRect);\n defs.appendChild(clipPath);\n\n // Build gradient defs for marks with gradient fills\n const gradientMap = buildGradientDefs(layout.marks as Array<{ fill?: unknown }>, defs);\n\n svg.appendChild(defs);\n\n // Prime mark-renderer module-level state so mark sub-renderers can resolve\n // animation + gradient fills without signature changes. try/finally guarantees\n // the reset fires even if any downstream renderer throws, so the next render\n // starts with a clean slate.\n setMarkRenderState({ animation, gradientMap });\n try {\n if (layout.facet) {\n // Faceted rendering: per-panel axes, marks, annotations\n renderFacetedPanels(svg, layout, layout.facet.panels, defs);\n } else {\n // Standard (non-faceted) rendering\n // Axes render outside clip (labels extend beyond chart area)\n renderAxes(svg, layout);\n\n // Marks are clipped to chart area so area fills don't cover chrome\n const clippedGroup = createSVGElement('g');\n clippedGroup.setAttribute('clip-path', `url(#${clipId})`);\n const markLabelsOverlay = renderMarks(clippedGroup, layout);\n\n // Add transparent overlay rect for line/area charts to enable voronoi tooltip lookup.\n const hasLineOrAreaWithDataPoints = layout.marks.some(\n (m) => (m.type === 'line' || m.type === 'area') && m.dataPoints && m.dataPoints.length > 0,\n );\n if (hasLineOrAreaWithDataPoints) {\n const pointEls = clippedGroup.querySelectorAll('circle.oc-mark-point');\n for (const el of pointEls) {\n el.setAttribute('pointer-events', 'none');\n }\n\n const overlay = createSVGElement('rect');\n setAttrs(overlay, {\n x: layout.area.x,\n y: layout.area.y,\n width: layout.area.width,\n height: layout.area.height,\n fill: 'transparent',\n });\n overlay.setAttribute('class', 'oc-voronoi-overlay');\n overlay.setAttribute('data-voronoi-overlay', 'true');\n clippedGroup.appendChild(overlay);\n\n if (opts?.crosshair) {\n const crosshairLine = createSVGElement('line');\n crosshairLine.setAttribute('data-crosshair', 'true');\n crosshairLine.setAttribute('class', 'oc-crosshair');\n setAttrs(crosshairLine, {\n x1: 0,\n y1: layout.area.y,\n x2: 0,\n y2: layout.area.y + layout.area.height,\n stroke: layout.theme.colors.axis,\n 'stroke-opacity': '0.4',\n 'stroke-dasharray': '3,3',\n 'stroke-width': '1',\n 'pointer-events': 'none',\n });\n crosshairLine.style.display = 'none';\n clippedGroup.appendChild(crosshairLine);\n }\n\n const dotsGroup = createSVGElement('g');\n dotsGroup.setAttribute('data-snap-dots', 'true');\n dotsGroup.setAttribute('class', 'oc-snap-dots');\n dotsGroup.setAttribute('pointer-events', 'none');\n clippedGroup.appendChild(dotsGroup);\n }\n\n svg.appendChild(clippedGroup);\n\n if (markLabelsOverlay) {\n svg.appendChild(markLabelsOverlay);\n }\n\n renderAnnotations(svg, layout);\n renderEndpointLabels(svg, layout);\n\n // Suppress decorative point marks under endpoint markers\n const epEntries = layout.endpointLabels?.entries ?? [];\n if (epEntries.length > 0) {\n const pointEls = clippedGroup.querySelectorAll<SVGCircleElement>('circle.oc-mark-point');\n for (const entry of epEntries) {\n if (!entry.marker) continue;\n const mx = entry.marker.dataX;\n const my = entry.marker.y;\n for (const el of pointEls) {\n const cx = Number(el.getAttribute('cx'));\n const cy = Number(el.getAttribute('cy'));\n if (Math.abs(cx - mx) < 0.5 && Math.abs(cy - my) < 0.5) {\n el.setAttribute('opacity', '0');\n }\n }\n }\n }\n }\n\n renderLegend(svg, layout.legend);\n\n // Chrome renders on top so titles are never obscured by chart elements\n renderChrome(svg, layout);\n renderMetrics(svg, layout);\n\n // Brand renders as a footer item, right-aligned on the source/footer row.\n // Suppressed when the spec supplies a custom chrome.brand so the two\n // brand blocks don't stack.\n if (layout.watermark && !layout.chrome.brand) {\n renderBrand(svg, layout);\n }\n } finally {\n resetMarkRenderState();\n }\n\n container.appendChild(svg);\n return svg;\n}\n\nfunction renderFacetedPanels(\n svg: SVGElement,\n layout: ChartLayout,\n panels: FacetPanelLayout[],\n defs: SVGElement,\n): void {\n for (const panel of panels) {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-facet-panel');\n g.setAttribute('data-facet', panel.key);\n\n // Panel background for visual grouping\n const bg = createSVGElement('rect');\n setAttrs(bg, {\n x: panel.area.x,\n y: panel.header.y - panel.header.fontSize * 0.6,\n width: panel.area.width,\n height: panel.area.height + panel.header.fontSize + 4,\n rx: 3,\n fill: layout.theme.isDark ? 'rgba(255,255,255,0.03)' : 'rgba(0,0,0,0.02)',\n });\n g.appendChild(bg);\n\n // Panel header label\n const headerText = createSVGElement('text');\n setAttrs(headerText, {\n x: panel.header.x,\n y: panel.header.y,\n 'text-anchor': 'middle',\n 'font-family': layout.theme.fonts.family,\n 'font-size': panel.header.fontSize,\n 'font-weight': panel.header.fontWeight,\n fill: layout.theme.colors.text,\n });\n headerText.textContent = panel.header.text;\n g.appendChild(headerText);\n\n // Build a per-panel synthetic layout for the existing renderers\n const panelLayout: ChartLayout = {\n ...layout,\n area: panel.area,\n axes: panel.axes,\n marks: panel.marks,\n annotations: panel.annotations,\n };\n\n // Panel axes (ticks already suppressed for inner panels by the engine)\n renderAxes(g, panelLayout);\n\n // Panel clip path\n const panelClipId = nextSvgId('oc-facet-clip');\n const clipPath = createSVGElement('clipPath');\n clipPath.setAttribute('id', panelClipId);\n const clipRect = createSVGElement('rect');\n setAttrs(clipRect, {\n x: panel.area.x,\n y: panel.area.y,\n width: panel.area.width,\n height: panel.area.height,\n });\n clipPath.appendChild(clipRect);\n defs.appendChild(clipPath);\n\n // Panel marks (clipped)\n const clippedGroup = createSVGElement('g');\n clippedGroup.setAttribute('clip-path', `url(#${panelClipId})`);\n const panelLabelsOverlay = renderMarks(clippedGroup, panelLayout);\n g.appendChild(clippedGroup);\n\n if (panelLabelsOverlay) {\n g.appendChild(panelLabelsOverlay);\n }\n\n // Panel annotations\n renderAnnotations(g, panelLayout);\n\n svg.appendChild(g);\n }\n}\n","/**\n * Annotation rendering: range rects, reference lines, labels with connectors.\n */\n\nimport type { ChartLayout, Point, ResolvedAnnotation } from '@opendata-ai/openchart-core';\nimport { applyTextStyle, createSVGElement, setAttrs } from './svg-dom';\n\n/**\n * Render a curved arrow connector from a label to a data point.\n * Uses a cubic bezier that sweeps outward then curves toward the\n * target, with a triangular arrowhead at the tip.\n */\nfunction renderCurvedArrow(parent: SVGElement, from: Point, to: Point, stroke: string): void {\n // Pad above the target so the arrow doesn't sit right on the element.\n const pad = 6;\n const tipY = to.y - pad;\n\n const dy = tipY - from.y;\n const dist = Math.sqrt((to.x - from.x) ** 2 + dy ** 2) || 1;\n\n // Arrowhead geometry\n const arrowLen = 8;\n const arrowWidth = 4;\n\n // cp2 directly above target so arrow arrives pointing straight down.\n const bulge = Math.max(dist * 0.4, 35);\n const cp1x = from.x + bulge;\n const cp1y = from.y + dy * 0.35;\n const cp2x = to.x;\n const cp2y = tipY - Math.abs(dy) * 0.25;\n\n // Tangent at the tip (from cp2 → tip), used for arrowhead direction.\n const tx = to.x - cp2x;\n const ty = tipY - cp2y;\n const tLen = Math.sqrt(tx * tx + ty * ty) || 1;\n const ux = tx / tLen;\n const uy = ty / tLen;\n\n // End the curve path at the arrowhead BASE so the stroke doesn't\n // poke through the filled triangle.\n const baseX = to.x - ux * arrowLen;\n const baseY = tipY - uy * arrowLen;\n\n const path = createSVGElement('path');\n path.setAttribute('class', 'oc-annotation-connector');\n setAttrs(path, {\n d: `M ${from.x} ${from.y} C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${baseX} ${baseY}`,\n fill: 'none',\n stroke,\n 'stroke-width': 1.5,\n });\n parent.appendChild(path);\n\n // Arrowhead triangle: perpendicular to tangent direction.\n const px = -uy;\n const py = ux;\n\n const arrow = createSVGElement('polygon');\n arrow.setAttribute('class', 'oc-annotation-connector');\n setAttrs(arrow, {\n points: [\n `${to.x},${tipY}`,\n `${baseX + px * arrowWidth},${baseY + py * arrowWidth}`,\n `${baseX - px * arrowWidth},${baseY - py * arrowWidth}`,\n ].join(' '),\n fill: stroke,\n });\n parent.appendChild(arrow);\n}\n\nfunction renderAnnotation(\n parent: SVGElement,\n annotation: ResolvedAnnotation,\n index: number,\n bgColor?: string,\n): void {\n const g = createSVGElement('g');\n g.setAttribute('class', `oc-annotation oc-annotation-${annotation.type}`);\n g.setAttribute('data-annotation-index', String(index));\n if (annotation.id) {\n g.setAttribute('data-annotation-id', annotation.id);\n }\n\n // Range rect\n if (annotation.rect) {\n const rect = createSVGElement('rect');\n rect.setAttribute('class', 'oc-annotation-range');\n // Range fills cover large chart-area regions; if they intercept pointer\n // events the voronoi tooltip overlay below stops receiving mousemove\n // inside the range, creating hover dead zones. The label still receives\n // events for annotation click handlers.\n rect.setAttribute('pointer-events', 'none');\n setAttrs(rect, {\n x: annotation.rect.x,\n y: annotation.rect.y,\n width: annotation.rect.width,\n height: annotation.rect.height,\n });\n if (annotation.fill) rect.setAttribute('fill', annotation.fill);\n if (annotation.opacity !== undefined) {\n rect.setAttribute('fill-opacity', String(annotation.opacity));\n }\n g.appendChild(rect);\n }\n\n // Reference line\n if (annotation.line) {\n const line = createSVGElement('line');\n line.setAttribute('class', 'oc-annotation-line');\n setAttrs(line, {\n x1: annotation.line.start.x,\n y1: annotation.line.start.y,\n x2: annotation.line.end.x,\n y2: annotation.line.end.y,\n 'stroke-width': annotation.strokeWidth ?? 1,\n });\n if (annotation.stroke) line.setAttribute('stroke', annotation.stroke);\n if (annotation.strokeDasharray) {\n line.setAttribute('stroke-dasharray', annotation.strokeDasharray);\n }\n g.appendChild(line);\n }\n\n // Footnote marker: annotation was demoted by auto-thinning. Render a numbered\n // dot at the data point instead of the full label text.\n if (annotation.footnoteIndex != null && annotation.label) {\n const cx =\n annotation.label.connector?.endpoint?.x ??\n annotation.label.connector?.to.x ??\n annotation.label.x;\n const cy =\n annotation.label.connector?.endpoint?.y ??\n annotation.label.connector?.to.y ??\n annotation.label.y;\n const r = 8;\n const circle = createSVGElement('circle');\n circle.setAttribute('class', 'oc-annotation-footnote-marker');\n setAttrs(circle, {\n cx,\n cy,\n r,\n fill: bgColor ?? '#ffffff',\n stroke: annotation.label.style.fill ?? '#666',\n 'stroke-width': 1.5,\n });\n g.appendChild(circle);\n\n const num = createSVGElement('text');\n num.setAttribute('class', 'oc-annotation-footnote-number');\n setAttrs(num, {\n x: cx,\n y: cy,\n 'dominant-baseline': 'central',\n 'text-anchor': 'middle',\n });\n applyTextStyle(num, {\n ...annotation.label.style,\n fontSize: 9,\n fontWeight: 600,\n });\n num.textContent = String(annotation.footnoteIndex);\n g.appendChild(num);\n parent.appendChild(g);\n return;\n }\n\n // Label with optional connector line\n if (annotation.label?.visible) {\n // Render connector first (behind the label text)\n if (annotation.label.connector) {\n const c = annotation.label.connector;\n if (c.style === 'curve') {\n renderCurvedArrow(g, c.from, c.to, c.stroke);\n } else if (c.style === 'drop-line') {\n const connector = createSVGElement('line');\n connector.setAttribute('class', 'oc-annotation-connector oc-annotation-drop-line');\n setAttrs(connector, {\n x1: c.from.x,\n y1: c.from.y,\n x2: c.to.x,\n y2: c.to.y,\n stroke: c.stroke,\n 'stroke-width': 1,\n 'stroke-opacity': 0.6,\n 'shape-rendering': 'crispEdges',\n });\n g.appendChild(connector);\n } else {\n const connector = createSVGElement('line');\n connector.setAttribute('class', 'oc-annotation-connector');\n setAttrs(connector, {\n x1: c.from.x,\n y1: c.from.y,\n x2: c.to.x,\n y2: c.to.y,\n stroke: c.stroke,\n 'stroke-width': 1,\n 'stroke-opacity': 0.5,\n });\n g.appendChild(connector);\n }\n\n // Endpoint marker: bullseye dot at the data point. Outer ring uses the\n // chart background as fill so it knocks out the line/area beneath; inner\n // dot is the connector color. Skipped for curve style — the arrowhead\n // already serves as the endpoint indicator there.\n if (c.endpoint && c.style !== 'curve') {\n const ring = createSVGElement('circle');\n ring.setAttribute('class', 'oc-annotation-endpoint-ring');\n setAttrs(ring, {\n cx: c.endpoint.x,\n cy: c.endpoint.y,\n r: 5,\n fill: bgColor ?? '#ffffff',\n stroke: c.stroke,\n 'stroke-width': 1.5,\n });\n g.appendChild(ring);\n\n const dot = createSVGElement('circle');\n dot.setAttribute('class', 'oc-annotation-endpoint-dot');\n setAttrs(dot, {\n cx: c.endpoint.x,\n cy: c.endpoint.y,\n r: 2,\n fill: c.stroke,\n });\n g.appendChild(dot);\n }\n }\n\n // Optional anchor dot: rendered AFTER the connector but BEFORE the label\n // text so the dot sits on top of the connector and under any text halo.\n // The engine resolves dot.x/y at the post-gap-pullback connector.to point;\n // the renderer just stamps coordinates.\n if (annotation.dot) {\n const dot = createSVGElement('circle');\n dot.setAttribute('class', 'oc-annotation-dot');\n setAttrs(dot, {\n cx: annotation.dot.x,\n cy: annotation.dot.y,\n r: annotation.dot.radius,\n fill: annotation.dot.fill,\n stroke: annotation.dot.stroke,\n 'stroke-width': annotation.dot.strokeWidth,\n });\n g.appendChild(dot);\n }\n\n const text = createSVGElement('text');\n text.setAttribute('class', 'oc-annotation-label');\n setAttrs(text, { x: annotation.label.x, y: annotation.label.y });\n applyTextStyle(text, annotation.label.style);\n\n const lines = annotation.label.text.split('\\n');\n const fontSize = annotation.label.style.fontSize ?? 12;\n const lineHeight = fontSize * (annotation.label.style.lineHeight ?? 1.3);\n const isMultiLine = lines.length > 1;\n\n if (isMultiLine) {\n for (let i = 0; i < lines.length; i++) {\n const tspan = createSVGElement('tspan');\n setAttrs(tspan, { x: annotation.label.x, dy: i === 0 ? 0 : lineHeight });\n tspan.textContent = lines[i];\n text.appendChild(tspan);\n }\n } else {\n text.textContent = annotation.label.text;\n }\n\n // Render background rect behind text if specified, otherwise use\n // paint-order stroke halo to knock out lines behind text\n if (annotation.label.background) {\n const pad = 3;\n let bgX: number;\n let bgY: number;\n let bgW: number;\n let bgH: number;\n\n if (annotation.label.bounds) {\n const b = annotation.label.bounds;\n bgX = b.x - pad;\n bgY = b.y - pad;\n bgW = b.width + pad * 2;\n bgH = b.height + pad * 2;\n } else {\n const charWidth = fontSize * 0.55;\n const maxLineWidth = Math.max(...lines.map((l) => l.length)) * charWidth;\n const totalHeight = lines.length * lineHeight;\n bgX = isMultiLine ? annotation.label.x - maxLineWidth / 2 - pad : annotation.label.x - pad;\n bgY = annotation.label.y - fontSize + (lineHeight - fontSize) / 2 - pad;\n bgW = maxLineWidth + pad * 2;\n bgH = totalHeight + pad * 2;\n }\n\n const bgRect = createSVGElement('rect');\n bgRect.setAttribute('class', 'oc-annotation-bg');\n setAttrs(bgRect, {\n x: bgX,\n y: bgY,\n width: bgW,\n height: bgH,\n fill: annotation.label.background,\n rx: 2,\n });\n g.appendChild(bgRect);\n } else if (bgColor && annotation.label.halo !== false) {\n text.style.paintOrder = 'stroke';\n text.style.stroke = bgColor;\n text.style.strokeWidth = `${Math.round(fontSize * 0.3)}px`;\n text.style.strokeLinejoin = 'round';\n }\n\n g.appendChild(text);\n\n // Optional muted subtitle, positioned by the engine below the primary label.\n if (annotation.subtitle) {\n const sub = createSVGElement('text');\n sub.setAttribute('class', 'oc-annotation-subtitle');\n setAttrs(sub, { x: annotation.subtitle.x, y: annotation.subtitle.y });\n applyTextStyle(sub, annotation.subtitle.style);\n sub.textContent = annotation.subtitle.text;\n g.appendChild(sub);\n }\n }\n\n parent.appendChild(g);\n}\n\nexport function renderAnnotations(parent: SVGElement, layout: ChartLayout): void {\n if (layout.annotations.length === 0) return;\n\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-annotations');\n\n // Annotations are already sorted by zIndex from the engine, so render in order\n const bgColor = layout.theme.colors.background;\n for (let i = 0; i < layout.annotations.length; i++) {\n renderAnnotation(g, layout.annotations[i], i, bgColor);\n }\n\n parent.appendChild(g);\n}\n","/**\n * Axis rendering: axis line, ticks, tick labels, gridlines, axis title.\n */\n\nimport type { AxisLayout, ChartLayout } from '@opendata-ai/openchart-core';\nimport {\n axisTitleOffset,\n estimateTextWidth,\n getAxisTitleOffset,\n TICK_LABEL_OFFSET,\n textAscent,\n} from '@opendata-ai/openchart-core';\nimport { serializeKeyValue } from '@opendata-ai/openchart-engine';\nimport { applyTextStyle, createSVGElement, setAttrs } from './svg-dom';\n\nfunction appendCompoundLabel(\n parent: SVGElement,\n primaryText: string,\n subtitle: string,\n fontWeight: number,\n): void {\n const primarySpan = createSVGElement('tspan');\n primarySpan.setAttribute('font-weight', String(fontWeight));\n primarySpan.textContent = primaryText;\n parent.appendChild(primarySpan);\n\n const subtitleSpan = createSVGElement('tspan');\n subtitleSpan.setAttribute('dx', '0.5em');\n subtitleSpan.textContent = subtitle;\n subtitleSpan.setAttribute('font-weight', '400');\n subtitleSpan.setAttribute('fill-opacity', '0.6');\n parent.appendChild(subtitleSpan);\n}\n\nfunction renderAxis(\n parent: SVGElement,\n axis: AxisLayout,\n orientation: 'x' | 'y',\n layout: ChartLayout,\n): void {\n const g = createSVGElement('g');\n const isRight = orientation === 'y' && axis.orient === 'right';\n const isInlineY = orientation === 'y' && axis.tickPosition === 'inline' && !isRight;\n g.setAttribute(\n 'class',\n `oc-axis oc-axis-${isRight ? 'y2' : orientation}${isInlineY ? ' oc-axis-inline' : ''}`,\n );\n\n const { area } = layout;\n\n // Only draw axis line for x-axis (bottom baseline), unless explicitly disabled.\n // Horizontal gridlines already guide y-values, so the vertical y-axis line is redundant.\n if (orientation === 'x' && axis.domainLine !== false) {\n const line = createSVGElement('line');\n line.setAttribute('class', 'oc-axis-line');\n setAttrs(line, {\n x1: axis.start.x,\n y1: axis.start.y,\n x2: axis.end.x,\n y2: axis.end.y,\n stroke: layout.theme.colors.axis,\n 'stroke-width': 1,\n });\n g.appendChild(line);\n }\n\n // Ticks and labels\n // Tick positions are absolute pixel coordinates from D3 scales whose range\n // was set to [chartArea.x, chartArea.x + chartArea.width] (and similarly for y).\n // Don't add area.x/area.y again or you'll double-offset everything.\n for (const tick of axis.ticks) {\n // Stable key for data-update transitions\n const tickKey = serializeKeyValue(tick.value);\n\n if (orientation === 'x') {\n // Label (no tick marks -- gridlines provide sufficient reference)\n const label = createSVGElement('text');\n label.setAttribute('class', 'oc-axis-tick');\n label.setAttribute('data-tick-key', tickKey);\n\n if (axis.tickAngle && Math.abs(axis.tickAngle) > 10) {\n // Rotated labels: anchor at the rotation pivot point\n const labelX = tick.position;\n const xLabelPad = axis.labelPadding ?? layout.theme.spacing.xAxisLabelPadding;\n const labelY = area.y + area.height + xLabelPad;\n setAttrs(label, {\n x: labelX,\n y: labelY,\n 'text-anchor': axis.tickAngle < 0 ? 'end' : 'start',\n 'dominant-baseline': 'central',\n transform: `rotate(${axis.tickAngle}, ${labelX}, ${labelY})`,\n });\n } else {\n const xLabelPad = axis.labelPadding ?? layout.theme.spacing.xAxisLabelPadding;\n // xLabelPad is the literal gap between the axis line and the TOP of\n // the label regardless of font size, so shift down by the ascent to\n // land on the alphabetic baseline. (dominant-baseline:hanging would\n // express this directly, but WebKit positions hanging from different\n // font metrics than Blink, drifting labels on iOS Safari.)\n setAttrs(label, {\n x: tick.position,\n y: area.y + area.height + xLabelPad + textAscent(axis.tickLabelStyle.fontSize),\n 'text-anchor': 'middle',\n });\n }\n\n applyTextStyle(label, axis.tickLabelStyle);\n label.textContent = tick.label;\n g.appendChild(label);\n } else if (isInlineY) {\n // Inline y-tick: label sits above its gridline at the chart-area left\n // edge, no gutter reserved. The gridline itself is the visual axis.\n const label = createSVGElement('text');\n label.setAttribute('class', 'oc-axis-tick oc-axis-tick-inline');\n label.setAttribute('data-tick-key', tickKey);\n setAttrs(label, {\n x: area.x,\n y: tick.position - 6,\n 'text-anchor': 'start',\n });\n applyTextStyle(label, axis.tickLabelStyle);\n label.textContent = tick.label;\n g.appendChild(label);\n } else {\n const label = createSVGElement('text');\n label.setAttribute('class', 'oc-axis-tick');\n label.setAttribute('data-tick-key', tickKey);\n setAttrs(label, {\n x: isRight ? area.x + area.width + TICK_LABEL_OFFSET : area.x - TICK_LABEL_OFFSET,\n y: tick.position,\n 'text-anchor': isRight ? 'start' : 'end',\n 'dominant-baseline': 'central',\n });\n applyTextStyle(label, axis.tickLabelStyle);\n if (!isRight) {\n // Truncate categorical left y-axis labels that exceed available space\n const availableWidth = area.x - TICK_LABEL_OFFSET;\n const fontSize = axis.tickLabelStyle.fontSize;\n const fontWeight = axis.tickLabelStyle.fontWeight;\n\n if (tick.subtitle) {\n // Compound label: primary + gap + subtitle via tspan elements\n const gapWidth = fontSize * 0.5;\n const subtitleWidth = estimateTextWidth(tick.subtitle, fontSize, fontWeight);\n const primaryWidth = estimateTextWidth(tick.label, fontSize, fontWeight);\n const totalWidth = primaryWidth + gapWidth + subtitleWidth;\n\n if (totalWidth > availableWidth && availableWidth > 20) {\n const ellipsis = '…';\n const ellipsisWidth = estimateTextWidth(ellipsis, fontSize, fontWeight);\n const budgetForPrimary = availableWidth - gapWidth - subtitleWidth - ellipsisWidth;\n\n let primaryText = tick.label;\n if (budgetForPrimary > 0) {\n let lo = 0;\n let hi = tick.label.length;\n while (lo < hi) {\n const mid = (lo + hi + 1) >>> 1;\n const candidate = tick.label.slice(0, mid);\n if (estimateTextWidth(candidate, fontSize, fontWeight) <= budgetForPrimary) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n primaryText = lo > 0 ? tick.label.slice(0, lo).trimEnd() + ellipsis : ellipsis;\n } else {\n primaryText = ellipsis;\n }\n\n appendCompoundLabel(label, primaryText, tick.subtitle, fontWeight);\n\n const titleEl = createSVGElement('title');\n titleEl.textContent = `${tick.label} ${tick.subtitle}`;\n label.appendChild(titleEl);\n } else {\n appendCompoundLabel(label, tick.label, tick.subtitle, fontWeight);\n }\n } else {\n // Plain label (no subtitle)\n const fullWidth = estimateTextWidth(tick.label, fontSize, fontWeight);\n if (fullWidth > availableWidth && availableWidth > 20) {\n const ellipsis = '…';\n const ellipsisWidth = estimateTextWidth(ellipsis, fontSize, fontWeight);\n let lo = 0;\n let hi = tick.label.length;\n while (lo < hi) {\n const mid = (lo + hi + 1) >>> 1;\n const candidate = tick.label.slice(0, mid);\n if (\n estimateTextWidth(candidate, fontSize, fontWeight) + ellipsisWidth <=\n availableWidth\n ) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n label.textContent = lo > 0 ? tick.label.slice(0, lo).trimEnd() + ellipsis : ellipsis;\n const titleEl = createSVGElement('title');\n titleEl.textContent = tick.label;\n label.appendChild(titleEl);\n } else {\n label.textContent = tick.label;\n }\n }\n } else {\n label.textContent = tick.label;\n }\n g.appendChild(label);\n }\n }\n\n // Gridlines (positions are also absolute from the scales)\n // Skip gridlines for right-side y-axis (left y-axis gridlines are sufficient)\n if (!isRight) {\n // Build position -> tick value map for keying gridlines\n const posToTickKey = new Map<number, string>();\n for (const tick of axis.ticks) {\n posToTickKey.set(tick.position, serializeKeyValue(tick.value));\n }\n\n for (const gridline of axis.gridlines) {\n const gl = createSVGElement('line');\n gl.setAttribute('class', 'oc-gridline');\n // Stamp data-tick-key for data-update transitions\n const glKey = posToTickKey.get(gridline.position);\n if (glKey) {\n gl.setAttribute('data-tick-key', glKey);\n }\n if (orientation === 'y') {\n setAttrs(gl, {\n x1: area.x,\n y1: gridline.position,\n x2: area.x + area.width,\n y2: gridline.position,\n stroke: layout.theme.colors.gridline,\n 'stroke-width': 1,\n 'stroke-opacity': 0.6,\n });\n } else {\n setAttrs(gl, {\n x1: gridline.position,\n y1: area.y,\n x2: gridline.position,\n y2: area.y + area.height,\n stroke: layout.theme.colors.gridline,\n 'stroke-width': 1,\n 'stroke-opacity': 0.6,\n });\n }\n g.appendChild(gl);\n }\n }\n\n // Axis label\n if (axis.label && axis.labelStyle) {\n const axisLabel = createSVGElement('text');\n axisLabel.setAttribute('class', 'oc-axis-title');\n applyTextStyle(axisLabel, axis.labelStyle);\n axisLabel.textContent = axis.label;\n\n const tp = axis.titlePosition;\n if (tp) {\n const attrs: Record<string, string | number> = {\n x: tp.x,\n y: tp.y,\n 'text-anchor': 'middle',\n };\n if (tp.angle) {\n attrs.transform = `rotate(${tp.angle}, ${tp.x}, ${tp.y})`;\n }\n setAttrs(axisLabel, attrs);\n } else if (orientation === 'x') {\n let titleY = area.y + area.height + 35;\n if (axis.tickAngle && Math.abs(axis.tickAngle) > 10) {\n const angleRad = Math.abs(axis.tickAngle) * (Math.PI / 180);\n let maxLabelWidth = 40;\n for (const tick of axis.ticks) {\n const w = estimateTextWidth(\n tick.label,\n axis.tickLabelStyle.fontSize,\n axis.tickLabelStyle.fontWeight,\n );\n if (w > maxLabelWidth) maxLabelWidth = w;\n }\n const rotatedHeight = Math.min(maxLabelWidth * Math.sin(angleRad) + 6, 120);\n titleY = area.y + area.height + rotatedHeight + 14;\n }\n setAttrs(axisLabel, {\n x: area.x + area.width / 2,\n y: titleY,\n 'text-anchor': 'middle',\n });\n } else if (isRight) {\n const titleOffset = getAxisTitleOffset(layout.dimensions.width);\n const titleX = area.x + area.width + titleOffset;\n setAttrs(axisLabel, {\n x: titleX,\n y: area.y + area.height / 2,\n 'text-anchor': 'middle',\n transform: `rotate(90, ${titleX}, ${area.y + area.height / 2})`,\n });\n } else {\n const maxTickLabelWidth = axis.ticks.reduce((max, t) => {\n const w = estimateTextWidth(\n t.label,\n axis.tickLabelStyle.fontSize,\n axis.tickLabelStyle.fontWeight ?? 400,\n );\n return Math.max(max, w);\n }, 0);\n // Inline y-ticks live inside the plot, so the title clears only the chart\n // edge — mirror the engine's reservation (see axisTitleOffset).\n const titleOffset = axisTitleOffset(\n maxTickLabelWidth,\n axis.labelStyle.fontSize,\n layout.dimensions.width,\n isInlineY,\n );\n setAttrs(axisLabel, {\n x: area.x - titleOffset,\n y: area.y + area.height / 2,\n 'text-anchor': 'middle',\n transform: `rotate(-90, ${area.x - titleOffset}, ${area.y + area.height / 2})`,\n });\n }\n g.appendChild(axisLabel);\n }\n\n parent.appendChild(g);\n}\n\nexport function renderAxes(parent: SVGElement, layout: ChartLayout): void {\n if (layout.axes.x) {\n renderAxis(parent, layout.axes.x, 'x', layout);\n }\n if (layout.axes.y) {\n renderAxis(parent, layout.axes.y, 'y', layout);\n }\n if (layout.axes.y2) {\n renderAxis(parent, layout.axes.y2, 'y', layout);\n }\n}\n","/**\n * Brand rendering: the \"tryOpenData.ai\" watermark footer.\n */\n\nimport type { ChartLayout } from '@opendata-ai/openchart-core';\nimport { BRAND_FONT_SIZE, BRAND_MIN_WIDTH, textAscent } from '@opendata-ai/openchart-core';\nimport { createSVGElement, setAttrs, XLINK_NS } from './svg-dom';\n\nconst BRAND_URL = 'https://tryopendata.ai';\n\n/**\n * Render the \"OpenData\" brand as a footer-row element, right-aligned on the\n * same baseline as the first bottom chrome text (source/byline/footer).\n * Uses the same font size as chrome source text so it blends in as a subtle\n * footer item rather than occupying independent visual space.\n */\nexport function renderBrand(parent: SVGElement, layout: ChartLayout): void {\n if (layout.dimensions.width < BRAND_MIN_WIDTH) return;\n\n const { width } = layout.dimensions;\n const padding = layout.theme.spacing.padding;\n const rightEdge = width - padding;\n const fill = layout.theme.colors.axis;\n\n // Vertically align with the first bottom chrome element.\n const { chrome } = layout;\n const bottomOffset = chrome.bottomAnchorY ?? layout.area.y + layout.area.height;\n const firstBottom = chrome.source ?? chrome.byline ?? chrome.footer;\n // When no bottom chrome items exist, derive a fallback offset that still\n // clears any bottom-positioned legend so the brand watermark doesn't\n // overlap legend swatches.\n const { legend } = layout;\n const bottomLegendOffset =\n legend.position === 'bottom' && legend.bounds.height > 0 ? legend.bounds.height + 8 : 0;\n const chromeY = firstBottom\n ? bottomOffset + firstBottom.y\n : bottomOffset + layout.theme.spacing.chartToFooter + bottomLegendOffset;\n\n const a = createSVGElement('a');\n a.setAttribute('href', BRAND_URL);\n a.setAttributeNS(XLINK_NS, 'xlink:href', BRAND_URL);\n a.setAttribute('target', '_blank');\n a.setAttribute('rel', 'noopener');\n a.setAttribute('class', 'oc-chrome-ref');\n\n // \"try\" in normal weight, \"OpenData\" in semibold, \".ai\" in normal weight,\n // rendered as a single right-aligned text element with three tspans.\n // chromeY is the top edge shared with source/byline chrome text; anchor the\n // shared alphabetic baseline from the largest tspan's ascent. (Hanging\n // baseline is avoided: WebKit positions it differently and never inherits\n // it into tspans, which scattered the three spans on iOS Safari.)\n const BRAND_LARGE = 16;\n const text = createSVGElement('text');\n setAttrs(text, {\n x: rightEdge,\n y: chromeY + textAscent(BRAND_LARGE),\n 'font-family': layout.theme.fonts.family,\n 'font-size': BRAND_FONT_SIZE,\n 'text-anchor': 'end',\n 'fill-opacity': 0.55,\n });\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', fill);\n\n const trySpan = createSVGElement('tspan');\n trySpan.setAttribute('font-weight', '500');\n trySpan.textContent = 'try';\n text.appendChild(trySpan);\n\n const openDataSpan = createSVGElement('tspan');\n openDataSpan.setAttribute('font-weight', '600');\n openDataSpan.setAttribute('font-size', String(BRAND_LARGE));\n openDataSpan.textContent = 'OpenData';\n text.appendChild(openDataSpan);\n\n const aiSpan = createSVGElement('tspan');\n aiSpan.setAttribute('font-weight', '500');\n aiSpan.textContent = '.ai';\n text.appendChild(aiSpan);\n\n a.appendChild(text);\n parent.appendChild(a);\n}\n","/**\n * Chrome rendering: title, subtitle, source, byline, footer.\n */\n\nimport type {\n ChartLayout,\n MeasureTextFn,\n ResolvedChromeElement,\n} from '@opendata-ai/openchart-core';\nimport { estimateTextWidth, textAscent, wrapText } from '@opendata-ai/openchart-core';\nimport { applyTextStyle, createSVGElement, setAttrs } from './svg-dom';\n\nfunction renderChromeElement(\n parent: SVGElement,\n element: ResolvedChromeElement,\n className: string,\n chromeKey: string,\n measureText?: MeasureTextFn,\n uppercase = false,\n): void {\n const text = createSVGElement('text');\n // element.y is the TOP of the text box; convert to the alphabetic baseline\n // here instead of relying on dominant-baseline:hanging, which WebKit\n // positions from different font metrics and never inherits into tspans.\n setAttrs(text, { x: element.x, y: element.y + textAscent(element.style.fontSize) });\n applyTextStyle(text, element.style);\n text.setAttribute('class', className);\n text.setAttribute('data-chrome-key', chromeKey);\n\n // happy-dom doesn't apply CSS text-transform inside SVG measurement, so\n // pre-uppercase the rendered text for elements that style as uppercase.\n // Browsers honor the CSS rule too, so this is double-applied harmlessly.\n const renderedText = uppercase ? element.text.toUpperCase() : element.text;\n\n const lines = wrapText(\n renderedText,\n element.style.fontSize,\n element.style.fontWeight,\n element.maxWidth,\n measureText,\n );\n\n if (lines.length === 1) {\n text.textContent = renderedText;\n } else {\n const lineHeight = element.style.fontSize * (element.style.lineHeight ?? 1.3);\n for (let i = 0; i < lines.length; i++) {\n const tspan = createSVGElement('tspan');\n setAttrs(tspan, { x: element.x, dy: i === 0 ? 0 : lineHeight });\n tspan.textContent = lines[i];\n text.appendChild(tspan);\n }\n }\n\n parent.appendChild(text);\n}\n\nexport function renderChrome(parent: SVGElement, layout: ChartLayout): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-chrome');\n\n const { chrome, measureText } = layout;\n\n // Top chrome: render at their stored y positions (already absolute)\n if (chrome.eyebrow) {\n // Leading accent dot — matches the editorial design system mock.\n // eyebrow.y is the top of the text box. Visual center is roughly\n // y + fontSize * 0.55 (cap height).\n const eyebrow = chrome.eyebrow;\n const dotR = 3;\n const dotGap = 8;\n const dotX = eyebrow.x + dotR;\n const dotY = eyebrow.y + eyebrow.style.fontSize * 0.42;\n const dot = createSVGElement('circle');\n dot.setAttribute('class', 'oc-eyebrow-dot');\n setAttrs(dot, { cx: dotX, cy: dotY, r: dotR });\n dot.setAttribute('fill', eyebrow.style.fill ?? 'currentColor');\n g.appendChild(dot);\n\n const shifted: ResolvedChromeElement = {\n ...eyebrow,\n x: eyebrow.x + dotR * 2 + dotGap,\n };\n renderChromeElement(g, shifted, 'oc-eyebrow', 'eyebrow', measureText, true);\n }\n if (chrome.title) {\n renderChromeElement(g, chrome.title, 'oc-title', 'title', measureText);\n }\n if (chrome.subtitle) {\n renderChromeElement(g, chrome.subtitle, 'oc-subtitle', 'subtitle', measureText);\n }\n\n const bottomOffset = layout.chrome.bottomAnchorY ?? layout.area.y + layout.area.height;\n\n // Footnotes from auto-thinned annotations, rendered above source/byline.\n // Each footnote gets its own line to avoid horizontal overflow.\n let footnoteBandHeight = 0;\n if (chrome.footnotes && chrome.footnotes.length > 0) {\n const fontSize = layout.theme.fonts.sizes.small;\n const pad = layout.theme.spacing.padding;\n const lineHeight = fontSize * 1.3;\n const style = {\n fontFamily: layout.theme.fonts.family,\n fontSize,\n fontWeight: layout.theme.fonts.weights.normal,\n fill: layout.theme.chrome.source.color,\n lineHeight: 1.3,\n textAnchor: 'start' as const,\n };\n\n for (let i = 0; i < chrome.footnotes.length; i++) {\n const f = chrome.footnotes[i];\n const y =\n bottomOffset + layout.theme.spacing.chartToFooter + textAscent(fontSize) + i * lineHeight;\n const el = createSVGElement('text');\n el.setAttribute('class', 'oc-footnotes');\n setAttrs(el, { x: pad, y });\n applyTextStyle(el, style);\n el.textContent = `${f.index}. ${f.text}`;\n g.appendChild(el);\n }\n footnoteBandHeight = chrome.footnotes.length * lineHeight + 4;\n }\n\n if (chrome.source) {\n renderChromeElement(\n g,\n { ...chrome.source, y: bottomOffset + chrome.source.y + footnoteBandHeight },\n 'oc-source',\n 'source',\n measureText,\n );\n }\n if (chrome.byline) {\n renderChromeElement(\n g,\n { ...chrome.byline, y: bottomOffset + chrome.byline.y + footnoteBandHeight },\n 'oc-byline',\n 'byline',\n measureText,\n );\n }\n if (chrome.footer) {\n renderChromeElement(\n g,\n { ...chrome.footer, y: bottomOffset + chrome.footer.y + footnoteBandHeight },\n 'oc-footer',\n 'footer',\n measureText,\n );\n }\n if (chrome.brand) {\n const brandY = bottomOffset + chrome.brand.y + footnoteBandHeight;\n renderChromeElement(g, { ...chrome.brand, y: brandY }, 'oc-brand', 'brand', measureText);\n // Accent dot to the left of the brand text. text-anchor=end means\n // brand.x is the right edge, so the dot sits 12px left of the measured\n // text's leftmost glyph. Use estimateTextWidth (the same path the\n // engine uses for label sizing) instead of a `length * 0.55em` fudge\n // so wide glyphs (W, M) and narrow ones (i, l) land correctly.\n const textWidth = estimateTextWidth(\n chrome.brand.text,\n chrome.brand.style.fontSize,\n chrome.brand.style.fontWeight,\n );\n const dotX = chrome.brand.x - textWidth - 12;\n const dotY = brandY + chrome.brand.style.fontSize / 2;\n const dot = createSVGElement('circle');\n dot.setAttribute('class', 'oc-brand-dot');\n setAttrs(dot, { cx: dotX, cy: dotY, r: 3 });\n g.appendChild(dot);\n }\n\n parent.appendChild(g);\n}\n","/**\n * Endpoint-labels rendering: per-series label columns for multi-series\n * line/area charts. Supports trailing (right) and optional leading (left)\n * columns when `ends: 'both'` is set.\n *\n * The engine resolves all positions, colors, and styles. This renderer is dumb:\n * it reads `layout.endpointLabels` and stamps SVG. Suppression logic lives in\n * the engine — when entries is empty, the renderer is a no-op.\n */\n\nimport type {\n ChartLayout,\n EndpointLabelEntry,\n EndpointLabelsLayout,\n Rect,\n} from '@opendata-ai/openchart-core';\nimport { applyTextStyle, createSVGElement, setAttrs } from './svg-dom';\n\nconst LEADER_STROKE_WIDTH = 1;\nconst LEADER_OPACITY = 0.45;\n\nfunction renderColumn(\n root: SVGElement,\n entries: EndpointLabelEntry[],\n bounds: Rect,\n ep: EndpointLabelsLayout,\n leaderAnchorX: number,\n side: 'trailing' | 'leading',\n): void {\n const labelFontSize = ep.labelStyle.fontSize ?? 11;\n const labelLineHeight = labelFontSize * (ep.labelStyle.lineHeight ?? 1.25);\n const valueFontSize = ep.valueStyle.fontSize ?? 11;\n\n const chipX = bounds.x;\n const chipWidth = ep.swatchSize;\n const textX = chipX + chipWidth + ep.gap;\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n\n const entryG = createSVGElement('g');\n entryG.setAttribute('class', 'oc-endpoint-label-entry');\n entryG.setAttribute('role', 'listitem');\n entryG.setAttribute('data-endpoint-index', String(i));\n entryG.setAttribute('data-endpoint-key', entry.seriesKey);\n entryG.setAttribute('data-endpoint-side', side);\n entryG.setAttribute('aria-label', `${entry.seriesKey}: ${entry.value}`);\n\n if (entry.showLeader) {\n const leader = createSVGElement('line');\n leader.setAttribute('class', 'oc-endpoint-leader');\n setAttrs(leader, {\n x1: chipX,\n y1: entry.labelY + labelFontSize / 2,\n x2: leaderAnchorX,\n y2: entry.dataY,\n stroke: entry.color,\n 'stroke-width': LEADER_STROKE_WIDTH,\n 'stroke-opacity': LEADER_OPACITY,\n });\n entryG.appendChild(leader);\n }\n\n const rowY = entry.labelY + labelFontSize / 2;\n const line = createSVGElement('line');\n line.setAttribute('class', 'oc-endpoint-swatch-line');\n setAttrs(line, {\n x1: chipX,\n y1: rowY,\n x2: chipX + chipWidth,\n y2: rowY,\n stroke: entry.color,\n 'stroke-width': 2,\n 'stroke-linecap': 'round',\n });\n entryG.appendChild(line);\n\n const label = createSVGElement('text');\n label.setAttribute('class', 'oc-endpoint-label');\n setAttrs(label, { x: textX, y: entry.labelY + labelFontSize });\n applyTextStyle(label, ep.labelStyle);\n (label as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', entry.color);\n\n if (entry.labelLines.length <= 1) {\n label.textContent = entry.labelLines[0] ?? entry.seriesKey;\n } else {\n for (let li = 0; li < entry.labelLines.length; li++) {\n const tspan = createSVGElement('tspan');\n setAttrs(tspan, { x: textX, dy: li === 0 ? 0 : labelLineHeight });\n tspan.textContent = entry.labelLines[li];\n label.appendChild(tspan);\n }\n }\n entryG.appendChild(label);\n\n const lineCount = Math.max(entry.labelLines.length, 1);\n const valueY =\n entry.labelY +\n labelFontSize +\n (lineCount - 1) * labelLineHeight +\n ep.valueGap +\n valueFontSize;\n const value = createSVGElement('text');\n value.setAttribute('class', 'oc-endpoint-value');\n setAttrs(value, { x: textX, y: valueY });\n applyTextStyle(value, ep.valueStyle);\n value.textContent = entry.value;\n entryG.appendChild(value);\n\n if (entry.marker) {\n const marker = createSVGElement('circle');\n marker.setAttribute('class', 'oc-endpoint-marker');\n setAttrs(marker, {\n cx: entry.marker.x,\n cy: entry.marker.y,\n r: entry.marker.radius,\n fill: entry.marker.fill,\n stroke: entry.marker.stroke,\n 'stroke-width': entry.marker.strokeWidth,\n });\n entryG.appendChild(marker);\n }\n\n root.appendChild(entryG);\n }\n}\n\nexport function renderEndpointLabels(parent: SVGElement, layout: ChartLayout): void {\n const ep = layout.endpointLabels;\n if (!ep || ep.entries.length === 0) return;\n\n const chartArea = layout.area;\n\n const root = createSVGElement('g');\n root.setAttribute('class', 'oc-endpoint-labels');\n root.setAttribute('role', 'list');\n root.setAttribute('aria-label', 'Endpoint labels');\n\n // Trailing column (right side).\n const chartRightX = chartArea.x + chartArea.width;\n renderColumn(root, ep.entries, ep.bounds, ep, chartRightX, 'trailing');\n\n // Leading column (left side) when `ends: 'both'`.\n if (ep.leading && ep.leading.length > 0 && ep.leadingBounds) {\n const chartLeftX = chartArea.x;\n renderColumn(root, ep.leading, ep.leadingBounds, ep, chartLeftX, 'leading');\n }\n\n parent.appendChild(root);\n}\n","/**\n * Legend rendering: swatches + labels with wrap/overflow handling.\n */\n\nimport type { CategoricalLegendLayout, LegendLayout } from '@opendata-ai/openchart-core';\nimport { estimateTextWidth } from '@opendata-ai/openchart-core';\nimport { applyTextStyle, createSVGElement, setAttrs } from './svg-dom';\n\nfunction isCategorical(legend: LegendLayout): legend is CategoricalLegendLayout {\n return !legend.type || legend.type === 'categorical';\n}\n\nexport function renderLegend(parent: SVGElement, legend: LegendLayout): void {\n if (!isCategorical(legend) || legend.entries.length === 0) return;\n\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-legend');\n g.setAttribute('role', 'list');\n g.setAttribute('aria-label', 'Chart legend');\n\n const isHorizontal = legend.position === 'top' || legend.position === 'bottom';\n const positions = 'entryPositions' in legend ? legend.entryPositions : undefined;\n let offsetX = legend.bounds.x;\n let offsetY = legend.bounds.y;\n\n for (let i = 0; i < legend.entries.length; i++) {\n const entry = legend.entries[i];\n\n const pos = positions?.[i];\n if (pos) {\n offsetX = pos.x;\n offsetY = pos.y;\n } else if (isHorizontal && i > 0) {\n const labelWidth = estimateTextWidth(\n entry.label,\n legend.labelStyle.fontSize,\n legend.labelStyle.fontWeight,\n );\n const entryWidth = legend.swatchSize + legend.swatchGap + labelWidth + legend.entryGap;\n if (offsetX + entryWidth > legend.bounds.x + legend.bounds.width) {\n offsetX = legend.bounds.x;\n offsetY += legend.swatchSize + 6;\n }\n }\n const entryG = createSVGElement('g');\n entryG.setAttribute('class', 'oc-legend-entry');\n entryG.setAttribute('role', 'listitem');\n entryG.setAttribute('data-legend-index', String(i));\n entryG.setAttribute('data-legend-label', entry.label);\n if (entry.overflow) {\n entryG.setAttribute('data-legend-overflow', 'true');\n entryG.setAttribute('aria-label', entry.label);\n entryG.setAttribute('opacity', '0.5');\n } else {\n entryG.setAttribute(\n 'aria-label',\n `${entry.label}: ${entry.active !== false ? 'visible' : 'hidden'}`,\n );\n entryG.setAttribute('style', 'cursor: pointer');\n\n // Apply dimming for inactive entries\n if (entry.active === false) {\n entryG.setAttribute('opacity', '0.3');\n }\n }\n\n // Swatch: bare colored mark matching the chart type.\n // Circle for point/scatter, line segment for line/area, filled rect for bar.\n const midX = offsetX + legend.swatchSize / 2;\n const midY = offsetY + legend.swatchSize / 2;\n if (entry.shape === 'circle') {\n const circle = createSVGElement('circle');\n setAttrs(circle, {\n cx: midX,\n cy: midY,\n r: legend.swatchSize / 2,\n fill: entry.color,\n });\n entryG.appendChild(circle);\n } else if (entry.shape === 'line') {\n const lineWidth = legend.swatchSize;\n const line = createSVGElement('line');\n line.setAttribute('class', 'oc-legend-swatch-line');\n setAttrs(line, {\n x1: offsetX,\n y1: midY,\n x2: offsetX + lineWidth,\n y2: midY,\n stroke: entry.color,\n 'stroke-width': 2,\n 'stroke-linecap': 'round',\n });\n entryG.appendChild(line);\n } else {\n const rectSize = Math.round(legend.swatchSize * 0.6);\n const rect = createSVGElement('rect');\n rect.setAttribute('class', 'oc-legend-swatch-rect');\n setAttrs(rect, {\n x: offsetX + (legend.swatchSize - rectSize) / 2,\n y: midY - rectSize / 2,\n width: rectSize,\n height: rectSize,\n rx: 2,\n ry: 2,\n fill: entry.color,\n });\n entryG.appendChild(rect);\n }\n\n // Label\n const label = createSVGElement('text');\n setAttrs(label, {\n x: offsetX + legend.swatchSize + legend.swatchGap,\n y: offsetY + legend.swatchSize / 2,\n 'dominant-baseline': 'central',\n });\n applyTextStyle(label, legend.labelStyle);\n label.textContent = entry.label;\n entryG.appendChild(label);\n\n g.appendChild(entryG);\n\n if (!pos) {\n if (isHorizontal) {\n const labelWidth = estimateTextWidth(\n entry.label,\n legend.labelStyle.fontSize,\n legend.labelStyle.fontWeight,\n );\n const entryWidth = legend.swatchSize + legend.swatchGap + labelWidth + legend.entryGap;\n offsetX += entryWidth;\n } else {\n offsetY +=\n 'rowHeight' in legend && legend.rowHeight\n ? legend.rowHeight\n : legend.swatchSize + legend.entryGap;\n }\n }\n }\n\n parent.appendChild(g);\n}\n","/**\n * KPI metric bar rendering. Emits a `<g class=\"oc-metrics\">` group containing\n * a label/value pair per cell. Visual styling lives in `chrome.css`\n * (`.oc-metric-*` classes); this renderer only sets positions and structure.\n */\n\nimport type { ChartLayout } from '@opendata-ai/openchart-core';\nimport { createSVGElement, setAttrs } from './svg-dom';\n\n// Delta and secondary text run at a fraction of the primary value size. This\n// preserves the editorial mock's proportion (12px delta against a 22px value)\n// at any theme-driven value size, so scaling metricValue scales the whole cell.\nconst DELTA_SIZE_RATIO = 12 / 22;\n\nexport function renderMetrics(parent: SVGElement, layout: ChartLayout): void {\n const bar = layout.metrics;\n if (!bar || bar.cells.length === 0) return;\n\n // Font sizes flow from the theme. Set them inline so they override the CSS\n // defaults (.oc-metric-* in chrome.css) when a chart customizes the sizes.\n const labelSize = layout.theme.fonts.sizes.metricLabel;\n const valueSize = layout.theme.fonts.sizes.metricValue;\n const deltaSize = Math.round(valueSize * DELTA_SIZE_RATIO);\n\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-metrics');\n\n for (const cell of bar.cells) {\n const label = createSVGElement('text');\n label.setAttribute('class', 'oc-metric-label');\n setAttrs(label, { x: cell.x, y: cell.labelY, 'font-size': labelSize });\n label.textContent = cell.metric.label.toUpperCase();\n g.appendChild(label);\n\n const value = createSVGElement('text');\n value.setAttribute('class', 'oc-metric-value');\n setAttrs(value, { x: cell.x, y: cell.valueY, 'font-size': valueSize });\n value.textContent = cell.metric.value;\n\n if (cell.metric.delta) {\n const delta = createSVGElement('tspan');\n const tone = cell.metric.deltaTone ?? 'up';\n delta.setAttribute('class', tone === 'down' ? 'oc-metric-delta-down' : 'oc-metric-delta-up');\n delta.setAttribute('dx', '8');\n delta.setAttribute('font-size', String(deltaSize));\n delta.textContent = cell.metric.delta;\n value.appendChild(delta);\n }\n\n if (cell.metric.secondary) {\n const secondary = createSVGElement('tspan');\n secondary.setAttribute('class', 'oc-metric-secondary');\n secondary.setAttribute('dx', '6');\n secondary.setAttribute('font-size', String(deltaSize));\n secondary.textContent = cell.metric.secondary;\n value.appendChild(secondary);\n }\n\n g.appendChild(value);\n }\n\n parent.appendChild(g);\n}\n","/**\n * TileMap SVG renderer: converts a TileMapLayout into SVG DOM elements.\n *\n * Creates an <svg> with tile rectangles, state code labels, value labels,\n * gradient legend, and chrome. All styling via inline SVG attributes from\n * layout data. Animation is pure CSS, driven by data attributes.\n */\n\nimport type {\n ResolvedAnimation,\n TileMapLayout,\n TileMapTileMark,\n} from '@opendata-ai/openchart-core';\nimport { textAscent } from '@opendata-ai/openchart-core';\nimport { renderLegend } from './renderers/legend';\nimport { nextSvgId } from './svg-ids';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst XLINK_NS = 'http://www.w3.org/1999/xlink';\nconst BRAND_URL = 'https://tryopendata.ai';\n\nconst EASE_VAR_MAP: Record<string, string> = {\n smooth: 'var(--oc-ease-smooth)',\n snappy: 'var(--oc-ease-snappy)',\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction createSVGElement(tag: string): SVGElement {\n return document.createElementNS(SVG_NS, tag);\n}\n\nfunction 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// Chrome rendering\n// ---------------------------------------------------------------------------\n\n// Chrome y positions are top-edge coordinates; convert to the alphabetic\n// baseline via textAscent() (WebKit mishandles dominant-baseline:hanging).\nfunction renderChrome(parent: SVGElement, layout: TileMapLayout): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-chrome');\n\n const { chrome } = layout;\n const bottomOffset = layout.area.y + layout.area.height;\n\n if (chrome.title) {\n const text = createSVGElement('text');\n setAttrs(text, {\n x: chrome.title.x,\n y: chrome.title.y + textAscent(chrome.title.style.fontSize),\n });\n text.setAttribute('class', 'oc-title');\n text.setAttribute('font-family', chrome.title.style.fontFamily);\n text.setAttribute('font-size', String(chrome.title.style.fontSize));\n text.setAttribute('font-weight', String(chrome.title.style.fontWeight));\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', chrome.title.style.fill);\n text.textContent = chrome.title.text;\n g.appendChild(text);\n }\n\n if (chrome.subtitle) {\n const text = createSVGElement('text');\n setAttrs(text, {\n x: chrome.subtitle.x,\n y: chrome.subtitle.y + textAscent(chrome.subtitle.style.fontSize),\n });\n text.setAttribute('class', 'oc-subtitle');\n text.setAttribute('font-family', chrome.subtitle.style.fontFamily);\n text.setAttribute('font-size', String(chrome.subtitle.style.fontSize));\n text.setAttribute('font-weight', String(chrome.subtitle.style.fontWeight));\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n chrome.subtitle.style.fill,\n );\n text.textContent = chrome.subtitle.text;\n g.appendChild(text);\n }\n\n if (chrome.source) {\n const text = createSVGElement('text');\n setAttrs(text, {\n x: chrome.source.x,\n y: bottomOffset + chrome.source.y + textAscent(chrome.source.style.fontSize),\n });\n text.setAttribute('class', 'oc-source');\n text.setAttribute('font-family', chrome.source.style.fontFamily);\n text.setAttribute('font-size', String(chrome.source.style.fontSize));\n text.setAttribute('font-weight', String(chrome.source.style.fontWeight));\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n chrome.source.style.fill,\n );\n text.textContent = chrome.source.text;\n g.appendChild(text);\n }\n\n if (chrome.byline) {\n const text = createSVGElement('text');\n setAttrs(text, {\n x: chrome.byline.x,\n y: bottomOffset + chrome.byline.y + textAscent(chrome.byline.style.fontSize),\n });\n text.setAttribute('class', 'oc-byline');\n text.setAttribute('font-family', chrome.byline.style.fontFamily);\n text.setAttribute('font-size', String(chrome.byline.style.fontSize));\n text.setAttribute('font-weight', String(chrome.byline.style.fontWeight));\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n chrome.byline.style.fill,\n );\n text.textContent = chrome.byline.text;\n g.appendChild(text);\n }\n\n if (chrome.footer) {\n const text = createSVGElement('text');\n setAttrs(text, {\n x: chrome.footer.x,\n y: bottomOffset + chrome.footer.y + textAscent(chrome.footer.style.fontSize),\n });\n text.setAttribute('class', 'oc-footer');\n text.setAttribute('font-family', chrome.footer.style.fontFamily);\n text.setAttribute('font-size', String(chrome.footer.style.fontSize));\n text.setAttribute('font-weight', String(chrome.footer.style.fontWeight));\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n chrome.footer.style.fill,\n );\n text.textContent = chrome.footer.text;\n g.appendChild(text);\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Watermark rendering\n// ---------------------------------------------------------------------------\n\nfunction renderWatermark(parent: SVGElement, layout: TileMapLayout): void {\n if (layout.width < 480) return; // Don't render if too narrow\n\n const { width, height } = layout;\n const { theme } = layout;\n const padding = theme.spacing.padding;\n const rightEdge = width - padding;\n const bottomEdge = height - padding;\n const fill = theme.colors.axis;\n\n const a = createSVGElement('a');\n a.setAttribute('href', BRAND_URL);\n a.setAttributeNS(XLINK_NS, 'xlink:href', BRAND_URL);\n a.setAttribute('target', '_blank');\n a.setAttribute('rel', 'noopener');\n a.setAttribute('class', 'oc-chrome-ref');\n\n const text = createSVGElement('text');\n setAttrs(text, {\n x: rightEdge,\n y: bottomEdge,\n 'dominant-baseline': 'alphabetic',\n 'text-anchor': 'end',\n 'font-family': theme.fonts.family,\n 'font-size': 12,\n 'fill-opacity': 0.55,\n });\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', fill);\n\n const trySpan = createSVGElement('tspan');\n setAttrs(trySpan, { 'font-weight': 500 });\n trySpan.textContent = 'try';\n\n const openDataSpan = createSVGElement('tspan');\n setAttrs(openDataSpan, { 'font-weight': 600, 'font-size': 16 });\n openDataSpan.textContent = 'OpenData';\n\n const aiSpan = createSVGElement('tspan');\n setAttrs(aiSpan, { 'font-weight': 500 });\n aiSpan.textContent = '.ai';\n\n text.appendChild(trySpan);\n text.appendChild(openDataSpan);\n text.appendChild(aiSpan);\n a.appendChild(text);\n parent.appendChild(a);\n}\n\n// ---------------------------------------------------------------------------\n// Tiles rendering\n// ---------------------------------------------------------------------------\n\nfunction renderTiles(\n parent: SVGElement,\n tiles: TileMapTileMark[],\n animation?: ResolvedAnimation,\n): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-tilemap-tiles');\n g.setAttribute('role', 'list');\n\n // Compute per-tile delays with jitter for organic feel.\n // Base delay spreads tiles across ~800ms window, jitter adds +-40% variation\n // so some tiles pop in clusters while others have longer gaps.\n const tileDelays: number[] = [];\n if (animation?.enter) {\n const baseStagger = 800 / Math.max(tiles.length, 1);\n let seed = 17;\n for (let i = 0; i < tiles.length; i++) {\n const idx = tiles[i].animationIndex ?? i;\n seed = (seed * 1103515245 + 12345) & 0x7fffffff;\n const jitter = ((seed % 1000) / 1000 - 0.5) * 0.8;\n tileDelays.push(Math.max(0, Math.round(idx * baseStagger * (1 + jitter))));\n }\n }\n\n for (let i = 0; i < tiles.length; i++) {\n const tile = tiles[i];\n const tileGroup = createSVGElement('g');\n tileGroup.setAttribute('class', 'oc-tilemap-tile');\n tileGroup.setAttribute('data-state', tile.stateCode);\n tileGroup.setAttribute('role', 'listitem');\n if (tile.aria?.label) {\n tileGroup.setAttribute('aria-label', tile.aria.label);\n }\n\n if (animation?.enter) {\n const idx = tile.animationIndex ?? i;\n tileGroup.setAttribute('data-animation-index', String(idx));\n (tileGroup as SVGElement & ElementCSSInlineStyle).style.setProperty(\n '--oc-mark-index',\n String(idx),\n );\n (tileGroup as SVGElement & ElementCSSInlineStyle).style.setProperty(\n '--oc-tile-delay',\n `${tileDelays[i]}ms`,\n );\n }\n\n // Tile background rect\n const rect = createSVGElement('rect');\n setAttrs(rect, {\n x: tile.x,\n y: tile.y,\n width: tile.size,\n height: tile.size,\n rx: tile.cornerRadius,\n fill: tile.fill,\n 'fill-opacity': tile.fillOpacity ?? 1,\n stroke: tile.stroke,\n 'stroke-width': tile.strokeWidth,\n });\n tileGroup.appendChild(rect);\n\n // State code label\n const codeLabel = createSVGElement('text');\n setAttrs(codeLabel, {\n x: tile.label.x,\n y: tile.label.y,\n 'text-anchor': 'middle',\n 'dominant-baseline': 'central',\n 'font-family': tile.label.style.fontFamily,\n 'font-size': tile.label.style.fontSize,\n 'font-weight': tile.label.style.fontWeight,\n });\n (codeLabel as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n tile.label.style.fill,\n );\n codeLabel.textContent = tile.label.text;\n tileGroup.appendChild(codeLabel);\n\n // Value label (if visible)\n if (tile.valueLabel.visible && tile.valueLabel.text) {\n const valueLabel = createSVGElement('text');\n setAttrs(valueLabel, {\n x: tile.valueLabel.x,\n y: tile.valueLabel.y,\n 'text-anchor': 'middle',\n 'dominant-baseline': 'central',\n 'font-family': tile.valueLabel.style.fontFamily,\n 'font-size': tile.valueLabel.style.fontSize,\n 'font-weight': tile.valueLabel.style.fontWeight,\n });\n (valueLabel as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n tile.valueLabel.style.fill,\n );\n valueLabel.textContent = tile.valueLabel.text;\n tileGroup.appendChild(valueLabel);\n }\n\n g.appendChild(tileGroup);\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Gradient legend rendering\n// ---------------------------------------------------------------------------\n\nfunction renderGradientLegend(parent: SVGElement, layout: TileMapLayout): void {\n if (!layout.gradientLegend) return;\n\n const { gradientLegend } = layout;\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-tilemap-legend');\n\n // Build linear gradient in defs\n const defs = parent.querySelector('defs') || createSVGElement('defs');\n const exists = parent.querySelector('defs');\n if (!exists) {\n parent.insertBefore(defs, parent.firstChild);\n }\n\n const gradientId = nextSvgId('oc-tilemap-legend-gradient');\n const grad = createSVGElement('linearGradient');\n grad.id = gradientId;\n grad.setAttribute('x1', '0%');\n grad.setAttribute('y1', '0%');\n grad.setAttribute('x2', '100%');\n grad.setAttribute('y2', '0%');\n\n for (const stop of gradientLegend.colorStops) {\n const s = createSVGElement('stop');\n const attrs: Record<string, string | number> = {\n offset: `${stop.offset * 100}%`,\n 'stop-color': stop.color,\n };\n if (stop.opacity !== undefined) {\n attrs['stop-opacity'] = stop.opacity;\n }\n setAttrs(s, attrs);\n grad.appendChild(s);\n }\n\n (defs as SVGElement).appendChild(grad);\n\n // Gradient bar (pill-shaped)\n const barHeight = gradientLegend.bounds.height;\n const bar = createSVGElement('rect');\n setAttrs(bar, {\n x: gradientLegend.bounds.x,\n y: gradientLegend.bounds.y,\n width: gradientLegend.bounds.width,\n height: barHeight,\n rx: barHeight / 2,\n fill: `url(#${gradientId})`,\n });\n g.appendChild(bar);\n\n // Min label\n const minText = createSVGElement('text');\n setAttrs(minText, {\n x: gradientLegend.bounds.x,\n y: gradientLegend.bounds.y + gradientLegend.bounds.height + 14,\n 'text-anchor': 'start',\n 'font-family': gradientLegend.labelStyle.fontFamily,\n 'font-size': gradientLegend.labelStyle.fontSize,\n 'font-weight': gradientLegend.labelStyle.fontWeight,\n });\n (minText as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n gradientLegend.labelStyle.fill,\n );\n minText.textContent = gradientLegend.minLabel;\n g.appendChild(minText);\n\n // Max label\n const maxText = createSVGElement('text');\n setAttrs(maxText, {\n x: gradientLegend.bounds.x + gradientLegend.bounds.width,\n y: gradientLegend.bounds.y + gradientLegend.bounds.height + 14,\n 'text-anchor': 'end',\n 'font-family': gradientLegend.labelStyle.fontFamily,\n 'font-size': gradientLegend.labelStyle.fontSize,\n 'font-weight': gradientLegend.labelStyle.fontWeight,\n });\n (maxText as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n gradientLegend.labelStyle.fill,\n );\n maxText.textContent = gradientLegend.maxLabel;\n g.appendChild(maxText);\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Render a TileMapLayout to an SVG element.\n */\nexport function renderTileMapSVG(\n layout: TileMapLayout,\n opts?: { animate?: boolean },\n): SVGSVGElement {\n const { width, height, tiles, a11y, watermark, animation } = layout;\n const animate = opts?.animate && !!animation?.enter;\n\n const svg = createSVGElement('svg') as SVGSVGElement;\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`);\n svg.setAttribute('role', 'img');\n if (a11y.altText) {\n svg.setAttribute('aria-label', a11y.altText);\n }\n\n const classes = animate ? 'oc-tilemap oc-animate' : 'oc-tilemap';\n svg.setAttribute('class', classes);\n\n if (animate && animation?.enter) {\n // Target ~1s total: stagger window ~800ms + per-tile pop ~200ms\n const stagger = Math.max(5, Math.round(800 / Math.max(tiles.length, 1)));\n svg.style.setProperty('--oc-animation-duration', `${animation.enter.duration}ms`);\n svg.style.setProperty('--oc-animation-stagger', `${stagger}ms`);\n svg.style.setProperty('--oc-annotation-delay', `${animation.annotationDelay}ms`);\n const easeVar = EASE_VAR_MAP[animation.enter.ease] || EASE_VAR_MAP.smooth;\n svg.style.setProperty('--oc-animation-ease', easeVar);\n }\n\n // Empty defs element (will be filled by gradient legend)\n const defs = createSVGElement('defs');\n svg.appendChild(defs);\n\n // Render chrome\n renderChrome(svg, layout);\n\n // Render tiles\n renderTiles(svg, tiles, animate ? animation : undefined);\n\n // Render legend (gradient for quantitative, categorical for nominal)\n if (layout.categoricalLegend) {\n renderLegend(svg, layout.categoricalLegend);\n } else {\n renderGradientLegend(svg, layout);\n }\n\n // Render watermark\n if (watermark) {\n renderWatermark(svg, layout);\n }\n\n return svg;\n}\n"],"mappings":"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","names":["SVG_NS","textAscent","textAscent","estimateTextWidth","textAscent","textAscent","estimateTextWidth","estimateTextWidth","estimateTextWidth","textAscent","SVG_NS","XLINK_NS","BRAND_URL","EASE_VAR_MAP","createSVGElement","setAttrs","renderChrome","textAscent"]}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
renderSingleMark,
|
|
7
7
|
renderTileMapSVG,
|
|
8
8
|
resolveMarkFill
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-EQ6DYFO7.js";
|
|
10
10
|
|
|
11
11
|
// src/barlist-mount.ts
|
|
12
12
|
import { compileBarList } from "@opendata-ai/openchart-engine";
|
|
@@ -9510,7 +9510,15 @@ function createTable(container, spec, options) {
|
|
|
9510
9510
|
}
|
|
9511
9511
|
|
|
9512
9512
|
// src/tilemap-mount.ts
|
|
9513
|
+
import { BREAKPOINT_COMPACT_MAX, BREAKPOINT_MEDIUM_MAX } from "@opendata-ai/openchart-core";
|
|
9513
9514
|
import { compileTileMap } from "@opendata-ai/openchart-engine";
|
|
9515
|
+
var TILEMAP_GRID_ROWS = 8;
|
|
9516
|
+
var TILEMAP_TILE_GAP = 5;
|
|
9517
|
+
var TILEMAP_CHROME_RESERVE = 180;
|
|
9518
|
+
function pickTargetTileSize(width) {
|
|
9519
|
+
if (width < BREAKPOINT_COMPACT_MAX) return 34;
|
|
9520
|
+
return 40;
|
|
9521
|
+
}
|
|
9514
9522
|
function resolveDarkMode6(mode) {
|
|
9515
9523
|
if (mode === "force") return true;
|
|
9516
9524
|
if (mode === "off" || mode === void 0) return false;
|
|
@@ -9540,7 +9548,12 @@ function createTileMap(container, spec, options) {
|
|
|
9540
9548
|
function getContainerDimensions() {
|
|
9541
9549
|
const rect = container.getBoundingClientRect();
|
|
9542
9550
|
const width = Math.max(rect.width || 600, 100);
|
|
9543
|
-
|
|
9551
|
+
if (width >= BREAKPOINT_MEDIUM_MAX) {
|
|
9552
|
+
return { width, height: width };
|
|
9553
|
+
}
|
|
9554
|
+
const targetTile = pickTargetTileSize(width);
|
|
9555
|
+
const height = targetTile * TILEMAP_GRID_ROWS + TILEMAP_TILE_GAP * (TILEMAP_GRID_ROWS - 1) + TILEMAP_CHROME_RESERVE;
|
|
9556
|
+
return { width, height };
|
|
9544
9557
|
}
|
|
9545
9558
|
function compile() {
|
|
9546
9559
|
const { width, height } = getContainerDimensions();
|