@perspective-dev/viewer-charts 4.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 (258) hide show
  1. package/LICENSE.md +193 -0
  2. package/dist/cdn/perspective-viewer-charts.js +3 -0
  3. package/dist/cdn/perspective-viewer-charts.js.map +7 -0
  4. package/dist/esm/axis/axis-primitives.d.ts +24 -0
  5. package/dist/esm/axis/bar-axis.d.ts +51 -0
  6. package/dist/esm/axis/canvas.d.ts +24 -0
  7. package/dist/esm/axis/categorical-axis-core.d.ts +42 -0
  8. package/dist/esm/axis/categorical-axis.d.ts +27 -0
  9. package/dist/esm/axis/facet-chrome.d.ts +13 -0
  10. package/dist/esm/axis/label-geometry.d.ts +41 -0
  11. package/dist/esm/axis/legend.d.ts +44 -0
  12. package/dist/esm/axis/numeric-axis.d.ts +20 -0
  13. package/dist/esm/charts/candlestick/candlestick-build.d.ts +129 -0
  14. package/dist/esm/charts/candlestick/candlestick-interact.d.ts +10 -0
  15. package/dist/esm/charts/candlestick/candlestick-render.d.ts +24 -0
  16. package/dist/esm/charts/candlestick/candlestick.d.ts +144 -0
  17. package/dist/esm/charts/candlestick/glyphs/draw-candlesticks.d.ts +36 -0
  18. package/dist/esm/charts/candlestick/glyphs/draw-ohlc.d.ts +33 -0
  19. package/dist/esm/charts/canvas-types.d.ts +15 -0
  20. package/dist/esm/charts/cartesian/cartesian-build.d.ts +14 -0
  21. package/dist/esm/charts/cartesian/cartesian-interact.d.ts +20 -0
  22. package/dist/esm/charts/cartesian/cartesian-render.d.ts +26 -0
  23. package/dist/esm/charts/cartesian/cartesian.d.ts +239 -0
  24. package/dist/esm/charts/cartesian/glyph.d.ts +53 -0
  25. package/dist/esm/charts/cartesian/glyphs/density.d.ts +142 -0
  26. package/dist/esm/charts/cartesian/glyphs/lines.d.ts +23 -0
  27. package/dist/esm/charts/cartesian/glyphs/points.d.ts +24 -0
  28. package/dist/esm/charts/cartesian/label-interner.d.ts +21 -0
  29. package/dist/esm/charts/cartesian/tooltip-lines.d.ts +11 -0
  30. package/dist/esm/charts/chart-base.d.ts +402 -0
  31. package/dist/esm/charts/chart.d.ts +338 -0
  32. package/dist/esm/charts/common/band-layout.d.ts +32 -0
  33. package/dist/esm/charts/common/categorical-y-chart.d.ts +53 -0
  34. package/dist/esm/charts/common/category-axis-resolver.d.ts +90 -0
  35. package/dist/esm/charts/common/chrome-cache.d.ts +18 -0
  36. package/dist/esm/charts/common/draw-tooltip-box.d.ts +9 -0
  37. package/dist/esm/charts/common/leaf-color.d.ts +33 -0
  38. package/dist/esm/charts/common/node-store.d.ts +81 -0
  39. package/dist/esm/charts/common/tree-chart.d.ts +48 -0
  40. package/dist/esm/charts/common/tree-chrome.d.ts +31 -0
  41. package/dist/esm/charts/common/tree-data.d.ts +54 -0
  42. package/dist/esm/charts/common/visible-extent.d.ts +51 -0
  43. package/dist/esm/charts/heatmap/heatmap-build.d.ts +86 -0
  44. package/dist/esm/charts/heatmap/heatmap-interact.d.ts +19 -0
  45. package/dist/esm/charts/heatmap/heatmap-render.d.ts +19 -0
  46. package/dist/esm/charts/heatmap/heatmap-y-axis.d.ts +46 -0
  47. package/dist/esm/charts/heatmap/heatmap.d.ts +117 -0
  48. package/dist/esm/charts/map/map.d.ts +67 -0
  49. package/dist/esm/charts/registry.d.ts +14 -0
  50. package/dist/esm/charts/series/glyphs/draw-areas.d.ts +30 -0
  51. package/dist/esm/charts/series/glyphs/draw-bars.d.ts +15 -0
  52. package/dist/esm/charts/series/glyphs/draw-lines.d.ts +34 -0
  53. package/dist/esm/charts/series/glyphs/draw-scatter.d.ts +33 -0
  54. package/dist/esm/charts/series/series-build.d.ts +228 -0
  55. package/dist/esm/charts/series/series-interact.d.ts +35 -0
  56. package/dist/esm/charts/series/series-render.d.ts +41 -0
  57. package/dist/esm/charts/series/series-type.d.ts +49 -0
  58. package/dist/esm/charts/series/series.d.ts +317 -0
  59. package/dist/esm/charts/sunburst/sunburst-interact.d.ts +7 -0
  60. package/dist/esm/charts/sunburst/sunburst-layout.d.ts +33 -0
  61. package/dist/esm/charts/sunburst/sunburst-render.d.ts +22 -0
  62. package/dist/esm/charts/sunburst/sunburst.d.ts +85 -0
  63. package/dist/esm/charts/treemap/treemap-interact.d.ts +12 -0
  64. package/dist/esm/charts/treemap/treemap-layout.d.ts +28 -0
  65. package/dist/esm/charts/treemap/treemap-render.d.ts +18 -0
  66. package/dist/esm/charts/treemap/treemap.d.ts +74 -0
  67. package/dist/esm/config.d.ts +27 -0
  68. package/dist/esm/data/lazy-row.d.ts +32 -0
  69. package/dist/esm/data/split-groups.d.ts +20 -0
  70. package/dist/esm/data/view-reader.d.ts +35 -0
  71. package/dist/esm/event-detail.d.ts +28 -0
  72. package/dist/esm/index.d.ts +3 -0
  73. package/dist/esm/interaction/hit-test.d.ts +30 -0
  74. package/dist/esm/interaction/host-sink-dom.d.ts +19 -0
  75. package/dist/esm/interaction/host-sink-message.d.ts +46 -0
  76. package/dist/esm/interaction/lazy-tooltip.d.ts +61 -0
  77. package/dist/esm/interaction/raw-event-forwarder.d.ts +27 -0
  78. package/dist/esm/interaction/spatial-grid.d.ts +15 -0
  79. package/dist/esm/interaction/tooltip-controller.d.ts +193 -0
  80. package/dist/esm/interaction/zoom-controller.d.ts +106 -0
  81. package/dist/esm/interaction/zoom-router.d.ts +48 -0
  82. package/dist/esm/layout/facet-grid.d.ts +126 -0
  83. package/dist/esm/layout/plot-layout.d.ts +104 -0
  84. package/dist/esm/layout/ticks.d.ts +17 -0
  85. package/dist/esm/map/mercator.d.ts +102 -0
  86. package/dist/esm/map/tile-cache.d.ts +38 -0
  87. package/dist/esm/map/tile-layer.d.ts +66 -0
  88. package/dist/esm/map/tile-loader.d.ts +52 -0
  89. package/dist/esm/map/tile-source.d.ts +66 -0
  90. package/dist/esm/perspective-viewer-charts.js +3 -0
  91. package/dist/esm/perspective-viewer-charts.js.map +7 -0
  92. package/dist/esm/plugin/charts.d.ts +40 -0
  93. package/dist/esm/plugin/plugin.d.ts +95 -0
  94. package/dist/esm/render/scheduler.d.ts +41 -0
  95. package/dist/esm/theme/gradient.d.ts +48 -0
  96. package/dist/esm/theme/palette.d.ts +13 -0
  97. package/dist/esm/theme/theme-snapshot.d.ts +7 -0
  98. package/dist/esm/theme/theme.d.ts +53 -0
  99. package/dist/esm/transport/protocol.d.ts +430 -0
  100. package/dist/esm/transport/renderer-transport.d.ts +201 -0
  101. package/dist/esm/utils/css.d.ts +1 -0
  102. package/dist/esm/utils/font-snapshot.d.ts +50 -0
  103. package/dist/esm/webgl/buffer-pool.d.ts +62 -0
  104. package/dist/esm/webgl/context-manager.d.ts +184 -0
  105. package/dist/esm/webgl/gradient-texture.d.ts +17 -0
  106. package/dist/esm/webgl/instanced-attrs.d.ts +44 -0
  107. package/dist/esm/webgl/plot-frame.d.ts +39 -0
  108. package/dist/esm/webgl/program-cache.d.ts +13 -0
  109. package/dist/esm/webgl/shader-manifest.d.ts +53 -0
  110. package/dist/esm/webgl/shader-registry.d.ts +22 -0
  111. package/dist/esm/worker/boot.d.ts +0 -0
  112. package/dist/esm/worker/dispatch.d.ts +9 -0
  113. package/dist/esm/worker/font-loader.d.ts +2 -0
  114. package/dist/esm/worker/renderer.worker.d.ts +115 -0
  115. package/dist/esm/worker/session-host.d.ts +26 -0
  116. package/package.json +47 -0
  117. package/src/css/perspective-viewer-charts.css +95 -0
  118. package/src/ts/axis/axis-primitives.ts +125 -0
  119. package/src/ts/axis/bar-axis.ts +345 -0
  120. package/src/ts/axis/canvas.ts +64 -0
  121. package/src/ts/axis/categorical-axis-core.ts +125 -0
  122. package/src/ts/axis/categorical-axis.ts +716 -0
  123. package/src/ts/axis/facet-chrome.ts +42 -0
  124. package/src/ts/axis/label-geometry.ts +188 -0
  125. package/src/ts/axis/legend.ts +218 -0
  126. package/src/ts/axis/numeric-axis.ts +353 -0
  127. package/src/ts/charts/candlestick/candlestick-build.ts +516 -0
  128. package/src/ts/charts/candlestick/candlestick-interact.ts +256 -0
  129. package/src/ts/charts/candlestick/candlestick-render.ts +387 -0
  130. package/src/ts/charts/candlestick/candlestick.ts +367 -0
  131. package/src/ts/charts/candlestick/glyphs/draw-candlesticks.ts +432 -0
  132. package/src/ts/charts/candlestick/glyphs/draw-ohlc.ts +317 -0
  133. package/src/ts/charts/canvas-types.ts +30 -0
  134. package/src/ts/charts/cartesian/cartesian-build.ts +616 -0
  135. package/src/ts/charts/cartesian/cartesian-interact.ts +355 -0
  136. package/src/ts/charts/cartesian/cartesian-render.ts +948 -0
  137. package/src/ts/charts/cartesian/cartesian.ts +469 -0
  138. package/src/ts/charts/cartesian/glyph.ts +81 -0
  139. package/src/ts/charts/cartesian/glyphs/density.ts +1263 -0
  140. package/src/ts/charts/cartesian/glyphs/lines.ts +320 -0
  141. package/src/ts/charts/cartesian/glyphs/points.ts +239 -0
  142. package/src/ts/charts/cartesian/label-interner.ts +56 -0
  143. package/src/ts/charts/cartesian/tooltip-lines.ts +80 -0
  144. package/src/ts/charts/chart-base.ts +840 -0
  145. package/src/ts/charts/chart.ts +427 -0
  146. package/src/ts/charts/common/band-layout.ts +63 -0
  147. package/src/ts/charts/common/categorical-y-chart.ts +81 -0
  148. package/src/ts/charts/common/category-axis-resolver.ts +314 -0
  149. package/src/ts/charts/common/chrome-cache.ts +79 -0
  150. package/src/ts/charts/common/draw-tooltip-box.ts +84 -0
  151. package/src/ts/charts/common/leaf-color.ts +92 -0
  152. package/src/ts/charts/common/node-store.ts +235 -0
  153. package/src/ts/charts/common/tree-chart.ts +76 -0
  154. package/src/ts/charts/common/tree-chrome.ts +123 -0
  155. package/src/ts/charts/common/tree-data.ts +623 -0
  156. package/src/ts/charts/common/visible-extent.ts +112 -0
  157. package/src/ts/charts/heatmap/heatmap-build.ts +426 -0
  158. package/src/ts/charts/heatmap/heatmap-interact.ts +274 -0
  159. package/src/ts/charts/heatmap/heatmap-render.ts +815 -0
  160. package/src/ts/charts/heatmap/heatmap-y-axis.ts +351 -0
  161. package/src/ts/charts/heatmap/heatmap.ts +368 -0
  162. package/src/ts/charts/map/map.ts +201 -0
  163. package/src/ts/charts/registry.ts +65 -0
  164. package/src/ts/charts/series/glyphs/draw-areas.ts +331 -0
  165. package/src/ts/charts/series/glyphs/draw-bars.ts +113 -0
  166. package/src/ts/charts/series/glyphs/draw-lines.ts +320 -0
  167. package/src/ts/charts/series/glyphs/draw-scatter.ts +328 -0
  168. package/src/ts/charts/series/series-build.ts +848 -0
  169. package/src/ts/charts/series/series-interact.ts +604 -0
  170. package/src/ts/charts/series/series-render.ts +1109 -0
  171. package/src/ts/charts/series/series-type.ts +99 -0
  172. package/src/ts/charts/series/series.ts +794 -0
  173. package/src/ts/charts/sunburst/sunburst-interact.ts +460 -0
  174. package/src/ts/charts/sunburst/sunburst-layout.ts +238 -0
  175. package/src/ts/charts/sunburst/sunburst-render.ts +887 -0
  176. package/src/ts/charts/sunburst/sunburst.ts +248 -0
  177. package/src/ts/charts/treemap/treemap-interact.ts +445 -0
  178. package/src/ts/charts/treemap/treemap-layout.ts +328 -0
  179. package/src/ts/charts/treemap/treemap-render.ts +886 -0
  180. package/src/ts/charts/treemap/treemap.ts +247 -0
  181. package/src/ts/config.ts +41 -0
  182. package/src/ts/data/lazy-row.ts +140 -0
  183. package/src/ts/data/split-groups.ts +97 -0
  184. package/src/ts/data/view-reader.ts +107 -0
  185. package/src/ts/event-detail.ts +44 -0
  186. package/src/ts/index.ts +53 -0
  187. package/src/ts/interaction/hit-test.ts +106 -0
  188. package/src/ts/interaction/host-sink-dom.ts +85 -0
  189. package/src/ts/interaction/host-sink-message.ts +75 -0
  190. package/src/ts/interaction/lazy-tooltip.ts +102 -0
  191. package/src/ts/interaction/raw-event-forwarder.ts +175 -0
  192. package/src/ts/interaction/spatial-grid.ts +100 -0
  193. package/src/ts/interaction/tooltip-controller.ts +407 -0
  194. package/src/ts/interaction/zoom-controller.ts +468 -0
  195. package/src/ts/interaction/zoom-router.ts +230 -0
  196. package/src/ts/layout/facet-grid.ts +346 -0
  197. package/src/ts/layout/plot-layout.ts +277 -0
  198. package/src/ts/layout/ticks.ts +168 -0
  199. package/src/ts/map/mercator.ts +204 -0
  200. package/src/ts/map/tile-cache.ts +96 -0
  201. package/src/ts/map/tile-layer.ts +382 -0
  202. package/src/ts/map/tile-loader.ts +143 -0
  203. package/src/ts/map/tile-source.ts +156 -0
  204. package/src/ts/plugin/charts.ts +286 -0
  205. package/src/ts/plugin/plugin.ts +668 -0
  206. package/src/ts/render/scheduler.ts +339 -0
  207. package/src/ts/shaders/area.frag.glsl +20 -0
  208. package/src/ts/shaders/area.vert.glsl +19 -0
  209. package/src/ts/shaders/bar.frag.glsl +25 -0
  210. package/src/ts/shaders/bar.vert.glsl +60 -0
  211. package/src/ts/shaders/candlestick-body.frag.glsl +19 -0
  212. package/src/ts/shaders/candlestick-body.vert.glsl +34 -0
  213. package/src/ts/shaders/density-extreme.frag.glsl +30 -0
  214. package/src/ts/shaders/density-mrt.frag.glsl +44 -0
  215. package/src/ts/shaders/density-mrt.vert.glsl +48 -0
  216. package/src/ts/shaders/density-resolve.frag.glsl +89 -0
  217. package/src/ts/shaders/density-resolve.vert.glsl +23 -0
  218. package/src/ts/shaders/density-splat.frag.glsl +34 -0
  219. package/src/ts/shaders/density-splat.vert.glsl +52 -0
  220. package/src/ts/shaders/gridline.frag.glsl +18 -0
  221. package/src/ts/shaders/gridline.vert.glsl +18 -0
  222. package/src/ts/shaders/heatmap.frag.glsl +23 -0
  223. package/src/ts/shaders/heatmap.vert.glsl +42 -0
  224. package/src/ts/shaders/line-uniform.frag.glsl +26 -0
  225. package/src/ts/shaders/line-uniform.vert.glsl +54 -0
  226. package/src/ts/shaders/line.frag.glsl +28 -0
  227. package/src/ts/shaders/line.vert.glsl +87 -0
  228. package/src/ts/shaders/scatter.frag.glsl +39 -0
  229. package/src/ts/shaders/scatter.vert.glsl +67 -0
  230. package/src/ts/shaders/sunburst-arc.frag.glsl +19 -0
  231. package/src/ts/shaders/sunburst-arc.vert.glsl +79 -0
  232. package/src/ts/shaders/tile.frag.glsl +27 -0
  233. package/src/ts/shaders/tile.vert.glsl +35 -0
  234. package/src/ts/shaders/treemap.frag.glsl +19 -0
  235. package/src/ts/shaders/treemap.vert.glsl +25 -0
  236. package/src/ts/shaders/y-scatter.frag.glsl +30 -0
  237. package/src/ts/shaders/y-scatter.vert.glsl +31 -0
  238. package/src/ts/theme/gradient.ts +312 -0
  239. package/src/ts/theme/palette.ts +64 -0
  240. package/src/ts/theme/theme-snapshot.ts +66 -0
  241. package/src/ts/theme/theme.ts +166 -0
  242. package/src/ts/transport/protocol.ts +497 -0
  243. package/src/ts/transport/renderer-transport.ts +788 -0
  244. package/src/ts/utils/css.ts +36 -0
  245. package/src/ts/utils/font-snapshot.ts +159 -0
  246. package/src/ts/webgl/buffer-pool.ts +163 -0
  247. package/src/ts/webgl/context-manager.ts +414 -0
  248. package/src/ts/webgl/gradient-texture.ts +84 -0
  249. package/src/ts/webgl/instanced-attrs.ts +139 -0
  250. package/src/ts/webgl/plot-frame.ts +91 -0
  251. package/src/ts/webgl/program-cache.ts +46 -0
  252. package/src/ts/webgl/shader-manifest.ts +148 -0
  253. package/src/ts/webgl/shader-registry.ts +97 -0
  254. package/src/ts/worker/boot.ts +22 -0
  255. package/src/ts/worker/dispatch.ts +99 -0
  256. package/src/ts/worker/font-loader.ts +89 -0
  257. package/src/ts/worker/renderer.worker.ts +734 -0
  258. package/src/ts/worker/session-host.ts +118 -0
@@ -0,0 +1,616 @@
1
+ // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2
+ // ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3
+ // ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4
+ // ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5
+ // ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6
+ // ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7
+ // ┃ Copyright (c) 2017, the Perspective Authors. ┃
8
+ // ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9
+ // ┃ This file is part of the Perspective library, distributed under the terms ┃
10
+ // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
+ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
+
13
+ import type { ColumnDataMap, ColumnData } from "../../data/view-reader";
14
+ import { buildSplitGroups } from "../../data/split-groups";
15
+ import type { WebGLContextManager } from "../../webgl/context-manager";
16
+ import type { CartesianChart, SplitGroup } from "./cartesian";
17
+ import { LabelInterner } from "./label-interner";
18
+
19
+ /**
20
+ * Resolve per-split-prefix column-name tuples. `colorBase`/`sizeBase`
21
+ * are optional (empty string when the corresponding slot is unset).
22
+ */
23
+ function buildCartesianSplitGroups(
24
+ columns: ColumnDataMap,
25
+ xBase: string,
26
+ yBase: string,
27
+ colorBase: string,
28
+ sizeBase: string,
29
+ labelBase: string,
30
+ ): SplitGroup[] {
31
+ const required = xBase ? [xBase, yBase] : [yBase];
32
+ const optional: string[] = [];
33
+ if (colorBase) {
34
+ optional.push(colorBase);
35
+ }
36
+
37
+ if (sizeBase) {
38
+ optional.push(sizeBase);
39
+ }
40
+
41
+ if (labelBase) {
42
+ optional.push(labelBase);
43
+ }
44
+
45
+ return buildSplitGroups(columns, required, optional).map((g) => ({
46
+ prefix: g.prefix,
47
+ xColName: xBase ? g.colNames.get(xBase)! : "",
48
+ yColName: g.colNames.get(yBase)!,
49
+ colorColName: colorBase ? `${g.prefix}|${colorBase}` : "",
50
+ sizeColName: sizeBase ? `${g.prefix}|${sizeBase}` : "",
51
+ labelColName: labelBase ? `${g.prefix}|${labelBase}` : "",
52
+ }));
53
+ }
54
+
55
+ /**
56
+ * First-chunk init: compile the glyph program, reset data extents,
57
+ * resolve column roles and split groups, pre-allocate CPU + GPU buffers.
58
+ */
59
+ export function initCartesianPipeline(
60
+ chart: CartesianChart,
61
+ glManager: WebGLContextManager,
62
+ columns: ColumnDataMap,
63
+ endRow: number,
64
+ ): void {
65
+ chart.glyph.ensureProgram(chart, glManager);
66
+
67
+ const prevColorName = chart._colorName;
68
+ const prevColorIsString = chart._colorIsString;
69
+
70
+ // `domain_mode: "expand"` seeds the per-build extents from the
71
+ // running accumulator instead of `±Infinity`, so the per-row scan
72
+ // below naturally unions new data into the previously rendered
73
+ // domain / range / color / size scales. `"fit"` clears the
74
+ // accumulator alongside the live extents so toggling back to
75
+ // expand later starts from a fresh baseline.
76
+ const expand = chart._pluginConfig.domain_mode === "expand";
77
+ if (expand) {
78
+ chart._xMin = chart._expandedXMin;
79
+ chart._xMax = chart._expandedXMax;
80
+ chart._yMin = chart._expandedYMin;
81
+ chart._yMax = chart._expandedYMax;
82
+ chart._colorMin = chart._expandedColorMin;
83
+ chart._colorMax = chart._expandedColorMax;
84
+ chart._sizeMin = chart._expandedSizeMin;
85
+ chart._sizeMax = chart._expandedSizeMax;
86
+ } else {
87
+ chart._xMin = Infinity;
88
+ chart._xMax = -Infinity;
89
+ chart._yMin = Infinity;
90
+ chart._yMax = -Infinity;
91
+ chart._colorMin = Infinity;
92
+ chart._colorMax = -Infinity;
93
+ chart._sizeMin = Infinity;
94
+ chart._sizeMax = -Infinity;
95
+ chart._expandedXMin = Infinity;
96
+ chart._expandedXMax = -Infinity;
97
+ chart._expandedYMin = Infinity;
98
+ chart._expandedYMax = -Infinity;
99
+ chart._expandedColorMin = Infinity;
100
+ chart._expandedColorMax = -Infinity;
101
+ chart._expandedSizeMin = Infinity;
102
+ chart._expandedSizeMax = -Infinity;
103
+ }
104
+
105
+ chart._xOrigin = NaN;
106
+ chart._yOrigin = NaN;
107
+ chart._dataCount = 0;
108
+ chart._hitTest.clear();
109
+ chart._maxSeriesUploaded = 0;
110
+
111
+ const slots = chart._columnSlots;
112
+
113
+ // Line uses `[yBase]` with row-index X; scatter and X/Y Line use
114
+ // `[xBase, yBase, colorBase, sizeBase]`. A single positional layout
115
+ // handles both: treat an empty slot[0] as "X = row index".
116
+ const xBase = slots[0] || "";
117
+ const yBase = slots[1] || "";
118
+ const colorBase = slots[2] || "";
119
+ const sizeBase = slots[3] || "";
120
+ const labelBase = slots[4] || "";
121
+ chart._xLabel = xBase;
122
+ chart._yLabel = yBase;
123
+ chart._xIsRowIndex = !xBase;
124
+
125
+ // Capture the per-series row budget BEFORE any split expansion. When
126
+ // split_by is active we grow `totalCapacity` to fit `numSplits`
127
+ // parallel slot ranges; reading `totalCapacity` again after that
128
+ // would hand every series the whole expanded buffer and cause
129
+ // series 1..N writes to overshoot the GPU buffer.
130
+ const rowsPerSeries = glManager.bufferPool.totalCapacity || endRow;
131
+
132
+ if (chart._splitBy.length > 0) {
133
+ chart._splitGroups = buildCartesianSplitGroups(
134
+ columns,
135
+ xBase,
136
+ yBase,
137
+ colorBase,
138
+ sizeBase,
139
+ labelBase,
140
+ );
141
+ if (chart._splitGroups.length === 0) {
142
+ chart._seriesCapacity = 0;
143
+ chart._seriesUploadedCounts = [];
144
+ return;
145
+ }
146
+
147
+ // Split mode: per-point columns live under `${prefix}|${base}`.
148
+ // The `_*Name` fields hold the base names so downstream code
149
+ // (render labels, tooltip lookup) can present them as one
150
+ // logical column. The per-facet resolution happens inside
151
+ // `processCartesianChunk` via `_splitGroups[i].*ColName`.
152
+ chart._xName = chart._splitGroups[0].xColName;
153
+ chart._yName = chart._splitGroups[0].yColName;
154
+ chart._colorName = colorBase;
155
+ chart._sizeName = sizeBase;
156
+ chart._labelName = labelBase;
157
+
158
+ // Infer dtype from any split's color column — all splits
159
+ // share the same underlying column type.
160
+ chart._colorIsString = false;
161
+ if (colorBase) {
162
+ const firstColorCol = columns.get(
163
+ chart._splitGroups[0].colorColName,
164
+ );
165
+ chart._colorIsString = firstColorCol?.type === "string";
166
+ }
167
+
168
+ glManager.ensureBufferCapacity(
169
+ rowsPerSeries * chart._splitGroups.length,
170
+ );
171
+ } else {
172
+ chart._splitGroups = [];
173
+ chart._xName = xBase;
174
+ chart._yName = yBase;
175
+ chart._colorName = colorBase;
176
+ chart._sizeName = sizeBase;
177
+ chart._labelName = labelBase;
178
+ chart._colorIsString = false;
179
+
180
+ if (chart._colorName) {
181
+ const colorCol = columns.get(chart._colorName);
182
+ chart._colorIsString = colorCol?.type === "string";
183
+ }
184
+ }
185
+
186
+ // Color label identity persists across `update()` calls so a given
187
+ // string keeps the same palette index for as long as the color column
188
+ // stays the same — perspective's dictionary encoding does not promise
189
+ // a stable index order between batches, so re-seeding from scratch
190
+ // would shuffle every label's color on each update. Reset only when
191
+ // the user changes the column or its dtype (string ↔ numeric); a
192
+ // numeric color column doesn't use this map and clearing keeps it
193
+ // small.
194
+ if (
195
+ chart._colorName !== prevColorName ||
196
+ chart._colorIsString !== prevColorIsString
197
+ ) {
198
+ chart._uniqueColorLabels = new Map();
199
+ }
200
+
201
+ const numSeries = Math.max(1, chart._splitGroups.length);
202
+ chart._seriesCapacity = rowsPerSeries;
203
+ chart._seriesUploadedCounts = new Array(numSeries).fill(0);
204
+
205
+ const cpuCap = numSeries * rowsPerSeries;
206
+ chart._xData = new Float32Array(cpuCap);
207
+ chart._yData = new Float32Array(cpuCap);
208
+ chart._colorData = new Float32Array(cpuCap);
209
+ chart._rowIndexData = new Int32Array(cpuCap);
210
+
211
+ chart._labels = labelBase ? new LabelInterner(cpuCap) : null;
212
+ }
213
+
214
+ /**
215
+ * Process one data chunk: extract positions + optional color/size per
216
+ * point, extend extents, write into per-series slots, capture tooltip
217
+ * data, and let the glyph upload its own GPU attribute buffers.
218
+ */
219
+ export function processCartesianChunk(
220
+ chart: CartesianChart,
221
+ glManager: WebGLContextManager,
222
+ columns: ColumnDataMap,
223
+ startRow: number,
224
+ chunkLength: number,
225
+ endRow: number,
226
+ ): void {
227
+ if (!chart._yName) {
228
+ return;
229
+ }
230
+
231
+ const sourceLength = chunkLength;
232
+ if (sourceLength === 0) {
233
+ return;
234
+ }
235
+
236
+ if (chart._seriesCapacity === 0) {
237
+ return;
238
+ }
239
+
240
+ const hasSplits = chart._splitGroups.length > 0;
241
+
242
+ // Per-series data source. `colorCol` is the facet's color column
243
+ // reference — in split mode each series has its own
244
+ // `${prefix}|${colorBase}`, in non-split mode the single series
245
+ // carries the user's selected color column. The color-resolution
246
+ // logic in the inner loop reads uniformly from `ser.colorCol`
247
+ // across both modes.
248
+ type SeriesSrc = {
249
+ xCol: Float32Array | Float64Array | Int32Array | null;
250
+ yCol: Float32Array | Float64Array | Int32Array;
251
+ xValid: Uint8Array | undefined;
252
+ yValid: Uint8Array | undefined;
253
+ colorCol: ColumnData | null;
254
+ sizeCol: (Float32Array | Float64Array | Int32Array) | null;
255
+ labelCol: ColumnData | null;
256
+ };
257
+ const series: SeriesSrc[] = [];
258
+
259
+ if (hasSplits) {
260
+ for (const sg of chart._splitGroups) {
261
+ const xc = sg.xColName ? columns.get(sg.xColName) : null;
262
+ const yc = columns.get(sg.yColName);
263
+ if (!yc?.values) {
264
+ continue;
265
+ }
266
+
267
+ const sc = sg.sizeColName ? columns.get(sg.sizeColName) : null;
268
+ const cc = sg.colorColName
269
+ ? (columns.get(sg.colorColName) ?? null)
270
+ : null;
271
+ const lc = sg.labelColName
272
+ ? (columns.get(sg.labelColName) ?? null)
273
+ : null;
274
+ series.push({
275
+ xCol: xc?.values ?? null,
276
+ yCol: yc.values,
277
+ xValid: xc?.valid,
278
+ yValid: yc.valid,
279
+ colorCol: cc,
280
+ sizeCol: sc?.values ?? null,
281
+ labelCol: lc,
282
+ });
283
+ }
284
+ } else {
285
+ const xc = chart._xName ? columns.get(chart._xName) : null;
286
+ const yc = chart._yName ? columns.get(chart._yName) : null;
287
+ if (!yc?.values) {
288
+ return;
289
+ }
290
+
291
+ const cc = chart._colorName
292
+ ? (columns.get(chart._colorName) ?? null)
293
+ : null;
294
+ const lc = chart._labelName
295
+ ? (columns.get(chart._labelName) ?? null)
296
+ : null;
297
+ series.push({
298
+ xCol: xc?.values ?? null,
299
+ yCol: yc.values,
300
+ xValid: xc?.valid,
301
+ yValid: yc?.valid,
302
+ colorCol: cc,
303
+ sizeCol: null,
304
+ labelCol: lc,
305
+ });
306
+ }
307
+
308
+ if (series.length === 0) {
309
+ return;
310
+ }
311
+
312
+ if (chart._stagingChunkSize < sourceLength) {
313
+ chart._stagingPositions = new Float32Array(sourceLength * 2);
314
+ chart._stagingColors = new Float32Array(sourceLength);
315
+ chart._stagingSizes = new Float32Array(sourceLength);
316
+ chart._stagingChunkSize = sourceLength;
317
+ }
318
+
319
+ const positions = chart._stagingPositions!;
320
+ const colorValues = chart._stagingColors!;
321
+ const sizeValues = chart._stagingSizes!;
322
+
323
+ // Non-split size column: resolve once; inner loop reads values[i].
324
+ const nonSplitSizeValues =
325
+ !hasSplits && chart._sizeName
326
+ ? (columns.get(chart._sizeName)?.values ?? null)
327
+ : null;
328
+
329
+ // Seed `_uniqueColorLabels` from the color column's dictionary in
330
+ // index order. For a stable single dictionary this makes
331
+ // `palette[_uniqueColorLabels.get(label)] === palette[dictIdx %
332
+ // N]`. For splits (distinct dictionaries per facet) values that
333
+ // appear in multiple splits are inserted once — later splits
334
+ // extend the map without disturbing earlier indices, so the
335
+ // same string has the same color in every facet.
336
+ //
337
+ // Also pin `_colorMin` / `_colorMax` to the full palette-index
338
+ // domain. If the row loop only encountered a subset of indices
339
+ // we'd otherwise set a narrower range and the shader's
340
+ // `(v - min) / (max - min)` mapping would land on the wrong
341
+ // palette stop.
342
+ if (chart._colorIsString && chart._colorName) {
343
+ for (const ser of series) {
344
+ const dict = ser.colorCol?.dictionary;
345
+ if (!dict) {
346
+ continue;
347
+ }
348
+
349
+ for (let i = 0; i < dict.length; i++) {
350
+ const s = dict[i];
351
+ if (!chart._uniqueColorLabels.has(s)) {
352
+ chart._uniqueColorLabels.set(
353
+ s,
354
+ chart._uniqueColorLabels.size,
355
+ );
356
+ }
357
+ }
358
+ }
359
+
360
+ if (chart._uniqueColorLabels.size > 0) {
361
+ chart._colorMin = 0;
362
+ chart._colorMax = chart._uniqueColorLabels.size - 1;
363
+ }
364
+ }
365
+
366
+ // Faceted-no-Color: pin the color range to the facet-index domain
367
+ // so the vertex shader's linear `(v - cmin) / (cmax - cmin)`
368
+ // mapping lands per-point at LUT stop `s / (N-1)`. Without this
369
+ // pin, `_colorMin/_colorMax` would stay at the +Inf/-Inf sentinel
370
+ // and every facet's points would sample the LUT center.
371
+ if (!chart._colorName && chart._splitGroups.length > 1) {
372
+ chart._colorMin = 0;
373
+ chart._colorMax = chart._splitGroups.length - 1;
374
+ }
375
+
376
+ for (let s = 0; s < series.length; s++) {
377
+ const ser = series[s];
378
+ const prevCount = chart._seriesUploadedCounts[s] ?? 0;
379
+ const slotBase = s * chart._seriesCapacity;
380
+ const maxWrite = chart._seriesCapacity - prevCount;
381
+ if (maxWrite <= 0) {
382
+ continue;
383
+ }
384
+
385
+ const colorValid = ser.colorCol?.valid;
386
+ let writeIdx = 0;
387
+ for (let j = 0; j < sourceLength && writeIdx < maxWrite; j++) {
388
+ const i = j;
389
+ if (ser.yValid && !((ser.yValid[i >> 3] >> (i & 7)) & 1)) {
390
+ continue;
391
+ }
392
+
393
+ if (
394
+ ser.xCol &&
395
+ ser.xValid &&
396
+ !((ser.xValid[i >> 3] >> (i & 7)) & 1)
397
+ ) {
398
+ continue;
399
+ }
400
+
401
+ const colorIsNull =
402
+ colorValid !== undefined &&
403
+ !((colorValid[i >> 3] >> (i & 7)) & 1);
404
+
405
+ const rawY = ser.yCol[i] as number;
406
+ const rawX = ser.xCol ? (ser.xCol[i] as number) : startRow + i;
407
+ if (isNaN(rawX) || isNaN(rawY)) {
408
+ continue;
409
+ }
410
+
411
+ // Project raw (x, y) → data-space (x, y). Default is
412
+ // identity for cartesian charts; map subclasses override
413
+ // to apply Mercator. Second NaN guard catches projection
414
+ // failures (e.g. Mercator's ±85° lat clamp).
415
+ const [x, y] = chart.projectPoint(rawX, rawY);
416
+ if (isNaN(x) || isNaN(y)) {
417
+ continue;
418
+ }
419
+
420
+ if (x < chart._xMin) {
421
+ chart._xMin = x;
422
+ }
423
+
424
+ if (x > chart._xMax) {
425
+ chart._xMax = x;
426
+ }
427
+
428
+ if (y < chart._yMin) {
429
+ chart._yMin = y;
430
+ }
431
+
432
+ if (y > chart._yMax) {
433
+ chart._yMax = y;
434
+ }
435
+
436
+ // Capture rebase origins from the first valid sample. The
437
+ // origin is f64 in JS state but applied before every f32
438
+ // store below — `_xData`, `_yData`, and the GPU `positions`
439
+ // staging buffer all hold rebased values, so the projection
440
+ // matrix's `tx`/`ty` terms (built from rebased extents in
441
+ // cartesian-render) stay near zero and the shader's
442
+ // `sx*x + tx` cancellation is precision-safe.
443
+ if (isNaN(chart._xOrigin)) {
444
+ chart._xOrigin = x;
445
+ }
446
+
447
+ if (isNaN(chart._yOrigin)) {
448
+ chart._yOrigin = y;
449
+ }
450
+
451
+ const xr = x - chart._xOrigin;
452
+ const yr = y - chart._yOrigin;
453
+
454
+ const flatIdx = slotBase + prevCount + writeIdx;
455
+ chart._xData![flatIdx] = xr;
456
+ chart._yData![flatIdx] = yr;
457
+
458
+ // Remember the source arrow row this slot came from so
459
+ // lazy tooltip fetches can resolve columns on demand. In
460
+ // split mode each series duplicates the same arrow row
461
+ // into its own slot, so `startRow + i` is the right view
462
+ // row regardless of `s`.
463
+ chart._rowIndexData![flatIdx] = startRow + i;
464
+
465
+ positions[writeIdx * 2] = xr;
466
+ positions[writeIdx * 2 + 1] = yr;
467
+
468
+ // Color: unified resolution for split + non-split.
469
+ // Read from this series' own color column (facet-specific
470
+ // in split mode, the chart-wide column otherwise). Scales
471
+ // (`_colorMin/_colorMax` and `_uniqueColorLabels`) are
472
+ // shared across every series so identical values render
473
+ // as identical colors in every facet.
474
+ const cc = ser.colorCol;
475
+ if (colorIsNull) {
476
+ colorValues[writeIdx] = 0.5;
477
+ chart._colorData![flatIdx] = 0.5;
478
+ } else if (cc && !chart._colorIsString && cc.values) {
479
+ const v = cc.values[i] as number;
480
+ colorValues[writeIdx] = v;
481
+ chart._colorData![flatIdx] = v;
482
+ if (v < chart._colorMin) {
483
+ chart._colorMin = v;
484
+ }
485
+
486
+ if (v > chart._colorMax) {
487
+ chart._colorMax = v;
488
+ }
489
+ } else if (
490
+ cc &&
491
+ chart._colorIsString &&
492
+ cc.indices &&
493
+ cc.dictionary
494
+ ) {
495
+ const label = cc.dictionary[cc.indices[i]];
496
+
497
+ // Dict-seeding above ensures this label is already
498
+ // in `_uniqueColorLabels`; defensive insert for any
499
+ // value that appears in data but not the dictionary
500
+ // (shouldn't happen for Arrow dict columns).
501
+ if (!chart._uniqueColorLabels.has(label)) {
502
+ chart._uniqueColorLabels.set(
503
+ label,
504
+ chart._uniqueColorLabels.size,
505
+ );
506
+ chart._colorMax = chart._uniqueColorLabels.size - 1;
507
+ }
508
+
509
+ const idx = chart._uniqueColorLabels.get(label)!;
510
+ colorValues[writeIdx] = idx;
511
+ chart._colorData![flatIdx] = idx;
512
+
513
+ // Skip min/max updates — they were pinned to the full
514
+ // palette-index domain during seeding.
515
+ } else {
516
+ colorValues[writeIdx] = s;
517
+ chart._colorData![flatIdx] = s;
518
+ }
519
+
520
+ // Label: resolve the slot's string via the column's arrow
521
+ // dictionary; `LabelInterner.set` deduplicates across
522
+ // facets so identical strings share an entry. Non-string
523
+ // or unencoded label columns are silently skipped — the
524
+ // slot stays at its `-1` initialization.
525
+ if (chart._labels && ser.labelCol) {
526
+ const lc = ser.labelCol;
527
+ const labelValid = lc.valid;
528
+ const labelIsNull =
529
+ labelValid !== undefined &&
530
+ !((labelValid[i >> 3] >> (i & 7)) & 1);
531
+ if (!labelIsNull && lc.indices && lc.dictionary) {
532
+ chart._labels.set(flatIdx, lc.dictionary[lc.indices[i]]);
533
+ }
534
+ }
535
+
536
+ // Size: per-split size column, or global sizeName.
537
+ if (ser.sizeCol) {
538
+ const v = ser.sizeCol[i] as number;
539
+ sizeValues[writeIdx] = v;
540
+ if (v < chart._sizeMin) {
541
+ chart._sizeMin = v;
542
+ }
543
+
544
+ if (v > chart._sizeMax) {
545
+ chart._sizeMax = v;
546
+ }
547
+ } else if (nonSplitSizeValues) {
548
+ const v = nonSplitSizeValues[i] as number;
549
+ sizeValues[writeIdx] = v;
550
+ if (v < chart._sizeMin) {
551
+ chart._sizeMin = v;
552
+ }
553
+
554
+ if (v > chart._sizeMax) {
555
+ chart._sizeMax = v;
556
+ }
557
+ } else {
558
+ sizeValues[writeIdx] = 0;
559
+ }
560
+
561
+ writeIdx++;
562
+ }
563
+
564
+ if (writeIdx === 0) {
565
+ continue;
566
+ }
567
+
568
+ // Upload the shared position buffer for this series's new slice.
569
+ const positionByteOffset =
570
+ (slotBase + prevCount) * 2 * Float32Array.BYTES_PER_ELEMENT;
571
+ glManager.bufferPool.upload(
572
+ "a_position",
573
+ positions.subarray(0, writeIdx * 2),
574
+ positionByteOffset,
575
+ 2,
576
+ );
577
+
578
+ // Upload the raw color and size buffers (consumed by glyphs).
579
+ const scalarByteOffset =
580
+ (slotBase + prevCount) * Float32Array.BYTES_PER_ELEMENT;
581
+ glManager.bufferPool.upload(
582
+ "a_color_value",
583
+ colorValues.subarray(0, writeIdx),
584
+ scalarByteOffset,
585
+ );
586
+ glManager.bufferPool.upload(
587
+ "a_size_value",
588
+ sizeValues.subarray(0, writeIdx),
589
+ scalarByteOffset,
590
+ );
591
+
592
+ chart._seriesUploadedCounts[s] = prevCount + writeIdx;
593
+ if (chart._seriesUploadedCounts[s] > chart._maxSeriesUploaded) {
594
+ chart._maxSeriesUploaded = chart._seriesUploadedCounts[s];
595
+ }
596
+ }
597
+
598
+ // Total dataCount = sum of all series' uploaded counts.
599
+ let total = 0;
600
+ for (const c of chart._seriesUploadedCounts) {
601
+ total += c;
602
+ }
603
+
604
+ chart._dataCount = total;
605
+ glManager.uploadedCount = total;
606
+ chart._hitTest.markDirty();
607
+
608
+ if (isFinite(chart._xMin)) {
609
+ chart.setZoomBaseDomain(
610
+ chart._xMin,
611
+ chart._xMax,
612
+ chart._yMin,
613
+ chart._yMax,
614
+ );
615
+ }
616
+ }