@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.
- package/LICENSE.md +193 -0
- package/dist/cdn/perspective-viewer-charts.js +3 -0
- package/dist/cdn/perspective-viewer-charts.js.map +7 -0
- package/dist/esm/axis/axis-primitives.d.ts +24 -0
- package/dist/esm/axis/bar-axis.d.ts +51 -0
- package/dist/esm/axis/canvas.d.ts +24 -0
- package/dist/esm/axis/categorical-axis-core.d.ts +42 -0
- package/dist/esm/axis/categorical-axis.d.ts +27 -0
- package/dist/esm/axis/facet-chrome.d.ts +13 -0
- package/dist/esm/axis/label-geometry.d.ts +41 -0
- package/dist/esm/axis/legend.d.ts +44 -0
- package/dist/esm/axis/numeric-axis.d.ts +20 -0
- package/dist/esm/charts/candlestick/candlestick-build.d.ts +129 -0
- package/dist/esm/charts/candlestick/candlestick-interact.d.ts +10 -0
- package/dist/esm/charts/candlestick/candlestick-render.d.ts +24 -0
- package/dist/esm/charts/candlestick/candlestick.d.ts +144 -0
- package/dist/esm/charts/candlestick/glyphs/draw-candlesticks.d.ts +36 -0
- package/dist/esm/charts/candlestick/glyphs/draw-ohlc.d.ts +33 -0
- package/dist/esm/charts/canvas-types.d.ts +15 -0
- package/dist/esm/charts/cartesian/cartesian-build.d.ts +14 -0
- package/dist/esm/charts/cartesian/cartesian-interact.d.ts +20 -0
- package/dist/esm/charts/cartesian/cartesian-render.d.ts +26 -0
- package/dist/esm/charts/cartesian/cartesian.d.ts +239 -0
- package/dist/esm/charts/cartesian/glyph.d.ts +53 -0
- package/dist/esm/charts/cartesian/glyphs/density.d.ts +142 -0
- package/dist/esm/charts/cartesian/glyphs/lines.d.ts +23 -0
- package/dist/esm/charts/cartesian/glyphs/points.d.ts +24 -0
- package/dist/esm/charts/cartesian/label-interner.d.ts +21 -0
- package/dist/esm/charts/cartesian/tooltip-lines.d.ts +11 -0
- package/dist/esm/charts/chart-base.d.ts +402 -0
- package/dist/esm/charts/chart.d.ts +338 -0
- package/dist/esm/charts/common/band-layout.d.ts +32 -0
- package/dist/esm/charts/common/categorical-y-chart.d.ts +53 -0
- package/dist/esm/charts/common/category-axis-resolver.d.ts +90 -0
- package/dist/esm/charts/common/chrome-cache.d.ts +18 -0
- package/dist/esm/charts/common/draw-tooltip-box.d.ts +9 -0
- package/dist/esm/charts/common/leaf-color.d.ts +33 -0
- package/dist/esm/charts/common/node-store.d.ts +81 -0
- package/dist/esm/charts/common/tree-chart.d.ts +48 -0
- package/dist/esm/charts/common/tree-chrome.d.ts +31 -0
- package/dist/esm/charts/common/tree-data.d.ts +54 -0
- package/dist/esm/charts/common/visible-extent.d.ts +51 -0
- package/dist/esm/charts/heatmap/heatmap-build.d.ts +86 -0
- package/dist/esm/charts/heatmap/heatmap-interact.d.ts +19 -0
- package/dist/esm/charts/heatmap/heatmap-render.d.ts +19 -0
- package/dist/esm/charts/heatmap/heatmap-y-axis.d.ts +46 -0
- package/dist/esm/charts/heatmap/heatmap.d.ts +117 -0
- package/dist/esm/charts/map/map.d.ts +67 -0
- package/dist/esm/charts/registry.d.ts +14 -0
- package/dist/esm/charts/series/glyphs/draw-areas.d.ts +30 -0
- package/dist/esm/charts/series/glyphs/draw-bars.d.ts +15 -0
- package/dist/esm/charts/series/glyphs/draw-lines.d.ts +34 -0
- package/dist/esm/charts/series/glyphs/draw-scatter.d.ts +33 -0
- package/dist/esm/charts/series/series-build.d.ts +228 -0
- package/dist/esm/charts/series/series-interact.d.ts +35 -0
- package/dist/esm/charts/series/series-render.d.ts +41 -0
- package/dist/esm/charts/series/series-type.d.ts +49 -0
- package/dist/esm/charts/series/series.d.ts +317 -0
- package/dist/esm/charts/sunburst/sunburst-interact.d.ts +7 -0
- package/dist/esm/charts/sunburst/sunburst-layout.d.ts +33 -0
- package/dist/esm/charts/sunburst/sunburst-render.d.ts +22 -0
- package/dist/esm/charts/sunburst/sunburst.d.ts +85 -0
- package/dist/esm/charts/treemap/treemap-interact.d.ts +12 -0
- package/dist/esm/charts/treemap/treemap-layout.d.ts +28 -0
- package/dist/esm/charts/treemap/treemap-render.d.ts +18 -0
- package/dist/esm/charts/treemap/treemap.d.ts +74 -0
- package/dist/esm/config.d.ts +27 -0
- package/dist/esm/data/lazy-row.d.ts +32 -0
- package/dist/esm/data/split-groups.d.ts +20 -0
- package/dist/esm/data/view-reader.d.ts +35 -0
- package/dist/esm/event-detail.d.ts +28 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/interaction/hit-test.d.ts +30 -0
- package/dist/esm/interaction/host-sink-dom.d.ts +19 -0
- package/dist/esm/interaction/host-sink-message.d.ts +46 -0
- package/dist/esm/interaction/lazy-tooltip.d.ts +61 -0
- package/dist/esm/interaction/raw-event-forwarder.d.ts +27 -0
- package/dist/esm/interaction/spatial-grid.d.ts +15 -0
- package/dist/esm/interaction/tooltip-controller.d.ts +193 -0
- package/dist/esm/interaction/zoom-controller.d.ts +106 -0
- package/dist/esm/interaction/zoom-router.d.ts +48 -0
- package/dist/esm/layout/facet-grid.d.ts +126 -0
- package/dist/esm/layout/plot-layout.d.ts +104 -0
- package/dist/esm/layout/ticks.d.ts +17 -0
- package/dist/esm/map/mercator.d.ts +102 -0
- package/dist/esm/map/tile-cache.d.ts +38 -0
- package/dist/esm/map/tile-layer.d.ts +66 -0
- package/dist/esm/map/tile-loader.d.ts +52 -0
- package/dist/esm/map/tile-source.d.ts +66 -0
- package/dist/esm/perspective-viewer-charts.js +3 -0
- package/dist/esm/perspective-viewer-charts.js.map +7 -0
- package/dist/esm/plugin/charts.d.ts +40 -0
- package/dist/esm/plugin/plugin.d.ts +95 -0
- package/dist/esm/render/scheduler.d.ts +41 -0
- package/dist/esm/theme/gradient.d.ts +48 -0
- package/dist/esm/theme/palette.d.ts +13 -0
- package/dist/esm/theme/theme-snapshot.d.ts +7 -0
- package/dist/esm/theme/theme.d.ts +53 -0
- package/dist/esm/transport/protocol.d.ts +430 -0
- package/dist/esm/transport/renderer-transport.d.ts +201 -0
- package/dist/esm/utils/css.d.ts +1 -0
- package/dist/esm/utils/font-snapshot.d.ts +50 -0
- package/dist/esm/webgl/buffer-pool.d.ts +62 -0
- package/dist/esm/webgl/context-manager.d.ts +184 -0
- package/dist/esm/webgl/gradient-texture.d.ts +17 -0
- package/dist/esm/webgl/instanced-attrs.d.ts +44 -0
- package/dist/esm/webgl/plot-frame.d.ts +39 -0
- package/dist/esm/webgl/program-cache.d.ts +13 -0
- package/dist/esm/webgl/shader-manifest.d.ts +53 -0
- package/dist/esm/webgl/shader-registry.d.ts +22 -0
- package/dist/esm/worker/boot.d.ts +0 -0
- package/dist/esm/worker/dispatch.d.ts +9 -0
- package/dist/esm/worker/font-loader.d.ts +2 -0
- package/dist/esm/worker/renderer.worker.d.ts +115 -0
- package/dist/esm/worker/session-host.d.ts +26 -0
- package/package.json +47 -0
- package/src/css/perspective-viewer-charts.css +95 -0
- package/src/ts/axis/axis-primitives.ts +125 -0
- package/src/ts/axis/bar-axis.ts +345 -0
- package/src/ts/axis/canvas.ts +64 -0
- package/src/ts/axis/categorical-axis-core.ts +125 -0
- package/src/ts/axis/categorical-axis.ts +716 -0
- package/src/ts/axis/facet-chrome.ts +42 -0
- package/src/ts/axis/label-geometry.ts +188 -0
- package/src/ts/axis/legend.ts +218 -0
- package/src/ts/axis/numeric-axis.ts +353 -0
- package/src/ts/charts/candlestick/candlestick-build.ts +516 -0
- package/src/ts/charts/candlestick/candlestick-interact.ts +256 -0
- package/src/ts/charts/candlestick/candlestick-render.ts +387 -0
- package/src/ts/charts/candlestick/candlestick.ts +367 -0
- package/src/ts/charts/candlestick/glyphs/draw-candlesticks.ts +432 -0
- package/src/ts/charts/candlestick/glyphs/draw-ohlc.ts +317 -0
- package/src/ts/charts/canvas-types.ts +30 -0
- package/src/ts/charts/cartesian/cartesian-build.ts +616 -0
- package/src/ts/charts/cartesian/cartesian-interact.ts +355 -0
- package/src/ts/charts/cartesian/cartesian-render.ts +948 -0
- package/src/ts/charts/cartesian/cartesian.ts +469 -0
- package/src/ts/charts/cartesian/glyph.ts +81 -0
- package/src/ts/charts/cartesian/glyphs/density.ts +1263 -0
- package/src/ts/charts/cartesian/glyphs/lines.ts +320 -0
- package/src/ts/charts/cartesian/glyphs/points.ts +239 -0
- package/src/ts/charts/cartesian/label-interner.ts +56 -0
- package/src/ts/charts/cartesian/tooltip-lines.ts +80 -0
- package/src/ts/charts/chart-base.ts +840 -0
- package/src/ts/charts/chart.ts +427 -0
- package/src/ts/charts/common/band-layout.ts +63 -0
- package/src/ts/charts/common/categorical-y-chart.ts +81 -0
- package/src/ts/charts/common/category-axis-resolver.ts +314 -0
- package/src/ts/charts/common/chrome-cache.ts +79 -0
- package/src/ts/charts/common/draw-tooltip-box.ts +84 -0
- package/src/ts/charts/common/leaf-color.ts +92 -0
- package/src/ts/charts/common/node-store.ts +235 -0
- package/src/ts/charts/common/tree-chart.ts +76 -0
- package/src/ts/charts/common/tree-chrome.ts +123 -0
- package/src/ts/charts/common/tree-data.ts +623 -0
- package/src/ts/charts/common/visible-extent.ts +112 -0
- package/src/ts/charts/heatmap/heatmap-build.ts +426 -0
- package/src/ts/charts/heatmap/heatmap-interact.ts +274 -0
- package/src/ts/charts/heatmap/heatmap-render.ts +815 -0
- package/src/ts/charts/heatmap/heatmap-y-axis.ts +351 -0
- package/src/ts/charts/heatmap/heatmap.ts +368 -0
- package/src/ts/charts/map/map.ts +201 -0
- package/src/ts/charts/registry.ts +65 -0
- package/src/ts/charts/series/glyphs/draw-areas.ts +331 -0
- package/src/ts/charts/series/glyphs/draw-bars.ts +113 -0
- package/src/ts/charts/series/glyphs/draw-lines.ts +320 -0
- package/src/ts/charts/series/glyphs/draw-scatter.ts +328 -0
- package/src/ts/charts/series/series-build.ts +848 -0
- package/src/ts/charts/series/series-interact.ts +604 -0
- package/src/ts/charts/series/series-render.ts +1109 -0
- package/src/ts/charts/series/series-type.ts +99 -0
- package/src/ts/charts/series/series.ts +794 -0
- package/src/ts/charts/sunburst/sunburst-interact.ts +460 -0
- package/src/ts/charts/sunburst/sunburst-layout.ts +238 -0
- package/src/ts/charts/sunburst/sunburst-render.ts +887 -0
- package/src/ts/charts/sunburst/sunburst.ts +248 -0
- package/src/ts/charts/treemap/treemap-interact.ts +445 -0
- package/src/ts/charts/treemap/treemap-layout.ts +328 -0
- package/src/ts/charts/treemap/treemap-render.ts +886 -0
- package/src/ts/charts/treemap/treemap.ts +247 -0
- package/src/ts/config.ts +41 -0
- package/src/ts/data/lazy-row.ts +140 -0
- package/src/ts/data/split-groups.ts +97 -0
- package/src/ts/data/view-reader.ts +107 -0
- package/src/ts/event-detail.ts +44 -0
- package/src/ts/index.ts +53 -0
- package/src/ts/interaction/hit-test.ts +106 -0
- package/src/ts/interaction/host-sink-dom.ts +85 -0
- package/src/ts/interaction/host-sink-message.ts +75 -0
- package/src/ts/interaction/lazy-tooltip.ts +102 -0
- package/src/ts/interaction/raw-event-forwarder.ts +175 -0
- package/src/ts/interaction/spatial-grid.ts +100 -0
- package/src/ts/interaction/tooltip-controller.ts +407 -0
- package/src/ts/interaction/zoom-controller.ts +468 -0
- package/src/ts/interaction/zoom-router.ts +230 -0
- package/src/ts/layout/facet-grid.ts +346 -0
- package/src/ts/layout/plot-layout.ts +277 -0
- package/src/ts/layout/ticks.ts +168 -0
- package/src/ts/map/mercator.ts +204 -0
- package/src/ts/map/tile-cache.ts +96 -0
- package/src/ts/map/tile-layer.ts +382 -0
- package/src/ts/map/tile-loader.ts +143 -0
- package/src/ts/map/tile-source.ts +156 -0
- package/src/ts/plugin/charts.ts +286 -0
- package/src/ts/plugin/plugin.ts +668 -0
- package/src/ts/render/scheduler.ts +339 -0
- package/src/ts/shaders/area.frag.glsl +20 -0
- package/src/ts/shaders/area.vert.glsl +19 -0
- package/src/ts/shaders/bar.frag.glsl +25 -0
- package/src/ts/shaders/bar.vert.glsl +60 -0
- package/src/ts/shaders/candlestick-body.frag.glsl +19 -0
- package/src/ts/shaders/candlestick-body.vert.glsl +34 -0
- package/src/ts/shaders/density-extreme.frag.glsl +30 -0
- package/src/ts/shaders/density-mrt.frag.glsl +44 -0
- package/src/ts/shaders/density-mrt.vert.glsl +48 -0
- package/src/ts/shaders/density-resolve.frag.glsl +89 -0
- package/src/ts/shaders/density-resolve.vert.glsl +23 -0
- package/src/ts/shaders/density-splat.frag.glsl +34 -0
- package/src/ts/shaders/density-splat.vert.glsl +52 -0
- package/src/ts/shaders/gridline.frag.glsl +18 -0
- package/src/ts/shaders/gridline.vert.glsl +18 -0
- package/src/ts/shaders/heatmap.frag.glsl +23 -0
- package/src/ts/shaders/heatmap.vert.glsl +42 -0
- package/src/ts/shaders/line-uniform.frag.glsl +26 -0
- package/src/ts/shaders/line-uniform.vert.glsl +54 -0
- package/src/ts/shaders/line.frag.glsl +28 -0
- package/src/ts/shaders/line.vert.glsl +87 -0
- package/src/ts/shaders/scatter.frag.glsl +39 -0
- package/src/ts/shaders/scatter.vert.glsl +67 -0
- package/src/ts/shaders/sunburst-arc.frag.glsl +19 -0
- package/src/ts/shaders/sunburst-arc.vert.glsl +79 -0
- package/src/ts/shaders/tile.frag.glsl +27 -0
- package/src/ts/shaders/tile.vert.glsl +35 -0
- package/src/ts/shaders/treemap.frag.glsl +19 -0
- package/src/ts/shaders/treemap.vert.glsl +25 -0
- package/src/ts/shaders/y-scatter.frag.glsl +30 -0
- package/src/ts/shaders/y-scatter.vert.glsl +31 -0
- package/src/ts/theme/gradient.ts +312 -0
- package/src/ts/theme/palette.ts +64 -0
- package/src/ts/theme/theme-snapshot.ts +66 -0
- package/src/ts/theme/theme.ts +166 -0
- package/src/ts/transport/protocol.ts +497 -0
- package/src/ts/transport/renderer-transport.ts +788 -0
- package/src/ts/utils/css.ts +36 -0
- package/src/ts/utils/font-snapshot.ts +159 -0
- package/src/ts/webgl/buffer-pool.ts +163 -0
- package/src/ts/webgl/context-manager.ts +414 -0
- package/src/ts/webgl/gradient-texture.ts +84 -0
- package/src/ts/webgl/instanced-attrs.ts +139 -0
- package/src/ts/webgl/plot-frame.ts +91 -0
- package/src/ts/webgl/program-cache.ts +46 -0
- package/src/ts/webgl/shader-manifest.ts +148 -0
- package/src/ts/webgl/shader-registry.ts +97 -0
- package/src/ts/worker/boot.ts +22 -0
- package/src/ts/worker/dispatch.ts +99 -0
- package/src/ts/worker/font-loader.ts +89 -0
- package/src/ts/worker/renderer.worker.ts +734 -0
- 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
|
+
}
|