@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,368 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
import type { ColumnDataMap } from "../../data/view-reader";
|
|
14
|
+
import type { WebGLContextManager } from "../../webgl/context-manager";
|
|
15
|
+
import { AbstractChart } from "../chart-base";
|
|
16
|
+
import { PlotLayout } from "../../layout/plot-layout";
|
|
17
|
+
import type { CategoricalLevel } from "../../axis/categorical-axis";
|
|
18
|
+
import type { FacetGrid } from "../../layout/facet-grid";
|
|
19
|
+
import type {
|
|
20
|
+
AxisMode,
|
|
21
|
+
NumericCategoryDomain,
|
|
22
|
+
} from "../common/category-axis-resolver";
|
|
23
|
+
import {
|
|
24
|
+
buildHeatmapPipeline,
|
|
25
|
+
partitionColumnsPerFacet,
|
|
26
|
+
type HeatmapCell,
|
|
27
|
+
type HeatmapPipelineResult,
|
|
28
|
+
} from "./heatmap-build";
|
|
29
|
+
import {
|
|
30
|
+
renderHeatmapFrame,
|
|
31
|
+
renderHeatmapChromeOverlay,
|
|
32
|
+
type HeatmapLocations,
|
|
33
|
+
} from "./heatmap-render";
|
|
34
|
+
import { handleHeatmapHover } from "./heatmap-interact";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* One heatmap in a facet-grid layout. Each facet corresponds to one
|
|
38
|
+
* user-selected column in the `Color` slot; its `pipeline` holds the
|
|
39
|
+
* cell data, and `layout` is the cell's `PlotLayout` from `buildFacetGrid`.
|
|
40
|
+
* `instanceStart`/`instanceCount` give the range of the packed
|
|
41
|
+
* cell/colorT buffers that belong to this facet.
|
|
42
|
+
*/
|
|
43
|
+
export interface HeatmapFacet {
|
|
44
|
+
label: string;
|
|
45
|
+
pipeline: HeatmapPipelineResult;
|
|
46
|
+
layout: PlotLayout;
|
|
47
|
+
instanceStart: number;
|
|
48
|
+
instanceCount: number;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Origins used to rebase cell positions before f32 narrowing —
|
|
52
|
+
* matches the per-axis convention in `SeriesChart._categoryOrigin`.
|
|
53
|
+
* `0` for non-numeric axes; for numeric (especially datetime) axes
|
|
54
|
+
* pinned to `xNumericDomain.min` / `yNumericDomain.min` so the
|
|
55
|
+
* shader's projection matrix can be built in rebased space.
|
|
56
|
+
*/
|
|
57
|
+
xOrigin: number;
|
|
58
|
+
yOrigin: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Heatmap chart. `yIdx` maps 1:1 to the arrow column iteration order
|
|
63
|
+
* (after skipping `__ROW_PATH_N__` metadata). `xIdx` is the row index
|
|
64
|
+
* post-`rowOffset`.
|
|
65
|
+
*
|
|
66
|
+
* With one user column in the `Color` slot the chart renders a single
|
|
67
|
+
* heatmap filling the canvas. With more than one, each column becomes
|
|
68
|
+
* its own heatmap in a facet grid; all facets share a common color
|
|
69
|
+
* scale and a single legend.
|
|
70
|
+
*/
|
|
71
|
+
export class HeatmapChart extends AbstractChart {
|
|
72
|
+
_program: WebGLProgram | null = null;
|
|
73
|
+
_locations: HeatmapLocations | null = null;
|
|
74
|
+
_cornerBuffer: WebGLBuffer | null = null;
|
|
75
|
+
_gradientCache:
|
|
76
|
+
| import("../../webgl/gradient-texture").GradientTextureCache
|
|
77
|
+
| null = null;
|
|
78
|
+
|
|
79
|
+
_xLevels: CategoricalLevel[] = [];
|
|
80
|
+
_yLevels: CategoricalLevel[] = [];
|
|
81
|
+
_yColumnNames: string[] = [];
|
|
82
|
+
_numX = 0;
|
|
83
|
+
_numY = 0;
|
|
84
|
+
_rowOffset = 0;
|
|
85
|
+
|
|
86
|
+
_xAxisMode: AxisMode = { mode: "category" };
|
|
87
|
+
_yAxisMode: AxisMode = { mode: "category" };
|
|
88
|
+
_xPositions: Float64Array | null = null;
|
|
89
|
+
_yPositions: Float64Array | null = null;
|
|
90
|
+
_xNumericDomain: NumericCategoryDomain | null = null;
|
|
91
|
+
_yNumericDomain: NumericCategoryDomain | null = null;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Single-plot rebase origins. Datetime numeric axes carry ~1.7e12
|
|
95
|
+
* timestamps which the f32 GPU pipeline cannot resolve below
|
|
96
|
+
* ~256ms; the cell upload subtracts these and the projection
|
|
97
|
+
* matrix is built with the same values so its `tx`/`ty` terms stay
|
|
98
|
+
* small enough for f32 cancellation in the shader. `0` for
|
|
99
|
+
* categorical or numeric-non-date axes.
|
|
100
|
+
*/
|
|
101
|
+
_xOrigin = 0;
|
|
102
|
+
_yOrigin = 0;
|
|
103
|
+
|
|
104
|
+
_cells: HeatmapCell[] = [];
|
|
105
|
+
_cells2D: (HeatmapCell | null)[] = [];
|
|
106
|
+
_uploadedCells = 0;
|
|
107
|
+
|
|
108
|
+
_colorMin = 0;
|
|
109
|
+
_colorMax = 1;
|
|
110
|
+
_aggName = "";
|
|
111
|
+
|
|
112
|
+
_hoveredCell: HeatmapCell | null = null;
|
|
113
|
+
_lastLayout: PlotLayout | null = null;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Last cursor position (canvas-CSS pixels) recorded by
|
|
117
|
+
* `handleHeatmapHover`. Used as the tooltip anchor instead of the
|
|
118
|
+
* cell center so the hover label tracks the mouse — necessary
|
|
119
|
+
* because heatmap cells can be many pixels wide and a center-anchored
|
|
120
|
+
* tooltip drifts away from the cursor.
|
|
121
|
+
*/
|
|
122
|
+
_hoveredMouseX = 0;
|
|
123
|
+
_hoveredMouseY = 0;
|
|
124
|
+
|
|
125
|
+
_facets: HeatmapFacet[] = [];
|
|
126
|
+
_facetGrid: FacetGrid | null = null;
|
|
127
|
+
_hoveredFacetIdx = -1;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Bound accessor so the interact module can trigger a chrome redraw.
|
|
131
|
+
*/
|
|
132
|
+
_renderChromeOverlay = () => renderHeatmapChromeOverlay(this);
|
|
133
|
+
|
|
134
|
+
protected override tooltipCallbacks() {
|
|
135
|
+
return {
|
|
136
|
+
onHover: (mx: number, my: number) =>
|
|
137
|
+
handleHeatmapHover(this, mx, my),
|
|
138
|
+
onLeave: () => {
|
|
139
|
+
if (this._hoveredCell) {
|
|
140
|
+
this._hoveredCell = null;
|
|
141
|
+
this._renderChromeOverlay();
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
onPin: (mx: number, my: number) => {
|
|
145
|
+
// Refresh the hit-test at the click coords so the pin
|
|
146
|
+
// path doesn't depend on the RAF-throttled hover state
|
|
147
|
+
// — see comment in `series.ts` `onPin`.
|
|
148
|
+
handleHeatmapHover(this, mx, my);
|
|
149
|
+
if (this._hoveredCell) {
|
|
150
|
+
void this._emitHeatmapClickSelect(
|
|
151
|
+
this._hoveredCell.xIdx,
|
|
152
|
+
this._hoveredCell.yIdx,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
onUnpin: () => {
|
|
157
|
+
this.emitUnselect();
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Resolve a clicked heatmap cell into a `PerspectiveClickDetail`
|
|
164
|
+
* and emit both `perspective-click` and
|
|
165
|
+
* `perspective-global-filter selected:true`. `xIdx` indexes the
|
|
166
|
+
* outer (group-by) hierarchy; `yIdx` indexes the column-side
|
|
167
|
+
* hierarchy (split-by + value-column splits). Each level is read
|
|
168
|
+
* directly from the pre-resolved `_xLevels` / `_yLevels` labels.
|
|
169
|
+
*
|
|
170
|
+
* Representative source row: `xIdx + _rowOffset` — the row in the
|
|
171
|
+
* pivoted view that owns this category. Sufficient for the
|
|
172
|
+
* `row.{col}` lookups consumers typically do; not authoritative for
|
|
173
|
+
* cells that aggregate across many source rows.
|
|
174
|
+
*/
|
|
175
|
+
private async _emitHeatmapClickSelect(
|
|
176
|
+
xIdx: number,
|
|
177
|
+
yIdx: number,
|
|
178
|
+
): Promise<void> {
|
|
179
|
+
const groupByValues: (string | null)[] = this._xLevels.map(
|
|
180
|
+
(level) => level.labels[xIdx] ?? null,
|
|
181
|
+
);
|
|
182
|
+
const splitByValues: (string | null)[] = this._yLevels
|
|
183
|
+
.slice(0, this._splitBy.length)
|
|
184
|
+
.map((level) => level.labels[yIdx] ?? null);
|
|
185
|
+
|
|
186
|
+
const colorColumn = this._columnSlots[0] ?? "";
|
|
187
|
+
await this.emitClickAndSelect({
|
|
188
|
+
rowIdx: xIdx + this._rowOffset,
|
|
189
|
+
columnName: colorColumn,
|
|
190
|
+
groupByValues,
|
|
191
|
+
splitByValues,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async uploadAndRender(
|
|
196
|
+
glManager: WebGLContextManager,
|
|
197
|
+
columns: ColumnDataMap,
|
|
198
|
+
startRow: number,
|
|
199
|
+
endRow: number,
|
|
200
|
+
): Promise<void> {
|
|
201
|
+
this._glManager = glManager;
|
|
202
|
+
|
|
203
|
+
if (startRow !== 0) {
|
|
204
|
+
// Heatmap renders a single consolidated pass; the viewer
|
|
205
|
+
// should not chunk this but guard defensively.
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const userColumns = this._columnSlots.filter((s): s is string => !!s);
|
|
210
|
+
|
|
211
|
+
if (userColumns.length > 1) {
|
|
212
|
+
const partitions = partitionColumnsPerFacet(columns, userColumns);
|
|
213
|
+
const facets: HeatmapFacet[] = [];
|
|
214
|
+
const allCells: HeatmapCell[] = [];
|
|
215
|
+
let globalMin = Infinity;
|
|
216
|
+
let globalMax = -Infinity;
|
|
217
|
+
for (const part of partitions) {
|
|
218
|
+
const pipeline = buildHeatmapPipeline({
|
|
219
|
+
columns: part.columns,
|
|
220
|
+
numRows: endRow,
|
|
221
|
+
groupBy: this._groupBy,
|
|
222
|
+
splitBy: this._splitBy,
|
|
223
|
+
groupByTypes: this._groupByTypes,
|
|
224
|
+
});
|
|
225
|
+
const instanceStart = allCells.length;
|
|
226
|
+
|
|
227
|
+
// Re-stamp each cell with its facet offset so the packed
|
|
228
|
+
// instance buffer can be drawn in one sweep; the facet's
|
|
229
|
+
// own `pipeline.cells` keeps its original indices for
|
|
230
|
+
// hit-testing via `cells2D`.
|
|
231
|
+
for (const c of pipeline.cells) {
|
|
232
|
+
allCells.push({
|
|
233
|
+
xIdx: c.xIdx,
|
|
234
|
+
yIdx: c.yIdx,
|
|
235
|
+
value: c.value,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
facets.push({
|
|
240
|
+
label: part.label,
|
|
241
|
+
pipeline,
|
|
242
|
+
layout: new PlotLayout(1, 1, {
|
|
243
|
+
hasXLabel: false,
|
|
244
|
+
hasYLabel: false,
|
|
245
|
+
hasLegend: false,
|
|
246
|
+
}),
|
|
247
|
+
instanceStart,
|
|
248
|
+
instanceCount: pipeline.cells.length,
|
|
249
|
+
xOrigin: pipeline.xNumericDomain?.min ?? 0,
|
|
250
|
+
yOrigin: pipeline.yNumericDomain?.min ?? 0,
|
|
251
|
+
});
|
|
252
|
+
if (
|
|
253
|
+
isFinite(pipeline.colorMin) &&
|
|
254
|
+
pipeline.colorMin < globalMin
|
|
255
|
+
) {
|
|
256
|
+
globalMin = pipeline.colorMin;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (
|
|
260
|
+
isFinite(pipeline.colorMax) &&
|
|
261
|
+
pipeline.colorMax > globalMax
|
|
262
|
+
) {
|
|
263
|
+
globalMax = pipeline.colorMax;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (!isFinite(globalMin) || !isFinite(globalMax)) {
|
|
268
|
+
globalMin = 0;
|
|
269
|
+
globalMax = 1;
|
|
270
|
+
} else if (globalMin === globalMax) {
|
|
271
|
+
globalMax = globalMin + 1;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Reset single-plot state so render-time dispatch on
|
|
275
|
+
// `_facets.length > 0` is unambiguous.
|
|
276
|
+
this._xLevels = [];
|
|
277
|
+
this._yLevels = [];
|
|
278
|
+
this._yColumnNames = [];
|
|
279
|
+
this._numX = 0;
|
|
280
|
+
this._numY = 0;
|
|
281
|
+
this._rowOffset = 0;
|
|
282
|
+
this._cells2D = [];
|
|
283
|
+
this._lastLayout = null;
|
|
284
|
+
this._xAxisMode = { mode: "category" };
|
|
285
|
+
this._yAxisMode = { mode: "category" };
|
|
286
|
+
this._xPositions = null;
|
|
287
|
+
this._yPositions = null;
|
|
288
|
+
this._xNumericDomain = null;
|
|
289
|
+
this._yNumericDomain = null;
|
|
290
|
+
this._xOrigin = 0;
|
|
291
|
+
this._yOrigin = 0;
|
|
292
|
+
|
|
293
|
+
this._facets = facets;
|
|
294
|
+
this._cells = allCells;
|
|
295
|
+
this._colorMin = globalMin;
|
|
296
|
+
this._colorMax = globalMax;
|
|
297
|
+
this._aggName = userColumns.join(", ");
|
|
298
|
+
} else {
|
|
299
|
+
const result = buildHeatmapPipeline({
|
|
300
|
+
columns,
|
|
301
|
+
numRows: endRow,
|
|
302
|
+
groupBy: this._groupBy,
|
|
303
|
+
splitBy: this._splitBy,
|
|
304
|
+
groupByTypes: this._groupByTypes,
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
this._facets = [];
|
|
308
|
+
this._facetGrid = null;
|
|
309
|
+
this._xLevels = result.xLevels;
|
|
310
|
+
this._yLevels = result.yLevels;
|
|
311
|
+
this._yColumnNames = result.yColumnNames;
|
|
312
|
+
this._numX = result.numX;
|
|
313
|
+
this._numY = result.numY;
|
|
314
|
+
this._rowOffset = result.rowOffset;
|
|
315
|
+
this._cells = result.cells;
|
|
316
|
+
this._cells2D = result.cells2D;
|
|
317
|
+
this._colorMin = result.colorMin;
|
|
318
|
+
this._colorMax = result.colorMax;
|
|
319
|
+
this._aggName = userColumns[0] ?? "Color";
|
|
320
|
+
this._xAxisMode = result.xAxisMode;
|
|
321
|
+
this._yAxisMode = result.yAxisMode;
|
|
322
|
+
this._xPositions = result.xPositions;
|
|
323
|
+
this._yPositions = result.yPositions;
|
|
324
|
+
this._xNumericDomain = result.xNumericDomain;
|
|
325
|
+
this._yNumericDomain = result.yNumericDomain;
|
|
326
|
+
this._xOrigin = result.xNumericDomain?.min ?? 0;
|
|
327
|
+
this._yOrigin = result.yNumericDomain?.min ?? 0;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
await this.requestRender(glManager);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
_fullRender(glManager: WebGLContextManager): void {
|
|
334
|
+
this._glManager = glManager;
|
|
335
|
+
const hasSingle = this._numX > 0 && this._numY > 0;
|
|
336
|
+
const hasFacets = this._facets.length > 0;
|
|
337
|
+
if (!hasSingle && !hasFacets) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
renderHeatmapFrame(this, glManager);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
protected destroyInternal(): void {
|
|
345
|
+
if (this._cornerBuffer && this._glManager) {
|
|
346
|
+
this._glManager.gl.deleteBuffer(this._cornerBuffer);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
this._program = null;
|
|
350
|
+
this._locations = null;
|
|
351
|
+
this._cornerBuffer = null;
|
|
352
|
+
this._xLevels = [];
|
|
353
|
+
this._yLevels = [];
|
|
354
|
+
this._yColumnNames = [];
|
|
355
|
+
this._cells = [];
|
|
356
|
+
this._cells2D = [];
|
|
357
|
+
this._hoveredCell = null;
|
|
358
|
+
this._facets = [];
|
|
359
|
+
this._facetGrid = null;
|
|
360
|
+
this._hoveredFacetIdx = -1;
|
|
361
|
+
this._xAxisMode = { mode: "category" };
|
|
362
|
+
this._yAxisMode = { mode: "category" };
|
|
363
|
+
this._xPositions = null;
|
|
364
|
+
this._yPositions = null;
|
|
365
|
+
this._xNumericDomain = null;
|
|
366
|
+
this._yNumericDomain = null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
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 { CartesianChart } from "../cartesian/cartesian";
|
|
14
|
+
import { PointGlyph } from "../cartesian/glyphs/points";
|
|
15
|
+
import { LineGlyph } from "../cartesian/glyphs/lines";
|
|
16
|
+
import { DensityGlyph } from "../cartesian/glyphs/density";
|
|
17
|
+
import type { Glyph } from "../cartesian/glyph";
|
|
18
|
+
import type { WebGLContextManager } from "../../webgl/context-manager";
|
|
19
|
+
import type { PlotLayout } from "../../layout/plot-layout";
|
|
20
|
+
import type { Theme } from "../../theme/theme";
|
|
21
|
+
import type { Canvas2D, Context2D } from "../canvas-types";
|
|
22
|
+
import type { ZoomConfig } from "../../interaction/zoom-controller";
|
|
23
|
+
import type { PluginConfig } from "../chart";
|
|
24
|
+
import { TileLayer } from "../../map/tile-layer";
|
|
25
|
+
import { tileSourceFor, type TileProviderId } from "../../map/tile-source";
|
|
26
|
+
import { lonLatToMercator } from "../../map/mercator";
|
|
27
|
+
import { getScaledContext } from "../../axis/canvas";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Map-mode base for cartesian charts. Reuses the entire cartesian
|
|
31
|
+
* pipeline (build, hit-test, zoom controller, lazy tooltips, faceting,
|
|
32
|
+
* theme, gradient texture) and swaps three behaviors:
|
|
33
|
+
*
|
|
34
|
+
* - `projectPoint(lon, lat)` Mercator-projects incoming columns so
|
|
35
|
+
* the rest of the pipeline operates in meter-space (linear
|
|
36
|
+
* projection matrix, screen-space splat radius, hit-test grid all
|
|
37
|
+
* "just work").
|
|
38
|
+
* - `_renderMode = "map"` flips the render-frame branches to skip
|
|
39
|
+
* cartesian gridlines and axes, insert a basemap layer before the
|
|
40
|
+
* glyph draw, and use the map-specific chrome (attribution).
|
|
41
|
+
* - `getZoomConfig()` returns `lockAspect: true` so wheel zoom keeps
|
|
42
|
+
* `dataPerPixel` uniform on both axes (required: Mercator
|
|
43
|
+
* preserves angle, glyphs distort otherwise).
|
|
44
|
+
*
|
|
45
|
+
* Concrete map plugin tags (`map-scatter`, `map-line`, `map-density`)
|
|
46
|
+
* pin a glyph in their nullary constructor exactly like the cartesian
|
|
47
|
+
* convenience subclasses.
|
|
48
|
+
*/
|
|
49
|
+
export class MapChart extends CartesianChart {
|
|
50
|
+
override _renderMode = "map" as const;
|
|
51
|
+
|
|
52
|
+
private _tileLayer: TileLayer;
|
|
53
|
+
|
|
54
|
+
constructor(glyph: Glyph) {
|
|
55
|
+
super(glyph);
|
|
56
|
+
this._tileLayer = new TileLayer();
|
|
57
|
+
this._tileLayer.setOnTileLoad(() => {
|
|
58
|
+
// Tile arrival schedules a fresh frame through the shared
|
|
59
|
+
// render scheduler; no-ops if a frame is already pending.
|
|
60
|
+
if (this._glManager) {
|
|
61
|
+
this.requestRender(this._glManager);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
override projectPoint(lon: number, lat: number): [number, number] {
|
|
67
|
+
return lonLatToMercator(lon, lat);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
protected override getZoomConfig(): ZoomConfig {
|
|
71
|
+
return { lockAspect: true };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
override setPluginConfig(cfg: PluginConfig): void {
|
|
75
|
+
super.setPluginConfig(cfg);
|
|
76
|
+
if (this._glManager) {
|
|
77
|
+
this._tileLayer.setSource(
|
|
78
|
+
this._glManager.gl,
|
|
79
|
+
tileSourceFor(cfg.map_tile_provider as TileProviderId),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this._tileLayer.setAlpha(cfg.map_tile_alpha);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
override renderBackground(
|
|
87
|
+
glManager: WebGLContextManager,
|
|
88
|
+
layout: PlotLayout,
|
|
89
|
+
projection: Float32Array,
|
|
90
|
+
domain: { xMin: number; xMax: number; yMin: number; yMax: number },
|
|
91
|
+
xOrigin: number,
|
|
92
|
+
yOrigin: number,
|
|
93
|
+
): void {
|
|
94
|
+
// Lazy source bind — `setPluginConfig` runs before
|
|
95
|
+
// `_glManager` is wired in some host bootstraps, so we
|
|
96
|
+
// re-attempt on first render if needed.
|
|
97
|
+
if (!this._tileLayer.source) {
|
|
98
|
+
this._tileLayer.setSource(
|
|
99
|
+
glManager.gl,
|
|
100
|
+
tileSourceFor(
|
|
101
|
+
this._pluginConfig.map_tile_provider as TileProviderId,
|
|
102
|
+
),
|
|
103
|
+
);
|
|
104
|
+
this._tileLayer.setAlpha(this._pluginConfig.map_tile_alpha);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this._tileLayer.render(
|
|
108
|
+
glManager,
|
|
109
|
+
layout,
|
|
110
|
+
projection,
|
|
111
|
+
domain,
|
|
112
|
+
xOrigin,
|
|
113
|
+
yOrigin,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
override renderMapChrome(
|
|
118
|
+
canvas: Canvas2D | null,
|
|
119
|
+
layout: PlotLayout,
|
|
120
|
+
theme: Theme,
|
|
121
|
+
dpr: number,
|
|
122
|
+
): void {
|
|
123
|
+
if (!canvas) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const ctx = getScaledContext(canvas, dpr) as Context2D | null;
|
|
128
|
+
if (!ctx) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const attribution = this._tileLayer.source?.attribution ?? "";
|
|
133
|
+
if (!attribution) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const plot = layout.plotRect;
|
|
138
|
+
ctx.save();
|
|
139
|
+
ctx.font = `10px ${theme.fontFamily}`;
|
|
140
|
+
ctx.textAlign = "right";
|
|
141
|
+
ctx.textBaseline = "bottom";
|
|
142
|
+
|
|
143
|
+
// Pill background so attribution stays legible over any tile.
|
|
144
|
+
const padding = 4;
|
|
145
|
+
const metrics = ctx.measureText(attribution);
|
|
146
|
+
const textW = metrics.width;
|
|
147
|
+
const textH = 12;
|
|
148
|
+
const x = plot.x + plot.width - 4;
|
|
149
|
+
const y = plot.y + plot.height - 4;
|
|
150
|
+
ctx.fillStyle = "rgba(255, 255, 255, 0.75)";
|
|
151
|
+
ctx.fillRect(
|
|
152
|
+
x - textW - padding * 2,
|
|
153
|
+
y - textH - padding,
|
|
154
|
+
textW + padding * 2,
|
|
155
|
+
textH + padding,
|
|
156
|
+
);
|
|
157
|
+
ctx.fillStyle = theme.labelColor;
|
|
158
|
+
ctx.fillText(attribution, x - padding, y - padding / 2);
|
|
159
|
+
ctx.restore();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
protected override destroyInternal(): void {
|
|
163
|
+
if (this._glManager) {
|
|
164
|
+
this._tileLayer.destroy(this._glManager.gl);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
super.destroyInternal();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Map Scatter — Mercator scatter on a raster basemap. Same glyph as
|
|
173
|
+
* `X/Y Scatter`; only projection and chrome differ.
|
|
174
|
+
*/
|
|
175
|
+
export class MapScatterChart extends MapChart {
|
|
176
|
+
constructor() {
|
|
177
|
+
super(new PointGlyph());
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Map Line — Mercator polyline on a raster basemap. Same glyph as
|
|
183
|
+
* `X/Y Line`.
|
|
184
|
+
*/
|
|
185
|
+
export class MapLineChart extends MapChart {
|
|
186
|
+
constructor() {
|
|
187
|
+
super(new LineGlyph());
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Map Density — Mercator KDE on a raster basemap. Same glyph as
|
|
193
|
+
* `Density`; the four `gradient_color_mode` variants
|
|
194
|
+
* (density/mean/extreme/signed) are all available on the map too
|
|
195
|
+
* because the glyph reads `_pluginConfig` directly.
|
|
196
|
+
*/
|
|
197
|
+
export class MapDensityChart extends MapChart {
|
|
198
|
+
constructor() {
|
|
199
|
+
super(new DensityGlyph());
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
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 { ScatterChart, LineChart, DensityChart } from "./cartesian/cartesian";
|
|
14
|
+
import { TreemapChart } from "./treemap/treemap";
|
|
15
|
+
import { SunburstChart } from "./sunburst/sunburst";
|
|
16
|
+
import { SeriesChart, XBarChart } from "./series/series";
|
|
17
|
+
import { HeatmapChart } from "./heatmap/heatmap";
|
|
18
|
+
import { CandlestickChart } from "./candlestick/candlestick";
|
|
19
|
+
import type { ChartImplementation } from "./chart";
|
|
20
|
+
|
|
21
|
+
type ChartImplCtor = new () => ChartImplementation;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Map from `ChartTypeConfig.tag` to a factory returning the chart-impl
|
|
25
|
+
* class. Consumed by `renderer.worker.ts` which `await`s the factory
|
|
26
|
+
* before constructing the impl.
|
|
27
|
+
*
|
|
28
|
+
* Eager chart types resolve immediately — `Promise.resolve(Class)` is
|
|
29
|
+
* a microtask, no I/O. Map plugins resolve via dynamic `import()` so
|
|
30
|
+
* the bundler emits the tile-rendering subsystem and the map-mode
|
|
31
|
+
* subclasses as a separate chunk; non-map users never fetch it.
|
|
32
|
+
*/
|
|
33
|
+
export const CHART_IMPLS: Record<string, () => Promise<ChartImplCtor>> = {
|
|
34
|
+
scatter: async () => ScatterChart,
|
|
35
|
+
line: async () => LineChart,
|
|
36
|
+
density: async () => DensityChart,
|
|
37
|
+
treemap: async () => TreemapChart,
|
|
38
|
+
sunburst: async () => SunburstChart,
|
|
39
|
+
heatmap: async () => HeatmapChart,
|
|
40
|
+
|
|
41
|
+
// All four Y-series plugins share BarChart; they differ only in the
|
|
42
|
+
// per-plugin default `chart_type` forwarded via `setDefaultChartType`
|
|
43
|
+
// during plugin setup.
|
|
44
|
+
"y-bar": async () => SeriesChart,
|
|
45
|
+
"y-line": async () => SeriesChart,
|
|
46
|
+
"y-scatter": async () => SeriesChart,
|
|
47
|
+
"y-area": async () => SeriesChart,
|
|
48
|
+
|
|
49
|
+
// X Bar is the horizontal orientation of the same chart class.
|
|
50
|
+
"x-bar": async () => XBarChart,
|
|
51
|
+
|
|
52
|
+
// Both candlestick-family plugins share one impl; the render path
|
|
53
|
+
// branches on `_defaultChartType` (set from `default_chart_type` in
|
|
54
|
+
// the plugin config) to pick the glyph.
|
|
55
|
+
candlestick: async () => CandlestickChart,
|
|
56
|
+
ohlc: async () => CandlestickChart,
|
|
57
|
+
|
|
58
|
+
// Map plugins. Dynamic-imported so the bundler splits the
|
|
59
|
+
// `map/*` (tile fetch, cache, layer, shaders) and `charts/map/*`
|
|
60
|
+
// (MapChart + subclasses) modules into a chunk that loads only
|
|
61
|
+
// when the user activates one of these tags.
|
|
62
|
+
"map-scatter": async () => (await import("./map/map")).MapScatterChart,
|
|
63
|
+
"map-line": async () => (await import("./map/map")).MapLineChart,
|
|
64
|
+
"map-density": async () => (await import("./map/map")).MapDensityChart,
|
|
65
|
+
};
|