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
@@ -57,6 +57,18 @@ function withFills(from, to, fillWas, fillNow) {
57
57
  return [from, to]
58
58
  }
59
59
 
60
+ /**
61
+ * Whether the treemap draws parent containers. Opt-out, but only for data
62
+ * authored with `children`: a flat treemap keeps drawing exactly what it
63
+ * always drew. Reads the tree Data stashed at parse time, so the layout can
64
+ * ask before the renderer runs.
65
+ * @param {any} w
66
+ */
67
+ const showsParents = (w) => {
68
+ const show = w.config.plotOptions.treemap.parents.show
69
+ return show === true || (show !== false && !!w.globals.treemapRoots?.length)
70
+ }
71
+
60
72
  const headerLook = (/** @type {Element | null | undefined} */ el) =>
61
73
  Series.treemapHeaderLook(el)
62
74
 
@@ -84,7 +96,6 @@ export default class TreemapChart {
84
96
  // Nested state, all resolved per draw.
85
97
  /** @type {any[]} */ this.roots = []
86
98
  /** @type {any[]} */ this.drawn = []
87
- /** @type {boolean} */ this.nested = false
88
99
  /** @type {boolean} */ this.showParents = false
89
100
  /** @type {any} */ this.scale = null
90
101
  /** @type {any[]|null} */ this._levelCache = null
@@ -133,7 +144,6 @@ export default class TreemapChart {
133
144
  // same recursion the nested case uses; with no padding and no headers that
134
145
  // reduces to exactly the two-level squarify it always was.
135
146
  const tree = getTreemapRoots(w)
136
- this.nested = tree.nested
137
147
  this.roots = tree.roots
138
148
  this.scale = buildContinuousScale(w)
139
149
 
@@ -147,10 +157,7 @@ export default class TreemapChart {
147
157
  // Parent containers are opt-out, but only appear at all when the data was
148
158
  // authored with `children`. A flat treemap must keep drawing exactly what
149
159
  // it always drew, with `seriesTitle` as its only group chrome.
150
- const parentsCfg = w.config.plotOptions.treemap.parents
151
- this.showParents =
152
- parentsCfg.show === true ||
153
- (parentsCfg.show !== false && this.nested)
160
+ this.showParents = showsParents(w)
154
161
 
155
162
  // Click-to-zoom: everything outside the focused branch is left out of the
156
163
  // layout entirely, so the focused group gets the whole canvas.
@@ -208,7 +215,7 @@ export default class TreemapChart {
208
215
  if (w.config.chart.dropShadow.enabled) {
209
216
  const shadow = w.config.chart.dropShadow
210
217
  const filters = new Filters(this.w)
211
- filters.dropShadow(ret, shadow, i)
218
+ filters.dropShadow(elSeries, shadow, i)
212
219
  }
213
220
 
214
221
  const elDataLabelWrap = graphics.group({
@@ -353,6 +360,10 @@ export default class TreemapChart {
353
360
  // See Sunburst: the branch identity a cross-type morph pairs on.
354
361
  elRect.node.setAttribute('data:key', morphKey(leaf._key))
355
362
 
363
+ // The tile's tween (mount grow or data change), which its label
364
+ // rides, and the centre the label rides from (null: it fades in).
365
+ /** @type {any} */
366
+ let tileTween = null
356
367
  let fromRect = {
357
368
  x: x1 + (x2 - x1) / 2,
358
369
  y: y1 + (y2 - y1) / 2,
@@ -390,7 +401,7 @@ export default class TreemapChart {
390
401
  // delay, so they popped in one after another.
391
402
  w.globals.animationEnded = true
392
403
  } else {
393
- this.animateTreemap(
404
+ tileTween = this.animateTreemap(
394
405
  elRect,
395
406
  fromRect,
396
407
  toRect,
@@ -401,10 +412,6 @@ export default class TreemapChart {
401
412
  )
402
413
  }
403
414
  }
404
- // A data change's tile tween, which the tile's label rides, and the
405
- // centre the label rides from (null for a tile the update adds).
406
- /** @type {any} */
407
- let tileTween = null
408
415
  /** @type {{x: number, y: number} | null} */
409
416
  let labelFrom = null
410
417
  // What the tile's label showed before ('' for none, null when not
@@ -516,7 +523,8 @@ export default class TreemapChart {
516
523
  dataLabels.node.setAttribute('data:key', morphKey(leaf._key))
517
524
  elSeries.add(dataLabels)
518
525
  // The label rides its tile from the old centre, on the tile's own
519
- // tween; a tile the update adds fades its label in as it grows.
526
+ // tween; a tile that mounts or the update adds fades its label in
527
+ // as it grows.
520
528
  // It used to sit at its final spot from the first frame, over
521
529
  // whatever tile was still there.
522
530
  if (tileTween) {
@@ -879,7 +887,7 @@ export default class TreemapChart {
879
887
  const elGroup = graphics.group({
880
888
  class: 'apexcharts-treemap-parent',
881
889
  'data:depth': depth,
882
- 'data:name': Utils.escapeString(node.name),
890
+ 'data:name': node.name,
883
891
  })
884
892
 
885
893
  // Cross-type morph: with branch keys on both sides, a container unrolls
@@ -1032,7 +1040,7 @@ export default class TreemapChart {
1032
1040
  if (typeof header.formatter === 'function') {
1033
1041
  text = String(
1034
1042
  header.formatter(node.name, {
1035
- value: node.value,
1043
+ value: node._area,
1036
1044
  depth,
1037
1045
  seriesIndex: i,
1038
1046
  node,
@@ -1040,7 +1048,7 @@ export default class TreemapChart {
1040
1048
  }),
1041
1049
  )
1042
1050
  } else if (header.showValue) {
1043
- text = `${text} ${this._formatValue(node.value)}`
1051
+ text = `${text} ${this._formatValue(node._area, node._si)}`
1044
1052
  }
1045
1053
  headerText = text
1046
1054
 
@@ -1053,6 +1061,8 @@ export default class TreemapChart {
1053
1061
  text,
1054
1062
  maxWidth,
1055
1063
  fontSize,
1064
+ fontFamily: chrome.headerFontFamily,
1065
+ fontWeight: chrome.headerFontWeight,
1056
1066
  })
1057
1067
 
1058
1068
  if (clipped) {
@@ -1158,7 +1168,7 @@ export default class TreemapChart {
1158
1168
  const lead =
1159
1169
  visibleText && String(visibleText).trim()
1160
1170
  ? String(visibleText).replace(/\s+/g, ' ').trim()
1161
- : `${node.name}, ${this._formatValue(node._area)}`
1171
+ : `${node.name}, ${this._formatValue(node._area, node._si)}`
1162
1172
  return `${lead}, ${n} ${n === 1 ? 'item' : 'items'}, ${pct}% of total`
1163
1173
  }
1164
1174
 
@@ -1178,17 +1188,21 @@ export default class TreemapChart {
1178
1188
  * @param {string} [visibleText] the header's rendered text, unclipped
1179
1189
  */
1180
1190
  _makeParentAccessible(el, node, chrome, elRect, visibleText) {
1191
+ const a11y = this.w.config.chart.accessibility
1181
1192
  if (!el || !el.setAttribute) return
1182
- if (!this._zoomEnabled()) return
1193
+ if (!a11y.enabled || !a11y.keyboard.enabled || !this._zoomEnabled()) return
1183
1194
 
1195
+ // The focused branch's strip zooms back out.
1196
+ const open = this.w.globals.treemapFocusKey === node._key
1197
+ el.tmKey = node._key
1184
1198
  el.setAttribute('role', 'button')
1185
1199
  el.setAttribute('tabindex', '0')
1186
1200
  el.setAttribute(
1187
1201
  'aria-label',
1188
- `${this._parentLabel(node, visibleText)}. Zoom in`,
1202
+ `${this._parentLabel(node, visibleText)}. Zoom ${open ? 'out' : 'in'}`,
1189
1203
  )
1190
1204
  // The strip is the affordance, and it labels the group it opens.
1191
- el.setAttribute('aria-expanded', 'false')
1205
+ el.setAttribute('aria-expanded', open)
1192
1206
 
1193
1207
  if (!Environment.isBrowser() || !el.addEventListener) return
1194
1208
 
@@ -1262,39 +1276,47 @@ export default class TreemapChart {
1262
1276
  * Active means the feature is loaded as well as configured: without it the
1263
1277
  * click navigates nowhere (the chart warns about the missing feature), so
1264
1278
  * standing zoom down too would leave the click doing nothing at all.
1265
- * @returns {boolean}
1279
+ *
1280
+ * Reads only `w`, so the layout, which runs before this renderer, asks it
1281
+ * through the type registry (`prototype.zoomLive`) and reserves the
1282
+ * breadcrumb band on the same answer: a flat treemap, with no parents to
1283
+ * click, used to keep an empty band. Not a static: one on this class cost
1284
+ * the default bundle about 290 B gzip.
1285
+ * @param {any} w
1286
+ * @param {any} drilldown the chart's drilldown feature, when loaded
1287
+ * @returns {any} the zoom config when live, null when drilldown is what
1288
+ * stands it down, else false
1266
1289
  */
1267
- _zoomEnabled() {
1268
- const w = this.w
1290
+ zoomLive(w, drilldown) {
1269
1291
  const z = w.config.plotOptions.treemap.zoom
1270
- if (!z || !z.enabled || !this.showParents) return false
1271
-
1292
+ if (!z?.enabled || !showsParents(w)) return false
1293
+ // An `onDrillDown` resolver drills on every click, so it counts too.
1272
1294
  const dd = w.config.drilldown
1273
- if (
1274
- this.ctx.drilldown &&
1275
- dd &&
1276
- dd.enabled &&
1277
- Array.isArray(dd.series) &&
1278
- dd.series.length
1279
- ) {
1280
- if (!this._warnedZoomConflict) {
1281
- this._warnedZoomConflict = true
1282
- console.warn(
1283
- 'ApexCharts treemap: `plotOptions.treemap.zoom` and the drilldown ' +
1284
- 'feature both navigate the hierarchy, so zoom is ignored here. ' +
1285
- 'Drop `drilldown.series` to zoom a nested treemap instead.',
1286
- )
1287
- }
1288
- return false
1295
+ return drilldown && dd?.enabled && (dd.series?.length || dd.onDrillDown)
1296
+ ? null
1297
+ : z
1298
+ }
1299
+
1300
+ /** @returns {boolean} */
1301
+ _zoomEnabled() {
1302
+ // The warned flag lives on the drilldown instance, which outlives a render.
1303
+ const d = this.ctx.drilldown
1304
+ const live = this.zoomLive(this.w, d)
1305
+ if (live === null && !d.zoomWarned) {
1306
+ d.zoomWarned = true
1307
+ console.warn(
1308
+ 'ApexCharts treemap: zoom is ignored while drilldown is active ' +
1309
+ '(plotOptions.treemap.zoom vs drilldown series or onDrillDown).',
1310
+ )
1289
1311
  }
1290
- return true
1312
+ return !!live
1291
1313
  }
1292
1314
 
1293
1315
  /**
1294
1316
  * The focused branch for this render, looked up by the key stashed on the
1295
1317
  * last click. Keys are rebuilt identically from the same data, so the focus
1296
- * survives a re-render; a key that no longer resolves (the data changed under
1297
- * it) simply falls back to the whole tree.
1318
+ * survives a re-render; a key that no longer resolves, or a branch left with
1319
+ * nothing to draw (the data changed under it), falls back to the whole tree.
1298
1320
  * @param {any[]} drawn
1299
1321
  * @returns {any}
1300
1322
  */
@@ -1314,7 +1336,16 @@ export default class TreemapChart {
1314
1336
  }
1315
1337
  drawn.forEach(walk)
1316
1338
  // Only a branch can be focused; a leaf has nothing to zoom into.
1317
- return found && found.children && found.children.length ? found : null
1339
+ if (
1340
+ found &&
1341
+ found.children &&
1342
+ found.children.length &&
1343
+ this._subtreeArea(found) > 0
1344
+ ) {
1345
+ return found
1346
+ }
1347
+ this.w.globals.treemapFocusKey = null
1348
+ return null
1318
1349
  }
1319
1350
 
1320
1351
  /**
@@ -1328,30 +1359,7 @@ export default class TreemapChart {
1328
1359
  const w = this.w
1329
1360
  if (!node || !node.children || !node.children.length) return
1330
1361
  const next = w.globals.treemapFocusKey === node._key ? null : node._key
1331
- const done = this._refocus(next)
1332
- if (!restoreFocus || !done || typeof done.then !== 'function') return
1333
- done.then(() => {
1334
- if (!Environment.isBrowser()) return
1335
- // The breadcrumb is where you are and how you get back, so it is the
1336
- // right landing spot after the view changes under you.
1337
- const crumb = /** @type {any} */ (
1338
- w.dom.baseEl.querySelector(
1339
- '.apexcharts-breadcrumb .apexcharts-breadcrumb-item',
1340
- )
1341
- )
1342
- if (crumb && crumb.focus) {
1343
- crumb.focus()
1344
- return
1345
- }
1346
- // Zoomed all the way back out: no breadcrumb, so return to the strip of
1347
- // the group that was just closed.
1348
- const header = /** @type {any} */ (
1349
- w.dom.baseEl.querySelector(
1350
- '.apexcharts-treemap-parent-header[tabindex]',
1351
- )
1352
- )
1353
- if (header && header.focus) header.focus()
1354
- })
1362
+ this._refocus(next, restoreFocus)
1355
1363
  }
1356
1364
 
1357
1365
  /**
@@ -1363,16 +1371,17 @@ export default class TreemapChart {
1363
1371
  * left, which replayed the mount animation (every tile growing from
1364
1372
  * nothing) or snapped, while the containers, headers and labels jumped.
1365
1373
  * @param {string | null} next
1366
- * @returns {any} the update's promise
1374
+ * @param {boolean} [restoreFocus] see _zoomTo
1367
1375
  */
1368
- _refocus(next) {
1376
+ _refocus(next, restoreFocus) {
1369
1377
  const w = this.w
1370
1378
  const gl = w.globals
1379
+ const from = gl.treemapFocusKey
1371
1380
  const anim = w.config.chart.animations
1372
1381
  const animate = !!(anim.enabled && anim.dynamicAnimation.enabled)
1373
1382
  gl.treemapZoom =
1374
1383
  animate && Environment.isBrowser()
1375
- ? { from: gl.treemapFocusKey ?? null, to: next }
1384
+ ? { from: from ?? null, to: next }
1376
1385
  : null
1377
1386
  gl.treemapFocusKey = next
1378
1387
  this._hideParentTooltip()
@@ -1380,7 +1389,27 @@ export default class TreemapChart {
1380
1389
  gl.resized = true
1381
1390
  gl.dataChanged = true
1382
1391
  if (gl.treemapZoom) this.ctx.series.getPreviousPaths()
1383
- return this.ctx.update()
1392
+ const done = this.ctx.update()
1393
+ if (restoreFocus) {
1394
+ done.then(() => {
1395
+ const b = w.dom.baseEl
1396
+ const heads = /** @type {any[]} */ (
1397
+ Array.from(
1398
+ b.querySelectorAll('.apexcharts-treemap-parent-header[tabindex]'),
1399
+ )
1400
+ )
1401
+ // The breadcrumb is where you are and how you get back, so it is the
1402
+ // right landing spot after the view changes under you. Zoomed all the
1403
+ // way back out there is none: return to the strip of the group that
1404
+ // was just closed.
1405
+ ;(
1406
+ b.querySelector('.apexcharts-breadcrumb-item') ||
1407
+ heads.find((h) => h.tmKey === from) ||
1408
+ heads[0] ||
1409
+ b
1410
+ ).focus()
1411
+ })
1412
+ }
1384
1413
  }
1385
1414
 
1386
1415
  /**
@@ -1756,8 +1785,9 @@ export default class TreemapChart {
1756
1785
  crumbs: [{ label: 'All', data: null }].concat(
1757
1786
  chain.map((/** @type {any} */ n) => ({ label: n.name, data: n })),
1758
1787
  ),
1759
- onNavigate: (_i, crumb) => {
1760
- this._refocus(crumb.data ? crumb.data._key : null)
1788
+ // A keyboard click (detail 0) keeps focus in the chart.
1789
+ onNavigate: (_i, crumb, e) => {
1790
+ this._refocus(crumb.data ? crumb.data._key : null, !e.detail)
1761
1791
  },
1762
1792
  })
1763
1793
  if (!nav) return
@@ -1776,6 +1806,9 @@ export default class TreemapChart {
1776
1806
  * that grows the font - where a readable chip over the tiles beats a
1777
1807
  * breadcrumb clipped by the plot.
1778
1808
  *
1809
+ * Breadcrumb.placeInReservedBand does the same plus a y-axis label ceiling
1810
+ * a treemap has no use for, which would cost the default bundle its bytes.
1811
+ *
1779
1812
  * @param {any} nav
1780
1813
  */
1781
1814
  _placeBreadcrumb(nav) {
@@ -1788,12 +1821,13 @@ export default class TreemapChart {
1788
1821
  : 0
1789
1822
 
1790
1823
  const navH = nav.getBoundingClientRect().height || BREADCRUMB_HEIGHT
1824
+ const oy = this._breadcrumbCfg().offsetY || 0
1791
1825
  if (gridTop - titleArea >= navH + 1) {
1792
- nav.style.top = `${gridTop - navH - 1}px`
1826
+ nav.style.top = `${gridTop - navH - 1 + oy}px`
1793
1827
  return
1794
1828
  }
1795
1829
 
1796
- nav.style.top = `${titleArea}px`
1830
+ nav.style.top = `${titleArea + oy}px`
1797
1831
  const dark = w.config.theme.mode === 'dark'
1798
1832
  nav.style.background = dark
1799
1833
  ? 'rgba(20,24,30,0.82)'
@@ -1817,7 +1851,8 @@ export default class TreemapChart {
1817
1851
  if (!t) return
1818
1852
 
1819
1853
  const total = this._drawnTotal()
1820
- const parentVal = node._parent ? node._parent._area : total
1854
+ // A zoom lays out only the focus, so the parent may have no _area.
1855
+ const parentVal = node._parent ? this._subtreeArea(node._parent) : total
1821
1856
  const pctTotal = total > 0 ? ((node._area / total) * 100).toFixed(1) : '0.0'
1822
1857
  const pctParent =
1823
1858
  parentVal > 0 ? ((node._area / parentVal) * 100).toFixed(1) : pctTotal
@@ -1843,15 +1878,18 @@ export default class TreemapChart {
1843
1878
  const groupBg = w.config.tooltip.fillSeriesColor
1844
1879
  ? `background-color:${marker};`
1845
1880
  : ''
1881
+ // The name sits in element text, where escaping & and < is enough to
1882
+ // keep markup in data inert. What a formatter returns is markup.
1846
1883
  html =
1847
1884
  `<div class="apexcharts-tooltip-series-group apexcharts-active" style="display:flex;${groupBg}">` +
1848
1885
  `<div class="apexcharts-tooltip-text">` +
1849
1886
  `<div class="apexcharts-tooltip-y-group">` +
1850
- `<span class="apexcharts-tooltip-text-y-label">${Utils.escapeString(
1851
- node.name,
1852
- )}: </span>` +
1887
+ `<span class="apexcharts-tooltip-text-y-label">${String(node.name)
1888
+ .replace(/&/g, '&amp;')
1889
+ .replace(/</g, '&lt;')}: </span>` +
1853
1890
  `<span class="apexcharts-tooltip-text-y-value">${this._formatValue(
1854
1891
  node._area,
1892
+ node._si,
1855
1893
  )}</span>` +
1856
1894
  `</div>` +
1857
1895
  `<div class="apexcharts-tooltip-y-group">` +
@@ -1966,16 +2004,20 @@ export default class TreemapChart {
1966
2004
 
1967
2005
  /**
1968
2006
  * Format an aggregate the way the chart formats its own y values, so a
1969
- * parent's total reads like the tiles it contains.
2007
+ * parent's total reads like the tiles it contains. A branch is no data
2008
+ * point, so dataPointIndex is -1.
1970
2009
  * @param {number} v
2010
+ * @param {number} [si] the branch's series index
1971
2011
  * @returns {string}
1972
2012
  */
1973
- _formatValue(v) {
2013
+ _formatValue(v, si) {
1974
2014
  const w = this.w
1975
2015
  const fmt = w.config.tooltip?.y?.formatter || w.config.yaxis?.[0]?.labels?.formatter
1976
2016
  if (typeof fmt === 'function') {
1977
2017
  try {
1978
- return String(fmt(v, { seriesIndex: 0, dataPointIndex: 0, w }))
2018
+ return String(
2019
+ fmt(v, { seriesIndex: si || 0, dataPointIndex: -1, w }),
2020
+ )
1979
2021
  } catch (_) {
1980
2022
  // A formatter written for leaf rows may expect fields a parent
1981
2023
  // aggregate has no equivalent of; fall through to the plain number.
@@ -2073,7 +2115,7 @@ export default class TreemapChart {
2073
2115
  */
2074
2116
  rotateToFitLabel(elText, fontSize, text, x1, y1, x2, y2) {
2075
2117
  const graphics = new Graphics(this.w)
2076
- const textRect = graphics.getTextRects(text, String(fontSize))
2118
+ const textRect = this._labelRect(graphics, text, fontSize)
2077
2119
 
2078
2120
  // if the label fits better sideways then rotate it
2079
2121
  if (
@@ -2091,6 +2133,25 @@ export default class TreemapChart {
2091
2133
  }
2092
2134
  }
2093
2135
 
2136
+ /**
2137
+ * A tile label's box, measured at the family and weight it is drawn at
2138
+ * (bold is wider than the default regular).
2139
+ * @param {Graphics} graphics
2140
+ * @param {string} text
2141
+ * @param {string | number} fontSize
2142
+ */
2143
+ _labelRect(graphics, text, fontSize) {
2144
+ const st = this.w.config.dataLabels.style
2145
+ return graphics.getTextRects(
2146
+ text,
2147
+ String(fontSize),
2148
+ st.fontFamily,
2149
+ '',
2150
+ true,
2151
+ st.fontWeight,
2152
+ )
2153
+ }
2154
+
2094
2155
  // This is an alternative label formatting method that uses a
2095
2156
  // consistent font size, and trims the edge of long labels
2096
2157
  /**
@@ -2103,7 +2164,7 @@ export default class TreemapChart {
2103
2164
  */
2104
2165
  truncateLabels(text, fontSize, x1, y1, x2, y2) {
2105
2166
  const graphics = new Graphics(this.w)
2106
- const textRect = graphics.getTextRects(text, String(fontSize))
2167
+ const textRect = this._labelRect(graphics, text, fontSize)
2107
2168
 
2108
2169
  // Determine max width based on ideal orientation of text
2109
2170
  const labelMaxWidth =
@@ -2112,9 +2173,10 @@ export default class TreemapChart {
2112
2173
  ? y2 - y1
2113
2174
  : x2 - x1
2114
2175
  const truncatedText = graphics.getTextBasedOnMaxWidth({
2115
- text: text,
2176
+ ...this.w.config.dataLabels.style,
2177
+ text,
2116
2178
  maxWidth: labelMaxWidth,
2117
- fontSize: fontSize,
2179
+ fontSize,
2118
2180
  })
2119
2181
 
2120
2182
  // Return empty label when text has been trimmed for very small rects