apexcharts 8.2.0 → 8.3.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 (256) hide show
  1. package/README.md +7 -7
  2. package/dist/apexcharts.common.js +2 -2
  3. package/dist/apexcharts.core.js +19793 -19713
  4. package/dist/apexcharts.core.min.js +2 -2
  5. package/dist/apexcharts.css +38 -8
  6. package/dist/apexcharts.esm.js +1882 -1625
  7. package/dist/apexcharts.full.js +22044 -21634
  8. package/dist/apexcharts.full.min.js +2 -2
  9. package/dist/apexcharts.js +21414 -21124
  10. package/dist/apexcharts.min.js +2 -2
  11. package/dist/apexcharts.ssr.common.js +2 -2
  12. package/dist/apexcharts.ssr.esm.js +21413 -21123
  13. package/dist/area.common.js +2 -2
  14. package/dist/area.esm.js +91 -40
  15. package/dist/bar.common.js +2 -2
  16. package/dist/bar.esm.js +478 -406
  17. package/dist/bar.js +2 -2
  18. package/dist/boxPlot.common.js +2 -2
  19. package/dist/boxPlot.esm.js +409 -334
  20. package/dist/bubble.common.js +2 -2
  21. package/dist/bubble.esm.js +91 -40
  22. package/dist/candlestick.common.js +2 -2
  23. package/dist/candlestick.esm.js +409 -334
  24. package/dist/candlestick.js +2 -2
  25. package/dist/column.common.js +2 -2
  26. package/dist/column.esm.js +478 -406
  27. package/dist/core.common.js +2 -2
  28. package/dist/core.esm.js +19793 -19713
  29. package/dist/donut.common.js +2 -2
  30. package/dist/donut.esm.js +3 -9
  31. package/dist/dumbbell.common.js +2 -2
  32. package/dist/dumbbell.esm.js +478 -406
  33. package/dist/features/all.common.js +2 -2
  34. package/dist/features/all.esm.js +442 -324
  35. package/dist/features/annotations.common.js +2 -2
  36. package/dist/features/annotations.esm.js +65 -48
  37. package/dist/features/annotations.js +2 -2
  38. package/dist/features/context-menu.common.js +1 -1
  39. package/dist/features/context-menu.esm.js +1 -1
  40. package/dist/features/context-menu.js +1 -1
  41. package/dist/features/drilldown.common.js +2 -2
  42. package/dist/features/drilldown.esm.js +4 -2
  43. package/dist/features/drilldown.js +2 -2
  44. package/dist/features/dumbbell.common.js +1 -1
  45. package/dist/features/dumbbell.esm.js +1 -1
  46. package/dist/features/dumbbell.js +1 -1
  47. package/dist/features/exports.common.js +2 -2
  48. package/dist/features/exports.esm.js +10 -4
  49. package/dist/features/exports.js +2 -2
  50. package/dist/features/facet.common.js +1 -1
  51. package/dist/features/facet.esm.js +1 -1
  52. package/dist/features/facet.js +1 -1
  53. package/dist/features/highlight-filter.common.js +2 -2
  54. package/dist/features/highlight-filter.esm.js +14 -9
  55. package/dist/features/highlight-filter.js +2 -2
  56. package/dist/features/history.common.js +1 -1
  57. package/dist/features/history.esm.js +1 -1
  58. package/dist/features/history.js +1 -1
  59. package/dist/features/ink.common.js +1 -1
  60. package/dist/features/ink.esm.js +1 -1
  61. package/dist/features/ink.js +1 -1
  62. package/dist/features/keyboard.common.js +2 -2
  63. package/dist/features/keyboard.esm.js +97 -145
  64. package/dist/features/keyboard.js +2 -2
  65. package/dist/features/legend.common.js +2 -2
  66. package/dist/features/legend.esm.js +64 -44
  67. package/dist/features/legend.js +2 -2
  68. package/dist/features/link.common.js +1 -1
  69. package/dist/features/link.esm.js +1 -1
  70. package/dist/features/link.js +1 -1
  71. package/dist/features/marks.common.js +1 -1
  72. package/dist/features/marks.esm.js +1 -1
  73. package/dist/features/marks.js +1 -1
  74. package/dist/features/measure.common.js +1 -1
  75. package/dist/features/measure.esm.js +1 -1
  76. package/dist/features/measure.js +1 -1
  77. package/dist/features/morph.common.js +2 -2
  78. package/dist/features/morph.esm.js +9 -5
  79. package/dist/features/morph.js +2 -2
  80. package/dist/features/perspectives.common.js +2 -2
  81. package/dist/features/perspectives.esm.js +4 -1
  82. package/dist/features/perspectives.js +2 -2
  83. package/dist/features/raincloud.common.js +2 -2
  84. package/dist/features/raincloud.esm.js +26 -27
  85. package/dist/features/raincloud.js +2 -2
  86. package/dist/features/renderer-canvas.common.js +2 -2
  87. package/dist/features/renderer-canvas.esm.js +2 -1
  88. package/dist/features/renderer-canvas.js +2 -2
  89. package/dist/features/stats.common.js +2 -2
  90. package/dist/features/stats.esm.js +52 -59
  91. package/dist/features/stats.js +2 -2
  92. package/dist/features/storyboard.common.js +2 -2
  93. package/dist/features/storyboard.esm.js +4 -1
  94. package/dist/features/storyboard.js +2 -2
  95. package/dist/features/streamgraph.common.js +2 -2
  96. package/dist/features/streamgraph.esm.js +48 -14
  97. package/dist/features/streamgraph.js +2 -2
  98. package/dist/features/toolbar.common.js +2 -2
  99. package/dist/features/toolbar.esm.js +148 -18
  100. package/dist/features/toolbar.js +2 -2
  101. package/dist/features/trellis.common.js +2 -2
  102. package/dist/features/trellis.esm.js +150 -63
  103. package/dist/features/trellis.js +2 -2
  104. package/dist/features/waterfall.common.js +1 -1
  105. package/dist/features/waterfall.esm.js +1 -1
  106. package/dist/features/waterfall.js +1 -1
  107. package/dist/features/weave.common.js +2 -2
  108. package/dist/features/weave.esm.js +13 -12
  109. package/dist/features/weave.js +2 -2
  110. package/dist/full.common.js +2 -2
  111. package/dist/full.esm.js +1068 -842
  112. package/dist/heatmap.common.js +2 -2
  113. package/dist/heatmap.esm.js +3 -17
  114. package/dist/heatmap.js +2 -2
  115. package/dist/histogram.common.js +2 -2
  116. package/dist/histogram.esm.js +529 -464
  117. package/dist/icicle.common.js +2 -2
  118. package/dist/icicle.esm.js +80 -46
  119. package/dist/icicle.js +2 -2
  120. package/dist/line.common.js +2 -2
  121. package/dist/line.esm.js +91 -40
  122. package/dist/line.js +2 -2
  123. package/dist/locales/en.json +2 -1
  124. package/dist/locales/ro.json +3 -2
  125. package/dist/pictograms.common.js +1 -1
  126. package/dist/pictograms.esm.js +1 -1
  127. package/dist/pictograms.js +1 -1
  128. package/dist/pie.common.js +2 -2
  129. package/dist/pie.esm.js +3 -9
  130. package/dist/pie.js +2 -2
  131. package/dist/polarArea.common.js +2 -2
  132. package/dist/polarArea.esm.js +3 -9
  133. package/dist/radar.common.js +2 -2
  134. package/dist/radar.esm.js +5 -4
  135. package/dist/radar.js +2 -2
  136. package/dist/radialBar.common.js +2 -2
  137. package/dist/radialBar.esm.js +5 -12
  138. package/dist/radialBar.js +2 -2
  139. package/dist/raincloud.common.js +2 -2
  140. package/dist/raincloud.esm.js +97 -52
  141. package/dist/rangeArea.common.js +2 -2
  142. package/dist/rangeArea.esm.js +91 -40
  143. package/dist/rangeBar.common.js +2 -2
  144. package/dist/rangeBar.esm.js +478 -406
  145. package/dist/scatter.common.js +2 -2
  146. package/dist/scatter.esm.js +91 -40
  147. package/dist/streamgraph.common.js +2 -2
  148. package/dist/streamgraph.esm.js +138 -53
  149. package/dist/sunburst.common.js +2 -2
  150. package/dist/sunburst.esm.js +116 -94
  151. package/dist/sunburst.js +2 -2
  152. package/dist/treemap.common.js +2 -2
  153. package/dist/treemap.esm.js +138 -104
  154. package/dist/treemap.js +2 -2
  155. package/dist/unit-shapes.common.js +1 -1
  156. package/dist/unit-shapes.esm.js +1 -1
  157. package/dist/unit-shapes.js +1 -1
  158. package/dist/unit.common.js +2 -2
  159. package/dist/unit.esm.js +280 -202
  160. package/dist/unit.js +2 -2
  161. package/dist/violin.common.js +2 -2
  162. package/dist/violin.esm.js +72 -26
  163. package/dist/violin.js +2 -2
  164. package/dist/waterfall.common.js +2 -2
  165. package/dist/waterfall.esm.js +477 -405
  166. package/package.json +1 -1
  167. package/src/apexcharts.js +40 -59
  168. package/src/assets/apexcharts.css +38 -8
  169. package/src/charts/Bar.js +62 -55
  170. package/src/charts/BarStacked.js +80 -88
  171. package/src/charts/BoxCandleStick.js +28 -31
  172. package/src/charts/Icicle.js +68 -47
  173. package/src/charts/Line.js +118 -42
  174. package/src/charts/Pie.js +2 -8
  175. package/src/charts/Radar.js +5 -7
  176. package/src/charts/Radial.js +2 -6
  177. package/src/charts/RangeBar.js +47 -43
  178. package/src/charts/Sunburst.js +101 -98
  179. package/src/charts/Treemap.js +150 -88
  180. package/src/charts/Unit.js +368 -250
  181. package/src/charts/Violin.js +48 -30
  182. package/src/charts/common/Breadcrumb.js +2 -2
  183. package/src/charts/common/Hierarchy.js +32 -11
  184. package/src/charts/common/Jitter.js +32 -7
  185. package/src/charts/common/Stats.js +30 -23
  186. package/src/charts/common/bar/DataLabels.js +76 -81
  187. package/src/charts/common/bar/Helpers.js +43 -7
  188. package/src/charts/common/line/Helpers.js +12 -15
  189. package/src/charts/common/partition/NodeTooltip.js +29 -7
  190. package/src/charts/common/partition/Partition.js +33 -1
  191. package/src/charts/common/treemap/Helpers.js +3 -11
  192. package/src/charts/common/treemap/Nested.js +2 -3
  193. package/src/features/raincloud.js +16 -10
  194. package/src/features/stats.js +67 -62
  195. package/src/locales/en.json +2 -1
  196. package/src/locales/ro.json +3 -2
  197. package/src/modules/Animations.js +102 -95
  198. package/src/modules/AxisMapping.js +47 -12
  199. package/src/modules/Core.js +4 -0
  200. package/src/modules/CoreUtils.js +18 -42
  201. package/src/modules/Data.js +23 -24
  202. package/src/modules/DataLabels.js +6 -6
  203. package/src/modules/Exports.js +12 -5
  204. package/src/modules/Fill.js +17 -8
  205. package/src/modules/Filters.js +50 -50
  206. package/src/modules/Graphics.js +69 -51
  207. package/src/modules/Markers.js +3 -1
  208. package/src/modules/MorphTypeChange.js +13 -7
  209. package/src/modules/Range.js +44 -29
  210. package/src/modules/RendererController.js +17 -3
  211. package/src/modules/Scales.js +32 -9
  212. package/src/modules/Series.js +41 -19
  213. package/src/modules/Theme.js +1 -1
  214. package/src/modules/Toolbar.js +3 -2
  215. package/src/modules/UnitMarkRegistry.js +0 -5
  216. package/src/modules/ZoomPanSelection.js +123 -2
  217. package/src/modules/accessibility/KeyboardNavigation.js +114 -186
  218. package/src/modules/animations/Easing.js +2 -1
  219. package/src/modules/animations/LengthTransition.js +22 -2
  220. package/src/modules/annotations/Helpers.js +68 -52
  221. package/src/modules/axes/Grid.js +21 -7
  222. package/src/modules/axes/YAxis.js +8 -9
  223. package/src/modules/dimensions/Dimensions.js +9 -3
  224. package/src/modules/dimensions/Grid.js +2 -2
  225. package/src/modules/dimensions/XAxis.js +2 -5
  226. package/src/modules/drilldown/Breadcrumb.js +5 -2
  227. package/src/modules/helpers/Destroy.js +1 -1
  228. package/src/modules/helpers/UpdateHelpers.js +33 -15
  229. package/src/modules/highlightFilter/HighlightFilter.js +8 -9
  230. package/src/modules/highlightFilter/TreemapPart.js +2 -2
  231. package/src/modules/legend/HeatmapGradientLegend.js +76 -45
  232. package/src/modules/legend/Helpers.js +8 -1
  233. package/src/modules/legend/Legend.js +11 -12
  234. package/src/modules/license/LicenseEnforcer.js +5 -0
  235. package/src/modules/settings/Defaults.js +28 -56
  236. package/src/modules/settings/Globals.js +5 -0
  237. package/src/modules/settings/Options.js +7 -7
  238. package/src/modules/settings/TypeAliases.js +33 -16
  239. package/src/modules/streamgraph/StreamLabels.js +1 -0
  240. package/src/modules/tooltip/Labels.js +73 -76
  241. package/src/modules/tooltip/Marker.js +25 -21
  242. package/src/modules/tooltip/Position.js +88 -51
  243. package/src/modules/tooltip/Tooltip.js +242 -255
  244. package/src/modules/tooltip/Utils.js +71 -130
  245. package/src/modules/tooltip/constants.js +5 -5
  246. package/src/modules/trellis/Trellis.js +6 -0
  247. package/src/modules/trellis/TrellisChrome.js +18 -7
  248. package/src/modules/trellis/TrellisSync.js +2 -0
  249. package/src/modules/trellis/TrellisTooltip.js +2 -11
  250. package/src/modules/weave/WeaveHost.js +18 -12
  251. package/src/renderers/canvas/CanvasGraphics.js +1 -0
  252. package/src/ssr/DOMShim.js +10 -0
  253. package/src/svg/SVGFilter.js +26 -17
  254. package/src/types/internal.d.ts +9 -3
  255. package/src/utils/Utils.js +0 -14
  256. package/types/apexcharts.d.ts +33 -12
package/dist/full.esm.js CHANGED
@@ -50,7 +50,7 @@ var __async = (__this, __arguments, generator) => {
50
50
  });
51
51
  };
52
52
  /*!
53
- * ApexCharts v8.2.0
53
+ * ApexCharts v8.3.1
54
54
  * (c) 2018-2026 ApexCharts
55
55
  */
56
56
  import ApexCharts$1 from "apexcharts";
@@ -62,6 +62,285 @@ const getChartClass = ApexCharts.__apex_ChartFactory_getChartClass;
62
62
  const Fill = ApexCharts.__apex_Fill;
63
63
  const Graphics = ApexCharts.__apex_Graphics;
64
64
  const Series = ApexCharts.__apex_Series;
65
+ const Animations = ApexCharts.__apex_Animations;
66
+ const prefersReducedMotion = ApexCharts.__apex_Animations_prefersReducedMotion;
67
+ const BrowserAPIs = ApexCharts.__apex_BrowserAPIs_BrowserAPIs;
68
+ const Environment = ApexCharts.__apex_Environment_Environment;
69
+ const resolveEasing = ApexCharts.__apex_Easing_resolveEasing;
70
+ const parsePath = ApexCharts.__apex_PathMorphing_parsePath;
71
+ const arrayToPath = ApexCharts.__apex_PathMorphing_arrayToPath;
72
+ function buildUnionEntries(join, oldN) {
73
+ const exitSet = new Set(join.exits);
74
+ const entries = [];
75
+ let oi = 0;
76
+ for (let nj = 0; nj < join.toOld.length; nj++) {
77
+ const oj = join.toOld[nj];
78
+ if (oj !== -1) {
79
+ while (oi < oj) {
80
+ if (exitSet.has(oi)) entries.push({ oldJ: oi, newJ: -1 });
81
+ oi++;
82
+ }
83
+ entries.push({ oldJ: oj, newJ: nj });
84
+ oi = oj + 1;
85
+ } else {
86
+ entries.push({ oldJ: -1, newJ: nj });
87
+ }
88
+ }
89
+ while (oi < oldN) {
90
+ if (exitSet.has(oi)) entries.push({ oldJ: oi, newJ: -1 });
91
+ oi++;
92
+ }
93
+ return entries;
94
+ }
95
+ function analyzeSeriesPath(d, expectedAnchors, isArea) {
96
+ if (!d || typeof d !== "string") return null;
97
+ const cmds = parsePath(d);
98
+ if (!cmds.length || cmds[0][0] !== "M") return null;
99
+ for (let i2 = 1; i2 < cmds.length; i2++) {
100
+ if (cmds[i2][0] === "M") return null;
101
+ }
102
+ let body = cmds;
103
+ let closing = null;
104
+ if (isArea) {
105
+ if (cmds.length < 5) return null;
106
+ closing = cmds.slice(-3);
107
+ body = cmds.slice(0, -3);
108
+ if (closing[2][0] !== "Z") return null;
109
+ if (closing[1][0] !== "L") return null;
110
+ if (closing[0][0] !== "L" && closing[0][0] !== "C") return null;
111
+ } else if (cmds[cmds.length - 1][0] === "Z") {
112
+ return null;
113
+ }
114
+ if (body.length !== expectedAnchors || body.length < 2) return null;
115
+ const segType = body[1][0];
116
+ if (segType !== "L" && segType !== "C") return null;
117
+ for (let i2 = 2; i2 < body.length; i2++) {
118
+ if (body[i2][0] !== segType) return null;
119
+ }
120
+ const anchors = body.map(
121
+ (c) => c[0] === "C" ? [Number(c[5]), Number(c[6])] : [Number(c[1]), Number(c[2])]
122
+ );
123
+ for (const a2 of anchors) {
124
+ if (!isFinite(a2[0]) || !isFinite(a2[1])) return null;
125
+ }
126
+ return { body, closing, segType, anchors };
127
+ }
128
+ function lerpPt(a2, b, t2) {
129
+ return [a2[0] + (b[0] - a2[0]) * t2, a2[1] + (b[1] - a2[1]) * t2];
130
+ }
131
+ function splitCubic(s2, cmd, t2) {
132
+ const p0 = s2;
133
+ const p1 = [cmd[1], cmd[2]];
134
+ const p2 = [cmd[3], cmd[4]];
135
+ const p3 = [cmd[5], cmd[6]];
136
+ const p01 = lerpPt(p0, p1, t2);
137
+ const p12 = lerpPt(p1, p2, t2);
138
+ const p23 = lerpPt(p2, p3, t2);
139
+ const p012 = lerpPt(p01, p12, t2);
140
+ const p123 = lerpPt(p12, p23, t2);
141
+ const mid = lerpPt(p012, p123, t2);
142
+ return {
143
+ first: ["C", p01[0], p01[1], p012[0], p012[1], mid[0], mid[1]],
144
+ second: ["C", p123[0], p123[1], p23[0], p23[1], p3[0], p3[1]],
145
+ mid
146
+ };
147
+ }
148
+ function splitLine(s2, cmd, t2) {
149
+ const e2 = [cmd[1], cmd[2]];
150
+ const mid = lerpPt(s2, e2, t2);
151
+ return {
152
+ first: ["L", mid[0], mid[1]],
153
+ second: ["L", e2[0], e2[1]],
154
+ mid
155
+ };
156
+ }
157
+ function expandPath(analysis, ownIdx) {
158
+ const { body, closing, segType, anchors } = analysis;
159
+ const n2 = anchors.length;
160
+ const m = ownIdx.length;
161
+ const degen = (p) => segType === "C" ? ["C", p[0], p[1], p[0], p[1], p[0], p[1]] : ["L", p[0], p[1]];
162
+ const out = [["M", anchors[0][0], anchors[0][1]]];
163
+ let firstOwn = 0;
164
+ while (firstOwn < m && ownIdx[firstOwn] !== 0) firstOwn++;
165
+ for (let q2 = 1; q2 <= firstOwn; q2++) out.push(degen(anchors[0]));
166
+ let entry = firstOwn + 1;
167
+ for (let s2 = 0; s2 < n2 - 1; s2++) {
168
+ let interior = 0;
169
+ while (entry + interior < m && ownIdx[entry + interior] === -1) interior++;
170
+ const cmd = body[s2 + 1];
171
+ if (!interior) {
172
+ out.push(cmd.slice());
173
+ } else {
174
+ const totalParts = interior + 1;
175
+ let start = anchors[s2];
176
+ let rest = cmd;
177
+ for (let q2 = 0; q2 < interior; q2++) {
178
+ const t2 = 1 / (totalParts - q2);
179
+ const sp = segType === "C" ? splitCubic(start, rest, t2) : splitLine(start, rest, t2);
180
+ out.push(sp.first);
181
+ start = sp.mid;
182
+ rest = sp.second;
183
+ }
184
+ out.push(rest);
185
+ }
186
+ entry += interior + 1;
187
+ }
188
+ while (entry < m) {
189
+ out.push(degen(anchors[n2 - 1]));
190
+ entry++;
191
+ }
192
+ if (closing) closing.forEach((c) => out.push(c.slice()));
193
+ return out;
194
+ }
195
+ function reconcilePathPair(fromD, toD, entries, oldN, newN, isArea) {
196
+ const fromAnalysis = analyzeSeriesPath(fromD, oldN, isArea);
197
+ if (!fromAnalysis) return null;
198
+ const toAnalysis = analyzeSeriesPath(toD, newN, isArea);
199
+ if (!toAnalysis) return null;
200
+ if (fromAnalysis.segType !== toAnalysis.segType) return null;
201
+ if ((fromAnalysis.closing || toAnalysis.closing) && (!fromAnalysis.closing || !toAnalysis.closing || fromAnalysis.closing[0][0] !== toAnalysis.closing[0][0])) {
202
+ return null;
203
+ }
204
+ const fromOwn = entries.map((e2) => e2.oldJ);
205
+ const toOwn = entries.map((e2) => e2.newJ);
206
+ return {
207
+ from: arrayToPath(expandPath(fromAnalysis, fromOwn)),
208
+ toInterp: arrayToPath(expandPath(toAnalysis, toOwn))
209
+ };
210
+ }
211
+ function lengthTransitionEnabled(w) {
212
+ var _a;
213
+ const anim = w.config.chart.animations;
214
+ if (!anim || anim.enabled === false) return false;
215
+ if (!anim.dynamicAnimation || anim.dynamicAnimation.enabled === false) {
216
+ return false;
217
+ }
218
+ const largeThreshold = (_a = anim.largeDatasetThreshold) != null ? _a : 0;
219
+ if (largeThreshold > 0 && w.globals.dataPoints > largeThreshold) return false;
220
+ return !!(Environment.isBrowser() && w.globals.dataChanged && w.globals.shouldAnimate);
221
+ }
222
+ function datumKey(w, realIndex, j2) {
223
+ var _a, _b, _c, _d;
224
+ if ((_a = w.axisFlags) == null ? void 0 : _a.isXNumeric) {
225
+ const sx = (_c = (_b = w.seriesData) == null ? void 0 : _b.seriesX) == null ? void 0 : _c[realIndex];
226
+ if (sx && sx.length && sx[j2] != null) return "x:" + sx[j2];
227
+ }
228
+ const lbl = (_d = w.globals.labels) == null ? void 0 : _d[j2];
229
+ if (lbl != null && String(lbl) !== "") {
230
+ return "c:" + (Array.isArray(lbl) ? lbl.join(" ") : String(lbl));
231
+ }
232
+ return "j:" + j2;
233
+ }
234
+ function frameDatumKey(frame, realIndex, j2) {
235
+ var _a, _b;
236
+ if (frame.isXNumeric) {
237
+ const sx = (_a = frame.seriesX) == null ? void 0 : _a[realIndex];
238
+ if (sx && sx.length && sx[j2] != null) return "x:" + sx[j2];
239
+ }
240
+ const lbl = (_b = frame.labels) == null ? void 0 : _b[j2];
241
+ if (lbl != null && String(lbl) !== "") {
242
+ return "c:" + (Array.isArray(lbl) ? lbl.join(" ") : String(lbl));
243
+ }
244
+ return "j:" + j2;
245
+ }
246
+ function joinKeys(oldKeys, newKeys) {
247
+ const oldIndex = /* @__PURE__ */ new Map();
248
+ oldKeys.forEach((k2, i2) => {
249
+ if (!oldIndex.has(k2)) oldIndex.set(k2, i2);
250
+ });
251
+ const toOld = new Array(newKeys.length);
252
+ const usedOld = /* @__PURE__ */ new Set();
253
+ let prev = -1;
254
+ let ordered = true;
255
+ let identity = oldKeys.length === newKeys.length;
256
+ newKeys.forEach((k2, i2) => {
257
+ const oi = oldIndex.has(k2) && !usedOld.has(oldIndex.get(k2)) ? oldIndex.get(k2) : -1;
258
+ toOld[i2] = oi;
259
+ if (oi !== -1) {
260
+ usedOld.add(oi);
261
+ if (oi < prev) ordered = false;
262
+ prev = oi;
263
+ }
264
+ if (oi !== i2) identity = false;
265
+ });
266
+ const exits = [];
267
+ for (let i2 = 0; i2 < oldKeys.length; i2++) {
268
+ if (!usedOld.has(i2)) exits.push(i2);
269
+ }
270
+ return { toOld, exits, ordered, changed: !identity };
271
+ }
272
+ function uniquifyKeys(keys) {
273
+ const seen = /* @__PURE__ */ new Map();
274
+ return keys.map((k2) => {
275
+ const count = seen.get(k2) || 0;
276
+ seen.set(k2, count + 1);
277
+ return count === 0 ? k2 : `${k2}#${count}`;
278
+ });
279
+ }
280
+ function seriesKeys(w, realIndex, n2 = ((_a) => (_a = w.seriesData.series[realIndex]) == null ? void 0 : _a.length)() | 0) {
281
+ return uniquifyKeys(
282
+ Array.from({ length: n2 }, (_2, j2) => datumKey(w, realIndex, j2))
283
+ );
284
+ }
285
+ function seriesJoin(w, realIndex, includeIdentity = false, allowReorder = false) {
286
+ var _a, _b;
287
+ if (!lengthTransitionEnabled(w)) return null;
288
+ const frame = w.globals.prevStreamFrame;
289
+ if (!frame) return null;
290
+ const oldY = (_a = frame.seriesY) == null ? void 0 : _a[realIndex];
291
+ const newY = (_b = w.seriesData.series) == null ? void 0 : _b[realIndex];
292
+ if (!Array.isArray(oldY) || !Array.isArray(newY)) return null;
293
+ if (!oldY.length || !newY.length) return null;
294
+ const oldKeys = uniquifyKeys(
295
+ oldY.map((_2, j2) => frameDatumKey(frame, realIndex, j2))
296
+ );
297
+ const newKeys = seriesKeys(w, realIndex);
298
+ const join = joinKeys(oldKeys, newKeys);
299
+ if (!join.ordered && !allowReorder) return null;
300
+ if (!join.changed && !includeIdentity) return null;
301
+ return { join, oldKeys, newKeys };
302
+ }
303
+ function morphEasing(w) {
304
+ var _a, _b;
305
+ const anim = w.config.chart.animations;
306
+ return resolveEasing((_b = (_a = anim.dynamicAnimation) == null ? void 0 : _a.easing) != null ? _b : anim.easing);
307
+ }
308
+ function reconcileSeriesPaths(w, { type, realIndex, pathFromLine, pathFromArea, linePaths, areaPaths }) {
309
+ var _a, _b;
310
+ const sj = seriesJoin(w, realIndex);
311
+ if (!sj) return null;
312
+ const { join, oldKeys, newKeys } = sj;
313
+ const frame = w.globals.prevStreamFrame;
314
+ if (!frame) return null;
315
+ const oldY = (_a = frame.seriesY) == null ? void 0 : _a[realIndex];
316
+ const newY = (_b = w.seriesData.series) == null ? void 0 : _b[realIndex];
317
+ if (oldY.length < 2 || newY.length < 2) return null;
318
+ if (oldY.some((v) => v === null) || newY.some((v) => v === null)) return null;
319
+ const entries = buildUnionEntries(join, oldKeys.length);
320
+ const out = {};
321
+ if (Array.isArray(linePaths) && linePaths.length === 1 && pathFromLine) {
322
+ out.line = reconcilePathPair(
323
+ pathFromLine,
324
+ linePaths[0],
325
+ entries,
326
+ oldKeys.length,
327
+ newKeys.length,
328
+ false
329
+ );
330
+ }
331
+ if (type === "area" && Array.isArray(areaPaths) && areaPaths.length === 1 && pathFromArea) {
332
+ out.area = reconcilePathPair(
333
+ pathFromArea,
334
+ areaPaths[0],
335
+ entries,
336
+ oldKeys.length,
337
+ newKeys.length,
338
+ true
339
+ );
340
+ }
341
+ if (!out.line && !out.area) return null;
342
+ return out;
343
+ }
65
344
  const Utils = ApexCharts.__apex_Utils;
66
345
  const tangents = (points) => {
67
346
  const m = finiteDifferences(points);
@@ -173,9 +452,20 @@ function finiteDifferences(points) {
173
452
  m[i2] = d;
174
453
  return m;
175
454
  }
455
+ function jitterExtent(pool, w) {
456
+ let lo = Infinity;
457
+ let hi = -Infinity;
458
+ pool.slice(0, w.seriesData.series.length).flat(2).forEach((v) => {
459
+ if (v === +v) {
460
+ if (v < lo) lo = v;
461
+ if (v > hi) hi = v;
462
+ }
463
+ });
464
+ return [lo, hi];
465
+ }
176
466
  function buildJitterGroups({
177
- w,
178
467
  points,
468
+ extent,
179
469
  seedA,
180
470
  seedB,
181
471
  center,
@@ -186,6 +476,7 @@ function buildJitterGroups({
186
476
  clampAt,
187
477
  sideSign
188
478
  }) {
479
+ var _a, _b;
189
480
  const opts = options;
190
481
  if (!opts || opts.show === false) return [];
191
482
  if (!points || !points.length) return [];
@@ -199,8 +490,8 @@ function buildJitterGroups({
199
490
  const scale = opts.colorScale;
200
491
  const useScale = scale && Array.isArray(scale.colors) && scale.colors.length > 0;
201
492
  const steps = useScale ? Math.max(2, scale.steps || 24) : 1;
202
- const sMin = useScale && scale.min != null ? scale.min : w.globals.minY;
203
- const sMax = useScale && scale.max != null ? scale.max : w.globals.maxY;
493
+ const sMin = (_a = scale == null ? void 0 : scale.min) != null ? _a : extent[0];
494
+ const sMax = (_b = scale == null ? void 0 : scale.max) != null ? _b : extent[1];
204
495
  const span = sMax - sMin || 1;
205
496
  const buckets = useScale ? new Array(steps).fill("") : [""];
206
497
  for (let k2 = 0; k2 < points.length; k2 += stride) {
@@ -286,7 +577,7 @@ function renderJitter({
286
577
  elSeries.add(elPointsWrap);
287
578
  }
288
579
  function darkenColor(color, amount) {
289
- const rgb = Utils.parseHex(color);
580
+ const rgb = Utils.parseColor(color) || Utils.parseColor(Utils.resolveColor(color));
290
581
  if (!rgb) return color;
291
582
  const f = Math.max(0, 1 - amount);
292
583
  return `rgb(${Math.round(rgb[0] * f)},${Math.round(rgb[1] * f)},${Math.round(rgb[2] * f)})`;
@@ -343,6 +634,7 @@ class Violin extends BarBase {
343
634
  const fill = new Fill(this.w);
344
635
  this.violinOptions = w.config.plotOptions.violin;
345
636
  this.pointsOptions = this.violinOptions.points;
637
+ this.jx = jitterExtent(w.violinData.seriesViolinPoints, w);
346
638
  this.boxOptions = this.violinOptions.box || {};
347
639
  this.cloudSign = crossSign(this.violinOptions.side);
348
640
  this.rainSign = this.pointsOptions.show === false ? 0 : crossSign(this.pointsOptions.position);
@@ -357,7 +649,7 @@ class Violin extends BarBase {
357
649
  series = this.coreUtils.getLogSeries(series);
358
650
  this.series = series;
359
651
  this.yRatio = this.coreUtils.getLogYRatios(this.yRatio);
360
- this.barHelpers.initVariables(series);
652
+ this.barHelpers.initVariables(series, seriesIndex);
361
653
  const ret = graphics.group({
362
654
  class: "apexcharts-violin-series apexcharts-plot-series"
363
655
  });
@@ -504,7 +796,8 @@ class Violin extends BarBase {
504
796
  elDataLabelsWrap,
505
797
  visibleSeries: this.visibleI,
506
798
  type: "violin",
507
- classes: "apexcharts-raincloud-box"
799
+ classes: "apexcharts-raincloud-box",
800
+ noLabel: true
508
801
  });
509
802
  });
510
803
  }
@@ -541,11 +834,16 @@ class Violin extends BarBase {
541
834
  var _a, _b, _c, _d, _e, _f, _g;
542
835
  const w = this.w;
543
836
  const { realIndex, j: j2, translationsIndex } = indexes;
544
- const yRatio = this.yRatio[translationsIndex];
837
+ const yRatio = this.yRatio[translationsIndex] * (this.isReversed ? -1 : 1);
838
+ let barXPosition = x2 + barWidth * this.visibleI;
545
839
  if (w.axisFlags.isXNumeric) {
546
- x2 = (w.seriesData.seriesX[realIndex][j2] - w.globals.minX) / this.xRatio - barWidth / 2;
840
+ ({ x: x2, barXPosition } = this.getBarXForNumericXAxis({
841
+ x: x2,
842
+ barWidth,
843
+ realIndex,
844
+ j: j2
845
+ }));
547
846
  }
548
- const barXPosition = x2 + barWidth * this.visibleI;
549
847
  const center = barXPosition + barWidth / 2;
550
848
  const halfExtent = barWidth / 2;
551
849
  const density = this.getDensity(realIndex, j2);
@@ -574,7 +872,7 @@ class Violin extends BarBase {
574
872
  if (morphFrom) {
575
873
  pathFrom = morphFrom;
576
874
  } else if (w.globals.previousPaths.length > 0) {
577
- pathFrom = this.getPreviousPath(realIndex, j2, pathTo);
875
+ pathFrom = this._prevBody(realIndex, j2, pathTo);
578
876
  }
579
877
  if (pathFrom == null) {
580
878
  pathFrom = this.buildBodyPath({
@@ -613,7 +911,7 @@ class Violin extends BarBase {
613
911
  alongFn,
614
912
  vertical: true
615
913
  }),
616
- alongRepresentative: alongFn((_g = this.series[indexes.i][j2]) != null ? _g : 0)
914
+ alongRepresentative: alongFn((_g = w.seriesData.series[realIndex][j2]) != null ? _g : 0)
617
915
  };
618
916
  }
619
917
  /** @param {{indexes: any, y: any, yDivision: any, barHeight: any, zeroW: any}} opts */
@@ -621,7 +919,7 @@ class Violin extends BarBase {
621
919
  var _a, _b, _c, _d, _e, _f, _g;
622
920
  const w = this.w;
623
921
  const { realIndex, j: j2 } = indexes;
624
- const yRatio = this.invertedYRatio;
922
+ const yRatio = this.invertedYRatio * (this.isReversed ? -1 : 1);
625
923
  const barYPosition = y + barHeight * this.visibleI;
626
924
  const center = barYPosition + barHeight / 2;
627
925
  const halfExtent = barHeight / 2;
@@ -651,7 +949,7 @@ class Violin extends BarBase {
651
949
  if (morphFrom) {
652
950
  pathFrom = morphFrom;
653
951
  } else if (w.globals.previousPaths.length > 0) {
654
- pathFrom = this.getPreviousPath(realIndex, j2, pathTo);
952
+ pathFrom = this._prevBody(realIndex, j2, pathTo);
655
953
  }
656
954
  if (pathFrom == null) {
657
955
  pathFrom = this.buildBodyPath({
@@ -688,7 +986,7 @@ class Violin extends BarBase {
688
986
  alongFn,
689
987
  vertical: false
690
988
  }),
691
- alongRepresentative: alongFn((_g = this.series[indexes.i][j2]) != null ? _g : 0)
989
+ alongRepresentative: alongFn((_g = w.seriesData.series[realIndex][j2]) != null ? _g : 0)
692
990
  };
693
991
  }
694
992
  /**
@@ -779,6 +1077,23 @@ class Violin extends BarBase {
779
1077
  leftPts.reverse();
780
1078
  return this.smoothSegment(rightPts, vertical, false) + this.smoothSegment(leftPts, vertical, true) + "z";
781
1079
  }
1080
+ /**
1081
+ * The survivor's previous body when it can morph to `pathTo`, else null so
1082
+ * the violin regrows from its centreline (a changed density node count
1083
+ * cannot tween, and bar corner reconciliation does not apply here).
1084
+ *
1085
+ * @param {number} realIndex
1086
+ * @param {number} j
1087
+ * @param {string} pathTo
1088
+ * @returns {string | null}
1089
+ */
1090
+ _prevBody(realIndex, j2, pathTo) {
1091
+ var _a, _b;
1092
+ const d = (_b = (_a = this._prevKeyedPaths(realIndex)) == null ? void 0 : _a.get(
1093
+ datumKey(this.w, realIndex, j2)
1094
+ )) == null ? void 0 : _b.d;
1095
+ return d && Violin.pathCommandCount(d) === Violin.pathCommandCount(pathTo) ? d : null;
1096
+ }
782
1097
  /**
783
1098
  * Build the five-number box sub-paths for one category — the raincloud
784
1099
  * "umbrella", or a violin box overlay. Two sub-paths so each can carry its
@@ -796,7 +1111,7 @@ class Violin extends BarBase {
796
1111
  * @returns {{pathTo:string, pathFrom:string, filled:boolean}[] | null}
797
1112
  */
798
1113
  buildBoxSubPaths({ realIndex, j: j2, boxCenter, boxHalfPx, alongFn, vertical }) {
799
- var _a, _b;
1114
+ var _a, _b, _c;
800
1115
  const w = this.w;
801
1116
  if (!this.boxShown || boxHalfPx <= 0) return null;
802
1117
  const summary = (_a = w.violinData.seriesViolinSummary[realIndex]) == null ? void 0 : _a[j2];
@@ -821,22 +1136,17 @@ class Violin extends BarBase {
821
1136
  };
822
1137
  const full = build2(capHalf, boxHalfPx);
823
1138
  const collapsed = build2(0, 0);
824
- const fromFor = (pathTo, collapsedFrom) => {
825
- let pathFrom = null;
826
- if (w.globals.previousPaths.length > 0) {
827
- pathFrom = this.getPreviousPath(realIndex, j2, pathTo);
828
- }
829
- return pathFrom == null ? collapsedFrom : pathFrom;
830
- };
1139
+ const keyed = w.globals.previousPaths.length ? this._prevKeyedPaths(realIndex) : null;
1140
+ const prevBox = ((_c = keyed == null ? void 0 : keyed.get(datumKey(w, realIndex, j2))) == null ? void 0 : _c.box) || [];
831
1141
  return [
832
1142
  {
833
1143
  pathTo: full.whiskers,
834
- pathFrom: fromFor(full.whiskers, collapsed.whiskers),
1144
+ pathFrom: prevBox[0] || collapsed.whiskers,
835
1145
  filled: false
836
1146
  },
837
1147
  {
838
1148
  pathTo: full.box,
839
- pathFrom: fromFor(full.box, collapsed.box),
1149
+ pathFrom: prevBox[1] || collapsed.box,
840
1150
  filled: true
841
1151
  }
842
1152
  ];
@@ -912,8 +1222,11 @@ class Violin extends BarBase {
912
1222
  const scatterCenter = offsetLane ? rainCenter : this.cloudSign !== 0 ? cloudBase : center;
913
1223
  const scatterHalf = offsetLane ? rainHalfPx : this.cloudSign !== 0 ? cloudMaxPx : halfExtent;
914
1224
  return buildJitterGroups({
915
- w: this.w,
916
1225
  points: (_a = this.w.violinData.seriesViolinPoints[realIndex]) == null ? void 0 : _a[j2],
1226
+ extent: (
1227
+ /** @type {number[]} */
1228
+ this.jx
1229
+ ),
917
1230
  seedA: realIndex,
918
1231
  seedB: j2,
919
1232
  center: scatterCenter,
@@ -1707,10 +2020,6 @@ function getUnitMark(name) {
1707
2020
  if (!name) return null;
1708
2021
  return getMarks()[name] || null;
1709
2022
  }
1710
- const Environment = ApexCharts.__apex_Environment_Environment;
1711
- const BrowserAPIs = ApexCharts.__apex_BrowserAPIs_BrowserAPIs;
1712
- const Animations = ApexCharts.__apex_Animations;
1713
- const prefersReducedMotion = ApexCharts.__apex_Animations_prefersReducedMotion;
1714
2023
  function drawOuterLabel(w, spec) {
1715
2024
  const {
1716
2025
  lines,
@@ -1813,6 +2122,15 @@ function spaceOutLabels(items, minGap, maxY, minY) {
1813
2122
  }
1814
2123
  }
1815
2124
  const GOLDEN_ANGLE = Math.PI * (3 - Math.sqrt(5));
2125
+ const uniqueId = (seen, id) => {
2126
+ const n2 = (seen.get(id) || 0) + 1;
2127
+ seen.set(id, n2);
2128
+ return n2 > 1 ? id + "#" + n2 : id;
2129
+ };
2130
+ const toNum = (v) => {
2131
+ if (typeof v === "string") v = parseFloat(v);
2132
+ return typeof v === "number" && isFinite(v) ? v : null;
2133
+ };
1816
2134
  function easeOutCubic(t2) {
1817
2135
  return 1 - Math.pow(1 - t2, 3);
1818
2136
  }
@@ -1858,6 +2176,9 @@ class Unit {
1858
2176
  const w = this.w;
1859
2177
  const graphics = new Graphics(w, this.ctx);
1860
2178
  const ret = graphics.group({ class: "apexcharts-unit" });
2179
+ BrowserAPIs.cancelAnimationFrame(w.globals.unitGatherRAF || 0);
2180
+ BrowserAPIs.cancelAnimationFrame(w.globals.unitExitRAF || 0);
2181
+ w.globals.unitGatherRAF = w.globals.unitExitRAF = null;
1861
2182
  if (w.globals.noData || !Array.isArray(series) || series.length === 0) {
1862
2183
  return ret;
1863
2184
  }
@@ -1867,15 +2188,16 @@ class Unit {
1867
2188
  const flow = transition === "flow";
1868
2189
  const identity = transition === "identity";
1869
2190
  const unitValue = opts.unitValue > 0 ? opts.unitValue : 1;
2191
+ const gridSplit = layout === "grid" && !!(opts.grid && opts.grid.split);
1870
2192
  let counts = series.map((v) => {
1871
2193
  const n2 = Math.abs(Utils.parseNumber(v)) / unitValue;
1872
- return n2 > 0 ? Math.max(1, Math.round(n2)) : 0;
2194
+ return gridSplit ? n2 : n2 > 0 ? Math.max(1, Math.round(n2)) : 0;
1873
2195
  });
1874
- counts = this._applyMaxUnits(counts, opts.maxUnits);
2196
+ if (!gridSplit && layout !== "scatter") {
2197
+ counts = this._applyMaxUnits(counts, opts.maxUnits);
2198
+ }
1875
2199
  const total = counts.reduce((a2, b) => a2 + b, 0);
1876
2200
  const clusters = layout === "packed" ? this._layoutPacked(counts, opts) : layout === "columns" ? this._layoutColumns(counts, opts) : layout === "grid" ? this._layoutGrid(counts, opts) : layout === "scatter" ? this._layoutScatter(opts) : layout === "arc" ? this._layoutArc(counts, opts) : layout === "custom" ? this._layoutCustom(counts, opts) : this._layoutGrouped(counts, opts);
1877
- const gridSplit = layout === "grid" && !!(opts.grid && opts.grid.split);
1878
- if (gridSplit) this._drawGridTrack(ret, graphics, opts);
1879
2201
  if (layout === "scatter") this._drawScatterAxes(ret, graphics);
1880
2202
  const dotR = this._lastDotR;
1881
2203
  const animate = this._shouldAnimate();
@@ -1906,7 +2228,49 @@ class Unit {
1906
2228
  const unitData = w.seriesData.unitData || [];
1907
2229
  const sizeStats = this._bubbleStats(unitData, opts, dotR);
1908
2230
  let gIndex = 0;
1909
- clusters.forEach((cluster) => {
2231
+ const seen = /* @__PURE__ */ new Map();
2232
+ const track = gridSplit && this._gridTrack && this._gridTrack.cells || [];
2233
+ const trackG = graphics.group({ class: "apexcharts-unit-track" });
2234
+ if (track.length) ret.add(trackG);
2235
+ const trackFill = opts.grid && opts.grid.trackColor || "rgba(128,128,128,0.14)";
2236
+ const trackSpec = this._baseSpec({ shape: opts.shape === "square" && "square" }, dotR);
2237
+ const perTile = track.length / Math.max(1, clusters.length);
2238
+ const live = this.ctx && this.ctx._unitSprings;
2239
+ const glide = (node, spec, x2, y, key, r2, at, pair) => {
2240
+ const from = prev && prev.get(key);
2241
+ const s2 = live && live.get(key);
2242
+ const still = from && from.x === x2 && from.y === y && from.r === r2 && (!s2 || s2.x.value === x2 && s2.y.value === y);
2243
+ nextPrev.set(key, { x: x2, y, fill: trackFill, r: r2, spec });
2244
+ if (prev && animate && !pieceTakeover && !still) {
2245
+ const cx0 = from ? from.x : x2;
2246
+ const cy0 = from ? from.y : y;
2247
+ node.style.opacity = from ? "1" : "0";
2248
+ this._place(node, spec, cx0, cy0);
2249
+ animDots.splice(at, 0, {
2250
+ node,
2251
+ spec,
2252
+ x: x2,
2253
+ y,
2254
+ cx0,
2255
+ cy0,
2256
+ key,
2257
+ r0: from && from.r != null ? from.r : r2,
2258
+ r1: r2,
2259
+ delay: 0,
2260
+ isEnter: !from,
2261
+ pair
2262
+ });
2263
+ } else {
2264
+ this._place(node, spec, x2, y);
2265
+ }
2266
+ };
2267
+ const ride2 = (k2, pair) => {
2268
+ const el = this._drawDot(graphics, opts, dotR, trackFill, -1, 0, trackSpec);
2269
+ el.node.classList.add("apexcharts-unit-track-cell");
2270
+ trackG.add(el);
2271
+ glide(el.node, trackSpec, track[k2].x, track[k2].y, "trk:" + k2, dotR, animDots.length, pair);
2272
+ };
2273
+ clusters.forEach((cluster, ci) => {
1910
2274
  const color = w.globals.colors[cluster.i] || w.globals.colors[0] || "#008FFB";
1911
2275
  const elSeries = graphics.group({
1912
2276
  class: "apexcharts-series",
@@ -1918,7 +2282,9 @@ class Unit {
1918
2282
  });
1919
2283
  const burstCount = cluster.dots.length;
1920
2284
  const catData = unitData[cluster.i];
2285
+ const at = animDots.length;
1921
2286
  cluster.dots.forEach((d, jj) => {
2287
+ if (track.length) ride2(ci * perTile + jj, true);
1922
2288
  const j2 = d.j != null ? d.j : jj;
1923
2289
  const datum = catData ? catData[j2] : void 0;
1924
2290
  const dotFill = datum && typeof datum === "object" && datum.fillColor ? datum.fillColor : color;
@@ -1929,7 +2295,7 @@ class Unit {
1929
2295
  let key;
1930
2296
  if (identity) {
1931
2297
  const id = datum && typeof datum === "object" ? datum.id != null ? datum.id : datum.name : void 0;
1932
- key = id != null ? `id:${id}` : `g:${gIndex}`;
2298
+ key = id != null ? `id:${uniqueId(seen, String(id))}` : `g:${gIndex}`;
1933
2299
  } else if (flow) {
1934
2300
  key = String(gIndex);
1935
2301
  } else if (d.slot != null) {
@@ -1949,8 +2315,9 @@ class Unit {
1949
2315
  const anchor = from || (morphActive ? morph.getInitialSlotFor(cluster.i, j2, burstCount) : null);
1950
2316
  const enter = opts.gather && opts.gather.enter || "burst";
1951
2317
  const inPlace = gridSplit || enter === "fade" || enter === "rise";
1952
- const cx0 = anchor ? anchor.x : inPlace ? d.x : cluster.cx;
1953
- const cy0 = anchor ? anchor.y : enter === "rise" && !gridSplit ? d.y + 14 : inPlace ? d.y : cluster.cy;
2318
+ const start = anchor || gridSplit && prev && prev.get("trk:" + d.slot);
2319
+ const cx0 = start ? start.x : inPlace ? d.x : cluster.cx;
2320
+ const cy0 = start ? start.y : enter === "rise" && !gridSplit ? d.y + 14 : inPlace ? d.y : cluster.cy;
1954
2321
  el.node.style.opacity = anchor ? "1" : "0";
1955
2322
  this._place(el.node, spec, cx0, cy0);
1956
2323
  animDots.push({
@@ -1980,9 +2347,16 @@ class Unit {
1980
2347
  this._place(el.node, spec, d.x, d.y);
1981
2348
  }
1982
2349
  });
2350
+ for (let k2 = cluster.dots.length; k2 < perTile; k2++) ride2(ci * perTile + k2, false);
1983
2351
  if ((layout === "grouped" || layout === "columns" || gridSplit) && opts.clusterLabels && opts.clusterLabels.show && counts[cluster.i] > 0) {
1984
2352
  const labelTotal = gridSplit ? this._gridDenom : total;
1985
- this._drawClusterLabel(elSeries, cluster, counts[cluster.i], labelTotal, opts, color);
2353
+ const t2 = this._drawClusterLabel(elSeries, cluster, counts[cluster.i], labelTotal, opts, color);
2354
+ if (t2 && gridSplit) {
2355
+ const spec = { pk: PK_CORNER, hx: 0, hy: 0, r: 0 };
2356
+ const lx = +(t2.getAttribute("x") || 0);
2357
+ const ly = +(t2.getAttribute("y") || 0);
2358
+ glide(t2, spec, lx, ly, "lbl:" + cluster.i, 0, at, animDots.length > at);
2359
+ }
1986
2360
  }
1987
2361
  ret.add(elSeries);
1988
2362
  });
@@ -2017,9 +2391,13 @@ class Unit {
2017
2391
  const total = counts.reduce((a2, b) => a2 + b, 0);
2018
2392
  if (!maxUnits || maxUnits <= 0 || total <= maxUnits) return counts;
2019
2393
  const scale = maxUnits / total;
2020
- console.warn(
2021
- `[ApexCharts] unit chart: ${total} dots exceeds maxUnits (${maxUnits}); counts were scaled down proportionally. Raise plotOptions.unit.maxUnits or use plotOptions.unit.unitValue to represent more units per dot.`
2022
- );
2394
+ const ctx = this.ctx || {};
2395
+ if (!ctx._unitCapWarned) {
2396
+ ctx._unitCapWarned = true;
2397
+ console.warn(
2398
+ `[ApexCharts] unit chart: ${total} dots exceeds maxUnits (${maxUnits}); counts were scaled down proportionally. Raise plotOptions.unit.maxUnits or use plotOptions.unit.unitValue to represent more units per dot.`
2399
+ );
2400
+ }
2023
2401
  return counts.map((c) => c > 0 ? Math.max(1, Math.round(c * scale)) : 0);
2024
2402
  }
2025
2403
  /**
@@ -2129,7 +2507,8 @@ class Unit {
2129
2507
  *
2130
2508
  * `id` is the datum's own id/name where the per-unit object form supplies
2131
2509
  * one, so a provider can address a specific unit ("Texas", "employee 41")
2132
- * rather than a positional slot. It falls back to `"<category>:<index>"`.
2510
+ * rather than a positional slot. It falls back to `"<category>:<index>"`, and
2511
+ * a repeated one is suffixed (`"Alex#2"`).
2133
2512
  *
2134
2513
  * @param {number[]} counts
2135
2514
  * @param {number} dotR the radius the engine would use, so a provider that
@@ -2141,13 +2520,17 @@ class Unit {
2141
2520
  const unitData = w.seriesData.unitData || [];
2142
2521
  const names = w.seriesData.seriesNames || [];
2143
2522
  const objects = [];
2523
+ const seen = /* @__PURE__ */ new Map();
2144
2524
  let index = 0;
2145
2525
  counts.forEach((n2, i2) => {
2146
2526
  var _a;
2147
2527
  const catData = unitData[i2];
2148
2528
  for (let j2 = 0; j2 < n2; j2++) {
2149
2529
  const datum = catData ? catData[j2] : void 0;
2150
- const id = datum && typeof datum === "object" && (datum.id != null || datum.name != null) ? String(datum.id != null ? datum.id : datum.name) : `${i2}:${j2}`;
2530
+ const id = uniqueId(
2531
+ seen,
2532
+ datum && typeof datum === "object" && (datum.id != null || datum.name != null) ? String(datum.id != null ? datum.id : datum.name) : `${i2}:${j2}`
2533
+ );
2151
2534
  objects.push({
2152
2535
  id,
2153
2536
  index,
@@ -2331,11 +2714,18 @@ class Unit {
2331
2714
  const pad = Math.min(gw, gh) * 0.04;
2332
2715
  const boxW = Math.max(1e-6, b.maxX - b.minX);
2333
2716
  const boxH = Math.max(1e-6, b.maxY - b.minY);
2334
- const r1 = Math.max(4, Math.min((gw - 2 * pad) / boxW, (gh - 2 * pad) / boxH));
2335
- const r0 = r1 * innerRatio;
2717
+ const fit = (inset) => Math.max(4, Math.min((gw - 2 * pad - inset) / boxW, (gh - 2 * pad - inset) / boxH));
2718
+ const seat = (r2) => fit(2 * this._arcAllocate(total, r2 * innerRatio, r2, span, opts).dotR);
2719
+ let hi = fit(0);
2720
+ let r1 = seat(hi);
2721
+ for (let k2 = 0; k2 < 6; k2++) {
2722
+ const m = (r1 + hi) / 2;
2723
+ if (m <= seat(m)) r1 = m;
2724
+ else hi = m;
2725
+ }
2336
2726
  const cx = gw / 2 - (b.minX + b.maxX) / 2 * r1;
2337
2727
  const cy = gh / 2 - (b.minY + b.maxY) / 2 * r1;
2338
- const alloc = this._arcAllocate(total, r0, r1, span, opts);
2728
+ const alloc = this._arcAllocate(total, r1 * innerRatio, r1, span, opts);
2339
2729
  this._lastDotR = alloc.dotR;
2340
2730
  const seats = [];
2341
2731
  for (let r2 = 0; r2 < alloc.R; r2++) {
@@ -2619,7 +3009,7 @@ class Unit {
2619
3009
  * value over a denominator (`grid.max`, else the largest count so the leader
2620
3010
  * fills its tile and every other tile stays proportionally full - no empty
2621
3011
  * tiles for arbitrary data). The unfilled cells are drawn as a faint TRACK
2622
- * backdrop (see _drawGridTrack) so each tile reads as a part-to-whole "of N".
3012
+ * backdrop (drawn by draw()) so each tile reads as a part-to-whole "of N".
2623
3013
  * Only VISIBLE (non-zero) categories claim a tile, so a legend hide drops the
2624
3014
  * tile and the rest re-flow. Each filled cell is keyed by a physical
2625
3015
  * `tile*cells + localCell` slot, so a value change grows/shrinks a tile's fill
@@ -2637,7 +3027,7 @@ class Unit {
2637
3027
  const rowsPerTile = Math.max(1, Math.ceil(cellsPerTile / cols));
2638
3028
  const visible = counts.map((_2, i2) => i2).filter((i2) => counts[i2] > 0);
2639
3029
  const K2 = Math.max(1, visible.length);
2640
- const denom = gcfg.max > 0 ? gcfg.max : Math.max(1, ...counts);
3030
+ const denom = gcfg.max > 0 ? gcfg.max : Math.max(...counts) || 1;
2641
3031
  const tileCols = Math.max(
2642
3032
  1,
2643
3033
  Math.round(gcfg.tileColumns > 0 ? gcfg.tileColumns : Math.ceil(Math.sqrt(K2)))
@@ -2702,40 +3092,6 @@ class Unit {
2702
3092
  this._gridTrack = { cells: track };
2703
3093
  return clusters;
2704
3094
  }
2705
- /**
2706
- * Draw the faint "track" backdrop for the small-multiple grid: every cell of
2707
- * every tile's full lattice, so the filled (coloured) cells drawn on top read
2708
- * as a fraction of the whole. Static (redrawn each render, never animated);
2709
- * painted BEHIND the series groups. `grid.trackColor` overrides the default
2710
- * theme-neutral grey.
2711
- * @param {any} ret @param {Graphics} graphics @param {any} opts
2712
- */
2713
- _drawGridTrack(ret, graphics, opts) {
2714
- const track = this._gridTrack;
2715
- if (!track || !track.cells || !track.cells.length) return;
2716
- const r2 = this._lastDotR;
2717
- const gcfg = opts.grid || {};
2718
- const trackColor = gcfg.trackColor || "rgba(128,128,128,0.14)";
2719
- const g = graphics.group({ class: "apexcharts-unit-track" });
2720
- track.cells.forEach((c) => {
2721
- let el;
2722
- if (opts.shape === "square") {
2723
- const side = r2 * 2;
2724
- el = graphics.drawRect(0, 0, side, side, opts.borderRadius || 0, trackColor, 1, 0, "none");
2725
- el.node.setAttribute("fill", trackColor);
2726
- el.node.setAttribute("x", String(c.x - r2));
2727
- el.node.setAttribute("y", String(c.y - r2));
2728
- } else {
2729
- el = graphics.drawCircle(r2, { fill: trackColor, "stroke-width": 0, stroke: "none" });
2730
- el.node.setAttribute("fill", trackColor);
2731
- el.node.setAttribute("cx", String(c.x));
2732
- el.node.setAttribute("cy", String(c.y));
2733
- }
2734
- el.node.classList.add("apexcharts-unit-track-cell");
2735
- g.add(el);
2736
- });
2737
- ret.add(g);
2738
- }
2739
3095
  /**
2740
3096
  * Scatter / beeswarm layout: position every unit on a real numeric X value
2741
3097
  * axis by its own value (`_unitValueOf`), laned by category on Y. Within a
@@ -2750,11 +3106,14 @@ class Unit {
2750
3106
  _layoutScatter(opts) {
2751
3107
  const w = this.w;
2752
3108
  const scfg = opts.scatter || {};
2753
- if (scfg.y === "value") return this._layoutScatter2D(opts);
2754
- if (scfg.orientation === "vertical") return this._layoutScatterVertical(opts);
3109
+ const unitData = w.seriesData.unitData || [];
3110
+ const lens = unitData.map((c) => c ? c.length : 0);
3111
+ const caps = this._applyMaxUnits(lens, opts.maxUnits);
3112
+ const keep = (ci, j2) => Math.floor((j2 + 1) * caps[ci] / lens[ci]) > Math.floor(j2 * caps[ci] / lens[ci]);
3113
+ if (scfg.y === "value") return this._layoutScatter2D(opts, keep);
3114
+ if (scfg.orientation === "vertical") return this._layoutScatterVertical(opts, keep);
2755
3115
  const gw = w.layout.gridWidth;
2756
3116
  const gh = w.layout.gridHeight;
2757
- const unitData = w.seriesData.unitData || [];
2758
3117
  const names = w.seriesData.seriesNames || [];
2759
3118
  const valueOf2 = (d) => this._unitValueOf(d);
2760
3119
  const sizeStats = this._scatterSizeStats(scfg, unitData);
@@ -2779,11 +3138,13 @@ class Unit {
2779
3138
  vmax = 1;
2780
3139
  }
2781
3140
  const tickAmount = Math.max(2, Math.round(scfg.tickAmount > 0 ? scfg.tickAmount : 5));
2782
- const domain = this._scatterValueDomain(scfg, vmin, vmax, tickAmount);
3141
+ const domain = this._scatterValueDomain(scfg.xMin, scfg.xMax, vmin, vmax, tickAmount);
2783
3142
  const xMin = domain.min;
2784
3143
  const xMax = domain.max;
2785
3144
  const xSpan = xMax - xMin || 1;
2786
- const laneW = scfg.laneLabelWidth != null ? Math.max(0, scfg.laneLabelWidth) : Kv > 1 ? 92 : 8;
3145
+ const font = { fontFamily: w.config.chart.fontFamily, fontWeight: 600 };
3146
+ const laneName = (i2) => names[i2] || `series-${i2 + 1}`;
3147
+ const laneW = scfg.laneLabelWidth != null ? Math.max(0, scfg.laneLabelWidth) : Kv > 1 ? Math.min(gw / 3, measureLabelWidth(w, visible.map(laneName), font) + 14) : 8;
2787
3148
  const bottomGutter = 30 + (scfg.xTitle ? 20 : 0);
2788
3149
  const plotL = laneW;
2789
3150
  const plotR = gw - 8;
@@ -2817,19 +3178,24 @@ class Unit {
2817
3178
  const maxR = sizeStats ? sizeStats.rMax : r2;
2818
3179
  visible.forEach((ci, slot) => {
2819
3180
  const cy = laneCy(slot);
2820
- lanes2.push({ i: ci, cy, name: names[ci] || `series-${ci + 1}` });
2821
- const cat = unitData[ci] || [];
2822
- const pts = cat.map((d, j2) => {
3181
+ let name = laneName(ci);
3182
+ const wid = laneW > 12 ? measureLabelWidth(w, [name], font) : 0;
3183
+ if (wid > laneW - 14 && wid) {
3184
+ name = name.slice(0, Math.max(1, Math.floor(name.length * (laneW - 14) / wid) - 1)) + "…";
3185
+ }
3186
+ lanes2.push({ i: ci, cy, name });
3187
+ const pts = [];
3188
+ (unitData[ci] || []).forEach((d, j2) => {
2823
3189
  const v = valueOf2(d);
2824
- const p = { j: j2, px: plotX(isNum(v) ? v : xMin), y: cy };
3190
+ if (!isNum(v) || !keep(ci, j2)) return;
3191
+ const p = { j: j2, px: plotX(v), y: cy };
2825
3192
  if (sizeStats) p.r = this._scatterRadius(d, sizeStats, r2);
2826
- return p;
3193
+ pts.push(p);
2827
3194
  });
2828
3195
  if (jitter) {
2829
3196
  const halfLane = Math.max(maxR, laneH / 2 - maxR);
2830
- pts.forEach((p, k2) => {
2831
- const t2 = (k2 * 9301 + 49297) % 233280 / 233280;
2832
- p.y = cy + (t2 * 2 - 1) * halfLane;
3197
+ pts.forEach((p) => {
3198
+ p.y = cy + (hash01(ci * 7919 + p.j) * 2 - 1) * halfLane;
2833
3199
  });
2834
3200
  } else {
2835
3201
  this._beeswarm(pts, cy, r2, step, maxR);
@@ -2839,7 +3205,7 @@ class Unit {
2839
3205
  cx: (plotL + plotR) / 2,
2840
3206
  cy,
2841
3207
  outerR: laneH / 2,
2842
- dots: pts.map((p) => ({ x: p.px, y: p.y, r: p.r }))
3208
+ dots: pts.map((p) => ({ x: p.px, y: p.y, r: p.r, j: p.j }))
2843
3209
  });
2844
3210
  });
2845
3211
  const ticks = domain.ticks;
@@ -2866,9 +3232,9 @@ class Unit {
2866
3232
  * dots horizontally off each column's centre line. The value-axis config keys
2867
3233
  * (`xMin`/`xMax`/`xTitle`/`xFormatter`/`tickAmount`) still describe the value
2868
3234
  * axis (now Y), so flipping `orientation` keeps the same value settings.
2869
- * @param {any} opts
3235
+ * @param {any} opts @param {(ci:number, j:number) => boolean} keep
2870
3236
  */
2871
- _layoutScatterVertical(opts) {
3237
+ _layoutScatterVertical(opts, keep) {
2872
3238
  const w = this.w;
2873
3239
  const scfg = opts.scatter || {};
2874
3240
  const gw = w.layout.gridWidth;
@@ -2898,7 +3264,7 @@ class Unit {
2898
3264
  vmax = 1;
2899
3265
  }
2900
3266
  const tickAmount = Math.max(2, Math.round(scfg.tickAmount > 0 ? scfg.tickAmount : 5));
2901
- const domain = this._scatterValueDomain(scfg, vmin, vmax, tickAmount);
3267
+ const domain = this._scatterValueDomain(scfg.xMin, scfg.xMax, vmin, vmax, tickAmount);
2902
3268
  const vMin = domain.min;
2903
3269
  const vMax = domain.max;
2904
3270
  const vSpan = vMax - vMin || 1;
@@ -2937,18 +3303,18 @@ class Unit {
2937
3303
  visible.forEach((ci, slot) => {
2938
3304
  const cx = laneCx(slot);
2939
3305
  lanes2.push({ i: ci, cx, name: names[ci] || `series-${ci + 1}` });
2940
- const cat = unitData[ci] || [];
2941
- const pts = cat.map((d, j2) => {
3306
+ const pts = [];
3307
+ (unitData[ci] || []).forEach((d, j2) => {
2942
3308
  const v = valueOf2(d);
2943
- const p = { j: j2, py: plotY(isNum(v) ? v : vMin), x: cx };
3309
+ if (!isNum(v) || !keep(ci, j2)) return;
3310
+ const p = { j: j2, py: plotY(v), x: cx };
2944
3311
  if (sizeStats) p.r = this._scatterRadius(d, sizeStats, r2);
2945
- return p;
3312
+ pts.push(p);
2946
3313
  });
2947
3314
  if (jitter) {
2948
3315
  const halfLane = Math.max(maxR, laneW / 2 - maxR);
2949
- pts.forEach((p, k2) => {
2950
- const t2 = (k2 * 9301 + 49297) % 233280 / 233280;
2951
- p.x = cx + (t2 * 2 - 1) * halfLane;
3316
+ pts.forEach((p) => {
3317
+ p.x = cx + (hash01(ci * 7919 + p.j) * 2 - 1) * halfLane;
2952
3318
  });
2953
3319
  } else {
2954
3320
  this._beeswarm(pts, cx, r2, step, maxR, true);
@@ -2958,7 +3324,7 @@ class Unit {
2958
3324
  cx,
2959
3325
  cy: (plotT + plotB) / 2,
2960
3326
  outerR: laneW / 2,
2961
- dots: pts.map((p) => ({ x: p.x, y: p.py, r: p.r }))
3327
+ dots: pts.map((p) => ({ x: p.x, y: p.py, r: p.r, j: p.j }))
2962
3328
  });
2963
3329
  });
2964
3330
  const ticks = domain.ticks;
@@ -2987,17 +3353,17 @@ class Unit {
2987
3353
  * per category). With `scatter.sizeRange` set, each dot is a BUBBLE scaled (by
2988
3354
  * area) from its `sizeField` (default 'z'). Needs the object form with numeric
2989
3355
  * `x` + `y`.
2990
- * @param {any} opts
3356
+ * @param {any} opts @param {(ci:number, j:number) => boolean} keep
2991
3357
  */
2992
- _layoutScatter2D(opts) {
3358
+ _layoutScatter2D(opts, keep) {
2993
3359
  const w = this.w;
2994
3360
  const gw = w.layout.gridWidth;
2995
3361
  const gh = w.layout.gridHeight;
2996
3362
  const scfg = opts.scatter || {};
2997
3363
  const unitData = w.seriesData.unitData || [];
2998
- const isNum = (v) => typeof v === "number" && isFinite(v);
2999
- const xOf = (d) => d && typeof d === "object" ? d.x : null;
3000
- const yOf = (d) => d && typeof d === "object" ? d.y != null ? d.y : d.value : null;
3364
+ const isNum = (v) => v != null;
3365
+ const xOf = (d) => d && typeof d === "object" ? toNum(d.x) : null;
3366
+ const yOf = (d) => d && typeof d === "object" ? toNum(d.y != null ? d.y : d.value) : null;
3001
3367
  const visible = unitData.map((_2, i2) => i2).filter(
3002
3368
  (i2) => (unitData[i2] || []).some((d) => isNum(xOf(d)) && isNum(yOf(d)))
3003
3369
  );
@@ -3023,22 +3389,24 @@ class Unit {
3023
3389
  ymn = 0;
3024
3390
  ymx = 1;
3025
3391
  }
3026
- const xTicksN = Math.max(2, Math.round(scfg.tickAmount > 0 ? scfg.tickAmount : 5));
3027
- const yTicksN = Math.max(2, Math.round(scfg.yTickAmount > 0 ? scfg.yTickAmount : 5));
3028
- const nx = this._niceScale(
3029
- scfg.xMin != null ? scfg.xMin : xmn,
3030
- scfg.xMax != null ? scfg.xMax : xmx,
3031
- xTicksN
3392
+ const dx = this._scatterValueDomain(
3393
+ scfg.xMin,
3394
+ scfg.xMax,
3395
+ xmn,
3396
+ xmx,
3397
+ Math.max(2, Math.round(scfg.tickAmount > 0 ? scfg.tickAmount : 5))
3032
3398
  );
3033
- const ny = this._niceScale(
3034
- scfg.yMin != null ? scfg.yMin : ymn,
3035
- scfg.yMax != null ? scfg.yMax : ymx,
3036
- yTicksN
3399
+ const dy = this._scatterValueDomain(
3400
+ scfg.yMin,
3401
+ scfg.yMax,
3402
+ ymn,
3403
+ ymx,
3404
+ Math.max(2, Math.round(scfg.yTickAmount > 0 ? scfg.yTickAmount : 5))
3037
3405
  );
3038
- const xMin = scfg.xMin != null ? scfg.xMin : nx.min;
3039
- const xMax = scfg.xMax != null ? scfg.xMax : nx.max;
3040
- const yMin = scfg.yMin != null ? scfg.yMin : ny.min;
3041
- const yMax = scfg.yMax != null ? scfg.yMax : ny.max;
3406
+ const xMin = dx.min;
3407
+ const xMax = dx.max;
3408
+ const yMin = dy.min;
3409
+ const yMax = dy.max;
3042
3410
  const xSpan = xMax - xMin || 1;
3043
3411
  const ySpan = yMax - yMin || 1;
3044
3412
  const leftGutter = 46 + (scfg.yTitle ? 18 : 0);
@@ -3056,15 +3424,17 @@ class Unit {
3056
3424
  this._lastDotR = baseR;
3057
3425
  const clusters = [];
3058
3426
  visible.forEach((ci) => {
3059
- const cat = unitData[ci] || [];
3060
- const dots = cat.map((d) => {
3427
+ const dots = [];
3428
+ (unitData[ci] || []).forEach((d, j2) => {
3061
3429
  const x2 = xOf(d);
3062
3430
  const y = yOf(d);
3063
- return {
3064
- x: plotX(isNum(x2) ? x2 : xMin),
3065
- y: plotY(isNum(y) ? y : yMin),
3066
- r: sizeStats ? this._scatterRadius(d, sizeStats, baseR) : void 0
3067
- };
3431
+ if (x2 == null || y == null || !keep(ci, j2)) return;
3432
+ dots.push({
3433
+ x: plotX(x2),
3434
+ y: plotY(y),
3435
+ r: sizeStats ? this._scatterRadius(d, sizeStats, baseR) : void 0,
3436
+ j: j2
3437
+ });
3068
3438
  });
3069
3439
  clusters.push({
3070
3440
  i: ci,
@@ -3074,18 +3444,6 @@ class Unit {
3074
3444
  dots
3075
3445
  });
3076
3446
  });
3077
- const mkTicks = (lo, hi, span, spacing, pinned, n2) => {
3078
- const out = [];
3079
- if (pinned) {
3080
- for (let k2 = 0; k2 < n2; k2++) out.push(lo + span * k2 / (n2 - 1));
3081
- } else {
3082
- const sp = spacing || span / Math.max(1, n2 - 1);
3083
- for (let v = lo; v <= hi + sp * 0.5; v += sp) {
3084
- out.push(Math.abs(v) < sp * 1e-9 ? 0 : v);
3085
- }
3086
- }
3087
- return out;
3088
- };
3089
3447
  this._scatterAxis = {
3090
3448
  mode: "2d",
3091
3449
  plotL,
@@ -3094,22 +3452,8 @@ class Unit {
3094
3452
  plotB,
3095
3453
  plotX,
3096
3454
  plotY,
3097
- xTicks: mkTicks(
3098
- xMin,
3099
- xMax,
3100
- xSpan,
3101
- nx.spacing,
3102
- scfg.xMin != null || scfg.xMax != null,
3103
- xTicksN
3104
- ),
3105
- yTicks: mkTicks(
3106
- yMin,
3107
- yMax,
3108
- ySpan,
3109
- ny.spacing,
3110
- scfg.yMin != null || scfg.yMax != null,
3111
- yTicksN
3112
- ),
3455
+ xTicks: dx.ticks,
3456
+ yTicks: dy.ticks,
3113
3457
  xTitle: scfg.xTitle,
3114
3458
  yTitle: scfg.yTitle,
3115
3459
  xFormatter: typeof scfg.xFormatter === "function" ? scfg.xFormatter : null,
@@ -3216,32 +3560,43 @@ class Unit {
3216
3560
  });
3217
3561
  }
3218
3562
  /**
3219
- * Value-axis domain + ticks for a 1D beeswarm. The domain ALWAYS contains
3563
+ * Value-axis domain + ticks for a scatter axis. The domain ALWAYS contains
3220
3564
  * every datum: a swarm that clips a dot outside the plot box is a bug, so an
3221
- * explicit `xMin`/`xMax` only FRAMES the axis and is extended by whole
3565
+ * explicit `lo`/`hi` only FRAMES the axis and is extended by whole
3222
3566
  * tick-steps whenever the data would otherwise overflow. Orientation-agnostic:
3223
3567
  * the same value axis is X for a horizontal swarm and Y for a vertical one.
3224
- * @param {any} scfg scatter config
3568
+ * @param {number|undefined} lo pinned minimum @param {number|undefined} hi
3569
+ * pinned maximum
3225
3570
  * @param {number} vmin data minimum @param {number} vmax data maximum
3226
3571
  * @param {number} tickAmount desired tick count
3227
3572
  * @returns {{ min:number, max:number, ticks:number[] }}
3228
3573
  */
3229
- _scatterValueDomain(scfg, vmin, vmax, tickAmount) {
3574
+ _scatterValueDomain(lo, hi, vmin, vmax, tickAmount) {
3230
3575
  const buildTicks = (min, max, spacing2) => {
3231
3576
  const ticks = [];
3232
- for (let v = min; v <= max + spacing2 * 0.5; v += spacing2) {
3577
+ for (let k2 = 0, v = min; v <= max + spacing2 * 0.5; v = min + ++k2 * spacing2) {
3233
3578
  ticks.push(Math.abs(v) < spacing2 * 1e-9 ? 0 : v);
3234
3579
  }
3235
3580
  return ticks;
3236
3581
  };
3237
- if (scfg.xMin != null || scfg.xMax != null) {
3238
- let min = scfg.xMin != null ? scfg.xMin : vmin;
3239
- let max = scfg.xMax != null ? scfg.xMax : vmax;
3240
- if (!(max > min)) max = min + 1;
3241
- const spacing2 = (max - min) / Math.max(1, tickAmount - 1);
3582
+ if (lo != null || hi != null) {
3583
+ let min = (
3584
+ /** @type {number} */
3585
+ lo != null ? lo : hi
3586
+ );
3587
+ let max = (
3588
+ /** @type {number} */
3589
+ hi != null ? hi : lo
3590
+ );
3591
+ const spacing2 = max > min ? (max - min) / Math.max(1, tickAmount - 1) : this._niceScale(Math.min(min, vmin), Math.max(max, vmax), tickAmount).spacing;
3242
3592
  if (vmin < min) min -= Math.ceil((min - vmin) / spacing2) * spacing2;
3243
3593
  if (vmax > max) max += Math.ceil((vmax - max) / spacing2) * spacing2;
3244
- return { min, max, ticks: buildTicks(min, max, spacing2) };
3594
+ if (!(max > min)) max = min + spacing2;
3595
+ if ((max - min) / spacing2 <= 2 * tickAmount) {
3596
+ return { min, max, ticks: buildTicks(min, max, spacing2) };
3597
+ }
3598
+ vmin = min;
3599
+ vmax = max;
3245
3600
  }
3246
3601
  const nice = this._niceScale(vmin, vmax, tickAmount);
3247
3602
  const spacing = nice.spacing || (nice.max - nice.min) / Math.max(1, tickAmount - 1);
@@ -3332,13 +3687,13 @@ class Unit {
3332
3687
  ax.yTicks.forEach((v) => {
3333
3688
  const y = ax.plotY(v);
3334
3689
  if (ax.gridlines) line(ax.plotL, y, ax.plotR, y, gridColor);
3335
- const label2 = ax.yFormatter ? String(ax.yFormatter(v)) : this._formatTick(v);
3690
+ const label2 = ax.yFormatter ? String(ax.yFormatter(v)) : this._formatTick(v, ax.yTicks);
3336
3691
  text(label2, ax.plotL - 8, y, "end", labelColor, 11, 400, "apexcharts-unit-tick");
3337
3692
  });
3338
3693
  ax.xTicks.forEach((v) => {
3339
3694
  const x2 = ax.plotX(v);
3340
3695
  if (ax.gridlines) line(x2, ax.plotT, x2, ax.plotB, gridColor);
3341
- const label2 = ax.xFormatter ? String(ax.xFormatter(v)) : this._formatTick(v);
3696
+ const label2 = ax.xFormatter ? String(ax.xFormatter(v)) : this._formatTick(v, ax.xTicks);
3342
3697
  text(label2, x2, ax.plotB + 14, "middle", labelColor, 11, 400, "apexcharts-unit-tick");
3343
3698
  });
3344
3699
  line(ax.plotL, ax.plotB, ax.plotR, ax.plotB, axisColor);
@@ -3378,7 +3733,7 @@ class Unit {
3378
3733
  ax.ticks.forEach((v) => {
3379
3734
  const y = ax.plotY(v);
3380
3735
  if (ax.gridlines) line(ax.plotL, y, ax.plotR, y, gridColor);
3381
- const label2 = ax.formatter ? String(ax.formatter(v)) : this._formatTick(v);
3736
+ const label2 = ax.formatter ? String(ax.formatter(v)) : this._formatTick(v, ax.ticks);
3382
3737
  text(label2, ax.plotL - 8, y, "end", labelColor, 11, 400, "apexcharts-unit-tick");
3383
3738
  });
3384
3739
  line(ax.plotL, ax.plotT, ax.plotL, ax.plotB, axisColor);
@@ -3408,7 +3763,7 @@ class Unit {
3408
3763
  ax.ticks.forEach((v, idx) => {
3409
3764
  const x2 = ax.plotX(v);
3410
3765
  if (ax.gridlines) line(x2, ax.plotT, x2, ax.plotB, gridColor);
3411
- const label2 = ax.formatter ? String(ax.formatter(v)) : this._formatTick(v);
3766
+ const label2 = ax.formatter ? String(ax.formatter(v)) : this._formatTick(v, ax.ticks);
3412
3767
  const anchor = idx === 0 ? "start" : idx === ax.ticks.length - 1 ? "end" : "middle";
3413
3768
  text(label2, x2, ax.plotB + 14, anchor, labelColor, 11, 400, "apexcharts-unit-tick");
3414
3769
  });
@@ -3434,17 +3789,19 @@ class Unit {
3434
3789
  ret.add(g);
3435
3790
  }
3436
3791
  /**
3437
- * Compact tick-value formatting: integers as-is, otherwise trimmed to a short
3438
- * decimal; large magnitudes get a k/M suffix.
3439
- * @param {number} v @returns {string}
3792
+ * Compact tick-value formatting: integers as-is, otherwise trimmed to enough
3793
+ * decimals to tell neighbouring ticks apart; large magnitudes get a k/M suffix.
3794
+ * @param {number} v @param {number[]} ticks the axis ticks (their step sets
3795
+ * the decimals) @returns {string}
3440
3796
  */
3441
- _formatTick(v) {
3797
+ _formatTick(v, ticks) {
3442
3798
  if (!isFinite(v)) return "";
3443
3799
  const a2 = Math.abs(v);
3444
3800
  if (a2 >= 1e6) return `${+(v / 1e6).toFixed(1)}M`;
3445
3801
  if (a2 >= 1e4) return `${+(v / 1e3).toFixed(1)}k`;
3446
3802
  if (Number.isInteger(v)) return String(v);
3447
- return String(+v.toFixed(2));
3803
+ const step = Math.abs(ticks[1] - ticks[0]) || 1;
3804
+ return String(+v.toFixed(Math.min(20, Math.max(2, 1 - Math.floor(Math.log10(step))))));
3448
3805
  }
3449
3806
  /**
3450
3807
  * Distribute `total` whole cells across `counts` in proportion to each value,
@@ -3509,17 +3866,12 @@ class Unit {
3509
3866
  return !!(sbv && sbv.enabled && opts.shape !== "image" && opts.shape !== "square");
3510
3867
  }
3511
3868
  /**
3512
- * This datum's numeric value for sizing / tooltip: the number itself, or an
3513
- * object's `value` / `y`. Null when there is no usable number.
3869
+ * This datum's numeric value for sizing / tooltip: the number (or numeric
3870
+ * string) itself, or an object's `value` / `y`. Null when there is none.
3514
3871
  * @param {any} d @returns {number | null}
3515
3872
  */
3516
3873
  _unitValueOf(d) {
3517
- if (typeof d === "number") return d;
3518
- if (d && typeof d === "object") {
3519
- const v = d.value != null ? d.value : d.y;
3520
- return typeof v === "number" ? v : null;
3521
- }
3522
- return null;
3874
+ return toNum(d && typeof d === "object" ? d.value != null ? d.value : d.y : d);
3523
3875
  }
3524
3876
  /**
3525
3877
  * Radius for one bubble given the value stats. Default 'area' scaling makes
@@ -3661,8 +4013,9 @@ class Unit {
3661
4013
  *
3662
4014
  * @param {SVGElement} node @param {UnitMarkSpec} spec
3663
4015
  * @param {number} x @param {number} y
4016
+ * @param {number} [k] scale against the spec's size, while a size tweens
3664
4017
  */
3665
- _place(node, spec, x2, y) {
4018
+ _place(node, spec, x2, y, k2 = 1) {
3666
4019
  const s2 = (
3667
4020
  /** @type {any} */
3668
4021
  spec
@@ -3670,16 +4023,31 @@ class Unit {
3670
4023
  if (s2.pk === PK_GLYPH) {
3671
4024
  node.setAttribute(
3672
4025
  "transform",
3673
- "translate(" + (x2 - s2.ox) + "," + (y - s2.oy) + s2.tail
4026
+ "translate(" + (x2 - s2.ox * k2) + "," + (y - s2.oy * k2) + (k2 === 1 ? s2.tail : ") scale(" + s2.s * k2 + ")")
3674
4027
  );
3675
4028
  } else if (s2.pk === PK_CORNER) {
3676
- node.setAttribute("x", String(x2 - s2.hx));
3677
- node.setAttribute("y", String(y - s2.hy));
4029
+ node.setAttribute("x", String(x2 - s2.hx * k2));
4030
+ node.setAttribute("y", String(y - s2.hy * k2));
3678
4031
  } else {
3679
4032
  node.setAttribute("cx", String(x2));
3680
4033
  node.setAttribute("cy", String(y));
3681
4034
  }
3682
4035
  }
4036
+ /**
4037
+ * Size one mark at `k` times its spec's size (a glyph scales in `_place`).
4038
+ * @param {SVGElement} node @param {UnitMarkSpec} spec @param {number} k
4039
+ */
4040
+ _size(node, spec, k2) {
4041
+ const s2 = (
4042
+ /** @type {any} */
4043
+ spec
4044
+ );
4045
+ if (s2.pk === PK_CIRCLE) node.setAttribute("r", String(s2.r * k2));
4046
+ else if (s2.pk === PK_CORNER) {
4047
+ node.setAttribute("width", String(2 * s2.hx * k2));
4048
+ node.setAttribute("height", String(2 * s2.hy * k2));
4049
+ }
4050
+ }
3683
4051
  /**
3684
4052
  * The spec for the chart-wide shape (no pictogram, no per-mark radius).
3685
4053
  * @param {any} opts @param {number} [r]
@@ -3738,7 +4106,7 @@ class Unit {
3738
4106
  */
3739
4107
  _glyphSpec(mark, dotR, pcfg) {
3740
4108
  const qr = Math.round(dotR * 10) / 10;
3741
- const key = mark.name + "|" + mark.path.length + "|" + qr;
4109
+ const key = mark.name + mark.path + mark.viewBox + mark.fillRule + qr;
3742
4110
  const hit = this._specCache.get(key);
3743
4111
  if (hit) return hit;
3744
4112
  const vb = mark.viewBox || [0, 0, 100, 100];
@@ -3787,9 +4155,9 @@ class Unit {
3787
4155
  * Draw one dot (circle, square, or image icon) with the category fill +
3788
4156
  * stroke, tagged so the shared non-axis tooltip and hover reuse work.
3789
4157
  * @param {Graphics} graphics @param {any} opts @param {number} dotR
3790
- * @param {string} color @param {number} i @param {number} j
3791
- * @param {UnitMarkSpec} [spec] this mark's resolved spec; defaults to the
3792
- * chart-wide shape
4158
+ * @param {string} color @param {number} i @param {number} j (i < 0: an exit
4159
+ * ghost, left untagged so tooltips and morph capture skip it)
4160
+ * @param {UnitMarkSpec} spec this mark's resolved spec
3793
4161
  * @returns {any}
3794
4162
  */
3795
4163
  _drawDot(graphics, opts, dotR, color, i2, j2, spec) {
@@ -3798,7 +4166,7 @@ class Unit {
3798
4166
  const strokeColor = Array.isArray(w.globals.stroke.colors) ? w.globals.stroke.colors[i2] || "none" : "none";
3799
4167
  const fillOpacity = typeof w.config.fill.opacity === "number" ? w.config.fill.opacity : 1;
3800
4168
  let el;
3801
- if (spec && spec.pk === PK_GLYPH) {
4169
+ if (spec.pk === PK_GLYPH) {
3802
4170
  el = w.dom.Paper.path(spec.d);
3803
4171
  el.node.setAttribute("fill", color);
3804
4172
  if (spec.fillRule === "evenodd") {
@@ -3806,7 +4174,7 @@ class Unit {
3806
4174
  }
3807
4175
  if (fillOpacity < 1) el.node.setAttribute("fill-opacity", String(fillOpacity));
3808
4176
  el.node.setAttribute("data:r", String(spec.r));
3809
- } else if (opts.shape === "image" && opts.image && opts.image.src) {
4177
+ } else if (spec.pk === PK_CORNER && opts.shape === "image" && opts.image && opts.image.src) {
3810
4178
  const iw = opts.image.width || 20;
3811
4179
  const ih = opts.image.height || 20;
3812
4180
  el = w.dom.Paper.image(opts.image.src);
@@ -3816,7 +4184,7 @@ class Unit {
3816
4184
  if (opts.image.tint) {
3817
4185
  el.node.setAttribute("filter", `url(#${this._tintFilter(color)})`);
3818
4186
  }
3819
- } else if (opts.shape === "square") {
4187
+ } else if (spec.pk === PK_CORNER) {
3820
4188
  const side = dotR * 2;
3821
4189
  el = graphics.drawRect(0, 0, side, side, opts.borderRadius || 0, color, 1, strokeW, strokeColor);
3822
4190
  el.node.setAttribute("fill", color);
@@ -3830,9 +4198,11 @@ class Unit {
3830
4198
  el.node.setAttribute("fill", color);
3831
4199
  if (fillOpacity < 1) el.node.setAttribute("fill-opacity", String(fillOpacity));
3832
4200
  }
3833
- el.node.classList.add("apexcharts-unit-area");
3834
- el.node.setAttribute("i", String(i2));
3835
- el.node.setAttribute("j", String(j2));
4201
+ if (i2 >= 0) {
4202
+ el.node.classList.add("apexcharts-unit-area");
4203
+ el.node.setAttribute("i", String(i2));
4204
+ el.node.setAttribute("j", String(j2));
4205
+ }
3836
4206
  return el;
3837
4207
  }
3838
4208
  /**
@@ -3846,10 +4216,12 @@ class Unit {
3846
4216
  _tintFilter(color) {
3847
4217
  const w = this.w;
3848
4218
  const NS = "http://www.w3.org/2000/svg";
3849
- const safe = String(color).replace(/[^a-zA-Z0-9]/g, "");
3850
- const id = `apexcharts-unit-tint-${w.globals.chartID}-${safe}`;
4219
+ const tints = this._tints || (this._tints = /* @__PURE__ */ new Map());
4220
+ let id = tints.get(color);
4221
+ if (id) return id;
4222
+ id = `apexcharts-unit-tint-${w.globals.chartID}-${tints.size}`;
4223
+ tints.set(color, id);
3851
4224
  const svg = w.dom.Paper.node;
3852
- if (svg.querySelector(`#${id}`)) return id;
3853
4225
  let defs = svg.querySelector("defs");
3854
4226
  if (!defs) {
3855
4227
  defs = BrowserAPIs.createElementNS(NS, "defs");
@@ -3972,6 +4344,14 @@ class Unit {
3972
4344
  }
3973
4345
  if (this.ctx) this.ctx._unitSprings = springs;
3974
4346
  }
4347
+ /**
4348
+ * True once a loop's node no longer belongs to this chart's live SVG.
4349
+ * @param {Element} node @returns {boolean}
4350
+ */
4351
+ _stale(node) {
4352
+ const P = this.w.dom.Paper;
4353
+ return !!this.w.globals.isDestroyed || !P || !P.node.contains(node);
4354
+ }
3975
4355
  /**
3976
4356
  * One rAF loop that tweens every dot from its start (cx0/cy0 - either the
3977
4357
  * cluster centre on first mount / for entering dots, or its previous slot on
@@ -3994,8 +4374,8 @@ class Unit {
3994
4374
  const speed = Math.max(1, w.config.chart.animations.speed || 800);
3995
4375
  const maxDelay = Math.min(speed * 0.6, 450);
3996
4376
  const n2 = dots.length;
3997
- for (let k2 = 0; k2 < n2; k2++) {
3998
- dots[k2].delay = n2 > 1 ? k2 / (n2 - 1) * maxDelay : 0;
4377
+ for (let k2 = n2; k2--; ) {
4378
+ dots[k2].delay = dots[k2].pair ? dots[k2 + 1].delay : n2 > 1 ? k2 / (n2 - 1) * maxDelay : 0;
3999
4379
  }
4000
4380
  const gcfg = opts.gather || {};
4001
4381
  const motion = gcfg.motion || "auto";
@@ -4004,8 +4384,9 @@ class Unit {
4004
4384
  else if (this.ctx) this.ctx._unitSprings = null;
4005
4385
  for (let k2 = 0; k2 < n2; k2++) {
4006
4386
  const d = dots[k2];
4007
- if (d.spec.pk === PK_CIRCLE && d.r0 != null && d.r1 != null && d.r0 !== d.r1) {
4008
- d.node.setAttribute("r", String(d.r0));
4387
+ if (d.r0 !== d.r1) {
4388
+ this._size(d.node, d.spec, d.r0 / d.r1);
4389
+ this._place(d.node, d.spec, d.cx0, d.cy0, d.r0 / d.r1);
4009
4390
  }
4010
4391
  }
4011
4392
  for (let k2 = 0; k2 < n2; k2++) {
@@ -4016,16 +4397,11 @@ class Unit {
4016
4397
  }
4017
4398
  }
4018
4399
  const easePos = gcfg.easing === "outBack" ? easeOutBack(typeof gcfg.overshoot === "number" ? gcfg.overshoot : 1.70158) : gcfg.easing === "inOutCubic" ? easeInOutCubic : easeOutCubic;
4019
- if (this.w.globals.unitGatherRAF != null) {
4020
- BrowserAPIs.cancelAnimationFrame(this.w.globals.unitGatherRAF);
4021
- this.w.globals.unitGatherRAF = null;
4022
- }
4023
4400
  const start = performance.now();
4024
4401
  let last = start;
4025
4402
  const stepFn = (now) => {
4026
- if (this.w.globals.isDestroyed) {
4403
+ if (this._stale(dots[0].node)) {
4027
4404
  this.w.globals.unitGatherRAF = null;
4028
- this.w.globals.animationEnded = true;
4029
4405
  return;
4030
4406
  }
4031
4407
  const dt = Math.min(MAX_FRAME_STEP, Math.max(0, (now - last) / 1e3));
@@ -4053,7 +4429,12 @@ class Unit {
4053
4429
  cx = d.cx0 + (d.x - d.cx0) * e2;
4054
4430
  cy = d.cy0 + (d.y - d.cy0) * e2;
4055
4431
  }
4056
- this._place(d.node, d.spec, cx, cy);
4432
+ let sk = 1;
4433
+ if (d.r0 !== d.r1) {
4434
+ sk = (d.r0 + (d.r1 - d.r0) * ec) / d.r1;
4435
+ this._size(d.node, d.spec, sk);
4436
+ }
4437
+ this._place(d.node, d.spec, cx, cy, sk);
4057
4438
  if (d.isEnter) d.node.style.opacity = String(Math.min(1, t2 * 2.5));
4058
4439
  if (d._c0 && d._c1) {
4059
4440
  const cr = Math.round(d._c0[0] + (d._c1[0] - d._c0[0]) * ec);
@@ -4061,9 +4442,6 @@ class Unit {
4061
4442
  const cb = Math.round(d._c0[2] + (d._c1[2] - d._c0[2]) * ec);
4062
4443
  d.node.setAttribute("fill", `rgb(${cr},${cg},${cb})`);
4063
4444
  }
4064
- if (d.spec.pk === PK_CIRCLE && d.r0 != null && d.r1 != null && d.r0 !== d.r1) {
4065
- d.node.setAttribute("r", String(d.r0 + (d.r1 - d.r0) * ec));
4066
- }
4067
4445
  if (t2 < 1) done = false;
4068
4446
  }
4069
4447
  if (done) {
@@ -4071,8 +4449,9 @@ class Unit {
4071
4449
  const d = dots[k2];
4072
4450
  d.node.style.opacity = "";
4073
4451
  if (d._c1 && d.fill1) d.node.setAttribute("fill", d.fill1);
4074
- if (d.spec.pk === PK_CIRCLE && d.r0 != null && d.r1 != null && d.r0 !== d.r1) {
4075
- d.node.setAttribute("r", String(d.r1));
4452
+ if (d.r0 !== d.r1) {
4453
+ this._size(d.node, d.spec, 1);
4454
+ this._place(d.node, d.spec, d.x, d.y);
4076
4455
  }
4077
4456
  }
4078
4457
  this.w.globals.unitGatherRAF = null;
@@ -4095,7 +4474,7 @@ class Unit {
4095
4474
  const cap = Math.max(0, opts.maxUnits || 5e3);
4096
4475
  const exits = [];
4097
4476
  for (const [key, slot] of prev) {
4098
- if (!nextPrev.has(key)) {
4477
+ if (!nextPrev.has(key) && key[0] !== "l") {
4099
4478
  exits.push(slot);
4100
4479
  if (exits.length >= cap) break;
4101
4480
  }
@@ -4122,7 +4501,7 @@ class Unit {
4122
4501
  exits.forEach((slot) => {
4123
4502
  const r2 = slot.r != null ? slot.r : dotR;
4124
4503
  const spec = slot.spec || this._baseSpec(opts, r2);
4125
- const el = this._drawDot(graphics, opts, r2, slot.fill, 0, 0, spec);
4504
+ const el = this._drawDot(graphics, opts, r2, slot.fill, -1, 0, spec);
4126
4505
  el.node.classList.add("apexcharts-unit-exit");
4127
4506
  this._place(el.node, spec, slot.x, slot.y);
4128
4507
  group2.add(el);
@@ -4133,13 +4512,9 @@ class Unit {
4133
4512
  return;
4134
4513
  }
4135
4514
  const speed = Math.max(1, w.config.chart.animations.speed || 800);
4136
- if (this.w.globals.unitExitRAF != null) {
4137
- BrowserAPIs.cancelAnimationFrame(this.w.globals.unitExitRAF);
4138
- this.w.globals.unitExitRAF = null;
4139
- }
4140
4515
  const start = performance.now();
4141
4516
  const stepFn = (now) => {
4142
- if (this.w.globals.isDestroyed) {
4517
+ if (this._stale(group2.node)) {
4143
4518
  this.w.globals.unitExitRAF = null;
4144
4519
  return;
4145
4520
  }
@@ -4210,7 +4585,8 @@ ${percent2.toFixed(1)}%`;
4210
4585
  if (!lines.length) return 0;
4211
4586
  const width = measureLabelWidth(w, lines, {
4212
4587
  fontSize: cfg.fontSize,
4213
- fontFamily: cfg.fontFamily || w.config.chart.fontFamily
4588
+ fontFamily: cfg.fontFamily || w.config.chart.fontFamily,
4589
+ fontWeight: cfg.fontWeight
4214
4590
  });
4215
4591
  const gap = conn.gap != null ? conn.gap : 8;
4216
4592
  const length = conn.length != null ? conn.length : 22;
@@ -4347,6 +4723,7 @@ ${percent2.toFixed(1)}%`;
4347
4723
  * the blob in either direction.
4348
4724
  * @param {any} elSeries @param {{ i:number, cx:number, cy:number, outerR:number, flat?:boolean }} cluster
4349
4725
  * @param {number} value @param {number} total @param {any} opts @param {string} color
4726
+ * @returns {SVGElement|undefined}
4350
4727
  */
4351
4728
  _drawClusterLabel(elSeries, cluster, value, total, opts, color) {
4352
4729
  const w = this.w;
@@ -4404,6 +4781,10 @@ ${percent2.toFixed(1)}%`;
4404
4781
  textEl.textContent = str;
4405
4782
  }
4406
4783
  elSeries.node.appendChild(textEl);
4784
+ return (
4785
+ /** @type {any} */
4786
+ textEl
4787
+ );
4407
4788
  }
4408
4789
  }
4409
4790
  ApexCharts__default.use({
@@ -4506,26 +4887,33 @@ function drilldownById(w, id) {
4506
4887
  const list = dd && Array.isArray(dd.series) ? dd.series : [];
4507
4888
  return list.find((s2) => s2 && s2.id === id);
4508
4889
  }
4509
- function toNode(w, d, i2, paletteFromParent, parentKey, seenIds = null, opts = {}) {
4890
+ function segment(name, seen) {
4891
+ var _a;
4892
+ const n2 = String(name).replace(/\//g, "%2F");
4893
+ const o2 = ((_a = seen.get(n2)) != null ? _a : -1) + 1;
4894
+ seen.set(n2, o2);
4895
+ return `${o2}:${n2}`;
4896
+ }
4897
+ function toNode(w, d, i2, paletteFromParent, parentKey, seenIds = null, opts = {}, seen = /* @__PURE__ */ new Map()) {
4510
4898
  var _a, _b, _c;
4511
4899
  const isObj = d && typeof d === "object";
4512
4900
  const name = isObj ? (_b = (_a = d.x) != null ? _a : d.name) != null ? _b : "" : "";
4513
- const value = isObj ? Number((_c = d.y) != null ? _c : d.value) : Number(d);
4901
+ const raw = isObj ? (_c = d.y) != null ? _c : d.value : d;
4902
+ const value = raw == null || raw === "" ? NaN : Number(raw);
4514
4903
  const node = {
4515
4904
  name: String(name),
4516
4905
  value: isNaN(value) ? null : value,
4517
4906
  color: isObj && d.color ? d.color : void 0,
4518
- // Identity across data updates: the path of names (indexed so same-named
4519
- // siblings stay distinct). Update animations morph matched keys in place.
4520
- _key: `${parentKey}/${i2}:${name}`
4907
+ _key: `${parentKey}/${segment(name, seen)}`
4521
4908
  };
4522
4909
  if (paletteFromParent && !node.color) {
4523
4910
  node.color = paletteFromParent[i2 % paletteFromParent.length];
4524
4911
  }
4525
4912
  if (opts.keepDatum) node._datum = d;
4913
+ const kids = /* @__PURE__ */ new Map();
4526
4914
  if (isObj && Array.isArray(d.children) && d.children.length) {
4527
4915
  node.children = d.children.map(
4528
- (c, j2) => toNode(w, c, j2, null, node._key, seenIds, opts)
4916
+ (c, j2) => toNode(w, c, j2, null, node._key, seenIds, opts, kids)
4529
4917
  );
4530
4918
  } else if (isObj && d.drilldown != null && opts.expandDrilldown !== false) {
4531
4919
  const visited = seenIds || /* @__PURE__ */ new Set();
@@ -4536,7 +4924,7 @@ function toNode(w, d, i2, paletteFromParent, parentKey, seenIds = null, opts = {
4536
4924
  nextSeen.add(d.drilldown);
4537
4925
  const palette = Array.isArray(dd.colors) ? dd.colors : null;
4538
4926
  node.children = dd.data.map(
4539
- (c, j2) => toNode(w, c, j2, palette, node._key, nextSeen, opts)
4927
+ (c, j2) => toNode(w, c, j2, palette, node._key, nextSeen, opts, kids)
4540
4928
  );
4541
4929
  }
4542
4930
  }
@@ -4551,8 +4939,9 @@ function buildHierarchy(w, opts = {}) {
4551
4939
  const first = cfgSeries && cfgSeries[0];
4552
4940
  const data = first && Array.isArray(first.data) ? first.data : cfgSeries;
4553
4941
  if (!Array.isArray(data)) return [];
4942
+ const seen = /* @__PURE__ */ new Map();
4554
4943
  return data.map(
4555
- (d, i2) => toNode(w, d, i2, null, "", null, opts)
4944
+ (d, i2) => toNode(w, d, i2, null, "", null, opts, seen)
4556
4945
  );
4557
4946
  }
4558
4947
  function fillValues(node) {
@@ -4706,7 +5095,7 @@ function renderBreadcrumb(w, opts) {
4706
5095
  text.setAttribute("class", "apexcharts-breadcrumb-label");
4707
5096
  text.textContent = String(label2);
4708
5097
  btn.appendChild(text);
4709
- btn.addEventListener("click", () => opts.onNavigate(i2, crumb));
5098
+ btn.addEventListener("click", (e2) => opts.onNavigate(i2, crumb, e2));
4710
5099
  nav.appendChild(btn);
4711
5100
  });
4712
5101
  elWrap.appendChild(nav);
@@ -4826,6 +5215,15 @@ function resolveFocus(node, current, roots) {
4826
5215
  if (next === current) return { changed: false, focus: current };
4827
5216
  return { changed: true, focus: next };
4828
5217
  }
5218
+ function focusByKey(key, nodesAll, roots) {
5219
+ var _a;
5220
+ const f = key && nodesAll.find((n2) => n2._key === key);
5221
+ return f && ((_a = f.children) == null ? void 0 : _a.length) && !(roots.length === 1 && f === roots[0]) ? f : null;
5222
+ }
5223
+ function setZoomCursor(chart, node) {
5224
+ if (!Environment.isBrowser() || chart.cfg.zoomOnClick === false) return;
5225
+ node._el.node.style.cursor = resolveFocus(node, chart._focus, chart._roots).changed ? "pointer" : "default";
5226
+ }
4829
5227
  function parseSize(size, max, fallbackRatio = 0) {
4830
5228
  if (typeof size === "number") return size;
4831
5229
  const s2 = String(size).trim();
@@ -4860,6 +5258,7 @@ function colorPass(node, color, tint, out) {
4860
5258
  }
4861
5259
  }
4862
5260
  }
5261
+ const escapeHtml$1 = (s2) => String(s2).replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
4863
5262
  class NodeTooltip {
4864
5263
  /**
4865
5264
  * @param {any} w
@@ -4897,14 +5296,29 @@ class NodeTooltip {
4897
5296
  * @param {any} node
4898
5297
  */
4899
5298
  show(e2, node) {
5299
+ var _a;
4900
5300
  const t2 = this._tip();
4901
5301
  if (!t2) return;
4902
5302
  const w = this.w;
4903
5303
  const pctTotal = (node.value / this.total * 100).toFixed(1);
4904
5304
  const parentVal = node._parent ? node._parent.value : this.total;
4905
5305
  const pctParent = parentVal > 0 ? (node.value / parentVal * 100).toFixed(1) : pctTotal;
4906
- const groupBg = w.config.tooltip.fillSeriesColor ? `background-color:${node._color};` : "";
4907
- t2.innerHTML = `<div class="apexcharts-tooltip-series-group apexcharts-active" style="display:flex;${groupBg}"><span class="apexcharts-tooltip-marker" style="background-color:${node._color}"></span><div class="apexcharts-tooltip-text"><div class="apexcharts-tooltip-y-group"><span class="apexcharts-tooltip-text-y-label">${node.name}: </span><span class="apexcharts-tooltip-text-y-value">${node.value} (${pctParent}% of parent, ${pctTotal}% of total)</span></div></div></div>`;
5306
+ const ty = w.config.tooltip.y;
5307
+ const fmt = (_a = Array.isArray(ty) ? ty[0] : ty) == null ? void 0 : _a.formatter;
5308
+ const val = fmt ? fmt(node.value, { seriesIndex: 0, dataPointIndex: -1, w, node }) : +node.value.toPrecision(12);
5309
+ t2.innerHTML = `<div class="apexcharts-tooltip-series-group apexcharts-active" style="display:flex"><span class="apexcharts-tooltip-marker"></span><div class="apexcharts-tooltip-text"><div class="apexcharts-tooltip-y-group"><span class="apexcharts-tooltip-text-y-label">${escapeHtml$1(node.name)}: </span><span class="apexcharts-tooltip-text-y-value">${val} (${pctParent}% of parent, ${pctTotal}% of total)</span></div></div></div>`;
5310
+ const group2 = (
5311
+ /** @type {HTMLElement} */
5312
+ t2.firstChild
5313
+ );
5314
+ const marker = (
5315
+ /** @type {HTMLElement} */
5316
+ group2.firstChild
5317
+ );
5318
+ marker.style.backgroundColor = node._color;
5319
+ if (w.config.tooltip.fillSeriesColor) {
5320
+ group2.style.backgroundColor = node._color;
5321
+ }
4908
5322
  t2.classList.add("apexcharts-active");
4909
5323
  t2.style.opacity = "1";
4910
5324
  this.position(e2);
@@ -4992,14 +5406,19 @@ class SunburstChart {
4992
5406
  this.centerY = gh / 2 + (this.cfg.offsetY || 0);
4993
5407
  this.maxRadius = Math.min(gw, gh) / 2.05 - this.strokeWidth - (!w.config.chart.sparkline.enabled ? w.config.chart.dropShadow.blur : 0);
4994
5408
  if (this.maxRadius < 5) return g;
4995
- this._roots = this._buildHierarchy();
5409
+ this._roots = buildHierarchy(w);
4996
5410
  if (!this._roots.length) return g;
4997
- this._roots.forEach((r2) => this._fillValues(r2));
5411
+ this._roots.forEach(fillValues);
4998
5412
  this._validateStrict();
4999
5413
  this._nodesAll = [];
5000
5414
  const colors = w.globals.colors || [];
5001
5415
  this._roots.forEach((r2, i2) => {
5002
- this._colorPass(r2, r2.color || colors[i2 % colors.length] || "#008FFB");
5416
+ colorPass(
5417
+ r2,
5418
+ r2.color || colors[i2 % colors.length] || "#008FFB",
5419
+ this.cfg.tint,
5420
+ this._nodesAll
5421
+ );
5003
5422
  });
5004
5423
  this.total = this._roots.reduce((s2, r2) => s2 + Math.max(0, r2.value), 0) || 1;
5005
5424
  this._tooltip.total = this.total;
@@ -5007,13 +5426,17 @@ class SunburstChart {
5007
5426
  this._labelsG = graphics.group({ class: "apexcharts-sunburst-labels" });
5008
5427
  g.add(this._ringsG);
5009
5428
  g.add(this._labelsG);
5010
- this._focus = null;
5429
+ this._focus = focusByKey(
5430
+ w.globals.sunburstFocusKey,
5431
+ this._nodesAll,
5432
+ this._roots
5433
+ );
5011
5434
  this._relayout(this._focus);
5012
5435
  const anims = w.config.chart.animations;
5013
5436
  let mode = "none";
5014
5437
  if (anims.enabled) {
5015
5438
  if (w.globals.dataChanged) {
5016
- if (anims.dynamicAnimation.enabled) mode = "update";
5439
+ if (w.globals.shouldAnimate !== false) mode = "update";
5017
5440
  } else if (!w.globals.resized) {
5018
5441
  mode = "intro";
5019
5442
  }
@@ -5023,22 +5446,6 @@ class SunburstChart {
5023
5446
  return g;
5024
5447
  }
5025
5448
  // ------------------------------------------------------------------ data
5026
- /**
5027
- * Resolve the config into root nodes `{ name, value, color?, children? }`.
5028
- * Each datum may carry `children` (native) or `drilldown: '<id>'` (adapter).
5029
- * Shared with the treemap - see charts/common/Hierarchy.
5030
- * @returns {any[]}
5031
- */
5032
- _buildHierarchy() {
5033
- return buildHierarchy(this.w);
5034
- }
5035
- /**
5036
- * Fill a parent's value from its children when missing.
5037
- * @param {any} node
5038
- */
5039
- _fillValues(node) {
5040
- fillValues(node);
5041
- }
5042
5449
  /**
5043
5450
  * With `partition: 'strict'`, warn (once) when a parent's value does not
5044
5451
  * match the sum of its children. The angles are still normalized to fill the
@@ -5052,22 +5459,13 @@ class SunburstChart {
5052
5459
  remedy: "Angles are normalized to fill the wedge."
5053
5460
  });
5054
5461
  }
5055
- /**
5056
- * Assign a colour to every node (explicit `color` wins, else the parent's
5057
- * colour tinted lighter). Done once so zoom preserves colours.
5058
- * Shared with the icicle - see charts/common/partition/Tint.
5059
- * @param {any} node
5060
- * @param {string} color
5061
- */
5062
- _colorPass(node, color) {
5063
- colorPass(node, color, this.cfg.tint, this._nodesAll);
5064
- }
5065
5462
  // ---------------------------------------------------------------- layout
5066
5463
  /**
5067
5464
  * Recompute visibility + angles + radii for a focus node (null = whole tree).
5068
5465
  * @param {any} focus
5069
5466
  */
5070
5467
  _relayout(focus) {
5468
+ this.w.globals.sunburstFocusKey = focus && focus._key;
5071
5469
  this._focusMaxDepth = placeTree({
5072
5470
  roots: this._roots,
5073
5471
  nodesAll: this._nodesAll,
@@ -5108,14 +5506,15 @@ class SunburstChart {
5108
5506
  * @param {'intro'|'zoom'|'update'|'none'} mode
5109
5507
  */
5110
5508
  _applyLayout(mode) {
5111
- var _a;
5509
+ var _a, _b, _c;
5112
5510
  const w = this.w;
5113
5511
  const anims = w.config.chart.animations;
5114
- const dur = !anims.enabled ? 0 : mode === "none" ? 0 : mode === "update" ? anims.dynamicAnimation.speed || 350 : anims.speed || 500;
5512
+ const dyn = anims.dynamicAnimation;
5513
+ const dur = !anims.enabled || mode === "none" ? 0 : mode === "intro" ? (_a = anims.speed) != null ? _a : 500 : dyn.enabled ? (_b = dyn.speed) != null ? _b : 350 : 0;
5115
5514
  const gen = ++this._zoomGen;
5116
5515
  const morph = (
5117
5516
  /** @type {any} */
5118
- (_a = this.ctx) == null ? void 0 : _a.morphTypeChange
5517
+ (_c = this.ctx) == null ? void 0 : _c.morphTypeChange
5119
5518
  );
5120
5519
  const morphActive = !!morph && typeof morph.isActive === "function" && morph.isActive() && typeof morph.getInitialPathAt === "function";
5121
5520
  const morphDur = morphActive ? morph.getSpeed() : 0;
@@ -5124,6 +5523,11 @@ class SunburstChart {
5124
5523
  /** @type {any} */
5125
5524
  this.ctx._sunburstPrevGeoms
5126
5525
  ) : null;
5526
+ const geo = (n2) => n2._cur || { a0: n2._t0, a1: n2._t1, iR: n2._iR, oR: n2._oR };
5527
+ const pinch = (c) => {
5528
+ const m = (c.a0 + c.a1) / 2;
5529
+ return { a0: m, a1: m, iR: c.iR, oR: c.iR };
5530
+ };
5127
5531
  this._nodesAll.forEach((node) => {
5128
5532
  if (node._show) {
5129
5533
  const target2 = {
@@ -5133,36 +5537,55 @@ class SunburstChart {
5133
5537
  oR: node._oR
5134
5538
  };
5135
5539
  if (!node._el) node._el = this._createArcEl(node);
5540
+ setZoomCursor(this, node);
5136
5541
  const morphFrom = morphActive ? this._morphSourceFor(node) : null;
5137
5542
  if (morphFrom && morphDur > 0) {
5138
5543
  this._morphArcFrom(node, morphFrom, target2, morphDur, gen);
5139
5544
  } else if ((mode === "intro" || morphActive) && dur > 0) {
5140
5545
  this._sweepArc(node, target2, morphActive ? morphDur : dur, gen);
5141
5546
  } else {
5142
- let from;
5143
- let isNew = false;
5144
- if (node._cur) {
5145
- from = node._cur;
5146
- } else if (prev && prev.get(node._key)) {
5147
- from = prev.get(node._key);
5148
- } else {
5149
- const mid = (target2.a0 + target2.a1) / 2;
5150
- from = { a0: mid, a1: mid, iR: target2.iR, oR: target2.iR };
5151
- isNew = true;
5152
- }
5153
- this._animateArc(node, from, target2, dur, false, isNew, gen);
5547
+ const p = prev && prev.get(node._key);
5548
+ const from = node._cur || (p ? geo(p) : pinch(target2));
5549
+ this._animateArc(node, from, target2, dur, false, !node._cur && !p, gen);
5154
5550
  }
5155
5551
  } else if (node._el && node._cur) {
5156
- const mid = (node._cur.a0 + node._cur.a1) / 2;
5157
- const target2 = { a0: mid, a1: mid, iR: node._cur.iR, oR: node._cur.iR };
5158
- this._animateArc(node, node._cur, target2, dur, true, false, gen);
5552
+ this._animateArc(node, node._cur, pinch(node._cur), dur, true, false, gen);
5159
5553
  }
5160
5554
  });
5555
+ if (prev && dur && !morphActive) {
5556
+ const keys = new Set(this._nodesAll.map((n2) => n2._show && n2._key));
5557
+ prev.forEach((p, k2) => {
5558
+ if (keys.has(k2) || !(p._show || p._cur)) return;
5559
+ const el = this._graphics.drawPath({
5560
+ fill: p._color,
5561
+ stroke: this.strokeColor,
5562
+ strokeWidth: this.strokeWidth,
5563
+ classes: "apexcharts-sunburst-arc"
5564
+ });
5565
+ el.node.setAttribute("data:name", p.name);
5566
+ this._ringsG.add(el.attr({ opacity: p._el.attr("opacity") }));
5567
+ const c = geo(p);
5568
+ const g = { _el: el, _color: p._color, name: p.name, _key: k2, _cur: c };
5569
+ this._nodesAll.push(g);
5570
+ this._animateArc(g, c, pinch(c), dur, true, false, gen);
5571
+ });
5572
+ }
5573
+ const end = Math.max(dur, morphDur);
5574
+ if (end) {
5575
+ this._ringsG.animate(end).after(() => {
5576
+ if (this._zoomGen === gen && this._ringsG.node.isConnected)
5577
+ new Animations(
5578
+ w,
5579
+ /** @type {any} */
5580
+ this.ctx
5581
+ ).animationCompleted(
5582
+ this._ringsG.node
5583
+ );
5584
+ });
5585
+ } else w.globals.animationEnded = true;
5161
5586
  const geoms = /* @__PURE__ */ new Map();
5162
5587
  this._nodesAll.forEach((n2) => {
5163
- if (n2._show) {
5164
- geoms.set(n2._key, { a0: n2._t0, a1: n2._t1, iR: n2._iR, oR: n2._oR });
5165
- }
5588
+ if (n2._show || n2._cur) geoms.set(n2._key, n2);
5166
5589
  });
5167
5590
  this.ctx._sunburstPrevGeoms = geoms;
5168
5591
  this._renderLabels(dur);
@@ -5279,11 +5702,9 @@ class SunburstChart {
5279
5702
  */
5280
5703
  _createArcEl(node) {
5281
5704
  const path = this._graphics.drawPath({
5282
- d: "",
5283
5705
  fill: node._color,
5284
5706
  stroke: this.strokeColor,
5285
5707
  strokeWidth: this.strokeWidth,
5286
- fillOpacity: 1,
5287
5708
  classes: "apexcharts-sunburst-arc"
5288
5709
  });
5289
5710
  const el = path.node;
@@ -5295,9 +5716,8 @@ class SunburstChart {
5295
5716
  String(!(node.children && node.children.length))
5296
5717
  );
5297
5718
  this._tooltip.attach(el, node);
5298
- if (Environment.isBrowser()) {
5719
+ if (Environment.isBrowser() && this.cfg.zoomOnClick !== false) {
5299
5720
  el.addEventListener("click", () => this._zoomTo(node));
5300
- el.style.cursor = "pointer";
5301
5721
  }
5302
5722
  this._ringsG.add(path);
5303
5723
  return path;
@@ -5361,11 +5781,12 @@ class SunburstChart {
5361
5781
  if (node._t1 - node._t0 < this.cfg.dataLabels.minAngleToShow) return;
5362
5782
  this._renderCurvedLabel(node);
5363
5783
  });
5784
+ const gen = this._zoomGen;
5785
+ labelsG.attr({ opacity: dur > 0 ? 0 : 1 });
5364
5786
  if (dur > 0) {
5365
- labelsG.attr({ opacity: 0 });
5366
- labelsG.animate(250, dur).attr({ opacity: 1 });
5367
- } else {
5368
- labelsG.attr({ opacity: 1 });
5787
+ labelsG.animate(250, dur).during((p) => {
5788
+ if (this._zoomGen === gen) labelsG.attr({ opacity: p });
5789
+ });
5369
5790
  }
5370
5791
  }
5371
5792
  /**
@@ -5374,11 +5795,10 @@ class SunburstChart {
5374
5795
  * @param {any} node
5375
5796
  */
5376
5797
  _renderCurvedLabel(node) {
5377
- if (!Environment.isBrowser()) return;
5378
5798
  const style = this.cfg.dataLabels.style;
5379
5799
  const w = this.w;
5380
5800
  const r2 = (node._iR + node._oR) / 2;
5381
- const mid = (node._t0 + node._t1) / 2;
5801
+ const mid = ((node._t0 + node._t1) / 2 % 360 + 360) % 360;
5382
5802
  const flip = mid > 90 && mid < 270;
5383
5803
  const padDeg = Math.min(r2 > 0 ? 4 / r2 * R2D : 0, (node._t1 - node._t0) / 2);
5384
5804
  const from = flip ? node._t1 - padDeg : node._t0 + padDeg;
@@ -5439,17 +5859,13 @@ class SunburstChart {
5439
5859
  */
5440
5860
  _zoomTo(node) {
5441
5861
  if (this.cfg.zoomOnClick === false) return;
5442
- const next = resolveFocus(node, this._focus);
5862
+ const next = resolveFocus(node, this._focus, this._roots);
5443
5863
  if (!next.changed) return;
5444
5864
  this._focus = next.focus;
5445
5865
  this._relayout(this._focus);
5446
5866
  this._applyLayout("zoom");
5447
5867
  this._renderBreadcrumb();
5448
5868
  }
5449
- /** Root -> focus chain of nodes. */
5450
- _focusChain() {
5451
- return focusChain(this._focus);
5452
- }
5453
5869
  /**
5454
5870
  * Minimal self-contained breadcrumb (reuses the shared `.apexcharts-breadcrumb`
5455
5871
  * CSS classes, but does NOT depend on the drilldown feature).
@@ -5469,7 +5885,7 @@ class SunburstChart {
5469
5885
  nav.style.top = "0px";
5470
5886
  nav.style.left = "0px";
5471
5887
  const crumbs = [{ name: "All", node: null }].concat(
5472
- this._focusChain().map((n2) => ({ name: n2.name, node: n2 }))
5888
+ focusChain(this._focus).map((n2) => ({ name: n2.name, node: n2 }))
5473
5889
  );
5474
5890
  crumbs.forEach((crumb, i2) => {
5475
5891
  if (i2 > 0) {
@@ -5511,21 +5927,7 @@ class SunburstChart {
5511
5927
  }
5512
5928
  });
5513
5929
  elWrap.appendChild(nav);
5514
- this._avoidChromeOverlap(nav);
5515
- }
5516
- /**
5517
- * The breadcrumb is an absolute overlay at top-left, so it can sit on top of
5518
- * a left-aligned title (or subtitle). After mounting, push it below any chart
5519
- * chrome it intersects. (Duplicated from drilldown's Breadcrumb on purpose —
5520
- * sunburst must not import the drilldown feature.)
5521
- * @param {any} nav
5522
- */
5523
- /**
5524
- * Shared with the treemap - see charts/common/Breadcrumb.
5525
- * @param {any} nav
5526
- */
5527
- _avoidChromeOverlap(nav) {
5528
- avoidChromeOverlap(this.w, nav);
5930
+ avoidChromeOverlap(w, nav);
5529
5931
  }
5530
5932
  // ------------------------------------------------------------ geometry
5531
5933
  /**
@@ -5626,6 +6028,8 @@ class IcicleChart {
5626
6028
  this._roots = buildHierarchy(this.w);
5627
6029
  if (!this._roots.length) return g;
5628
6030
  this._roots.forEach((r2) => fillValues(r2));
6031
+ this._nodesAll = [];
6032
+ this._colorNodes();
5629
6033
  sortTree(this._roots, this.cfg.sort);
5630
6034
  if (this.cfg.partition === "strict") {
5631
6035
  validateStrict(this._roots, {
@@ -5633,15 +6037,17 @@ class IcicleChart {
5633
6037
  remedy: "Extents are normalized to fill the parent."
5634
6038
  });
5635
6039
  }
5636
- this._nodesAll = [];
5637
- this._colorNodes();
5638
6040
  this.total = this._roots.reduce((s2, r2) => s2 + Math.max(0, r2.value), 0) || 1;
5639
6041
  this._tooltip.total = this.total;
5640
6042
  this._cellsG = graphics.group({ class: "apexcharts-icicle-cells" });
5641
6043
  this._labelsG = graphics.group({ class: "apexcharts-icicle-labels" });
5642
6044
  g.add(this._cellsG);
5643
6045
  g.add(this._labelsG);
5644
- this._focus = null;
6046
+ this._focus = focusByKey(
6047
+ w.globals.icicleFocusKey,
6048
+ this._nodesAll,
6049
+ this._roots
6050
+ );
5645
6051
  this._relayout(this._focus);
5646
6052
  const anims = w.config.chart.animations;
5647
6053
  let mode = "none";
@@ -5672,7 +6078,7 @@ class IcicleChart {
5672
6078
  const fallback = colors[0] || "#008FFB";
5673
6079
  let level = this._roots;
5674
6080
  const trunk = [];
5675
- while (level.length === 1 && level[0].children && level[0].children.length > 1) {
6081
+ while (level.length === 1 && level[0].children && level[0].children.length) {
5676
6082
  trunk.push(level[0]);
5677
6083
  level = level[0].children;
5678
6084
  }
@@ -5704,6 +6110,7 @@ class IcicleChart {
5704
6110
  * @param {any} focus
5705
6111
  */
5706
6112
  _relayout(focus) {
6113
+ this.w.globals.icicleFocusKey = focus && focus._key;
5707
6114
  const extent = this._valueExtent();
5708
6115
  const maxDepth = this.cfg.maxDepth;
5709
6116
  const capLevels = typeof maxDepth === "number" && maxDepth > 0 ? maxDepth : 0;
@@ -5739,9 +6146,14 @@ class IcicleChart {
5739
6146
  gap: 1
5740
6147
  });
5741
6148
  this._nodesAll.forEach((n2) => {
6149
+ n2._sub = false;
5742
6150
  if (!n2._show) return;
5743
6151
  n2._d0 = scale.near(n2._vDepth);
5744
6152
  n2._d1 = farEdge(n2, scale, this._focusMaxDepth, this.cfg.leaf, used);
6153
+ if (n2._t1 - n2._t0 < 0.5) {
6154
+ n2._show = false;
6155
+ n2._sub = true;
6156
+ }
5745
6157
  });
5746
6158
  }
5747
6159
  /**
@@ -5819,31 +6231,30 @@ class IcicleChart {
5819
6231
  * @param {'intro'|'zoom'|'update'|'none'} mode
5820
6232
  */
5821
6233
  _applyLayout(mode) {
6234
+ var _a, _b;
5822
6235
  const w = this.w;
5823
6236
  const anims = w.config.chart.animations;
5824
- const dur = !anims.enabled ? 0 : mode === "none" ? 0 : mode === "update" || mode === "zoom" ? anims.dynamicAnimation.speed || 350 : anims.speed || 500;
6237
+ const dyn = anims.dynamicAnimation;
6238
+ const dur = !anims.enabled || mode === "none" ? 0 : mode === "intro" ? (_a = anims.speed) != null ? _a : 500 : dyn.enabled ? (_b = dyn.speed) != null ? _b : 350 : 0;
5825
6239
  const gen = ++this._zoomGen;
5826
- const prev = mode === "update" ? (
6240
+ const prev = dur > 0 && mode !== "intro" ? (
5827
6241
  /** @type {any} */
5828
6242
  this.ctx._iciclePrevGeoms
5829
6243
  ) : null;
5830
6244
  this._nodesAll.forEach((node) => {
6245
+ const was = node._cur || prev && prev.get(node._key) && prev.get(node._key)();
5831
6246
  if (node._show) {
5832
6247
  const to = this._box(node);
5833
6248
  if (!node._el) node._el = this._createCellEl(node);
5834
6249
  node._el.node.setAttribute("data:clipped", String(!!node._clipped));
5835
- this._setCursor(node);
6250
+ setZoomCursor(this, node);
5836
6251
  if (mode === "intro" && dur > 0) {
5837
6252
  this._wipeCell(node, to, dur, gen);
5838
6253
  return;
5839
6254
  }
5840
- let from;
6255
+ let from = was;
5841
6256
  let isNew = false;
5842
- if (node._cur) {
5843
- from = node._cur;
5844
- } else if (prev && prev.get(node._key)) {
5845
- from = prev.get(node._key);
5846
- } else {
6257
+ if (!from) {
5847
6258
  from = {
5848
6259
  x: to.x + to.w / 2,
5849
6260
  y: to.y + to.h / 2,
@@ -5853,6 +6264,9 @@ class IcicleChart {
5853
6264
  isNew = true;
5854
6265
  }
5855
6266
  this._animateCell(node, from, to, dur, false, isNew, gen);
6267
+ } else if (node._sub && was && !was.s) {
6268
+ if (!node._el) node._el = this._createCellEl(node);
6269
+ this._animateCell(node, was, this._box(node), dur, true, false, gen);
5856
6270
  } else if (node._el && node._cur) {
5857
6271
  const c = node._cur;
5858
6272
  const collapsed = {
@@ -5866,7 +6280,9 @@ class IcicleChart {
5866
6280
  });
5867
6281
  const geoms = /* @__PURE__ */ new Map();
5868
6282
  this._nodesAll.forEach((n2) => {
5869
- if (n2._show) geoms.set(n2._key, this._box(n2));
6283
+ const b = this._box(n2);
6284
+ if (n2._sub) b.s = 1;
6285
+ if (n2._show || n2._sub) geoms.set(n2._key, () => n2._cur || b);
5870
6286
  });
5871
6287
  this.ctx._iciclePrevGeoms = geoms;
5872
6288
  this._renderLabels(dur);
@@ -5961,7 +6377,7 @@ class IcicleChart {
5961
6377
  }
5962
6378
  el.node.style.display = "";
5963
6379
  const startOp = hide ? Number(el.attr("opacity")) || 1 : fadeIn ? 0 : 1;
5964
- const endOp = hide ? 0 : 1;
6380
+ const endOp = hide && !node._sub ? 0 : 1;
5965
6381
  el.attr({ opacity: startOp });
5966
6382
  el.animate(dur).during((pos) => {
5967
6383
  if (this._zoomGen !== gen) return;
@@ -6023,11 +6439,12 @@ class IcicleChart {
6023
6439
  this._renderLabel(node);
6024
6440
  if (node._clipped) this._renderMoreMark(node);
6025
6441
  });
6442
+ const gen = this._zoomGen;
6443
+ labelsG.attr({ opacity: dur > 0 ? 0 : 1 });
6026
6444
  if (dur > 0) {
6027
- labelsG.attr({ opacity: 0 });
6028
- labelsG.animate(250, dur).attr({ opacity: 1 });
6029
- } else {
6030
- labelsG.attr({ opacity: 1 });
6445
+ labelsG.animate(250, dur).during((p) => {
6446
+ if (this._zoomGen === gen) labelsG.attr({ opacity: p });
6447
+ });
6031
6448
  }
6032
6449
  }
6033
6450
  /**
@@ -6040,7 +6457,6 @@ class IcicleChart {
6040
6457
  * @param {any} node
6041
6458
  */
6042
6459
  _renderLabel(node) {
6043
- if (!Environment.isBrowser()) return;
6044
6460
  const dl = this.cfg.dataLabels;
6045
6461
  const style = dl.style;
6046
6462
  const box = this._box(node);
@@ -6053,7 +6469,7 @@ class IcicleChart {
6053
6469
  const room = along - 8;
6054
6470
  let label2 = node.name;
6055
6471
  if (dl.showValue) {
6056
- const full = `${node.name}: ${node.value}`;
6472
+ const full = `${node.name}: ${+node.value.toPrecision(12)}`;
6057
6473
  if (this._fits(full, room, fontPx)) label2 = full;
6058
6474
  }
6059
6475
  const text = this._truncate(label2, room, fontPx);
@@ -6102,7 +6518,6 @@ class IcicleChart {
6102
6518
  * @param {any} node
6103
6519
  */
6104
6520
  _renderMoreMark(node) {
6105
- if (!Environment.isBrowser()) return;
6106
6521
  const box = this._box(node);
6107
6522
  const along = this._vertical ? box.w : box.h;
6108
6523
  if (along < 18) return;
@@ -6153,18 +6568,6 @@ class IcicleChart {
6153
6568
  return name.slice(0, maxChars - 1) + "…";
6154
6569
  }
6155
6570
  // ----------------------------------------------------------------- zoom
6156
- /**
6157
- * A cell offers the pointer only while clicking it would change the view.
6158
- * A leaf under the current focus, or the single root of a one-root tree,
6159
- * resolves to the focus the reader is already on, and a pointer there
6160
- * promises a zoom that cannot happen. Asked on every layout, because a zoom
6161
- * changes the answer for every cell.
6162
- * @param {any} node
6163
- */
6164
- _setCursor(node) {
6165
- if (!Environment.isBrowser() || this.cfg.zoomOnClick === false) return;
6166
- node._el.node.style.cursor = resolveFocus(node, this._focus, this._roots).changed ? "pointer" : "default";
6167
- }
6168
6571
  /**
6169
6572
  * Focus a node (zoom in), or zoom out one level when the current focus is
6170
6573
  * clicked.
@@ -6353,24 +6756,18 @@ function observationsOf(d, allowFlatY) {
6353
6756
  return out.length ? out : null;
6354
6757
  }
6355
6758
  function derivedStats(w, kind) {
6356
- var _a, _b;
6357
- const all = (_a = w.statsDerived) != null ? _a : w.statsDerived = {};
6358
- return (_b = all[kind]) != null ? _b : all[kind] = /* @__PURE__ */ new Map();
6759
+ const all = w.statsDerived || (w.statsDerived = {});
6760
+ return all[kind] || (all[kind] = /* @__PURE__ */ new Map());
6761
+ }
6762
+ function deriveStat(derived, key, values, opts, fn) {
6763
+ const s2 = JSON.stringify(opts) + values;
6764
+ let hit = derived.get(key);
6765
+ if (!hit || hit.s !== s2) derived.set(key, hit = { s: s2, e: fn(values, opts) });
6766
+ return hit.e;
6359
6767
  }
6360
6768
  function isDerived(derived, key, value) {
6361
- const ours = derived.get(key);
6362
- if (!ours || !Array.isArray(value) || ours.length !== value.length) {
6363
- return false;
6364
- }
6365
- for (let k2 = 0; k2 < value.length; k2++) {
6366
- const a2 = ours[k2];
6367
- const b = value[k2];
6368
- if (a2 === b) continue;
6369
- if (!Array.isArray(a2) || !Array.isArray(b) || a2[0] !== b[0] || a2[1] !== b[1]) {
6370
- return false;
6371
- }
6372
- }
6373
- return true;
6769
+ const e2 = (derived.get(key) || {}).e;
6770
+ return !!e2 && JSON.stringify(e2.density || e2.summary) === JSON.stringify(value);
6374
6771
  }
6375
6772
  function raincloudTransform(ser, w) {
6376
6773
  var _a, _b;
@@ -6395,21 +6792,26 @@ function raincloudTransform(ser, w) {
6395
6792
  if (!values) return d;
6396
6793
  const out = __spreadValues({}, y);
6397
6794
  if (needDensity) {
6398
- const est = kernelDensity(values, {
6399
- bandwidth: kde.bandwidth,
6400
- resolution: kde.resolution
6401
- });
6795
+ const est = deriveStat(
6796
+ ourDensity,
6797
+ key,
6798
+ values,
6799
+ { bandwidth: kde.bandwidth, resolution: kde.resolution },
6800
+ kernelDensity
6801
+ );
6402
6802
  if (!est) return d;
6403
6803
  out.density = est.density;
6404
6804
  out.points = values;
6405
- ourDensity.set(key, est.density);
6406
6805
  }
6407
6806
  if (needSummary) {
6408
- const est = fiveNumberSummary(values, { whiskers });
6409
- if (est) {
6410
- out.summary = est.summary;
6411
- ourSummary.set(key, est.summary);
6412
- }
6807
+ const est = deriveStat(
6808
+ ourSummary,
6809
+ key,
6810
+ values,
6811
+ { whiskers },
6812
+ fiveNumberSummary
6813
+ );
6814
+ if (est) out.summary = est.summary;
6413
6815
  }
6414
6816
  touched = true;
6415
6817
  return __spreadProps(__spreadValues({}, d), { y: out });
@@ -6438,7 +6840,9 @@ class Breadcrumb {
6438
6840
  const w = this.w;
6439
6841
  const elWrap = w.dom.elWrap;
6440
6842
  if (!elWrap) return;
6441
- const existing = elWrap.querySelector(".apexcharts-breadcrumb");
6843
+ const existing = elWrap.querySelector(
6844
+ ".apexcharts-breadcrumb[aria-label^=Drill]"
6845
+ );
6442
6846
  if (existing && existing.parentNode) {
6443
6847
  existing.parentNode.removeChild(existing);
6444
6848
  }
@@ -7869,22 +8273,55 @@ class AxisMapping {
7869
8273
  return w.globals.minX + px * AxisMapping.xRatio(w);
7870
8274
  }
7871
8275
  /**
7872
- * Client (screen) x -> pixels from the plot origin. The origin is the svg
7873
- * element's left edge plus `translateX`, never the `.apexcharts-grid` box
7874
- * (fact 2 above), so the result does not depend on what the grid happens to
7875
- * render. `svgWidth` is the unscaled width the svg was drawn at, so the ratio
7876
- * against the measured one is the CSS zoom of any container the chart sits in.
8276
+ * The plot area on screen, in client px: its corner is where the plot's
8277
+ * group is translated to (translateX, translateY into the svg), and it is
8278
+ * gridWidth by gridHeight. The one screen-to-plot measurement: the tooltip,
8279
+ * zoom, selection and every other pointer reader map through it, so x and y
8280
+ * cannot disagree under CSS zoom.
8281
+ *
8282
+ * Never the `.apexcharts-grid` group's box: a group measures to the union
8283
+ * of what it happens to draw (fact 2 above). The plot's outline starts a
8284
+ * pixel down (`Grid.drawGridArea`), so unless gridlines or row bands reach
8285
+ * the top edge the box starts a pixel below the plot, and on a numeric-x bar
8286
+ * chart the horizontal gridlines run `barPadForNumericAxis` out past both
8287
+ * sides.
8288
+ *
8289
+ * `zoom` is the CSS zoom of any container the chart sits in (screen px per
8290
+ * plot px): the measured svg width over `svgWidth`, the unscaled width it
8291
+ * was drawn at. A distance measured on screen from this corner is divided
8292
+ * by it to land in plot px, the space the series are laid out and painted in.
8293
+ * With nothing mounted to measure, screen px are taken as svg px.
8294
+ *
8295
+ * @param {import('../types/internal').ChartStateW} w
8296
+ * @returns {{ left: number, top: number, width: number, height: number, zoom: number }}
8297
+ */
8298
+ static plotRect(w) {
8299
+ var _a, _b, _c;
8300
+ const svg = ((_a = w.dom.Paper) == null ? void 0 : _a.node) || ((_b = w.dom.baseEl) == null ? void 0 : _b.querySelector(".apexcharts-svg"));
8301
+ const box = ((_c = svg || w.dom.elWrap) == null ? void 0 : _c.getBoundingClientRect()) || {
8302
+ left: 0,
8303
+ top: 0,
8304
+ width: 0
8305
+ };
8306
+ const zoom = (svg && w.globals.svgWidth ? box.width / w.globals.svgWidth : 1) || 1;
8307
+ return {
8308
+ left: box.left + w.layout.translateX * zoom,
8309
+ top: box.top + w.layout.translateY * zoom,
8310
+ width: w.layout.gridWidth * zoom,
8311
+ height: w.layout.gridHeight * zoom,
8312
+ zoom
8313
+ };
8314
+ }
8315
+ /**
8316
+ * Client (screen) x -> pixels from the plot origin of {@link plotRect}.
8317
+ * Pass the rect when the caller has already measured it.
7877
8318
  * @param {import('../types/internal').ChartStateW} w
7878
8319
  * @param {number} screenX
8320
+ * @param {{ left: number, zoom: number }} [plot]
7879
8321
  * @returns {number}
7880
8322
  */
7881
- static screenXToPlotPx(w, screenX) {
7882
- const baseEl = w.dom.baseEl;
7883
- const svg = baseEl && baseEl.querySelector(".apexcharts-svg");
7884
- if (!svg) return screenX - w.layout.translateX;
7885
- const svgRect = svg.getBoundingClientRect();
7886
- const zoom = w.globals.svgWidth ? svgRect.width / w.globals.svgWidth : 1;
7887
- return (screenX - svgRect.left) / (zoom || 1) - w.layout.translateX;
8323
+ static screenXToPlotPx(w, screenX, plot = AxisMapping.plotRect(w)) {
8324
+ return (screenX - plot.left) / plot.zoom;
7888
8325
  }
7889
8326
  }
7890
8327
  const VPAD = 3;
@@ -8077,7 +8514,8 @@ class StreamLabels {
8077
8514
  text: name,
8078
8515
  maxWidth: span,
8079
8516
  fontSize: `${px}px`,
8080
- fontFamily
8517
+ fontFamily,
8518
+ fontWeight
8081
8519
  });
8082
8520
  if (!text || text === "...") continue;
8083
8521
  const drawnWidth = text === name ? rect.width : rect.width * (text.length / name.length);
@@ -8928,7 +9366,8 @@ class RendererController {
8928
9366
  this._activate(desired, this._instances[desired]);
8929
9367
  return this._activeKind;
8930
9368
  }
8931
- if (mode === desired) {
9369
+ if (mode === desired && !this._warned) {
9370
+ this._warned = 1;
8932
9371
  warnMissingFeature(
8933
9372
  `\`chart.renderer: '${desired}'\``,
8934
9373
  `renderer-${desired}`,
@@ -8937,11 +9376,17 @@ class RendererController {
8937
9376
  }
8938
9377
  );
8939
9378
  }
8940
- } else if (mode === "canvas" && hasCanvasUnsupportedFeature(this.w)) {
9379
+ } else if (mode === "canvas" && !this._warned && hasCanvasUnsupportedFeature(this.w)) {
9380
+ this._warned = 1;
8941
9381
  console.warn(
8942
9382
  `[apexcharts] renderer:"canvas" requested but this chart uses a feature the canvas renderer does not render yet (gradient/pattern/image fill or a state color-matrix filter); falling back to SVG.`
8943
9383
  );
8944
9384
  }
9385
+ const prev = this._instances[this._activeKind];
9386
+ if (prev) {
9387
+ prev.destroy();
9388
+ delete this._instances[this._activeKind];
9389
+ }
8945
9390
  this._activate("svg", this.svg);
8946
9391
  return this._activeKind;
8947
9392
  }
@@ -10058,9 +10503,11 @@ class HeatmapGradientLegend {
10058
10503
  this._min = 0;
10059
10504
  this._max = 0;
10060
10505
  this._geom = null;
10506
+ this._grad = null;
10061
10507
  this._bandHitEls = [];
10062
10508
  this._activeBandIndex = -1;
10063
10509
  this._targetEl = null;
10510
+ this.panelsW = null;
10064
10511
  this._onCellEnter = this._onCellEnter.bind(this);
10065
10512
  this._onCellLeave = this._onCellLeave.bind(this);
10066
10513
  this._onBandEnter = this._onBandEnter.bind(this);
@@ -10175,15 +10622,8 @@ class HeatmapGradientLegend {
10175
10622
  linearGrad.setAttribute("x2", "1");
10176
10623
  linearGrad.setAttribute("y2", "0");
10177
10624
  }
10178
- const { min, max, stops, bands } = this._computeStops();
10179
- this._min = min;
10180
- this._max = max;
10181
- stops.forEach((s2) => {
10182
- const stopEl = BrowserAPIs.createElementNS(SVG_NS, "stop");
10183
- stopEl.setAttribute("offset", `${(s2.percent * 100).toFixed(2)}%`);
10184
- stopEl.setAttribute("stop-color", s2.color);
10185
- linearGrad.appendChild(stopEl);
10186
- });
10625
+ this._grad = linearGrad;
10626
+ const { min, max, bands } = this._paintStops();
10187
10627
  defs.appendChild(linearGrad);
10188
10628
  svg.appendChild(defs);
10189
10629
  const rect = BrowserAPIs.createElementNS(SVG_NS, "rect");
@@ -10392,6 +10832,7 @@ class HeatmapGradientLegend {
10392
10832
  */
10393
10833
  repositionToPlot() {
10394
10834
  var _a, _b;
10835
+ if (this._grad) this._paintStops();
10395
10836
  if (!Environment.isBrowser()) return;
10396
10837
  if (this._targetEl) return;
10397
10838
  const w = this.w;
@@ -10526,14 +10967,25 @@ class HeatmapGradientLegend {
10526
10967
  if (idx < 0 || idx === this._activeBandIndex) return;
10527
10968
  this._activeBandIndex = idx;
10528
10969
  (_d = (_c = (_b = this.ctx) == null ? void 0 : _b.events) == null ? void 0 : _c.fireEvent) == null ? void 0 : _d.call(_c, "legendHover", [this.ctx, idx, w]);
10529
- new Series(w).highlightRangeInSeries(idx, "highlight");
10970
+ this._highlightRange(idx, "highlight");
10530
10971
  }
10531
10972
  /** Leaving a band clears the highlight. */
10532
10973
  _onBandLeave() {
10533
10974
  if (this._activeBandIndex < 0) return;
10534
10975
  const idx = this._activeBandIndex;
10535
10976
  this._activeBandIndex = -1;
10536
- new Series(this.w).highlightRangeInSeries(idx, "reset");
10977
+ this._highlightRange(idx, "reset");
10978
+ }
10979
+ /**
10980
+ * A shared trellis strip sets `panelsW` so a band reaches every panel.
10981
+ * @param {number} idx
10982
+ * @param {'highlight'|'reset'} action
10983
+ */
10984
+ _highlightRange(idx, action) {
10985
+ var _a;
10986
+ (((_a = this.panelsW) == null ? void 0 : _a.call(this)) || [this.w]).forEach(
10987
+ (w) => new Series(w).highlightRangeInSeries(idx, action)
10988
+ );
10537
10989
  }
10538
10990
  _attachHoverListeners() {
10539
10991
  var _a, _b;
@@ -10555,10 +11007,10 @@ class HeatmapGradientLegend {
10555
11007
  */
10556
11008
  _onCellEnter(...args) {
10557
11009
  var _a, _b, _c;
10558
- const w = this.w;
10559
11010
  if (!this.arrowEl) return;
10560
11011
  const opts = args[args.length - 1];
10561
11012
  if (!opts || typeof opts !== "object") return;
11013
+ const w = opts.w || this.w;
10562
11014
  const i2 = opts.seriesIndex;
10563
11015
  const j2 = opts.dataPointIndex;
10564
11016
  if (typeof i2 !== "number" || typeof j2 !== "number") return;
@@ -10670,6 +11122,21 @@ class HeatmapGradientLegend {
10670
11122
  polygon.setAttribute("pointer-events", "none");
10671
11123
  return polygon;
10672
11124
  }
11125
+ /** (Re)write the strip's stops; returns `_computeStops()`. */
11126
+ _paintStops() {
11127
+ const r2 = this._computeStops();
11128
+ const grad = this._grad;
11129
+ this._min = r2.min;
11130
+ this._max = r2.max;
11131
+ grad.innerHTML = "";
11132
+ r2.stops.forEach((s2) => {
11133
+ const stopEl = BrowserAPIs.createElementNS(SVG_NS, "stop");
11134
+ stopEl.setAttribute("offset", `${(s2.percent * 100).toFixed(2)}%`);
11135
+ stopEl.setAttribute("stop-color", s2.color);
11136
+ grad.appendChild(stopEl);
11137
+ });
11138
+ return r2;
11139
+ }
10673
11140
  /**
10674
11141
  * Build gradient stops + return effective min/max.
10675
11142
  * - If `colorScale.ranges` is set, stops are placed at each range boundary
@@ -10711,7 +11178,8 @@ class HeatmapGradientLegend {
10711
11178
  if (!Number.isFinite(dataMax)) dataMax = 0;
10712
11179
  let min = dataMin;
10713
11180
  let max = dataMax;
10714
- if (typeof cs.min !== "undefined" && typeof cs.max !== "undefined" && cs.max > cs.min) {
11181
+ const csWindow = typeof cs.min !== "undefined" && typeof cs.max !== "undefined" && cs.max > cs.min;
11182
+ if (csWindow) {
10715
11183
  min = cs.min;
10716
11184
  max = cs.max;
10717
11185
  } else {
@@ -10742,34 +11210,30 @@ class HeatmapGradientLegend {
10742
11210
  } else {
10743
11211
  const baseColor = w.globals.colors[0] || "#008FFB";
10744
11212
  const utils = new Utils();
10745
- const plot = w.config.plotOptions[w.config.chart.type] || {};
11213
+ const type = w.config.chart.type;
11214
+ const plot = w.config.plotOptions[type] || {};
10746
11215
  const shadeIntensity = (_b = plot.shadeIntensity) != null ? _b : 0.5;
10747
- const hasNegs = (
11216
+ const g = (
10748
11217
  /** @type {any} */
10749
- w.globals.hasNegs
11218
+ w.globals
10750
11219
  );
11220
+ const hasNegs = g.hasNegs;
11221
+ const yExt = type === "heatmap" && !plot.distributed && !csWindow && g.maxY >= g.minY;
11222
+ const hi = yExt ? g.maxY : max;
11223
+ const total = Math.abs(hi) + Math.abs(yExt ? cs.min < g.minY ? cs.min : g.minY : min);
11224
+ const k2 = shadeIntensity * 1.25;
10751
11225
  const n2 = Math.max(2, cfg.stops || 16);
10752
11226
  for (let s2 = 0; s2 < n2; s2++) {
10753
11227
  const t2 = s2 / (n2 - 1);
10754
- const v = min + t2 * (max - min);
10755
- const total = Math.abs(max) + Math.abs(min);
10756
- const percent_v = total === 0 ? 0 : 100 * v / total;
10757
- let colorShadePercent;
10758
- if (hasNegs) {
10759
- if (plot.reverseNegativeShade) {
10760
- colorShadePercent = percent_v < 0 ? percent_v / 100 * (shadeIntensity * 1.25) : (1 - percent_v / 100) * (shadeIntensity * 1.25);
10761
- } else {
10762
- colorShadePercent = percent_v <= 0 ? 1 - (1 + percent_v / 100) * shadeIntensity : (1 - percent_v / 100) * shadeIntensity;
10763
- }
10764
- } else {
10765
- colorShadePercent = 1 - percent_v / 100;
10766
- }
10767
- if (colorShadePercent > 1) colorShadePercent = 1;
10768
- if (colorShadePercent < -1) colorShadePercent = -1;
10769
- const shaded = plot.enableShades ? utils.shadeColor(
10770
- w.config.theme.mode === "dark" ? colorShadePercent * -1 : colorShadePercent,
10771
- baseColor
10772
- ) : baseColor;
11228
+ const p = total === 0 ? 0 : Math.min(min + t2 * (max - min), hi) / total;
11229
+ const c = Math.max(
11230
+ -1,
11231
+ Math.min(
11232
+ 1,
11233
+ hasNegs ? plot.reverseNegativeShade ? (p < 0 ? p : 1 - p) * k2 : p <= 0 ? 1 - (1 + p) * shadeIntensity : (1 - p) * shadeIntensity : (1 - p) * (type === "treemap" ? k2 : 1)
11234
+ )
11235
+ );
11236
+ const shaded = plot.enableShades ? utils.shadeColor(w.config.theme.mode === "dark" ? -c : c, baseColor) : baseColor;
10773
11237
  stops.push({ percent: t2, color: shaded });
10774
11238
  }
10775
11239
  }
@@ -10794,6 +11258,7 @@ class TrellisChrome {
10794
11258
  this.elBreadcrumb = null;
10795
11259
  this.gradientLegend = null;
10796
11260
  this._gradPending = null;
11261
+ this._gradWire = null;
10797
11262
  }
10798
11263
  /**
10799
11264
  * The per-cell facet header. Built with the cell, before the panel mounts,
@@ -11024,17 +11489,20 @@ class TrellisChrome {
11024
11489
  const legend = new HeatmapGradientLegend(chart.w, chart.ctx);
11025
11490
  legend.draw(slot);
11026
11491
  this.gradientLegend = legend;
11027
- t2.panels.forEach((p) => {
11492
+ legend.panelsW = () => t2.panels.filter((p) => p.chart).map((p) => (
11493
+ /** @type {any} */
11494
+ p.chart.w
11495
+ ));
11496
+ const wire = (_2, p) => {
11028
11497
  var _a;
11029
- if (!p.chart || p === mounted) return;
11030
- const ev = (
11031
- /** @type {any} */
11032
- (_a = p.chart.ctx) == null ? void 0 : _a.events
11033
- );
11034
- if (!(ev == null ? void 0 : ev.addEventListener)) return;
11498
+ const ev = p.chart !== chart && ((_a = p.chart) == null ? void 0 : _a.ctx.events);
11499
+ if (!ev) return;
11035
11500
  ev.addEventListener("dataPointMouseEnter", legend._onCellEnter);
11036
11501
  ev.addEventListener("dataPointMouseLeave", legend._onCellLeave);
11037
- });
11502
+ };
11503
+ t2.panels.forEach((p) => wire(0, p));
11504
+ t2.ctx.events.addEventListener("panelMounted", wire);
11505
+ this._gradWire = wire;
11038
11506
  }
11039
11507
  /** Tear down the shared gradient strip (P5). */
11040
11508
  destroyGradientLegend() {
@@ -11044,6 +11512,7 @@ class TrellisChrome {
11044
11512
  (_b = (_a = t2.ctx.events).removeEventListener) == null ? void 0 : _b.call(_a, "panelMounted", this._gradPending);
11045
11513
  this._gradPending = null;
11046
11514
  }
11515
+ t2.ctx.events.removeEventListener("panelMounted", this._gradWire);
11047
11516
  if (this.gradientLegend) {
11048
11517
  try {
11049
11518
  this.gradientLegend.destroy();
@@ -11360,6 +11829,7 @@ class TrellisSync {
11360
11829
  });
11361
11830
  };
11362
11831
  const loop = () => {
11832
+ if (elGrid !== this.trellis.elGrid) return raf2 = 0;
11363
11833
  apply();
11364
11834
  raf2 = hoverTarget ? requestAnimationFrame(loop) : 0;
11365
11835
  };
@@ -11842,15 +12312,33 @@ class TrellisVirtual {
11842
12312
  this._gutterFloor = 0;
11843
12313
  }
11844
12314
  }
11845
- const CURSOR_PAD = 14;
11846
- const BAR_FAMILY = [
12315
+ Object.setPrototypeOf(
12316
+ {
12317
+ funnel: "bar",
12318
+ pyramid: "bar",
12319
+ gauge: "radialBar",
12320
+ waffle: "unit",
12321
+ histogram: "bar",
12322
+ waterfall: "rangeBar",
12323
+ dumbbell: "rangeBar",
12324
+ streamgraph: "rangeArea",
12325
+ raincloud: "violin",
12326
+ // `column` is the name half the world uses for a vertical bar chart, and the
12327
+ // combo path has always accepted it on `series[].type`. On `chart.type` it
12328
+ // used to fall through every dispatch and die inside the renderer (#5325),
12329
+ // so it is spelled out here as what it has always meant.
12330
+ column: "bar"
12331
+ },
12332
+ null
12333
+ );
12334
+ const BAR_PATHWAY_TYPES = [
11847
12335
  "bar",
11848
- "column",
11849
12336
  "rangeBar",
11850
12337
  "candlestick",
11851
12338
  "boxPlot",
11852
12339
  "violin"
11853
12340
  ];
12341
+ const CURSOR_PAD = 14;
11854
12342
  class TrellisTooltip {
11855
12343
  /**
11856
12344
  * @param {import('./Trellis').default} trellis
@@ -11915,7 +12403,7 @@ class TrellisTooltip {
11915
12403
  return -1;
11916
12404
  }
11917
12405
  }
11918
- const slotted = (BAR_FAMILY.indexOf(w.config.chart.type) !== -1 || w.config.xaxis.tickPlacement === "between") && !w.config.xaxis.convertedCatToNumeric;
12406
+ const slotted = (BAR_PATHWAY_TYPES.includes(w.config.chart.type) || w.config.xaxis.tickPlacement === "between") && !w.config.xaxis.convertedCatToNumeric;
11919
12407
  const j2 = slotted ? Math.ceil(hoverX / (gridWidth / n2)) - 1 : Math.round(hoverX / (gridWidth / Math.max(1, n2 - 1)));
11920
12408
  return Math.max(0, Math.min(n2 - 1, j2));
11921
12409
  }
@@ -13063,8 +13551,12 @@ class Trellis {
13063
13551
  // gap is the breathing room here).
13064
13552
  parentHeightOffset: 0,
13065
13553
  toolbar: { show: false },
13554
+ // the shared toolbar owns the one reset (TrellisSync.resetAll); with
13555
+ // toolbar 'none' a panel's own reset is the only way back, unless the
13556
+ // page turned it off
13066
13557
  zoom: {
13067
- enabled: this.cfg.zoom !== "none"
13558
+ enabled: this.cfg.zoom !== "none",
13559
+ resetControl: this.cfg.toolbar == "none" && w.config.chart.zoom.resetControl !== false
13068
13560
  }
13069
13561
  }, animationsOff ? { animations: { enabled: false } } : {}), this._panelRenderer ? { renderer: this._panelRenderer } : {}), {
13070
13562
  events: __spreadProps(__spreadValues({}, userEvents), {
@@ -15870,6 +16362,7 @@ function licensedForPremium(key) {
15870
16362
  }
15871
16363
  function reinstateWatermark(ctx, elWrap) {
15872
16364
  const node = C.add(elWrap, { manage: false });
16365
+ ctx._wmPainted = true;
15873
16366
  if (!node || typeof MutationObserver === "undefined") return;
15874
16367
  if (ctx._wmNodeObserver && ctx._wmObservedNode === node) return;
15875
16368
  if (ctx._wmNodeObserver) ctx._wmNodeObserver.disconnect();
@@ -15898,6 +16391,8 @@ function addWatermark(ctx, elWrap) {
15898
16391
  ctx._wmObservedWrap = elWrap;
15899
16392
  }
15900
16393
  function teardownWatermark(ctx, elWrap) {
16394
+ if (!ctx._wmPainted) return;
16395
+ ctx._wmPainted = false;
15901
16396
  if (ctx._wmWrapObserver) {
15902
16397
  ctx._wmWrapObserver.disconnect();
15903
16398
  ctx._wmWrapObserver = null;
@@ -17290,6 +17785,7 @@ class CanvasGraphics {
17290
17785
  cmd.strokeWidth = opts.strokeWidth;
17291
17786
  cmd.fill = opts.fill;
17292
17787
  cmd.lineCap = opts.strokeLinecap;
17788
+ cmd.strokeDash = this._g.seriesDash(opts.realIndex);
17293
17789
  cmd.si = opts.realIndex;
17294
17790
  if (typeof opts.j === "number") cmd.dj = opts.j;
17295
17791
  if (opts.shouldClipToGrid !== false) {
@@ -18959,405 +19455,135 @@ class History {
18959
19455
  return;
18960
19456
  }
18961
19457
  applyViewInteraction(this.ctx, cp.view);
18962
- this._refreshSettle();
18963
- this._emitChange();
18964
- }).catch(() => {
18965
- this.applying = false;
18966
- });
18967
- }
18968
- /**
18969
- * Hold `applying` true until the restore's burst of async 'updated' events
18970
- * has drained (one macrotask after the last one). Refreshed by _onUpdated.
18971
- */
18972
- _refreshSettle() {
18973
- if (!Environment.isBrowser()) {
18974
- this.applying = false;
18975
- return;
18976
- }
18977
- clearTimeout(this._settleTimer);
18978
- this._settleTimer = setTimeout(() => {
18979
- this.applying = false;
18980
- }, 0);
18981
- }
18982
- // ─── Public API ─────────────────────────────────────────────────────────
18983
- /**
18984
- * Commit a checkpoint of the current state now (a discrete undo step). Used by
18985
- * callers that mutate `w.config` without going through a full re-render (e.g.
18986
- * Ink Layer's targeted annotation redraws, which fire no 'updated' event).
18987
- * No-op when disabled or while a restore is applying.
18988
- * @param {string} [label]
18989
- */
18990
- snapshot(label2) {
18991
- if (!this.enabled || this.applying) return;
18992
- this._commit(label2 || "change");
18993
- }
18994
- /**
18995
- * @param {boolean} [animate]
18996
- */
18997
- undo(animate = true) {
18998
- if (!this.canUndo()) return;
18999
- this.pointer--;
19000
- this._restore(this.stack[this.pointer], animate);
19001
- }
19002
- /**
19003
- * @param {boolean} [animate]
19004
- */
19005
- redo(animate = true) {
19006
- if (!this.canRedo()) return;
19007
- this.pointer++;
19008
- this._restore(this.stack[this.pointer], animate);
19009
- }
19010
- canUndo() {
19011
- return this.pointer > 0;
19012
- }
19013
- canRedo() {
19014
- return this.pointer > -1 && this.pointer < this.stack.length - 1;
19015
- }
19016
- /**
19017
- * @param {string} id
19018
- * @param {boolean} [animate]
19019
- */
19020
- jump(id, animate = true) {
19021
- const idx = this.stack.findIndex((c) => c.id === id);
19022
- if (idx === -1 || idx === this.pointer) return;
19023
- this.pointer = idx;
19024
- this._restore(this.stack[idx], animate);
19025
- }
19026
- /** Clear the history, keeping the current state as the new baseline. */
19027
- clear() {
19028
- clearTimeout(this._coalesceTimer);
19029
- this._coalesceTimer = null;
19030
- const current = this.stack[this.pointer];
19031
- this.stack = current ? [current] : [];
19032
- this.pointer = this.stack.length - 1;
19033
- this._emitChange();
19034
- }
19035
- /**
19036
- * Group multiple edits into a single undo step. `fn` may be async; await your
19037
- * updateOptions/updateSeries calls inside it so the intermediate 'updated'
19038
- * events are suppressed and only one checkpoint is committed afterwards.
19039
- * @param {() => (void | Promise<any>)} fn
19040
- * @param {{ label?: string }} [opts]
19041
- * @returns {Promise<void>}
19042
- */
19043
- transaction(fn, opts = {}) {
19044
- if (typeof fn !== "function") return Promise.resolve();
19045
- const wasBatching = this._batching;
19046
- this._batching = true;
19047
- return Promise.resolve().then(() => fn()).finally(() => {
19048
- this._batching = wasBatching;
19049
- if (!wasBatching) this._commit(opts.label || "transaction", true);
19050
- });
19051
- }
19052
- /**
19053
- * @returns {{ id: string, label: string, at: number }[]}
19054
- */
19055
- entries() {
19056
- return this.stack.map((c) => ({ id: c.id, label: c.label, at: c.at }));
19057
- }
19058
- /** Lightweight state for the historyChange event / a history-rail UI. */
19059
- state() {
19060
- return {
19061
- canUndo: this.canUndo(),
19062
- canRedo: this.canRedo(),
19063
- index: this.pointer,
19064
- length: this.stack.length
19065
- };
19066
- }
19067
- _emitChange() {
19068
- this.ctx.events.fireEvent("historyChange", [this.ctx, this.state()]);
19069
- }
19070
- /** Drop the stack + detach listeners (called on full destroy). */
19071
- teardown() {
19072
- var _a, _b, _c, _d, _e, _f, _g, _h;
19073
- clearTimeout(this._coalesceTimer);
19074
- clearTimeout(this._settleTimer);
19075
- this._coalesceTimer = null;
19076
- this._settleTimer = null;
19077
- this._unwireKeyboard();
19078
- if (this._wired) {
19079
- (_b = (_a = this.ctx).removeEventListener) == null ? void 0 : _b.call(_a, "mounted", this._onMounted);
19080
- (_d = (_c = this.ctx).removeEventListener) == null ? void 0 : _d.call(_c, "updated", this._onUpdated);
19081
- (_f = (_e = this.ctx).removeEventListener) == null ? void 0 : _f.call(_e, "scrolled", this._onUpdated);
19082
- (_h = (_g = this.ctx).removeEventListener) == null ? void 0 : _h.call(_g, "dataPointSelection", this._onSelection);
19083
- }
19084
- this.stack = [];
19085
- this.pointer = -1;
19086
- this._wired = false;
19087
- }
19088
- }
19089
- ApexCharts__default.registerFeatures({ history: History });
19090
- const DataLabels = ApexCharts.__apex_DataLabels;
19091
- const resolveEasing = ApexCharts.__apex_Easing_resolveEasing;
19092
- const parsePath = ApexCharts.__apex_PathMorphing_parsePath;
19093
- const arrayToPath = ApexCharts.__apex_PathMorphing_arrayToPath;
19094
- function buildUnionEntries(join, oldN) {
19095
- const exitSet = new Set(join.exits);
19096
- const entries = [];
19097
- let oi = 0;
19098
- for (let nj = 0; nj < join.toOld.length; nj++) {
19099
- const oj = join.toOld[nj];
19100
- if (oj !== -1) {
19101
- while (oi < oj) {
19102
- if (exitSet.has(oi)) entries.push({ oldJ: oi, newJ: -1 });
19103
- oi++;
19104
- }
19105
- entries.push({ oldJ: oj, newJ: nj });
19106
- oi = oj + 1;
19107
- } else {
19108
- entries.push({ oldJ: -1, newJ: nj });
19109
- }
19110
- }
19111
- while (oi < oldN) {
19112
- if (exitSet.has(oi)) entries.push({ oldJ: oi, newJ: -1 });
19113
- oi++;
19114
- }
19115
- return entries;
19116
- }
19117
- function analyzeSeriesPath(d, expectedAnchors, isArea) {
19118
- if (!d || typeof d !== "string") return null;
19119
- const cmds = parsePath(d);
19120
- if (!cmds.length || cmds[0][0] !== "M") return null;
19121
- for (let i2 = 1; i2 < cmds.length; i2++) {
19122
- if (cmds[i2][0] === "M") return null;
19123
- }
19124
- let body = cmds;
19125
- let closing = null;
19126
- if (isArea) {
19127
- if (cmds.length < 5) return null;
19128
- closing = cmds.slice(-3);
19129
- body = cmds.slice(0, -3);
19130
- if (closing[2][0] !== "Z") return null;
19131
- if (closing[1][0] !== "L") return null;
19132
- if (closing[0][0] !== "L" && closing[0][0] !== "C") return null;
19133
- } else if (cmds[cmds.length - 1][0] === "Z") {
19134
- return null;
19135
- }
19136
- if (body.length !== expectedAnchors || body.length < 2) return null;
19137
- const segType = body[1][0];
19138
- if (segType !== "L" && segType !== "C") return null;
19139
- for (let i2 = 2; i2 < body.length; i2++) {
19140
- if (body[i2][0] !== segType) return null;
19141
- }
19142
- const anchors = body.map(
19143
- (c) => c[0] === "C" ? [Number(c[5]), Number(c[6])] : [Number(c[1]), Number(c[2])]
19144
- );
19145
- for (const a2 of anchors) {
19146
- if (!isFinite(a2[0]) || !isFinite(a2[1])) return null;
19147
- }
19148
- return { body, closing, segType, anchors };
19149
- }
19150
- function lerpPt(a2, b, t2) {
19151
- return [a2[0] + (b[0] - a2[0]) * t2, a2[1] + (b[1] - a2[1]) * t2];
19152
- }
19153
- function splitCubic(s2, cmd, t2) {
19154
- const p0 = s2;
19155
- const p1 = [cmd[1], cmd[2]];
19156
- const p2 = [cmd[3], cmd[4]];
19157
- const p3 = [cmd[5], cmd[6]];
19158
- const p01 = lerpPt(p0, p1, t2);
19159
- const p12 = lerpPt(p1, p2, t2);
19160
- const p23 = lerpPt(p2, p3, t2);
19161
- const p012 = lerpPt(p01, p12, t2);
19162
- const p123 = lerpPt(p12, p23, t2);
19163
- const mid = lerpPt(p012, p123, t2);
19164
- return {
19165
- first: ["C", p01[0], p01[1], p012[0], p012[1], mid[0], mid[1]],
19166
- second: ["C", p123[0], p123[1], p23[0], p23[1], p3[0], p3[1]],
19167
- mid
19168
- };
19169
- }
19170
- function splitLine(s2, cmd, t2) {
19171
- const e2 = [cmd[1], cmd[2]];
19172
- const mid = lerpPt(s2, e2, t2);
19173
- return {
19174
- first: ["L", mid[0], mid[1]],
19175
- second: ["L", e2[0], e2[1]],
19176
- mid
19177
- };
19178
- }
19179
- function expandPath(analysis, ownIdx) {
19180
- const { body, closing, segType, anchors } = analysis;
19181
- const n2 = anchors.length;
19182
- const m = ownIdx.length;
19183
- const degen = (p) => segType === "C" ? ["C", p[0], p[1], p[0], p[1], p[0], p[1]] : ["L", p[0], p[1]];
19184
- const out = [["M", anchors[0][0], anchors[0][1]]];
19185
- let firstOwn = 0;
19186
- while (firstOwn < m && ownIdx[firstOwn] !== 0) firstOwn++;
19187
- for (let q2 = 1; q2 <= firstOwn; q2++) out.push(degen(anchors[0]));
19188
- let entry = firstOwn + 1;
19189
- for (let s2 = 0; s2 < n2 - 1; s2++) {
19190
- let interior = 0;
19191
- while (entry + interior < m && ownIdx[entry + interior] === -1) interior++;
19192
- const cmd = body[s2 + 1];
19193
- if (!interior) {
19194
- out.push(cmd.slice());
19195
- } else {
19196
- const totalParts = interior + 1;
19197
- let start = anchors[s2];
19198
- let rest = cmd;
19199
- for (let q2 = 0; q2 < interior; q2++) {
19200
- const t2 = 1 / (totalParts - q2);
19201
- const sp = segType === "C" ? splitCubic(start, rest, t2) : splitLine(start, rest, t2);
19202
- out.push(sp.first);
19203
- start = sp.mid;
19204
- rest = sp.second;
19205
- }
19206
- out.push(rest);
19458
+ this._refreshSettle();
19459
+ this._emitChange();
19460
+ }).catch(() => {
19461
+ this.applying = false;
19462
+ });
19463
+ }
19464
+ /**
19465
+ * Hold `applying` true until the restore's burst of async 'updated' events
19466
+ * has drained (one macrotask after the last one). Refreshed by _onUpdated.
19467
+ */
19468
+ _refreshSettle() {
19469
+ if (!Environment.isBrowser()) {
19470
+ this.applying = false;
19471
+ return;
19207
19472
  }
19208
- entry += interior + 1;
19473
+ clearTimeout(this._settleTimer);
19474
+ this._settleTimer = setTimeout(() => {
19475
+ this.applying = false;
19476
+ }, 0);
19209
19477
  }
19210
- while (entry < m) {
19211
- out.push(degen(anchors[n2 - 1]));
19212
- entry++;
19478
+ // ─── Public API ─────────────────────────────────────────────────────────
19479
+ /**
19480
+ * Commit a checkpoint of the current state now (a discrete undo step). Used by
19481
+ * callers that mutate `w.config` without going through a full re-render (e.g.
19482
+ * Ink Layer's targeted annotation redraws, which fire no 'updated' event).
19483
+ * No-op when disabled or while a restore is applying.
19484
+ * @param {string} [label]
19485
+ */
19486
+ snapshot(label2) {
19487
+ if (!this.enabled || this.applying) return;
19488
+ this._commit(label2 || "change");
19213
19489
  }
19214
- if (closing) closing.forEach((c) => out.push(c.slice()));
19215
- return out;
19216
- }
19217
- function reconcilePathPair(fromD, toD, entries, oldN, newN, isArea) {
19218
- const fromAnalysis = analyzeSeriesPath(fromD, oldN, isArea);
19219
- if (!fromAnalysis) return null;
19220
- const toAnalysis = analyzeSeriesPath(toD, newN, isArea);
19221
- if (!toAnalysis) return null;
19222
- if (fromAnalysis.segType !== toAnalysis.segType) return null;
19223
- if ((fromAnalysis.closing || toAnalysis.closing) && (!fromAnalysis.closing || !toAnalysis.closing || fromAnalysis.closing[0][0] !== toAnalysis.closing[0][0])) {
19224
- return null;
19490
+ /**
19491
+ * @param {boolean} [animate]
19492
+ */
19493
+ undo(animate = true) {
19494
+ if (!this.canUndo()) return;
19495
+ this.pointer--;
19496
+ this._restore(this.stack[this.pointer], animate);
19225
19497
  }
19226
- const fromOwn = entries.map((e2) => e2.oldJ);
19227
- const toOwn = entries.map((e2) => e2.newJ);
19228
- return {
19229
- from: arrayToPath(expandPath(fromAnalysis, fromOwn)),
19230
- toInterp: arrayToPath(expandPath(toAnalysis, toOwn))
19231
- };
19232
- }
19233
- function lengthTransitionEnabled(w) {
19234
- var _a;
19235
- const anim = w.config.chart.animations;
19236
- if (!anim || anim.enabled === false) return false;
19237
- if (!anim.dynamicAnimation || anim.dynamicAnimation.enabled === false) {
19238
- return false;
19498
+ /**
19499
+ * @param {boolean} [animate]
19500
+ */
19501
+ redo(animate = true) {
19502
+ if (!this.canRedo()) return;
19503
+ this.pointer++;
19504
+ this._restore(this.stack[this.pointer], animate);
19239
19505
  }
19240
- const largeThreshold = (_a = anim.largeDatasetThreshold) != null ? _a : 0;
19241
- if (largeThreshold > 0 && w.globals.dataPoints > largeThreshold) return false;
19242
- return !!(Environment.isBrowser() && w.globals.dataChanged && w.globals.shouldAnimate);
19243
- }
19244
- function datumKey(w, realIndex, j2) {
19245
- var _a, _b, _c, _d;
19246
- if ((_a = w.axisFlags) == null ? void 0 : _a.isXNumeric) {
19247
- const sx = (_c = (_b = w.seriesData) == null ? void 0 : _b.seriesX) == null ? void 0 : _c[realIndex];
19248
- if (sx && sx.length && sx[j2] != null) return "x:" + sx[j2];
19506
+ canUndo() {
19507
+ return this.pointer > 0;
19249
19508
  }
19250
- const lbl = (_d = w.globals.labels) == null ? void 0 : _d[j2];
19251
- if (lbl != null && String(lbl) !== "") {
19252
- return "c:" + (Array.isArray(lbl) ? lbl.join(" ") : String(lbl));
19509
+ canRedo() {
19510
+ return this.pointer > -1 && this.pointer < this.stack.length - 1;
19253
19511
  }
19254
- return "j:" + j2;
19255
- }
19256
- function frameDatumKey(frame, realIndex, j2) {
19257
- var _a, _b;
19258
- if (frame.isXNumeric) {
19259
- const sx = (_a = frame.seriesX) == null ? void 0 : _a[realIndex];
19260
- if (sx && sx.length && sx[j2] != null) return "x:" + sx[j2];
19512
+ /**
19513
+ * @param {string} id
19514
+ * @param {boolean} [animate]
19515
+ */
19516
+ jump(id, animate = true) {
19517
+ const idx = this.stack.findIndex((c) => c.id === id);
19518
+ if (idx === -1 || idx === this.pointer) return;
19519
+ this.pointer = idx;
19520
+ this._restore(this.stack[idx], animate);
19261
19521
  }
19262
- const lbl = (_b = frame.labels) == null ? void 0 : _b[j2];
19263
- if (lbl != null && String(lbl) !== "") {
19264
- return "c:" + (Array.isArray(lbl) ? lbl.join(" ") : String(lbl));
19522
+ /** Clear the history, keeping the current state as the new baseline. */
19523
+ clear() {
19524
+ clearTimeout(this._coalesceTimer);
19525
+ this._coalesceTimer = null;
19526
+ const current = this.stack[this.pointer];
19527
+ this.stack = current ? [current] : [];
19528
+ this.pointer = this.stack.length - 1;
19529
+ this._emitChange();
19265
19530
  }
19266
- return "j:" + j2;
19267
- }
19268
- function joinKeys(oldKeys, newKeys) {
19269
- const oldIndex = /* @__PURE__ */ new Map();
19270
- oldKeys.forEach((k2, i2) => {
19271
- if (!oldIndex.has(k2)) oldIndex.set(k2, i2);
19272
- });
19273
- const toOld = new Array(newKeys.length);
19274
- const usedOld = /* @__PURE__ */ new Set();
19275
- let prev = -1;
19276
- let ordered = true;
19277
- let identity = oldKeys.length === newKeys.length;
19278
- newKeys.forEach((k2, i2) => {
19279
- const oi = oldIndex.has(k2) && !usedOld.has(oldIndex.get(k2)) ? oldIndex.get(k2) : -1;
19280
- toOld[i2] = oi;
19281
- if (oi !== -1) {
19282
- usedOld.add(oi);
19283
- if (oi < prev) ordered = false;
19284
- prev = oi;
19285
- }
19286
- if (oi !== i2) identity = false;
19287
- });
19288
- const exits = [];
19289
- for (let i2 = 0; i2 < oldKeys.length; i2++) {
19290
- if (!usedOld.has(i2)) exits.push(i2);
19531
+ /**
19532
+ * Group multiple edits into a single undo step. `fn` may be async; await your
19533
+ * updateOptions/updateSeries calls inside it so the intermediate 'updated'
19534
+ * events are suppressed and only one checkpoint is committed afterwards.
19535
+ * @param {() => (void | Promise<any>)} fn
19536
+ * @param {{ label?: string }} [opts]
19537
+ * @returns {Promise<void>}
19538
+ */
19539
+ transaction(fn, opts = {}) {
19540
+ if (typeof fn !== "function") return Promise.resolve();
19541
+ const wasBatching = this._batching;
19542
+ this._batching = true;
19543
+ return Promise.resolve().then(() => fn()).finally(() => {
19544
+ this._batching = wasBatching;
19545
+ if (!wasBatching) this._commit(opts.label || "transaction", true);
19546
+ });
19291
19547
  }
19292
- return { toOld, exits, ordered, changed: !identity };
19293
- }
19294
- function uniquifyKeys(keys) {
19295
- const seen = /* @__PURE__ */ new Map();
19296
- return keys.map((k2) => {
19297
- const count = seen.get(k2) || 0;
19298
- seen.set(k2, count + 1);
19299
- return count === 0 ? k2 : `${k2}#${count}`;
19300
- });
19301
- }
19302
- function seriesJoin(w, realIndex, includeIdentity = false, allowReorder = false) {
19303
- var _a, _b;
19304
- if (!lengthTransitionEnabled(w)) return null;
19305
- const frame = w.globals.prevStreamFrame;
19306
- if (!frame) return null;
19307
- const oldY = (_a = frame.seriesY) == null ? void 0 : _a[realIndex];
19308
- const newY = (_b = w.seriesData.series) == null ? void 0 : _b[realIndex];
19309
- if (!Array.isArray(oldY) || !Array.isArray(newY)) return null;
19310
- if (!oldY.length || !newY.length) return null;
19311
- const oldKeys = uniquifyKeys(
19312
- oldY.map((_2, j2) => frameDatumKey(frame, realIndex, j2))
19313
- );
19314
- const newKeys = uniquifyKeys(newY.map((_2, j2) => datumKey(w, realIndex, j2)));
19315
- const join = joinKeys(oldKeys, newKeys);
19316
- if (!join.ordered && !allowReorder) return null;
19317
- if (!join.changed && !includeIdentity) return null;
19318
- return { join, oldKeys, newKeys };
19319
- }
19320
- function morphEasing(w) {
19321
- var _a, _b;
19322
- const anim = w.config.chart.animations;
19323
- return resolveEasing((_b = (_a = anim.dynamicAnimation) == null ? void 0 : _a.easing) != null ? _b : anim.easing);
19324
- }
19325
- function reconcileSeriesPaths(w, { type, realIndex, pathFromLine, pathFromArea, linePaths, areaPaths }) {
19326
- var _a, _b;
19327
- const sj = seriesJoin(w, realIndex);
19328
- if (!sj) return null;
19329
- const { join, oldKeys, newKeys } = sj;
19330
- const frame = w.globals.prevStreamFrame;
19331
- if (!frame) return null;
19332
- const oldY = (_a = frame.seriesY) == null ? void 0 : _a[realIndex];
19333
- const newY = (_b = w.seriesData.series) == null ? void 0 : _b[realIndex];
19334
- if (oldY.length < 2 || newY.length < 2) return null;
19335
- if (oldY.some((v) => v === null) || newY.some((v) => v === null)) return null;
19336
- const entries = buildUnionEntries(join, oldKeys.length);
19337
- const out = {};
19338
- if (Array.isArray(linePaths) && linePaths.length === 1 && pathFromLine) {
19339
- out.line = reconcilePathPair(
19340
- pathFromLine,
19341
- linePaths[0],
19342
- entries,
19343
- oldKeys.length,
19344
- newKeys.length,
19345
- false
19346
- );
19548
+ /**
19549
+ * @returns {{ id: string, label: string, at: number }[]}
19550
+ */
19551
+ entries() {
19552
+ return this.stack.map((c) => ({ id: c.id, label: c.label, at: c.at }));
19347
19553
  }
19348
- if (type === "area" && Array.isArray(areaPaths) && areaPaths.length === 1 && pathFromArea) {
19349
- out.area = reconcilePathPair(
19350
- pathFromArea,
19351
- areaPaths[0],
19352
- entries,
19353
- oldKeys.length,
19354
- newKeys.length,
19355
- true
19356
- );
19554
+ /** Lightweight state for the historyChange event / a history-rail UI. */
19555
+ state() {
19556
+ return {
19557
+ canUndo: this.canUndo(),
19558
+ canRedo: this.canRedo(),
19559
+ index: this.pointer,
19560
+ length: this.stack.length
19561
+ };
19562
+ }
19563
+ _emitChange() {
19564
+ this.ctx.events.fireEvent("historyChange", [this.ctx, this.state()]);
19565
+ }
19566
+ /** Drop the stack + detach listeners (called on full destroy). */
19567
+ teardown() {
19568
+ var _a, _b, _c, _d, _e, _f, _g, _h;
19569
+ clearTimeout(this._coalesceTimer);
19570
+ clearTimeout(this._settleTimer);
19571
+ this._coalesceTimer = null;
19572
+ this._settleTimer = null;
19573
+ this._unwireKeyboard();
19574
+ if (this._wired) {
19575
+ (_b = (_a = this.ctx).removeEventListener) == null ? void 0 : _b.call(_a, "mounted", this._onMounted);
19576
+ (_d = (_c = this.ctx).removeEventListener) == null ? void 0 : _d.call(_c, "updated", this._onUpdated);
19577
+ (_f = (_e = this.ctx).removeEventListener) == null ? void 0 : _f.call(_e, "scrolled", this._onUpdated);
19578
+ (_h = (_g = this.ctx).removeEventListener) == null ? void 0 : _h.call(_g, "dataPointSelection", this._onSelection);
19579
+ }
19580
+ this.stack = [];
19581
+ this.pointer = -1;
19582
+ this._wired = false;
19357
19583
  }
19358
- if (!out.line && !out.area) return null;
19359
- return out;
19360
19584
  }
19585
+ ApexCharts__default.registerFeatures({ history: History });
19586
+ const DataLabels = ApexCharts.__apex_DataLabels;
19361
19587
  function detectStreamScroll(w, realIndex, newXPixels, newYPixels) {
19362
19588
  var _a;
19363
19589
  const gl = w.globals;
@@ -21324,9 +21550,9 @@ function wrapParentTip(hf, tm) {
21324
21550
  }
21325
21551
  const v = (_c = tm._tip()) == null ? void 0 : _c.querySelector(".apexcharts-tooltip-text-y-value");
21326
21552
  if (!v) return;
21327
- let rest = `/ ${tm._formatValue(h.total)}`;
21553
+ let rest = `/ ${tm._formatValue(h.total, node._si)}`;
21328
21554
  if (tt.share && h.total) rest += ` · ${Math.round(h.share * 100)}%`;
21329
- v.innerHTML = `${tm._formatValue(h.value)} <span class="apexcharts-highlight-total" style="font-weight: 400; opacity: 0.6">${rest}</span>`;
21555
+ v.innerHTML = `${tm._formatValue(h.value, node._si)} <span class="apexcharts-highlight-total" style="font-weight: 400; opacity: 0.6">${rest}</span>`;
21330
21556
  };
21331
21557
  }
21332
21558
  function tone(rec, fore) {
@@ -21864,7 +22090,7 @@ class HighlightFilter {
21864
22090
  const active = hd.active;
21865
22091
  if (!active && !(prevMap == null ? void 0 : prevMap.size)) return void 0;
21866
22092
  const { j: j2, realIndex } = o2;
21867
- const key = BAR + `${realIndex}::${datumKey(w, realIndex, j2)}`;
22093
+ const key = BAR + `${realIndex}::${bar._keys(realIndex)[j2]}`;
21868
22094
  this._seen.add(key);
21869
22095
  const prev = prevMap == null ? void 0 : prevMap.get(key);
21870
22096
  const p = active ? (_a = hd.parts[realIndex]) == null ? void 0 : _a[j2] : null;
@@ -22174,14 +22400,14 @@ class HighlightFilter {
22174
22400
  }
22175
22401
  /**
22176
22402
  * The stack a stacked bar datum joins, as the renderer resolves it
22177
- * (BarStacked drawStackedColumnPaths): its series group, then its x value
22178
- * on a numeric or datetime column axis, else its index.
22403
+ * (BarStacked): its series group, then its x value on a numeric or
22404
+ * datetime axis, else its index.
22179
22405
  * @param {number} i @param {number} j
22180
22406
  */
22181
22407
  _barKey(i2, j2) {
22182
22408
  var _a;
22183
22409
  const w = this.w;
22184
- return w.labelData.seriesGroupIndex[i2] + "|" + (!w.config.plotOptions.bar.horizontal && w.axisFlags.isXNumeric ? (_a = w.seriesData.seriesX[i2]) == null ? void 0 : _a[j2] : j2);
22410
+ return w.labelData.seriesGroupIndex[i2] + "|" + (w.axisFlags.isXNumeric ? (_a = w.seriesData.seriesX[i2]) == null ? void 0 : _a[j2] : j2);
22185
22411
  }
22186
22412
  /**
22187
22413
  * Line.draw, once per series right after its whole has been rendered and
@@ -22245,7 +22471,7 @@ class HighlightFilter {
22245
22471
  const exit = !to && !!(prev == null ? void 0 : prev.d) && animate;
22246
22472
  const base = active && animate && (exit || to && !(prev == null ? void 0 : prev.d) && (prev || this.cfg.enter === "baseline")) ? this._lineBase(ln, type, series, i2, realIndex, ti, has ? raw : null) : null;
22247
22473
  if (pp && w.config.chart.stacked) {
22248
- this._swap(ln, () => ln._recordStackTops(realIndex, pp.yArrj));
22474
+ this._swap(ln, () => ln._recordStackTops(realIndex, pp.yArrj, pp.S[i2]));
22249
22475
  this._stkPrev.push(pp.yArrj);
22250
22476
  }
22251
22477
  if (exit) {