apexcharts 8.2.0 → 8.3.0

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 (222) hide show
  1. package/README.md +7 -7
  2. package/dist/apexcharts.common.js +2 -2
  3. package/dist/apexcharts.core.js +271 -173
  4. package/dist/apexcharts.core.min.js +2 -2
  5. package/dist/apexcharts.css +35 -0
  6. package/dist/apexcharts.esm.js +1722 -1527
  7. package/dist/apexcharts.full.js +1459 -1075
  8. package/dist/apexcharts.full.min.js +2 -2
  9. package/dist/apexcharts.js +994 -715
  10. package/dist/apexcharts.min.js +2 -2
  11. package/dist/apexcharts.ssr.common.js +2 -2
  12. package/dist/apexcharts.ssr.esm.js +994 -715
  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 +433 -394
  17. package/dist/bar.js +2 -2
  18. package/dist/boxPlot.common.js +2 -2
  19. package/dist/boxPlot.esm.js +364 -322
  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 +364 -322
  24. package/dist/candlestick.js +2 -2
  25. package/dist/column.common.js +2 -2
  26. package/dist/column.esm.js +433 -394
  27. package/dist/core.common.js +2 -2
  28. package/dist/core.esm.js +271 -173
  29. package/dist/donut.common.js +1 -1
  30. package/dist/donut.esm.js +1 -1
  31. package/dist/dumbbell.common.js +2 -2
  32. package/dist/dumbbell.esm.js +433 -394
  33. package/dist/features/all.common.js +2 -2
  34. package/dist/features/all.esm.js +250 -187
  35. package/dist/features/annotations.common.js +1 -1
  36. package/dist/features/annotations.esm.js +1 -1
  37. package/dist/features/annotations.js +1 -1
  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 +1 -1
  48. package/dist/features/exports.esm.js +1 -1
  49. package/dist/features/exports.js +1 -1
  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 +63 -43
  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 +1 -1
  78. package/dist/features/morph.esm.js +1 -1
  79. package/dist/features/morph.js +1 -1
  80. package/dist/features/perspectives.common.js +1 -1
  81. package/dist/features/perspectives.esm.js +1 -1
  82. package/dist/features/perspectives.js +1 -1
  83. package/dist/features/raincloud.common.js +1 -1
  84. package/dist/features/raincloud.esm.js +1 -1
  85. package/dist/features/raincloud.js +1 -1
  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 +1 -1
  90. package/dist/features/stats.esm.js +1 -1
  91. package/dist/features/stats.js +1 -1
  92. package/dist/features/storyboard.common.js +1 -1
  93. package/dist/features/storyboard.esm.js +1 -1
  94. package/dist/features/storyboard.js +1 -1
  95. package/dist/features/streamgraph.common.js +2 -2
  96. package/dist/features/streamgraph.esm.js +3 -2
  97. package/dist/features/streamgraph.js +2 -2
  98. package/dist/features/toolbar.common.js +2 -2
  99. package/dist/features/toolbar.esm.js +92 -2
  100. package/dist/features/toolbar.js +2 -2
  101. package/dist/features/trellis.common.js +2 -2
  102. package/dist/features/trellis.esm.js +83 -47
  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 +1 -1
  108. package/dist/features/weave.esm.js +1 -1
  109. package/dist/features/weave.js +1 -1
  110. package/dist/full.common.js +2 -2
  111. package/dist/full.esm.js +950 -795
  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 +433 -394
  117. package/dist/icicle.common.js +2 -2
  118. package/dist/icicle.esm.js +54 -38
  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 +1 -1
  129. package/dist/pie.esm.js +1 -1
  130. package/dist/pie.js +1 -1
  131. package/dist/polarArea.common.js +1 -1
  132. package/dist/polarArea.esm.js +1 -1
  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 +1 -1
  137. package/dist/radialBar.esm.js +1 -1
  138. package/dist/radialBar.js +1 -1
  139. package/dist/raincloud.common.js +2 -2
  140. package/dist/raincloud.esm.js +72 -26
  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 +433 -394
  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 +93 -41
  149. package/dist/sunburst.common.js +2 -2
  150. package/dist/sunburst.esm.js +103 -93
  151. package/dist/sunburst.js +2 -2
  152. package/dist/treemap.common.js +2 -2
  153. package/dist/treemap.esm.js +105 -86
  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 +432 -393
  166. package/package.json +1 -1
  167. package/src/apexcharts.js +13 -6
  168. package/src/assets/apexcharts.css +35 -0
  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 +37 -37
  173. package/src/charts/Line.js +118 -42
  174. package/src/charts/Radar.js +5 -7
  175. package/src/charts/RangeBar.js +47 -43
  176. package/src/charts/Sunburst.js +101 -98
  177. package/src/charts/Treemap.js +108 -66
  178. package/src/charts/Unit.js +368 -250
  179. package/src/charts/Violin.js +48 -30
  180. package/src/charts/common/Breadcrumb.js +2 -2
  181. package/src/charts/common/Hierarchy.js +32 -11
  182. package/src/charts/common/Jitter.js +32 -7
  183. package/src/charts/common/bar/DataLabels.js +76 -81
  184. package/src/charts/common/bar/Helpers.js +43 -7
  185. package/src/charts/common/line/Helpers.js +12 -15
  186. package/src/charts/common/partition/NodeTooltip.js +8 -1
  187. package/src/charts/common/partition/Partition.js +33 -1
  188. package/src/charts/common/treemap/Helpers.js +3 -11
  189. package/src/locales/en.json +2 -1
  190. package/src/locales/ro.json +3 -2
  191. package/src/modules/Core.js +4 -0
  192. package/src/modules/CoreUtils.js +18 -42
  193. package/src/modules/Data.js +23 -24
  194. package/src/modules/DataLabels.js +6 -6
  195. package/src/modules/Graphics.js +62 -49
  196. package/src/modules/Markers.js +3 -1
  197. package/src/modules/Range.js +44 -29
  198. package/src/modules/RendererController.js +17 -3
  199. package/src/modules/Scales.js +32 -9
  200. package/src/modules/Series.js +39 -18
  201. package/src/modules/Theme.js +1 -1
  202. package/src/modules/ZoomPanSelection.js +119 -2
  203. package/src/modules/accessibility/KeyboardNavigation.js +114 -186
  204. package/src/modules/animations/LengthTransition.js +22 -2
  205. package/src/modules/drilldown/Breadcrumb.js +5 -2
  206. package/src/modules/helpers/Destroy.js +1 -1
  207. package/src/modules/highlightFilter/HighlightFilter.js +8 -9
  208. package/src/modules/highlightFilter/TreemapPart.js +2 -2
  209. package/src/modules/legend/HeatmapGradientLegend.js +76 -45
  210. package/src/modules/legend/Helpers.js +2 -0
  211. package/src/modules/legend/Legend.js +11 -12
  212. package/src/modules/settings/Options.js +7 -0
  213. package/src/modules/streamgraph/StreamLabels.js +1 -0
  214. package/src/modules/tooltip/Tooltip.js +20 -4
  215. package/src/modules/tooltip/Utils.js +8 -0
  216. package/src/modules/trellis/Trellis.js +6 -0
  217. package/src/modules/trellis/TrellisChrome.js +18 -7
  218. package/src/modules/trellis/TrellisSync.js +2 -0
  219. package/src/renderers/canvas/CanvasGraphics.js +1 -0
  220. package/src/ssr/DOMShim.js +10 -0
  221. package/src/types/internal.d.ts +9 -3
  222. package/types/apexcharts.d.ts +31 -12
@@ -33,10 +33,12 @@ import { avoidChromeOverlap } from './common/Breadcrumb'
33
33
  import {
34
34
  bandScale,
35
35
  farEdge,
36
+ focusByKey,
36
37
  focusChain,
37
38
  parseSize,
38
39
  placeTree,
39
40
  resolveFocus,
41
+ setZoomCursor,
40
42
  validateStrict,
41
43
  } from './common/partition/Partition'
42
44
  import { colorPass } from './common/partition/Tint'
@@ -129,15 +131,22 @@ export default class SunburstChart {
129
131
  (!w.config.chart.sparkline.enabled ? w.config.chart.dropShadow.blur : 0)
130
132
  if (this.maxRadius < 5) return g
131
133
 
132
- // Build + colour the hierarchy once (angles/radii are recomputed per zoom).
133
- this._roots = this._buildHierarchy()
134
+ // Build + colour the hierarchy once (angles/radii are recomputed per zoom),
135
+ // through the helpers shared with the treemap and icicle: a node's explicit
136
+ // `color` wins, else it takes its parent's tinted lighter.
137
+ this._roots = buildHierarchy(w)
134
138
  if (!this._roots.length) return g
135
- this._roots.forEach((r) => this._fillValues(r))
139
+ this._roots.forEach(fillValues)
136
140
  this._validateStrict()
137
141
  this._nodesAll = []
138
142
  const colors = w.globals.colors || []
139
143
  this._roots.forEach((r, i) => {
140
- this._colorPass(r, r.color || colors[i % colors.length] || '#008FFB')
144
+ colorPass(
145
+ r,
146
+ r.color || colors[i % colors.length] || '#008FFB',
147
+ this.cfg.tint,
148
+ this._nodesAll,
149
+ )
141
150
  })
142
151
  this.total = this._roots.reduce((s, r) => s + Math.max(0, r.value), 0) || 1
143
152
  this._tooltip.total = this.total
@@ -147,7 +156,12 @@ export default class SunburstChart {
147
156
  g.add(this._ringsG)
148
157
  g.add(this._labelsG)
149
158
 
150
- this._focus = null
159
+ // The focus outlives this instance by key (_relayout clears a stale one).
160
+ this._focus = focusByKey(
161
+ w.globals.sunburstFocusKey,
162
+ this._nodesAll,
163
+ this._roots,
164
+ )
151
165
  this._relayout(this._focus)
152
166
 
153
167
  // Same gating as Pie: angular clock-sweep intro on first render, a morph
@@ -158,7 +172,7 @@ export default class SunburstChart {
158
172
  let mode = 'none'
159
173
  if (anims.enabled) {
160
174
  if (w.globals.dataChanged) {
161
- if (anims.dynamicAnimation.enabled) mode = 'update'
175
+ if (w.globals.shouldAnimate !== false) mode = 'update'
162
176
  } else if (!w.globals.resized) {
163
177
  mode = 'intro'
164
178
  }
@@ -171,24 +185,6 @@ export default class SunburstChart {
171
185
 
172
186
  // ------------------------------------------------------------------ data
173
187
 
174
- /**
175
- * Resolve the config into root nodes `{ name, value, color?, children? }`.
176
- * Each datum may carry `children` (native) or `drilldown: '<id>'` (adapter).
177
- * Shared with the treemap - see charts/common/Hierarchy.
178
- * @returns {any[]}
179
- */
180
- _buildHierarchy() {
181
- return buildHierarchy(this.w)
182
- }
183
-
184
- /**
185
- * Fill a parent's value from its children when missing.
186
- * @param {any} node
187
- */
188
- _fillValues(node) {
189
- fillValues(node)
190
- }
191
-
192
188
  /**
193
189
  * With `partition: 'strict'`, warn (once) when a parent's value does not
194
190
  * match the sum of its children. The angles are still normalized to fill the
@@ -203,17 +199,6 @@ export default class SunburstChart {
203
199
  })
204
200
  }
205
201
 
206
- /**
207
- * Assign a colour to every node (explicit `color` wins, else the parent's
208
- * colour tinted lighter). Done once so zoom preserves colours.
209
- * Shared with the icicle - see charts/common/partition/Tint.
210
- * @param {any} node
211
- * @param {string} color
212
- */
213
- _colorPass(node, color) {
214
- colorPass(node, color, this.cfg.tint, this._nodesAll)
215
- }
216
-
217
202
  // ---------------------------------------------------------------- layout
218
203
 
219
204
  /**
@@ -221,6 +206,7 @@ export default class SunburstChart {
221
206
  * @param {any} focus
222
207
  */
223
208
  _relayout(focus) {
209
+ this.w.globals.sunburstFocusKey = focus && focus._key
224
210
  // The angular partition. `_t0`/`_t1` come back in degrees because that is
225
211
  // the interval handed in; the icicle passes pixels to the same recursion.
226
212
  this._focusMaxDepth = placeTree({
@@ -271,13 +257,15 @@ export default class SunburstChart {
271
257
  _applyLayout(mode) {
272
258
  const w = this.w
273
259
  const anims = w.config.chart.animations
274
- const dur = !anims.enabled
275
- ? 0
276
- : mode === 'none'
260
+ const dyn = anims.dynamicAnimation
261
+ const dur =
262
+ !anims.enabled || mode === 'none'
277
263
  ? 0
278
- : mode === 'update'
279
- ? anims.dynamicAnimation.speed || 350
280
- : anims.speed || 500
264
+ : mode === 'intro'
265
+ ? (anims.speed ?? 500)
266
+ : dyn.enabled
267
+ ? (dyn.speed ?? 350)
268
+ : 0
281
269
 
282
270
  // Supersede any in-flight zoom: stale frames from the previous pass check
283
271
  // this and stop, so a fast re-click can't leave two animations fighting.
@@ -299,10 +287,19 @@ export default class SunburstChart {
299
287
  const morphDur = morphActive ? morph.getSpeed() : 0
300
288
  this._morphLeafIndex = 0
301
289
 
302
- // Geometry of the PREVIOUS render (stashed on the persistent chart ctx —
303
- // this module is re-instantiated on every data update).
290
+ // The PREVIOUS render's nodes (stashed on the persistent chart ctx, as
291
+ // this module is re-instantiated on every data update), read live so an
292
+ // update landing mid-tween starts where each arc actually is.
304
293
  const prev =
305
294
  mode === 'update' ? /** @type {any} */ (this.ctx)._sunburstPrevGeoms : null
295
+ /** @param {any} n */
296
+ const geo = (n) =>
297
+ n._cur || { a0: n._t0, a1: n._t1, iR: n._iR, oR: n._oR }
298
+ /** @param {any} c the arc pinched to nothing at its mid angle */
299
+ const pinch = (c) => {
300
+ const m = (c.a0 + c.a1) / 2
301
+ return { a0: m, a1: m, iR: c.iR, oR: c.iR }
302
+ }
306
303
 
307
304
  this._nodesAll.forEach((node) => {
308
305
  if (node._show) {
@@ -313,6 +310,7 @@ export default class SunburstChart {
313
310
  oR: node._oR,
314
311
  }
315
312
  if (!node._el) node._el = this._createArcEl(node)
313
+ setZoomCursor(this, node)
316
314
 
317
315
  // Cross-type morph (treemap -> sunburst): a leaf starts as the tile
318
316
  // that stood for the same row and unrolls into its arc. Interior rings
@@ -325,36 +323,58 @@ export default class SunburstChart {
325
323
  } else if ((mode === 'intro' || morphActive) && dur > 0) {
326
324
  this._sweepArc(node, target, morphActive ? morphDur : dur, gen)
327
325
  } else {
328
- let from
329
- let isNew = false
330
- if (node._cur) {
331
- // `_cur` is the arc's LIVE geometry (updated each frame), so an
332
- // interrupted zoom continues smoothly from where it actually is.
333
- from = node._cur
334
- } else if (prev && prev.get(node._key)) {
335
- from = prev.get(node._key) // survived a data update: morph in place
336
- } else {
337
- const mid = (target.a0 + target.a1) / 2 // new arc: unfurl from its slot
338
- from = { a0: mid, a1: mid, iR: target.iR, oR: target.iR }
339
- isNew = true
340
- }
341
- // Only genuinely new arcs fade in; arcs morphing from a previous
342
- // geometry stay fully opaque while their shape tweens.
343
- this._animateArc(node, from, target, dur, false, isNew, gen)
326
+ const p = prev && prev.get(node._key)
327
+ // `_cur` is the arc's LIVE geometry (updated each frame), so an
328
+ // interrupted zoom continues smoothly from where it actually is; a
329
+ // survivor of a data update morphs in place; a new arc unfurls from
330
+ // its slot and is the only one that fades in.
331
+ const from = node._cur || (p ? geo(p) : pinch(target))
332
+ this._animateArc(node, from, target, dur, false, !node._cur && !p, gen)
344
333
  }
345
334
  } else if (node._el && node._cur) {
346
- const mid = (node._cur.a0 + node._cur.a1) / 2
347
- const target = { a0: mid, a1: mid, iR: node._cur.iR, oR: node._cur.iR }
348
- this._animateArc(node, node._cur, target, dur, true, false, gen)
335
+ this._animateArc(node, node._cur, pinch(node._cur), dur, true, false, gen)
349
336
  }
350
337
  })
351
338
 
339
+ // An arc the update dropped (or no longer places) collapses out with the
340
+ // morph, as a hidden one does, instead of vanishing at frame 0. The ghost
341
+ // joins _nodesAll (never shown), so a zoom or the next update picks it up
342
+ // mid-collapse like any other arc.
343
+ if (prev && dur && !morphActive) {
344
+ const keys = new Set(this._nodesAll.map((n) => n._show && n._key))
345
+ prev.forEach((/** @type {any} */ p, /** @type {string} */ k) => {
346
+ if (keys.has(k) || !(p._show || p._cur)) return
347
+ const el = this._graphics.drawPath({
348
+ fill: p._color,
349
+ stroke: this.strokeColor,
350
+ strokeWidth: this.strokeWidth,
351
+ classes: 'apexcharts-sunburst-arc',
352
+ })
353
+ el.node.setAttribute('data:name', p.name)
354
+ this._ringsG.add(el.attr({ opacity: p._el.attr('opacity') }))
355
+ const c = geo(p)
356
+ const g = { _el: el, _color: p._color, name: p.name, _key: k, _cur: c }
357
+ this._nodesAll.push(g)
358
+ this._animateArc(g, c, pinch(c), dur, true, false, gen)
359
+ })
360
+ }
361
+
362
+ // Over when the last arc lands (a newer layout takes that over), or now
363
+ // when nothing moves.
364
+ const end = Math.max(dur, morphDur)
365
+ if (end) {
366
+ this._ringsG.animate(end).after(() => {
367
+ if (this._zoomGen === gen && this._ringsG.node.isConnected)
368
+ new Animations(w, /** @type {any} */ (this.ctx)).animationCompleted(
369
+ this._ringsG.node,
370
+ )
371
+ })
372
+ } else w.globals.animationEnded = true
373
+
352
374
  // Stash what is now on screen so the NEXT data update can morph from it.
353
375
  const geoms = new Map()
354
376
  this._nodesAll.forEach((n) => {
355
- if (n._show) {
356
- geoms.set(n._key, { a0: n._t0, a1: n._t1, iR: n._iR, oR: n._oR })
357
- }
377
+ if (n._show || n._cur) geoms.set(n._key, n)
358
378
  })
359
379
  ;/** @type {any} */ (this.ctx)._sunburstPrevGeoms = geoms
360
380
 
@@ -480,11 +500,9 @@ export default class SunburstChart {
480
500
  */
481
501
  _createArcEl(node) {
482
502
  const path = this._graphics.drawPath({
483
- d: '',
484
503
  fill: node._color,
485
504
  stroke: this.strokeColor,
486
505
  strokeWidth: this.strokeWidth,
487
- fillOpacity: 1,
488
506
  classes: 'apexcharts-sunburst-arc',
489
507
  })
490
508
  const el = path.node
@@ -501,9 +519,8 @@ export default class SunburstChart {
501
519
  String(!(node.children && node.children.length)),
502
520
  )
503
521
  this._tooltip.attach(el, node)
504
- if (Environment.isBrowser()) {
522
+ if (Environment.isBrowser() && this.cfg.zoomOnClick !== false) {
505
523
  el.addEventListener('click', () => this._zoomTo(node))
506
- el.style.cursor = 'pointer'
507
524
  }
508
525
  this._ringsG.add(path)
509
526
  return path
@@ -579,11 +596,14 @@ export default class SunburstChart {
579
596
  this._renderCurvedLabel(node)
580
597
  })
581
598
 
599
+ // Gen-checked: a superseded zoom's fade must not reveal labels over arcs
600
+ // the newer zoom is still moving.
601
+ const gen = this._zoomGen
602
+ labelsG.attr({ opacity: dur > 0 ? 0 : 1 })
582
603
  if (dur > 0) {
583
- labelsG.attr({ opacity: 0 })
584
- labelsG.animate(250, dur).attr({ opacity: 1 })
585
- } else {
586
- labelsG.attr({ opacity: 1 })
604
+ labelsG.animate(250, dur).during((/** @type {number} */ p) => {
605
+ if (this._zoomGen === gen) labelsG.attr({ opacity: p })
606
+ })
587
607
  }
588
608
  }
589
609
 
@@ -593,11 +613,11 @@ export default class SunburstChart {
593
613
  * @param {any} node
594
614
  */
595
615
  _renderCurvedLabel(node) {
596
- if (!Environment.isBrowser()) return
597
616
  const style = this.cfg.dataLabels.style
598
617
  const w = this.w
599
618
  const r = (node._iR + node._oR) / 2
600
- const mid = (node._t0 + node._t1) / 2
619
+ // Normalised, so a negative or past-360 startAngle flips the same half.
620
+ const mid = ((((node._t0 + node._t1) / 2) % 360) + 360) % 360
601
621
  const flip = mid > 90 && mid < 270
602
622
 
603
623
  // Small angular padding so text does not touch the radial edges.
@@ -667,7 +687,7 @@ export default class SunburstChart {
667
687
  */
668
688
  _zoomTo(node) {
669
689
  if (this.cfg.zoomOnClick === false) return
670
- const next = resolveFocus(node, this._focus)
690
+ const next = resolveFocus(node, this._focus, this._roots)
671
691
  if (!next.changed) return
672
692
  this._focus = next.focus
673
693
  this._relayout(this._focus)
@@ -675,11 +695,6 @@ export default class SunburstChart {
675
695
  this._renderBreadcrumb()
676
696
  }
677
697
 
678
- /** Root -> focus chain of nodes. */
679
- _focusChain() {
680
- return focusChain(this._focus)
681
- }
682
-
683
698
  /**
684
699
  * Minimal self-contained breadcrumb (reuses the shared `.apexcharts-breadcrumb`
685
700
  * CSS classes, but does NOT depend on the drilldown feature).
@@ -702,7 +717,7 @@ export default class SunburstChart {
702
717
  nav.style.left = '0px'
703
718
 
704
719
  const crumbs = [{ name: 'All', node: null }].concat(
705
- this._focusChain().map((n) => ({ name: n.name, node: n })),
720
+ focusChain(this._focus).map((n) => ({ name: n.name, node: n })),
706
721
  )
707
722
 
708
723
  crumbs.forEach((crumb, i) => {
@@ -746,22 +761,10 @@ export default class SunburstChart {
746
761
  })
747
762
 
748
763
  elWrap.appendChild(nav)
749
- this._avoidChromeOverlap(nav)
750
- }
751
-
752
- /**
753
- * The breadcrumb is an absolute overlay at top-left, so it can sit on top of
754
- * a left-aligned title (or subtitle). After mounting, push it below any chart
755
- * chrome it intersects. (Duplicated from drilldown's Breadcrumb on purpose —
756
- * sunburst must not import the drilldown feature.)
757
- * @param {any} nav
758
- */
759
- /**
760
- * Shared with the treemap - see charts/common/Breadcrumb.
761
- * @param {any} nav
762
- */
763
- _avoidChromeOverlap(nav) {
764
- avoidChromeOverlap(this.w, nav)
764
+ // The breadcrumb is an absolute overlay at top-left: push it below any
765
+ // chart chrome it intersects (shared with the treemap, see
766
+ // charts/common/Breadcrumb).
767
+ avoidChromeOverlap(w, nav)
765
768
  }
766
769
 
767
770
  // ------------------------------------------------------------ geometry