@perspective-dev/viewer-charts 5.2.0 → 5.3.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 +1 -2
- package/dist/cdn/perspective-viewer-charts.js.map +4 -4
- package/dist/esm/axis/legend.d.ts +53 -5
- package/dist/esm/axis/map-ticks.d.ts +15 -0
- package/dist/esm/charts/candlestick/candlestick-interact.d.ts +2 -6
- package/dist/esm/charts/candlestick/candlestick-render.d.ts +3 -0
- package/dist/esm/charts/cartesian/cartesian.d.ts +7 -0
- package/dist/esm/charts/cartesian/glyph.d.ts +2 -1
- package/dist/esm/charts/cartesian/glyphs/density.d.ts +2 -1
- package/dist/esm/charts/cartesian/glyphs/lines.d.ts +2 -1
- package/dist/esm/charts/cartesian/glyphs/points.d.ts +2 -1
- package/dist/esm/charts/cartesian/tooltip-lines.d.ts +1 -1
- package/dist/esm/charts/chart-base.d.ts +24 -9
- package/dist/esm/charts/chart.d.ts +81 -6
- package/dist/esm/charts/common/category-axis-resolver.d.ts +1 -1
- package/dist/esm/charts/common/draw-tooltip-box.d.ts +2 -1
- package/dist/esm/charts/common/tree-chart.d.ts +1 -0
- package/dist/esm/charts/common/tree-interact.d.ts +1 -1
- package/dist/esm/charts/heatmap/heatmap.d.ts +1 -0
- package/dist/esm/charts/series/series-build.d.ts +7 -0
- package/dist/esm/charts/series/series-interact.d.ts +1 -1
- package/dist/esm/charts/series/series-type.d.ts +18 -0
- package/dist/esm/charts/series/series.d.ts +10 -1
- package/dist/esm/charts/sunburst/sunburst-render.d.ts +4 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/interaction/axis-indicators.d.ts +11 -0
- package/dist/esm/interaction/host-sink-dom.d.ts +3 -2
- package/dist/esm/interaction/host-sink-message.d.ts +3 -2
- package/dist/esm/interaction/lazy-tooltip.d.ts +2 -2
- package/dist/esm/interaction/legend-controller.d.ts +246 -0
- package/dist/esm/interaction/tooltip-controller.d.ts +20 -95
- package/dist/esm/interaction/tooltip-grid.d.ts +33 -0
- package/dist/esm/layout/facet-grid.d.ts +6 -0
- package/dist/esm/layout/ticks.d.ts +1 -0
- package/dist/esm/map/tile-source.d.ts +77 -8
- package/dist/esm/perspective-viewer-charts.js +1 -2
- package/dist/esm/perspective-viewer-charts.js.map +4 -4
- package/dist/esm/plugin/charts.d.ts +2 -0
- package/dist/esm/plugin/format-defaults.d.ts +9 -0
- package/dist/esm/plugin/plugin.d.ts +28 -1
- package/dist/esm/theme/gradient.d.ts +32 -0
- package/dist/esm/theme/overrides.d.ts +19 -0
- package/dist/esm/transport/protocol.d.ts +58 -5
- package/dist/esm/transport/renderer-transport.d.ts +3 -0
- package/dist/esm/utils/css.d.ts +4 -0
- package/dist/esm/worker/renderer.worker.d.ts +46 -1
- package/package.json +1 -1
- package/src/css/perspective-viewer-charts.css +0 -1
- package/src/ts/axis/bar-axis.ts +2 -7
- package/src/ts/axis/legend.ts +351 -24
- package/src/ts/axis/map-ticks.ts +94 -0
- package/src/ts/axis/numeric-axis.ts +2 -9
- package/src/ts/charts/candlestick/candlestick-build.ts +1 -0
- package/src/ts/charts/candlestick/candlestick-interact.ts +46 -40
- package/src/ts/charts/candlestick/candlestick-render.ts +81 -10
- package/src/ts/charts/candlestick/candlestick.ts +4 -3
- package/src/ts/charts/cartesian/cartesian-interact.ts +9 -3
- package/src/ts/charts/cartesian/cartesian-render.ts +374 -75
- package/src/ts/charts/cartesian/cartesian.ts +13 -0
- package/src/ts/charts/cartesian/glyph.ts +6 -2
- package/src/ts/charts/cartesian/glyphs/density.ts +2 -2
- package/src/ts/charts/cartesian/glyphs/lines.ts +15 -11
- package/src/ts/charts/cartesian/glyphs/points.ts +9 -5
- package/src/ts/charts/cartesian/tooltip-lines.ts +8 -8
- package/src/ts/charts/chart-base.ts +76 -42
- package/src/ts/charts/chart.ts +111 -7
- package/src/ts/charts/common/category-axis-resolver.ts +44 -5
- package/src/ts/charts/common/draw-tooltip-box.ts +13 -30
- package/src/ts/charts/common/tree-chart.ts +4 -0
- package/src/ts/charts/common/tree-chrome.ts +102 -23
- package/src/ts/charts/common/tree-interact.ts +18 -17
- package/src/ts/charts/heatmap/heatmap-build.ts +7 -1
- package/src/ts/charts/heatmap/heatmap-interact.ts +75 -8
- package/src/ts/charts/heatmap/heatmap-render.ts +105 -24
- package/src/ts/charts/heatmap/heatmap.ts +8 -3
- package/src/ts/charts/map/map.ts +3 -5
- package/src/ts/charts/series/series-build.ts +15 -2
- package/src/ts/charts/series/series-interact.ts +14 -24
- package/src/ts/charts/series/series-render.ts +310 -132
- package/src/ts/charts/series/series-type.ts +65 -0
- package/src/ts/charts/series/series.ts +31 -8
- package/src/ts/charts/sunburst/sunburst-render.ts +16 -1
- package/src/ts/charts/treemap/treemap-render.ts +12 -1
- package/src/ts/data/view-reader.ts +1 -4
- package/src/ts/index.ts +2 -0
- package/src/ts/interaction/axis-indicators.ts +137 -0
- package/src/ts/interaction/host-sink-dom.ts +66 -2
- package/src/ts/interaction/host-sink-message.ts +8 -2
- package/src/ts/interaction/lazy-tooltip.ts +5 -5
- package/src/ts/interaction/legend-controller.ts +1084 -0
- package/src/ts/interaction/tooltip-controller.ts +43 -131
- package/src/ts/interaction/tooltip-grid.ts +187 -0
- package/src/ts/layout/facet-grid.ts +8 -1
- package/src/ts/layout/ticks.ts +48 -12
- package/src/ts/map/tile-loader.ts +16 -1
- package/src/ts/map/tile-source.ts +199 -53
- package/src/ts/map/tile-sources.json +18 -0
- package/src/ts/plugin/charts.ts +40 -6
- package/src/ts/plugin/format-defaults.ts +37 -0
- package/src/ts/plugin/plugin.ts +330 -76
- package/src/ts/shaders/line.vert.glsl +5 -2
- package/src/ts/shaders/scatter.vert.glsl +0 -7
- package/src/ts/theme/gradient.ts +265 -1
- package/src/ts/theme/overrides.ts +76 -0
- package/src/ts/transport/protocol.ts +60 -4
- package/src/ts/transport/renderer-transport.ts +107 -14
- package/src/ts/utils/css.ts +12 -0
- package/src/ts/worker/dispatch.ts +6 -2
- package/src/ts/worker/renderer.worker.ts +191 -7
|
@@ -1,7 +1,55 @@
|
|
|
1
|
-
import type { Canvas2D } from "../charts/canvas-types";
|
|
1
|
+
import type { Canvas2D, Context2D } from "../charts/canvas-types";
|
|
2
2
|
import type { PlotLayout, PlotRect } from "../layout/plot-layout";
|
|
3
|
+
import { LEGEND_LINE_HEIGHT, type LegendAutoFit, type LegendController } from "../interaction/legend-controller";
|
|
3
4
|
import { type GradientStop } from "../theme/gradient";
|
|
4
5
|
import type { Theme } from "../theme/theme";
|
|
6
|
+
export { LEGEND_LINE_HEIGHT };
|
|
7
|
+
/**
|
|
8
|
+
* Presentation context threaded into every legend painter. Carries the
|
|
9
|
+
* resolved `legend_mode` branch and the chart's {@link LegendController}
|
|
10
|
+
* — the painter reads its scroll offset and reports the painted
|
|
11
|
+
* geometry back so hit-testing always resolves against what is on
|
|
12
|
+
* screen. `"none"` mode never reaches a painter (call sites skip and
|
|
13
|
+
* `clearPainted()` instead).
|
|
14
|
+
*/
|
|
15
|
+
export interface LegendPaintView {
|
|
16
|
+
mode: "sidebar" | "floating";
|
|
17
|
+
legend: LegendController;
|
|
18
|
+
title?: string;
|
|
19
|
+
sidebarGutter?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Floating background-fill opacity (`plugin_config.legend_opacity`,
|
|
22
|
+
* default 1). Border, header text, and entries stay opaque.
|
|
23
|
+
*/
|
|
24
|
+
opacity?: number;
|
|
25
|
+
}
|
|
26
|
+
export declare function legendAutoFit(canvas: Canvas2D | null | undefined, theme: Theme, entryCount: number, labels: () => Iterable<string>, opts?: {
|
|
27
|
+
title?: string;
|
|
28
|
+
leading?: number;
|
|
29
|
+
fontPx?: number;
|
|
30
|
+
}): LegendAutoFit;
|
|
31
|
+
export declare function gradientLegendAutoFit(canvas: Canvas2D | null | undefined, theme: Theme, colorDomain: {
|
|
32
|
+
min: number;
|
|
33
|
+
max: number;
|
|
34
|
+
}, formatter?: (v: number) => string, title?: string): LegendAutoFit;
|
|
35
|
+
/**
|
|
36
|
+
* Paint the floating panel's chrome — themed background, border, and
|
|
37
|
+
* header strip — and return the content rect inside it. The header
|
|
38
|
+
* carries `title` and doubles as the move grip. `opacity` applies to
|
|
39
|
+
* the background fill only.
|
|
40
|
+
*/
|
|
41
|
+
export declare function paintFloatingLegendFrame(ctx: Context2D, box: PlotRect, theme: Theme, title: string | undefined, opacity?: number): PlotRect;
|
|
42
|
+
/**
|
|
43
|
+
* Paint the scroll thumb on the content rect's right edge. No-op when
|
|
44
|
+
* the content fits.
|
|
45
|
+
*/
|
|
46
|
+
export declare function paintLegendScrollbar(ctx: Context2D, content: PlotRect, scroll: number, contentHeight: number, theme: Theme): void;
|
|
47
|
+
/**
|
|
48
|
+
* Clip `text` to `maxWidth` with a trailing ellipsis. Only called for
|
|
49
|
+
* entries inside the visible window, so the `measureText` cost is
|
|
50
|
+
* bounded by the box height, not the entry count.
|
|
51
|
+
*/
|
|
52
|
+
export declare function truncateText(ctx: Context2D, text: string, maxWidth: number): string;
|
|
5
53
|
/**
|
|
6
54
|
* Render a vertical color gradient legend on the Canvas2D overlay.
|
|
7
55
|
* Only call when a color column is active. When `colorDomain` crosses
|
|
@@ -15,7 +63,7 @@ export declare function renderLegend(canvas: Canvas2D, layout: PlotLayout, color
|
|
|
15
63
|
min: number;
|
|
16
64
|
max: number;
|
|
17
65
|
label: string;
|
|
18
|
-
}, stops: GradientStop[], theme: Theme, formatter?: (v: number) => string): void;
|
|
66
|
+
}, stops: GradientStop[], theme: Theme, formatter?: (v: number) => string, view?: LegendPaintView): void;
|
|
19
67
|
/**
|
|
20
68
|
* Render a gradient legend at an explicit canvas-absolute rect.
|
|
21
69
|
* Used by facet grids that paint one legend for the whole grid and
|
|
@@ -25,7 +73,7 @@ export declare function renderLegendAt(canvas: Canvas2D, rect: PlotRect, colorDo
|
|
|
25
73
|
min: number;
|
|
26
74
|
max: number;
|
|
27
75
|
label: string;
|
|
28
|
-
}, stops: GradientStop[], theme: Theme, formatter?: (v: number) => string): void;
|
|
76
|
+
}, stops: GradientStop[], theme: Theme, formatter?: (v: number) => string, view?: LegendPaintView): void;
|
|
29
77
|
/**
|
|
30
78
|
* Render a categorical legend with discrete colored swatches.
|
|
31
79
|
* Used when split_by or string color columns produce distinct categories.
|
|
@@ -35,10 +83,10 @@ export declare function renderLegendAt(canvas: Canvas2D, rect: PlotRect, colorDo
|
|
|
35
83
|
* shared legend pass an explicit rect to `renderCategoricalLegendAt`
|
|
36
84
|
* directly.
|
|
37
85
|
*/
|
|
38
|
-
export declare function renderCategoricalLegend(canvas: Canvas2D, layout: PlotLayout, labels: Map<string, number>, palette: [number, number, number][], theme: Theme): void;
|
|
86
|
+
export declare function renderCategoricalLegend(canvas: Canvas2D, layout: PlotLayout, labels: Map<string, number>, palette: [number, number, number][], theme: Theme, view?: LegendPaintView): void;
|
|
39
87
|
/**
|
|
40
88
|
* Render a categorical legend at an explicit canvas-absolute rect.
|
|
41
89
|
* Used by facet grids that paint one legend for the whole grid and by
|
|
42
90
|
* single-plot charts through {@link renderCategoricalLegend}.
|
|
43
91
|
*/
|
|
44
|
-
export declare function renderCategoricalLegendAt(canvas: Canvas2D, rect: PlotRect, labels: Map<string, number>, palette: [number, number, number][], theme: Theme): void;
|
|
92
|
+
export declare function renderCategoricalLegendAt(canvas: Canvas2D, rect: PlotRect, labels: Map<string, number>, palette: [number, number, number][], theme: Theme, view?: LegendPaintView): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PlotLayout } from "../layout/plot-layout";
|
|
2
|
+
export interface MapDegreeTicks {
|
|
3
|
+
xTicks: number[];
|
|
4
|
+
yTicks: number[];
|
|
5
|
+
formatX: (meters: number) => string;
|
|
6
|
+
formatY: (meters: number) => string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Compute "nice" longitude/latitude ticks for the visible window of a
|
|
10
|
+
* map layout. Must be called AFTER `buildProjectionMatrix` has seeded
|
|
11
|
+
* the layout's padded-domain fields — the ticks are derived from the
|
|
12
|
+
* exact meter domain the projection maps, or labels would misalign
|
|
13
|
+
* with glyphs.
|
|
14
|
+
*/
|
|
15
|
+
export declare function computeMapDegreeTicks(layout: PlotLayout): MapDegreeTicks;
|
|
@@ -2,9 +2,5 @@ import type { CandlestickChart } from "./candlestick";
|
|
|
2
2
|
export declare function handleCandlestickHover(chart: CandlestickChart, mx: number, my: number): void;
|
|
3
3
|
export declare function showCandlestickPinnedTooltip(chart: CandlestickChart, idx: number): void;
|
|
4
4
|
export declare function dismissCandlestickPinnedTooltip(chart: CandlestickChart): void;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* storage. Indexed access avoids materializing a `CandleRecord` POJO
|
|
8
|
-
* on the hot tooltip path.
|
|
9
|
-
*/
|
|
10
|
-
export declare function buildCandlestickTooltipLines(chart: CandlestickChart, idx: number): string[];
|
|
5
|
+
export declare function buildCandlestickTooltipLines(chart: CandlestickChart, idx: number): string[][];
|
|
6
|
+
export declare function candleCategoryText(chart: CandlestickChart, catIdx: number): string;
|
|
@@ -21,4 +21,7 @@ export declare function invalidateGlyphBuffers(chart: CandlestickChart): void;
|
|
|
21
21
|
*/
|
|
22
22
|
export declare function rebuildGlyphBuffers(chart: CandlestickChart, glManager: WebGLContextManager): void;
|
|
23
23
|
export declare function renderCandlestickFrame(chart: CandlestickChart, glManager: WebGLContextManager): void;
|
|
24
|
+
/**
|
|
25
|
+
* Draw axes chrome + (optional) tooltip onto the overlay canvas.
|
|
26
|
+
*/
|
|
24
27
|
export declare function renderCandlestickChromeOverlay(chart: CandlestickChart): void;
|
|
@@ -29,6 +29,13 @@ export interface SplitGroup {
|
|
|
29
29
|
export declare class CartesianChart extends AbstractChart {
|
|
30
30
|
readonly glyph: Glyph;
|
|
31
31
|
constructor(glyph: Glyph);
|
|
32
|
+
protected colorScaleColumn(): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Chrome-only repaint for legend scroll / floating-legend drag —
|
|
35
|
+
* the same lightweight path hover updates use. No GL pass; the
|
|
36
|
+
* composite re-presents over the retained plot bitmap.
|
|
37
|
+
*/
|
|
38
|
+
repaintChrome(): void;
|
|
32
39
|
/**
|
|
33
40
|
* Rendering pipeline selector. `"cartesian"` is the default —
|
|
34
41
|
* draws axes, gridlines, and ticks via the chrome canvas.
|
|
@@ -38,13 +38,14 @@ export interface Glyph {
|
|
|
38
38
|
* Glyphs whose tooltip is geometry-only (e.g. `LineGlyph`) return
|
|
39
39
|
* a microtask-resolved promise.
|
|
40
40
|
*/
|
|
41
|
-
buildTooltipLines(chart: CartesianChart, flatIdx: number): Promise<string[]>;
|
|
41
|
+
buildTooltipLines(chart: CartesianChart, flatIdx: number): Promise<string[][]>;
|
|
42
42
|
/**
|
|
43
43
|
* Hover-overlay options (crosshair, highlight radius).
|
|
44
44
|
*/
|
|
45
45
|
tooltipOptions(): {
|
|
46
46
|
crosshair: boolean;
|
|
47
47
|
highlightRadius: number;
|
|
48
|
+
axisIndicators: boolean;
|
|
48
49
|
};
|
|
49
50
|
/**
|
|
50
51
|
* Release GL resources created by `ensureProgram`.
|
|
@@ -26,10 +26,11 @@ export declare class DensityGlyph implements Glyph {
|
|
|
26
26
|
ensureProgram(chart: CartesianChart, glManager: WebGLContextManager): void;
|
|
27
27
|
draw(chart: CartesianChart, glManager: WebGLContextManager, projection: Float32Array): void;
|
|
28
28
|
drawSeries(chart: CartesianChart, glManager: WebGLContextManager, projection: Float32Array, seriesIdx: number): void;
|
|
29
|
-
buildTooltipLines(chart: CartesianChart, flatIdx: number): Promise<string[]>;
|
|
29
|
+
buildTooltipLines(chart: CartesianChart, flatIdx: number): Promise<string[][]>;
|
|
30
30
|
tooltipOptions(): {
|
|
31
31
|
crosshair: boolean;
|
|
32
32
|
highlightRadius: number;
|
|
33
|
+
axisIndicators: boolean;
|
|
33
34
|
};
|
|
34
35
|
destroy(chart: CartesianChart): void;
|
|
35
36
|
/**
|
|
@@ -14,10 +14,11 @@ export declare class LineGlyph implements Glyph {
|
|
|
14
14
|
ensureProgram(_chart: CartesianChart, glManager: WebGLContextManager): void;
|
|
15
15
|
draw(chart: CartesianChart, glManager: WebGLContextManager, projection: Float32Array): void;
|
|
16
16
|
drawSeries(chart: CartesianChart, glManager: WebGLContextManager, projection: Float32Array, seriesIdx: number): void;
|
|
17
|
-
buildTooltipLines(chart: CartesianChart, flatIdx: number): Promise<string[]>;
|
|
17
|
+
buildTooltipLines(chart: CartesianChart, flatIdx: number): Promise<string[][]>;
|
|
18
18
|
tooltipOptions(): {
|
|
19
19
|
crosshair: boolean;
|
|
20
20
|
highlightRadius: number;
|
|
21
|
+
axisIndicators: boolean;
|
|
21
22
|
};
|
|
22
23
|
destroy(chart: CartesianChart): void;
|
|
23
24
|
}
|
|
@@ -15,10 +15,11 @@ export declare class PointGlyph implements Glyph {
|
|
|
15
15
|
ensureProgram(_chart: CartesianChart, glManager: WebGLContextManager): void;
|
|
16
16
|
draw(chart: CartesianChart, glManager: WebGLContextManager, projection: Float32Array): void;
|
|
17
17
|
drawSeries(chart: CartesianChart, glManager: WebGLContextManager, projection: Float32Array, seriesIdx: number): void;
|
|
18
|
-
buildTooltipLines(chart: CartesianChart, flatIdx: number): Promise<string[]>;
|
|
18
|
+
buildTooltipLines(chart: CartesianChart, flatIdx: number): Promise<string[][]>;
|
|
19
19
|
tooltipOptions(): {
|
|
20
20
|
crosshair: boolean;
|
|
21
21
|
highlightRadius: number;
|
|
22
|
+
axisIndicators: boolean;
|
|
22
23
|
};
|
|
23
24
|
destroy(_chart: CartesianChart): void;
|
|
24
25
|
}
|
|
@@ -8,4 +8,4 @@ import type { CartesianChart } from "./cartesian";
|
|
|
8
8
|
* Returns `[]` when the chart has no row-index mirror or no fetcher;
|
|
9
9
|
* callers should fall back to a geometry-only tooltip in that case.
|
|
10
10
|
*/
|
|
11
|
-
export declare function buildPointRowTooltipLines(chart: CartesianChart, flatIdx: number): Promise<string[]>;
|
|
11
|
+
export declare function buildPointRowTooltipLines(chart: CartesianChart, flatIdx: number): Promise<string[][]>;
|
|
@@ -5,6 +5,7 @@ import type { WebGLContextManager } from "../webgl/context-manager";
|
|
|
5
5
|
import { ZoomController, type ZoomConfig } from "../interaction/zoom-controller";
|
|
6
6
|
import { type ChartImplementation, type FacetConfig, type PluginConfig } from "./chart";
|
|
7
7
|
import { TooltipController, type HostSink, type TooltipCallbacks } from "../interaction/tooltip-controller";
|
|
8
|
+
import { LegendController } from "../interaction/legend-controller";
|
|
8
9
|
import type { PerspectiveClickDetail } from "../event-detail";
|
|
9
10
|
import type { ViewConfig } from "@perspective-dev/client";
|
|
10
11
|
import { type Theme } from "../theme/theme";
|
|
@@ -57,6 +58,7 @@ export declare abstract class AbstractChart implements ChartImplementation {
|
|
|
57
58
|
_glManager: WebGLContextManager | null;
|
|
58
59
|
_gridlineCanvas: HTMLCanvasElement | OffscreenCanvas | null;
|
|
59
60
|
_chromeCanvas: HTMLCanvasElement | OffscreenCanvas | null;
|
|
61
|
+
_overlayPresenter: (() => void) | null;
|
|
60
62
|
/**
|
|
61
63
|
* 2D-canvas draw closures collected during `_fullRender` (the GL
|
|
62
64
|
* pass) and flushed by {@link _flush2D} *after* the scheduler's
|
|
@@ -143,6 +145,7 @@ export declare abstract class AbstractChart implements ChartImplementation {
|
|
|
143
145
|
* the pre-refactor output.
|
|
144
146
|
*/
|
|
145
147
|
_pluginConfig: PluginConfig;
|
|
148
|
+
_legend: LegendController;
|
|
146
149
|
_tooltip: TooltipController;
|
|
147
150
|
/**
|
|
148
151
|
* Reference to the active host sink, captured in {@link attachTooltip}.
|
|
@@ -163,11 +166,14 @@ export declare abstract class AbstractChart implements ChartImplementation {
|
|
|
163
166
|
_emitQueue: Promise<void>;
|
|
164
167
|
/**
|
|
165
168
|
* Cached resolved theme — populated on first `_resolveTheme()` call,
|
|
166
|
-
* cleared by `invalidateTheme()` (driven from `plugin.restyle()`)
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
+
* cleared by `invalidateTheme()` (driven from `plugin.restyle()`)
|
|
170
|
+
* and by `setColumnsConfig` (per-column color overrides patch the
|
|
171
|
+
* resolved theme). `getComputedStyle` / `getPropertyValue` reads
|
|
172
|
+
* cost ~100µs each; zoom/hover dispatch redraws at 60Hz so we
|
|
173
|
+
* resolve once and reuse.
|
|
169
174
|
*/
|
|
170
175
|
_theme: Theme | null;
|
|
176
|
+
_themeColorColumn: string | null;
|
|
171
177
|
/**
|
|
172
178
|
* On-demand single-row fetcher used by lazy tooltip column
|
|
173
179
|
* lookups. Reset on every `setView` call; subclasses read
|
|
@@ -181,6 +187,12 @@ export declare abstract class AbstractChart implements ChartImplementation {
|
|
|
181
187
|
_lazyRows: LazyRowFetcher | null;
|
|
182
188
|
setGridlineCanvas(canvas: HTMLCanvasElement | OffscreenCanvas): void;
|
|
183
189
|
setChromeCanvas(canvas: HTMLCanvasElement | OffscreenCanvas): void;
|
|
190
|
+
setOverlayPresenter(cb: () => void): void;
|
|
191
|
+
/**
|
|
192
|
+
* Present a chrome-overlay repaint that ran outside the scheduler's
|
|
193
|
+
* frame chain.
|
|
194
|
+
*/
|
|
195
|
+
presentOverlay(): void;
|
|
184
196
|
setTheme(vars: Record<string, string>): void;
|
|
185
197
|
setZoomController(zc: ZoomController): void;
|
|
186
198
|
/**
|
|
@@ -294,12 +306,15 @@ export declare abstract class AbstractChart implements ChartImplementation {
|
|
|
294
306
|
* inputs in `uploadAndRender`; they take effect on next data load.
|
|
295
307
|
*/
|
|
296
308
|
setPluginConfig(cfg: PluginConfig): void;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
* the
|
|
300
|
-
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
309
|
+
protected colorScaleColumn(): string | null;
|
|
310
|
+
/**
|
|
311
|
+
* Lazily decode the host-supplied theme vars, then patch in any
|
|
312
|
+
* per-column color-scale override for `colorScaleColumn()`.
|
|
313
|
+
* Subsequent calls hit the cache until `invalidateTheme()` /
|
|
314
|
+
* `setColumnsConfig` clears it or the color column changes.
|
|
315
|
+
* Render-path callers should always read theme values through this
|
|
316
|
+
* method so the parsed `Theme` (gradient stops, palette, etc.)
|
|
317
|
+
* amortizes across an entire frame.
|
|
303
318
|
*/
|
|
304
319
|
_resolveTheme(): Theme;
|
|
305
320
|
/**
|
|
@@ -59,6 +59,10 @@ export interface ChartImplementation {
|
|
|
59
59
|
* Set the chrome canvas (above WebGL, for axes/labels/legend/tooltip).
|
|
60
60
|
*/
|
|
61
61
|
setChromeCanvas?(canvas: HTMLCanvasElement | OffscreenCanvas): void;
|
|
62
|
+
/**
|
|
63
|
+
* Install the renderer's overlay-present hook.
|
|
64
|
+
*/
|
|
65
|
+
setOverlayPresenter?(cb: () => void): void;
|
|
62
66
|
/**
|
|
63
67
|
* Hand the chart a pre-computed CSS-variable map produced on the
|
|
64
68
|
* main thread via `snapshotThemeVars(el)`, which it can decode into
|
|
@@ -154,6 +158,7 @@ export interface ChartImplementation {
|
|
|
154
158
|
* host's filter set.
|
|
155
159
|
*/
|
|
156
160
|
deselect?(): void;
|
|
161
|
+
repaintChrome?(): void;
|
|
157
162
|
destroy(): void;
|
|
158
163
|
}
|
|
159
164
|
export interface FacetConfig {
|
|
@@ -356,13 +361,15 @@ export interface PluginConfig {
|
|
|
356
361
|
*/
|
|
357
362
|
gradient_color_mode: "mean" | "density" | "extreme" | "signed";
|
|
358
363
|
/**
|
|
359
|
-
* Map basemap tile provider
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
+
* Map basemap tile provider — a `TileSourceSpec` id from the
|
|
365
|
+
* tile-source registry ([map/tile-sources.json] entries plus any
|
|
366
|
+
* runtime `registerTileSource` additions). Applies only to map
|
|
367
|
+
* plugin tags (`map-scatter`, `map-line`, `map-density`); other
|
|
368
|
+
* charts ignore the field. The default is the JSON's FIRST entry
|
|
369
|
+
* (reordering the file changes the default), and unknown ids fall
|
|
370
|
+
* back to that same entry rather than blanking the map.
|
|
364
371
|
*/
|
|
365
|
-
map_tile_provider:
|
|
372
|
+
map_tile_provider: string;
|
|
366
373
|
/**
|
|
367
374
|
* Map basemap alpha (0..1). Pre-multiplied into the tile fragment
|
|
368
375
|
* shader's output so the chart's glyph layer composites over a
|
|
@@ -370,5 +377,73 @@ export interface PluginConfig {
|
|
|
370
377
|
* shows the tiles at full opacity.
|
|
371
378
|
*/
|
|
372
379
|
map_tile_alpha: number;
|
|
380
|
+
/**
|
|
381
|
+
* Map plugins only. `true` (default): standard numeric axes in the
|
|
382
|
+
* usual cartesian gutters, with tick labels in degrees
|
|
383
|
+
* longitude/latitude (`122.4°W`) rather than Mercator meters.
|
|
384
|
+
* `false`: no axes, and the plot is full-bleed — the basemap fills
|
|
385
|
+
* the entire canvas, minus only the sidebar legend gutter when a
|
|
386
|
+
* legend is actually shown. Gridlines are never drawn in map mode
|
|
387
|
+
* — the gridline canvas composites BELOW the GL layer, so opaque
|
|
388
|
+
* basemap tiles would hide them.
|
|
389
|
+
*/
|
|
390
|
+
numeric_axes: boolean;
|
|
391
|
+
/**
|
|
392
|
+
* Legend presentation mode. `"auto"` (default) resolves per frame
|
|
393
|
+
* to `"floating"` when every entry fits the default floating panel
|
|
394
|
+
* without scrolling (≤ 7 entries; continuous gradient legends
|
|
395
|
+
* always qualify) and to `"sidebar"` otherwise — see
|
|
396
|
+
* `resolveLegendMode`. Treemap overrides the default to
|
|
397
|
+
* `"sidebar"` (a floating panel over edge-to-edge tiles always
|
|
398
|
+
* occludes data).
|
|
399
|
+
*/
|
|
400
|
+
legend_mode: "auto" | "sidebar" | "none" | "floating";
|
|
401
|
+
/**
|
|
402
|
+
* Floating-panel sizing regime. `"auto"` (default) sizes the panel
|
|
403
|
+
* to its CONTENT every frame — the height hugs the entry rows
|
|
404
|
+
* exactly, and the width hugs the widest entry label (measured on
|
|
405
|
+
* the chrome canvas). `"fixed"` uses the saved `legend_width_px` /
|
|
406
|
+
* `legend_height_px` verbatim.
|
|
407
|
+
*
|
|
408
|
+
* Applies to `legend_mode: "floating"` ONLY; the sidebar gutter is
|
|
409
|
+
* always `legend_width_px` (its height is the plot's). Dragging a
|
|
410
|
+
* resize handle switches an auto panel to `"fixed"` — otherwise
|
|
411
|
+
* the gesture would be undone by the next paint — and
|
|
412
|
+
* double-clicking a resize handle switches it back.
|
|
413
|
+
*/
|
|
414
|
+
legend_size_mode: LegendSizeMode;
|
|
415
|
+
/**
|
|
416
|
+
* Legend width in CSS pixels. `0` (default) = automatic — each
|
|
417
|
+
* chart family keeps its historical gutter width (80–96px). In
|
|
418
|
+
* `"sidebar"` mode this is the full right-gutter width; in
|
|
419
|
+
* `"floating"` mode it is the panel width. Clamped at paint time
|
|
420
|
+
* to at most half the canvas width so a saved wide legend cannot
|
|
421
|
+
* crush a small panel. Ignored by a floating panel in
|
|
422
|
+
* `legend_size_mode: "auto"`.
|
|
423
|
+
*/
|
|
424
|
+
legend_width_px: number;
|
|
425
|
+
/**
|
|
426
|
+
* Floating-legend panel height in CSS pixels. Ignored in
|
|
427
|
+
* `"sidebar"` mode (the legend spans the plot height) and by a
|
|
428
|
+
* floating panel in `legend_size_mode: "auto"`. Clamped at paint
|
|
429
|
+
* time to the canvas height.
|
|
430
|
+
*/
|
|
431
|
+
legend_height_px: number;
|
|
432
|
+
/**
|
|
433
|
+
* Canvas corner that `legend_x` / `legend_y` are measured FROM.
|
|
434
|
+
* Floating mode only. The panel keeps its distance to this corner
|
|
435
|
+
* across panel resizes — anchor `"bottom-right"` with small
|
|
436
|
+
* offsets stays glued to the bottom-right.
|
|
437
|
+
*/
|
|
438
|
+
legend_anchor: LegendAnchor;
|
|
439
|
+
legend_x: number;
|
|
440
|
+
legend_y: number;
|
|
441
|
+
legend_opacity: number;
|
|
442
|
+
/** Per-column width cap for tooltip grid cells, in CSS pixels. */
|
|
443
|
+
tooltip_max_column_px: number;
|
|
444
|
+
/** Tooltip background/border alpha (0..1). */
|
|
445
|
+
tooltip_opacity: number;
|
|
373
446
|
}
|
|
447
|
+
export type LegendAnchor = "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
448
|
+
export type LegendSizeMode = "auto" | "fixed";
|
|
374
449
|
export declare const DEFAULT_PLUGIN_CONFIG: PluginConfig;
|
|
@@ -87,7 +87,7 @@ export declare function synthesizeStringLevel(rp: ColumnData, numRows: number, l
|
|
|
87
87
|
* category axis falls back to the raw row index — callers infer that
|
|
88
88
|
* from `rowPaths.length === 0`.
|
|
89
89
|
*/
|
|
90
|
-
export declare function resolveCategoryAxis(columns: ColumnDataMap, numRows: number, groupByLen: number, levelTypes?: string[]): CategoryAxisResult;
|
|
90
|
+
export declare function resolveCategoryAxis(columns: ColumnDataMap, numRows: number, groupByLen: number, levelTypes?: string[], axisMode?: AxisMode): CategoryAxisResult;
|
|
91
91
|
export interface ValueCategoryColumn {
|
|
92
92
|
/**
|
|
93
93
|
* Source aggregate column name; used only for the axis label fallback.
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Context2D } from "../canvas-types";
|
|
2
2
|
import type { Theme } from "../../theme/theme";
|
|
3
|
+
import { type TooltipContent, type TooltipStyle } from "../../interaction/tooltip-grid";
|
|
3
4
|
/**
|
|
4
5
|
* Draw a freestanding tooltip box anchored near (cx, cy), measuring
|
|
5
6
|
* lines, sizing/clamping the box, painting bg/border, and laying out
|
|
6
7
|
* text rows. Shared by sunburst + treemap which need a non-PlotLayout
|
|
7
8
|
* anchor.
|
|
8
9
|
*/
|
|
9
|
-
export declare function drawTooltipBox(ctx: Context2D, theme: Theme,
|
|
10
|
+
export declare function drawTooltipBox(ctx: Context2D, theme: Theme, grid: TooltipContent, cx: number, cy: number, cssWidth: number, cssHeight: number, fontFamily: string, style?: TooltipStyle): void;
|
|
@@ -18,6 +18,7 @@ export declare function firstNonMetadataColumn(columns: ColumnDataMap): string;
|
|
|
18
18
|
* layout modules can read/write them without friction.
|
|
19
19
|
*/
|
|
20
20
|
export declare abstract class TreeChartBase extends AbstractChart {
|
|
21
|
+
protected colorScaleColumn(): string | null;
|
|
21
22
|
_sizeName: string;
|
|
22
23
|
_colorName: string;
|
|
23
24
|
/**
|
|
@@ -26,7 +26,7 @@ export declare function emitTreeNodeEvent(chart: TreeInteractChart, nodeId: numb
|
|
|
26
26
|
* fetch; branch nodes have no underlying row so they emit a Children
|
|
27
27
|
* count instead.
|
|
28
28
|
*/
|
|
29
|
-
export declare function buildTreeTooltipLines(chart: TreeInteractChart, nodeId: number): Promise<string[]>;
|
|
29
|
+
export declare function buildTreeTooltipLines(chart: TreeInteractChart, nodeId: number): Promise<string[][]>;
|
|
30
30
|
/**
|
|
31
31
|
* Pin a tooltip at the chart-supplied anchor. Lines are fetched lazily;
|
|
32
32
|
* the `_pinnedNodeId` check on resolve discards stale results from a
|
|
@@ -41,6 +41,7 @@ export interface HeatmapFacet {
|
|
|
41
41
|
* scale and a single legend.
|
|
42
42
|
*/
|
|
43
43
|
export declare class HeatmapChart extends AbstractChart {
|
|
44
|
+
protected colorScaleColumn(): string | null;
|
|
44
45
|
_program: WebGLProgram | null;
|
|
45
46
|
_locations: HeatmapLocations | null;
|
|
46
47
|
_cornerBuffer: WebGLBuffer | null;
|
|
@@ -213,6 +213,13 @@ export interface SeriesPipelineResult {
|
|
|
213
213
|
* is the position. Indexed by `catIdx` (0..numCategories-1).
|
|
214
214
|
*/
|
|
215
215
|
categoryPositions: Float64Array | null;
|
|
216
|
+
/**
|
|
217
|
+
* One entry per (aggregate × split), in `k * P + p` order. INVARIANT:
|
|
218
|
+
* `series.length === aggregates.length * splitPrefixes.length` —
|
|
219
|
+
* consumers index `series[k * P]` directly (glyph runs, the
|
|
220
|
+
* `domain_mode: "expand"` axis signature), so an empty `series` MUST
|
|
221
|
+
* be paired with empty `aggregates` / `splitPrefixes`.
|
|
222
|
+
*/
|
|
216
223
|
series: SeriesInfo[];
|
|
217
224
|
/**
|
|
218
225
|
* Columnar bar/area records, one per (catIdx, agg, split) for series
|
|
@@ -32,7 +32,7 @@ export declare function handleBarLegendClick(chart: SeriesChart, mx: number, my:
|
|
|
32
32
|
/**
|
|
33
33
|
* Build the per-bar tooltip content lines.
|
|
34
34
|
*/
|
|
35
|
-
export declare function buildBarTooltipLines(chart: SeriesChart, b: SeriesChartRecord): string[];
|
|
35
|
+
export declare function buildBarTooltipLines(chart: SeriesChart, b: SeriesChartRecord): string[][];
|
|
36
36
|
/**
|
|
37
37
|
* Format the hierarchical path label for a given category index. Used by
|
|
38
38
|
* the tooltip — the axis uses per-level text directly instead.
|
|
@@ -28,6 +28,16 @@ export interface ColumnChartConfig {
|
|
|
28
28
|
* `"skip"`). Default `"skip"`. No effect on bar / scatter.
|
|
29
29
|
*/
|
|
30
30
|
interpolate?: InterpolateMode;
|
|
31
|
+
/**
|
|
32
|
+
* Single series-color override (`#rrggbb`) — the no-`split_by`
|
|
33
|
+
* shape.
|
|
34
|
+
*/
|
|
35
|
+
color?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Discrete color palette cycled over this column's split-generated
|
|
38
|
+
* series — the `split_by` shape.
|
|
39
|
+
*/
|
|
40
|
+
palette?: string;
|
|
31
41
|
}
|
|
32
42
|
/**
|
|
33
43
|
* Resolve the render glyph for an aggregate base name. Lookup key is the
|
|
@@ -45,6 +55,14 @@ export declare function resolveStack(aggName: string, chartType: ChartType, cfg:
|
|
|
45
55
|
* `columns_config[aggName].alt_axis`.
|
|
46
56
|
*/
|
|
47
57
|
export declare function resolveAltAxis(aggName: string, cfg: Record<string, ColumnChartConfig> | undefined): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Resolve a per-series color override from `columns_config`, or `null`
|
|
60
|
+
* when the theme palette applies.
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveSeriesColorOverride(series: {
|
|
63
|
+
aggName: string;
|
|
64
|
+
splitIdx: number;
|
|
65
|
+
}, facetActive: boolean, cfg: Record<string, ColumnChartConfig> | undefined): [number, number, number] | null;
|
|
48
66
|
/**
|
|
49
67
|
* Resolve the interpolation mode for this aggregate.
|
|
50
68
|
*/
|
|
@@ -74,6 +74,12 @@ export declare class SeriesChart extends CategoricalYChart {
|
|
|
74
74
|
* always present. The value axis stays freely zoomable.
|
|
75
75
|
*/
|
|
76
76
|
protected getZoomConfig(): ZoomConfig;
|
|
77
|
+
/**
|
|
78
|
+
* Chrome-only repaint for legend scroll / floating-legend drag —
|
|
79
|
+
* the same lightweight path hover updates use. No GL pass; the
|
|
80
|
+
* composite re-presents over the retained plot bitmap.
|
|
81
|
+
*/
|
|
82
|
+
repaintChrome(): void;
|
|
77
83
|
_locations: CachedLocations | null;
|
|
78
84
|
_aggregates: string[];
|
|
79
85
|
_splitPrefixes: string[];
|
|
@@ -190,13 +196,16 @@ export declare class SeriesChart extends CategoricalYChart {
|
|
|
190
196
|
/**
|
|
191
197
|
* Cached palette + identity-keys for short-circuiting per-frame
|
|
192
198
|
* resolution. Inputs (`seriesPalette` ref, `gradientStops` ref,
|
|
193
|
-
* `series.length`
|
|
199
|
+
* `series.length`, `_columnsConfig` ref — per-series color
|
|
200
|
+
* overrides) only change on data load, `restyle()`, or
|
|
201
|
+
* `setColumnsConfig`.
|
|
194
202
|
*/
|
|
195
203
|
_paletteCache: [number, number, number][] | null;
|
|
196
204
|
_paletteCacheKey: {
|
|
197
205
|
seriesPalette: [number, number, number][] | null;
|
|
198
206
|
gradientStops: unknown;
|
|
199
207
|
seriesLength: number;
|
|
208
|
+
columnsConfig: unknown;
|
|
200
209
|
} | null;
|
|
201
210
|
/**
|
|
202
211
|
* Reusable scratch for the build pipeline — keeps the stack ladder
|
|
@@ -19,4 +19,8 @@ export declare function facetCenterForNode(chart: SunburstChart, nodeId: number)
|
|
|
19
19
|
* Full-frame render: layout → WebGL arcs → chrome overlay.
|
|
20
20
|
*/
|
|
21
21
|
export declare function renderSunburstFrame(chart: SunburstChart, glManager: WebGLContextManager): void;
|
|
22
|
+
/**
|
|
23
|
+
* Render the chrome overlay (labels, center text, hover highlight +
|
|
24
|
+
* tooltip).
|
|
25
|
+
*/
|
|
22
26
|
export declare function renderSunburstChromeOverlay(chart: SunburstChart): void;
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export type { PerspectiveClickDetail } from "./event-detail";
|
|
2
2
|
export { PerspectiveSelectDetail } from "./event-detail";
|
|
3
|
+
export { registerTileSource } from "./plugin/plugin";
|
|
4
|
+
export { tileSources, type TileSourceSpec } from "./map/tile-source";
|
|
3
5
|
export declare function register(...plugin_names: string[]): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Canvas2D } from "../charts/canvas-types";
|
|
2
|
+
import type { PlotLayout } from "../layout/plot-layout";
|
|
3
|
+
import type { Theme } from "../theme/theme";
|
|
4
|
+
export type AxisSide = "bottom" | "left" | "right";
|
|
5
|
+
export interface AxisIndicator {
|
|
6
|
+
side: AxisSide;
|
|
7
|
+
px: number;
|
|
8
|
+
py: number;
|
|
9
|
+
text: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function renderAxisHoverIndicators(canvas: Canvas2D | null, layout: PlotLayout, theme: Theme, dpr: number, indicators: AxisIndicator[], opacity?: number): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CssBounds, HostSink } from "./tooltip-controller";
|
|
2
|
+
import { type TooltipContent, type TooltipStyle } from "./tooltip-grid";
|
|
2
3
|
/**
|
|
3
4
|
* Host-side `HostSink` that materializes pinned tooltips as a `<div>`
|
|
4
5
|
* next to the GL canvas, and applies cursor changes to the canvas's
|
|
@@ -10,10 +11,10 @@ export declare class DomHostSink implements HostSink {
|
|
|
10
11
|
private _parent;
|
|
11
12
|
private _div;
|
|
12
13
|
constructor(glCanvas: HTMLCanvasElement, parent: HTMLElement);
|
|
13
|
-
pin(
|
|
14
|
+
pin(grid: TooltipContent, pos: {
|
|
14
15
|
px: number;
|
|
15
16
|
py: number;
|
|
16
|
-
}, bounds: CssBounds): void;
|
|
17
|
+
}, bounds: CssBounds, style?: TooltipStyle): void;
|
|
17
18
|
dismiss(): void;
|
|
18
19
|
setCursor(cursor: string): void;
|
|
19
20
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DismissTooltipMsg, PinTooltipMsg, SetCursorMsg, UserClickMsg, UserSelectMsg } from "../transport/protocol";
|
|
2
2
|
import type { CssBounds, HostSink, UserClickPayload, UserSelectPayload } from "./tooltip-controller";
|
|
3
|
+
import { type TooltipContent, type TooltipStyle } from "./tooltip-grid";
|
|
3
4
|
/**
|
|
4
5
|
* The subset of `WorkerMsg`s that flow chart → host through a
|
|
5
6
|
* `MessageHostSink`. Identical to the worker-side post payloads so the
|
|
@@ -17,10 +18,10 @@ export type HostSinkEnvelope = PinTooltipMsg | DismissTooltipMsg | SetCursorMsg
|
|
|
17
18
|
export declare class MessageHostSink implements HostSink {
|
|
18
19
|
private _send;
|
|
19
20
|
constructor(send: (msg: HostSinkEnvelope) => void);
|
|
20
|
-
pin(
|
|
21
|
+
pin(grid: TooltipContent, pos: {
|
|
21
22
|
px: number;
|
|
22
23
|
py: number;
|
|
23
|
-
}, bounds: CssBounds): void;
|
|
24
|
+
}, bounds: CssBounds, style?: TooltipStyle): void;
|
|
24
25
|
dismiss(): void;
|
|
25
26
|
setCursor(cursor: string): void;
|
|
26
27
|
emitUserClick(payload: UserClickPayload): void;
|
|
@@ -20,7 +20,7 @@ export declare class LazyTooltip<Target> {
|
|
|
20
20
|
/**
|
|
21
21
|
* Cached lines for the latest committed hover, or `null`.
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
grid: string[][] | null;
|
|
24
24
|
/**
|
|
25
25
|
* Identity of the entity `lines` describe. `null` when cleared.
|
|
26
26
|
*/
|
|
@@ -40,7 +40,7 @@ export declare class LazyTooltip<Target> {
|
|
|
40
40
|
* when the write happened (caller should repaint), false when the
|
|
41
41
|
* serial was stale.
|
|
42
42
|
*/
|
|
43
|
-
commitHover(serial: number,
|
|
43
|
+
commitHover(serial: number, grid: string[][]): boolean;
|
|
44
44
|
/**
|
|
45
45
|
* Clear hover state (mouse left, view changed, etc.).
|
|
46
46
|
*/
|