@wick-charts/vue 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +45 -6
  2. package/dist/BarSeries.vue.js +26 -20
  3. package/dist/CandlestickSeries.vue.js +30 -24
  4. package/dist/ChartContainer.vue.js +125 -72
  5. package/dist/HeatmapSeries.vue.js +40 -0
  6. package/dist/HeatmapSeries.vue2.js +4 -0
  7. package/dist/LineSeries.vue.js +26 -20
  8. package/dist/PieSeries.vue.js +24 -18
  9. package/dist/core/dist/animation/animator.js +21 -21
  10. package/dist/core/dist/animation/config.js +114 -87
  11. package/dist/core/dist/animation/easing.js +3 -1
  12. package/dist/core/dist/animation/intro-wave.js +68 -0
  13. package/dist/core/dist/axis/dom-labels.js +13 -14
  14. package/dist/core/dist/chart/badge-animator.js +56 -0
  15. package/dist/core/dist/chart/edge-indicators.js +28 -13
  16. package/dist/core/dist/chart/last-value.js +18 -17
  17. package/dist/core/dist/chart/options.js +27 -16
  18. package/dist/core/dist/chart/y-target.js +13 -12
  19. package/dist/core/dist/chart.js +868 -441
  20. package/dist/core/dist/components/annotation-chip.js +28 -0
  21. package/dist/core/dist/components/crosshair.js +8 -6
  22. package/dist/core/dist/components/edge-indicator.js +58 -26
  23. package/dist/core/dist/components/loading-indicator.js +46 -0
  24. package/dist/core/dist/components/marker.js +49 -31
  25. package/dist/core/dist/components/reference-line.js +27 -36
  26. package/dist/core/dist/components/time-region.js +30 -28
  27. package/dist/core/dist/data/store.js +38 -19
  28. package/dist/core/dist/data/sync.js +60 -38
  29. package/dist/core/dist/heatmap-tooltip.js +16 -0
  30. package/dist/core/dist/interactions/handler.js +86 -46
  31. package/dist/core/dist/perf/perf-hud.js +5 -5
  32. package/dist/core/dist/scales/x-scale.js +85 -37
  33. package/dist/core/dist/scales/y-scale.js +38 -27
  34. package/dist/core/dist/series/bar-intro.js +18 -0
  35. package/dist/core/dist/series/bar.js +337 -205
  36. package/dist/core/dist/series/base-multi-layer.js +224 -96
  37. package/dist/core/dist/series/candlestick-intro.js +57 -0
  38. package/dist/core/dist/series/candlestick.js +454 -276
  39. package/dist/core/dist/series/heatmap.js +387 -0
  40. package/dist/core/dist/series/line-intro.js +85 -0
  41. package/dist/core/dist/series/line.js +590 -282
  42. package/dist/core/dist/series/painters/builtins.js +2 -2
  43. package/dist/core/dist/series/pie.js +396 -259
  44. package/dist/core/dist/series/register-builtins.js +8 -7
  45. package/dist/core/dist/series/types.js +6 -0
  46. package/dist/core/dist/series/wave-intro.js +26 -0
  47. package/dist/core/dist/theme/create.js +69 -63
  48. package/dist/core/dist/theme/themes/mint-breeze.js +2 -2
  49. package/dist/core/dist/theme/themes/sand-dune.js +2 -2
  50. package/dist/core/dist/utils/color.js +109 -34
  51. package/dist/core/dist/utils/deep-equal.js +18 -0
  52. package/dist/core/dist/utils/time.js +25 -19
  53. package/dist/index.d.ts +1494 -122
  54. package/dist/index.js +177 -130
  55. package/dist/ui/Crosshair.vue.js +20 -21
  56. package/dist/ui/HeatmapTooltip.vue.js +96 -0
  57. package/dist/ui/HeatmapTooltip.vue2.js +4 -0
  58. package/dist/ui/InfoBar.vue.js +46 -47
  59. package/dist/ui/Legend.vue.js +80 -79
  60. package/dist/ui/PieLegend.vue.js +5 -5
  61. package/dist/ui/PieTooltip.vue.js +77 -67
  62. package/dist/ui/Tooltip.vue.js +60 -60
  63. package/dist/ui/YAxis.vue.js +2 -2
  64. package/dist/ui/YLabel.vue.js +94 -61
  65. package/package.json +2 -2
  66. package/src/BarSeries.vue +23 -7
  67. package/src/CandlestickSeries.vue +23 -7
  68. package/src/ChartContainer.vue +250 -13
  69. package/src/HeatmapSeries.vue +69 -0
  70. package/src/LineSeries.vue +23 -7
  71. package/src/PieSeries.vue +22 -6
  72. package/src/index.ts +84 -3
  73. package/src/ui/Crosshair.vue +1 -2
  74. package/src/ui/HeatmapTooltip.vue +144 -0
  75. package/src/ui/InfoBar.vue +1 -2
  76. package/src/ui/Legend.vue +13 -0
  77. package/src/ui/Marker.vue +1 -1
  78. package/src/ui/PieTooltip.vue +10 -0
  79. package/src/ui/ReferenceLine.vue +2 -2
  80. package/src/ui/TimeRegion.vue +2 -2
  81. package/src/ui/Tooltip.vue +2 -2
  82. package/src/ui/YLabel.vue +123 -8
@@ -1,6 +1,8 @@
1
- import { lighten as st } from "../utils/color.js";
2
- import { smoothToward as K, clamp as E } from "../utils/math.js";
3
- const tt = {
1
+ import { DEFAULT_PIE_ENTRY as ct } from "../animation/config.js";
2
+ import { IntroWave as ut } from "../animation/intro-wave.js";
3
+ import { isLightColor as ft, lighten as dt } from "../utils/color.js";
4
+ import { smoothToward as nt, clamp as U } from "../utils/math.js";
5
+ const lt = {
4
6
  mode: "outside",
5
7
  content: "both",
6
8
  fontSize: 11,
@@ -18,11 +20,15 @@ const tt = {
18
20
  // 1.8 gives each label room to breathe without spreading so aggressively
19
21
  // that PAV collapses into a centered block on dense datasets.
20
22
  labelGap: 1.8
21
- }, ot = {
23
+ }, mt = {
22
24
  innerRadiusRatio: 0,
23
25
  // 1.15° ≈ 0.02 rad — same visual default as before the radians→degrees switch.
24
26
  padAngle: 1.15,
25
- sliceLabels: { ...tt },
27
+ // Softly rounded slice corners by default, matching the bar/candlestick
28
+ // families. Pass 0 for sharp wedges. Thin rings and narrow slices clamp it
29
+ // down automatically.
30
+ cornerRadius: 3,
31
+ sliceLabels: { ...lt },
26
32
  // Motion off by default: label draw-in + hover explode both skipped.
27
33
  animate: !1,
28
34
  // Small-slice grouping on by default: dense datasets collapse into the top
@@ -31,54 +37,72 @@ const tt = {
31
37
  // Radial depth gradient (lighter center → flat edge) on by default. Set
32
38
  // false for flat, solid-color slices.
33
39
  gradient: !0
34
- }, Q = {
40
+ }, ot = {
35
41
  maxSlices: 8,
36
42
  label: "Other"
37
43
  };
38
- function nt(l) {
39
- return l === !1 ? null : l === !0 || l === void 0 ? Q : { ...Q, ...l };
44
+ function gt(a) {
45
+ return a === !1 ? null : a === !0 || a === void 0 ? ot : { ...ot, ...a };
40
46
  }
41
- const U = Math.PI / 180;
42
- function lt(l, e) {
43
- return { ...l ?? {}, ...e };
47
+ const et = Math.PI / 180;
48
+ function pt(a, e) {
49
+ return { ...a ?? {}, ...e };
44
50
  }
45
- function it(l) {
46
- return { ...tt, ...l ?? {} };
51
+ function it(a) {
52
+ return { ...lt, ...a ?? {} };
47
53
  }
48
- function at(l) {
54
+ function bt(a) {
49
55
  const e = { color: "rgba(0, 0, 0, 0.22)", blur: 24, offsetX: 0, offsetY: 10 };
50
- return l === !0 || l === !1 ? e : { ...e, ...l };
56
+ return a === !0 || a === !1 ? e : { ...e, ...a };
51
57
  }
52
- function rt(l) {
58
+ function xt(a) {
53
59
  const e = { color: "rgba(0, 0, 0, 0.1)", depth: 0.3 };
54
- return l === !0 || l === !1 ? e : { ...e, ...l };
60
+ return a === !0 || a === !1 ? e : { ...e, ...a };
61
+ }
62
+ const H = Math.PI * 2, rt = 0.85, Mt = 0.5, yt = 20;
63
+ function st(a) {
64
+ const { bitmapWidth: e, bitmapHeight: t, padTop: n, padBottom: o } = a, s = Math.max(0, a.labelReserve ?? 0), h = Math.min(Math.max(0, n), t), r = Math.min(Math.max(0, o), t - h), u = t - h - r, m = Math.max(0, e - 2 * s), R = e / 2, g = Math.min(m, u) / 2, y = Math.min(e, t) / 2, p = Math.max(0, Math.max(g, y * Mt) * rt), T = Math.min(2, Math.max(0, t / 2 - p)), b = h + u / 2, C = Math.min(Math.max(b, p + T), t - p - T);
65
+ return { cx: R, cy: C, maxR: p };
66
+ }
67
+ function Z(a) {
68
+ const { ringR: e, theta: t, radius: n, outward: o, angleSign: s } = a, h = o ? e - n : e + n, r = Math.asin(U(n / h, 0, 1)) * s, u = t + r;
69
+ return {
70
+ fx: h * Math.cos(u),
71
+ fy: h * Math.sin(u),
72
+ lineR: h * Math.cos(r),
73
+ archAngle: u
74
+ };
55
75
  }
56
- const N = Math.PI * 2, et = 0.85;
57
- function Z(l) {
58
- const { bitmapWidth: e, bitmapHeight: t, padTop: o, padBottom: i } = l, s = Math.max(0, l.labelReserve ?? 0), d = Math.min(Math.max(0, o), t), r = Math.min(Math.max(0, i), t - d), c = t - d - r, g = Math.max(0, e - 2 * s), C = e / 2, x = d + c / 2, R = Math.max(0, Math.min(g, c) / 2 * et);
59
- return { cx: C, cy: x, maxR: R };
76
+ function vt(a) {
77
+ const { outerR: e, innerR: t, halfSpan: n } = a, o = Math.sin(Math.min(n, Math.PI / 2 - 1e-3)), s = e * o / (1 + o), h = t > 0 ? t * o / (1 - o) : 1 / 0, r = (e - t) / 2;
78
+ return Math.max(0, Math.min(s, h, r));
60
79
  }
61
- function ht(l) {
62
- if (!l.startsWith("#")) return !1;
63
- const e = parseInt(l.slice(1, 3), 16), t = parseInt(l.slice(3, 5), 16), o = parseInt(l.slice(5, 7), 16);
64
- return e * 0.299 + t * 0.587 + o * 0.114 > 150;
80
+ function St(a, e, t) {
81
+ if (t <= 0) return "";
82
+ if (a.measureText(e).width <= t) return e;
83
+ let n = e.length - 1;
84
+ for (; n > 0 && a.measureText(`${e.slice(0, n)}…`).width > t; )
85
+ n--;
86
+ return n <= 0 ? "" : `${e.slice(0, n)}…`;
65
87
  }
66
- function ct(l, e) {
67
- if (!l.startsWith("#")) return l;
68
- const t = l.length === 4 ? `#${l[1]}${l[1]}${l[2]}${l[2]}${l[3]}${l[3]}` : l;
69
- return st(t, e);
88
+ function Rt(a, e) {
89
+ if (!a.startsWith("#")) return a;
90
+ const t = a.length === 4 ? `#${a[1]}${a[1]}${a[2]}${a[2]}${a[3]}${a[3]}` : a;
91
+ return dt(t, e);
70
92
  }
71
- function J(l) {
72
- if (l.startsWith("#"))
93
+ function at(a) {
94
+ if (a.startsWith("#")) {
95
+ const t = a.length === 4 ? `#${a[1]}${a[1]}${a[2]}${a[2]}${a[3]}${a[3]}` : a;
73
96
  return {
74
- r: parseInt(l.slice(1, 3), 16) || 0,
75
- g: parseInt(l.slice(3, 5), 16) || 0,
76
- b: parseInt(l.slice(5, 7), 16) || 0,
97
+ r: parseInt(t.slice(1, 3), 16) || 0,
98
+ g: parseInt(t.slice(3, 5), 16) || 0,
99
+ b: parseInt(t.slice(5, 7), 16) || 0,
77
100
  a: 1
78
101
  };
79
- const e = l.match(/^rgba?\s*\(([^)]+)\)$/i);
102
+ }
103
+ const e = a.match(/^rgba?\s*\(([^)]+)\)$/i);
80
104
  if (e) {
81
- const t = e[1].split(",").map((o) => o.trim());
105
+ const t = e[1].split(",").map((n) => n.trim());
82
106
  return {
83
107
  r: Number.parseFloat(t[0]) || 0,
84
108
  g: Number.parseFloat(t[1]) || 0,
@@ -88,11 +112,11 @@ function J(l) {
88
112
  }
89
113
  return { r: 0, g: 0, b: 0, a: 1 };
90
114
  }
91
- function ut(l, e) {
92
- const t = J(l), o = J(e), i = o.a, s = Math.round(o.r * i + t.r * (1 - i)), d = Math.round(o.g * i + t.g * (1 - i)), r = Math.round(o.b * i + t.b * (1 - i));
93
- return `#${s.toString(16).padStart(2, "0")}${d.toString(16).padStart(2, "0")}${r.toString(16).padStart(2, "0")}`;
115
+ function wt(a, e) {
116
+ const t = at(a), n = at(e), o = n.a, s = Math.round(n.r * o + t.r * (1 - o)), h = Math.round(n.g * o + t.g * (1 - o)), r = Math.round(n.b * o + t.b * (1 - o));
117
+ return `#${s.toString(16).padStart(2, "0")}${h.toString(16).padStart(2, "0")}${r.toString(16).padStart(2, "0")}`;
94
118
  }
95
- class ft {
119
+ class It {
96
120
  kind = "pie";
97
121
  #n = [];
98
122
  /**
@@ -108,39 +132,54 @@ class ft {
108
132
  * grouping didn't apply. Lets the color resolution pick the theme's muted
109
133
  * `pie.otherColor` for the aggregate instead of the next palette color.
110
134
  */
111
- #c = -1;
135
+ #u = -1;
112
136
  #e;
113
137
  /** Index of the hovered slice (-1 = none). Set via {@link setHoverIndex}. */
114
- #i = -1;
138
+ #a = -1;
115
139
  /** Animated offset per slice (0..1), smoothly interpolated toward target. */
116
140
  #s = [];
117
- #u = 0;
141
+ #f = 0;
118
142
  /**
119
143
  * Outside-label reveal progress (0..1). Eased toward 1 on mount / data-swap
120
144
  * when `animate` is on; drives the leader-line draw-in and label fade-in
121
145
  * stagger. When `animate` is off (the default) this stays pinned at 1 so
122
146
  * labels paint fully-revealed on the first frame.
123
147
  */
124
- #a = 1;
148
+ #o = 1;
149
+ /**
150
+ * Initial-load reveal clock — armed on the first empty → non-empty seed;
151
+ * slices unfurl clockwise from 12 o'clock, then {@link #labelReveal}
152
+ * chains in. Armed with `entryMs / 2` because the wave's full window is
153
+ * `2 ×` its per-element duration and the pie treats `entryMs` as the
154
+ * total sweep time.
155
+ */
156
+ #r = new ut();
125
157
  /**
126
158
  * Cached horizontal bitmap-pixel reserve for outside labels. Invalidated on
127
159
  * `setData` / `updateOptions`; computed lazily on first `render` call per
128
160
  * frame using the live canvas context for accurate `measureText`.
129
161
  */
130
162
  #l = null;
163
+ /**
164
+ * Horizontal reserve the last `render` actually applied — 0 when outside
165
+ * labels were auto-hidden below `MIN_LABELED_PIE_RADIUS`. `hitTest` reads
166
+ * this instead of the measurement cache so hover geometry always matches
167
+ * the painted frame.
168
+ */
169
+ #g = 0;
131
170
  /** Subscribers notified on setData (pie has no TimeSeriesStore to piggy-back on). */
132
- #r = [];
171
+ #h = [];
133
172
  constructor(e) {
134
- this.#e = this.#m(ot, e ?? {});
173
+ this.#e = this.#p(mt, e ?? {});
135
174
  }
136
175
  /**
137
176
  * Merge partial options onto a base, deep-merging `sliceLabels` and `other`
138
177
  * so callers can override one field (e.g. `mode` or `maxSlices`) without
139
178
  * dropping sibling defaults.
140
179
  */
141
- #m(e, t) {
142
- const o = { ...e, ...t };
143
- return t.sliceLabels !== void 0 && (o.sliceLabels = lt(e.sliceLabels, t.sliceLabels)), typeof t.other == "object" && typeof e.other == "object" && (o.other = { ...e.other, ...t.other }), o;
180
+ #p(e, t) {
181
+ const n = { ...e, ...t };
182
+ return t.sliceLabels !== void 0 && (n.sliceLabels = pt(e.sliceLabels, t.sliceLabels)), typeof t.other == "object" && typeof e.other == "object" && (n.other = { ...e.other, ...t.other }), n;
144
183
  }
145
184
  /**
146
185
  * Build the display array from the raw data. When grouping applies, the
@@ -149,18 +188,18 @@ class ft {
149
188
  * layout-sanitized value so negative / non-finite entries can never outrank
150
189
  * a real slice.
151
190
  */
152
- #p() {
153
- this.#c = -1;
154
- const e = nt(this.#e.other);
191
+ #b() {
192
+ this.#u = -1;
193
+ const e = gt(this.#e.other);
155
194
  if (!e || this.#n.length <= e.maxSlices) return this.#n;
156
- const t = Math.max(1, e.maxSlices - 1), o = this.#n.map((r, c) => ({ index: c, value: this.#o(r.value) })).sort((r, c) => c.value - r.value), i = /* @__PURE__ */ new Set();
157
- for (const r of o.slice(0, t))
158
- i.add(r.index);
195
+ const t = Math.max(1, e.maxSlices - 1), n = this.#n.map((r, u) => ({ index: u, value: this.#i(r.value) })).sort((r, u) => u.value - r.value), o = /* @__PURE__ */ new Set();
196
+ for (const r of n.slice(0, t))
197
+ o.add(r.index);
159
198
  const s = [];
160
- let d = 0;
199
+ let h = 0;
161
200
  for (let r = 0; r < this.#n.length; r++)
162
- i.has(r) ? s.push(this.#n[r]) : d += this.#o(this.#n[r].value);
163
- return s.push({ label: e.label, value: d, color: e.color }), this.#c = s.length - 1, s;
201
+ o.has(r) ? s.push(this.#n[r]) : h += this.#i(this.#n[r].value);
202
+ return s.push({ label: e.label, value: h, color: e.color }), this.#u = s.length - 1, s;
164
203
  }
165
204
  /**
166
205
  * Paint color for one display slice: explicit slice color → theme-driven
@@ -169,28 +208,28 @@ class ft {
169
208
  * `pie.otherColor`, so hand-built theme literals without the `pie` block
170
209
  * get the same muted tone.
171
210
  */
172
- #h(e) {
173
- const { index: t, palette: o, theme: i } = e, s = this.#t[t];
174
- return s?.color ? s.color : t === this.#c ? i.pie?.otherColor ?? i.axis.textColor : o[t % o.length];
211
+ #c(e) {
212
+ const { index: t, palette: n, theme: o } = e, s = this.#t[t];
213
+ return s?.color ? s.color : t === this.#u ? o.pie?.otherColor ?? o.axis.textColor : n[t % n.length];
175
214
  }
176
215
  getData() {
177
216
  return this.#n;
178
217
  }
179
218
  setData(e) {
180
- const t = e ?? [];
181
- this.#n = t, this.#t = this.#p(), this.#s = new Array(this.#t.length).fill(0), this.#a = this.#e.animate ? 0 : 1, this.#l = null;
182
- for (const o of this.#r)
219
+ const t = this.#n.length > 0, n = e ?? [];
220
+ this.#n = n, this.#t = this.#b(), this.#s = new Array(this.#t.length).fill(0), !t && this.#t.length > 0 && this.#r.arm(this.#M() / 2), this.#o = this.#e.animate || this.#r.active ? 0 : 1, this.#l = null;
221
+ for (const o of this.#h)
183
222
  o();
184
223
  }
185
224
  onDataChanged(e) {
186
- return this.#r.push(e), () => {
187
- const t = this.#r.indexOf(e);
188
- t >= 0 && this.#r.splice(t, 1);
225
+ return this.#h.push(e), () => {
226
+ const t = this.#h.indexOf(e);
227
+ t >= 0 && this.#h.splice(t, 1);
189
228
  };
190
229
  }
191
230
  updateOptions(e) {
192
231
  const t = this.#e.sliceLabels?.mode;
193
- this.#e = this.#m(this.#e, e ?? {}), this.#e.sliceLabels?.mode === "outside" && t !== "outside" && (this.#a = this.#e.animate ? 0 : 1), this.#t = this.#p(), this.#s.length !== this.#t.length && (this.#s = new Array(this.#t.length).fill(0)), this.#l = null;
232
+ this.#e = this.#p(this.#e, e ?? {}), this.#e.sliceLabels?.mode === "outside" && t !== "outside" && (this.#o = this.#e.animate ? 0 : 1), this.#t = this.#b(), this.#s.length !== this.#t.length && (this.#s = new Array(this.#t.length).fill(0)), this.#l = null;
194
233
  }
195
234
  getColor() {
196
235
  return this.#t[0]?.color ?? this.#e.colors?.[0] ?? "#888";
@@ -210,67 +249,85 @@ class ft {
210
249
  e.typography.fontFamily !== t.typography.fontFamily && (this.#l = null);
211
250
  }
212
251
  /** Hit-test: which slice is at this bitmap coordinate? Returns index or -1. */
213
- hitTest(e, t, o, i, s) {
252
+ hitTest(e, t, n, o, s) {
214
253
  if (this.#t.length === 0) return -1;
215
- const d = this.#f();
216
- if (d <= 0) return -1;
217
- const r = this.#l?.reserve ?? 0, { cx: c, cy: g, maxR: C } = Z({
218
- bitmapWidth: o,
219
- bitmapHeight: i,
254
+ const h = this.#d();
255
+ if (h <= 0) return -1;
256
+ const r = this.#g, { cx: u, cy: m, maxR: R } = st({
257
+ bitmapWidth: n,
258
+ bitmapHeight: o,
220
259
  padTop: s?.top ?? 0,
221
260
  padBottom: s?.bottom ?? 0,
222
261
  labelReserve: r
223
- }), x = C, R = x * this.#e.innerRadiusRatio, M = e - c, X = t - g, $ = Math.sqrt(M * M + X * X);
224
- if ($ > x || $ < R) return -1;
225
- let L = Math.atan2(X, M) + Math.PI / 2;
226
- L < 0 && (L += N);
227
- let A = 0;
228
- for (let b = 0; b < this.#t.length; b++) {
229
- const I = this.#o(this.#t[b].value) / d * N;
230
- if (L >= A && L < A + I) return b;
231
- A += I;
262
+ }), g = R, y = g * this.#e.innerRadiusRatio, p = e - u, T = t - m, b = Math.sqrt(p * p + T * T);
263
+ if (b > g || b < y) return -1;
264
+ let C = Math.atan2(T, p) + Math.PI / 2;
265
+ C < 0 && (C += H);
266
+ let P = 0;
267
+ for (let f = 0; f < this.#t.length; f++) {
268
+ const v = this.#i(this.#t[f].value) / h * H;
269
+ if (C >= P && C < P + v) return f;
270
+ P += v;
232
271
  }
233
272
  return -1;
234
273
  }
235
274
  setHoverIndex(e) {
236
- return this.#i === e ? !1 : (this.#i = e, !0);
275
+ return this.#a === e ? !1 : (this.#a = e, !0);
237
276
  }
238
277
  getHoverIndex() {
239
- return this.#i;
278
+ return this.#a;
240
279
  }
241
280
  getHoverInfo(e) {
242
- if (this.#i < 0) return null;
243
- const t = this.#t[this.#i];
281
+ if (this.#a < 0) return null;
282
+ const t = this.#t[this.#a];
244
283
  if (!t) return null;
245
- const o = this.#f(), i = this.#e.colors ?? e.seriesColors;
284
+ const n = this.#d(), o = this.#e.colors ?? e.seriesColors;
246
285
  return {
247
286
  label: t.label,
248
287
  value: t.value,
249
- percent: o > 0 ? this.#o(t.value) / o * 100 : 0,
250
- color: this.#h({ index: this.#i, palette: i, theme: e })
288
+ percent: n > 0 ? this.#i(t.value) / n * 100 : 0,
289
+ color: this.#c({ index: this.#a, palette: o, theme: e })
251
290
  };
252
291
  }
253
292
  getSliceInfo(e) {
254
293
  if (this.#t.length === 0) return null;
255
- const t = this.#f(), o = this.#e.colors ?? e.seriesColors;
256
- return this.#t.map((i, s) => ({
257
- label: i.label,
258
- value: i.value,
259
- percent: t > 0 ? this.#o(i.value) / t * 100 : 0,
260
- color: this.#h({ index: s, palette: o, theme: e })
294
+ const t = this.#d(), n = this.#e.colors ?? e.seriesColors;
295
+ return this.#t.map((o, s) => ({
296
+ label: o.label,
297
+ value: o.value,
298
+ percent: t > 0 ? this.#i(o.value) / t * 100 : 0,
299
+ color: this.#c({ index: s, palette: n, theme: e })
261
300
  }));
262
301
  }
302
+ /** Resolved slice-sweep duration — `entryMs` with the `false` sentinel
303
+ * normalized to `0` (pie stores raw public options, unlike the
304
+ * time-series renderers which normalize at the merge boundary). */
305
+ #M() {
306
+ const e = this.#e.entryMs;
307
+ return e === !1 ? 0 : e ?? ct;
308
+ }
309
+ /**
310
+ * Settle every reveal clock when a render pass has nothing to paint
311
+ * (empty display or non-positive total). The clocks only advance inside
312
+ * the paint path, so leaving them armed here would hold
313
+ * {@link needsAnimation} true forever and busy-loop the frame scheduler
314
+ * over a blank chart.
315
+ */
316
+ #x() {
317
+ this.#r.finish(), this.#o = 1;
318
+ }
263
319
  /** Returns true if animation is still in progress. */
264
320
  get needsAnimation() {
321
+ if (this.#r.active || it(this.#e.sliceLabels).mode === "outside" && this.#o < 1) return !0;
265
322
  if (!this.#e.animate) return !1;
266
323
  for (let e = 0; e < this.#s.length; e++) {
267
- const t = e === this.#i ? 1 : 0;
324
+ const t = e === this.#a ? 1 : 0;
268
325
  if (Math.abs(this.#s[e] - t) > 0.01) return !0;
269
326
  }
270
- return this.#e.sliceLabels?.mode === "outside" && this.#a < 0.99;
327
+ return !1;
271
328
  }
272
329
  dispose() {
273
- this.#r = [], this.#n = [], this.#t = [], this.#c = -1, this.#s = [], this.#u = 0;
330
+ this.#h = [], this.#n = [], this.#t = [], this.#u = -1, this.#s = [], this.#f = 0;
274
331
  }
275
332
  /**
276
333
  * @internal Test-only accessor for the animated slice offsets. The backing
@@ -289,21 +346,21 @@ class ft {
289
346
  * contribute nothing to the geometry. The original value is still surfaced
290
347
  * verbatim in reported SliceInfo / HoverInfo.
291
348
  */
292
- #o(e) {
349
+ #i(e) {
293
350
  return Number.isFinite(e) && e > 0 ? e : 0;
294
351
  }
295
352
  /** Sum of layout-sanitized slice values — the denominator for every arc
296
353
  * sweep and percentage. Always finite and ≥ 0. */
297
- #f() {
354
+ #d() {
298
355
  let e = 0;
299
356
  for (const t of this.#t)
300
- e += this.#o(t.value);
357
+ e += this.#i(t.value);
301
358
  return e;
302
359
  }
303
360
  /** Build the text shown for one slice given the resolved content mode. */
304
- #d(e, t, o) {
305
- const i = t > 0 ? this.#o(e.value) / t * 100 : 0, s = `${i.toFixed(i >= 10 ? 0 : 1)}%`;
306
- return o === "percent" ? s : o === "label" ? e.label : `${e.label} ${s}`;
361
+ #m(e, t, n) {
362
+ const o = t > 0 ? this.#i(e.value) / t * 100 : 0, s = `${o.toFixed(o >= 10 ? 0 : 1)}%`;
363
+ return n === "percent" ? s : n === "label" ? e.label : `${e.label} ${s}`;
307
364
  }
308
365
  /**
309
366
  * Bitmap-pixel horizontal reserve needed for outside labels. Measured using
@@ -314,17 +371,72 @@ class ft {
314
371
  * the active `context.font` string so a theme swap that changes the font
315
372
  * family / size busts the cache and triggers a fresh measurement.
316
373
  */
317
- #b(e, t, o, i) {
374
+ #y(e, t, n, o) {
318
375
  const s = e.font;
319
- if (this.#l && this.#l.fontScale === i && this.#l.font === s)
376
+ if (this.#l && this.#l.fontScale === o && this.#l.font === s)
320
377
  return this.#l.reserve;
321
- let d = 0;
322
- for (const g of this.#t) {
323
- const C = this.#d(g, o, t.content), x = e.measureText(C).width;
324
- x > d && (d = x);
378
+ let h = 0;
379
+ for (const m of this.#t) {
380
+ const R = this.#m(m, n, t.content), g = e.measureText(R).width;
381
+ g > h && (h = g);
325
382
  }
326
- const r = Math.max(t.distance, t.elbowLen), c = (d + (r + Math.max(0, t.railWidth) + t.legPad + 4) * i) / et;
327
- return this.#l = { fontScale: i, font: s, reserve: c }, c;
383
+ const r = Math.max(t.distance, t.elbowLen), u = (h + (r + Math.max(0, t.railWidth) + t.legPad + 4) * o) / rt;
384
+ return this.#l = { fontScale: o, font: s, reserve: u }, u;
385
+ }
386
+ /**
387
+ * Trace one slice's outline with its four corners rounded (two on the
388
+ * outer rim, plus two on the inner rim when `innerR > 0`) instead of the
389
+ * plain `arc` + `lineTo` sharp-corner path. `cornerRadius` must already be
390
+ * clamped by the caller ({@link maxCornerRadius}) — this only draws.
391
+ *
392
+ * Each fillet is a small circle tangent to the ring and to the slice's
393
+ * straight edge; the main arcs are inset to the fillets' tangent angles
394
+ * instead of the slice's raw start/end angles. A closure keeps the sweep
395
+ * direction for each fillet's tiny arc correct regardless of which corner
396
+ * it's rounding, by always turning the shorter way between its two tangent
397
+ * points rather than reasoning about clockwise/anticlockwise per corner.
398
+ */
399
+ #v(e, t) {
400
+ const { sliceCx: n, sliceCy: o, outerR: s, innerR: h, startAngle: r, endAngle: u, cornerRadius: m } = t, R = (f, v) => [
401
+ n + f * Math.cos(v),
402
+ o + f * Math.sin(v)
403
+ ], g = (f, v, A, S) => {
404
+ const c = n + f, l = o + v, M = Math.atan2(A[1] - l, A[0] - c);
405
+ let i = Math.atan2(S[1] - l, S[0] - c) - M;
406
+ for (; i > Math.PI; ) i -= H;
407
+ for (; i <= -Math.PI; ) i += H;
408
+ e.arc(c, l, m, M, M + i, i < 0);
409
+ }, y = Z({
410
+ ringR: s,
411
+ theta: r,
412
+ radius: m,
413
+ outward: !0,
414
+ angleSign: 1
415
+ }), p = Z({
416
+ ringR: s,
417
+ theta: u,
418
+ radius: m,
419
+ outward: !0,
420
+ angleSign: -1
421
+ }), T = R(y.lineR, r), b = R(s, y.archAngle), C = R(s, p.archAngle), P = R(p.lineR, u);
422
+ if (h > 0) {
423
+ const f = Z({
424
+ ringR: h,
425
+ theta: r,
426
+ radius: m,
427
+ outward: !1,
428
+ angleSign: 1
429
+ }), v = Z({
430
+ ringR: h,
431
+ theta: u,
432
+ radius: m,
433
+ outward: !1,
434
+ angleSign: -1
435
+ }), A = R(f.lineR, r), S = R(v.lineR, u), c = R(h, v.archAngle), l = R(h, f.archAngle);
436
+ e.moveTo(...A), e.lineTo(...T), g(y.fx, y.fy, T, b), e.arc(n, o, s, y.archAngle, p.archAngle), g(p.fx, p.fy, C, P), e.lineTo(...S), g(v.fx, v.fy, S, c), e.arc(n, o, h, v.archAngle, f.archAngle, !0), g(f.fx, f.fy, l, A);
437
+ return;
438
+ }
439
+ e.moveTo(n, o), e.lineTo(...T), g(y.fx, y.fy, T, b), e.arc(n, o, s, y.archAngle, p.archAngle), g(p.fx, p.fy, C, P), e.lineTo(n, o);
328
440
  }
329
441
  /**
330
442
  * Draw one outside label: anchor dot → radial elbow (per-slice, at slice
@@ -333,20 +445,24 @@ class ft {
333
445
  * lines from cutting across the pie when several small slices cluster near
334
446
  * 12 o'clock or 6 o'clock.
335
447
  */
336
- #g(e) {
337
- const { context: t, entry: o, textColor: i, labels: s, hpr: d, progress: r } = e;
448
+ #S(e) {
449
+ const { context: t, entry: n, textColor: o, labels: s, hpr: h, progress: r, bitmapWidth: u } = e;
338
450
  if (r <= 0) return;
339
- const { anchorX: c, anchorY: g, elbowX: C, elbowY: x, side: R, text: M, color: X, labelX: $, labelY: L } = o, A = $ + R * s.legPad * d, b = E(r / 0.15, 0, 1), I = E((r - 0.15) / 0.45, 0, 1), S = E((r - 0.6) / 0.4, 0, 1);
340
- if (t.save(), t.globalAlpha = b, t.fillStyle = X, t.beginPath(), t.arc(c, g, 2.5 * d, 0, N), t.fill(), t.restore(), I > 0) {
341
- t.save(), t.globalAlpha = I, t.strokeStyle = X, t.lineWidth = 1 * d, t.lineCap = "round", t.beginPath(), t.moveTo(c, g);
342
- const v = c + (C - c) * I, u = g + (x - g) * I;
343
- if (t.lineTo(v, u), S > 0) {
344
- const a = C + ($ - C) * S, w = x + (L - x) * S;
345
- t.lineTo(a, w);
451
+ const { anchorX: m, anchorY: R, elbowX: g, elbowY: y, side: p, text: T, color: b, labelX: C, labelY: P } = n, f = C + p * s.legPad * h, v = U(r / 0.15, 0, 1), A = U((r - 0.15) / 0.45, 0, 1), S = U((r - 0.6) / 0.4, 0, 1);
452
+ if (t.save(), t.globalAlpha = v, t.fillStyle = b, t.beginPath(), t.arc(m, R, 2.5 * h, 0, H), t.fill(), t.restore(), A > 0) {
453
+ t.save(), t.globalAlpha = A, t.strokeStyle = b, t.lineWidth = 1 * h, t.lineCap = "round", t.beginPath(), t.moveTo(m, R);
454
+ const c = m + (g - m) * A, l = R + (y - R) * A;
455
+ if (t.lineTo(c, l), S > 0) {
456
+ const M = g + (C - g) * S, i = y + (P - y) * S;
457
+ t.lineTo(M, i);
346
458
  }
347
459
  t.stroke(), t.restore();
348
460
  }
349
- S > 0 && (t.save(), t.globalAlpha = S, t.fillStyle = i, t.textAlign = R >= 0 ? "left" : "right", t.textBaseline = "middle", t.fillText(M, A, L), t.restore());
461
+ if (S > 0) {
462
+ const c = 2 * h, l = p >= 0 ? u - c - f : f - c, M = St(t, T, l);
463
+ if (M.length === 0) return;
464
+ t.save(), t.globalAlpha = S, t.fillStyle = o, t.textAlign = p >= 0 ? "left" : "right", t.textBaseline = "middle", t.fillText(M, f, P), t.restore();
465
+ }
350
466
  }
351
467
  /**
352
468
  * Lay out one outside label per eligible slice. Returns entries in original
@@ -363,183 +479,204 @@ class ft {
363
479
  * to the opposite side would mean flipping text direction without moving
364
480
  * the label, which would push text across the pie.
365
481
  */
366
- #x(e) {
367
- const { cx: t, cy: o, outerR: i, total: s, palette: d, theme: r, labels: c, hpr: g, bitmapHeight: C } = e, x = new Array(this.#t.length).fill(null), R = c.elbowLen * g, M = Math.max(c.distance, c.elbowLen) * g, X = Math.max(0, c.railWidth) * g, $ = [];
368
- let L = -Math.PI / 2;
369
- const A = c.minSliceAngle * U;
370
- for (let v = 0; v < this.#t.length; v++) {
371
- const u = this.#t[v], a = this.#o(u.value) / s * N;
372
- if (a >= A) {
373
- const w = L + a / 2, n = this.#s[v] * (8 * g), f = Math.cos(w), h = Math.sin(w), m = f >= 0 ? 1 : -1, O = t + f * (i + n), P = o + h * (i + n), H = t + f * (i + n + R), p = o + h * (i + n + R), W = t + f * (i + n + M) + m * X, y = o + h * (i + n + M), Y = {
374
- anchorX: O,
375
- anchorY: P,
376
- elbowX: H,
377
- elbowY: p,
378
- side: m,
379
- labelX: W,
380
- labelY: y,
381
- text: this.#d(u, s, c.content),
382
- color: this.#h({ index: v, palette: d, theme: r })
482
+ #R(e) {
483
+ const { cx: t, cy: n, outerR: o, total: s, palette: h, theme: r, labels: u, hpr: m, bitmapHeight: R } = e, g = new Array(this.#t.length).fill(null), y = u.elbowLen * m, p = Math.max(u.distance, u.elbowLen) * m, T = Math.max(0, u.railWidth) * m, b = [];
484
+ let C = -Math.PI / 2;
485
+ const P = u.minSliceAngle * et;
486
+ for (let S = 0; S < this.#t.length; S++) {
487
+ const c = this.#t[S], l = this.#i(c.value) / s * H;
488
+ if (l >= P) {
489
+ const M = C + l / 2, i = this.#s[S] * (8 * m), x = Math.cos(M), d = Math.sin(M), I = x >= 0 ? 1 : -1, Y = t + x * (o + i), k = n + d * (o + i), B = t + x * (o + i + y), V = n + d * (o + i + y), X = t + x * (o + i + p) + I * T, tt = n + d * (o + i + p), D = {
490
+ anchorX: Y,
491
+ anchorY: k,
492
+ elbowX: B,
493
+ elbowY: V,
494
+ side: I,
495
+ labelX: X,
496
+ labelY: tt,
497
+ text: this.#m(c, s, u.content),
498
+ color: this.#c({ index: S, palette: h, theme: r })
383
499
  };
384
- x[v] = Y, $.push({ entry: Y });
500
+ g[S] = D, b.push({ entry: D });
385
501
  }
386
- L += a;
502
+ C += l;
387
503
  }
388
- const b = Math.max(1, c.fontSize * c.labelGap) * g, I = c.fontSize * g, S = C - c.fontSize * g;
389
- for (const v of [1, -1]) {
390
- const u = [];
391
- for (const n of $)
392
- n.entry.side === v && u.push(n.entry);
393
- if (u.length === 0) continue;
394
- u.sort((n, f) => n.labelY - f.labelY);
395
- const a = [];
396
- for (let n = 0; n < u.length; n++)
397
- for (a.push({ count: 1, sumIdeal: u[n].labelY, startIdx: n }); a.length >= 2; ) {
398
- const f = a[a.length - 2], h = a[a.length - 1], m = f.sumIdeal / f.count, O = h.sumIdeal / h.count, P = m + (f.count - 1) * b / 2;
399
- if (O - (h.count - 1) * b / 2 >= P + b) break;
400
- f.count += h.count, f.sumIdeal += h.sumIdeal, a.pop();
504
+ const f = Math.max(1, u.fontSize * u.labelGap) * m, v = u.fontSize * m, A = R - u.fontSize * m;
505
+ for (const S of [1, -1]) {
506
+ const c = [];
507
+ for (const i of b)
508
+ i.entry.side === S && c.push(i.entry);
509
+ if (c.length === 0) continue;
510
+ c.sort((i, x) => i.labelY - x.labelY);
511
+ const l = [];
512
+ for (let i = 0; i < c.length; i++)
513
+ for (l.push({ count: 1, sumIdeal: c[i].labelY, startIdx: i }); l.length >= 2; ) {
514
+ const x = l[l.length - 2], d = l[l.length - 1], I = x.sumIdeal / x.count, Y = d.sumIdeal / d.count, k = I + (x.count - 1) * f / 2;
515
+ if (Y - (d.count - 1) * f / 2 >= k + f) break;
516
+ x.count += d.count, x.sumIdeal += d.sumIdeal, l.pop();
401
517
  }
402
- if (a.length > 0) {
403
- const n = a[0], f = n.sumIdeal / n.count - (n.count - 1) * b / 2;
404
- if (f < I)
405
- for (n.sumIdeal += (I - f) * n.count; a.length >= 2; ) {
406
- const h = a[0], m = a[1], O = h.sumIdeal / h.count, P = m.sumIdeal / m.count, H = O + (h.count - 1) * b / 2;
407
- if (P - (m.count - 1) * b / 2 >= H + b) break;
408
- h.count += m.count, h.sumIdeal += m.sumIdeal, a.splice(1, 1);
518
+ if (l.length > 0) {
519
+ const i = l[0], x = i.sumIdeal / i.count - (i.count - 1) * f / 2;
520
+ if (x < v)
521
+ for (i.sumIdeal += (v - x) * i.count; l.length >= 2; ) {
522
+ const d = l[0], I = l[1], Y = d.sumIdeal / d.count, k = I.sumIdeal / I.count, B = Y + (d.count - 1) * f / 2;
523
+ if (k - (I.count - 1) * f / 2 >= B + f) break;
524
+ d.count += I.count, d.sumIdeal += I.sumIdeal, l.splice(1, 1);
409
525
  }
410
526
  }
411
- if (a.length > 0) {
412
- const n = a[a.length - 1], f = n.sumIdeal / n.count + (n.count - 1) * b / 2;
413
- if (f > S)
414
- for (n.sumIdeal -= (f - S) * n.count; a.length >= 2; ) {
415
- const h = a[a.length - 2], m = a[a.length - 1], O = h.sumIdeal / h.count, P = m.sumIdeal / m.count, H = O + (h.count - 1) * b / 2;
416
- if (P - (m.count - 1) * b / 2 >= H + b) break;
417
- h.count += m.count, h.sumIdeal += m.sumIdeal, a.pop();
527
+ if (l.length > 0) {
528
+ const i = l[l.length - 1], x = i.sumIdeal / i.count + (i.count - 1) * f / 2;
529
+ if (x > A)
530
+ for (i.sumIdeal -= (x - A) * i.count; l.length >= 2; ) {
531
+ const d = l[l.length - 2], I = l[l.length - 1], Y = d.sumIdeal / d.count, k = I.sumIdeal / I.count, B = Y + (d.count - 1) * f / 2;
532
+ if (k - (I.count - 1) * f / 2 >= B + f) break;
533
+ d.count += I.count, d.sumIdeal += I.sumIdeal, l.pop();
418
534
  }
419
535
  }
420
- const w = (I + S) / 2;
421
- for (const n of a) {
422
- const f = (n.count - 1) * b, h = n.sumIdeal / n.count;
423
- f > S - I && h - f / 2 < I && (n.sumIdeal = w * n.count);
536
+ const M = (v + A) / 2;
537
+ for (const i of l) {
538
+ const x = (i.count - 1) * f, d = i.sumIdeal / i.count;
539
+ x > A - v && d - x / 2 < v && (i.sumIdeal = M * i.count);
424
540
  }
425
- for (const n of a) {
426
- const f = n.sumIdeal / n.count;
427
- for (let h = 0; h < n.count; h++)
428
- u[n.startIdx + h].labelY = f + (h - (n.count - 1) / 2) * b;
541
+ for (const i of l) {
542
+ const x = i.sumIdeal / i.count;
543
+ for (let d = 0; d < i.count; d++)
544
+ c[i.startIdx + d].labelY = x + (d - (i.count - 1) / 2) * f;
429
545
  }
430
546
  }
431
- for (const v of $) {
432
- const u = v.entry, a = u.labelY - u.anchorY;
433
- let w;
434
- if (Math.abs(a) <= R) {
435
- const h = u.side * Math.sqrt(Math.max(0, R * R - a * a));
436
- w = u.anchorX + h;
547
+ for (const S of b) {
548
+ const c = S.entry, l = c.labelY - c.anchorY;
549
+ let M;
550
+ if (Math.abs(l) <= y) {
551
+ const d = c.side * Math.sqrt(Math.max(0, y * y - l * l));
552
+ M = c.anchorX + d;
437
553
  } else
438
- w = (u.anchorX + u.labelX) / 2;
439
- const n = Math.min(u.anchorX, u.labelX), f = Math.max(u.anchorX, u.labelX);
440
- u.elbowX = Math.max(n, Math.min(f, w)), u.elbowY = u.labelY;
554
+ M = (c.anchorX + c.labelX) / 2;
555
+ const i = Math.min(c.anchorX, c.labelX), x = Math.max(c.anchorX, c.labelX);
556
+ c.elbowX = Math.max(i, Math.min(x, M)), c.elbowY = c.labelY;
441
557
  }
442
- return x;
558
+ return g;
443
559
  }
444
560
  render(e) {
445
- if (this.#t.length === 0) return;
446
- const { scope: t, theme: o, padding: i } = e, { context: s, bitmapSize: d, horizontalPixelRatio: r, verticalPixelRatio: c } = t, g = performance.now(), C = this.#u ? Math.min(0.05, (g - this.#u) / 1e3) : 0;
447
- this.#u = g;
448
- const x = this.#f();
449
- if (x <= 0) return;
450
- const R = 12;
561
+ if (this.#t.length === 0) {
562
+ this.#x();
563
+ return;
564
+ }
565
+ const { scope: t, theme: n, padding: o } = e, { context: s, bitmapSize: h, horizontalPixelRatio: r, verticalPixelRatio: u } = t, m = performance.now(), R = this.#f ? Math.min(0.05, (m - this.#f) / 1e3) : 0;
566
+ this.#f = m;
567
+ const g = this.#d();
568
+ if (g <= 0) {
569
+ this.#x();
570
+ return;
571
+ }
572
+ this.#r.tick(m);
573
+ const y = this.#r.active, p = -Math.PI / 2 + this.#r.sweep() * H, T = 12;
451
574
  for (; this.#s.length < this.#t.length; )
452
575
  this.#s.push(0);
453
576
  if (this.#e.animate)
454
- for (let p = 0; p < this.#t.length; p++) {
455
- const W = p === this.#i ? 1 : 0;
456
- this.#s[p] = K(this.#s[p], W, R, C);
577
+ for (let w = 0; w < this.#t.length; w++) {
578
+ const O = w === this.#a ? 1 : 0;
579
+ this.#s[w] = nt(this.#s[w], O, T, R);
580
+ }
581
+ const b = it(this.#e.sliceLabels);
582
+ s.font = `${b.fontSize * r}px ${n.typography.fontFamily}`, b.mode === "outside" && !y && this.#o < 1 && (this.#o = nt(this.#o, 1, 6, R), this.#o >= 0.995 && (this.#o = 1));
583
+ const C = this.#e.colors ?? n.seriesColors;
584
+ let P = b.mode === "outside" ? this.#y(s, b, g, r) : 0;
585
+ const f = {
586
+ bitmapWidth: h.width,
587
+ bitmapHeight: h.height,
588
+ padTop: o.top * u,
589
+ padBottom: o.bottom * u
590
+ };
591
+ let { cx: v, cy: A, maxR: S } = st({ ...f, labelReserve: P }), c = b.mode === "outside";
592
+ c && S < yt * r && (c = !1, P = 0, { cx: v, cy: A, maxR: S } = st({ ...f, labelReserve: P })), this.#g = P;
593
+ const l = S, M = l * this.#e.innerRadiusRatio, i = this.#e.padAngle * et, x = (this.#e.cornerRadius ?? 3) * r, d = 8 * r, I = this.#e.shadow ?? !1, Y = bt(I), k = this.#e.innerShadow ?? !1, B = xt(k), V = this.#e.gradient !== !1;
594
+ let X = -Math.PI / 2;
595
+ for (let w = 0; w < this.#t.length; w++) {
596
+ const O = this.#t[w], $ = this.#i(O.value) / g * H, W = X + i / 2;
597
+ let L = X + $ - i / 2;
598
+ const _ = X + $ / 2, F = this.#c({ index: w, palette: C, theme: n });
599
+ if (y) {
600
+ if (W >= p) {
601
+ X += $;
602
+ continue;
603
+ }
604
+ L = Math.min(L, p);
457
605
  }
458
- const M = it(this.#e.sliceLabels);
459
- s.font = `${M.fontSize * r}px ${o.typography.fontFamily}`, M.mode === "outside" && this.#e.animate && (this.#a = K(this.#a, 1, 6, C));
460
- const X = this.#e.colors ?? o.seriesColors, $ = M.mode === "outside" ? this.#b(s, M, x, r) : 0, { cx: L, cy: A, maxR: b } = Z({
461
- bitmapWidth: d.width,
462
- bitmapHeight: d.height,
463
- padTop: i.top * c,
464
- padBottom: i.bottom * c,
465
- labelReserve: $
466
- }), I = b, S = I * this.#e.innerRadiusRatio, v = this.#e.padAngle * U, u = 8 * r, a = this.#e.shadow ?? !1, w = at(a), n = this.#e.innerShadow ?? !1, f = rt(n), h = this.#e.gradient !== !1;
467
- let m = -Math.PI / 2;
468
- for (let p = 0; p < this.#t.length; p++) {
469
- const W = this.#t[p], y = this.#o(W.value) / x * N, Y = m + v / 2, B = m + y - v / 2, D = m + y / 2, F = this.#h({ index: p, palette: X, theme: o });
470
- if (B <= Y) {
471
- m += y;
606
+ if (L <= W) {
607
+ X += $;
472
608
  continue;
473
609
  }
474
- const V = this.#s[p] * u, q = Math.cos(D) * V, _ = Math.sin(D) * V, z = L + q, k = A + _;
475
- if (s.beginPath(), s.arc(z, k, I, Y, B), S > 0 ? s.arc(z, k, S, B, Y, !0) : s.lineTo(z, k), s.closePath(), h || n) {
476
- const T = s.createRadialGradient(z, k, S || 0, z, k, I);
477
- if (T.addColorStop(0, h ? ct(F, 0.15) : F), n) {
478
- const G = Math.max(0, Math.min(0.999, 1 - f.depth));
479
- T.addColorStop(G, F), T.addColorStop(1, ut(F, f.color));
610
+ const K = this.#s[w] * d, q = Math.cos(_) * K, J = Math.sin(_) * K, N = v + q, E = A + J, j = x > 0.5 ? Math.min(x, vt({ outerR: l, innerR: M, halfSpan: (L - W) / 2 })) : 0;
611
+ if (s.beginPath(), j > 0.5 ? this.#v(s, { sliceCx: N, sliceCy: E, outerR: l, innerR: M, startAngle: W, endAngle: L, cornerRadius: j }) : (s.arc(N, E, l, W, L), M > 0 ? s.arc(N, E, M, L, W, !0) : s.lineTo(N, E)), s.closePath(), V || k) {
612
+ const z = s.createRadialGradient(N, E, M || 0, N, E, l);
613
+ if (z.addColorStop(0, V ? Rt(F, 0.15) : F), k) {
614
+ const G = Math.max(0, Math.min(0.999, 1 - B.depth));
615
+ z.addColorStop(G, F), z.addColorStop(1, wt(F, B.color));
480
616
  } else
481
- T.addColorStop(1, F);
482
- s.fillStyle = T;
617
+ z.addColorStop(1, F);
618
+ s.fillStyle = z;
483
619
  } else
484
620
  s.fillStyle = F;
485
- const j = this.#s[p];
486
- if (a || j > 0.01) {
487
- const T = a ? 1 : 0, G = j;
488
- s.shadowColor = a ? w.color : "rgba(0,0,0,0.25)", s.shadowBlur = (w.blur * T + 12 * G) * r, s.shadowOffsetX = w.offsetX * T * r + q * 0.3 * G, s.shadowOffsetY = w.offsetY * T * c + _ * 0.3 * G;
621
+ const Q = this.#s[w];
622
+ if (I || Q > 0.01) {
623
+ const z = I ? 1 : 0, G = Q;
624
+ s.shadowColor = I ? Y.color : "rgba(0,0,0,0.25)", s.shadowBlur = (Y.blur * z + 12 * G) * r, s.shadowOffsetX = Y.offsetX * z * r + q * 0.3 * G, s.shadowOffsetY = Y.offsetY * z * u + J * 0.3 * G;
489
625
  }
490
- s.fill(), s.shadowColor = "transparent", s.shadowBlur = 0, s.shadowOffsetX = 0, s.shadowOffsetY = 0, m += y;
626
+ s.fill(), s.shadowColor = "transparent", s.shadowBlur = 0, s.shadowOffsetX = 0, s.shadowOffsetY = 0, X += $;
491
627
  }
492
- if (M.mode === "none") return;
493
- m = -Math.PI / 2;
494
- const O = o.tooltip.textColor;
495
- if (M.mode === "outside") {
496
- const p = this.#x({
497
- cx: L,
628
+ if (b.mode === "none" || b.mode === "outside" && !c) return;
629
+ X = -Math.PI / 2;
630
+ const tt = n.tooltip.textColor;
631
+ if (b.mode === "outside") {
632
+ const w = this.#R({
633
+ cx: v,
498
634
  cy: A,
499
- outerR: I,
500
- total: x,
501
- palette: X,
502
- theme: o,
503
- labels: M,
635
+ outerR: l,
636
+ total: g,
637
+ palette: C,
638
+ theme: n,
639
+ labels: b,
504
640
  hpr: r,
505
- bitmapHeight: d.height
506
- }), W = p.length > 1 ? Math.min(0.06, 0.9 / (p.length - 1)) : 0;
507
- for (let y = 0; y < p.length; y++) {
508
- const Y = p[y];
509
- if (Y === null) continue;
510
- const B = y * W, D = E((this.#a - B) / (1 - B), 0, 1);
511
- this.#g({
641
+ bitmapHeight: h.height
642
+ }), O = w.length > 1 ? Math.min(0.06, 0.9 / (w.length - 1)) : 0;
643
+ for (let $ = 0; $ < w.length; $++) {
644
+ const W = w[$];
645
+ if (W === null) continue;
646
+ const L = $ * O, _ = U((this.#o - L) / (1 - L), 0, 1);
647
+ this.#S({
512
648
  context: s,
513
- entry: Y,
514
- textColor: O,
515
- labels: M,
649
+ entry: W,
650
+ textColor: tt,
651
+ labels: b,
516
652
  hpr: r,
517
- progress: D
653
+ progress: _,
654
+ bitmapWidth: h.width
518
655
  });
519
656
  }
520
657
  return;
521
658
  }
522
- const P = S > 0 ? (I + S) / 2 : I * 0.65;
659
+ const D = M > 0 ? (l + M) / 2 : l * 0.65;
523
660
  s.textAlign = "center", s.textBaseline = "middle";
524
- const H = M.minSliceAngle * U;
525
- for (let p = 0; p < this.#t.length; p++) {
526
- const W = this.#t[p], y = this.#o(W.value) / x * N;
527
- if (y >= H) {
528
- const Y = m + y / 2, B = this.#s[p] * u, D = this.#h({ index: p, palette: X, theme: o }), F = this.#d(W, x, M.content), V = s.measureText(F).width, q = M.fontSize * 1.2 * r, _ = y < Math.PI ? 2 * P * Math.sin(y / 2) : 2 * P, z = V > _ - 4 * r, k = S > 0 && P - S < q;
529
- if (!z && !k) {
530
- const j = L + Math.cos(Y) * (P + B), T = A + Math.sin(Y) * (P + B);
531
- s.fillStyle = ht(D) ? "#000000" : "#ffffff", s.fillText(F, j, T);
661
+ const ht = b.minSliceAngle * et;
662
+ for (let w = 0; w < this.#t.length; w++) {
663
+ const O = this.#t[w], $ = this.#i(O.value) / g * H;
664
+ if ($ >= ht) {
665
+ const W = X + $ / 2, L = this.#s[w] * d, _ = this.#c({ index: w, palette: C, theme: n }), F = this.#m(O, g, b.content), K = s.measureText(F).width, q = b.fontSize * 1.2 * r, J = $ < Math.PI ? 2 * D * Math.sin($ / 2) : 2 * D, N = K > J - 4 * r, E = M > 0 && D - M < q, j = y ? U((p - (X + $)) / 0.35, 0, 1) : 1;
666
+ if (!N && !E && j > 0) {
667
+ const Q = v + Math.cos(W) * (D + L), z = A + Math.sin(W) * (D + L), G = j < 1;
668
+ G && (s.save(), s.globalAlpha *= j), s.fillStyle = ft(_) ? "#000000" : "#ffffff", s.fillText(F, Q, z), G && s.restore();
532
669
  }
533
670
  }
534
- m += y;
671
+ X += $;
535
672
  }
536
673
  }
537
674
  }
538
- const pt = {
675
+ const Pt = {
539
676
  type: "pie",
540
- create: (l, e) => new ft({ ...e })
677
+ create: (a, e) => new It({ ...e })
541
678
  };
542
679
  export {
543
- ft as PieRenderer,
544
- pt as PieSeriesDef
680
+ It as PieRenderer,
681
+ Pt as PieSeriesDef
545
682
  };