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
@@ -457,6 +457,23 @@ class Graphics {
457
457
  return arc
458
458
  }
459
459
 
460
+ /**
461
+ * stroke.dashArray of a series, shared with the canvas renderer. A plugin
462
+ * may have claimed it: resolved here rather than written into the config,
463
+ * so the caller's own dashing is untouched and there is nothing to restore
464
+ * when the claim goes. See weave/Claims.
465
+ * @param {number} realIndex
466
+ */
467
+ seriesDash(realIndex) {
468
+ const d = this.w.config.stroke.dashArray
469
+ return resolveClaimed(
470
+ this.w,
471
+ 'stroke.dashArray',
472
+ realIndex,
473
+ Array.isArray(d) ? d[realIndex] : d,
474
+ )
475
+ }
476
+
460
477
  /**
461
478
  * @memberof Graphics
462
479
  * @param {Record<string, any>} opts
@@ -610,23 +627,6 @@ class Graphics {
610
627
  }
611
628
  }
612
629
 
613
- const strokeDashArrayOpt = w.config.stroke.dashArray
614
- let strokeDashArray = 0
615
- if (Array.isArray(strokeDashArrayOpt)) {
616
- strokeDashArray = strokeDashArrayOpt[realIndex]
617
- } else {
618
- strokeDashArray = w.config.stroke.dashArray
619
- }
620
- // A plugin may have claimed this series' dash. Resolved here rather than
621
- // written into the config above, so the caller's own dashing is untouched
622
- // and there is nothing to restore when the claim goes. See weave/Claims.
623
- strokeDashArray = resolveClaimed(
624
- w,
625
- 'stroke.dashArray',
626
- realIndex,
627
- strokeDashArray,
628
- )
629
-
630
630
  const el = this.drawPath({
631
631
  d,
632
632
  stroke,
@@ -635,7 +635,7 @@ class Graphics {
635
635
  fillOpacity: 1,
636
636
  classes: className,
637
637
  strokeLinecap,
638
- strokeDashArray,
638
+ strokeDashArray: this.seriesDash(realIndex),
639
639
  })
640
640
 
641
641
  el.attr('index', realIndex)
@@ -718,11 +718,16 @@ class Graphics {
718
718
  // Skip the immediate reveal when we're fading in via revealBulk — it owns
719
719
  // the reveal (a single scheduled rAF), so revealing here would pre-empt it.
720
720
  // An update that does not animate has no completion to reveal them at,
721
- // so it reveals them now.
721
+ // so it reveals them now. Only when something was registered since the
722
+ // last reveal: the list is new each render, and walking it again for
723
+ // every bar is a no-op that grew as bars x overlays.
724
+ const de = /** @type {any} */ (w.globals.delayedElements)
722
725
  if (
723
726
  (w.globals.resized || !w.globals.dataChanged || !shouldAnimate) &&
724
- !revealViaFade
727
+ !revealViaFade &&
728
+ de.shown !== de.length
725
729
  ) {
730
+ de.shown = de.length
726
731
  anim.showDelayedElements()
727
732
  }
728
733
  }
@@ -935,13 +940,21 @@ class Graphics {
935
940
  return g
936
941
  }
937
942
 
938
- /** @param {{ text: any, maxWidth: any, fontSize: any, fontFamily?: any }} opts */
939
- getTextBasedOnMaxWidth({ text, maxWidth, fontSize, fontFamily }) {
940
- const tRects = this.getTextRects(text, fontSize, fontFamily, '')
941
- const wordWidth = tRects.width / text.length
942
- const wordsBasedOnWidth = Math.floor(maxWidth / wordWidth)
943
+ /** @param {{ text: any, maxWidth: any, fontSize: any, fontFamily?: any, fontWeight?: any }} opts */
944
+ getTextBasedOnMaxWidth({ text, maxWidth, fontSize, fontFamily, fontWeight }) {
945
+ const tRects = this.getTextRects(
946
+ text,
947
+ fontSize,
948
+ fontFamily,
949
+ '',
950
+ true,
951
+ fontWeight,
952
+ )
953
+ // Characters that fit, less the ellipsis. Below zero not even '...'
954
+ // fits (and a negative slice end would keep nearly the whole text).
955
+ const n = Math.floor(maxWidth / (tRects.width / text.length)) - 3
943
956
  if (maxWidth < tRects.width) {
944
- return text.slice(0, wordsBasedOnWidth - 3) + '...'
957
+ return n < 0 ? '' : text.slice(0, n) + '...'
945
958
  }
946
959
  return text
947
960
  }
@@ -984,6 +997,7 @@ class Graphics {
984
997
  maxWidth,
985
998
  fontSize,
986
999
  fontFamily,
1000
+ fontWeight,
987
1001
  }
988
1002
  let elText
989
1003
  if (Array.isArray(text)) {
@@ -1226,7 +1240,12 @@ class Graphics {
1226
1240
  if (w.config.states.hover.filter.type !== 'none') {
1227
1241
  if (!w.interact.isTouchDevice) {
1228
1242
  const hoverFilter = w.config.states.hover.filter
1229
- filters.applyFilter(path, i, hoverFilter.type, hoverFilter.value)
1243
+ filters.applyFilter(
1244
+ path,
1245
+ Filters.isSliceChart(w) ? j : i,
1246
+ hoverFilter.type,
1247
+ hoverFilter.value,
1248
+ )
1230
1249
  }
1231
1250
  }
1232
1251
  }
@@ -1267,35 +1286,29 @@ class Graphics {
1267
1286
  if (Filters.hoverOutlineOwnsHoverState(w)) return
1268
1287
 
1269
1288
  if (w.config.states.hover.filter.type !== 'none') {
1270
- filters.getDefaultFilter(path, i)
1289
+ filters.getDefaultFilter(path, Filters.isSliceChart(w) ? j : i)
1271
1290
  }
1272
1291
  }
1273
1292
 
1274
1293
  /**
1275
1294
  * Clear every selected data point (single-select mode): reset the selection
1276
- * array and restore the default filter on all series path/circle/rect nodes.
1277
- * NOTE: preserves the original behavior of passing the clicked series index
1278
- * `i` to getDefaultFilter for every element (not each element's own index).
1279
- * @param {any} filters @param {number} i
1295
+ * array and restore the default filter on each selected node, with its own
1296
+ * series index (dropShadow.enabledOnSeries is per series; a pie slice's
1297
+ * shadow is per slice, j).
1298
+ * @param {any} filters
1280
1299
  */
1281
- _clearAllDataPointSelections(filters, i) {
1300
+ _clearAllDataPointSelections(filters) {
1282
1301
  const w = this.w
1283
1302
  w.interact.selectedDataPoints = []
1284
- const elPaths = w.dom.Paper.find(
1285
- '.apexcharts-series path:not(.apexcharts-decoration-element)',
1286
- )
1287
- const elCircles = w.dom.Paper.find(
1288
- '.apexcharts-series circle:not(.apexcharts-decoration-element), .apexcharts-series rect:not(.apexcharts-decoration-element)',
1289
- )
1290
- /** @param {any[]} els */
1291
- const deSelect = (els) => {
1292
- Array.prototype.forEach.call(els, (/** @type {any} */ el) => {
1303
+ w.dom.Paper.find('.apexcharts-series [selected="true"]').forEach(
1304
+ (/** @type {any} */ el) => {
1293
1305
  el.node.setAttribute('selected', 'false')
1294
- filters.getDefaultFilter(el, i)
1295
- })
1296
- }
1297
- deSelect(elPaths)
1298
- deSelect(elCircles)
1306
+ filters.getDefaultFilter(
1307
+ el,
1308
+ +el.node.getAttribute(Filters.isSliceChart(w) ? 'j' : 'index'),
1309
+ )
1310
+ },
1311
+ )
1299
1312
  }
1300
1313
 
1301
1314
  /**
@@ -1321,7 +1334,7 @@ class Graphics {
1321
1334
  !w.config.states.active.allowMultipleDataPointsSelection &&
1322
1335
  w.interact.selectedDataPoints.length > 0
1323
1336
  ) {
1324
- this._clearAllDataPointSelections(filters, i)
1337
+ this._clearAllDataPointSelections(filters)
1325
1338
  }
1326
1339
 
1327
1340
  path.node.setAttribute('selected', 'true')
@@ -1350,11 +1363,11 @@ class Graphics {
1350
1363
 
1351
1364
  if (selected === 'true') {
1352
1365
  const activeFilter = w.config.states.active.filter
1353
- if (activeFilter !== 'none') {
1366
+ if (activeFilter.type !== 'none') {
1354
1367
  filters.applyFilter(path, i, activeFilter.type, activeFilter.value)
1355
1368
  } else {
1356
1369
  // Reapply the hover filter in case it was removed by `deselect`when there is no active filter and it is not a touch device
1357
- if (w.config.states.hover.filter !== 'none') {
1370
+ if (w.config.states.hover.filter.type !== 'none') {
1358
1371
  if (!w.interact.isTouchDevice) {
1359
1372
  const hoverFilter = w.config.states.hover.filter
1360
1373
  filters.applyFilter(path, i, hoverFilter.type, hoverFilter.value)
@@ -1404,7 +1417,12 @@ class Graphics {
1404
1417
 
1405
1418
  if (!crossfilterClick) {
1406
1419
  const selected = this._togglePointSelection(path, filters, i, j)
1407
- this._applyPointSelectionFilter(path, filters, i, selected)
1420
+ this._applyPointSelectionFilter(
1421
+ path,
1422
+ filters,
1423
+ Filters.isSliceChart(w) ? j : i,
1424
+ selected,
1425
+ )
1408
1426
  }
1409
1427
 
1410
1428
  if (typeof w.config.chart.events.dataPointSelection === 'function') {
@@ -143,8 +143,10 @@ export default class Markers {
143
143
  setGlobalMarkerSize() {
144
144
  const w = this.w
145
145
 
146
+ // A copy: the padding below must not grow (or throw on a frozen) caller
147
+ // array.
146
148
  w.globals.markers.size = Array.isArray(w.config.markers.size)
147
- ? w.config.markers.size
149
+ ? w.config.markers.size.slice()
148
150
  : [w.config.markers.size]
149
151
 
150
152
  if (w.globals.markers.size.length > 0) {
@@ -685,7 +685,7 @@ export default class MorphTypeChange {
685
685
  !svg ||
686
686
  typeof svg.createSVGPoint !== 'function'
687
687
  ) {
688
- layer.removeChild(probe)
688
+ probe.remove()
689
689
  return null
690
690
  }
691
691
  const pt = svg.createSVGPoint()
@@ -694,10 +694,8 @@ export default class MorphTypeChange {
694
694
  pt.x = x
695
695
  pt.y = y
696
696
  const p = /** @type {any} */ (probe)
697
- return (
698
- p.isPointInFill(pt) ||
699
- (typeof p.isPointInStroke === 'function' && p.isPointInStroke(pt))
700
- )
697
+ // isPointInStroke shipped with isPointInFill, which was checked above.
698
+ return p.isPointInFill(pt) || p.isPointInStroke(pt)
701
699
  }
702
700
 
703
701
  // Samples across the minor axis per probe line. Fine enough to catch a
@@ -829,6 +827,10 @@ export default class MorphTypeChange {
829
827
  /** @type {import('./MorphPieces').Piece[]} */
830
828
  const pieces = []
831
829
  const doc = layer.ownerDocument
830
+ // Cells are staged off the page and land in one write after the loop: a
831
+ // probe hit-test brings style and layout up to date, so cells written
832
+ // between two marks' probes would make every later probe pay for them.
833
+ const staged = doc.createDocumentFragment()
832
834
 
833
835
  // A bar IS its bounding box, so the plain grid tiles it exactly. A
834
836
  // summary mark (violin, boxPlot) is a silhouette inside its box, and
@@ -887,7 +889,7 @@ export default class MorphTypeChange {
887
889
  el.setAttribute('height', String(cell.height))
888
890
  el.setAttribute('rx', '0')
889
891
  el.setAttribute('fill', String(markFill))
890
- layer.appendChild(el)
892
+ staged.appendChild(el)
891
893
  pieces.push({
892
894
  el,
893
895
  from: { x: cell.x, y: cell.y, width: cell.width, height: cell.height, rx: 0 },
@@ -905,6 +907,7 @@ export default class MorphTypeChange {
905
907
  })
906
908
  }
907
909
  })
910
+ layer.appendChild(staged)
908
911
 
909
912
  if (!pieces.length) return this._cancelPieces()
910
913
 
@@ -973,6 +976,8 @@ export default class MorphTypeChange {
973
976
  const layer = this._makePieceLayer()
974
977
  if (!layer) return this._revealPieceHidden()
975
978
  const doc = layer.ownerDocument
979
+ // Staged off the page until every mark is probed, as in _separatePieces.
980
+ const staged = doc.createDocumentFragment()
976
981
 
977
982
  /** @type {import('./MorphPieces').Piece[]} */
978
983
  const pieces = []
@@ -1024,7 +1029,7 @@ export default class MorphTypeChange {
1024
1029
  const markState = {
1025
1030
  remaining: ordered.length,
1026
1031
  els: target.els,
1027
- g: layer.appendChild(doc.createElementNS('http://www.w3.org/2000/svg', 'g')),
1032
+ g: staged.appendChild(doc.createElementNS('http://www.w3.org/2000/svg', 'g')),
1028
1033
  }
1029
1034
 
1030
1035
  for (let m = 0; m < ordered.length; m++) {
@@ -1053,6 +1058,7 @@ export default class MorphTypeChange {
1053
1058
  })
1054
1059
  }
1055
1060
  }
1061
+ layer.appendChild(staged)
1056
1062
 
1057
1063
  if (!pieces.length) return this._cancelPieces()
1058
1064
 
@@ -634,42 +634,38 @@ class Range {
634
634
  gl.barGroups = []
635
635
  gl.lineGroups = []
636
636
  gl.areaGroups = []
637
- /**
638
- * @param {Record<string, any>} s
639
- */
640
- cnf.series.forEach((s) => {
641
- const _s = /** @type {any} */ (s)
642
- const type = _s.type || cnf.chart.type
643
- switch (type) {
637
+ cnf.series.forEach((s, i) => {
638
+ const g = this.w.labelData.seriesGroupIndex[i]
639
+ switch (/** @type {any} */ (s).type || cnf.chart.type) {
644
640
  case 'bar':
645
641
  case 'column':
646
- gl.barGroups.push(_s.group)
642
+ gl.barGroups.push(g)
647
643
  break
648
644
  case 'line':
649
- gl.lineGroups.push(_s.group)
645
+ gl.lineGroups.push(g)
650
646
  break
651
647
  case 'area':
652
- gl.areaGroups.push(_s.group)
648
+ gl.areaGroups.push(g)
653
649
  break
654
650
  }
655
651
  })
656
652
  // Uniquify the group names in each stackable chart type.
657
653
  /**
658
- * @param {string} v
654
+ * @param {number} v
659
655
  * @param {number} i
660
- * @param {string[]} a
656
+ * @param {number[]} a
661
657
  */
662
658
  gl.barGroups = gl.barGroups.filter((v, i, a) => a.indexOf(v) === i)
663
659
  /**
664
- * @param {string} v
660
+ * @param {number} v
665
661
  * @param {number} i
666
- * @param {string[]} a
662
+ * @param {number[]} a
667
663
  */
668
664
  gl.lineGroups = gl.lineGroups.filter((v, i, a) => a.indexOf(v) === i)
669
665
  /**
670
- * @param {string} v
666
+ * @param {number} v
671
667
  * @param {number} i
672
- * @param {string[]} a
668
+ * @param {number[]} a
673
669
  */
674
670
  gl.areaGroups = gl.areaGroups.filter((v, i, a) => a.indexOf(v) === i)
675
671
 
@@ -796,9 +792,10 @@ class Range {
796
792
  ticks = gl.dataPoints - 1
797
793
  }
798
794
  } else if (cnf.xaxis.tickAmount === 'dataPoints') {
799
- if (this.w.seriesData.series.length > 1) {
800
- ticks = this.w.seriesData.series[gl.maxValsInArrayIndex].length - 1
801
- }
795
+ ticks = Math.max(
796
+ 1,
797
+ (this.w.seriesData.series[gl.maxValsInArrayIndex] || []).length - 1,
798
+ )
802
799
  if (this.w.axisFlags.isXNumeric) {
803
800
  const diff = Math.round(gl.maxX - gl.minX)
804
801
  if (diff < 30) {
@@ -877,9 +874,30 @@ class Range {
877
874
  // On its side the chart draws one band per row and one label per
878
875
  // band, so each band is labelled with its own row's x. The evenly
879
876
  // spaced ticks put "Jan 03" against the row that holds Jan 04.
880
- this.w.labelData.labels = /** @type {any} */ (
881
- (this.w.seriesData.seriesX[gl.maxValsInArrayIndex] || []).slice()
882
- )
877
+ // Series that do not share their x values get a band for every x any
878
+ // of them has, in the longest series' direction, and each bar sits in
879
+ // its own x's band (bar/Helpers barRow).
880
+ const rows = (
881
+ this.w.seriesData.seriesX[gl.maxValsInArrayIndex] || []
882
+ ).slice()
883
+ const seen = new Set(rows)
884
+ const n = rows.length
885
+ if (cnf.chart.type === 'bar') {
886
+ this.w.seriesData.seriesX.forEach((s) =>
887
+ s?.forEach((x) => {
888
+ if (x != null && !seen.has(x)) {
889
+ seen.add(x)
890
+ rows.push(x)
891
+ }
892
+ }),
893
+ )
894
+ }
895
+ if (rows.length > n) {
896
+ const dir = rows[0] > rows[n - 1] ? -1 : 1
897
+ rows.sort((a, b) => (a - b) * dir)
898
+ gl.dataPoints = rows.length
899
+ }
900
+ this.w.labelData.labels = /** @type {any} */ (rows)
883
901
  } else if (isXNumeric) {
884
902
  this.w.labelData.labels = /** @type {any} */ (
885
903
  gl.xAxisScale.result.slice()
@@ -1073,10 +1091,9 @@ class Range {
1073
1091
  if (!this.w.seriesData.series.length) return
1074
1092
  const gIdx = this.w.labelData.seriesGroupIndex
1075
1093
  // [positive, negative] sums per stack: the series group (by index, groups
1076
- // may reuse names), then the x value on a numeric axis as stacked columns
1077
- // and lines draw (#4886), else the ordinal (horizontal bars stack by it).
1078
- const byX =
1079
- this.w.axisFlags.isXNumeric && !this.w.config.plotOptions.bar.horizontal
1094
+ // may reuse names), then the x value on a numeric axis as stacked bars and
1095
+ // lines draw (#4886), else the ordinal.
1096
+ const byX = this.w.axisFlags.isXNumeric
1080
1097
  /** @type {Map<string, number[]>} */
1081
1098
  const stacks = new Map()
1082
1099
 
@@ -1108,9 +1125,7 @@ class Range {
1108
1125
 
1109
1126
  const v = this.w.seriesData.series[i][j]
1110
1127
  if (stackSeries && v !== null && Utils.isNumber(v)) {
1111
- v > 0
1112
- ? (st[0] += parseFloat(String(v)) + 0.0001)
1113
- : (st[1] += parseFloat(String(v)))
1128
+ v > 0 ? (st[0] += v * 1.000001) : (st[1] += +v)
1114
1129
  }
1115
1130
  }
1116
1131
  },
@@ -143,7 +143,9 @@ export default class RendererController {
143
143
  return this._activeKind
144
144
  }
145
145
  // The backend was requested/auto-selected but its feature isn't bundled.
146
- if (mode === desired) {
146
+ // resolve() runs every render, so say it once per chart.
147
+ if (mode === desired && !this._warned) {
148
+ this._warned = 1
147
149
  warnMissingFeature(
148
150
  `\`chart.renderer: '${desired}'\``,
149
151
  `renderer-${desired}`,
@@ -152,10 +154,15 @@ export default class RendererController {
152
154
  },
153
155
  )
154
156
  }
155
- } else if (mode === 'canvas' && hasCanvasUnsupportedFeature(this.w)) {
157
+ } else if (
158
+ mode === 'canvas' &&
159
+ !this._warned &&
160
+ hasCanvasUnsupportedFeature(this.w)
161
+ ) {
156
162
  // Explicit canvas, but a configured feature (gradient/pattern/image fill,
157
163
  // or a state color-matrix filter) can't render on canvas yet: 'auto'
158
- // declines silently, explicit 'canvas' says why.
164
+ // declines silently, explicit 'canvas' says why (once).
165
+ this._warned = 1
159
166
  console.warn(
160
167
  `[apexcharts] renderer:"canvas" requested but this chart uses a feature the ` +
161
168
  `canvas renderer does not render yet (gradient/pattern/image fill or a ` +
@@ -163,6 +170,13 @@ export default class RendererController {
163
170
  )
164
171
  }
165
172
 
173
+ // Leaving a non-SVG backend frees it (display list, bitmap); the factory
174
+ // builds a fresh one if the chart crosses back.
175
+ const prev = this._instances[this._activeKind]
176
+ if (prev) {
177
+ prev.destroy()
178
+ delete this._instances[this._activeKind]
179
+ }
166
180
  this._activate('svg', this.svg)
167
181
  return this._activeKind
168
182
  }
@@ -655,6 +655,19 @@ export default class Scales {
655
655
  ;/** @type {any} */ (gl).yAxisScale[index] = []
656
656
  }
657
657
 
658
+ // Zero, a negative or the MIN_VALUE sentinel has no logarithm. The floor
659
+ // was the base, clipping smaller values: drop it to the power of the base
660
+ // at or below the smallest positive value this axis plots.
661
+ if (y.logarithmic && minY <= Number.MIN_VALUE) {
662
+ const s = this.w.seriesData.series
663
+ const map = gl.isMultipleYAxis && gl.seriesYAxisMap[index]
664
+ const b = y.logBase || 10
665
+ const m = (map ? map.map((i) => s[i]) : s)
666
+ .flat()
667
+ .reduce((a, v) => (v > 0 && (!a || v < a) ? v : a), 0)
668
+ minY = m && Math.min(b, b ** Math.floor(Math.log(m) / Math.log(b)))
669
+ }
670
+
658
671
  const range = Math.abs(maxY - minY)
659
672
 
660
673
  // A log scale is degenerate when the domain spans less than one full
@@ -719,15 +732,25 @@ export default class Scales {
719
732
  // no data in the chart. Either all series collapsed or user passed a blank array
720
733
  gl.xAxisScale = this.linearScale(0, 10, 10)
721
734
  } else {
722
- const ticks = gl.xTickAmount
723
-
724
- gl.xAxisScale = this.linearScale(
725
- minX,
726
- maxX,
727
- ticks,
728
- 0,
729
- w.config.xaxis.max === undefined ? w.config.xaxis.stepSize : undefined,
730
- )
735
+ const x = w.config.xaxis
736
+ // a fixed max or a streaming range window wins over the step
737
+ let step = (x.max ?? x.range) === undefined ? x.stepSize : undefined
738
+ // A step fixes the tick count and the axis ends on the last step. One
739
+ // too fine to draw keeps the default count instead.
740
+ const fit = step > 0 && !gl.isBarHorizontal && x.type !== 'datetime'
741
+ if (fit) {
742
+ const n = Math.ceil((maxX - minX) / step - 1e-9)
743
+ n > 1e3 ? (step = undefined) : (gl.xTickAmount = n)
744
+ }
745
+
746
+ let s = this.linearScale(minX, maxX, gl.xTickAmount, 0, step)
747
+ if (fit && step) {
748
+ // linearScale rounds the step, so it can fall short of the data
749
+ while (s.niceMax < maxX)
750
+ s = this.linearScale(minX, maxX, ++gl.xTickAmount, 0, step)
751
+ gl.maxX = s.niceMax
752
+ }
753
+ gl.xAxisScale = s
731
754
  }
732
755
  return gl.xAxisScale
733
756
  }
@@ -63,8 +63,9 @@ export default class Series {
63
63
  * @param {string} seriesName
64
64
  */
65
65
  isSeriesHidden(seriesName) {
66
- const targetElement = this.getSeriesByName(seriesName)
67
- const el = /** @type {Element} */ (targetElement)
66
+ const el = this.getSeriesByName(seriesName)
67
+ // An unknown name (or a type that draws no series group) is a no-op.
68
+ if (!el) return { isHidden: false, realIndex: -1 }
68
69
  const realIndex = parseInt(el.getAttribute('data:realIndex') ?? '0', 10)
69
70
  // The collapse is recorded per index for every type; the class only on
70
71
  // the types that draw a series group for it. A pie, donut or polarArea
@@ -295,11 +296,11 @@ export default class Series {
295
296
  * @param {string} seriesName
296
297
  */
297
298
  toggleSeries(seriesName) {
298
- const isSeriesHidden = this.isSeriesHidden(seriesName)
299
+ const { isHidden, realIndex } = this.isSeriesHidden(seriesName)
299
300
 
300
- this._toggleDataSeries?.(isSeriesHidden.realIndex, isSeriesHidden.isHidden)
301
+ if (realIndex > -1) this._toggleDataSeries?.(realIndex, isHidden)
301
302
 
302
- return isSeriesHidden.isHidden
303
+ return isHidden
303
304
  }
304
305
 
305
306
  /**
@@ -319,7 +320,7 @@ export default class Series {
319
320
  hideSeries(seriesName) {
320
321
  const isSeriesHidden = this.isSeriesHidden(seriesName)
321
322
 
322
- if (!isSeriesHidden.isHidden) {
323
+ if (!isSeriesHidden.isHidden && isSeriesHidden.realIndex > -1) {
323
324
  this._toggleDataSeries?.(isSeriesHidden.realIndex, false)
324
325
  }
325
326
  }
@@ -372,7 +373,8 @@ export default class Series {
372
373
 
373
374
  this.clearSeriesCache()
374
375
 
375
- let series = Utils.clone(w.globals.initialSeries)
376
+ // From the peek: reading initialSeries deep clones it first.
377
+ let series = Utils.clone(w.globals._initialSeriesPeek)
376
378
  // A chart constructed (or once updated) with an invalid series leaves no
377
379
  // usable snapshot; resetting to the live config beats crashing here and
378
380
  // stranding the chart mid-update.
@@ -409,10 +411,14 @@ export default class Series {
409
411
  * @param {any[]} series
410
412
  */
411
413
  emptyCollapsedSeries(series) {
412
- const w = this.w
414
+ const gl = this.w.globals
413
415
  if (!Array.isArray(series)) return series
414
416
  for (let i = 0; i < series.length; i++) {
415
- if (w.globals.collapsedSeriesIndices.indexOf(i) > -1) {
417
+ // A series hidden on a showAlways y axis sits on the ancillary list.
418
+ if (
419
+ gl.collapsedSeriesIndices.includes(i) ||
420
+ gl.ancillaryCollapsedSeriesIndices.includes(i)
421
+ ) {
416
422
  // Axis charts carry {name, data}; non-axis charts (pie / donut / unit)
417
423
  // carry a bare numeric value. Empty each in its own shape: setting
418
424
  // `.data` on a number throws ("Cannot create property 'data' on number"),
@@ -656,8 +662,10 @@ export default class Series {
656
662
  */
657
663
  highlightRangeInSeries(rangeIndex, action) {
658
664
  const w = this.w
665
+ // a treemap's gradient legend draws range bands too
666
+ const t = w.config.chart.type === 'treemap' ? 'treemap' : 'heatmap'
659
667
  const allHeatMapElements = w.dom.baseEl.getElementsByClassName(
660
- 'apexcharts-heatmap-rect',
668
+ `apexcharts-${t}-rect`,
661
669
  )
662
670
 
663
671
  /**
@@ -677,17 +685,24 @@ export default class Series {
677
685
  return
678
686
  }
679
687
 
680
- const ranges = w.config.plotOptions.heatmap.colorScale.ranges
688
+ const ranges = w.config.plotOptions[t].colorScale.ranges
681
689
  const range = ranges && ranges[rangeIndex]
682
690
  if (!range) return
683
691
 
684
692
  toggleAllInactive('add')
685
693
  for (let i = 0; i < allHeatMapElements.length; i++) {
686
- const val = Number(allHeatMapElements[i].getAttribute('val'))
694
+ const el = allHeatMapElements[i]
695
+ // treemap tiles carry no val; they are coloured by series[i][j]
696
+ const val = Number(
697
+ el.getAttribute('val') ??
698
+ w.seriesData.series[/** @type {any} */ (el.getAttribute('i'))]?.[
699
+ /** @type {any} */ (el.getAttribute('j'))
700
+ ],
701
+ )
687
702
  // Match the inclusive bounds used by determineColor (treemap/Helpers.js)
688
703
  // so the same cells that were colored by this range get highlighted.
689
704
  if (val >= range.from && val <= range.to) {
690
- allHeatMapElements[i].classList.remove(this.legendInactiveClass)
705
+ el.classList.remove(this.legendInactiveClass)
691
706
  }
692
707
  }
693
708
  }
@@ -711,10 +726,7 @@ export default class Series {
711
726
  return (
712
727
  chartTypes.length === 0 ||
713
728
  (chartTypes.length &&
714
- chartTypes.indexOf(
715
- /** @type {Record<string,any>} */ (w.config.series[index])
716
- .type,
717
- ) > -1)
729
+ chartTypes.indexOf(s.type || w.config.chart.type) > -1)
718
730
  )
719
731
  }
720
732
  return true
@@ -765,7 +777,7 @@ export default class Series {
765
777
  if (
766
778
  w.globals.comboCharts &&
767
779
  chartTypes.length &&
768
- chartTypes.indexOf(s.type) === -1
780
+ chartTypes.indexOf(s.type || w.config.chart.type) === -1
769
781
  ) {
770
782
  return
771
783
  }
@@ -786,7 +798,9 @@ export default class Series {
786
798
  if (w.globals.comboCharts) {
787
799
  return this.w.config.series
788
800
  .map((/** @type {any} */ s, /** @type {number} */ i) => {
789
- return s.type === 'bar' || s.type === 'column' ? i : -1
801
+ // An untyped series draws as chart.type.
802
+ const t = s.type || w.config.chart.type
803
+ return t === 'bar' || t === 'column' ? i : -1
790
804
  })
791
805
  .filter((/** @type {number} */ i) => {
792
806
  return i !== -1
@@ -892,6 +906,13 @@ export default class Series {
892
906
  ((type === 'line' || type === 'area') &&
893
907
  paths[j].getAttribute('d')) ||
894
908
  paths[j].getAttribute('pathTo')
909
+ // A violin's box lane shares its body's datum key: ride on the
910
+ // body's entry so the keyed join stays one path per datum.
911
+ if (paths[j].classList.contains('apexcharts-raincloud-box')) {
912
+ const body = dArr.paths[dArr.paths.length - 1]
913
+ if (body) (body.box ||= []).push(d)
914
+ continue
915
+ }
895
916
  // Datum key + fill stamped by the bar renderer: the key lets the
896
917
  // next render match survivors by identity (not position) and detect
897
918
  // exited datums; the fill paints their exit ghosts.
@@ -935,6 +956,7 @@ export default class Series {
935
956
  'candlestick',
936
957
  'boxPlot',
937
958
  'radar',
959
+ 'violin',
938
960
  ]
939
961
  chartTypes.forEach((type) => {
940
962
  const paths = getPaths(type)