@perspective-dev/viewer-charts 4.3.0 → 4.5.1
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/dist/cdn/perspective-viewer-charts.js +2 -2
- package/dist/cdn/perspective-viewer-charts.js.map +3 -3
- package/dist/esm/axis/bar-axis.d.ts +9 -1
- package/dist/esm/axis/categorical-axis.d.ts +0 -2
- package/dist/esm/charts/cartesian/cartesian.d.ts +26 -0
- package/dist/esm/charts/common/category-axis-resolver.d.ts +43 -1
- package/dist/esm/charts/common/expand-domain.d.ts +20 -0
- package/dist/esm/charts/common/tree-chart.d.ts +7 -0
- package/dist/esm/charts/common/tree-chrome.d.ts +23 -1
- package/dist/esm/charts/common/tree-interact.d.ts +46 -0
- package/dist/esm/charts/series/glyphs/draw-lines.d.ts +11 -4
- package/dist/esm/charts/series/series-build.d.ts +38 -2
- package/dist/esm/charts/series/series-render.d.ts +1 -4
- package/dist/esm/charts/series/series-type.d.ts +19 -17
- package/dist/esm/charts/series/series.d.ts +16 -0
- package/dist/esm/charts/sunburst/sunburst-interact.d.ts +1 -1
- package/dist/esm/charts/treemap/treemap-interact.d.ts +1 -6
- package/dist/esm/interaction/host-sink-message.d.ts +10 -28
- package/dist/esm/interaction/raw-event-forwarder.d.ts +6 -7
- package/dist/esm/interaction/zoom-controller.d.ts +31 -20
- package/dist/esm/interaction/zoom-router.d.ts +3 -26
- package/dist/esm/perspective-viewer-charts.js +2 -2
- package/dist/esm/perspective-viewer-charts.js.map +3 -3
- package/dist/esm/plugin/plugin.d.ts +0 -1
- package/dist/esm/theme/palette.d.ts +0 -5
- package/dist/esm/transport/protocol.d.ts +2 -7
- package/dist/esm/worker/renderer.worker.d.ts +2 -4
- package/package.json +1 -1
- package/src/ts/axis/bar-axis.ts +74 -45
- package/src/ts/axis/categorical-axis.ts +0 -2
- package/src/ts/charts/candlestick/candlestick-render.ts +10 -7
- package/src/ts/charts/candlestick/candlestick.ts +10 -29
- package/src/ts/charts/candlestick/glyphs/draw-candlesticks.ts +36 -2
- package/src/ts/charts/candlestick/glyphs/draw-ohlc.ts +36 -2
- package/src/ts/charts/cartesian/cartesian-build.ts +143 -9
- package/src/ts/charts/cartesian/cartesian-render.ts +205 -30
- package/src/ts/charts/cartesian/cartesian.ts +43 -4
- package/src/ts/charts/cartesian/glyphs/density.ts +36 -41
- package/src/ts/charts/cartesian/glyphs/lines.ts +13 -15
- package/src/ts/charts/cartesian/glyphs/points.ts +12 -17
- package/src/ts/charts/chart-base.ts +20 -6
- package/src/ts/charts/chart.ts +1 -1
- package/src/ts/charts/common/category-axis-resolver.ts +135 -1
- package/src/ts/charts/common/expand-domain.ts +40 -0
- package/src/ts/charts/common/tree-chart.ts +16 -0
- package/src/ts/charts/common/tree-chrome.ts +86 -1
- package/src/ts/charts/common/tree-interact.ts +209 -0
- package/src/ts/charts/heatmap/heatmap-render.ts +9 -11
- package/src/ts/charts/series/glyphs/draw-areas.ts +30 -1
- package/src/ts/charts/series/glyphs/draw-lines.ts +151 -76
- package/src/ts/charts/series/series-build.ts +394 -21
- package/src/ts/charts/series/series-render.ts +159 -38
- package/src/ts/charts/series/series-type.ts +37 -17
- package/src/ts/charts/series/series.ts +63 -68
- package/src/ts/charts/sunburst/sunburst-interact.ts +18 -162
- package/src/ts/charts/sunburst/sunburst-render.ts +24 -89
- package/src/ts/charts/sunburst/sunburst.ts +1 -15
- package/src/ts/charts/treemap/treemap-interact.ts +22 -189
- package/src/ts/charts/treemap/treemap-render.ts +19 -46
- package/src/ts/charts/treemap/treemap.ts +1 -16
- package/src/ts/interaction/host-sink-message.ts +33 -22
- package/src/ts/interaction/raw-event-forwarder.ts +10 -12
- package/src/ts/interaction/zoom-controller.ts +120 -83
- package/src/ts/interaction/zoom-router.ts +3 -126
- package/src/ts/map/tile-layer.ts +13 -13
- package/src/ts/plugin/plugin.ts +100 -184
- package/src/ts/shaders/line-uniform.frag.glsl +2 -1
- package/src/ts/shaders/line-uniform.vert.glsl +19 -0
- package/src/ts/theme/palette.ts +1 -4
- package/src/ts/transport/protocol.ts +3 -8
- package/src/ts/worker/dispatch.ts +0 -1
- package/src/ts/worker/renderer.worker.ts +10 -46
|
@@ -18,6 +18,14 @@ export type BarCategoryAxis = {
|
|
|
18
18
|
domain: AxisDomain;
|
|
19
19
|
ticks: number[];
|
|
20
20
|
};
|
|
21
|
+
export type BarValueAxis = {
|
|
22
|
+
mode: "category";
|
|
23
|
+
domain: CategoricalDomain;
|
|
24
|
+
} | {
|
|
25
|
+
mode: "numeric";
|
|
26
|
+
domain: AxisDomain;
|
|
27
|
+
ticks: number[];
|
|
28
|
+
};
|
|
21
29
|
/**
|
|
22
30
|
* Render a numeric date-aware axis along the bottom of the plot. Aliases
|
|
23
31
|
* the bar-axis bottom variant so heatmap can share the implementation.
|
|
@@ -42,7 +50,7 @@ export interface BarAxesFormatters {
|
|
|
42
50
|
/** Formatter for the numeric category axis (when `catAxis.mode === "numeric"`). */
|
|
43
51
|
category?: (v: number) => string;
|
|
44
52
|
}
|
|
45
|
-
export declare function renderBarAxesChrome(canvas: Canvas2D, catAxis: BarCategoryAxis,
|
|
53
|
+
export declare function renderBarAxesChrome(canvas: Canvas2D, catAxis: BarCategoryAxis, valueAxis: BarValueAxis, layout: PlotLayout, theme: Theme, dpr: number, altAxis: BarValueAxis | undefined, isHorizontal?: boolean, formatters?: BarAxesFormatters): void;
|
|
46
54
|
/**
|
|
47
55
|
* Render gridlines at the numeric axis ticks. In vertical bar charts
|
|
48
56
|
* the gridlines run horizontally at numeric Y ticks; in horizontal bar
|
|
@@ -16,8 +16,6 @@ interface LevelTickLayout {
|
|
|
16
16
|
size: number;
|
|
17
17
|
rotation: 0 | 45 | 90;
|
|
18
18
|
}
|
|
19
|
-
declare function categoryIndexToPixelX(layout: PlotLayout, index: number): number;
|
|
20
|
-
export declare const categoryIndexToPixel: typeof categoryIndexToPixelX;
|
|
21
19
|
export declare function measureCategoricalLevels(domain: CategoricalDomain, plotWidth: number): LevelTickLayout[];
|
|
22
20
|
export declare function measureCategoricalLevelWidths(domain: CategoricalDomain): number[];
|
|
23
21
|
export declare function measureCategoricalAxisHeight(domain: CategoricalDomain, plotWidth: number): number;
|
|
@@ -4,6 +4,7 @@ import { AbstractChart } from "../chart-base";
|
|
|
4
4
|
import { SpatialHitTester } from "../../interaction/hit-test";
|
|
5
5
|
import { PlotLayout } from "../../layout/plot-layout";
|
|
6
6
|
import { type AxisDomain } from "../../axis/numeric-axis";
|
|
7
|
+
import type { CategoricalDomain } from "../../axis/categorical-axis";
|
|
7
8
|
import type { GradientTextureCache } from "../../webgl/gradient-texture";
|
|
8
9
|
import type { Glyph } from "./glyph";
|
|
9
10
|
import type { LabelInterner } from "./label-interner";
|
|
@@ -93,6 +94,31 @@ export declare class CartesianChart extends AbstractChart {
|
|
|
93
94
|
_sizeName: string;
|
|
94
95
|
_labelName: string;
|
|
95
96
|
_colorIsString: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* When the X (or Y) axis source column is post-aggregation
|
|
99
|
+
* `string`-typed, the build pipeline writes per-row dictionary slot
|
|
100
|
+
* indices into `_xData` (or `_yData`) instead of numeric values,
|
|
101
|
+
* and the render pass dispatches `renderCategoricalXTicks` /
|
|
102
|
+
* `renderCategoricalYTicks` instead of the numeric axis painter.
|
|
103
|
+
*
|
|
104
|
+
* The companion `_xCategoryDictionary` / `_xCategorySeen` pair is
|
|
105
|
+
* built lazily during `processCartesianChunk` in first-seen row
|
|
106
|
+
* order; `(null)` is appended on first encounter of an invalid row
|
|
107
|
+
* rather than reserved at slot 0, so charts without missing values
|
|
108
|
+
* don't get a phantom slot.
|
|
109
|
+
*
|
|
110
|
+
* `_xCategoryDomain` is materialized once per frame in
|
|
111
|
+
* `cartesian-render` and held for chrome overlay redraws (same
|
|
112
|
+
* lifecycle as `_lastXDomain` on the numeric path).
|
|
113
|
+
*/
|
|
114
|
+
_xIsString: boolean;
|
|
115
|
+
_yIsString: boolean;
|
|
116
|
+
_xCategoryDictionary: string[];
|
|
117
|
+
_yCategoryDictionary: string[];
|
|
118
|
+
_xCategorySeen: Map<string, number>;
|
|
119
|
+
_yCategorySeen: Map<string, number>;
|
|
120
|
+
_xCategoryDomain: CategoricalDomain | null;
|
|
121
|
+
_yCategoryDomain: CategoricalDomain | null;
|
|
96
122
|
_splitGroups: SplitGroup[];
|
|
97
123
|
_xMin: number;
|
|
98
124
|
_xMax: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ColumnDataMap, ColumnData } from "../../data/view-reader";
|
|
2
|
-
import type { CategoricalLevel } from "../../axis/categorical-axis";
|
|
2
|
+
import type { CategoricalDomain, CategoricalLevel } from "../../axis/categorical-axis";
|
|
3
3
|
export interface CategoryAxisResult {
|
|
4
4
|
/**
|
|
5
5
|
* Fully materialized hierarchical levels — labels and group runs are
|
|
@@ -88,3 +88,45 @@ export declare function synthesizeStringLevel(rp: ColumnData, numRows: number, l
|
|
|
88
88
|
* from `rowPaths.length === 0`.
|
|
89
89
|
*/
|
|
90
90
|
export declare function resolveCategoryAxis(columns: ColumnDataMap, numRows: number, groupByLen: number, levelTypes?: string[]): CategoryAxisResult;
|
|
91
|
+
export interface ValueCategoryColumn {
|
|
92
|
+
/**
|
|
93
|
+
* Source aggregate column name; used only for the axis label fallback.
|
|
94
|
+
*/
|
|
95
|
+
name: string;
|
|
96
|
+
/**
|
|
97
|
+
* Post-aggregation perspective type string from `chart._columnTypes`
|
|
98
|
+
* (`"string"` is what triggers categorical mode).
|
|
99
|
+
*/
|
|
100
|
+
type: string;
|
|
101
|
+
/**
|
|
102
|
+
* The actual `ColumnData` from the view. May be undefined when the
|
|
103
|
+
* caller couldn't resolve the column (treated as all-null).
|
|
104
|
+
*/
|
|
105
|
+
data: ColumnData | undefined;
|
|
106
|
+
}
|
|
107
|
+
export interface ValueCategoryDomain {
|
|
108
|
+
/**
|
|
109
|
+
* Single-level `CategoricalDomain` shared across all input columns.
|
|
110
|
+
* `levels[0].labels` is the dictionary in slot order.
|
|
111
|
+
*/
|
|
112
|
+
domain: CategoricalDomain;
|
|
113
|
+
/**
|
|
114
|
+
* Per-column slot-index buffers. Length === `numCategories`.
|
|
115
|
+
* Indexed in the same order as the input `columns` array.
|
|
116
|
+
*/
|
|
117
|
+
perColumnSlots: Int32Array[];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Build a single shared categorical domain across one or more aggregate
|
|
121
|
+
* columns that land on the same axis side (primary or alt). Implements
|
|
122
|
+
* the "all-or-nothing per axis side" rule: returns `null` (= caller stays
|
|
123
|
+
* numeric) when any column is non-string; otherwise returns a single-
|
|
124
|
+
* level domain with the dictionary built in first-seen row order plus
|
|
125
|
+
* per-column slot indices the build pipeline writes into its pixel/slot
|
|
126
|
+
* buffer.
|
|
127
|
+
*
|
|
128
|
+
* Null / invalid rows surface as a `"(null)"` slot that's lazily added
|
|
129
|
+
* to the dictionary on first encounter — no reserved slot 0 when the
|
|
130
|
+
* data has no missing values.
|
|
131
|
+
*/
|
|
132
|
+
export declare function resolveValueCategoryDomain(columns: ValueCategoryColumn[], numRows: number, rowOffset: number, axisLabel: string): ValueCategoryDomain | null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Numeric extent — used by series + candlestick build pipelines for
|
|
3
|
+
* value / category axis domains.
|
|
4
|
+
*/
|
|
5
|
+
export interface Domain {
|
|
6
|
+
min: number;
|
|
7
|
+
max: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Union `next` (a freshly-computed extent) with `prev` (the prior
|
|
11
|
+
* accumulator) IN PLACE on `next`, then return a fresh copy to store
|
|
12
|
+
* back as the new accumulator. Idempotent when `prev` is null — `next`
|
|
13
|
+
* is left untouched.
|
|
14
|
+
*
|
|
15
|
+
* Used by the `domain_mode: "expand"` mirror-back step in the series /
|
|
16
|
+
* candlestick / cartesian build pipelines: mutating `next` in place
|
|
17
|
+
* means every downstream assignment that reads from the pipeline
|
|
18
|
+
* result struct automatically picks up the grown extent.
|
|
19
|
+
*/
|
|
20
|
+
export declare function expandDomainInPlace(prev: Domain | null, next: Domain): Domain;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { AbstractChart } from "../chart-base";
|
|
2
|
+
import type { ColumnDataMap } from "../../data/view-reader";
|
|
2
3
|
import { NodeStore } from "./node-store";
|
|
3
4
|
import { LazyTooltip } from "../../interaction/lazy-tooltip";
|
|
5
|
+
/**
|
|
6
|
+
* Sentinel fallback for the Size slot when the user hasn't picked one:
|
|
7
|
+
* use the first non-metadata column in the incoming view. Tree charts
|
|
8
|
+
* still need *some* numeric-ish column to size geometry.
|
|
9
|
+
*/
|
|
10
|
+
export declare function firstNonMetadataColumn(columns: ColumnDataMap): string;
|
|
4
11
|
/**
|
|
5
12
|
* Shared state for hierarchical charts (treemap, sunburst). Holds the
|
|
6
13
|
* tree store + streaming-insert scaffolding + per-row tooltip data
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type { Context2D } from "../canvas-types";
|
|
1
|
+
import type { Canvas2D, Context2D } from "../canvas-types";
|
|
2
|
+
import type { PlotRect } from "../../layout/plot-layout";
|
|
3
|
+
import type { GradientStop } from "../../theme/gradient";
|
|
4
|
+
import type { Vec3 } from "../../theme/palette";
|
|
5
|
+
import type { Theme } from "../../theme/theme";
|
|
2
6
|
import type { TreeChartBase } from "./tree-chart";
|
|
3
7
|
/**
|
|
4
8
|
* Click target for one breadcrumb segment. Tree-chart hit-testing
|
|
@@ -29,3 +33,21 @@ export declare function renderBreadcrumbs(chart: TreeChartBase & {
|
|
|
29
33
|
* (arc-mid) charts only differ in how they compute the anchor.
|
|
30
34
|
*/
|
|
31
35
|
export declare function renderTreeTooltip(chart: TreeChartBase, ctx: Context2D, nodeId: number, cx: number, cy: number, cssWidth: number, cssHeight: number, fontFamily: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Paint a color legend (categorical swatches or numeric gradient bar)
|
|
38
|
+
* for a tree chart. Shared by sunburst + treemap; both consult
|
|
39
|
+
* `_colorMode` / `_uniqueColorLabels.size` / `_colorMin..max` the same
|
|
40
|
+
* way.
|
|
41
|
+
*
|
|
42
|
+
* `categoricalRect`, when non-null, is used as the explicit rect for
|
|
43
|
+
* the categorical-swatch variant (sunburst's faceted mode passes
|
|
44
|
+
* `FacetGrid.legendRect` here). Numeric mode always derives from a
|
|
45
|
+
* synthetic single-plot `PlotLayout` to match the legacy per-chart
|
|
46
|
+
* branch — its gradient bar's vertical span doesn't fit the
|
|
47
|
+
* categorical legend's compact rect.
|
|
48
|
+
*
|
|
49
|
+
* Returns silently when the color slot is empty, when categorical mode
|
|
50
|
+
* has only one label, or when numeric mode has a degenerate
|
|
51
|
+
* (`min >= max`) extent.
|
|
52
|
+
*/
|
|
53
|
+
export declare function renderTreeColorLegend(chart: TreeChartBase, canvas: Canvas2D, palette: Vec3[], stops: GradientStop[], theme: Theme, cssWidth: number, cssHeight: number, categoricalRect?: PlotRect | null): void;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { TreeChartBase } from "./tree-chart";
|
|
2
|
+
/**
|
|
3
|
+
* Common subset of `TreemapChart` / `SunburstChart` reached by the
|
|
4
|
+
* shared interaction helpers — anything that lives on `TreeChartBase`
|
|
5
|
+
* plus the pinned/hover/facet-drill state the two charts both declare
|
|
6
|
+
* with identical shape but on the subclass (so we type it as an
|
|
7
|
+
* intersection).
|
|
8
|
+
*/
|
|
9
|
+
export type TreeInteractChart = TreeChartBase & {
|
|
10
|
+
_pinnedNodeId: number;
|
|
11
|
+
_hoveredNodeId: number;
|
|
12
|
+
_facetDrillRoots: Map<string, number>;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Emit `perspective-click` + `perspective-global-filter selected:true`
|
|
16
|
+
* for a treemap/sunburst node. The path is walked via `ancestorNames`
|
|
17
|
+
* and split into split-by prefix + group-by levels using
|
|
18
|
+
* `_splitBy.length` as the boundary; faceted mode keeps the depth-0
|
|
19
|
+
* ancestor as the split prefix.
|
|
20
|
+
*/
|
|
21
|
+
export declare function emitTreeNodeEvent(chart: TreeInteractChart, nodeId: number, kind: "leaf" | "branch"): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Build tooltip lines for `nodeId`: ancestor name path + aggregate
|
|
24
|
+
* value + (numeric) color value + per-row tooltip columns from
|
|
25
|
+
* `_lazyRows` for leaves. The leaf branch awaits the source-view row
|
|
26
|
+
* fetch; branch nodes have no underlying row so they emit a Children
|
|
27
|
+
* count instead.
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildTreeTooltipLines(chart: TreeInteractChart, nodeId: number): Promise<string[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Pin a tooltip at the chart-supplied anchor. Lines are fetched lazily;
|
|
32
|
+
* the `_pinnedNodeId` check on resolve discards stale results from a
|
|
33
|
+
* prior pin or dismissal.
|
|
34
|
+
*/
|
|
35
|
+
export declare function showTreePinnedTooltip(chart: TreeInteractChart, nodeId: number, anchor: {
|
|
36
|
+
cx: number;
|
|
37
|
+
cy: number;
|
|
38
|
+
}, renderChromeOverlay: () => void): void;
|
|
39
|
+
export declare function dismissTreePinnedTooltip(chart: TreeInteractChart): void;
|
|
40
|
+
/**
|
|
41
|
+
* Drill the clicked facet (or the whole chart in non-facet mode).
|
|
42
|
+
* Faceted drill walks up to the facet root (top-level child of
|
|
43
|
+
* `_rootId`), records the new drill node under that facet's label, and
|
|
44
|
+
* re-renders.
|
|
45
|
+
*/
|
|
46
|
+
export declare function treeDrillTo(chart: TreeInteractChart, nodeId: number, renderFrame: () => void): void;
|
|
@@ -19,14 +19,21 @@ export declare class LineGlyph {
|
|
|
19
19
|
* Rebuild the per-series GPU buffers for line glyphs. Called once
|
|
20
20
|
* per data load (and once after `restyle()` because palette colors
|
|
21
21
|
* are captured on the {@link LineSeriesEntry}). The buffer contents
|
|
22
|
-
* encode `[x,y]` points
|
|
23
|
-
* series. After this, every `draw` call rebinds +
|
|
24
|
-
* no further uploads until the next data load.
|
|
22
|
+
* encode `[x,y]` points for every cat in `[start, end]`; one
|
|
23
|
+
* `bufferData` per series. After this, every `draw` call rebinds +
|
|
24
|
+
* dispatches with no further uploads until the next data load.
|
|
25
|
+
*
|
|
26
|
+
* Gap behavior at synthesized cells is handled in the shader via
|
|
27
|
+
* `u_interp_alpha` (set per draw based on the series'
|
|
28
|
+
* `interpolateMode`): `skip` → 0 (invisible segments touching a
|
|
29
|
+
* synthesized endpoint), `solid` → 1, `transparent` → 0.5.
|
|
25
30
|
*/
|
|
26
31
|
rebuildBuffers(chart: SeriesChart, glManager: WebGLContextManager): void;
|
|
27
32
|
/**
|
|
28
33
|
* Bind the persistent vertex buffers and dispatch one instanced draw
|
|
29
|
-
* per
|
|
34
|
+
* per series. Skips hidden series via `_hiddenSeries`. Gap /
|
|
35
|
+
* transparency rendering is governed by `u_interp_alpha`, set per
|
|
36
|
+
* series.
|
|
30
37
|
*/
|
|
31
38
|
draw(chart: SeriesChart, gl: GL, glManager: WebGLContextManager, projLeft: Float32Array, projRight: Float32Array): void;
|
|
32
39
|
destroy(chart: SeriesChart): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ColumnDataMap } from "../../data/view-reader";
|
|
2
|
-
import type { CategoricalLevel } from "../../axis/categorical-axis";
|
|
2
|
+
import type { CategoricalDomain, CategoricalLevel } from "../../axis/categorical-axis";
|
|
3
3
|
import { type AxisMode, type NumericCategoryDomain } from "../common/category-axis-resolver";
|
|
4
|
-
import { type ChartType, type ColumnChartConfig } from "./series-type";
|
|
4
|
+
import { type ChartType, type ColumnChartConfig, type InterpolateMode } from "./series-type";
|
|
5
5
|
export interface SeriesInfo {
|
|
6
6
|
seriesId: number;
|
|
7
7
|
aggIdx: number;
|
|
@@ -13,6 +13,24 @@ export interface SeriesInfo {
|
|
|
13
13
|
axis: 0 | 1;
|
|
14
14
|
chartType: ChartType;
|
|
15
15
|
stack: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* First / last category index this series contributes data to, in
|
|
18
|
+
* the post-Pass-2 sample grid. For line+any mode and area+solid:
|
|
19
|
+
* every cell in `[start, end]` has a value (real or synthesized).
|
|
20
|
+
* For area+skip: `[start, end]` is the real-data extent; interior
|
|
21
|
+
* cells with `sampleValid=0` are gaps. `start = -1` (with `end = -1`)
|
|
22
|
+
* means the series has no real samples — downstream skips it.
|
|
23
|
+
*/
|
|
24
|
+
start: number;
|
|
25
|
+
end: number;
|
|
26
|
+
/**
|
|
27
|
+
* Resolved interpolation mode for this aggregate. The build
|
|
28
|
+
* pipeline reads it to decide whether Pass 2 runs for area
|
|
29
|
+
* (and which fills to apply); the line glyph reads it at draw
|
|
30
|
+
* time to set `u_interp_alpha`. Always one of the three modes;
|
|
31
|
+
* never the legacy boolean form.
|
|
32
|
+
*/
|
|
33
|
+
interpolateMode: InterpolateMode;
|
|
16
34
|
}
|
|
17
35
|
/**
|
|
18
36
|
* Logical bar/area record. Synthesized on demand from {@link BarColumns}
|
|
@@ -215,6 +233,24 @@ export interface SeriesPipelineResult {
|
|
|
215
233
|
max: number;
|
|
216
234
|
} | null;
|
|
217
235
|
hasRightAxis: boolean;
|
|
236
|
+
/**
|
|
237
|
+
* Per-axis-side value mode discriminator. `"category"` fires when
|
|
238
|
+
* every aggregate on that side is post-aggregation `string`-typed
|
|
239
|
+
* (all-or-nothing rule). Bar y0/y1 then hold dictionary slot
|
|
240
|
+
* indices and the chrome overlay paints a categorical axis on
|
|
241
|
+
* that side. `null` for the alt side when there are no series
|
|
242
|
+
* pinned to alt.
|
|
243
|
+
*/
|
|
244
|
+
leftValueAxisMode: "numeric" | "category";
|
|
245
|
+
rightValueAxisMode: "numeric" | "category" | null;
|
|
246
|
+
/**
|
|
247
|
+
* Single-level `CategoricalDomain` shared across every aggregate
|
|
248
|
+
* on the corresponding side. Set only when that side's mode is
|
|
249
|
+
* `"category"`; the chrome renderer in `series-render` materializes
|
|
250
|
+
* the side's `BarCategoryAxis` from this.
|
|
251
|
+
*/
|
|
252
|
+
leftValueCategoryDomain: CategoricalDomain | null;
|
|
253
|
+
rightValueCategoryDomain: CategoricalDomain | null;
|
|
218
254
|
}
|
|
219
255
|
/**
|
|
220
256
|
* Pure pipeline: turn a raw `ColumnDataMap` into (a) columnar stacked
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { WebGLContextManager } from "../../webgl/context-manager";
|
|
2
2
|
import { type SeriesChart } from "./series";
|
|
3
3
|
/**
|
|
4
|
-
* Upload bar instance buffers from the columnar `_bars` storage.
|
|
5
|
-
* to bar-typed records only (areas draw as triangle strips). Skips
|
|
6
|
-
* hidden series. Re-called from data-load and legend-toggle paths; the
|
|
7
|
-
* scratch buffers and `_visibleBarIndices` are reused across calls.
|
|
4
|
+
* Upload bar instance buffers from the columnar `_bars` storage.
|
|
8
5
|
*/
|
|
9
6
|
export declare function uploadBarInstances(chart: SeriesChart, glManager: WebGLContextManager): void;
|
|
10
7
|
/**
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export type ChartType = "bar" | "line" | "scatter" | "area";
|
|
2
2
|
/**
|
|
3
|
-
* Per-column
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
* Per-column interpolation mode for line / area glyphs.
|
|
4
|
+
*/
|
|
5
|
+
export type InterpolateMode = "skip" | "solid" | "transparent";
|
|
6
|
+
/**
|
|
7
|
+
* Per-column entry inside the viewer's `columns_config` map.
|
|
7
8
|
*/
|
|
8
9
|
export interface ColumnChartConfig {
|
|
9
10
|
/**
|
|
@@ -11,39 +12,40 @@ export interface ColumnChartConfig {
|
|
|
11
12
|
*/
|
|
12
13
|
chart_type?: string;
|
|
13
14
|
/**
|
|
14
|
-
* Explicit stack override.
|
|
15
|
-
* line / scatter do not.
|
|
15
|
+
* Explicit stack override.
|
|
16
16
|
*/
|
|
17
17
|
stack?: boolean;
|
|
18
18
|
/**
|
|
19
19
|
* Force this aggregate onto the secondary (right) Y axis,
|
|
20
20
|
* independent of `autoAltYAxis` and the dual-axis ratio
|
|
21
|
-
* heuristic.
|
|
22
|
-
* `autoAltYAxis` alone.
|
|
21
|
+
* heuristic.
|
|
23
22
|
*/
|
|
24
23
|
alt_axis?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Interpolation mode for line / area glyphs. See
|
|
26
|
+
* {@link InterpolateMode}. Legacy values `true` / `false` are also
|
|
27
|
+
* accepted by {@link resolveInterpolate} (mapped to `"solid"` /
|
|
28
|
+
* `"skip"`). Default `"skip"`. No effect on bar / scatter.
|
|
29
|
+
*/
|
|
30
|
+
interpolate?: InterpolateMode;
|
|
25
31
|
}
|
|
26
32
|
/**
|
|
27
33
|
* Resolve the render glyph for an aggregate base name. Lookup key is the
|
|
28
34
|
* *base* (e.g. `"Sales"`); composite arrow columns like `"North|Sales"`
|
|
29
35
|
* should strip the prefix before calling — the bar pipeline already
|
|
30
36
|
* tracks aggregates as base names, so call sites pass the base directly.
|
|
31
|
-
*
|
|
32
|
-
* `fallback` is the plugin's default glyph (e.g. `"line"` for Y Line),
|
|
33
|
-
* supplied by the plugin element via `setDefaultChartType`. Falls back to
|
|
34
|
-
* `"bar"` when the plugin never set one.
|
|
35
37
|
*/
|
|
36
38
|
export declare function resolveChartType(aggName: string, cfg: Record<string, ColumnChartConfig> | undefined, fallback?: ChartType): ChartType;
|
|
37
39
|
/**
|
|
38
40
|
* Resolve whether a series stacks with its aggregate siblings.
|
|
39
|
-
* Default: `true` for bar/area, `false` for line/scatter. Overridable
|
|
40
|
-
* per column via `columns_config[aggName].stack`.
|
|
41
41
|
*/
|
|
42
42
|
export declare function resolveStack(aggName: string, chartType: ChartType, cfg: Record<string, ColumnChartConfig> | undefined): boolean;
|
|
43
43
|
/**
|
|
44
44
|
* Resolve whether a column is pinned to the secondary Y axis via
|
|
45
|
-
* `columns_config[aggName].alt_axis`.
|
|
46
|
-
* when `true`, the per-column override forces axis 1 regardless of
|
|
47
|
-
* the auto-split heuristic.
|
|
45
|
+
* `columns_config[aggName].alt_axis`.
|
|
48
46
|
*/
|
|
49
47
|
export declare function resolveAltAxis(aggName: string, cfg: Record<string, ColumnChartConfig> | undefined): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the interpolation mode for this aggregate.
|
|
50
|
+
*/
|
|
51
|
+
export declare function resolveInterpolate(aggName: string, chartType: ChartType, cfg: Record<string, ColumnChartConfig> | undefined): InterpolateMode;
|
|
@@ -4,6 +4,7 @@ import type { ZoomConfig } from "../../interaction/zoom-controller";
|
|
|
4
4
|
import { CategoricalYChart } from "../common/categorical-y-chart";
|
|
5
5
|
import { type PlotRect } from "../../layout/plot-layout";
|
|
6
6
|
import { type AxisDomain } from "../../axis/numeric-axis";
|
|
7
|
+
import type { CategoricalDomain } from "../../axis/categorical-axis";
|
|
7
8
|
import { type SeriesChartRecord, type NumericCategoryDomain, type SeriesInfo, type BarColumns } from "./series-build";
|
|
8
9
|
import { LineGlyph } from "./glyphs/draw-lines";
|
|
9
10
|
import { ScatterGlyph } from "./glyphs/draw-scatter";
|
|
@@ -90,6 +91,21 @@ export declare class SeriesChart extends CategoricalYChart {
|
|
|
90
91
|
*/
|
|
91
92
|
_primaryValueLabel: string;
|
|
92
93
|
_altValueLabel: string;
|
|
94
|
+
/**
|
|
95
|
+
* Per-side value-axis mode. `"category"` fires when every
|
|
96
|
+
* aggregate on that side is post-aggregation `string`-typed
|
|
97
|
+
* (all-or-nothing rule, evaluated independently for primary and
|
|
98
|
+
* alt). When set, `_bars[].y0`/`y1` carry dictionary slot indices
|
|
99
|
+
* instead of numeric values, and the chrome overlay paints a
|
|
100
|
+
* categorical axis on that side.
|
|
101
|
+
*
|
|
102
|
+
* Read by `series-render.ts` to construct the `BarCategoryAxis`
|
|
103
|
+
* descriptor for the value-axis sides.
|
|
104
|
+
*/
|
|
105
|
+
_leftValueAxisMode: "numeric" | "category";
|
|
106
|
+
_rightValueAxisMode: "numeric" | "category" | null;
|
|
107
|
+
_leftValueCategoryDomain: CategoricalDomain | null;
|
|
108
|
+
_rightValueCategoryDomain: CategoricalDomain | null;
|
|
93
109
|
/**
|
|
94
110
|
* (seriesId * 1e9 + catIdx) → bar-record index in `_bars`. Built once
|
|
95
111
|
* per pipeline run for area-strip lookups; rebuilt on hidden-toggle
|
|
@@ -4,4 +4,4 @@ export declare function handleSunburstHover(chart: SunburstChart, mx: number, my
|
|
|
4
4
|
export declare function handleSunburstClick(chart: SunburstChart, mx: number, my: number): void;
|
|
5
5
|
export declare function showSunburstPinnedTooltip(chart: SunburstChart, nodeId: number): void;
|
|
6
6
|
export declare function dismissSunburstPinnedTooltip(chart: SunburstChart): void;
|
|
7
|
-
export
|
|
7
|
+
export { buildTreeTooltipLines as buildSunburstTooltipLines } from "../common/tree-interact";
|
|
@@ -4,9 +4,4 @@ export declare function handleTreemapClick(chart: TreemapChart, mx: number, my:
|
|
|
4
4
|
export declare function handleTreemapDblClick(chart: TreemapChart, mx: number, my: number): void;
|
|
5
5
|
export declare function showTreemapPinnedTooltip(chart: TreemapChart, nodeId: number): void;
|
|
6
6
|
export declare function dismissTreemapPinnedTooltip(chart: TreemapChart): void;
|
|
7
|
-
|
|
8
|
-
* Build the tooltip for `nodeId`. The node's own name path + aggregate
|
|
9
|
-
* value are derived from the tree; per-row tooltip columns come from
|
|
10
|
-
* the `leafRowIdx` → column-buffer lookup (no per-node `Map`).
|
|
11
|
-
*/
|
|
12
|
-
export declare function buildTreemapTooltipLines(chart: TreemapChart, nodeId: number): Promise<string[]>;
|
|
7
|
+
export { buildTreeTooltipLines as buildTreemapTooltipLines } from "../common/tree-interact";
|
|
@@ -1,36 +1,18 @@
|
|
|
1
|
+
import type { DismissTooltipMsg, PinTooltipMsg, SetCursorMsg, UserClickMsg, UserSelectMsg } from "../transport/protocol";
|
|
1
2
|
import type { CssBounds, HostSink, UserClickPayload, UserSelectPayload } from "./tooltip-controller";
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* The subset of `WorkerMsg`s that flow chart → host through a
|
|
5
|
+
* `MessageHostSink`. Identical to the worker-side post payloads so the
|
|
6
|
+
* sink can ship them straight to `WorkerRenderer.post` with no
|
|
7
|
+
* intermediate translation.
|
|
6
8
|
*/
|
|
7
|
-
export type HostSinkEnvelope =
|
|
8
|
-
kind: "pin";
|
|
9
|
-
payload: {
|
|
10
|
-
lines: string[];
|
|
11
|
-
pos: {
|
|
12
|
-
px: number;
|
|
13
|
-
py: number;
|
|
14
|
-
};
|
|
15
|
-
bounds: CssBounds;
|
|
16
|
-
};
|
|
17
|
-
} | {
|
|
18
|
-
kind: "dismiss";
|
|
19
|
-
} | {
|
|
20
|
-
kind: "setCursor";
|
|
21
|
-
cursor: string;
|
|
22
|
-
} | {
|
|
23
|
-
kind: "userClick";
|
|
24
|
-
payload: UserClickPayload;
|
|
25
|
-
} | {
|
|
26
|
-
kind: "userSelect";
|
|
27
|
-
payload: UserSelectPayload;
|
|
28
|
-
};
|
|
9
|
+
export type HostSinkEnvelope = PinTooltipMsg | DismissTooltipMsg | SetCursorMsg | UserClickMsg | UserSelectMsg;
|
|
29
10
|
/**
|
|
30
11
|
* `HostSink` that posts pin / dismiss / setCursor / user-event intents
|
|
31
|
-
* over a `postMessage`-style channel. The host-side
|
|
32
|
-
* for these
|
|
33
|
-
* dispatches `CustomEvent`s on the viewer for user
|
|
12
|
+
* over a `postMessage`-style channel as `WorkerMsg`s. The host-side
|
|
13
|
+
* transport listens for these and drives a `DomHostSink` for
|
|
14
|
+
* pin/dismiss and dispatches `CustomEvent`s on the viewer for user
|
|
15
|
+
* events.
|
|
34
16
|
*/
|
|
35
17
|
export declare class MessageHostSink implements HostSink {
|
|
36
18
|
private _send;
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import type { InteractionEvent } from "../transport/protocol";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Renderer
|
|
7
|
-
*
|
|
8
|
-
* logic — see `applyWheel` / `applyPan` in `zoom-router.ts`.
|
|
3
|
+
* Captures wheel / pointer events on the GL canvas, normalizes coords
|
|
4
|
+
* to canvas-relative CSS pixels, and emits semantic
|
|
5
|
+
* {@link InteractionEvent}s to the Renderer over its transport. The
|
|
6
|
+
* Renderer owns the `ZoomController`s and runs the actual hit-test +
|
|
7
|
+
* apply logic — see `applyWheel` / `applyPan` in `zoom-router.ts`.
|
|
9
8
|
*
|
|
10
9
|
* Pointer capture is set on `pointerdown` and released on `pointerup`
|
|
11
10
|
* so drags continue to deliver `pointermove` events when the cursor
|
|
12
|
-
* leaves the canvas
|
|
11
|
+
* leaves the canvas.
|
|
13
12
|
*/
|
|
14
13
|
export declare class RawEventForwarder {
|
|
15
14
|
private _element;
|
|
@@ -37,6 +37,8 @@ export declare class ZoomController {
|
|
|
37
37
|
private _baseYMax;
|
|
38
38
|
private _lockAxis;
|
|
39
39
|
private _lockAspect;
|
|
40
|
+
private _xPinned;
|
|
41
|
+
private _yPinned;
|
|
40
42
|
private _element;
|
|
41
43
|
private _layout;
|
|
42
44
|
private _onUpdate;
|
|
@@ -59,30 +61,37 @@ export declare class ZoomController {
|
|
|
59
61
|
get baseXRange(): number;
|
|
60
62
|
get baseYRange(): number;
|
|
61
63
|
/**
|
|
62
|
-
* Update the base (full-data) domain
|
|
63
|
-
*
|
|
64
|
-
* the *absolute* center of any user-applied pan.
|
|
64
|
+
* Update the base (full-data) domain. Each axis is handled
|
|
65
|
+
* independently:
|
|
65
66
|
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
67
|
+
* - If the axis is at default (no user pan or zoom on this axis),
|
|
68
|
+
* just swap the new base in — no further math needed.
|
|
69
|
+
* - If the axis has been explicitly *pinned* (`pinAxis("x" | "y")`),
|
|
70
|
+
* preserve its *absolute* visible center across the swap:
|
|
71
|
+
* re-solve `_normT` so the data-space center is unchanged.
|
|
72
|
+
* This is paused-frame-review semantics — the user has marked a
|
|
73
|
+
* region of interest and wants it to stay put even as new data
|
|
74
|
+
* flows in. No current caller pins, but the API is here so the
|
|
75
|
+
* default rule below doesn't bake the choice in.
|
|
76
|
+
* - Otherwise (the default — "follow"): keep `_normT` as-is and
|
|
77
|
+
* just swap the new base. The visible window's *fractional*
|
|
78
|
+
* position is preserved, so sliding windows slide with the data
|
|
79
|
+
* and extending windows grow proportionally with the data.
|
|
77
80
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* the same absolute (data-coordinate) position before and after
|
|
83
|
-
* the swap.
|
|
81
|
+
* Per-axis handling matters because `_scaleX/_normTX` and
|
|
82
|
+
* `_scaleY/_normTY` are independent. A user who panned X to scroll
|
|
83
|
+
* through time should not force Y onto the rebase path — Y data
|
|
84
|
+
* updates should still flow through cleanly.
|
|
84
85
|
*/
|
|
85
86
|
setBaseDomain(xMin: number, xMax: number, yMin: number, yMax: number): void;
|
|
87
|
+
/**
|
|
88
|
+
* Mark an axis as "pinned" so subsequent `setBaseDomain` calls
|
|
89
|
+
* preserve its *absolute* visible center (paused-frame-review
|
|
90
|
+
* semantics). Default-cleared on construction; both axes follow
|
|
91
|
+
* data growth fractionally until explicitly pinned.
|
|
92
|
+
*/
|
|
93
|
+
pinAxis(axis: "x" | "y"): void;
|
|
94
|
+
unpinAxis(axis: "x" | "y"): void;
|
|
86
95
|
/**
|
|
87
96
|
* Apply config. Called once by the chart during `setZoomController`.
|
|
88
97
|
* Locking an axis snaps its `scale`/`translate` to identity so any
|
|
@@ -90,6 +99,8 @@ export declare class ZoomController {
|
|
|
90
99
|
* pan events leave the locked axis alone.
|
|
91
100
|
*/
|
|
92
101
|
configure(config: ZoomConfig): void;
|
|
102
|
+
isXDefault(): boolean;
|
|
103
|
+
isYDefault(): boolean;
|
|
93
104
|
isDefault(): boolean;
|
|
94
105
|
getVisibleDomain(): {
|
|
95
106
|
xMin: number;
|