minerva-design 1.2.0 → 1.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 (256) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/charts/canvas.d.cts +4 -1
  3. package/dist/charts/canvas.d.ts +4 -1
  4. package/dist/charts/core.cjs +1 -1
  5. package/dist/charts/core.d.cts +5 -2
  6. package/dist/charts/core.d.ts +5 -2
  7. package/dist/charts/core.js +6 -4
  8. package/dist/charts/engine/canvas.cjs +1 -1
  9. package/dist/charts/engine/canvas.cjs.map +1 -1
  10. package/dist/charts/engine/canvas.js +65 -53
  11. package/dist/charts/engine/canvas.js.map +1 -1
  12. package/dist/charts/engine/chart.cjs +1 -2
  13. package/dist/charts/engine/chart.cjs.map +1 -1
  14. package/dist/charts/engine/chart.js +342 -323
  15. package/dist/charts/engine/chart.js.map +1 -1
  16. package/dist/charts/engine/color.cjs +1 -1
  17. package/dist/charts/engine/color.cjs.map +1 -1
  18. package/dist/charts/engine/color.d.cts +17 -0
  19. package/dist/charts/engine/color.d.ts +17 -0
  20. package/dist/charts/engine/color.js +27 -3
  21. package/dist/charts/engine/color.js.map +1 -1
  22. package/dist/charts/engine/controller.cjs +2 -2
  23. package/dist/charts/engine/controller.cjs.map +1 -1
  24. package/dist/charts/engine/controller.d.cts +6 -0
  25. package/dist/charts/engine/controller.d.ts +6 -0
  26. package/dist/charts/engine/controller.js +317 -253
  27. package/dist/charts/engine/controller.js.map +1 -1
  28. package/dist/charts/engine/curve.cjs +2 -0
  29. package/dist/charts/engine/curve.cjs.map +1 -0
  30. package/dist/charts/engine/curve.d.cts +15 -0
  31. package/dist/charts/engine/curve.d.ts +15 -0
  32. package/dist/charts/engine/curve.js +56 -0
  33. package/dist/charts/engine/curve.js.map +1 -0
  34. package/dist/charts/engine/data.cjs +1 -1
  35. package/dist/charts/engine/data.cjs.map +1 -1
  36. package/dist/charts/engine/data.d.cts +15 -2
  37. package/dist/charts/engine/data.d.ts +15 -2
  38. package/dist/charts/engine/data.js +98 -38
  39. package/dist/charts/engine/data.js.map +1 -1
  40. package/dist/charts/engine/dom.cjs +1 -1
  41. package/dist/charts/engine/dom.cjs.map +1 -1
  42. package/dist/charts/engine/dom.d.cts +5 -3
  43. package/dist/charts/engine/dom.d.ts +5 -3
  44. package/dist/charts/engine/dom.js +27 -22
  45. package/dist/charts/engine/dom.js.map +1 -1
  46. package/dist/charts/engine/items.cjs +1 -1
  47. package/dist/charts/engine/items.cjs.map +1 -1
  48. package/dist/charts/engine/items.js +132 -61
  49. package/dist/charts/engine/items.js.map +1 -1
  50. package/dist/charts/engine/model.cjs +1 -1
  51. package/dist/charts/engine/model.cjs.map +1 -1
  52. package/dist/charts/engine/model.d.cts +30 -3
  53. package/dist/charts/engine/model.d.ts +30 -3
  54. package/dist/charts/engine/model.js +225 -108
  55. package/dist/charts/engine/model.js.map +1 -1
  56. package/dist/charts/engine/overlay.cjs +1 -1
  57. package/dist/charts/engine/overlay.cjs.map +1 -1
  58. package/dist/charts/engine/overlay.d.cts +2 -0
  59. package/dist/charts/engine/overlay.d.ts +2 -0
  60. package/dist/charts/engine/overlay.js +16 -16
  61. package/dist/charts/engine/overlay.js.map +1 -1
  62. package/dist/charts/engine/presets.cjs +2 -2
  63. package/dist/charts/engine/presets.cjs.map +1 -1
  64. package/dist/charts/engine/presets.d.cts +71 -5
  65. package/dist/charts/engine/presets.d.ts +71 -5
  66. package/dist/charts/engine/presets.js +120 -33
  67. package/dist/charts/engine/presets.js.map +1 -1
  68. package/dist/charts/engine/renderers/canvas2d.cjs +1 -1
  69. package/dist/charts/engine/renderers/canvas2d.cjs.map +1 -1
  70. package/dist/charts/engine/renderers/canvas2d.js +149 -111
  71. package/dist/charts/engine/renderers/canvas2d.js.map +1 -1
  72. package/dist/charts/engine/renderers/range.cjs +1 -1
  73. package/dist/charts/engine/renderers/range.cjs.map +1 -1
  74. package/dist/charts/engine/renderers/range.js +4 -4
  75. package/dist/charts/engine/renderers/range.js.map +1 -1
  76. package/dist/charts/engine/renderers/shaders.cjs +37 -19
  77. package/dist/charts/engine/renderers/shaders.cjs.map +1 -1
  78. package/dist/charts/engine/renderers/shaders.d.cts +2 -2
  79. package/dist/charts/engine/renderers/shaders.d.ts +2 -2
  80. package/dist/charts/engine/renderers/shaders.js +37 -19
  81. package/dist/charts/engine/renderers/shaders.js.map +1 -1
  82. package/dist/charts/engine/renderers/types.cjs.map +1 -1
  83. package/dist/charts/engine/renderers/types.d.cts +11 -4
  84. package/dist/charts/engine/renderers/types.d.ts +11 -4
  85. package/dist/charts/engine/renderers/types.js.map +1 -1
  86. package/dist/charts/engine/renderers/webgl2.cjs +1 -1
  87. package/dist/charts/engine/renderers/webgl2.cjs.map +1 -1
  88. package/dist/charts/engine/renderers/webgl2.js +33 -12
  89. package/dist/charts/engine/renderers/webgl2.js.map +1 -1
  90. package/dist/charts/engine/renderers/webgpu.cjs +1 -1
  91. package/dist/charts/engine/renderers/webgpu.cjs.map +1 -1
  92. package/dist/charts/engine/renderers/webgpu.js +18 -15
  93. package/dist/charts/engine/renderers/webgpu.js.map +1 -1
  94. package/dist/charts/engine/scene.cjs +1 -1
  95. package/dist/charts/engine/scene.cjs.map +1 -1
  96. package/dist/charts/engine/scene.d.cts +19 -6
  97. package/dist/charts/engine/scene.d.ts +19 -6
  98. package/dist/charts/engine/scene.js +201 -89
  99. package/dist/charts/engine/scene.js.map +1 -1
  100. package/dist/charts/engine/shapes/canvas.cjs +2 -0
  101. package/dist/charts/engine/shapes/canvas.cjs.map +1 -0
  102. package/dist/charts/engine/shapes/canvas.d.cts +58 -0
  103. package/dist/charts/engine/shapes/canvas.d.ts +58 -0
  104. package/dist/charts/engine/shapes/canvas.js +159 -0
  105. package/dist/charts/engine/shapes/canvas.js.map +1 -0
  106. package/dist/charts/engine/shapes/chart.cjs +2 -0
  107. package/dist/charts/engine/shapes/chart.cjs.map +1 -0
  108. package/dist/charts/engine/shapes/chart.d.cts +6 -0
  109. package/dist/charts/engine/shapes/chart.d.ts +6 -0
  110. package/dist/charts/engine/shapes/chart.js +273 -0
  111. package/dist/charts/engine/shapes/chart.js.map +1 -0
  112. package/dist/charts/engine/shapes/draw.cjs +2 -0
  113. package/dist/charts/engine/shapes/draw.cjs.map +1 -0
  114. package/dist/charts/engine/shapes/draw.d.cts +20 -0
  115. package/dist/charts/engine/shapes/draw.d.ts +20 -0
  116. package/dist/charts/engine/shapes/draw.js +152 -0
  117. package/dist/charts/engine/shapes/draw.js.map +1 -0
  118. package/dist/charts/engine/shapes/funnel.cjs +2 -0
  119. package/dist/charts/engine/shapes/funnel.cjs.map +1 -0
  120. package/dist/charts/engine/shapes/funnel.d.cts +6 -0
  121. package/dist/charts/engine/shapes/funnel.d.ts +6 -0
  122. package/dist/charts/engine/shapes/funnel.js +149 -0
  123. package/dist/charts/engine/shapes/funnel.js.map +1 -0
  124. package/dist/charts/engine/shapes/gauge.cjs +2 -0
  125. package/dist/charts/engine/shapes/gauge.cjs.map +1 -0
  126. package/dist/charts/engine/shapes/gauge.d.cts +7 -0
  127. package/dist/charts/engine/shapes/gauge.d.ts +7 -0
  128. package/dist/charts/engine/shapes/gauge.js +173 -0
  129. package/dist/charts/engine/shapes/gauge.js.map +1 -0
  130. package/dist/charts/engine/shapes/hit.cjs +2 -0
  131. package/dist/charts/engine/shapes/hit.cjs.map +1 -0
  132. package/dist/charts/engine/shapes/hit.d.cts +28 -0
  133. package/dist/charts/engine/shapes/hit.d.ts +28 -0
  134. package/dist/charts/engine/shapes/hit.js +124 -0
  135. package/dist/charts/engine/shapes/hit.js.map +1 -0
  136. package/dist/charts/engine/shapes/index.d.cts +9 -0
  137. package/dist/charts/engine/shapes/index.d.ts +9 -0
  138. package/dist/charts/engine/shapes/layout.cjs +3 -0
  139. package/dist/charts/engine/shapes/layout.cjs.map +1 -0
  140. package/dist/charts/engine/shapes/layout.d.cts +88 -0
  141. package/dist/charts/engine/shapes/layout.d.ts +88 -0
  142. package/dist/charts/engine/shapes/layout.js +266 -0
  143. package/dist/charts/engine/shapes/layout.js.map +1 -0
  144. package/dist/charts/engine/shapes/pie.cjs +2 -0
  145. package/dist/charts/engine/shapes/pie.cjs.map +1 -0
  146. package/dist/charts/engine/shapes/pie.d.cts +20 -0
  147. package/dist/charts/engine/shapes/pie.d.ts +20 -0
  148. package/dist/charts/engine/shapes/pie.js +302 -0
  149. package/dist/charts/engine/shapes/pie.js.map +1 -0
  150. package/dist/charts/engine/shapes/radar.cjs +2 -0
  151. package/dist/charts/engine/shapes/radar.cjs.map +1 -0
  152. package/dist/charts/engine/shapes/radar.d.cts +8 -0
  153. package/dist/charts/engine/shapes/radar.d.ts +8 -0
  154. package/dist/charts/engine/shapes/radar.js +197 -0
  155. package/dist/charts/engine/shapes/radar.js.map +1 -0
  156. package/dist/charts/engine/shapes/runtime.cjs +2 -0
  157. package/dist/charts/engine/shapes/runtime.cjs.map +1 -0
  158. package/dist/charts/engine/shapes/runtime.d.cts +29 -0
  159. package/dist/charts/engine/shapes/runtime.d.ts +29 -0
  160. package/dist/charts/engine/shapes/runtime.js +97 -0
  161. package/dist/charts/engine/shapes/runtime.js.map +1 -0
  162. package/dist/charts/engine/shapes/scene.cjs +2 -0
  163. package/dist/charts/engine/shapes/scene.cjs.map +1 -0
  164. package/dist/charts/engine/shapes/scene.d.cts +257 -0
  165. package/dist/charts/engine/shapes/scene.d.ts +257 -0
  166. package/dist/charts/engine/shapes/scene.js +123 -0
  167. package/dist/charts/engine/shapes/scene.js.map +1 -0
  168. package/dist/charts/engine/shapes/treemap.cjs +2 -0
  169. package/dist/charts/engine/shapes/treemap.cjs.map +1 -0
  170. package/dist/charts/engine/shapes/treemap.d.cts +14 -0
  171. package/dist/charts/engine/shapes/treemap.d.ts +14 -0
  172. package/dist/charts/engine/shapes/treemap.js +213 -0
  173. package/dist/charts/engine/shapes/treemap.js.map +1 -0
  174. package/dist/charts/engine/shapes/types.d.cts +292 -0
  175. package/dist/charts/engine/shapes/types.d.ts +292 -0
  176. package/dist/charts/engine/signature.cjs +2 -0
  177. package/dist/charts/engine/signature.cjs.map +1 -0
  178. package/dist/charts/engine/signature.d.cts +9 -0
  179. package/dist/charts/engine/signature.d.ts +9 -0
  180. package/dist/charts/engine/signature.js +13 -0
  181. package/dist/charts/engine/signature.js.map +1 -0
  182. package/dist/charts/engine/theme.cjs +1 -1
  183. package/dist/charts/engine/theme.cjs.map +1 -1
  184. package/dist/charts/engine/theme.d.cts +10 -1
  185. package/dist/charts/engine/theme.d.ts +10 -1
  186. package/dist/charts/engine/theme.js +40 -16
  187. package/dist/charts/engine/theme.js.map +1 -1
  188. package/dist/charts/engine/types.d.cts +70 -9
  189. package/dist/charts/engine/types.d.ts +70 -9
  190. package/dist/charts/index.cjs +1 -1
  191. package/dist/charts/index.d.cts +4 -2
  192. package/dist/charts/index.d.ts +4 -2
  193. package/dist/charts/index.js +8 -5
  194. package/dist/charts/react/Chart.cjs +1 -1
  195. package/dist/charts/react/Chart.cjs.map +1 -1
  196. package/dist/charts/react/Chart.d.cts +8 -1
  197. package/dist/charts/react/Chart.d.ts +8 -1
  198. package/dist/charts/react/Chart.js +66 -47
  199. package/dist/charts/react/Chart.js.map +1 -1
  200. package/dist/charts/react/charts.cjs +1 -1
  201. package/dist/charts/react/charts.cjs.map +1 -1
  202. package/dist/charts/react/charts.d.cts +10 -2
  203. package/dist/charts/react/charts.d.ts +10 -2
  204. package/dist/charts/react/charts.js +174 -51
  205. package/dist/charts/react/charts.js.map +1 -1
  206. package/dist/charts/react/shapes.cjs +2 -0
  207. package/dist/charts/react/shapes.cjs.map +1 -0
  208. package/dist/charts/react/shapes.d.cts +255 -0
  209. package/dist/charts/react/shapes.d.ts +255 -0
  210. package/dist/charts/react/shapes.js +242 -0
  211. package/dist/charts/react/shapes.js.map +1 -0
  212. package/dist/charts/react/types.d.cts +73 -4
  213. package/dist/charts/react/types.d.ts +73 -4
  214. package/dist/native/charts/src/engine/color.cjs +1 -1
  215. package/dist/native/charts/src/engine/color.cjs.map +1 -1
  216. package/dist/native/charts/src/engine/color.js +12 -3
  217. package/dist/native/charts/src/engine/color.js.map +1 -1
  218. package/dist/native/charts/src/engine/controller.cjs +2 -2
  219. package/dist/native/charts/src/engine/controller.cjs.map +1 -1
  220. package/dist/native/charts/src/engine/controller.js +334 -270
  221. package/dist/native/charts/src/engine/controller.js.map +1 -1
  222. package/dist/native/charts/src/engine/curve.cjs +2 -0
  223. package/dist/native/charts/src/engine/curve.cjs.map +1 -0
  224. package/dist/native/charts/src/engine/curve.js +56 -0
  225. package/dist/native/charts/src/engine/curve.js.map +1 -0
  226. package/dist/native/charts/src/engine/data.cjs +1 -1
  227. package/dist/native/charts/src/engine/data.cjs.map +1 -1
  228. package/dist/native/charts/src/engine/data.js +98 -38
  229. package/dist/native/charts/src/engine/data.js.map +1 -1
  230. package/dist/native/charts/src/engine/model.cjs +1 -1
  231. package/dist/native/charts/src/engine/model.cjs.map +1 -1
  232. package/dist/native/charts/src/engine/model.js +229 -112
  233. package/dist/native/charts/src/engine/model.js.map +1 -1
  234. package/dist/native/charts/src/engine/overlay.cjs +1 -1
  235. package/dist/native/charts/src/engine/overlay.cjs.map +1 -1
  236. package/dist/native/charts/src/engine/overlay.js +16 -16
  237. package/dist/native/charts/src/engine/overlay.js.map +1 -1
  238. package/dist/native/charts/src/engine/presets.cjs +1 -1
  239. package/dist/native/charts/src/engine/presets.cjs.map +1 -1
  240. package/dist/native/charts/src/engine/presets.js +11 -4
  241. package/dist/native/charts/src/engine/presets.js.map +1 -1
  242. package/dist/native/charts/src/engine/scene.cjs +1 -1
  243. package/dist/native/charts/src/engine/scene.cjs.map +1 -1
  244. package/dist/native/charts/src/engine/scene.js +209 -97
  245. package/dist/native/charts/src/engine/scene.js.map +1 -1
  246. package/dist/native/charts/src/engine/theme.cjs.map +1 -1
  247. package/dist/native/charts/src/engine/theme.js.map +1 -1
  248. package/dist/native/components/Chart/scene.cjs +1 -1
  249. package/dist/native/components/Chart/scene.cjs.map +1 -1
  250. package/dist/native/components/Chart/scene.js +31 -19
  251. package/dist/native/components/Chart/scene.js.map +1 -1
  252. package/dist/native/source/components/Chart/scene.tsx +54 -20
  253. package/dist/taro/index.js +1059 -579
  254. package/dist/uni/charts-canvas.js +3 -1
  255. package/dist/weapp/controls.js +966 -225
  256. package/package.json +1 -1
@@ -6364,6 +6364,118 @@ var mix = (a, b, t) => [
6364
6364
  a[2] + (b[2] - a[2]) * t,
6365
6365
  a[3] + (b[3] - a[3]) * t
6366
6366
  ];
6367
+ /** Inverse of `packColor` */
6368
+ var unpackColor = (packed) => [
6369
+ (packed & 255) / 255,
6370
+ (packed >>> 8 & 255) / 255,
6371
+ (packed >>> 16 & 255) / 255,
6372
+ (packed >>> 24 & 255) / 255
6373
+ ];
6374
+ /** Color at `t` (0-1) of a ramp through `stops` */
6375
+ var rampColor = (stops, t) => {
6376
+ if (stops.length === 1) return stops[0];
6377
+ const p = clamp01(t) * (stops.length - 1);
6378
+ const i = Math.min(stops.length - 2, Math.floor(p));
6379
+ return mix(stops[i], stops[i + 1], p - i);
6380
+ };
6381
+ /**
6382
+ * Points of the curve through `x[i], y[i]` (`i` in `[start, end)`), as
6383
+ * interleaved x, y, plus the index of the source point each output point
6384
+ * belongs to. Gaps (non-finite y) are kept.
6385
+ */
6386
+ var curvePoints = (x, y, start, end, curve) => {
6387
+ const n = Math.max(0, end - start);
6388
+ if (curve === "step") {
6389
+ const points = new Float64Array(n * 4);
6390
+ const source = new Uint32Array(n * 2);
6391
+ let length = 0;
6392
+ for (let i = start; i < end; i++) {
6393
+ if (i > start && Number.isFinite(y[i - 1]) && Number.isFinite(y[i])) {
6394
+ points[length * 2] = x[i];
6395
+ points[length * 2 + 1] = y[i - 1];
6396
+ source[length++] = i - 1;
6397
+ }
6398
+ points[length * 2] = x[i];
6399
+ points[length * 2 + 1] = y[i];
6400
+ source[length++] = i;
6401
+ }
6402
+ return {
6403
+ points,
6404
+ source,
6405
+ length
6406
+ };
6407
+ }
6408
+ if (curve !== "smooth" || n < 3 || n > 5e4) {
6409
+ const points = new Float64Array(n * 2);
6410
+ const source = new Uint32Array(n);
6411
+ for (let i = start; i < end; i++) {
6412
+ points[(i - start) * 2] = x[i];
6413
+ points[(i - start) * 2 + 1] = y[i];
6414
+ source[i - start] = i;
6415
+ }
6416
+ return {
6417
+ points,
6418
+ source,
6419
+ length: n
6420
+ };
6421
+ }
6422
+ const tangents = new Float64Array(n);
6423
+ const valid = (i) => i >= start && i < end && Number.isFinite(y[i]) && Number.isFinite(x[i]);
6424
+ const slope = (i) => {
6425
+ const dx = x[i + 1] - x[i];
6426
+ return dx !== 0 ? (y[i + 1] - y[i]) / dx : 0;
6427
+ };
6428
+ for (let i = start; i < end; i++) {
6429
+ if (!valid(i)) continue;
6430
+ const hasPrev = valid(i - 1);
6431
+ const hasNext = valid(i + 1);
6432
+ let m;
6433
+ if (hasPrev && hasNext) {
6434
+ const a = slope(i - 1);
6435
+ const b = slope(i);
6436
+ if (a * b <= 0) m = 0;
6437
+ else {
6438
+ const ha = x[i] - x[i - 1];
6439
+ const hb = x[i + 1] - x[i];
6440
+ const w1 = 2 * hb + ha;
6441
+ const w2 = hb + 2 * ha;
6442
+ m = (w1 + w2) / (w1 / a + w2 / b);
6443
+ }
6444
+ } else if (hasNext) m = slope(i);
6445
+ else if (hasPrev) m = slope(i - 1);
6446
+ else m = 0;
6447
+ tangents[i - start] = m;
6448
+ }
6449
+ const points = new Float64Array((n - 1) * 10 * 2 + 2);
6450
+ const source = new Uint32Array((n - 1) * 10 + 1);
6451
+ let length = 0;
6452
+ for (let i = start; i < end; i++) {
6453
+ points[length * 2] = x[i];
6454
+ points[length * 2 + 1] = y[i];
6455
+ source[length++] = i;
6456
+ if (!valid(i) || !valid(i + 1)) continue;
6457
+ const x0 = x[i];
6458
+ const y0 = y[i];
6459
+ const h = x[i + 1] - x0;
6460
+ const m0 = tangents[i - start] * h;
6461
+ const m1 = tangents[i + 1 - start] * h;
6462
+ const y1 = y[i + 1];
6463
+ for (let k = 1; k < 10; k++) {
6464
+ const t = k / 10;
6465
+ const t2 = t * t;
6466
+ const t3 = t2 * t;
6467
+ const v = (2 * t3 - 3 * t2 + 1) * y0 + (t3 - 2 * t2 + t) * m0 + (-2 * t3 + 3 * t2) * y1 + (t3 - t2) * m1;
6468
+ points[length * 2] = x0 + h * t;
6469
+ points[length * 2 + 1] = v;
6470
+ source[length++] = i;
6471
+ }
6472
+ }
6473
+ return {
6474
+ points,
6475
+ source,
6476
+ length
6477
+ };
6478
+ };
6367
6479
  //#endregion
6368
6480
  //#region ../charts/src/engine/data.ts
6369
6481
  var isColumns = (data) => typeof data === "object" && data !== null && !("length" in data) && "y" in data;
@@ -6382,6 +6494,27 @@ var xResolver = (type, categoryIndex) => {
6382
6494
  };
6383
6495
  };
6384
6496
  var toNumber = (v) => typeof v === "number" ? v : v === null || v === void 0 ? NaN : Number(v);
6497
+ /** Category names used by string y values (heatmap rows), in order of appearance */
6498
+ var collectYCategories = (datas) => {
6499
+ const seen = /* @__PURE__ */ new Set();
6500
+ for (const data of datas) {
6501
+ if (isColumns(data)) {
6502
+ const ys = data.y;
6503
+ if (!ArrayBuffer.isView(ys)) for (let i = 0; i < ys.length; i++) {
6504
+ const v = ys[i];
6505
+ if (typeof v === "string") seen.add(v);
6506
+ }
6507
+ continue;
6508
+ }
6509
+ const list = data;
6510
+ for (let i = 0; i < list.length; i++) {
6511
+ const item = list[i];
6512
+ const v = Array.isArray(item) ? item[1] : item && typeof item === "object" ? item.y : void 0;
6513
+ if (typeof v === "string") seen.add(v);
6514
+ }
6515
+ }
6516
+ return [...seen];
6517
+ };
6385
6518
  /** Category names used by string x values, in order of appearance */
6386
6519
  var collectCategories = (datas) => {
6387
6520
  const seen = /* @__PURE__ */ new Set();
@@ -6410,6 +6543,7 @@ var finalize = (x, y, count, extra) => {
6410
6543
  let yMax = -Infinity;
6411
6544
  let sorted = true;
6412
6545
  let prev = -Infinity;
6546
+ const { high, low, value } = extra;
6413
6547
  for (let i = 0; i < count; i++) {
6414
6548
  const xi = x[i];
6415
6549
  if (!Number.isFinite(xi)) {
@@ -6424,6 +6558,24 @@ var finalize = (x, y, count, extra) => {
6424
6558
  if (xi > xMax) xMax = xi;
6425
6559
  if (yi < yMin) yMin = yi;
6426
6560
  if (yi > yMax) yMax = yi;
6561
+ if (high) {
6562
+ const h = high[i];
6563
+ if (h > yMax) yMax = h;
6564
+ if (h < yMin) yMin = h;
6565
+ }
6566
+ if (low) {
6567
+ const l = low[i];
6568
+ if (l < yMin) yMin = l;
6569
+ if (l > yMax) yMax = l;
6570
+ }
6571
+ }
6572
+ let valueMin = Infinity;
6573
+ let valueMax = -Infinity;
6574
+ if (value) for (let i = 0; i < count; i++) {
6575
+ const v = value[i];
6576
+ if (!Number.isFinite(v)) continue;
6577
+ if (v < valueMin) valueMin = v;
6578
+ if (v > valueMax) valueMax = v;
6427
6579
  }
6428
6580
  const empty = xMin > xMax;
6429
6581
  return {
@@ -6435,24 +6587,44 @@ var finalize = (x, y, count, extra) => {
6435
6587
  xMax: empty ? NaN : xMax,
6436
6588
  yMin: empty ? NaN : yMin,
6437
6589
  yMax: empty ? NaN : yMax,
6590
+ valueMin: valueMin > valueMax ? NaN : valueMin,
6591
+ valueMax: valueMin > valueMax ? NaN : valueMax,
6438
6592
  ...extra
6439
6593
  };
6440
6594
  };
6595
+ var column = (values, count) => {
6596
+ if (!values) return null;
6597
+ if (values instanceof Float64Array && values.length >= count) return values.length === count ? values : values.subarray(0, count);
6598
+ const out = new Float64Array(count);
6599
+ for (let i = 0; i < count; i++) out[i] = toNumber(values[i]);
6600
+ return out;
6601
+ };
6441
6602
  /** Turns any supported data form into columns */
6442
- var normalizeData = (data, resolveX) => {
6603
+ var normalizeData = (data, resolveX, resolveY = toNumber) => {
6443
6604
  const none = {
6444
6605
  size: null,
6445
6606
  colors: null,
6446
- labels: null
6607
+ labels: null,
6608
+ open: null,
6609
+ high: null,
6610
+ low: null,
6611
+ value: null
6447
6612
  };
6448
6613
  if (isColumns(data)) {
6449
6614
  const count = data.y.length;
6450
6615
  const x = new Float64Array(count);
6451
- const y = new Float64Array(count);
6452
6616
  const xs = data.x;
6453
- for (let i = 0; i < count; i++) {
6454
- y[i] = toNumber(data.y[i]);
6455
- x[i] = xs ? resolveX(xs[i], i) : i;
6617
+ if (!xs) for (let i = 0; i < count; i++) x[i] = i;
6618
+ else if (ArrayBuffer.isView(xs) && xs.length >= count) x.set(xs.length === count ? xs : xs.subarray(0, count));
6619
+ else for (let i = 0; i < count; i++) x[i] = resolveX(xs[i], i);
6620
+ const ys = data.y;
6621
+ let y;
6622
+ if (ArrayBuffer.isView(ys)) {
6623
+ y = new Float64Array(count);
6624
+ y.set(ys);
6625
+ } else {
6626
+ y = new Float64Array(count);
6627
+ for (let i = 0; i < count; i++) y[i] = resolveY(ys[i]);
6456
6628
  }
6457
6629
  let size = null;
6458
6630
  if (data.size) {
@@ -6461,7 +6633,11 @@ var normalizeData = (data, resolveX) => {
6461
6633
  }
6462
6634
  return finalize(x, y, count, {
6463
6635
  ...none,
6464
- size
6636
+ size,
6637
+ open: column(data.open, count),
6638
+ high: column(data.high, count),
6639
+ low: column(data.low, count),
6640
+ value: column(data.value, count)
6465
6641
  });
6466
6642
  }
6467
6643
  const list = data;
@@ -6471,6 +6647,11 @@ var normalizeData = (data, resolveX) => {
6471
6647
  let size = null;
6472
6648
  let colors = null;
6473
6649
  let labels = null;
6650
+ let open = null;
6651
+ let high = null;
6652
+ let low = null;
6653
+ let value = null;
6654
+ const nanColumn = () => new Float64Array(count).fill(NaN);
6474
6655
  for (let i = 0; i < count; i++) {
6475
6656
  const item = list[i];
6476
6657
  if (item === null || item === void 0 || typeof item === "number") {
@@ -6478,11 +6659,11 @@ var normalizeData = (data, resolveX) => {
6478
6659
  y[i] = toNumber(item);
6479
6660
  } else if (Array.isArray(item)) {
6480
6661
  x[i] = resolveX(item[0], i);
6481
- y[i] = toNumber(item[1]);
6662
+ y[i] = resolveY(item[1]);
6482
6663
  } else if (typeof item === "object") {
6483
6664
  const d = item;
6484
6665
  x[i] = d.x === void 0 ? i : resolveX(d.x, i);
6485
- y[i] = toNumber(d.y);
6666
+ y[i] = resolveY(d.y);
6486
6667
  if (d.size !== void 0) {
6487
6668
  size ??= new Float32Array(count).fill(NaN);
6488
6669
  size[i] = d.size;
@@ -6495,6 +6676,10 @@ var normalizeData = (data, resolveX) => {
6495
6676
  labels ??= new Array(count);
6496
6677
  labels[i] = d.label;
6497
6678
  }
6679
+ if (d.open !== void 0) (open ??= nanColumn())[i] = toNumber(d.open);
6680
+ if (d.high !== void 0) (high ??= nanColumn())[i] = toNumber(d.high);
6681
+ if (d.low !== void 0) (low ??= nanColumn())[i] = toNumber(d.low);
6682
+ if (d.value !== void 0) (value ??= nanColumn())[i] = toNumber(d.value);
6498
6683
  } else {
6499
6684
  x[i] = i;
6500
6685
  y[i] = NaN;
@@ -6503,7 +6688,11 @@ var normalizeData = (data, resolveX) => {
6503
6688
  return finalize(x, y, count, {
6504
6689
  size,
6505
6690
  colors,
6506
- labels
6691
+ labels,
6692
+ open,
6693
+ high,
6694
+ low,
6695
+ value
6507
6696
  });
6508
6697
  };
6509
6698
  /** First index whose x is >= value (sorted x) */
@@ -6802,18 +6991,94 @@ var extent = (values) => {
6802
6991
  }
6803
6992
  return [min, max];
6804
6993
  };
6805
- /** Smallest positive gap between consecutive x values (bar width on numeric axes) */
6806
- var smallestStep = (cols) => {
6994
+ /** Smallest positive gap between consecutive values (bar width on numeric axes) */
6995
+ var smallestStep = (columns, sorted) => {
6807
6996
  let step = Infinity;
6808
- for (const c of cols) {
6809
- const xs = c.sorted ? c.x : Float64Array.from(c.x).sort();
6810
- for (let i = 1; i < c.count; i++) {
6997
+ columns.forEach((values, k) => {
6998
+ const xs = sorted[k] ? values : Float64Array.from(values).sort();
6999
+ for (let i = 1; i < xs.length; i++) {
6811
7000
  const d = xs[i] - xs[i - 1];
6812
7001
  if (d > 0 && d < step) step = d;
6813
7002
  }
6814
- }
7003
+ });
6815
7004
  return step;
6816
7005
  };
7006
+ var bandOf = (list, axis, category) => {
7007
+ if (category) return 1;
7008
+ const step = smallestStep(list.map((s) => axis === "x" ? s.cols.x : s.cols.y), list.map((s) => axis === "x" && s.cols.sorted));
7009
+ return Number.isFinite(step) ? step : 1;
7010
+ };
7011
+ /**
7012
+ * Stacks the y values of series sharing a stack id (positive and negative
7013
+ * values separately); `percent` scales every stack to 100 at each x
7014
+ */
7015
+ var stackValues = (list, percent) => {
7016
+ const totals = /* @__PURE__ */ new Map();
7017
+ if (percent) for (const { s, stack } of list) {
7018
+ let byX = totals.get(stack);
7019
+ if (!byX) totals.set(stack, byX = /* @__PURE__ */ new Map());
7020
+ const { x, y, count } = s.cols;
7021
+ for (let i = 0; i < count; i++) {
7022
+ const v = y[i];
7023
+ if (!Number.isFinite(v)) continue;
7024
+ const t = byX.get(x[i]) ?? [0, 0];
7025
+ if (v >= 0) t[0] += v;
7026
+ else t[1] -= v;
7027
+ byX.set(x[i], t);
7028
+ }
7029
+ }
7030
+ const running = /* @__PURE__ */ new Map();
7031
+ const members = /* @__PURE__ */ new Map();
7032
+ for (const { stack } of list) members.set(stack, (members.get(stack) ?? 0) + 1);
7033
+ return list.map(({ s, stack }) => {
7034
+ const { x, y, count } = s.cols;
7035
+ if (!percent && members.get(stack) === 1) {
7036
+ const base = new Float64Array(count);
7037
+ const top = new Float64Array(count);
7038
+ for (let i = 0; i < count; i++) {
7039
+ const v = y[i];
7040
+ const valid = Number.isFinite(v);
7041
+ base[i] = valid ? 0 : NaN;
7042
+ top[i] = valid ? v : NaN;
7043
+ }
7044
+ return {
7045
+ base,
7046
+ top
7047
+ };
7048
+ }
7049
+ let byX = running.get(stack);
7050
+ if (!byX) running.set(stack, byX = /* @__PURE__ */ new Map());
7051
+ const sums = totals.get(stack);
7052
+ const base = new Float64Array(count);
7053
+ const top = new Float64Array(count);
7054
+ for (let i = 0; i < count; i++) {
7055
+ let v = y[i];
7056
+ if (!Number.isFinite(v)) {
7057
+ base[i] = NaN;
7058
+ top[i] = NaN;
7059
+ continue;
7060
+ }
7061
+ if (sums) {
7062
+ const t = sums.get(x[i]);
7063
+ const total = t ? v >= 0 ? t[0] : t[1] : 0;
7064
+ v = total > 0 ? v / total * 100 : 0;
7065
+ }
7066
+ const t = byX.get(x[i]) ?? [0, 0];
7067
+ const b = v >= 0 ? t[0] : t[1];
7068
+ base[i] = b;
7069
+ top[i] = b + v;
7070
+ if (v >= 0) t[0] += v;
7071
+ else t[1] += v;
7072
+ byX.set(x[i], t);
7073
+ }
7074
+ return {
7075
+ base,
7076
+ top
7077
+ };
7078
+ });
7079
+ };
7080
+ var DEFAULT_UP = "var(--success-color, #16a34a)";
7081
+ var DEFAULT_DOWN = "var(--danger-color, #dc2626)";
6817
7082
  var buildModel = (options, theme, hidden, cache, resolver = null) => {
6818
7083
  const resolve = resolver ?? theme.resolve ?? ((value, fallback) => resolveStaticColor(value, {}, fallback));
6819
7084
  const input = options.series;
@@ -6822,7 +7087,14 @@ var buildModel = (options, theme, hidden, cache, resolver = null) => {
6822
7087
  const categories = xType === "category" ? [...options.xAxis?.categories ?? collectCategories(datas)] : [];
6823
7088
  const categoryMap = new Map(categories.map((c, i) => [c, i]));
6824
7089
  const resolveX = xResolver(xType, (name) => categoryMap.get(name) ?? NaN);
6825
- const resolverKey = `${xType}|${categories.join("")}`;
7090
+ const yOpts = options.yAxis;
7091
+ const heatmapData = input.filter((s) => s.type === "heatmap").map((s) => s.data);
7092
+ const yCategories = yOpts?.type === "category" || !yOpts?.type && heatmapData.length ? [...yOpts?.categories ?? collectYCategories(heatmapData)] : [];
7093
+ const yType = yOpts?.type === "category" || yCategories.length ? "category" : yOpts?.type === "time" ? "time" : "linear";
7094
+ const yCategoryMap = new Map(yCategories.map((c, i) => [c, i]));
7095
+ const resolveY = (v) => typeof v === "number" ? v : typeof v === "string" ? yType === "category" ? yCategoryMap.get(v) ?? NaN : Number(v) : NaN;
7096
+ const resolverKey = `${xType}|${categories.join("")}|${yType}|${yCategories.join("")}`;
7097
+ const percent = options.stackMode === "percent";
6826
7098
  const usedKeys = /* @__PURE__ */ new Set();
6827
7099
  const series = input.map((s, index) => {
6828
7100
  let key = s.id ?? `#${index}`;
@@ -6833,15 +7105,16 @@ var buildModel = (options, theme, hidden, cache, resolver = null) => {
6833
7105
  entry = {
6834
7106
  data: s.data,
6835
7107
  resolverKey,
6836
- cols: normalizeData(s.data, resolveX)
7108
+ cols: normalizeData(s.data, resolveX, resolveY)
6837
7109
  };
6838
7110
  cache.set(key, entry);
6839
7111
  }
6840
7112
  const type = s.type ?? "line";
6841
- const color = s.color ? resolve(s.color, theme.palette[index % theme.palette.length]) : theme.palette[index % theme.palette.length];
7113
+ const paletteColor = theme.palette[index % theme.palette.length];
7114
+ const color = s.color ? resolve(s.color, paletteColor) : paletteColor;
6842
7115
  const cols = entry.cols;
6843
7116
  let pointColors = null;
6844
- if (type === "scatter" && cols.colors) {
7117
+ if ((type === "scatter" || type === "bar") && cols.colors) {
6845
7118
  const resolved = /* @__PURE__ */ new Map();
6846
7119
  pointColors = cols.colors.map((c) => {
6847
7120
  if (c === void 0) return void 0;
@@ -6850,6 +7123,23 @@ var buildModel = (options, theme, hidden, cache, resolver = null) => {
6850
7123
  return rgba;
6851
7124
  });
6852
7125
  }
7126
+ let colorScale = [];
7127
+ let valueRange = [0, 1];
7128
+ let cellColors = null;
7129
+ if (type === "heatmap") {
7130
+ colorScale = s.colorScale && s.colorScale.length ? s.colorScale.map((c) => resolve(c, color)) : [mix(theme.background, color, .08), color];
7131
+ valueRange = s.valueRange ? [s.valueRange[0], s.valueRange[1]] : [cols.valueMin, cols.valueMax];
7132
+ if (!Number.isFinite(valueRange[0])) valueRange = [0, 1];
7133
+ const values = cols.value ?? cols.y;
7134
+ const [lo, hi] = valueRange;
7135
+ const span = hi - lo || 1;
7136
+ cellColors = new Uint32Array(cols.count);
7137
+ for (let i = 0; i < cols.count; i++) {
7138
+ const v = values[i];
7139
+ if (!Number.isFinite(v) || !Number.isFinite(cols.y[i])) continue;
7140
+ cellColors[i] = packColor(rampColor(colorScale, (v - lo) / span));
7141
+ }
7142
+ }
6853
7143
  const id = s.id ?? String(index);
6854
7144
  return {
6855
7145
  index,
@@ -6859,61 +7149,93 @@ var buildModel = (options, theme, hidden, cache, resolver = null) => {
6859
7149
  type,
6860
7150
  color,
6861
7151
  colorCss: toCss(color),
6862
- lineWidth: s.lineWidth ?? 2,
7152
+ lineWidth: s.lineWidth ?? (type === "candlestick" ? 1 : 2),
6863
7153
  pointSize: s.pointSize ?? 8,
6864
7154
  opacity: s.opacity ?? (type === "area" ? .28 : type === "scatter" ? .78 : 1),
6865
7155
  hidden: !!s.hidden || hidden.has(id),
6866
7156
  showLabels: !!s.showLabels,
7157
+ curve: s.curve ?? "linear",
6867
7158
  cols,
6868
7159
  barOffset: 0,
6869
7160
  barHalfWidth: 0,
6870
7161
  barBase: null,
6871
7162
  barTop: null,
6872
- pointColors
7163
+ stackBase: null,
7164
+ stackTop: null,
7165
+ pointColors,
7166
+ upColor: type === "candlestick" ? resolve(s.upColor ?? DEFAULT_UP, [
7167
+ .09,
7168
+ .64,
7169
+ .29,
7170
+ 1
7171
+ ]) : color,
7172
+ downColor: type === "candlestick" ? resolve(s.downColor ?? DEFAULT_DOWN, [
7173
+ .86,
7174
+ .15,
7175
+ .15,
7176
+ 1
7177
+ ]) : color,
7178
+ cellColors,
7179
+ cellHalf: {
7180
+ x: .5,
7181
+ y: .5
7182
+ },
7183
+ colorScale,
7184
+ valueRange,
7185
+ radius: s.radius ?? (type === "heatmap" ? 2 : 3),
7186
+ format: s.format
6873
7187
  };
6874
7188
  });
6875
7189
  const visible = series.filter((s) => !s.hidden);
6876
- const allScatter = series.length > 0 && series.every((s) => s.type === "scatter");
7190
+ const allScatter = series.length > 0 && series.every((s) => s.type === "scatter" || s.type === "heatmap");
6877
7191
  const bars = visible.filter((s) => s.type === "bar");
6878
- const band = xType === "category" ? 1 : (() => {
6879
- const step = smallestStep(bars.map((s) => s.cols));
6880
- return Number.isFinite(step) ? step : 1;
6881
- })();
7192
+ const band = bandOf(bars, "x", xType === "category");
6882
7193
  if (bars.length) {
6883
7194
  const slots = /* @__PURE__ */ new Map();
6884
- for (const s of bars) {
6885
- const stack = input[s.index].stack ?? `\u0000${s.key}`;
6886
- if (!slots.has(stack)) slots.set(stack, slots.size);
6887
- }
7195
+ const stackId = (s) => input[s.index].stack ?? `\u0000${s.key}`;
7196
+ for (const s of bars) if (!slots.has(stackId(s))) slots.set(stackId(s), slots.size);
6888
7197
  const group = band * (slots.size > 1 ? .78 : .62);
6889
7198
  const slotWidth = group / slots.size;
6890
- const sums = /* @__PURE__ */ new Map();
6891
- for (const s of bars) {
6892
- const stack = input[s.index].stack ?? `\u0000${s.key}`;
6893
- const slot = slots.get(stack) ?? 0;
7199
+ const stacked = stackValues(bars.map((s) => ({
7200
+ s,
7201
+ stack: stackId(s)
7202
+ })), false);
7203
+ const percentStacked = percent ? stackValues(bars.filter((s) => input[s.index].stack !== void 0).map((s) => ({
7204
+ s,
7205
+ stack: stackId(s)
7206
+ })), true) : [];
7207
+ let p = 0;
7208
+ bars.forEach((s, k) => {
7209
+ const slot = slots.get(stackId(s)) ?? 0;
6894
7210
  s.barOffset = -group / 2 + slotWidth * (slot + .5);
6895
7211
  s.barHalfWidth = slotWidth / 2 * (slots.size > 1 ? .86 : 1);
6896
- let totals = sums.get(stack);
6897
- if (!totals) sums.set(stack, totals = /* @__PURE__ */ new Map());
6898
- const { x, y, count } = s.cols;
6899
- s.barBase = new Float64Array(count);
6900
- s.barTop = new Float64Array(count);
6901
- for (let i = 0; i < count; i++) {
6902
- const v = y[i];
6903
- if (!Number.isFinite(v)) {
6904
- s.barBase[i] = NaN;
6905
- s.barTop[i] = NaN;
6906
- continue;
6907
- }
6908
- const t = totals.get(x[i]) ?? [0, 0];
6909
- const base = v >= 0 ? t[0] : t[1];
6910
- s.barBase[i] = base;
6911
- s.barTop[i] = base + v;
6912
- if (v >= 0) t[0] += v;
6913
- else t[1] += v;
6914
- totals.set(x[i], t);
6915
- }
6916
- }
7212
+ const values = percent && input[s.index].stack !== void 0 ? percentStacked[p++] : stacked[k];
7213
+ s.barBase = values.base;
7214
+ s.barTop = values.top;
7215
+ });
7216
+ }
7217
+ const stackedLines = visible.filter((s) => (s.type === "line" || s.type === "area") && input[s.index].stack !== void 0);
7218
+ if (stackedLines.length) {
7219
+ const values = stackValues(stackedLines.map((s) => ({
7220
+ s,
7221
+ stack: input[s.index].stack ?? ""
7222
+ })), percent);
7223
+ stackedLines.forEach((s, k) => {
7224
+ s.stackBase = values[k].base;
7225
+ s.stackTop = values[k].top;
7226
+ });
7227
+ }
7228
+ const candles = visible.filter((s) => s.type === "candlestick");
7229
+ const candleBand = bandOf(candles, "x", xType === "category");
7230
+ for (const s of candles) s.barHalfWidth = candleBand * .3;
7231
+ const heatmaps = visible.filter((s) => s.type === "heatmap");
7232
+ if (heatmaps.length) {
7233
+ const cx = bandOf(heatmaps, "x", xType === "category") / 2;
7234
+ const cy = bandOf(heatmaps, "y", yType === "category") / 2;
7235
+ for (const s of heatmaps) s.cellHalf = {
7236
+ x: cx,
7237
+ y: cy
7238
+ };
6917
7239
  }
6918
7240
  const xOpts = options.xAxis;
6919
7241
  let xRange;
@@ -6922,31 +7244,48 @@ var buildModel = (options, theme, hidden, cache, resolver = null) => {
6922
7244
  const values = [];
6923
7245
  for (const s of visible) {
6924
7246
  values.push(s.cols.xMin, s.cols.xMax);
6925
- if (s.type === "bar") values.push(s.cols.xMin - band / 2, s.cols.xMax + band / 2);
7247
+ const pad = s.type === "bar" ? band / 2 : s.type === "candlestick" ? candleBand / 2 : s.type === "heatmap" ? s.cellHalf.x : 0;
7248
+ if (pad) values.push(s.cols.xMin - pad, s.cols.xMax + pad);
6926
7249
  }
6927
7250
  xRange = ensureSpan(...extent(values), xType === "time" ? [Date.now() - 864e5, Date.now()] : [0, 1]);
6928
- if (allScatter) {
7251
+ const pointsOnly = series.every((s) => s.type === "scatter");
7252
+ if (pointsOnly) {
6929
7253
  const pad = (xRange[1] - xRange[0]) * .04;
6930
7254
  xRange = [xRange[0] - pad, xRange[1] + pad];
6931
7255
  }
6932
- if ((xOpts?.nice ?? (allScatter && xType === "linear")) && xType === "linear") xRange = niceDomain(xRange[0], xRange[1], xOpts?.tickCount ?? 6);
7256
+ if ((xOpts?.nice ?? (pointsOnly && xType === "linear")) && xType === "linear") xRange = niceDomain(xRange[0], xRange[1], xOpts?.tickCount ?? 6);
6933
7257
  }
6934
7258
  if (xOpts?.min !== void 0) xRange[0] = xOpts.min;
6935
7259
  if (xOpts?.max !== void 0) xRange[1] = xOpts.max;
6936
7260
  xRange = ensureSpan(xRange[0], xRange[1]);
6937
- const yOpts = options.yAxis;
6938
- const yValues = [];
6939
- for (const s of visible) if (s.type === "bar" && s.barBase && s.barTop) yValues.push(...extent(s.barBase), ...extent(s.barTop));
6940
- else yValues.push(s.cols.yMin, s.cols.yMax);
6941
- if (bars.length || yOpts?.zero) yValues.push(0);
6942
- let yRange = ensureSpan(...extent(yValues));
6943
- if (allScatter) {
6944
- const pad = (yRange[1] - yRange[0]) * .06;
6945
- yRange = [yRange[0] - pad, yRange[1] + pad];
6946
- }
6947
- if ((yOpts?.nice ?? true) && (yOpts?.type ?? "linear") === "linear") yRange = niceDomain(yRange[0], yRange[1], yOpts?.tickCount ?? 5);
6948
- if (bars.length && !yOpts?.zero) {
6949
- if (yRange[0] < 0 && extent(yValues)[0] >= 0) yRange[0] = 0;
7261
+ let yRange;
7262
+ if (yType === "category") yRange = [-.5, Math.max(1, yCategories.length) - .5];
7263
+ else {
7264
+ const yValues = [];
7265
+ for (const s of visible) if (s.type === "bar" && s.barBase && s.barTop) yValues.push(...extent(s.barBase), ...extent(s.barTop));
7266
+ else if (s.stackBase && s.stackTop) yValues.push(...extent(s.stackBase), ...extent(s.stackTop));
7267
+ else if (s.type === "heatmap") yValues.push(s.cols.yMin - s.cellHalf.y, s.cols.yMax + s.cellHalf.y);
7268
+ else yValues.push(s.cols.yMin, s.cols.yMax);
7269
+ const filled = bars.length > 0 || visible.some((s) => s.type === "area");
7270
+ if (bars.length || yOpts?.zero) yValues.push(0);
7271
+ if (bars.some((s) => s.showLabels)) {
7272
+ const [lo, hi] = extent(yValues);
7273
+ if (hi > 0) yValues.push(hi + (hi - Math.min(0, lo)) * .1);
7274
+ if (lo < 0) yValues.push(lo - (Math.max(0, hi) - lo) * .1);
7275
+ }
7276
+ yRange = ensureSpan(...extent(yValues));
7277
+ if (series.every((s) => s.type === "scatter")) {
7278
+ const pad = (yRange[1] - yRange[0]) * .06;
7279
+ yRange = [yRange[0] - pad, yRange[1] + pad];
7280
+ } else if (candles.length && !bars.length) {
7281
+ const pad = (yRange[1] - yRange[0]) * .04;
7282
+ yRange = [yRange[0] - pad, yRange[1] + pad];
7283
+ }
7284
+ if ((yOpts?.nice ?? !heatmaps.length) && yType === "linear") yRange = niceDomain(yRange[0], yRange[1], yOpts?.tickCount ?? 5);
7285
+ if (percent && (bars.length || stackedLines.length)) yRange = [extent(yValues)[0] < 0 ? -100 : 0, 100];
7286
+ if (filled && !yOpts?.zero) {
7287
+ if (yRange[0] < 0 && extent(yValues)[0] >= 0) yRange[0] = 0;
7288
+ }
6950
7289
  }
6951
7290
  if (yOpts?.min !== void 0) yRange[0] = yOpts.min;
6952
7291
  if (yOpts?.max !== void 0) yRange[1] = yOpts.max;
@@ -6963,10 +7302,14 @@ var buildModel = (options, theme, hidden, cache, resolver = null) => {
6963
7302
  y: zoomOption.includes("y")
6964
7303
  };
6965
7304
  const tooltip = typeof options.tooltip === "object" ? options.tooltip : void 0;
7305
+ const yFormat = yOpts?.format ?? (percent && (bars.length || stackedLines.length) ? (v) => `${+v.toFixed(1)}%` : void 0);
6966
7306
  return {
6967
7307
  series,
6968
7308
  x: axisModel(xOpts, xType, categories, false),
6969
- y: axisModel(yOpts, yOpts?.type === "time" ? "time" : "linear", [], true),
7309
+ y: {
7310
+ ...axisModel(yOpts, yType, yCategories, yType !== "category"),
7311
+ format: yFormat
7312
+ },
6970
7313
  base: {
6971
7314
  x: xRange,
6972
7315
  y: yRange
@@ -6977,10 +7320,14 @@ var buildModel = (options, theme, hidden, cache, resolver = null) => {
6977
7320
  baseline: Math.min(Math.max(0, yRange[0]), yRange[1]),
6978
7321
  minSpan: {
6979
7322
  x: xType === "category" ? 1 : (xRange[1] - xRange[0]) * 1e-7,
6980
- y: (yRange[1] - yRange[0]) * 1e-7
6981
- }
7323
+ y: yType === "category" ? 1 : (yRange[1] - yRange[0]) * 1e-7
7324
+ },
7325
+ percent,
7326
+ stacks: input.map((s) => s.stack !== void 0 && (s.type === "bar" || s.type === "line" || s.type === "area" || !s.type) ? `${s.type === "bar" ? "bar" : "line"}:${s.stack}` : null)
6982
7327
  };
6983
7328
  };
7329
+ /** Y value drawn for a point: its stacked top for stacks, the close for candles */
7330
+ var plottedY = (s, i) => s.barTop ? s.barTop[i] : s.stackTop ? s.stackTop[i] : s.cols.y[i];
6984
7331
  var grids = /* @__PURE__ */ new WeakMap();
6985
7332
  /** Spatial index of a scatter series, built on first use and kept with its data */
6986
7333
  var gridOf = (s) => {
@@ -7135,7 +7482,19 @@ var placeLabels = (labels, plot, measure, height, occupied = []) => {
7135
7482
  for (const label of labels) {
7136
7483
  const w = measure(label.text);
7137
7484
  const gap = label.r + 4;
7138
- const box = [
7485
+ const above = {
7486
+ x: label.x - w / 2,
7487
+ y: label.y - gap - height,
7488
+ width: w,
7489
+ height
7490
+ };
7491
+ const below = {
7492
+ x: label.x - w / 2,
7493
+ y: label.y + gap,
7494
+ width: w,
7495
+ height
7496
+ };
7497
+ const box = (label.placement === "above" ? [above] : label.placement === "below" ? [below] : [
7139
7498
  {
7140
7499
  x: label.x + gap,
7141
7500
  y: label.y - height / 2,
@@ -7148,19 +7507,9 @@ var placeLabels = (labels, plot, measure, height, occupied = []) => {
7148
7507
  width: w,
7149
7508
  height
7150
7509
  },
7151
- {
7152
- x: label.x - w / 2,
7153
- y: label.y - gap - height,
7154
- width: w,
7155
- height
7156
- },
7157
- {
7158
- x: label.x - w / 2,
7159
- y: label.y + gap,
7160
- width: w,
7161
- height
7162
- }
7163
- ].find((c) => inside(c, plot) && !occupied.some((o) => overlaps(o, c)));
7510
+ above,
7511
+ below
7512
+ ]).find((c) => inside(c, plot) && !occupied.some((o) => overlaps(o, c)));
7164
7513
  if (!box) continue;
7165
7514
  occupied.push(box);
7166
7515
  placed.push({
@@ -7610,7 +7959,7 @@ var resolveAnnotations = (annotations, theme) => {
7610
7959
  /** Ticks, room for the axes and the plot rectangle */
7611
7960
  var layoutChart = (input) => {
7612
7961
  const { model, view, theme, width, height, measure } = input;
7613
- const yCount = model.y.tickCount ?? (height >= 220 ? 5 : Math.max(2, Math.round((height - 48) / 52)));
7962
+ const yCount = model.y.tickCount ?? (model.y.type === "category" ? Math.max(1, Math.floor((height - 40) / (theme.fontSize + 5))) : height >= 220 ? 5 : Math.max(2, Math.round((height - 48) / 52)));
7614
7963
  const yTicks = axisTicks(model.y, view.y, yCount);
7615
7964
  let yLabelWidth = 0;
7616
7965
  if (model.y.visible) for (const label of yTicks.labels) yLabelWidth = Math.max(yLabelWidth, measure(label));
@@ -7634,7 +7983,7 @@ var layoutChart = (input) => {
7634
7983
  fontSize: theme.fontSize
7635
7984
  });
7636
7985
  if (input.top) plot.y += input.top;
7637
- const xCount = model.x.type === "category" ? Math.max(1, Math.floor(plot.width / (categoryWidth + 14))) : model.x.tickCount ?? Math.max(2, Math.floor(plot.width / 96));
7986
+ const xCount = model.x.type === "category" ? Math.max(1, Math.floor(plot.width / (categoryWidth + 14))) : model.x.tickCount ?? Math.max(3, Math.floor(plot.width / 88));
7638
7987
  const xTicks = axisTicks(model.x, view.x, xCount);
7639
7988
  return {
7640
7989
  plot,
@@ -7643,11 +7992,32 @@ var layoutChart = (input) => {
7643
7992
  yTicks
7644
7993
  };
7645
7994
  };
7646
- /** Labels of the visible scatter points (`showLabels`) */
7647
- var collectPointLabels = (model, view, s) => {
7995
+ /** Labels of the visible scatter points and bar values (`showLabels`) */
7996
+ var collectPointLabels = (model, view, s, yTicks) => {
7648
7997
  const labels = [];
7998
+ const axisFormat = model.percent ? formatValue : yTicks?.formatValue ?? formatValue;
7649
7999
  for (const series of model.series) {
7650
- if (series.hidden || series.type !== "scatter" || !series.showLabels) continue;
8000
+ if (series.hidden || !series.showLabels) continue;
8001
+ if (series.type === "bar" && series.barTop) {
8002
+ const format = series.format ?? axisFormat;
8003
+ const { x, y, count } = series.cols;
8004
+ const top = series.barTop;
8005
+ const [x0, x1] = view.x[0] <= view.x[1] ? view.x : [view.x[1], view.x[0]];
8006
+ for (let i = 0; i < count && labels.length < 300; i++) {
8007
+ const xv = x[i] + series.barOffset;
8008
+ if (!Number.isFinite(y[i]) || xv < x0 || xv > x1) continue;
8009
+ const negative = top[i] < (series.barBase?.[i] ?? 0);
8010
+ labels.push({
8011
+ x: s.xToPx(xv),
8012
+ y: s.yToPx(top[i]),
8013
+ r: 0,
8014
+ text: format(y[i]),
8015
+ placement: negative ? "below" : "above"
8016
+ });
8017
+ }
8018
+ continue;
8019
+ }
8020
+ if (series.type !== "scatter") continue;
7651
8021
  const { x, y, count, labels: texts, size } = series.cols;
7652
8022
  if (!texts) continue;
7653
8023
  for (let i = 0; i < count && labels.length < 300; i++) {
@@ -7667,13 +8037,12 @@ var collectPointLabels = (model, view, s) => {
7667
8037
  }
7668
8038
  return labels;
7669
8039
  };
7670
- /** Pixel position of a point (the top of a bar) */
8040
+ /** Pixel position of a point (the top of a bar or stack, the close of a candle) */
7671
8041
  var pointOf = (s, i, sc) => {
7672
8042
  const xv = s.cols.x[i] + (s.type === "bar" ? s.barOffset : 0);
7673
- const yv = s.type === "bar" && s.barTop ? s.barTop[i] : s.cols.y[i];
7674
8043
  return {
7675
8044
  px: sc.xToPx(xv),
7676
- py: sc.yToPx(yv)
8045
+ py: sc.yToPx(plottedY(s, i))
7677
8046
  };
7678
8047
  };
7679
8048
  var candidateOf = (s, i, px, py, sc) => {
@@ -7683,6 +8052,12 @@ var candidateOf = (s, i, px, py, sc) => {
7683
8052
  const half = s.barHalfWidth / sc.xPerPx;
7684
8053
  const base = sc.yToPx(s.barBase[i]);
7685
8054
  inside = Math.abs(px - p.px) <= half && py >= Math.min(base, p.py) - 2 && py <= Math.max(base, p.py) + 2;
8055
+ } else if (s.type === "candlestick") {
8056
+ const { high, low, y } = s.cols;
8057
+ const half = Math.max(s.barHalfWidth / sc.xPerPx, 3);
8058
+ const a = sc.yToPx(high ? high[i] : y[i]);
8059
+ const b = sc.yToPx(low ? low[i] : y[i]);
8060
+ inside = Math.abs(px - p.px) <= half && py >= Math.min(a, b) - 2 && py <= Math.max(a, b) + 2;
7686
8061
  }
7687
8062
  return {
7688
8063
  series: s,
@@ -7714,6 +8089,16 @@ var nearestScatter = (s, px, py, sc, slop) => {
7714
8089
  });
7715
8090
  return best;
7716
8091
  };
8092
+ /** Heatmap cell containing a data position, -1 if none */
8093
+ var cellAt = (s, xv, yv) => {
8094
+ const { x: hx, y: hy } = s.cellHalf;
8095
+ const { x, y } = s.cols;
8096
+ let found = -1;
8097
+ gridOf(s).query(xv - hx, xv + hx, yv - hy, yv + hy, (i) => {
8098
+ if (s.cellColors?.[i] && Math.abs(x[i] - xv) <= hx && Math.abs(y[i] - yv) <= hy) found = i;
8099
+ });
8100
+ return found;
8101
+ };
7717
8102
  var nearestX = (s, xv) => {
7718
8103
  const { x, y, count, sorted } = s.cols;
7719
8104
  if (sorted) return nearestIndex(x, y, count, xv);
@@ -7733,6 +8118,21 @@ var nearestX = (s, xv) => {
7733
8118
  var hoverItemOf = (s, index) => {
7734
8119
  const pc = s.pointColors?.[index];
7735
8120
  const label = s.cols.labels?.[index];
8121
+ const { open, high, low, value } = s.cols;
8122
+ let color = pc ? toCss(pc) : s.colorCss;
8123
+ const extra = {};
8124
+ if (s.type === "candlestick") {
8125
+ const o = open ? open[index] : NaN;
8126
+ if (Number.isFinite(o)) extra.open = o;
8127
+ if (high && Number.isFinite(high[index])) extra.high = high[index];
8128
+ if (low && Number.isFinite(low[index])) extra.low = low[index];
8129
+ color = toCss(s.cols.y[index] < o ? s.downColor : s.upColor);
8130
+ } else if (s.type === "heatmap") {
8131
+ const v = value ? value[index] : s.cols.y[index];
8132
+ if (Number.isFinite(v)) extra.value = v;
8133
+ const packed = s.cellColors?.[index];
8134
+ if (packed) color = toCss(unpackColor(packed));
8135
+ }
7736
8136
  return {
7737
8137
  seriesIndex: s.index,
7738
8138
  seriesId: s.id,
@@ -7740,8 +8140,9 @@ var hoverItemOf = (s, index) => {
7740
8140
  index,
7741
8141
  x: s.cols.x[index],
7742
8142
  y: s.cols.y[index],
7743
- color: pc ? toCss(pc) : s.colorCss,
7744
- ...label !== void 0 ? { label } : {}
8143
+ color,
8144
+ ...label !== void 0 ? { label } : {},
8145
+ ...extra
7745
8146
  };
7746
8147
  };
7747
8148
  var eventOf = (candidates, xTicks) => {
@@ -7772,6 +8173,14 @@ var hitTest = (model, sc, xTicks, px, py, slop = 0) => {
7772
8173
  if (s.type === "scatter") {
7773
8174
  const i = nearestScatter(s, px, py, sc, slop);
7774
8175
  if (i >= 0) scatter.push(candidateOf(s, i, px, py, sc));
8176
+ } else if (s.type === "heatmap") {
8177
+ const i = cellAt(s, sc.pxToX(px), sc.pxToY(py));
8178
+ if (i >= 0) {
8179
+ const c = candidateOf(s, i, px, py, sc);
8180
+ c.inside = true;
8181
+ c.dist = 0;
8182
+ scatter.push(c);
8183
+ }
7775
8184
  } else {
7776
8185
  const i = nearestX(s, xv);
7777
8186
  if (i >= 0) others.push(candidateOf(s, i, px, py, sc));
@@ -7806,6 +8215,20 @@ var sameHover = (a, b) => a === b || !!a && !!b && a.items.length === b.items.le
7806
8215
  /** Default tooltip content of a hover payload */
7807
8216
  var tooltipContent = (model, event, yTicks) => {
7808
8217
  const yFormat = yTicks?.formatValue ?? String;
8218
+ const first = event.items[0];
8219
+ const firstSeries = first ? model.series[first.seriesIndex] : null;
8220
+ if (event.items.length === 1 && firstSeries?.type === "heatmap") {
8221
+ const yName = model.y.type === "category" ? model.y.categories[Math.round(first.y)] ?? yFormat(first.y) : yFormat(first.y);
8222
+ return {
8223
+ title: `${event.xLabel} · ${yName}`,
8224
+ titleColor: null,
8225
+ rows: [{
8226
+ color: first.color,
8227
+ name: first.label ?? firstSeries.name,
8228
+ value: first.value === void 0 ? "–" : (firstSeries.format ?? formatValue)(first.value)
8229
+ }]
8230
+ };
8231
+ }
7809
8232
  if (event.items.every((it) => model.series[it.seriesIndex].type === "scatter") && event.items.length === 1) {
7810
8233
  const it = event.items[0];
7811
8234
  const rows = [{
@@ -7828,52 +8251,125 @@ var tooltipContent = (model, event, yTicks) => {
7828
8251
  rows
7829
8252
  };
7830
8253
  }
8254
+ const rows = [];
8255
+ /** Row of every item */
8256
+ const rowOf = [];
8257
+ for (const it of event.items) {
8258
+ const s = model.series[it.seriesIndex];
8259
+ rowOf.push(rows.length);
8260
+ if (s.type === "candlestick") {
8261
+ const change = it.open !== void 0 && it.open !== 0 ? (it.y - it.open) / Math.abs(it.open) * 100 : NaN;
8262
+ rows.push({
8263
+ color: it.color,
8264
+ name: s.name,
8265
+ value: Number.isFinite(change) ? `${change >= 0 ? "+" : ""}${change.toFixed(2)}%` : ""
8266
+ });
8267
+ const ohlc = [
8268
+ ["Open", it.open],
8269
+ ["High", it.high],
8270
+ ["Low", it.low],
8271
+ ["Close", it.y]
8272
+ ];
8273
+ for (const [name, v] of ohlc) if (v !== void 0 && Number.isFinite(v)) rows.push({
8274
+ color: null,
8275
+ name,
8276
+ value: (s.format ?? yFormat)(v)
8277
+ });
8278
+ continue;
8279
+ }
8280
+ rows.push({
8281
+ color: it.color,
8282
+ name: it.label ? `${it.seriesName} · ${it.label}` : it.seriesName,
8283
+ value: (s.format ?? yFormat)(it.y)
8284
+ });
8285
+ }
8286
+ if (model.percent) {
8287
+ const totals = /* @__PURE__ */ new Map();
8288
+ for (const it of event.items) {
8289
+ const stack = stackIdOf(model, it.seriesIndex);
8290
+ if (stack !== null && Number.isFinite(it.y)) totals.set(stack, (totals.get(stack) ?? 0) + Math.abs(it.y));
8291
+ }
8292
+ event.items.forEach((it, k) => {
8293
+ const stack = stackIdOf(model, it.seriesIndex);
8294
+ const total = stack !== null ? totals.get(stack) : void 0;
8295
+ const row = rows[rowOf[k]];
8296
+ if (total && row && Number.isFinite(it.y)) row.value = `${(model.series[it.seriesIndex].format ?? formatValue)(it.y)} · ${(Math.abs(it.y) / total * 100).toFixed(1)}%`;
8297
+ });
8298
+ }
7831
8299
  return {
7832
8300
  title: event.xLabel,
7833
8301
  titleColor: null,
7834
- rows: event.items.map((it) => ({
7835
- color: it.color,
7836
- name: it.label ? `${it.seriesName} · ${it.label}` : it.seriesName,
7837
- value: yFormat(it.y)
7838
- }))
8302
+ rows
7839
8303
  };
7840
8304
  };
7841
- /** Markers of the hovered points (pixels of the stage) */
8305
+ /** Stack of a series in a 100% chart (`null` when it is not stacked) */
8306
+ var stackIdOf = (model, seriesIndex) => model.series[seriesIndex].hidden ? null : model.stacks[seriesIndex];
8307
+ /** Markers of the hovered points (pixels of the stage); bands come first */
7842
8308
  var hoverMarks = (model, sc, event) => {
7843
8309
  const marks = [];
7844
8310
  const { plot } = sc;
8311
+ let bandLo = Infinity;
8312
+ let bandHi = -Infinity;
7845
8313
  for (const it of event.items) {
7846
8314
  const s = model.series[it.seriesIndex];
7847
- if (s.type === "bar" && s.barBase && s.barTop) {
8315
+ if (s.type === "bar" || s.type === "candlestick") {
7848
8316
  const cx = sc.xToPx(it.x + s.barOffset);
7849
8317
  const half = Math.max(s.barHalfWidth / sc.xPerPx, 1);
7850
- const a = sc.yToPx(s.barBase[it.index]);
7851
- const b = sc.yToPx(s.barTop[it.index]);
8318
+ bandLo = Math.min(bandLo, cx - half);
8319
+ bandHi = Math.max(bandHi, cx + half);
8320
+ continue;
8321
+ }
8322
+ if (s.type === "heatmap") {
8323
+ const cx = sc.xToPx(it.x);
8324
+ const cy = sc.yToPx(it.y);
8325
+ const hw = Math.abs(s.cellHalf.x / sc.xPerPx);
8326
+ const hh = Math.abs(s.cellHalf.y / sc.yPerPx);
7852
8327
  marks.push({
7853
- kind: "bar",
7854
- x: cx - half,
7855
- y: Math.min(a, b),
7856
- width: half * 2,
7857
- height: Math.max(1, Math.abs(a - b))
8328
+ kind: "cell",
8329
+ x: cx - hw,
8330
+ y: cy - hh,
8331
+ width: hw * 2,
8332
+ height: hh * 2
7858
8333
  });
7859
8334
  continue;
7860
8335
  }
7861
- const px = sc.xToPx(it.x);
7862
- const py = sc.yToPx(it.y);
8336
+ const { px, py } = pointOf(s, it.index, sc);
7863
8337
  if (px < plot.x - 1 || px > plot.x + plot.width + 1 || py < plot.y - 1 || py > plot.y + plot.height + 1) continue;
7864
- const size = s.type === "scatter" ? dotSize(s, it.index) + 6 : Math.max(10, s.lineWidth * 2 + 6);
8338
+ const size = s.type === "scatter" ? dotSize(s, it.index) + 4 : Math.max(9, s.lineWidth * 2 + 5);
8339
+ const rgba = s.pointColors?.[it.index] ?? s.color;
7865
8340
  marks.push({
7866
8341
  kind: "dot",
7867
8342
  x: px,
7868
8343
  y: py,
7869
8344
  size,
7870
- color: it.color
8345
+ color: it.color,
8346
+ halo: toCss(rgba, .2)
8347
+ });
8348
+ }
8349
+ if (bandHi > bandLo) {
8350
+ const pad = Math.max(4, (bandHi - bandLo) * .14);
8351
+ const x0 = Math.max(plot.x, bandLo - pad);
8352
+ const x1 = Math.min(plot.x + plot.width, bandHi + pad);
8353
+ if (x1 > x0) marks.unshift({
8354
+ kind: "band",
8355
+ x: x0,
8356
+ y: plot.y,
8357
+ width: x1 - x0,
8358
+ height: plot.height
7871
8359
  });
7872
8360
  }
7873
8361
  return marks;
7874
8362
  };
8363
+ /** Swatch of a series in the legend */
8364
+ var legendShape = (type) => type === "scatter" ? "dot" : type === "line" ? "line" : "square";
7875
8365
  /** Whether the guide line follows the pointer */
7876
- var showsCrosshair = (model, event, crosshair) => crosshair ?? (model.tooltipMode === "axis" && event.items.some((it) => model.series[it.seriesIndex].type !== "scatter"));
8366
+ var showsCrosshair = (model, event, crosshair) => crosshair ?? (model.tooltipMode === "axis" && event.items.some((it) => {
8367
+ const type = model.series[it.seriesIndex].type;
8368
+ return type === "line" || type === "area";
8369
+ }) && !event.items.some((it) => {
8370
+ const type = model.series[it.seriesIndex].type;
8371
+ return type === "bar" || type === "candlestick";
8372
+ }));
7877
8373
  //#endregion
7878
8374
  //#region ../charts/src/engine/theme.ts
7879
8375
  /** Used when no CSS variable is defined (e.g. without the Minerva stylesheet) */
@@ -8065,7 +8561,7 @@ var createChartController = (config) => {
8065
8561
  id: s.id,
8066
8562
  name: s.name,
8067
8563
  color: s.colorCss,
8068
- shape: s.type === "scatter" ? "dot" : s.type === "line" ? "line" : "square",
8564
+ shape: legendShape(s.type),
8069
8565
  hidden: s.hidden,
8070
8566
  box: {
8071
8567
  x,
@@ -8141,7 +8637,7 @@ var createChartController = (config) => {
8141
8637
  top: legendTop,
8142
8638
  measure: (text) => measure(text)
8143
8639
  });
8144
- const labels = collectPointLabels(model, view, layout.scales);
8640
+ const labels = collectPointLabels(model, view, layout.scales, layout.yTicks);
8145
8641
  const occupied = [];
8146
8642
  const labelHeight = theme.fontSize + 4;
8147
8643
  for (const a of annotations) {
@@ -8567,19 +9063,49 @@ var GAP = 3e38;
8567
9063
  //#endregion
8568
9064
  //#region ../charts/src/engine/items.ts
8569
9065
  var rel = (value, origin) => Number.isFinite(value) ? value - origin : GAP;
8570
- var points = (x, y, count, o) => {
8571
- const out = new Float32Array(count * 2);
8572
- for (let i = 0; i < count; i++) {
8573
- out[i * 2] = rel(x[i], o.x);
8574
- out[i * 2 + 1] = Number.isFinite(y[i]) ? y[i] - o.y : GAP;
8575
- }
8576
- return out;
8577
- };
8578
9066
  var DRAW_ORDER = {
8579
- area: 0,
8580
- bar: 1,
8581
- line: 2,
8582
- scatter: 3
9067
+ heatmap: 0,
9068
+ area: 1,
9069
+ bar: 2,
9070
+ candlestick: 3,
9071
+ line: 4,
9072
+ scatter: 5
9073
+ };
9074
+ /** Line (and area) points of a series: stacked, curved; interleaved x, y */
9075
+ var linePoints = (s) => {
9076
+ const { x, count } = s.cols;
9077
+ const top = s.stackTop ?? s.cols.y;
9078
+ const stackBase = s.stackBase;
9079
+ if (s.curve === "linear") return {
9080
+ n: count,
9081
+ xAt: (i) => x[i],
9082
+ yAt: (i) => top[i],
9083
+ baseAt: stackBase ? (i) => stackBase[i] : null
9084
+ };
9085
+ const curved = curvePoints(x, top, 0, count, s.curve);
9086
+ const base = stackBase ? curvePoints(x, stackBase, 0, count, s.curve).points : null;
9087
+ const points = curved.points;
9088
+ return {
9089
+ n: curved.length,
9090
+ xAt: (i) => points[i * 2],
9091
+ yAt: (i) => points[i * 2 + 1],
9092
+ baseAt: base ? (i) => base[i * 2 + 1] : null
9093
+ };
9094
+ };
9095
+ var barItem = (key, version, s, count, write, extra) => {
9096
+ const instances = /* @__PURE__ */ new ArrayBuffer(count * 16);
9097
+ const f = new Float32Array(instances);
9098
+ const u = new Uint32Array(instances);
9099
+ for (let i = 0; i < count; i++) write(i, f, u);
9100
+ return {
9101
+ kind: "bar",
9102
+ key,
9103
+ version,
9104
+ color: s.color,
9105
+ instances,
9106
+ count,
9107
+ ...extra
9108
+ };
8583
9109
  };
8584
9110
  /** Render items of the visible series, back to front */
8585
9111
  var buildItems = (model, origin, version) => {
@@ -8593,25 +9119,48 @@ var buildItems = (model, origin, version) => {
8593
9119
  switch (s.type) {
8594
9120
  case "line":
8595
9121
  case "area": {
8596
- const pts = points(x, y, count, origin);
8597
- if (s.type === "area") items.push({
8598
- kind: "area",
8599
- key: `${s.key}:area`,
8600
- version,
8601
- color: s.color,
8602
- points: pts,
8603
- count,
8604
- baseline: model.baseline - origin.y,
8605
- opacity: s.opacity,
8606
- sorted
8607
- });
9122
+ const { n, xAt, yAt, baseAt } = linePoints(s);
9123
+ const pts = new Float32Array(n * 2);
9124
+ if (s.curve === "linear") {
9125
+ const top = s.stackTop ?? y;
9126
+ const ox = origin.x;
9127
+ const oy = origin.y;
9128
+ for (let i = 0; i < n; i++) {
9129
+ const xv = x[i];
9130
+ const yv = top[i];
9131
+ pts[i * 2] = Number.isFinite(xv) ? xv - ox : GAP;
9132
+ pts[i * 2 + 1] = Number.isFinite(yv) ? yv - oy : GAP;
9133
+ }
9134
+ } else for (let i = 0; i < n; i++) {
9135
+ pts[i * 2] = rel(xAt(i), origin.x);
9136
+ pts[i * 2 + 1] = rel(yAt(i), origin.y);
9137
+ }
9138
+ if (s.type === "area") {
9139
+ const area = new Float32Array(n * 3);
9140
+ const baseline = model.baseline - origin.y;
9141
+ for (let i = 0; i < n; i++) {
9142
+ area[i * 3] = pts[i * 2];
9143
+ area[i * 3 + 1] = pts[i * 2 + 1];
9144
+ area[i * 3 + 2] = baseAt ? rel(baseAt(i), origin.y) : baseline;
9145
+ }
9146
+ items.push({
9147
+ kind: "area",
9148
+ key: `${s.key}:area`,
9149
+ version,
9150
+ color: s.color,
9151
+ points: area,
9152
+ count: n,
9153
+ opacity: s.opacity,
9154
+ sorted
9155
+ });
9156
+ }
8608
9157
  (s.type === "area" ? outlines : items).push({
8609
9158
  kind: "line",
8610
9159
  key: `${s.key}:line`,
8611
9160
  version,
8612
9161
  color: s.color,
8613
9162
  points: pts,
8614
- count,
9163
+ count: n,
8615
9164
  width: s.lineWidth,
8616
9165
  sorted
8617
9166
  });
@@ -8620,24 +9169,76 @@ var buildItems = (model, origin, version) => {
8620
9169
  case "bar": {
8621
9170
  const base = s.barBase ?? new Float64Array(count);
8622
9171
  const top = s.barTop ?? y;
8623
- const instances = new Float32Array(count * 3);
8624
- for (let i = 0; i < count; i++) {
9172
+ const seriesColor = packColor(s.color);
9173
+ const shared = model.series.some((o) => o !== s && !o.hidden && o.type === "bar" && o.barOffset === s.barOffset);
9174
+ items.push(barItem(`${s.key}:bar`, version, s, count, (i, f, u) => {
8625
9175
  const valid = Number.isFinite(top[i]) && Number.isFinite(base[i]);
8626
- instances[i * 3] = rel(x[i] + s.barOffset, origin.x);
8627
- instances[i * 3 + 1] = valid ? base[i] - origin.y : GAP;
8628
- instances[i * 3 + 2] = valid ? top[i] - origin.y : GAP;
8629
- }
8630
- items.push({
8631
- kind: "bar",
8632
- key: `${s.key}:bar`,
8633
- version,
8634
- color: s.color,
8635
- instances,
8636
- count,
9176
+ f[i * 4] = rel(x[i] + s.barOffset, origin.x);
9177
+ f[i * 4 + 1] = valid ? base[i] - origin.y : GAP;
9178
+ f[i * 4 + 2] = valid ? top[i] - origin.y : GAP;
9179
+ const pc = s.pointColors?.[i];
9180
+ u[i * 4 + 3] = pc ? packColor(pc) : seriesColor;
9181
+ }, {
8637
9182
  halfWidth: s.barHalfWidth,
8638
- sorted,
8639
- radius: model.series.some((o) => o !== s && !o.hidden && o.type === "bar" && o.barOffset === s.barOffset) ? 0 : 3
8640
- });
9183
+ radius: shared ? 0 : s.radius,
9184
+ inset: 0,
9185
+ minHalf: 0,
9186
+ sorted
9187
+ }));
9188
+ break;
9189
+ }
9190
+ case "candlestick": {
9191
+ const { open, high, low } = s.cols;
9192
+ const up = packColor(s.upColor);
9193
+ const down = packColor(s.downColor);
9194
+ const colorAt = (i) => open && Number.isFinite(open[i]) && y[i] < open[i] ? down : up;
9195
+ items.push(barItem(`${s.key}:wick`, version, s, count, (i, f, u) => {
9196
+ const hi = high ? high[i] : y[i];
9197
+ const lo = low ? low[i] : y[i];
9198
+ const valid = Number.isFinite(hi) && Number.isFinite(lo) && Number.isFinite(y[i]);
9199
+ f[i * 4] = rel(x[i], origin.x);
9200
+ f[i * 4 + 1] = valid ? lo - origin.y : GAP;
9201
+ f[i * 4 + 2] = valid ? hi - origin.y : GAP;
9202
+ u[i * 4 + 3] = colorAt(i);
9203
+ }, {
9204
+ halfWidth: 0,
9205
+ radius: 0,
9206
+ inset: 0,
9207
+ minHalf: s.lineWidth / 2,
9208
+ sorted
9209
+ }), barItem(`${s.key}:body`, version, s, count, (i, f, u) => {
9210
+ const o = open ? open[i] : y[i];
9211
+ const valid = Number.isFinite(o) && Number.isFinite(y[i]);
9212
+ f[i * 4] = rel(x[i], origin.x);
9213
+ f[i * 4 + 1] = valid ? o - origin.y : GAP;
9214
+ f[i * 4 + 2] = valid ? y[i] - origin.y : GAP;
9215
+ u[i * 4 + 3] = colorAt(i);
9216
+ }, {
9217
+ halfWidth: s.barHalfWidth,
9218
+ radius: Math.min(s.radius, 1.5),
9219
+ inset: 0,
9220
+ minHalf: .5,
9221
+ sorted
9222
+ }));
9223
+ break;
9224
+ }
9225
+ case "heatmap": {
9226
+ const colors = s.cellColors;
9227
+ const hy = s.cellHalf.y;
9228
+ items.push(barItem(`${s.key}:cells`, version, s, count, (i, f, u) => {
9229
+ const c = colors ? colors[i] : 0;
9230
+ const valid = c !== 0 && Number.isFinite(x[i]);
9231
+ f[i * 4] = rel(x[i], origin.x);
9232
+ f[i * 4 + 1] = valid ? y[i] - hy - origin.y : GAP;
9233
+ f[i * 4 + 2] = valid ? y[i] + hy - origin.y : GAP;
9234
+ u[i * 4 + 3] = c;
9235
+ }, {
9236
+ halfWidth: s.cellHalf.x,
9237
+ radius: s.radius,
9238
+ inset: 1,
9239
+ minHalf: 0,
9240
+ sorted
9241
+ }));
8641
9242
  break;
8642
9243
  }
8643
9244
  default: {
@@ -8673,25 +9274,77 @@ var buildItems = (model, origin, version) => {
8673
9274
  return items;
8674
9275
  };
8675
9276
  var rgba = (c, alpha) => `rgba(${Math.round(c[0] * 255)},${Math.round(c[1] * 255)},${Math.round(c[2] * 255)},${c[3] * alpha})`;
8676
- var unpack = (packed) => [
8677
- (packed & 255) / 255,
8678
- (packed >>> 8 & 255) / 255,
8679
- (packed >>> 16 & 255) / 255,
8680
- (packed >>> 24 & 255) / 255
8681
- ];
8682
9277
  var isGap = (v) => !Number.isFinite(v) || Math.abs(v) >= 15e37;
8683
9278
  /** First point index whose relative x is >= value (sorted, interleaved) */
8684
- var lowerBoundX = (points, count, value) => {
9279
+ var lowerBoundX = (points, count, value, stride = 2) => {
8685
9280
  let lo = 0;
8686
9281
  let hi = count;
8687
9282
  while (lo < hi) {
8688
9283
  const mid = lo + hi >>> 1;
8689
- if (points[mid * 2] < value) lo = mid + 1;
9284
+ if (points[mid * stride] < value) lo = mid + 1;
8690
9285
  else hi = mid;
8691
9286
  }
8692
9287
  return lo;
8693
9288
  };
8694
9289
  /**
9290
+ * Min-max decimation of area points (x, top, bottom): per pixel column the
9291
+ * first, lowest, highest and last tops are kept with their bottoms
9292
+ */
9293
+ var decimateArea = (points, start, end, column) => {
9294
+ const out = new Float64Array(Math.max(0, end - start) * 3);
9295
+ let length = 0;
9296
+ const push = (i) => {
9297
+ out[length * 3] = points[i * 3];
9298
+ out[length * 3 + 1] = points[i * 3 + 1];
9299
+ out[length * 3 + 2] = points[i * 3 + 2];
9300
+ length++;
9301
+ };
9302
+ let col = NaN;
9303
+ let first = -1;
9304
+ let min = -1;
9305
+ let max = -1;
9306
+ let last = -1;
9307
+ const flush = () => {
9308
+ if (first < 0) return;
9309
+ const picks = [
9310
+ first,
9311
+ min,
9312
+ max,
9313
+ last
9314
+ ].sort((a, b) => a - b);
9315
+ let prev = -1;
9316
+ for (const i of picks) {
9317
+ if (i !== prev) push(i);
9318
+ prev = i;
9319
+ }
9320
+ first = -1;
9321
+ };
9322
+ for (let i = start; i < end; i++) {
9323
+ const y = points[i * 3 + 1];
9324
+ if (isGap(points[i * 3]) || isGap(y) || isGap(points[i * 3 + 2])) {
9325
+ flush();
9326
+ col = NaN;
9327
+ push(i);
9328
+ continue;
9329
+ }
9330
+ const c = Math.floor(column(points[i * 3]));
9331
+ if (c !== col || first < 0) {
9332
+ flush();
9333
+ col = c;
9334
+ first = min = max = last = i;
9335
+ } else {
9336
+ if (y < points[min * 3 + 1]) min = i;
9337
+ if (y > points[max * 3 + 1]) max = i;
9338
+ last = i;
9339
+ }
9340
+ }
9341
+ flush();
9342
+ return {
9343
+ points: out,
9344
+ length
9345
+ };
9346
+ };
9347
+ /**
8695
9348
  * Data layer drawn with any 2D context (browser canvases, mini-program
8696
9349
  * canvases, OffscreenCanvas). `scratchCanvas` creates the canvas used to
8697
9350
  * rasterize very large scatter sets; without it they are drawn as one
@@ -8754,61 +9407,82 @@ var createCanvas2dPainter = (ctx, scratchCanvas) => {
8754
9407
  };
8755
9408
  const drawArea = (item, frame) => {
8756
9409
  const m = mapper(frame);
8757
- const { points, length } = visiblePoints(item, frame);
8758
- const base = m.py(item.baseline);
8759
- const gradient = ctx.createLinearGradient(0, 0, 0, base);
9410
+ let points = item.points;
9411
+ let length = item.count;
9412
+ if (item.sorted && item.count > frame.width * 2) {
9413
+ const [x0, x1] = m.xRange();
9414
+ const start = Math.max(0, lowerBoundX(item.points, item.count, x0, 3) - 1);
9415
+ const end = Math.min(item.count, lowerBoundX(item.points, item.count, x1, 3) + 1);
9416
+ ({points, length} = decimateArea(item.points, start, end, m.px));
9417
+ }
9418
+ const gradient = ctx.createLinearGradient(0, 0, 0, frame.height);
8760
9419
  gradient.addColorStop(0, rgba(item.color, item.opacity));
8761
- gradient.addColorStop(1, rgba(item.color, item.opacity * .3));
9420
+ gradient.addColorStop(1, rgba(item.color, item.opacity * .25));
8762
9421
  ctx.fillStyle = gradient;
8763
9422
  ctx.beginPath();
8764
9423
  let runStart = -1;
8765
- let lastX = 0;
8766
- const close = () => {
9424
+ const close = (end) => {
8767
9425
  if (runStart < 0) return;
8768
- ctx.lineTo(lastX, base);
9426
+ for (let k = end - 1; k >= runStart; k--) ctx.lineTo(m.px(points[k * 3]), m.py(points[k * 3 + 2]));
8769
9427
  ctx.closePath();
8770
9428
  runStart = -1;
8771
9429
  };
8772
9430
  for (let i = 0; i < length; i++) {
8773
- const x = points[i * 2];
8774
- const y = points[i * 2 + 1];
8775
- if (isGap(x) || isGap(y)) {
8776
- close();
9431
+ const x = points[i * 3];
9432
+ const y = points[i * 3 + 1];
9433
+ if (isGap(x) || isGap(y) || isGap(points[i * 3 + 2])) {
9434
+ close(i);
8777
9435
  continue;
8778
9436
  }
8779
- const px = m.px(x);
8780
9437
  if (runStart < 0) {
8781
9438
  runStart = i;
8782
- ctx.moveTo(px, base);
8783
- }
8784
- ctx.lineTo(px, m.py(y));
8785
- lastX = px;
9439
+ ctx.moveTo(m.px(x), m.py(y));
9440
+ } else ctx.lineTo(m.px(x), m.py(y));
8786
9441
  }
8787
- close();
9442
+ close(length);
8788
9443
  ctx.fill();
8789
9444
  };
8790
9445
  const drawBars = (item, frame) => {
8791
9446
  const m = mapper(frame);
8792
- const half = Math.max(Math.abs(item.halfWidth * frame.transform.xScale) * .5 * frame.width, .5);
8793
- const r = item.radius * frame.dpr;
8794
- ctx.fillStyle = rgba(item.color, 1);
8795
- ctx.beginPath();
8796
- const v = item.instances;
9447
+ const dpr = frame.dpr;
9448
+ const minHalf = item.minHalf * dpr;
9449
+ const rawHalf = Math.abs(item.halfWidth * frame.transform.xScale) * .5 * frame.width;
9450
+ const r = item.radius * dpr;
9451
+ const f = new Float32Array(item.instances, 0, item.count * 4);
9452
+ const u = new Uint32Array(item.instances, 0, item.count * 4);
9453
+ const [x0, x1] = m.xRange();
9454
+ const pad = Math.abs(item.halfWidth);
9455
+ const groups = /* @__PURE__ */ new Map();
8797
9456
  for (let i = 0; i < item.count; i++) {
8798
- const x = v[i * 3];
8799
- const y0 = v[i * 3 + 1];
8800
- const y1 = v[i * 3 + 2];
8801
- if (isGap(x) || isGap(y0) || isGap(y1)) continue;
8802
- const cx = m.px(x);
8803
- const a = m.py(y0);
8804
- const b = m.py(y1);
8805
- const top = Math.min(a, b);
8806
- const height = Math.abs(a - b);
8807
- const radius = Math.min(r, half, height / 2);
8808
- if (radius > .5 && typeof ctx.roundRect === "function") ctx.roundRect(cx - half, top, half * 2, height, radius);
8809
- else ctx.rect(cx - half, top, half * 2, height);
9457
+ const x = f[i * 4];
9458
+ if (isGap(x) || isGap(f[i * 4 + 1]) || isGap(f[i * 4 + 2])) continue;
9459
+ if (x < x0 - pad || x > x1 + pad) continue;
9460
+ const packed = u[i * 4 + 3];
9461
+ let list = groups.get(packed);
9462
+ if (!list) groups.set(packed, list = []);
9463
+ list.push(i);
9464
+ }
9465
+ const rounded = typeof ctx.roundRect === "function";
9466
+ for (const [packed, list] of groups) {
9467
+ ctx.fillStyle = rgba(unpackColor(packed), 1);
9468
+ ctx.beginPath();
9469
+ for (const i of list) {
9470
+ const cx = m.px(f[i * 4]);
9471
+ const a = m.py(f[i * 4 + 1]);
9472
+ const b = m.py(f[i * 4 + 2]);
9473
+ const rawHh = Math.abs(a - b) / 2;
9474
+ const fade = Math.min(1, Math.max(0, (Math.min(rawHalf, rawHh) - 3 * dpr) / (2 * dpr)));
9475
+ const inset = item.inset * dpr * fade - (item.inset > 0 ? .5 * (1 - fade) : 0);
9476
+ const half = Math.max(rawHalf - inset, .5, minHalf);
9477
+ const hh = Math.max(rawHh - inset, minHalf);
9478
+ if (hh <= 0) continue;
9479
+ const cy = (a + b) / 2;
9480
+ const radius = Math.min(r, half, hh);
9481
+ if (radius > .5 && rounded) ctx.roundRect(cx - half, cy - hh, half * 2, hh * 2, radius);
9482
+ else ctx.rect(cx - half, cy - hh, half * 2, hh * 2);
9483
+ }
9484
+ ctx.fill();
8810
9485
  }
8811
- ctx.fill();
8812
9486
  };
8813
9487
  /** One square per occupied cell (the last point of a cell wins, like the GPU) */
8814
9488
  const drawScatterCells = (item, frame) => {
@@ -8842,7 +9516,7 @@ var createCanvas2dPainter = (ctx, scratchCanvas) => {
8842
9516
  list.push(c);
8843
9517
  }
8844
9518
  for (const [packed, cells] of groups) {
8845
- ctx.fillStyle = rgba(unpack(packed), Math.max(item.opacity, .6));
9519
+ ctx.fillStyle = rgba(unpackColor(packed), Math.max(item.opacity, .6));
8846
9520
  for (const c of cells) ctx.fillRect(c % cols * cell, Math.floor(c / cols) * cell, cell, cell);
8847
9521
  }
8848
9522
  };
@@ -8908,7 +9582,7 @@ var createCanvas2dPainter = (ctx, scratchCanvas) => {
8908
9582
  }
8909
9583
  const stroke = item.stroke * frame.dpr;
8910
9584
  for (const [packed, list] of groups) {
8911
- const color = unpack(packed);
9585
+ const color = unpackColor(packed);
8912
9586
  ctx.beginPath();
8913
9587
  for (const i of list) {
8914
9588
  const x = f[i * 4];
@@ -8969,6 +9643,33 @@ var createCanvas2dPainter = (ctx, scratchCanvas) => {
8969
9643
  };
8970
9644
  };
8971
9645
  //#endregion
9646
+ //#region ../charts/src/engine/signature.ts
9647
+ var ids = /* @__PURE__ */ new WeakMap();
9648
+ var counter = 0;
9649
+ /** Stable id of an object (data columns compare by identity) */
9650
+ var idOf = (value) => {
9651
+ let id = ids.get(value);
9652
+ if (id === void 0) ids.set(value, id = ++counter);
9653
+ return id;
9654
+ };
9655
+ /**
9656
+ * Every input of `buildItems` (and of the origin of its positions): data
9657
+ * identity, types, colors, visibility, widths, bar layout, stacks, curves,
9658
+ * radii, candlestick and heatmap colors. `themeKey` covers the colors resolved
9659
+ * from the theme that the model doesn't spell out (per-point colors);
9660
+ * `stackOf` gives the `stack` option of a series.
9661
+ */
9662
+ var itemsSignature = (model, themeKey, stackOf) => {
9663
+ const { base } = model;
9664
+ let signature = `${themeKey}|${model.baseline}|${model.percent}|${base.x[0]},${base.x[1]}|${base.y[0]},${base.y[1]}`;
9665
+ for (const s of model.series) {
9666
+ signature += `\n${s.key}|${s.type}|${idOf(s.cols)}|${s.colorCss}|${s.hidden}|${s.lineWidth}|${s.pointSize}|${s.opacity}|${s.barOffset}|${s.barHalfWidth}|${stackOf(s.index) ?? ""}|${s.curve}|${s.radius}`;
9667
+ if (s.type === "candlestick") signature += `|${s.upColor}/${s.downColor}`;
9668
+ else if (s.type === "heatmap") signature += `|${s.colorScale.join(";")}/${s.valueRange[0]},${s.valueRange[1]}/${s.cellHalf.x},${s.cellHalf.y}`;
9669
+ }
9670
+ return signature;
9671
+ };
9672
+ //#endregion
8972
9673
  //#region ../charts/src/engine/canvas.ts
8973
9674
  var mid = (r) => (r[0] + r[1]) / 2;
8974
9675
  var roundedRect = (ctx, x, y, w, h, r) => {
@@ -9026,6 +9727,12 @@ var drawScene = (ctx, scene, items, origin, pixelRatio, painter = createCanvas2d
9026
9727
  }
9027
9728
  ctx.globalAlpha = 1;
9028
9729
  }
9730
+ for (const mark of scene.hover?.marks ?? []) {
9731
+ if (mark.kind !== "band") continue;
9732
+ roundedRect(ctx, mark.x, mark.y, mark.width, mark.height, 6);
9733
+ ctx.fillStyle = toCss(theme.text, .06);
9734
+ ctx.fill();
9735
+ }
9029
9736
  const scale = (range, o, reverse) => {
9030
9737
  const s = 2 / (range[1] - range[0]);
9031
9738
  const offset = (o - range[0]) * s - 1;
@@ -9084,13 +9791,23 @@ var drawScene = (ctx, scene, items, origin, pixelRatio, painter = createCanvas2d
9084
9791
  ctx.restore();
9085
9792
  }
9086
9793
  for (const mark of hover.marks) {
9087
- if (mark.kind === "bar") {
9088
- ctx.fillStyle = toCss(theme.text, .08);
9089
- ctx.fillRect(mark.x - 2, mark.y - 2, mark.width + 4, mark.height + 2);
9794
+ if (mark.kind === "band") continue;
9795
+ if (mark.kind === "cell") {
9796
+ roundedRect(ctx, mark.x, mark.y, mark.width, mark.height, 3);
9797
+ ctx.lineWidth = 3;
9798
+ ctx.strokeStyle = toCss(theme.background);
9799
+ ctx.stroke();
9800
+ ctx.lineWidth = 1.5;
9801
+ ctx.strokeStyle = toCss(theme.text, .55);
9802
+ ctx.stroke();
9090
9803
  continue;
9091
9804
  }
9092
9805
  ctx.beginPath();
9093
- ctx.arc(mark.x, mark.y, mark.size / 2, 0, Math.PI * 2);
9806
+ ctx.arc(mark.x, mark.y, mark.size / 2 + 4, 0, Math.PI * 2);
9807
+ ctx.fillStyle = mark.halo;
9808
+ ctx.fill();
9809
+ ctx.beginPath();
9810
+ ctx.arc(mark.x, mark.y, mark.size / 2 - 1, 0, Math.PI * 2);
9094
9811
  ctx.fillStyle = mark.color;
9095
9812
  ctx.fill();
9096
9813
  ctx.lineWidth = 2;
@@ -9122,7 +9839,7 @@ var drawScene = (ctx, scene, items, origin, pixelRatio, painter = createCanvas2d
9122
9839
  ctx.fill();
9123
9840
  ctx.restore();
9124
9841
  roundedRect(ctx, box.x + .5, box.y + .5, box.width - 1, box.height - 1, 8);
9125
- ctx.strokeStyle = toCss(theme.axis);
9842
+ ctx.strokeStyle = toCss(theme.axis, .6);
9126
9843
  ctx.lineWidth = 1;
9127
9844
  ctx.stroke();
9128
9845
  ctx.textBaseline = "middle";
@@ -9190,6 +9907,16 @@ var createCanvasChart = (config) => {
9190
9907
  let frameId = null;
9191
9908
  let items = [];
9192
9909
  let itemsModel = null;
9910
+ let itemsKey = "";
9911
+ let options = config.options;
9912
+ /** Ids of the themes seen (the controller replaces its theme on changes) */
9913
+ const themeIds = /* @__PURE__ */ new WeakMap();
9914
+ let themeCount = 0;
9915
+ const themeId = (theme) => {
9916
+ let id = themeIds.get(theme);
9917
+ if (id === void 0) themeIds.set(theme, id = ++themeCount);
9918
+ return id;
9919
+ };
9193
9920
  let origin = {
9194
9921
  x: 0,
9195
9922
  y: 0
@@ -9218,11 +9945,15 @@ var createCanvasChart = (config) => {
9218
9945
  fontSet = "";
9219
9946
  if (itemsModel !== scene.model) {
9220
9947
  itemsModel = scene.model;
9221
- origin = {
9222
- x: mid(scene.model.base.x),
9223
- y: mid(scene.model.base.y)
9224
- };
9225
- items = buildItems(scene.model, origin, ++version);
9948
+ const key = itemsSignature(scene.model, themeId(scene.theme), (index) => options.series[index]?.stack);
9949
+ if (key !== itemsKey) {
9950
+ itemsKey = key;
9951
+ origin = {
9952
+ x: mid(scene.model.base.x),
9953
+ y: mid(scene.model.base.y)
9954
+ };
9955
+ items = buildItems(scene.model, origin, ++version);
9956
+ }
9226
9957
  }
9227
9958
  drawScene(ctx, scene, items, origin, dpr, painter);
9228
9959
  fontSet = "";
@@ -9245,7 +9976,10 @@ var createCanvasChart = (config) => {
9245
9976
  touch: true
9246
9977
  });
9247
9978
  return {
9248
- setOptions: (o) => controller.setOptions(o),
9979
+ setOptions: (o) => {
9980
+ options = o;
9981
+ controller.setOptions(o);
9982
+ },
9249
9983
  setTheme: (t) => controller.setTheme(t),
9250
9984
  resize(w, h, ratio) {
9251
9985
  width = w;
@@ -9308,15 +10042,22 @@ var createCanvasChart = (config) => {
9308
10042
  //#endregion
9309
10043
  //#region ../charts/src/engine/presets.ts
9310
10044
  /** Gives the series without a `type` the type of the component */
9311
- var withSeriesType = (series, type, stack) => series.map((s) => ({
9312
- ...s,
9313
- type: s.type ?? type,
9314
- ...stack !== void 0 && (s.type ?? type) === "bar" ? { stack: s.stack ?? stack } : {}
9315
- }));
10045
+ var withSeriesType = (series, type, stack, curve) => series.map((s) => {
10046
+ const t = s.type ?? type;
10047
+ return {
10048
+ ...s,
10049
+ type: t,
10050
+ ...stack !== void 0 && t === type ? { stack: s.stack ?? stack } : {},
10051
+ ...curve !== void 0 && (t === "line" || t === "area") ? { curve: s.curve ?? curve } : {}
10052
+ };
10053
+ });
9316
10054
  /** Series of a LineChart (`area` fills them) */
9317
- var lineSeries = (series, area = false) => withSeriesType(series, area ? "area" : "line");
9318
- /** Series of a BarChart (`stacked` stacks them) */
9319
- var barSeries = (series, stacked = false) => withSeriesType(series, "bar", stacked ? "stack" : void 0);
10055
+ var lineSeries = (series, area = false, extra = {}) => withSeriesType(series, area ? "area" : "line", extra.stacked ? "stack" : void 0, extra.curve);
10056
+ /** Series of a BarChart (`stacked` stacks them, `labels` shows the values) */
10057
+ var barSeries = (series, stacked = false, labels = false) => withSeriesType(series, "bar", stacked ? "stack" : void 0).map((s) => labels && s.type === "bar" ? {
10058
+ ...s,
10059
+ showLabels: s.showLabels ?? true
10060
+ } : s);
9320
10061
  /** Series of a ScatterChart */
9321
10062
  var scatterSeries = (series) => withSeriesType(series, "scatter");
9322
10063
  var DEFAULT_QUADRANT_COLORS = {