@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,320 @@
|
|
|
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 { WebGLContextManager } from "../../../webgl/context-manager";
|
|
14
|
+
import type { CartesianChart } from "../cartesian";
|
|
15
|
+
import type { Glyph } from "../glyph";
|
|
16
|
+
import { bindGradientTexture } from "../../../webgl/gradient-texture";
|
|
17
|
+
import {
|
|
18
|
+
createLineCornerBuffer,
|
|
19
|
+
getInstancing,
|
|
20
|
+
} from "../../../webgl/instanced-attrs";
|
|
21
|
+
import { formatTickValue, formatDateTickValue } from "../../../layout/ticks";
|
|
22
|
+
import lineVert from "../../../shaders/line.vert.glsl";
|
|
23
|
+
import lineFrag from "../../../shaders/line.frag.glsl";
|
|
24
|
+
|
|
25
|
+
interface LineCache {
|
|
26
|
+
program: WebGLProgram;
|
|
27
|
+
cornerBuffer: WebGLBuffer;
|
|
28
|
+
u_projection: WebGLUniformLocation | null;
|
|
29
|
+
u_resolution: WebGLUniformLocation | null;
|
|
30
|
+
u_line_width: WebGLUniformLocation | null;
|
|
31
|
+
u_color_range: WebGLUniformLocation | null;
|
|
32
|
+
u_gradient_lut: WebGLUniformLocation | null;
|
|
33
|
+
a_start: number;
|
|
34
|
+
a_end: number;
|
|
35
|
+
a_color_start: number;
|
|
36
|
+
a_color_end: number;
|
|
37
|
+
a_corner: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Polyline glyph — instanced triangle-strip segments between adjacent
|
|
42
|
+
* same-series points. Segments are scoped per-series via byte-offset
|
|
43
|
+
* rebinding (see `drawLineSeries`); the shader reads the endpoints'
|
|
44
|
+
* raw color values and samples the gradient LUT via the same sign-
|
|
45
|
+
* aware `(v - cmin) / (cmax - cmin)` mapping the scatter glyph uses.
|
|
46
|
+
*/
|
|
47
|
+
export class LineGlyph implements Glyph {
|
|
48
|
+
readonly name = "line" as const;
|
|
49
|
+
private _cache: LineCache | null = null;
|
|
50
|
+
|
|
51
|
+
ensureProgram(
|
|
52
|
+
_chart: CartesianChart,
|
|
53
|
+
glManager: WebGLContextManager,
|
|
54
|
+
): void {
|
|
55
|
+
if (this._cache) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const gl = glManager.gl;
|
|
60
|
+
const program = glManager.shaders.getOrCreate(
|
|
61
|
+
"line",
|
|
62
|
+
lineVert,
|
|
63
|
+
lineFrag,
|
|
64
|
+
);
|
|
65
|
+
const cornerBuffer = createLineCornerBuffer(gl);
|
|
66
|
+
this._cache = {
|
|
67
|
+
program,
|
|
68
|
+
cornerBuffer,
|
|
69
|
+
u_projection: gl.getUniformLocation(program, "u_projection"),
|
|
70
|
+
u_resolution: gl.getUniformLocation(program, "u_resolution"),
|
|
71
|
+
u_line_width: gl.getUniformLocation(program, "u_line_width"),
|
|
72
|
+
u_color_range: gl.getUniformLocation(program, "u_color_range"),
|
|
73
|
+
u_gradient_lut: gl.getUniformLocation(program, "u_gradient_lut"),
|
|
74
|
+
a_start: gl.getAttribLocation(program, "a_start"),
|
|
75
|
+
a_end: gl.getAttribLocation(program, "a_end"),
|
|
76
|
+
a_color_start: gl.getAttribLocation(program, "a_color_start"),
|
|
77
|
+
a_color_end: gl.getAttribLocation(program, "a_color_end"),
|
|
78
|
+
a_corner: gl.getAttribLocation(program, "a_corner"),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
draw(
|
|
83
|
+
chart: CartesianChart,
|
|
84
|
+
glManager: WebGLContextManager,
|
|
85
|
+
projection: Float32Array,
|
|
86
|
+
): void {
|
|
87
|
+
const cache = this._cache;
|
|
88
|
+
if (!cache) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const bind = bindLineState(cache, chart, glManager, projection);
|
|
93
|
+
if (!bind) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const numSeries = Math.max(1, chart._splitGroups.length);
|
|
98
|
+
for (let s = 0; s < numSeries; s++) {
|
|
99
|
+
drawLineSeries(cache, chart, glManager, s);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
unbindLineDivisors(cache, glManager);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
drawSeries(
|
|
106
|
+
chart: CartesianChart,
|
|
107
|
+
glManager: WebGLContextManager,
|
|
108
|
+
projection: Float32Array,
|
|
109
|
+
seriesIdx: number,
|
|
110
|
+
): void {
|
|
111
|
+
const cache = this._cache;
|
|
112
|
+
if (!cache) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!bindLineState(cache, chart, glManager, projection)) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
drawLineSeries(cache, chart, glManager, seriesIdx);
|
|
121
|
+
unbindLineDivisors(cache, glManager);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// helpers
|
|
125
|
+
|
|
126
|
+
async buildTooltipLines(
|
|
127
|
+
chart: CartesianChart,
|
|
128
|
+
flatIdx: number,
|
|
129
|
+
): Promise<string[]> {
|
|
130
|
+
const lines: string[] = [];
|
|
131
|
+
if (!chart._xData || !chart._yData) {
|
|
132
|
+
return lines;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (chart._splitGroups.length > 0 && chart._seriesCapacity > 0) {
|
|
136
|
+
const seriesIdx = Math.floor(flatIdx / chart._seriesCapacity);
|
|
137
|
+
const sg = chart._splitGroups[seriesIdx];
|
|
138
|
+
if (sg) {
|
|
139
|
+
lines.push(sg.prefix);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const xVal = chart._xData[flatIdx];
|
|
144
|
+
const yVal = chart._yData[flatIdx];
|
|
145
|
+
|
|
146
|
+
const xType = chart._columnTypes[chart._xLabel] || "";
|
|
147
|
+
const xIsDate = xType === "date" || xType === "datetime";
|
|
148
|
+
const xFormatted = xIsDate
|
|
149
|
+
? formatDateTickValue(xVal)
|
|
150
|
+
: formatTickValue(xVal);
|
|
151
|
+
lines.push(`${chart._xLabel || "Row"}: ${xFormatted}`);
|
|
152
|
+
|
|
153
|
+
const yType = chart._columnTypes[chart._yLabel] || "";
|
|
154
|
+
const yIsDate = yType === "date" || yType === "datetime";
|
|
155
|
+
const yFormatted = yIsDate
|
|
156
|
+
? formatDateTickValue(yVal)
|
|
157
|
+
: formatTickValue(yVal);
|
|
158
|
+
lines.push(`${chart._yLabel}: ${yFormatted}`);
|
|
159
|
+
|
|
160
|
+
return lines;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
tooltipOptions() {
|
|
164
|
+
return { crosshair: true, highlightRadius: 5 };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
destroy(chart: CartesianChart): void {
|
|
168
|
+
const cache = this._cache;
|
|
169
|
+
if (cache?.cornerBuffer && chart._glManager) {
|
|
170
|
+
chart._glManager.gl.deleteBuffer(cache.cornerBuffer);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
this._cache = null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Shared pre-draw state setup for `draw` and `drawSeries`. Binds the
|
|
179
|
+
* program, uploads uniforms + gradient texture, binds the static corner
|
|
180
|
+
* buffer, enables the instanced attributes. Returns false if the
|
|
181
|
+
* gradient cache is missing.
|
|
182
|
+
*/
|
|
183
|
+
function bindLineState(
|
|
184
|
+
cache: LineCache,
|
|
185
|
+
chart: CartesianChart,
|
|
186
|
+
glManager: WebGLContextManager,
|
|
187
|
+
projection: Float32Array,
|
|
188
|
+
): boolean {
|
|
189
|
+
const gl = glManager.gl;
|
|
190
|
+
if (!chart._gradientCache) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const dpr = glManager.dpr;
|
|
195
|
+
|
|
196
|
+
gl.useProgram(cache.program);
|
|
197
|
+
gl.uniformMatrix4fv(cache.u_projection, false, projection);
|
|
198
|
+
gl.uniform2f(cache.u_resolution, gl.canvas.width, gl.canvas.height);
|
|
199
|
+
gl.uniform1f(cache.u_line_width, chart._pluginConfig.line_width_px * dpr);
|
|
200
|
+
if (chart._colorMin < chart._colorMax) {
|
|
201
|
+
gl.uniform2f(cache.u_color_range, chart._colorMin, chart._colorMax);
|
|
202
|
+
} else {
|
|
203
|
+
gl.uniform2f(cache.u_color_range, 0.0, 0.0);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
bindGradientTexture(
|
|
207
|
+
glManager,
|
|
208
|
+
chart._gradientCache.texture,
|
|
209
|
+
cache.u_gradient_lut,
|
|
210
|
+
0,
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
const instancing = getInstancing(glManager);
|
|
214
|
+
const { setDivisor } = instancing;
|
|
215
|
+
|
|
216
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, cache.cornerBuffer);
|
|
217
|
+
gl.enableVertexAttribArray(cache.a_corner);
|
|
218
|
+
gl.vertexAttribPointer(cache.a_corner, 1, gl.FLOAT, false, 0, 0);
|
|
219
|
+
setDivisor(cache.a_corner, 0);
|
|
220
|
+
|
|
221
|
+
gl.enableVertexAttribArray(cache.a_start);
|
|
222
|
+
setDivisor(cache.a_start, 1);
|
|
223
|
+
gl.enableVertexAttribArray(cache.a_end);
|
|
224
|
+
setDivisor(cache.a_end, 1);
|
|
225
|
+
gl.enableVertexAttribArray(cache.a_color_start);
|
|
226
|
+
setDivisor(cache.a_color_start, 1);
|
|
227
|
+
gl.enableVertexAttribArray(cache.a_color_end);
|
|
228
|
+
setDivisor(cache.a_color_end, 1);
|
|
229
|
+
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Dispatch one instanced draw for series `s`. Rebinds start/end attrib
|
|
235
|
+
* pointers with byte offsets into the slotted buffer so instance 0 is
|
|
236
|
+
* the series' first segment.
|
|
237
|
+
*/
|
|
238
|
+
function drawLineSeries(
|
|
239
|
+
cache: LineCache,
|
|
240
|
+
chart: CartesianChart,
|
|
241
|
+
glManager: WebGLContextManager,
|
|
242
|
+
s: number,
|
|
243
|
+
): void {
|
|
244
|
+
const count = chart._seriesUploadedCounts[s] ?? 0;
|
|
245
|
+
if (count < 2) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const gl = glManager.gl;
|
|
250
|
+
const cap = chart._seriesCapacity;
|
|
251
|
+
const posStride = 2 * Float32Array.BYTES_PER_ELEMENT;
|
|
252
|
+
const idStride = Float32Array.BYTES_PER_ELEMENT;
|
|
253
|
+
|
|
254
|
+
// Render-path uses `peek`. If buffers haven't been uploaded
|
|
255
|
+
// yet (pan/zoom render landing between a pending draw's
|
|
256
|
+
// `ensureBufferCapacity` and its `uploadChunk`), skip — drawing
|
|
257
|
+
// against a recreated zero-filled buffer would produce one frame
|
|
258
|
+
// of empty plot area.
|
|
259
|
+
const posBuf = glManager.bufferPool.peek("a_position");
|
|
260
|
+
const idBuf = glManager.bufferPool.peek("a_color_value");
|
|
261
|
+
if (!posBuf || !idBuf) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const posBase = s * cap * posStride;
|
|
266
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, posBuf.buffer);
|
|
267
|
+
gl.vertexAttribPointer(
|
|
268
|
+
cache.a_start,
|
|
269
|
+
2,
|
|
270
|
+
gl.FLOAT,
|
|
271
|
+
false,
|
|
272
|
+
posStride,
|
|
273
|
+
posBase,
|
|
274
|
+
);
|
|
275
|
+
gl.vertexAttribPointer(
|
|
276
|
+
cache.a_end,
|
|
277
|
+
2,
|
|
278
|
+
gl.FLOAT,
|
|
279
|
+
false,
|
|
280
|
+
posStride,
|
|
281
|
+
posBase + posStride,
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
const idBase = s * cap * idStride;
|
|
285
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, idBuf.buffer);
|
|
286
|
+
gl.vertexAttribPointer(
|
|
287
|
+
cache.a_color_start,
|
|
288
|
+
1,
|
|
289
|
+
gl.FLOAT,
|
|
290
|
+
false,
|
|
291
|
+
idStride,
|
|
292
|
+
idBase,
|
|
293
|
+
);
|
|
294
|
+
gl.vertexAttribPointer(
|
|
295
|
+
cache.a_color_end,
|
|
296
|
+
1,
|
|
297
|
+
gl.FLOAT,
|
|
298
|
+
false,
|
|
299
|
+
idStride,
|
|
300
|
+
idBase + idStride,
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
getInstancing(glManager).drawArraysInstanced(
|
|
304
|
+
gl.TRIANGLE_STRIP,
|
|
305
|
+
0,
|
|
306
|
+
4,
|
|
307
|
+
count - 1,
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function unbindLineDivisors(
|
|
312
|
+
cache: LineCache,
|
|
313
|
+
glManager: WebGLContextManager,
|
|
314
|
+
): void {
|
|
315
|
+
const { setDivisor } = getInstancing(glManager);
|
|
316
|
+
setDivisor(cache.a_start, 0);
|
|
317
|
+
setDivisor(cache.a_end, 0);
|
|
318
|
+
setDivisor(cache.a_color_start, 0);
|
|
319
|
+
setDivisor(cache.a_color_end, 0);
|
|
320
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
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 { WebGLContextManager } from "../../../webgl/context-manager";
|
|
14
|
+
import type { CartesianChart } from "../cartesian";
|
|
15
|
+
import type { Glyph } from "../glyph";
|
|
16
|
+
import { bindGradientTexture } from "../../../webgl/gradient-texture";
|
|
17
|
+
import { buildPointRowTooltipLines } from "../tooltip-lines";
|
|
18
|
+
import scatterVert from "../../../shaders/scatter.vert.glsl";
|
|
19
|
+
import scatterFrag from "../../../shaders/scatter.frag.glsl";
|
|
20
|
+
|
|
21
|
+
type GL = WebGL2RenderingContext | WebGLRenderingContext;
|
|
22
|
+
|
|
23
|
+
interface PointCache {
|
|
24
|
+
program: WebGLProgram;
|
|
25
|
+
u_projection: WebGLUniformLocation | null;
|
|
26
|
+
u_point_size: WebGLUniformLocation | null;
|
|
27
|
+
u_color_range: WebGLUniformLocation | null;
|
|
28
|
+
u_gradient_lut: WebGLUniformLocation | null;
|
|
29
|
+
u_size_range: WebGLUniformLocation | null;
|
|
30
|
+
u_point_size_range: WebGLUniformLocation | null;
|
|
31
|
+
a_position: number;
|
|
32
|
+
a_color_value: number;
|
|
33
|
+
a_size_value: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* `gl.POINTS` glyph — one squared/antialiased point per data row. Color
|
|
38
|
+
* and size are driven by the shared `a_color_value` / `a_size_value`
|
|
39
|
+
* buffers; the vertex shader does sign-aware color-t mapping and samples
|
|
40
|
+
* the gradient LUT. One draw call per series (the slot layout leaves
|
|
41
|
+
* gaps at each series' tail that we can't safely include in a single
|
|
42
|
+
* draw — dispatching `count[s]` per series skips them).
|
|
43
|
+
*/
|
|
44
|
+
export class PointGlyph implements Glyph {
|
|
45
|
+
readonly name = "point" as const;
|
|
46
|
+
private _cache: PointCache | null = null;
|
|
47
|
+
|
|
48
|
+
ensureProgram(
|
|
49
|
+
_chart: CartesianChart,
|
|
50
|
+
glManager: WebGLContextManager,
|
|
51
|
+
): void {
|
|
52
|
+
if (this._cache) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const gl = glManager.gl;
|
|
57
|
+
const program = glManager.shaders.getOrCreate(
|
|
58
|
+
"scatter",
|
|
59
|
+
scatterVert,
|
|
60
|
+
scatterFrag,
|
|
61
|
+
);
|
|
62
|
+
this._cache = {
|
|
63
|
+
program,
|
|
64
|
+
u_projection: gl.getUniformLocation(program, "u_projection"),
|
|
65
|
+
u_point_size: gl.getUniformLocation(program, "u_point_size"),
|
|
66
|
+
u_color_range: gl.getUniformLocation(program, "u_color_range"),
|
|
67
|
+
u_gradient_lut: gl.getUniformLocation(program, "u_gradient_lut"),
|
|
68
|
+
u_size_range: gl.getUniformLocation(program, "u_size_range"),
|
|
69
|
+
u_point_size_range: gl.getUniformLocation(
|
|
70
|
+
program,
|
|
71
|
+
"u_point_size_range",
|
|
72
|
+
),
|
|
73
|
+
a_position: gl.getAttribLocation(program, "a_position"),
|
|
74
|
+
a_color_value: gl.getAttribLocation(program, "a_color_value"),
|
|
75
|
+
a_size_value: gl.getAttribLocation(program, "a_size_value"),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
draw(
|
|
80
|
+
chart: CartesianChart,
|
|
81
|
+
glManager: WebGLContextManager,
|
|
82
|
+
projection: Float32Array,
|
|
83
|
+
): void {
|
|
84
|
+
const cache = this._cache;
|
|
85
|
+
if (!cache) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!bindPointState(cache, chart, glManager, projection)) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Per-series tight draws: each series `s` occupies slots
|
|
94
|
+
// `[s*cap, s*cap + count[s])`. Dispatching `count[s]` avoids
|
|
95
|
+
// rasterizing unused tail slots. All attribs have divisor=0 so
|
|
96
|
+
// `first` shifts them together.
|
|
97
|
+
const gl = glManager.gl;
|
|
98
|
+
const numSeries = Math.max(1, chart._splitGroups.length);
|
|
99
|
+
const cap = chart._seriesCapacity;
|
|
100
|
+
for (let s = 0; s < numSeries; s++) {
|
|
101
|
+
const count = chart._seriesUploadedCounts[s] ?? 0;
|
|
102
|
+
if (count <= 0) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
gl.drawArrays(gl.POINTS, s * cap, count);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
drawSeries(
|
|
111
|
+
chart: CartesianChart,
|
|
112
|
+
glManager: WebGLContextManager,
|
|
113
|
+
projection: Float32Array,
|
|
114
|
+
seriesIdx: number,
|
|
115
|
+
): void {
|
|
116
|
+
const cache = this._cache;
|
|
117
|
+
if (!cache) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!bindPointState(cache, chart, glManager, projection)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const count = chart._seriesUploadedCounts[seriesIdx] ?? 0;
|
|
126
|
+
if (count <= 0) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const gl = glManager.gl;
|
|
131
|
+
const cap = chart._seriesCapacity;
|
|
132
|
+
gl.drawArrays(gl.POINTS, seriesIdx * cap, count);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
buildTooltipLines(
|
|
136
|
+
chart: CartesianChart,
|
|
137
|
+
flatIdx: number,
|
|
138
|
+
): Promise<string[]> {
|
|
139
|
+
return buildPointRowTooltipLines(chart, flatIdx);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
tooltipOptions() {
|
|
143
|
+
return { crosshair: true, highlightRadius: 6 };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
destroy(_chart: CartesianChart): void {
|
|
147
|
+
// Program lifetime is owned by the shader registry; just drop
|
|
148
|
+
// the cache reference. No private GPU resources to free.
|
|
149
|
+
this._cache = null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function setUniforms(
|
|
154
|
+
cache: PointCache,
|
|
155
|
+
gl: GL,
|
|
156
|
+
projection: Float32Array,
|
|
157
|
+
chart: CartesianChart,
|
|
158
|
+
dpr: number,
|
|
159
|
+
): void {
|
|
160
|
+
gl.uniformMatrix4fv(cache.u_projection, false, projection);
|
|
161
|
+
gl.uniform1f(cache.u_point_size, chart._pluginConfig.point_size_px * dpr);
|
|
162
|
+
|
|
163
|
+
if (chart._colorMin < chart._colorMax) {
|
|
164
|
+
gl.uniform2f(cache.u_color_range, chart._colorMin, chart._colorMax);
|
|
165
|
+
} else {
|
|
166
|
+
gl.uniform2f(cache.u_color_range, 0.0, 0.0);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (chart._sizeMin < chart._sizeMax) {
|
|
170
|
+
gl.uniform2f(cache.u_size_range, chart._sizeMin, chart._sizeMax);
|
|
171
|
+
} else {
|
|
172
|
+
gl.uniform2f(cache.u_size_range, 0.0, 0.0);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const size_scale_factor = Math.min(chart._pluginConfig.point_size_px, 3);
|
|
176
|
+
|
|
177
|
+
gl.uniform2f(
|
|
178
|
+
cache.u_point_size_range,
|
|
179
|
+
Math.max(
|
|
180
|
+
2 * dpr,
|
|
181
|
+
(chart._pluginConfig.point_size_px / size_scale_factor) * dpr,
|
|
182
|
+
),
|
|
183
|
+
chart._pluginConfig.point_size_px * size_scale_factor * dpr,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Shared pre-draw state setup for `draw` and `drawSeries`. Binds the
|
|
189
|
+
* program, uploads uniforms + gradient texture, wires the three per-
|
|
190
|
+
* vertex attributes. Returns false if the gradient cache is missing.
|
|
191
|
+
*/
|
|
192
|
+
function bindPointState(
|
|
193
|
+
cache: PointCache,
|
|
194
|
+
chart: CartesianChart,
|
|
195
|
+
glManager: WebGLContextManager,
|
|
196
|
+
projection: Float32Array,
|
|
197
|
+
): boolean {
|
|
198
|
+
const gl = glManager.gl;
|
|
199
|
+
if (!chart._gradientCache) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
gl.useProgram(cache.program);
|
|
204
|
+
setUniforms(cache, gl, projection, chart, glManager.dpr);
|
|
205
|
+
bindGradientTexture(
|
|
206
|
+
glManager,
|
|
207
|
+
chart._gradientCache.texture,
|
|
208
|
+
cache.u_gradient_lut,
|
|
209
|
+
0,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// Render-path uses `peek` (not `getOrCreate`) so we never
|
|
213
|
+
// recreate buffers from the draw path. If a buffer hasn't been
|
|
214
|
+
// uploaded yet — e.g. pan/zoom render landing between a pending
|
|
215
|
+
// draw's `ensureBufferCapacity` and its `uploadChunk` — return
|
|
216
|
+
// false and let the caller skip `drawArrays`. Painting against
|
|
217
|
+
// a freshly-recreated zero-filled buffer would show one frame
|
|
218
|
+
// of empty plot area while gridlines/chrome remain correct.
|
|
219
|
+
const posBuf = glManager.bufferPool.peek("a_position");
|
|
220
|
+
const colorBuf = glManager.bufferPool.peek("a_color_value");
|
|
221
|
+
const sizeBuf = glManager.bufferPool.peek("a_size_value");
|
|
222
|
+
if (!posBuf || !colorBuf || !sizeBuf) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, posBuf.buffer);
|
|
227
|
+
gl.enableVertexAttribArray(cache.a_position);
|
|
228
|
+
gl.vertexAttribPointer(cache.a_position, 2, gl.FLOAT, false, 0, 0);
|
|
229
|
+
|
|
230
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuf.buffer);
|
|
231
|
+
gl.enableVertexAttribArray(cache.a_color_value);
|
|
232
|
+
gl.vertexAttribPointer(cache.a_color_value, 1, gl.FLOAT, false, 0, 0);
|
|
233
|
+
|
|
234
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, sizeBuf.buffer);
|
|
235
|
+
gl.enableVertexAttribArray(cache.a_size_value);
|
|
236
|
+
gl.vertexAttribPointer(cache.a_size_value, 1, gl.FLOAT, false, 0, 0);
|
|
237
|
+
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
/**
|
|
14
|
+
* Slot-indexed string store for the scatter "Label" column. Strings
|
|
15
|
+
* are deduplicated across split-by facets so identical labels share a
|
|
16
|
+
* dictionary entry; the per-slot `Int32Array` then holds dictionary
|
|
17
|
+
* indices (`-1` means "no label for this slot").
|
|
18
|
+
*/
|
|
19
|
+
export class LabelInterner {
|
|
20
|
+
readonly data: Int32Array;
|
|
21
|
+
readonly dictionary: string[] = [];
|
|
22
|
+
private readonly dictMap: Map<string, number> = new Map();
|
|
23
|
+
|
|
24
|
+
constructor(capacity: number) {
|
|
25
|
+
this.data = new Int32Array(capacity);
|
|
26
|
+
this.data.fill(-1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Insert (or look up) `label` and write its dictionary index into
|
|
31
|
+
* the slot at `flatIdx`. Returns the assigned dictionary index.
|
|
32
|
+
*/
|
|
33
|
+
set(flatIdx: number, label: string): number {
|
|
34
|
+
let mapped = this.dictMap.get(label);
|
|
35
|
+
if (mapped === undefined) {
|
|
36
|
+
mapped = this.dictionary.length;
|
|
37
|
+
this.dictionary.push(label);
|
|
38
|
+
this.dictMap.set(label, mapped);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.data[flatIdx] = mapped;
|
|
42
|
+
return mapped;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Resolve a slot's label string, or `null` if unset.
|
|
47
|
+
*/
|
|
48
|
+
get(flatIdx: number): string | null {
|
|
49
|
+
const idx = this.data[flatIdx];
|
|
50
|
+
if (idx < 0) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return this.dictionary[idx];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Build the per-row tooltip for a point-style glyph (scatter, gradient
|
|
17
|
+
* heatmap). Resolves the source arrow row via the chart's lazy row
|
|
18
|
+
* fetcher, then surfaces every non-null column under the (split-aware)
|
|
19
|
+
* prefix filter formatted by column type.
|
|
20
|
+
*
|
|
21
|
+
* Returns `[]` when the chart has no row-index mirror or no fetcher;
|
|
22
|
+
* callers should fall back to a geometry-only tooltip in that case.
|
|
23
|
+
*/
|
|
24
|
+
export async function buildPointRowTooltipLines(
|
|
25
|
+
chart: CartesianChart,
|
|
26
|
+
flatIdx: number,
|
|
27
|
+
): Promise<string[]> {
|
|
28
|
+
const lines: string[] = [];
|
|
29
|
+
if (!chart._rowIndexData || !chart._lazyRows) {
|
|
30
|
+
return lines;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const rowIdx = chart._rowIndexData[flatIdx];
|
|
34
|
+
if (rowIdx < 0) {
|
|
35
|
+
return lines;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (chart._splitGroups.length > 0 && chart._seriesCapacity > 0) {
|
|
39
|
+
const seriesIdx = Math.floor(flatIdx / chart._seriesCapacity);
|
|
40
|
+
const sg = chart._splitGroups[seriesIdx];
|
|
41
|
+
if (sg?.prefix) {
|
|
42
|
+
lines.push(sg.prefix);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const row = await chart._lazyRows.fetchRow(rowIdx);
|
|
47
|
+
|
|
48
|
+
const prefixFilter =
|
|
49
|
+
chart._splitGroups.length > 0 && chart._seriesCapacity > 0
|
|
50
|
+
? (chart._splitGroups[Math.floor(flatIdx / chart._seriesCapacity)]
|
|
51
|
+
?.prefix ?? null)
|
|
52
|
+
: null;
|
|
53
|
+
|
|
54
|
+
for (const [colName, value] of row) {
|
|
55
|
+
if (value === null || value === undefined) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let displayName = colName;
|
|
60
|
+
if (prefixFilter !== null) {
|
|
61
|
+
const expected = `${prefixFilter}|`;
|
|
62
|
+
if (!colName.startsWith(expected)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
displayName = colName.substring(expected.length);
|
|
67
|
+
} else if (colName.includes("|")) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (typeof value === "number") {
|
|
72
|
+
const formatted = chart.getColumnFormatter(colName, "value")(value);
|
|
73
|
+
lines.push(`${displayName}: ${formatted}`);
|
|
74
|
+
} else {
|
|
75
|
+
lines.push(`${displayName}: ${value}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return lines;
|
|
80
|
+
}
|