@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,355 @@
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 { CartesianChart } from "./cartesian";
14
+ import { renderCartesianChromeOverlay } from "./cartesian-render";
15
+
16
+ const TOOLTIP_RADIUS_PX = 24;
17
+
18
+ /**
19
+ * Lazily rebuild the spatial hit-test index from the current CPU-side
20
+ * point buffers. Walks every series slot so ranges with gaps (unused
21
+ * tails) are skipped naturally.
22
+ */
23
+ function ensureCartesianSpatialGrid(chart: CartesianChart): void {
24
+ if (!chart._hitTest.isDirty || !chart._xData || !chart._yData) {
25
+ return;
26
+ }
27
+
28
+ const xData = chart._xData;
29
+ const yData = chart._yData;
30
+ const numSeries = Math.max(1, chart._splitGroups.length);
31
+ const cap = chart._seriesCapacity;
32
+
33
+ // `_xData`/`_yData` hold rebased values (`absolute - origin`) so the
34
+ // f32 GPU pipeline keeps sub-millisecond precision for datetime
35
+ // axes; the spatial-grid bounds and queries below must live in the
36
+ // same rebased space.
37
+ const xOrigin = isNaN(chart._xOrigin) ? 0 : chart._xOrigin;
38
+ const yOrigin = isNaN(chart._yOrigin) ? 0 : chart._yOrigin;
39
+ chart._hitTest.rebuild(
40
+ {
41
+ xMin: chart._xMin - xOrigin,
42
+ xMax: chart._xMax - xOrigin,
43
+ yMin: chart._yMin - yOrigin,
44
+ yMax: chart._yMax - yOrigin,
45
+ },
46
+ chart._dataCount,
47
+ (insert) => {
48
+ for (let s = 0; s < numSeries; s++) {
49
+ const count = chart._seriesUploadedCounts[s] ?? 0;
50
+ const base = s * cap;
51
+ for (let j = 0; j < count; j++) {
52
+ insert(base + j, xData[base + j], yData[base + j]);
53
+ }
54
+ }
55
+ },
56
+ );
57
+ }
58
+
59
+ /**
60
+ * Update {@link CartesianChart._hoveredIndex} for the given mouse
61
+ * position. Triggers a chrome re-render if the hovered index changes.
62
+ *
63
+ * In faceted mode, the hit test first resolves which facet the mouse is
64
+ * over, then restricts the search to that facet's series slice. This
65
+ * makes hover local to a facet; coordinated ghost indicators in other
66
+ * facets are painted by the chrome overlay.
67
+ */
68
+ export function handleCartesianHover(
69
+ chart: CartesianChart,
70
+ mx: number,
71
+ my: number,
72
+ ): void {
73
+ if (!chart._xData || !chart._yData) {
74
+ return;
75
+ }
76
+
77
+ // Resolve the facet (and its layout) under the cursor. Non-facet
78
+ // charts have `_facetGrid = null` and fall back to the cached
79
+ // `_lastLayout`; the hover then scans every series.
80
+ const { layout, facetIdx } = resolveHoverTarget(chart, mx, my);
81
+ if (!layout) {
82
+ clearHover(chart);
83
+ return;
84
+ }
85
+
86
+ const plot = layout.plotRect;
87
+ if (
88
+ mx < plot.x ||
89
+ mx > plot.x + plot.width ||
90
+ my < plot.y ||
91
+ my > plot.y + plot.height
92
+ ) {
93
+ clearHover(chart);
94
+ return;
95
+ }
96
+
97
+ const xMin = layout.paddedXMin;
98
+ const xMax = layout.paddedXMax;
99
+ const yMin = layout.paddedYMin;
100
+ const yMax = layout.paddedYMax;
101
+ const dataX = xMin + ((mx - plot.x) / plot.width) * (xMax - xMin);
102
+ const dataY = yMax - ((my - plot.y) / plot.height) * (yMax - yMin);
103
+ const pxPerDataX = plot.width / (xMax - xMin);
104
+ const pxPerDataY = plot.height / (yMax - yMin);
105
+
106
+ // `_xData`/`_yData` are rebased (see `processCartesianChunk`), so
107
+ // pass rebased mouse coords into the hit-test routines below; range
108
+ // ratios (`pxPerData*`) are translation-invariant and stay as-is.
109
+ const xOrigin = isNaN(chart._xOrigin) ? 0 : chart._xOrigin;
110
+ const yOrigin = isNaN(chart._yOrigin) ? 0 : chart._yOrigin;
111
+ const dataXRebased = dataX - xOrigin;
112
+ const dataYRebased = dataY - yOrigin;
113
+
114
+ const bestIdx =
115
+ facetIdx < 0
116
+ ? hoverAllSeries(
117
+ chart,
118
+ dataXRebased,
119
+ dataYRebased,
120
+ pxPerDataX,
121
+ pxPerDataY,
122
+ )
123
+ : hoverOneSeries(
124
+ chart,
125
+ facetIdx,
126
+ dataXRebased,
127
+ dataYRebased,
128
+ pxPerDataX,
129
+ pxPerDataY,
130
+ );
131
+
132
+ if (bestIdx !== chart._hoveredIndex || facetIdx !== chart._hoveredFacet) {
133
+ chart._hoveredIndex = bestIdx;
134
+ chart._hoveredFacet = facetIdx;
135
+ if (bestIdx >= 0) {
136
+ // Fire the lazy tooltip build; the controller drops stale
137
+ // resolves so rapid mouse motion can't paint out-of-date
138
+ // text. Crosshair / highlight ring are painted immediately
139
+ // from geometry so the hover feels instant; the tooltip
140
+ // box fills in once the row arrives (no "loading…" flicker).
141
+ const serial = chart._lazyTooltip.beginHover(bestIdx);
142
+ chart.glyph.buildTooltipLines(chart, bestIdx).then((lines) => {
143
+ if (chart._lazyTooltip.commitHover(serial, lines)) {
144
+ renderCartesianChromeOverlay(chart);
145
+ }
146
+ });
147
+ } else {
148
+ chart._lazyTooltip.clearHover();
149
+ }
150
+
151
+ renderCartesianChromeOverlay(chart);
152
+ }
153
+ }
154
+
155
+ function clearHover(chart: CartesianChart): void {
156
+ if (chart._hoveredIndex !== -1 || chart._hoveredFacet !== -1) {
157
+ chart._hoveredIndex = -1;
158
+ chart._hoveredFacet = -1;
159
+ renderCartesianChromeOverlay(chart);
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Return `(layout, facetIdx)` for the sub-plot under `(mx, my)`.
165
+ * `facetIdx` is `-1` in single-plot mode; the caller then scans every
166
+ * series (legacy behaviour). In faceted mode, `-1` also signals "mouse
167
+ * is in the grid frame but not inside any plot rect" — the caller
168
+ * clears hover in that case.
169
+ */
170
+ function resolveHoverTarget(
171
+ chart: CartesianChart,
172
+ mx: number,
173
+ my: number,
174
+ ): {
175
+ layout: import("../../layout/plot-layout").PlotLayout | null;
176
+ facetIdx: number;
177
+ } {
178
+ if (chart._facetGrid) {
179
+ const cells = chart._facetGrid.cells;
180
+ for (let i = 0; i < cells.length; i++) {
181
+ const plot = cells[i].layout.plotRect;
182
+ if (
183
+ mx >= plot.x &&
184
+ mx <= plot.x + plot.width &&
185
+ my >= plot.y &&
186
+ my <= plot.y + plot.height
187
+ ) {
188
+ return { layout: cells[i].layout, facetIdx: i };
189
+ }
190
+ }
191
+
192
+ return { layout: null, facetIdx: -1 };
193
+ }
194
+
195
+ return { layout: chart._lastLayout, facetIdx: -1 };
196
+ }
197
+
198
+ function hoverAllSeries(
199
+ chart: CartesianChart,
200
+ dataX: number,
201
+ dataY: number,
202
+ pxPerDataX: number,
203
+ pxPerDataY: number,
204
+ ): number {
205
+ ensureCartesianSpatialGrid(chart);
206
+ let bestIdx = chart._hitTest.query(
207
+ dataX,
208
+ dataY,
209
+ TOOLTIP_RADIUS_PX,
210
+ pxPerDataX,
211
+ pxPerDataY,
212
+ chart._xData,
213
+ chart._yData,
214
+ );
215
+ if (bestIdx >= 0) {
216
+ return bestIdx;
217
+ }
218
+
219
+ // Brute-force fallback over every valid slot.
220
+ let bestDistSq = TOOLTIP_RADIUS_PX * TOOLTIP_RADIUS_PX;
221
+ const numSeries = Math.max(1, chart._splitGroups.length);
222
+ const cap = chart._seriesCapacity;
223
+ const xData = chart._xData!;
224
+ const yData = chart._yData!;
225
+ for (let s = 0; s < numSeries; s++) {
226
+ const count = chart._seriesUploadedCounts[s] ?? 0;
227
+ const base = s * cap;
228
+ for (let j = 0; j < count; j++) {
229
+ const idx = base + j;
230
+ const dx = (xData[idx] - dataX) * pxPerDataX;
231
+ const dy = (yData[idx] - dataY) * pxPerDataY;
232
+ const distSq = dx * dx + dy * dy;
233
+ if (distSq < bestDistSq) {
234
+ bestDistSq = distSq;
235
+ bestIdx = idx;
236
+ }
237
+ }
238
+ }
239
+
240
+ return bestIdx;
241
+ }
242
+
243
+ /**
244
+ * Hit-test a single series' slot range. Faceted mode scopes hover to
245
+ * the series that owns the facet under the cursor; the spatial grid
246
+ * spans all series so we do a brute-force scan over just that series'
247
+ * slice — cheap even for dense datasets because only `count[s]` slots
248
+ * are read.
249
+ */
250
+ function hoverOneSeries(
251
+ chart: CartesianChart,
252
+ seriesIdx: number,
253
+ dataX: number,
254
+ dataY: number,
255
+ pxPerDataX: number,
256
+ pxPerDataY: number,
257
+ ): number {
258
+ const count = chart._seriesUploadedCounts[seriesIdx] ?? 0;
259
+ if (count === 0) {
260
+ return -1;
261
+ }
262
+
263
+ const cap = chart._seriesCapacity;
264
+ const base = seriesIdx * cap;
265
+ const xData = chart._xData!;
266
+ const yData = chart._yData!;
267
+
268
+ let bestDistSq = TOOLTIP_RADIUS_PX * TOOLTIP_RADIUS_PX;
269
+ let bestIdx = -1;
270
+ for (let j = 0; j < count; j++) {
271
+ const idx = base + j;
272
+ const dx = (xData[idx] - dataX) * pxPerDataX;
273
+ const dy = (yData[idx] - dataY) * pxPerDataY;
274
+ const distSq = dx * dx + dy * dy;
275
+ if (distSq < bestDistSq) {
276
+ bestDistSq = distSq;
277
+ bestIdx = idx;
278
+ }
279
+ }
280
+
281
+ return bestIdx;
282
+ }
283
+
284
+ /**
285
+ * Show a sticky (pinned) tooltip at the given point, anchored to the
286
+ * GL canvas's parent via the tooltip controller.
287
+ *
288
+ * In faceted mode, resolves the source facet from `pointIdx` and uses
289
+ * that cell's layout so the tooltip anchors to the correct sub-plot.
290
+ */
291
+ export function showCartesianPinnedTooltip(
292
+ chart: CartesianChart,
293
+ pointIdx: number,
294
+ ): void {
295
+ chart._tooltip.dismiss();
296
+ chart._pinnedIndex = pointIdx;
297
+ if (pointIdx < 0 || !chart._xData || !chart._yData) {
298
+ return;
299
+ }
300
+
301
+ const layout = layoutForIndex(chart, pointIdx);
302
+ if (!layout) {
303
+ return;
304
+ }
305
+
306
+ const xOrigin = isNaN(chart._xOrigin) ? 0 : chart._xOrigin;
307
+ const yOrigin = isNaN(chart._yOrigin) ? 0 : chart._yOrigin;
308
+ const pos = layout.dataToPixel(
309
+ chart._xData[pointIdx] + xOrigin,
310
+ chart._yData[pointIdx] + yOrigin,
311
+ );
312
+
313
+ const serial = chart._lazyTooltip.beginPin();
314
+ chart.glyph.buildTooltipLines(chart, pointIdx).then((lines) => {
315
+ // Abandon the pin if the user moved on (another pin/dismiss
316
+ // between click and resolve) or the underlying view changed.
317
+ if (!chart._lazyTooltip.isPinFresh(serial)) {
318
+ return;
319
+ }
320
+
321
+ if (chart._pinnedIndex !== pointIdx) {
322
+ return;
323
+ }
324
+
325
+ if (lines.length === 0) {
326
+ return;
327
+ }
328
+
329
+ chart._tooltip.pin(lines, pos, layout);
330
+ });
331
+
332
+ chart._hoveredIndex = -1;
333
+ chart._hoveredFacet = -1;
334
+ renderCartesianChromeOverlay(chart);
335
+ }
336
+
337
+ function layoutForIndex(
338
+ chart: CartesianChart,
339
+ pointIdx: number,
340
+ ): import("../../layout/plot-layout").PlotLayout | null {
341
+ if (chart._facetGrid && chart._seriesCapacity > 0) {
342
+ const s = Math.floor(pointIdx / chart._seriesCapacity);
343
+ const cell = chart._facetGrid.cells[s];
344
+ if (cell) {
345
+ return cell.layout;
346
+ }
347
+ }
348
+
349
+ return chart._lastLayout;
350
+ }
351
+
352
+ export function dismissCartesianPinnedTooltip(chart: CartesianChart): void {
353
+ chart._tooltip.dismiss();
354
+ chart._pinnedIndex = -1;
355
+ }