@vielzeug/prism 26.11.4 → 26.11.6
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/README.md +25 -10
- package/dist/_dev.js +1 -2
- package/dist/_tappers.js +1 -2
- package/dist/animation/easing.js +1 -2
- package/dist/animation/motion.js +0 -1
- package/dist/animation/reveal.cjs +1 -1
- package/dist/animation/reveal.cjs.map +1 -1
- package/dist/animation/reveal.js +29 -30
- package/dist/animation/transition.js +1 -2
- package/dist/animation/tween.js +1 -2
- package/dist/axes/axis.js +1 -2
- package/dist/axes/grid.js +1 -2
- package/dist/axes/scale-utils.js +1 -2
- package/dist/charts/area/area-chart.cjs +1 -1
- package/dist/charts/area/area-chart.cjs.map +1 -1
- package/dist/charts/area/area-chart.js +34 -35
- package/dist/charts/area/area-renderer.cjs +1 -1
- package/dist/charts/area/area-renderer.cjs.map +1 -1
- package/dist/charts/area/area-renderer.js +56 -57
- package/dist/charts/area/area-renderer.js.map +1 -1
- package/dist/charts/bar/bar-chart.cjs +1 -1
- package/dist/charts/bar/bar-chart.cjs.map +1 -1
- package/dist/charts/bar/bar-chart.js +80 -81
- package/dist/charts/bar/bar-chart.js.map +1 -1
- package/dist/charts/bar/bar-hit-test.js +1 -2
- package/dist/charts/bar/bar-renderer.cjs +1 -1
- package/dist/charts/bar/bar-renderer.cjs.map +1 -1
- package/dist/charts/bar/bar-renderer.js +42 -43
- package/dist/charts/bar/bar-value-labels.cjs +1 -1
- package/dist/charts/bar/bar-value-labels.cjs.map +1 -1
- package/dist/charts/bar/bar-value-labels.js +17 -18
- package/dist/charts/heatmap/heatmap-chart.cjs +1 -1
- package/dist/charts/heatmap/heatmap-chart.cjs.map +1 -1
- package/dist/charts/heatmap/heatmap-chart.js +43 -44
- package/dist/charts/heatmap/heatmap-color.js +1 -2
- package/dist/charts/line/line-chart.cjs +1 -1
- package/dist/charts/line/line-chart.cjs.map +1 -1
- package/dist/charts/line/line-chart.js +41 -42
- package/dist/charts/line/line-renderer.cjs +1 -1
- package/dist/charts/line/line-renderer.cjs.map +1 -1
- package/dist/charts/line/line-renderer.js +81 -82
- package/dist/charts/line/line-renderer.js.map +1 -1
- package/dist/charts/pie/pie-chart.cjs +1 -1
- package/dist/charts/pie/pie-chart.cjs.map +1 -1
- package/dist/charts/pie/pie-chart.js +69 -70
- package/dist/charts/pie/pie-renderer.js +1 -2
- package/dist/charts/radar/radar-chart.cjs +1 -1
- package/dist/charts/radar/radar-chart.cjs.map +1 -1
- package/dist/charts/radar/radar-chart.js +118 -119
- package/dist/charts/radar/radar-chart.js.map +1 -1
- package/dist/charts/radar/radar-geometry.cjs +1 -1
- package/dist/charts/radar/radar-geometry.cjs.map +1 -1
- package/dist/charts/radar/radar-geometry.js +15 -16
- package/dist/charts/scatter/scatter-chart.cjs +1 -1
- package/dist/charts/scatter/scatter-chart.cjs.map +1 -1
- package/dist/charts/scatter/scatter-chart.js +33 -34
- package/dist/charts/scatter/scatter-renderer.cjs +1 -1
- package/dist/charts/scatter/scatter-renderer.cjs.map +1 -1
- package/dist/charts/scatter/scatter-renderer.js +22 -23
- package/dist/charts/sparkline/sparkline.cjs +1 -1
- package/dist/charts/sparkline/sparkline.cjs.map +1 -1
- package/dist/charts/sparkline/sparkline.js +87 -88
- package/dist/charts/sparkline/sparkline.js.map +1 -1
- package/dist/core/cartesian-model.js +1 -2
- package/dist/core/cartesian-scales.js +1 -2
- package/dist/core/chart-base.cjs +1 -1
- package/dist/core/chart-base.cjs.map +1 -1
- package/dist/core/chart-base.js +13 -14
- package/dist/core/chart-scaffold.cjs +1 -1
- package/dist/core/chart-scaffold.cjs.map +1 -1
- package/dist/core/chart-scaffold.js +33 -34
- package/dist/core/datum-style.js +1 -2
- package/dist/core/ids.js +1 -2
- package/dist/core/layout.js +1 -2
- package/dist/core/polar.js +1 -2
- package/dist/core/responsive.js +1 -2
- package/dist/core/series-id.js +1 -2
- package/dist/errors.js +1 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +14 -14
- package/dist/interaction/announcer.js +1 -2
- package/dist/interaction/crosshair.js +1 -2
- package/dist/interaction/events.js +1 -2
- package/dist/interaction/legend.js +1 -2
- package/dist/interaction/scatter-interaction.cjs +1 -1
- package/dist/interaction/scatter-interaction.cjs.map +1 -1
- package/dist/interaction/scatter-interaction.js +26 -27
- package/dist/interaction/series-interaction.cjs +1 -1
- package/dist/interaction/series-interaction.cjs.map +1 -1
- package/dist/interaction/series-interaction.js +40 -41
- package/dist/interaction/tooltip.js +1 -2
- package/dist/prism.cjs +1 -1
- package/dist/prism.cjs.map +1 -1
- package/dist/prism.iife.js +1 -1
- package/dist/prism.iife.js.map +1 -1
- package/dist/prism.js +52 -103
- package/dist/prism.js.map +1 -1
- package/dist/scales/band.js +1 -2
- package/dist/scales/linear.js +1 -2
- package/dist/scales/time.js +1 -2
- package/dist/svg/element.js +1 -2
- package/dist/svg/path.js +1 -2
- package/dist/svg/text.js +1 -2
- package/dist/theme/index.js +1 -2
- package/package.json +6 -6
|
@@ -1,135 +1,135 @@
|
|
|
1
1
|
import "../../_dev.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { resolveEasing as e } from "../../animation/easing.js";
|
|
3
|
+
import { resolveMotion as t } from "../../animation/motion.js";
|
|
4
|
+
import { cancelReveal as n, playTraceReveal as r } from "../../animation/reveal.js";
|
|
5
|
+
import { startTween as i } from "../../animation/transition.js";
|
|
6
|
+
import { tweenNumber as a } from "../../animation/tween.js";
|
|
7
7
|
import { computeStyleRuns as o, hasStyledRuns as s } from "../../core/datum-style.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
8
|
+
import { createSvgElement as c, setAttributes as l } from "../../svg/element.js";
|
|
9
|
+
import { linePath as u, monotonePath as d, stepPath as f } from "../../svg/path.js";
|
|
10
|
+
// src/charts/line/line-renderer.ts
|
|
11
11
|
var p = /* @__PURE__ */ new WeakMap(), m = /* @__PURE__ */ new WeakMap();
|
|
12
12
|
function buildPath(e, t) {
|
|
13
|
-
return t === "monotone" ?
|
|
13
|
+
return t === "monotone" ? d(e) : t === "step" ? f(e) : u(e);
|
|
14
14
|
}
|
|
15
|
-
function renderLine(
|
|
16
|
-
let h = s(
|
|
15
|
+
function renderLine(u, d, f) {
|
|
16
|
+
let h = s(f.marks), g = f.marks ?? [], _ = t(f.transition), v = _.duration, y = e(_.easing), b = null, x = [], S = [];
|
|
17
17
|
if (h) {
|
|
18
|
-
x = o(g,
|
|
19
|
-
let
|
|
20
|
-
for (let
|
|
21
|
-
S = x.map((t,
|
|
22
|
-
let
|
|
23
|
-
if (
|
|
24
|
-
let
|
|
18
|
+
x = o(g, d.length);
|
|
19
|
+
let e = [...u.querySelectorAll(".prism-line-path")];
|
|
20
|
+
for (let t of e.slice(x.length)) t.remove();
|
|
21
|
+
S = x.map((t, n) => {
|
|
22
|
+
let r = e[n];
|
|
23
|
+
if (r) return r;
|
|
24
|
+
let i = c("path", {
|
|
25
25
|
class: "prism-line-path",
|
|
26
26
|
fill: "none"
|
|
27
27
|
});
|
|
28
|
-
return
|
|
28
|
+
return u.appendChild(i), i;
|
|
29
29
|
});
|
|
30
|
-
for (let [e,
|
|
31
|
-
opacity:
|
|
32
|
-
stroke:
|
|
33
|
-
"stroke-dasharray":
|
|
34
|
-
"stroke-width":
|
|
35
|
-
}), S[e].style.strokeWidth =
|
|
30
|
+
for (let [e, t] of x.entries()) l(S[e], {
|
|
31
|
+
opacity: t.opacity,
|
|
32
|
+
stroke: f.color,
|
|
33
|
+
"stroke-dasharray": t.dash,
|
|
34
|
+
"stroke-width": f.strokeWidth ?? 2
|
|
35
|
+
}), S[e].style.strokeWidth = f.strokeWidth === void 0 ? "" : String(f.strokeWidth);
|
|
36
36
|
} else {
|
|
37
|
-
let
|
|
38
|
-
b =
|
|
39
|
-
for (let
|
|
40
|
-
b || (b =
|
|
37
|
+
let e = [...u.querySelectorAll(".prism-line-path")];
|
|
38
|
+
b = e[0] ?? null;
|
|
39
|
+
for (let t of e.slice(1)) t.remove();
|
|
40
|
+
b || (b = c("path", {
|
|
41
41
|
class: "prism-line-path",
|
|
42
42
|
fill: "none"
|
|
43
|
-
}),
|
|
43
|
+
}), u.appendChild(b)), l(b, {
|
|
44
44
|
opacity: void 0,
|
|
45
|
-
stroke:
|
|
45
|
+
stroke: f.color,
|
|
46
46
|
"stroke-dasharray": void 0,
|
|
47
|
-
"stroke-width":
|
|
48
|
-
}), b.style.strokeWidth =
|
|
47
|
+
"stroke-width": f.strokeWidth ?? 2
|
|
48
|
+
}), b.style.strokeWidth = f.strokeWidth === void 0 ? "" : String(f.strokeWidth);
|
|
49
49
|
}
|
|
50
50
|
let draw = (e) => {
|
|
51
|
-
if (h) for (let [
|
|
52
|
-
else
|
|
53
|
-
}, C =
|
|
54
|
-
if (
|
|
55
|
-
if (p.get(
|
|
56
|
-
for (; C.children.length >
|
|
57
|
-
for (let
|
|
58
|
-
let
|
|
59
|
-
|
|
60
|
-
cx:
|
|
61
|
-
cy:
|
|
62
|
-
fill:
|
|
63
|
-
opacity: g[
|
|
64
|
-
r:
|
|
51
|
+
if (h) for (let [t, n] of x.entries()) l(S[t], { d: buildPath(e.slice(n.start, n.end + 1), f.curve) });
|
|
52
|
+
else l(b, { d: buildPath(e, f.curve) });
|
|
53
|
+
}, C = u.querySelector(".prism-line-dots");
|
|
54
|
+
if (f.showPoints ? C || (C = c("g", { class: "prism-line-dots" }), u.appendChild(C)) : C &&= (C.remove(), null), v === 0) {
|
|
55
|
+
if (p.get(u)?.(), n(u), draw(d), m.set(u, d), C) {
|
|
56
|
+
for (; C.children.length > d.length;) C.removeChild(C.lastChild);
|
|
57
|
+
for (let e = 0; e < d.length; e++) {
|
|
58
|
+
let t = C.children[e];
|
|
59
|
+
t || (t = c("circle", { class: "prism-line-dot" }), C.appendChild(t)), l(t, {
|
|
60
|
+
cx: d[e].x,
|
|
61
|
+
cy: d[e].y,
|
|
62
|
+
fill: f.color,
|
|
63
|
+
opacity: g[e]?.opacity,
|
|
64
|
+
r: f.pointRadius
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
|
-
p.get(
|
|
71
|
-
let w = !m.has(
|
|
70
|
+
p.get(u)?.(), n(u);
|
|
71
|
+
let w = !m.has(u);
|
|
72
72
|
if (C) {
|
|
73
|
-
for (; C.children.length >
|
|
74
|
-
for (let
|
|
75
|
-
let
|
|
76
|
-
t
|
|
77
|
-
fill:
|
|
78
|
-
opacity: g[
|
|
79
|
-
r:
|
|
80
|
-
}), C.appendChild(
|
|
73
|
+
for (; C.children.length > d.length;) C.removeChild(C.lastChild);
|
|
74
|
+
for (let e = C.children.length; e < d.length; e++) {
|
|
75
|
+
let t = c("circle", { class: "prism-line-dot" });
|
|
76
|
+
l(t, {
|
|
77
|
+
fill: f.color,
|
|
78
|
+
opacity: g[e]?.opacity,
|
|
79
|
+
r: f.pointRadius
|
|
80
|
+
}), C.appendChild(t);
|
|
81
81
|
}
|
|
82
|
-
for (let e = 0; e < C.children.length; e++)
|
|
82
|
+
for (let e = 0; e < C.children.length; e++) l(C.children[e], { opacity: g[e]?.opacity });
|
|
83
83
|
}
|
|
84
84
|
if (w) {
|
|
85
|
-
if (draw(
|
|
86
|
-
let
|
|
87
|
-
|
|
88
|
-
cx:
|
|
89
|
-
cy:
|
|
85
|
+
if (draw(d), m.set(u, d), C) for (let [e, t] of d.entries()) {
|
|
86
|
+
let n = C.children[e];
|
|
87
|
+
n && l(n, {
|
|
88
|
+
cx: t.x,
|
|
89
|
+
cy: t.y
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
|
-
if (
|
|
93
|
-
let e = b ?? S[0],
|
|
92
|
+
if (d.length > 1) {
|
|
93
|
+
let e = b ?? S[0], n = f.strokeWidth ?? (Number.parseFloat(getComputedStyle(e).strokeWidth) || 2), i = h ? x.map((e, t) => ({
|
|
94
94
|
d: S[t].getAttribute("d"),
|
|
95
|
-
end: e.end / (
|
|
96
|
-
start: e.start / (
|
|
95
|
+
end: e.end / (d.length - 1),
|
|
96
|
+
start: e.start / (d.length - 1)
|
|
97
97
|
})) : [{
|
|
98
98
|
d: b.getAttribute("d"),
|
|
99
99
|
end: 1,
|
|
100
100
|
start: 0
|
|
101
101
|
}];
|
|
102
|
-
|
|
102
|
+
r(u, f.bounds, i, Math.max(n, f.showPoints ? f.pointRadius * 2 : 0) + 2, t(f.transition, { defaultDuration: 420 }), f.disposalSignal);
|
|
103
103
|
}
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
|
-
let T = [], E = m.get(
|
|
107
|
-
for (let [e, t] of
|
|
106
|
+
let T = [], E = m.get(u) ?? d;
|
|
107
|
+
for (let [e, t] of d.entries()) T.push(E[e] ?? E.at(-1) ?? t);
|
|
108
108
|
let paintFrame = (e) => {
|
|
109
|
-
let
|
|
109
|
+
let t = d.map((t, n) => {
|
|
110
110
|
let r = T[n] ?? t;
|
|
111
111
|
return {
|
|
112
|
-
x:
|
|
113
|
-
y:
|
|
112
|
+
x: a(r.x, t.x, e),
|
|
113
|
+
y: a(r.y, t.y, e)
|
|
114
114
|
};
|
|
115
115
|
});
|
|
116
|
-
if (m.set(
|
|
117
|
-
let
|
|
118
|
-
|
|
119
|
-
cx:
|
|
120
|
-
cy:
|
|
116
|
+
if (m.set(u, t), draw(t), C) for (let e = 0; e < d.length; e++) {
|
|
117
|
+
let n = C.children[e];
|
|
118
|
+
n && l(n, {
|
|
119
|
+
cx: t[e].x,
|
|
120
|
+
cy: t[e].y
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
123
|
};
|
|
124
|
-
paintFrame(0), p.set(
|
|
124
|
+
paintFrame(0), p.set(u, i({
|
|
125
125
|
count: 1,
|
|
126
126
|
duration: v,
|
|
127
127
|
easing: y,
|
|
128
128
|
onComplete: () => {
|
|
129
|
-
p.delete(
|
|
129
|
+
p.delete(u), m.set(u, d);
|
|
130
130
|
},
|
|
131
131
|
onFrame: (e) => paintFrame(e(0)),
|
|
132
|
-
signal:
|
|
132
|
+
signal: f.disposalSignal
|
|
133
133
|
}));
|
|
134
134
|
}
|
|
135
135
|
function computePoints(e, t, n) {
|
|
@@ -138,7 +138,6 @@ function computePoints(e, t, n) {
|
|
|
138
138
|
y: n.map(e.value)
|
|
139
139
|
}));
|
|
140
140
|
}
|
|
141
|
-
//#endregion
|
|
142
141
|
export { computePoints, renderLine };
|
|
143
142
|
|
|
144
143
|
//# sourceMappingURL=line-renderer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-renderer.js","names":["activeAnimations","drawnPoints","curve","monotonePath","pts","stepPath","linePath","styled","hasStyledRuns","options","marks","motion","resolveMotion","dur","easing","resolveEasing","path","runs","runPaths","computeStyleRuns","points","existing","parent","extra","reuse","created","createSvgElement","r","run","setAttributes","stale","dotsGroup","cancelReveal","i","c","isMount","point","renderedPath","strokeWidth","traces","fromPts","drawn","to","interpolated","from","tweenNumber","startTween","progress","data","d","xScale","yScale"],"sources":["../../../src/charts/line/line-renderer.ts"],"sourcesContent":["import { warn } from '../../_dev';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { cancelReveal, playTraceReveal } from '../../animation/reveal';\nimport { startTween } from '../../animation/transition';\nimport { tweenNumber } from '../../animation/tween';\nimport { computeStyleRuns, type DatumMark, hasStyledRuns, type StyleRun } from '../../core/datum-style';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ContinuousDatum, Scale, TransitionOption } from '../../types';\n\nexport interface LineRenderOptions {\n /** Plot-area size in area-local coordinates: bounds the entrance mask. */\n bounds: { height: number; width: number };\n color: string;\n curve: 'linear' | 'monotone' | 'step';\n /** Aborted when the owning chart is disposed: stops the transition's `requestAnimationFrame` loop from rescheduling. */\n disposalSignal?: AbortSignal;\n /** Per-datum presentation parallel to `points`; styled runs split the line into subpaths. */\n marks?: readonly DatumMark[];\n pointRadius: number;\n showPoints: boolean;\n /** Explicit width beats the `--prism-line-width` theme token. */\n strokeWidth?: number;\n transition?: TransitionOption;\n}\n\nconst activeAnimations = new WeakMap<SVGGElement, () => void>();\n// Geometry currently on screen, so an update interpolates from it even when the\n// series hides its point markers (the dots would otherwise be the only record).\nconst drawnPoints = new WeakMap<SVGGElement, Point[]>();\n\nfunction buildPath(pts: Point[], curve: LineRenderOptions['curve']): string {\n return curve === 'monotone' ? monotonePath(pts) : curve === 'step' ? stepPath(pts) : linePath(pts);\n}\n\nexport function renderLine(parent: SVGGElement, points: Point[], options: LineRenderOptions): void {\n const styled = hasStyledRuns(options.marks);\n const marks = options.marks ?? [];\n const motion = resolveMotion(options.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n let path: SVGPathElement | null = null;\n let runs: readonly StyleRun[] = [];\n let runPaths: SVGPathElement[] = [];\n\n if (styled) {\n runs = computeStyleRuns(marks, points.length);\n\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n for (const extra of existing.slice(runs.length)) extra.remove();\n\n runPaths = runs.map((_, r) => {\n const reuse = existing[r];\n\n if (reuse) return reuse;\n\n const created = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n\n parent.appendChild(created);\n\n return created;\n });\n\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], {\n opacity: run.opacity,\n stroke: options.color,\n 'stroke-dasharray': run.dash,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n runPaths[r].style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n } else {\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n path = existing[0] ?? null;\n\n for (const stale of existing.slice(1)) stale.remove();\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n parent.appendChild(path);\n }\n\n setAttributes(path, {\n opacity: undefined,\n stroke: options.color,\n 'stroke-dasharray': undefined,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n path.style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n\n const draw = (pts: Point[]): void => {\n if (styled) {\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], { d: buildPath(pts.slice(run.start, run.end + 1), options.curve) });\n }\n } else {\n setAttributes(path!, { d: buildPath(pts, options.curve) });\n }\n };\n\n let dotsGroup = parent.querySelector<SVGGElement>('.prism-line-dots');\n\n if (options.showPoints) {\n if (!dotsGroup) {\n dotsGroup = createSvgElement('g', { class: 'prism-line-dots' });\n parent.appendChild(dotsGroup);\n }\n } else if (dotsGroup) {\n dotsGroup.remove();\n dotsGroup = null;\n }\n\n if (dur === 0) {\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = 0; i < points.length; i++) {\n let c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (!c) {\n c = createSvgElement('circle', { class: 'prism-line-dot' });\n dotsGroup.appendChild(c);\n }\n\n setAttributes(c, {\n cx: points[i].x,\n cy: points[i].y,\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n }\n }\n\n return;\n }\n\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n\n const isMount = !drawnPoints.has(parent);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = dotsGroup.children.length; i < points.length; i++) {\n const c = createSvgElement('circle', { class: 'prism-line-dot' });\n\n setAttributes(c, {\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n dotsGroup.appendChild(c);\n }\n\n for (let i = 0; i < dotsGroup.children.length; i++) {\n setAttributes(dotsGroup.children[i] as SVGCircleElement, { opacity: marks[i]?.opacity });\n }\n }\n\n if (isMount) {\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n for (const [i, point] of points.entries()) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: point.x, cy: point.y });\n }\n }\n\n if (points.length > 1) {\n const renderedPath = path ?? runPaths[0];\n const strokeWidth = options.strokeWidth ?? (Number.parseFloat(getComputedStyle(renderedPath).strokeWidth) || 2);\n const traces = styled\n ? runs.map((run, i) => ({\n d: runPaths[i].getAttribute('d')!,\n end: run.end / (points.length - 1),\n start: run.start / (points.length - 1),\n }))\n : [{ d: path!.getAttribute('d')!, end: 1, start: 0 }];\n\n // A wide trace also uncovers markers as it reaches them, without a second timeline.\n playTraceReveal(\n parent,\n options.bounds,\n traces,\n Math.max(strokeWidth, options.showPoints ? options.pointRadius * 2 : 0) + 2,\n resolveMotion(options.transition, { defaultDuration: 420 }),\n options.disposalSignal,\n );\n }\n\n return;\n }\n\n const fromPts: Point[] = [];\n const drawn = drawnPoints.get(parent) ?? points;\n\n for (const [i, to] of points.entries()) {\n fromPts.push(drawn[i] ?? drawn.at(-1) ?? to);\n }\n\n const paintFrame = (e: number): void => {\n const interpolated: Point[] = points.map((to, i) => {\n const from = fromPts[i] ?? to;\n\n return { x: tweenNumber(from.x, to.x, e), y: tweenNumber(from.y, to.y, e) };\n });\n\n drawnPoints.set(parent, interpolated);\n draw(interpolated);\n\n if (dotsGroup) {\n for (let i = 0; i < points.length; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: interpolated[i].x, cy: interpolated[i].y });\n }\n }\n };\n\n // The starting geometry goes on screen immediately: `startTween` only paints on\n // the first frame callback, which would otherwise leave one blank frame.\n paintFrame(0);\n\n activeAnimations.set(\n parent,\n startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => {\n activeAnimations.delete(parent);\n drawnPoints.set(parent, points);\n },\n onFrame: (progress) => paintFrame(progress(0)),\n signal: options.disposalSignal,\n }),\n );\n}\n\nexport function computePoints(data: ContinuousDatum[], xScale: Scale<Date | number>, yScale: Scale<number>): Point[] {\n if (data.some((d) => d.key == null)) {\n warn(\n 'computePoints: datum.key is null or undefined: data must use the Datum shape { key, value }. Did you pass { x, y } instead?',\n );\n } else if (data.some((d) => typeof d.key === 'string')) {\n warn('computePoints: string keys are not supported for line/area charts: use numeric or Date keys.');\n }\n\n return data.map((d) => ({\n x: xScale.map(d.key as Date | number),\n y: yScale.map(d.value),\n }));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"line-renderer.js","names":["activeAnimations","drawnPoints","curve","monotonePath","pts","stepPath","linePath","styled","hasStyledRuns","options","marks","motion","resolveMotion","dur","easing","resolveEasing","path","runs","runPaths","computeStyleRuns","points","existing","parent","extra","reuse","r","created","createSvgElement","run","setAttributes","stale","dotsGroup","cancelReveal","i","c","isMount","point","renderedPath","strokeWidth","traces","fromPts","drawn","to","interpolated","from","tweenNumber","startTween","progress","data","d","xScale","yScale"],"sources":["../../../src/charts/line/line-renderer.ts"],"sourcesContent":["import { warn } from '../../_dev';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { cancelReveal, playTraceReveal } from '../../animation/reveal';\nimport { startTween } from '../../animation/transition';\nimport { tweenNumber } from '../../animation/tween';\nimport { computeStyleRuns, type DatumMark, hasStyledRuns, type StyleRun } from '../../core/datum-style';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ContinuousDatum, Scale, TransitionOption } from '../../types';\n\nexport interface LineRenderOptions {\n /** Plot-area size in area-local coordinates: bounds the entrance mask. */\n bounds: { height: number; width: number };\n color: string;\n curve: 'linear' | 'monotone' | 'step';\n /** Aborted when the owning chart is disposed: stops the transition's `requestAnimationFrame` loop from rescheduling. */\n disposalSignal?: AbortSignal;\n /** Per-datum presentation parallel to `points`; styled runs split the line into subpaths. */\n marks?: readonly DatumMark[];\n pointRadius: number;\n showPoints: boolean;\n /** Explicit width beats the `--prism-line-width` theme token. */\n strokeWidth?: number;\n transition?: TransitionOption;\n}\n\nconst activeAnimations = new WeakMap<SVGGElement, () => void>();\n// Geometry currently on screen, so an update interpolates from it even when the\n// series hides its point markers (the dots would otherwise be the only record).\nconst drawnPoints = new WeakMap<SVGGElement, Point[]>();\n\nfunction buildPath(pts: Point[], curve: LineRenderOptions['curve']): string {\n return curve === 'monotone' ? monotonePath(pts) : curve === 'step' ? stepPath(pts) : linePath(pts);\n}\n\nexport function renderLine(parent: SVGGElement, points: Point[], options: LineRenderOptions): void {\n const styled = hasStyledRuns(options.marks);\n const marks = options.marks ?? [];\n const motion = resolveMotion(options.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n let path: SVGPathElement | null = null;\n let runs: readonly StyleRun[] = [];\n let runPaths: SVGPathElement[] = [];\n\n if (styled) {\n runs = computeStyleRuns(marks, points.length);\n\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n for (const extra of existing.slice(runs.length)) extra.remove();\n\n runPaths = runs.map((_, r) => {\n const reuse = existing[r];\n\n if (reuse) return reuse;\n\n const created = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n\n parent.appendChild(created);\n\n return created;\n });\n\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], {\n opacity: run.opacity,\n stroke: options.color,\n 'stroke-dasharray': run.dash,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n runPaths[r].style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n } else {\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n path = existing[0] ?? null;\n\n for (const stale of existing.slice(1)) stale.remove();\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n parent.appendChild(path);\n }\n\n setAttributes(path, {\n opacity: undefined,\n stroke: options.color,\n 'stroke-dasharray': undefined,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n path.style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n\n const draw = (pts: Point[]): void => {\n if (styled) {\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], { d: buildPath(pts.slice(run.start, run.end + 1), options.curve) });\n }\n } else {\n setAttributes(path!, { d: buildPath(pts, options.curve) });\n }\n };\n\n let dotsGroup = parent.querySelector<SVGGElement>('.prism-line-dots');\n\n if (options.showPoints) {\n if (!dotsGroup) {\n dotsGroup = createSvgElement('g', { class: 'prism-line-dots' });\n parent.appendChild(dotsGroup);\n }\n } else if (dotsGroup) {\n dotsGroup.remove();\n dotsGroup = null;\n }\n\n if (dur === 0) {\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = 0; i < points.length; i++) {\n let c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (!c) {\n c = createSvgElement('circle', { class: 'prism-line-dot' });\n dotsGroup.appendChild(c);\n }\n\n setAttributes(c, {\n cx: points[i].x,\n cy: points[i].y,\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n }\n }\n\n return;\n }\n\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n\n const isMount = !drawnPoints.has(parent);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = dotsGroup.children.length; i < points.length; i++) {\n const c = createSvgElement('circle', { class: 'prism-line-dot' });\n\n setAttributes(c, {\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n dotsGroup.appendChild(c);\n }\n\n for (let i = 0; i < dotsGroup.children.length; i++) {\n setAttributes(dotsGroup.children[i] as SVGCircleElement, { opacity: marks[i]?.opacity });\n }\n }\n\n if (isMount) {\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n for (const [i, point] of points.entries()) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: point.x, cy: point.y });\n }\n }\n\n if (points.length > 1) {\n const renderedPath = path ?? runPaths[0];\n const strokeWidth = options.strokeWidth ?? (Number.parseFloat(getComputedStyle(renderedPath).strokeWidth) || 2);\n const traces = styled\n ? runs.map((run, i) => ({\n d: runPaths[i].getAttribute('d')!,\n end: run.end / (points.length - 1),\n start: run.start / (points.length - 1),\n }))\n : [{ d: path!.getAttribute('d')!, end: 1, start: 0 }];\n\n // A wide trace also uncovers markers as it reaches them, without a second timeline.\n playTraceReveal(\n parent,\n options.bounds,\n traces,\n Math.max(strokeWidth, options.showPoints ? options.pointRadius * 2 : 0) + 2,\n resolveMotion(options.transition, { defaultDuration: 420 }),\n options.disposalSignal,\n );\n }\n\n return;\n }\n\n const fromPts: Point[] = [];\n const drawn = drawnPoints.get(parent) ?? points;\n\n for (const [i, to] of points.entries()) {\n fromPts.push(drawn[i] ?? drawn.at(-1) ?? to);\n }\n\n const paintFrame = (e: number): void => {\n const interpolated: Point[] = points.map((to, i) => {\n const from = fromPts[i] ?? to;\n\n return { x: tweenNumber(from.x, to.x, e), y: tweenNumber(from.y, to.y, e) };\n });\n\n drawnPoints.set(parent, interpolated);\n draw(interpolated);\n\n if (dotsGroup) {\n for (let i = 0; i < points.length; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: interpolated[i].x, cy: interpolated[i].y });\n }\n }\n };\n\n // The starting geometry goes on screen immediately: `startTween` only paints on\n // the first frame callback, which would otherwise leave one blank frame.\n paintFrame(0);\n\n activeAnimations.set(\n parent,\n startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => {\n activeAnimations.delete(parent);\n drawnPoints.set(parent, points);\n },\n onFrame: (progress) => paintFrame(progress(0)),\n signal: options.disposalSignal,\n }),\n );\n}\n\nexport function computePoints(data: ContinuousDatum[], xScale: Scale<Date | number>, yScale: Scale<number>): Point[] {\n if (data.some((d) => d.key == null)) {\n warn(\n 'computePoints: datum.key is null or undefined: data must use the Datum shape { key, value }. Did you pass { x, y } instead?',\n );\n } else if (data.some((d) => typeof d.key === 'string')) {\n warn('computePoints: string keys are not supported for line/area charts: use numeric or Date keys.');\n }\n\n return data.map((d) => ({\n x: xScale.map(d.key as Date | number),\n y: yScale.map(d.value),\n }));\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../
|
|
1
|
+
const e=require("../../animation/easing.cjs"),t=require("../../animation/motion.cjs"),n=require("../../animation/transition.cjs"),r=require("../../animation/tween.cjs"),i=require("../../core/chart-scaffold.cjs"),a=require("../../svg/element.cjs"),o=require("../../svg/text.cjs"),s=require("../../theme/index.cjs"),c=require("./pie-renderer.cjs");var l=2*Math.PI,u=12;function labelFits(e,t){let n=e.outerRadius-e.innerRadius,r=(e.outerRadius+e.innerRadius)/2,i=(e.endAngle-e.startAngle-2*e.padAngle)*r;return n>=u*1.4&&i>=o.estimateTextWidth(t,u)+8}var d=-Math.PI/2,f=Math.PI/2;function semiAngles(e){return e===`semi`?{end:f,start:d}:{end:l,start:0}}function createPieChart(o,l){let u=l.variant??`pie`,d=l.padPixels??(u===`pie`?0:8),f=l.cornerRadius??(u===`pie`?0:8),p=l.data,m=a.createSvgElement(`circle`,{class:`prism-pie-bg`,"pointer-events":`none`}),h=a.createSvgElement(`g`,{class:`prism-pie-slices`,"shape-rendering":`geometricPrecision`}),g=a.createSvgElement(`g`,{class:`prism-pie-labels`,"pointer-events":`none`}),_=[],v=[],y=null;function renderLabels(e){g.replaceChildren();for(let t=0;t<_.length;t++){let n=_[t],r=e[t];if(!r?.label||!labelFits(n,r.label))continue;let{x:i,y:o}=c.arcCentroid(n),s=a.createSvgElement(`text`,{class:`prism-pie-label`});a.setAttributes(s,{"dominant-baseline":`middle`,fill:`var(--prism-pie-label-color, #fff)`,"font-family":`var(--prism-font-family, system-ui)`,"font-size":`var(--prism-pie-label-size, 12px)`,"text-anchor":`middle`,x:i,y:o}),s.textContent=r.label,g.appendChild(s)}}return i.createRadialScaffold(o,{a11y:l.a11y,legend:l.legend,tooltip:l.tooltip},i=>{let{legend:b,svg:x,tooltip:S}=i,C=p.some(e=>e.value>0);b?.update(C?p.map((e,t)=>({color:e.color??s.seriesColor(t),name:e.label??``})):[]),x.contains(m)||(x.appendChild(m),x.appendChild(h),x.appendChild(g));let{height:w,width:T}=i.dimensions,E=u===`semi`,D=T/2,O=E?w*.85:w/2,k=E?Math.min(D,O)-8:Math.min(T,w)/2-8,A=u===`pie`?0:Math.round(k*.55),j=l.innerRadius===void 0?A:l.innerRadius,M=Math.max(j+1,k),N=p,{end:P,start:F}=semiAngles(u);for(_=c.computeArcs(N,D,O,M,j,F,P,d,f,e=>s.seriesColor(e),!1),a.setAttributes(m,{cx:D,cy:O,r:j>0?j:0}),m.setAttribute(`style`,`fill:var(--prism-bg,#fff)`);h.children.length>_.length;)h.removeChild(h.lastChild);g.replaceChildren();let I=t.resolveMotion(l.transition),L=I.duration,R=e.resolveEasing(I.easing);for(let e=0;e<_.length;e++){let t=_[e],n=h.children[e];n||(n=a.createSvgElement(`path`,{class:`prism-pie-slice`}),h.appendChild(n)),n.setAttribute(`fill`,t.color),n.setAttribute(`stroke`,`none`),n.style.cursor=l.onClick||l.onHover?`pointer`:``}y?.();let z=v.length===0,B=v;y=n.startTween({count:1,duration:L,easing:R,onComplete:()=>renderLabels(N),onFrame:e=>{let t=e(0);if(z){let e=r.tweenNumber(F,P,t);v=_.map((t,n)=>{let r=h.children[n];if(!r)return t;if(e<=t.startAngle)return a.setAttributes(r,{d:``}),{...t,endAngle:t.startAngle};let i=Math.min(t.endAngle,e);return a.setAttributes(r,{d:c.arcPath({...t,endAngle:i})}),{...t,endAngle:i}})}else v=_.map((e,n)=>{let i=h.children[n],o=B.at(-1),s=B[n]??{...e,endAngle:o?.endAngle??F,startAngle:o?.endAngle??F},l={...e,endAngle:r.tweenNumber(s.endAngle,e.endAngle,t),innerRadius:r.tweenNumber(s.innerRadius,e.innerRadius,t),outerRadius:r.tweenNumber(s.outerRadius,e.outerRadius,t),padAngle:r.tweenNumber(s.padAngle,e.padAngle,t),startAngle:r.tweenNumber(s.startAngle,e.startAngle,t)};return i&&a.setAttributes(i,{d:l.endAngle-l.startAngle<=1e-6?``:c.arcPath(l)}),l})},signal:i.disposalSignal}),S?.hide();let V=_.reduce((e,t)=>e+Math.max(0,t.slice.value),0),H=-1,describe=e=>{let t=V>0?Math.round(Math.max(0,e.slice.value)/V*1e3)/10:0;return`${e.slice.label??`Slice ${e.index+1}`}: ${e.slice.value} (${t}%)`},setActive=e=>{H=e,h.classList.toggle(`prism-pie-focused`,e>=0);for(let[t,n]of[...h.children].entries())n.classList.toggle(`prism-pie-slice--active`,t===e)},activate=(e,t)=>{let n=_[e];if(!n)return;setActive(e),l.onHover?.({index:e,originalEvent:t,slice:n.slice});let r=describe(n);if(!S){i.announcer.announce(r);return}let{x:a,y:s}=c.arcCentroid(n),u=x.getBoundingClientRect(),d=o.getBoundingClientRect();S.show(a+(u.left-d.left),s+(u.top-d.top),{key:e,value:n.slice.value},{color:n.color,data:[],name:n.slice.label??``},r)},deactivate=()=>{setActive(-1),S?.hide(),i.announcer.clear(),l.onHover?.(null)},hitAt=e=>{let t=x.getBoundingClientRect();return hitTestArc(_,e.clientX-t.left,e.clientY-t.top,u)},onMouseMove=e=>{let t=hitAt(e);t>=0?t!==H&&activate(t,e):H>=0&&deactivate()},onClick=e=>{if(!l.onClick)return;let t=hitAt(e);t>=0&&l.onClick({index:t,originalEvent:e,slice:_[t].slice})},onKeyDown=e=>{let t=_.length;if(t===0)return;let n={ArrowDown:1,ArrowLeft:-1,ArrowRight:1,ArrowUp:-1};e.key in n?(e.preventDefault(),activate(H<0?n[e.key]>0?0:t-1:(H+n[e.key]+t)%t,e)):e.key===`Home`||e.key===`End`?(e.preventDefault(),activate(e.key===`Home`?0:t-1,e)):(e.key===`Enter`||e.key===` `)&&H>=0&&l.onClick?(e.preventDefault(),l.onClick({index:H,originalEvent:e,slice:_[H].slice})):e.key===`Escape`&&deactivate()};return{onClick,onKeyDown,onMouseLeave:deactivate,onMouseMove}},e=>{p=e})}function hitTestArc(e,t,n,r){for(let i=0;i<e.length;i++){let a=e[i],o=t-a.centerX,s=n-a.centerY,c=Math.sqrt(o*o+s*s);if(c<a.outerRadius&&c>=a.innerRadius){let e=Math.atan2(o,-s);if(r===`semi`){if(e>=a.startAngle-1e-9&&e<=a.endAngle+1e-9)return i}else{let t=e<0?e+l:e;if(t>=a.startAngle-1e-9&&t<=a.endAngle+1e-9)return i}}}return-1}exports.createPieChart=createPieChart;
|
|
2
2
|
//# sourceMappingURL=pie-chart.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pie-chart.cjs","names":["estimateTextWidth","createSvgElement","arcCentroid","createRadialScaffold","seriesColor","computeArcs","resolveMotion","resolveEasing","startTween","tweenNumber","arcPath","require_element","require_text","require_chart_scaffold","require_index","require_easing","require_motion","require_tween","require_transition","require_pie_renderer","TWO_PI","LABEL_FONT_SIZE","thickness","arc","midRadius","arcLength","label","SEMI_START","SEMI_END","variant","config","padPixels","cornerRadius","data","bgCircle","pieGroup","labelGroup","currentArcs","drawnArcs","activeTween","i","slice","slices","text","container","ctx","hasSlices","legend","svg","h","w","isSemi","cx","cy","outer","defaultInner","inner","outerR","start","end","motion","dur","easing","path","isMount","fromArcs","e","progress","revealAngle","el","j","a","visibleEnd","lastDrawn","from","to","morphed","tooltip","total","sum","activeIndex","percent","index","svgRect","contR","x","y","hit","count","step","next","arcs","dx","mx","dy","my","dist","rawAngle","angle"],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { startTween } from '../../animation/transition';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { estimateTextWidth } from '../../svg/text';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n/** Default `--prism-pie-label-size` in px, used to decide whether a label fits its slice. */\nconst LABEL_FONT_SIZE = 12;\n\n/** A label fits when its slice is wide enough along the centroid arc and thick enough radially. */\nfunction labelFits(arc: Arc, label: string): boolean {\n const thickness = arc.outerRadius - arc.innerRadius;\n const midRadius = (arc.outerRadius + arc.innerRadius) / 2;\n const arcLength = (arc.endAngle - arc.startAngle - 2 * arc.padAngle) * midRadius;\n\n return thickness >= LABEL_FONT_SIZE * 1.4 && arcLength >= estimateTextWidth(label, LABEL_FONT_SIZE) + 8;\n}\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle<PieSliceConfig[]> {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n let data = config.data;\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n // The geometry actually on screen right now (mid-tween included): the update\n // morph interpolates from this, so interrupting a tween never jumps.\n let drawnArcs: Arc[] = [];\n let activeTween: (() => void) | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n labelGroup.replaceChildren();\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label || !labelFits(arc, slice.label)) continue;\n\n const { x, y } = arcCentroid(arc);\n const text = createSvgElement('text', { class: 'prism-pie-label' });\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n labelGroup.appendChild(text);\n }\n }\n\n return createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n const hasSlices = data.some((slice) => slice.value > 0);\n legend?.update(\n hasSlices ? data.map((slice, i) => ({ color: slice.color ?? seriesColor(i), name: slice.label ?? '' })) : [],\n );\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n labelGroup.replaceChildren();\n\n const motion = resolveMotion(config.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n activeTween?.();\n\n // Mount sweeps the ring in once; an update morphs every slice from its\n // drawn angles to the new ones, which reads as the data changing rather\n // than the chart redrawing.\n const isMount = drawnArcs.length === 0;\n const fromArcs = drawnArcs;\n\n activeTween = startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => renderLabels(slices),\n onFrame: (progress) => {\n const e = progress(0);\n\n if (isMount) {\n const revealAngle = tweenNumber(start, end, e);\n\n drawnArcs = currentArcs.map((a, j) => {\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) return a;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n\n return { ...a, endAngle: a.startAngle };\n }\n\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n\n return { ...a, endAngle: visibleEnd };\n });\n\n return;\n }\n\n drawnArcs = currentArcs.map((to, j) => {\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n const lastDrawn = fromArcs.at(-1);\n // A slice that was not drawn before grows out of the end of the last drawn one.\n const from: Arc = fromArcs[j] ?? {\n ...to,\n endAngle: lastDrawn?.endAngle ?? start,\n startAngle: lastDrawn?.endAngle ?? start,\n };\n const morphed: Arc = {\n ...to,\n endAngle: tweenNumber(from.endAngle, to.endAngle, e),\n innerRadius: tweenNumber(from.innerRadius, to.innerRadius, e),\n outerRadius: tweenNumber(from.outerRadius, to.outerRadius, e),\n padAngle: tweenNumber(from.padAngle, to.padAngle, e),\n startAngle: tweenNumber(from.startAngle, to.startAngle, e),\n };\n\n if (!el) return morphed;\n\n setAttributes(el, {\n d: morphed.endAngle - morphed.startAngle <= 1e-6 ? '' : arcPath(morphed),\n });\n\n return morphed;\n });\n },\n signal: ctx.disposalSignal,\n });\n\n tooltip?.hide();\n\n const total = currentArcs.reduce((sum, arc) => sum + Math.max(0, arc.slice.value), 0);\n let activeIndex = -1;\n\n const describe = (arc: Arc): string => {\n const percent = total > 0 ? Math.round((Math.max(0, arc.slice.value) / total) * 1000) / 10 : 0;\n\n return `${arc.slice.label ?? `Slice ${arc.index + 1}`}: ${arc.slice.value} (${percent}%)`;\n };\n\n const setActive = (index: number): void => {\n activeIndex = index;\n pieGroup.classList.toggle('prism-pie-focused', index >= 0);\n for (const [i, el] of [...pieGroup.children].entries())\n el.classList.toggle('prism-pie-slice--active', i === index);\n };\n\n const activate = (index: number, originalEvent: Event): void => {\n const arc = currentArcs[index];\n\n if (!arc) return;\n\n setActive(index);\n config.onHover?.({ index, originalEvent, slice: arc.slice });\n\n const text = describe(arc);\n\n if (!tooltip) {\n ctx.announcer.announce(text);\n\n return;\n }\n\n const { x, y } = arcCentroid(arc);\n const svgRect = svg.getBoundingClientRect();\n const contR = container.getBoundingClientRect();\n\n tooltip.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: index, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n text,\n );\n };\n\n const deactivate = (): void => {\n setActive(-1);\n tooltip?.hide();\n ctx.announcer.clear();\n config.onHover?.(null);\n };\n\n const hitAt = (e: MouseEvent): number => {\n const svgRect = svg.getBoundingClientRect();\n\n return hitTestArc(currentArcs, e.clientX - svgRect.left, e.clientY - svgRect.top, variant);\n };\n\n const onMouseMove = (e: MouseEvent): void => {\n const hit = hitAt(e);\n\n if (hit >= 0) {\n if (hit !== activeIndex) activate(hit, e);\n } else if (activeIndex >= 0) {\n deactivate();\n }\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const hit = hitAt(e);\n\n if (hit >= 0) config.onClick({ index: hit, originalEvent: e, slice: currentArcs[hit].slice });\n };\n\n const onKeyDown = (e: KeyboardEvent): void => {\n const count = currentArcs.length;\n\n if (count === 0) return;\n\n const step: Record<string, number> = { ArrowDown: 1, ArrowLeft: -1, ArrowRight: 1, ArrowUp: -1 };\n\n if (e.key in step) {\n e.preventDefault();\n activate(\n activeIndex < 0 ? (step[e.key] > 0 ? 0 : count - 1) : (activeIndex + step[e.key] + count) % count,\n e,\n );\n } else if (e.key === 'Home' || e.key === 'End') {\n e.preventDefault();\n activate(e.key === 'Home' ? 0 : count - 1, e);\n } else if ((e.key === 'Enter' || e.key === ' ') && activeIndex >= 0 && config.onClick) {\n e.preventDefault();\n config.onClick({ index: activeIndex, originalEvent: e, slice: currentArcs[activeIndex].slice });\n } else if (e.key === 'Escape') {\n deactivate();\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave: deactivate, onMouseMove };\n },\n (next) => {\n data = next;\n },\n );\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pie-chart.cjs","names":["estimateTextWidth","createSvgElement","arcCentroid","createRadialScaffold","seriesColor","computeArcs","resolveMotion","resolveEasing","startTween","tweenNumber","arcPath","require_easing","require_motion","require_transition","require_tween","require_chart_scaffold","require_element","require_text","require_index","require_pie_renderer","TWO_PI","LABEL_FONT_SIZE","thickness","arc","midRadius","arcLength","label","SEMI_START","SEMI_END","variant","config","padPixels","cornerRadius","data","bgCircle","pieGroup","labelGroup","currentArcs","drawnArcs","activeTween","i","slice","slices","text","container","ctx","hasSlices","legend","svg","h","w","isSemi","cx","cy","outer","defaultInner","inner","outerR","start","end","motion","dur","easing","path","isMount","fromArcs","e","progress","revealAngle","el","j","a","visibleEnd","lastDrawn","from","to","morphed","tooltip","total","sum","activeIndex","percent","index","svgRect","contR","x","y","hit","count","step","next","arcs","dx","mx","dy","my","dist","rawAngle","angle"],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { startTween } from '../../animation/transition';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { estimateTextWidth } from '../../svg/text';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n/** Default `--prism-pie-label-size` in px, used to decide whether a label fits its slice. */\nconst LABEL_FONT_SIZE = 12;\n\n/** A label fits when its slice is wide enough along the centroid arc and thick enough radially. */\nfunction labelFits(arc: Arc, label: string): boolean {\n const thickness = arc.outerRadius - arc.innerRadius;\n const midRadius = (arc.outerRadius + arc.innerRadius) / 2;\n const arcLength = (arc.endAngle - arc.startAngle - 2 * arc.padAngle) * midRadius;\n\n return thickness >= LABEL_FONT_SIZE * 1.4 && arcLength >= estimateTextWidth(label, LABEL_FONT_SIZE) + 8;\n}\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle<PieSliceConfig[]> {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n let data = config.data;\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n // The geometry actually on screen right now (mid-tween included): the update\n // morph interpolates from this, so interrupting a tween never jumps.\n let drawnArcs: Arc[] = [];\n let activeTween: (() => void) | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n labelGroup.replaceChildren();\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label || !labelFits(arc, slice.label)) continue;\n\n const { x, y } = arcCentroid(arc);\n const text = createSvgElement('text', { class: 'prism-pie-label' });\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n labelGroup.appendChild(text);\n }\n }\n\n return createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n const hasSlices = data.some((slice) => slice.value > 0);\n legend?.update(\n hasSlices ? data.map((slice, i) => ({ color: slice.color ?? seriesColor(i), name: slice.label ?? '' })) : [],\n );\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n labelGroup.replaceChildren();\n\n const motion = resolveMotion(config.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n activeTween?.();\n\n // Mount sweeps the ring in once; an update morphs every slice from its\n // drawn angles to the new ones, which reads as the data changing rather\n // than the chart redrawing.\n const isMount = drawnArcs.length === 0;\n const fromArcs = drawnArcs;\n\n activeTween = startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => renderLabels(slices),\n onFrame: (progress) => {\n const e = progress(0);\n\n if (isMount) {\n const revealAngle = tweenNumber(start, end, e);\n\n drawnArcs = currentArcs.map((a, j) => {\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) return a;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n\n return { ...a, endAngle: a.startAngle };\n }\n\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n\n return { ...a, endAngle: visibleEnd };\n });\n\n return;\n }\n\n drawnArcs = currentArcs.map((to, j) => {\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n const lastDrawn = fromArcs.at(-1);\n // A slice that was not drawn before grows out of the end of the last drawn one.\n const from: Arc = fromArcs[j] ?? {\n ...to,\n endAngle: lastDrawn?.endAngle ?? start,\n startAngle: lastDrawn?.endAngle ?? start,\n };\n const morphed: Arc = {\n ...to,\n endAngle: tweenNumber(from.endAngle, to.endAngle, e),\n innerRadius: tweenNumber(from.innerRadius, to.innerRadius, e),\n outerRadius: tweenNumber(from.outerRadius, to.outerRadius, e),\n padAngle: tweenNumber(from.padAngle, to.padAngle, e),\n startAngle: tweenNumber(from.startAngle, to.startAngle, e),\n };\n\n if (!el) return morphed;\n\n setAttributes(el, {\n d: morphed.endAngle - morphed.startAngle <= 1e-6 ? '' : arcPath(morphed),\n });\n\n return morphed;\n });\n },\n signal: ctx.disposalSignal,\n });\n\n tooltip?.hide();\n\n const total = currentArcs.reduce((sum, arc) => sum + Math.max(0, arc.slice.value), 0);\n let activeIndex = -1;\n\n const describe = (arc: Arc): string => {\n const percent = total > 0 ? Math.round((Math.max(0, arc.slice.value) / total) * 1000) / 10 : 0;\n\n return `${arc.slice.label ?? `Slice ${arc.index + 1}`}: ${arc.slice.value} (${percent}%)`;\n };\n\n const setActive = (index: number): void => {\n activeIndex = index;\n pieGroup.classList.toggle('prism-pie-focused', index >= 0);\n for (const [i, el] of [...pieGroup.children].entries())\n el.classList.toggle('prism-pie-slice--active', i === index);\n };\n\n const activate = (index: number, originalEvent: Event): void => {\n const arc = currentArcs[index];\n\n if (!arc) return;\n\n setActive(index);\n config.onHover?.({ index, originalEvent, slice: arc.slice });\n\n const text = describe(arc);\n\n if (!tooltip) {\n ctx.announcer.announce(text);\n\n return;\n }\n\n const { x, y } = arcCentroid(arc);\n const svgRect = svg.getBoundingClientRect();\n const contR = container.getBoundingClientRect();\n\n tooltip.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: index, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n text,\n );\n };\n\n const deactivate = (): void => {\n setActive(-1);\n tooltip?.hide();\n ctx.announcer.clear();\n config.onHover?.(null);\n };\n\n const hitAt = (e: MouseEvent): number => {\n const svgRect = svg.getBoundingClientRect();\n\n return hitTestArc(currentArcs, e.clientX - svgRect.left, e.clientY - svgRect.top, variant);\n };\n\n const onMouseMove = (e: MouseEvent): void => {\n const hit = hitAt(e);\n\n if (hit >= 0) {\n if (hit !== activeIndex) activate(hit, e);\n } else if (activeIndex >= 0) {\n deactivate();\n }\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const hit = hitAt(e);\n\n if (hit >= 0) config.onClick({ index: hit, originalEvent: e, slice: currentArcs[hit].slice });\n };\n\n const onKeyDown = (e: KeyboardEvent): void => {\n const count = currentArcs.length;\n\n if (count === 0) return;\n\n const step: Record<string, number> = { ArrowDown: 1, ArrowLeft: -1, ArrowRight: 1, ArrowUp: -1 };\n\n if (e.key in step) {\n e.preventDefault();\n activate(\n activeIndex < 0 ? (step[e.key] > 0 ? 0 : count - 1) : (activeIndex + step[e.key] + count) % count,\n e,\n );\n } else if (e.key === 'Home' || e.key === 'End') {\n e.preventDefault();\n activate(e.key === 'Home' ? 0 : count - 1, e);\n } else if ((e.key === 'Enter' || e.key === ' ') && activeIndex >= 0 && config.onClick) {\n e.preventDefault();\n config.onClick({ index: activeIndex, originalEvent: e, slice: currentArcs[activeIndex].slice });\n } else if (e.key === 'Escape') {\n deactivate();\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave: deactivate, onMouseMove };\n },\n (next) => {\n data = next;\n },\n );\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
|