@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
package/src/ts/plugin/plugin.ts
CHANGED
|
@@ -10,13 +10,19 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
+
import { colorsToCss, stopsToCss } from "../theme/gradient";
|
|
13
14
|
import type { View } from "@perspective-dev/client";
|
|
14
15
|
import type {
|
|
15
16
|
HTMLPerspectiveViewerElement,
|
|
16
17
|
IPerspectiveViewerPlugin,
|
|
17
18
|
PluginStaticConfig,
|
|
18
19
|
} from "@perspective-dev/viewer";
|
|
19
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
ChartTypeConfig,
|
|
22
|
+
LEGEND_FIELDS,
|
|
23
|
+
TOOLTIP_FIELDS,
|
|
24
|
+
PluginConfigField,
|
|
25
|
+
} from "./charts";
|
|
20
26
|
import style from "../../css/perspective-viewer-charts.css";
|
|
21
27
|
import {
|
|
22
28
|
DEFAULT_FACET_CONFIG,
|
|
@@ -24,9 +30,19 @@ import {
|
|
|
24
30
|
type FacetConfig,
|
|
25
31
|
type PluginConfig,
|
|
26
32
|
} from "../charts/chart";
|
|
33
|
+
import {
|
|
34
|
+
CHART_DATE_DEFAULTS,
|
|
35
|
+
CHART_DATETIME_DEFAULTS,
|
|
36
|
+
CHART_NUMBER_DEFAULTS,
|
|
37
|
+
} from "./format-defaults";
|
|
27
38
|
import { RawEventForwarder } from "../interaction/raw-event-forwarder";
|
|
28
39
|
import { RendererTransport } from "../transport/renderer-transport";
|
|
40
|
+
import { TILE_SOURCES, type TileSourceSpec } from "../map/tile-source";
|
|
29
41
|
import { RENDER_BLIT_MODE } from "../config";
|
|
42
|
+
import { snapshotThemeVars } from "../theme/theme-snapshot";
|
|
43
|
+
import { resolveThemeFromVars, type Theme } from "../theme/theme";
|
|
44
|
+
import { resolvePalette } from "../theme/palette";
|
|
45
|
+
import { vec3ToHexColor } from "../utils/css";
|
|
30
46
|
|
|
31
47
|
/**
|
|
32
48
|
* Facet-rendering defaults shared by every chart. Per-chart overrides
|
|
@@ -37,6 +53,26 @@ import { RENDER_BLIT_MODE } from "../config";
|
|
|
37
53
|
*/
|
|
38
54
|
const FACET_CONFIG_DEFAULTS: FacetConfig = { ...DEFAULT_FACET_CONFIG };
|
|
39
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Register a raster XYZ tile provider at runtime. The provider joins
|
|
58
|
+
* the bundled [map/tile-sources.json] entries in the settings panel's
|
|
59
|
+
* `map_tile_provider` enum and resolves on any map chart from its next
|
|
60
|
+
* config forward onward — the resolved spec rides every outgoing
|
|
61
|
+
* `setPluginConfig` / `init` message alongside the config that names
|
|
62
|
+
* it, so no separate registry-sync operation exists. Re-registering an
|
|
63
|
+
* id replaces it (a changed template drops cached tiles via the
|
|
64
|
+
* content-derived cache identity); a chart currently displaying that
|
|
65
|
+
* id picks the replacement up on its next `restore()`. Throws
|
|
66
|
+
* `TypeError` on a malformed spec. Returns the normalized spec.
|
|
67
|
+
*
|
|
68
|
+
* A key-gated provider is registered with the key embedded in its
|
|
69
|
+
* `template` — keys never enter `plugin_config`, so they never appear
|
|
70
|
+
* in `save()` output.
|
|
71
|
+
*/
|
|
72
|
+
export function registerTileSource(spec: unknown): TileSourceSpec {
|
|
73
|
+
return TILE_SOURCES.register(spec);
|
|
74
|
+
}
|
|
75
|
+
|
|
40
76
|
/**
|
|
41
77
|
* Static UI-control spec per `plugin_config` field. Mirrors the shape
|
|
42
78
|
* `column_config_schema` already returns (datagrid). The runtime default
|
|
@@ -52,72 +88,157 @@ type FieldSpec =
|
|
|
52
88
|
}
|
|
53
89
|
| { kind: "Number"; min: number; max: number; step?: number };
|
|
54
90
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
91
|
+
/**
|
|
92
|
+
* A `FieldSpec` entry may be a thunk when its contents depend on
|
|
93
|
+
* runtime state — `map_tile_provider`'s variants come from the tile-
|
|
94
|
+
* source registry, which grows via `registerTileSource`, so the enum
|
|
95
|
+
* must be resolved per `plugin_config_schema()` call rather than at
|
|
96
|
+
* module init.
|
|
97
|
+
*/
|
|
98
|
+
const FIELD_SCHEMAS: Record<PluginConfigField, FieldSpec | (() => FieldSpec)> =
|
|
99
|
+
{
|
|
100
|
+
auto_alt_y_axis: { kind: "Bool" },
|
|
101
|
+
include_zero: { kind: "Bool" },
|
|
102
|
+
domain_mode: {
|
|
103
|
+
kind: "Enum",
|
|
104
|
+
variants: [
|
|
105
|
+
{ value: "fit", label: "Fit" },
|
|
106
|
+
{ value: "expand", label: "Expand" },
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
facet_mode: {
|
|
110
|
+
kind: "Enum",
|
|
111
|
+
variants: [
|
|
112
|
+
{ value: "grid", label: "Grid" },
|
|
113
|
+
{ value: "overlay", label: "Overlay" },
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
facet_zoom_mode: {
|
|
117
|
+
kind: "Enum",
|
|
118
|
+
variants: [
|
|
119
|
+
{ value: "shared", label: "Shared" },
|
|
120
|
+
{ value: "independent", label: "Independent" },
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
series_zoom_mode: {
|
|
124
|
+
kind: "Enum",
|
|
125
|
+
variants: [
|
|
126
|
+
{ value: "dynamic", label: "Dynamic" },
|
|
127
|
+
{ value: "fixed", label: "Fixed" },
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
line_width_px: { kind: "Number", min: 0.5, step: 0.5, max: 16 },
|
|
131
|
+
point_size_px: { kind: "Number", min: 1, max: 32 },
|
|
132
|
+
band_inner_frac: { kind: "Number", min: 0.1, max: 1, step: 0.01 },
|
|
133
|
+
bar_inner_pad: { kind: "Number", min: 0, max: 0.9, step: 0.01 },
|
|
134
|
+
wick_width_px: { kind: "Number", min: 0.5, step: 0.5, max: 8 },
|
|
135
|
+
ohlc_line_width_px: { kind: "Number", min: 0.5, step: 0.5, max: 8 },
|
|
136
|
+
gradient_radius_px: { kind: "Number", min: 2, step: 1, max: 256 },
|
|
137
|
+
gradient_intensity: { kind: "Number", min: 0.05, step: 0.05, max: 4 },
|
|
138
|
+
gradient_heat_max: { kind: "Number", min: 0.1, step: 0.1, max: 64 },
|
|
139
|
+
gradient_color_mode: {
|
|
140
|
+
kind: "Enum",
|
|
141
|
+
variants: [
|
|
142
|
+
{ value: "mean", label: "Mean (density-weighted)" },
|
|
143
|
+
{ value: "density", label: "Density only" },
|
|
144
|
+
{ value: "extreme", label: "Extremes" },
|
|
145
|
+
{ value: "signed", label: "Signed sum" },
|
|
146
|
+
],
|
|
147
|
+
},
|
|
148
|
+
map_tile_provider: () => ({
|
|
149
|
+
kind: "Enum",
|
|
150
|
+
variants: TILE_SOURCES.list().map((s) => ({
|
|
151
|
+
value: s.id,
|
|
152
|
+
label: s.label,
|
|
153
|
+
})),
|
|
154
|
+
}),
|
|
155
|
+
map_tile_alpha: { kind: "Number", min: 0, max: 1, step: 0.05 },
|
|
156
|
+
numeric_axes: { kind: "Bool" },
|
|
157
|
+
legend_mode: {
|
|
158
|
+
kind: "Enum",
|
|
159
|
+
variants: [
|
|
160
|
+
{ value: "auto", label: "Auto" },
|
|
161
|
+
{ value: "sidebar", label: "Sidebar" },
|
|
162
|
+
{ value: "none", label: "None" },
|
|
163
|
+
{ value: "floating", label: "Floating" },
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
legend_size_mode: {
|
|
167
|
+
kind: "Enum",
|
|
168
|
+
variants: [
|
|
169
|
+
{ value: "auto", label: "Auto" },
|
|
170
|
+
{ value: "fixed", label: "Fixed" },
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
// 0 = auto (the chart family's historical gutter width).
|
|
174
|
+
legend_width_px: { kind: "Number", min: 0, max: 512, step: 1 },
|
|
175
|
+
legend_height_px: { kind: "Number", min: 48, max: 1024, step: 1 },
|
|
176
|
+
legend_anchor: {
|
|
177
|
+
kind: "Enum",
|
|
178
|
+
variants: [
|
|
179
|
+
{ value: "top-right", label: "Top Right" },
|
|
180
|
+
{ value: "top-left", label: "Top Left" },
|
|
181
|
+
{ value: "bottom-right", label: "Bottom Right" },
|
|
182
|
+
{ value: "bottom-left", label: "Bottom Left" },
|
|
183
|
+
],
|
|
184
|
+
},
|
|
185
|
+
legend_x: { kind: "Number", min: 0, max: 1, step: 0.01 },
|
|
186
|
+
legend_y: { kind: "Number", min: 0, max: 1, step: 0.01 },
|
|
187
|
+
legend_opacity: { kind: "Number", min: 0, max: 1, step: 0.05 },
|
|
188
|
+
tooltip_max_column_px: { kind: "Number", min: 40, max: 512, step: 1 },
|
|
189
|
+
tooltip_opacity: { kind: "Number", min: 0, max: 1, step: 0.05 },
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
function fieldSpec(
|
|
193
|
+
key: PluginConfigField,
|
|
194
|
+
defaults: PluginConfig,
|
|
195
|
+
): Record<string, unknown> & { kind: string } {
|
|
196
|
+
const entry = FIELD_SCHEMAS[key];
|
|
197
|
+
const spec = typeof entry === "function" ? entry() : entry;
|
|
198
|
+
return { ...spec, key, default: defaults[key] };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const PLUGIN_FIELD_GROUPS: ReadonlyArray<{
|
|
202
|
+
key: string;
|
|
203
|
+
fields: readonly PluginConfigField[];
|
|
204
|
+
}> = [
|
|
205
|
+
{
|
|
206
|
+
key: "axes",
|
|
207
|
+
fields: [
|
|
208
|
+
"auto_alt_y_axis",
|
|
209
|
+
"include_zero",
|
|
210
|
+
"domain_mode",
|
|
211
|
+
"numeric_axes",
|
|
77
212
|
],
|
|
78
213
|
},
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
{ value: "dynamic", label: "Dynamic" },
|
|
83
|
-
{ value: "fixed", label: "Fixed" },
|
|
84
|
-
],
|
|
214
|
+
{
|
|
215
|
+
key: "facets",
|
|
216
|
+
fields: ["facet_mode", "facet_zoom_mode", "series_zoom_mode"],
|
|
85
217
|
},
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
gradient_color_mode: {
|
|
96
|
-
kind: "Enum",
|
|
97
|
-
variants: [
|
|
98
|
-
{ value: "mean", label: "Mean (density-weighted)" },
|
|
99
|
-
{ value: "density", label: "Density only" },
|
|
100
|
-
{ value: "extreme", label: "Extremes" },
|
|
101
|
-
{ value: "signed", label: "Signed sum" },
|
|
218
|
+
{
|
|
219
|
+
key: "glyph",
|
|
220
|
+
fields: [
|
|
221
|
+
"line_width_px",
|
|
222
|
+
"point_size_px",
|
|
223
|
+
"band_inner_frac",
|
|
224
|
+
"bar_inner_pad",
|
|
225
|
+
"wick_width_px",
|
|
226
|
+
"ohlc_line_width_px",
|
|
102
227
|
],
|
|
103
228
|
},
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
229
|
+
{
|
|
230
|
+
key: "density",
|
|
231
|
+
fields: [
|
|
232
|
+
"gradient_color_mode",
|
|
233
|
+
"gradient_radius_px",
|
|
234
|
+
"gradient_intensity",
|
|
235
|
+
"gradient_heat_max",
|
|
110
236
|
],
|
|
111
237
|
},
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
key: PluginConfigField,
|
|
117
|
-
defaults: PluginConfig,
|
|
118
|
-
): Record<string, unknown> & { kind: string } {
|
|
119
|
-
return { ...FIELD_SCHEMAS[key], key, default: defaults[key] };
|
|
120
|
-
}
|
|
238
|
+
{ key: "basemap", fields: ["map_tile_provider", "map_tile_alpha"] },
|
|
239
|
+
{ key: "legend", fields: LEGEND_FIELDS },
|
|
240
|
+
{ key: "tooltip", fields: TOOLTIP_FIELDS },
|
|
241
|
+
];
|
|
121
242
|
|
|
122
243
|
const GLOBAL_STYLES = (() => {
|
|
123
244
|
const sheet = new CSSStyleSheet();
|
|
@@ -394,6 +515,19 @@ export class HTMLPerspectiveViewerWebGLPluginElement
|
|
|
394
515
|
zoomControls.classList.toggle("visible", !isDefault);
|
|
395
516
|
}
|
|
396
517
|
},
|
|
518
|
+
onPluginConfigDelta: (fields) => {
|
|
519
|
+
this._pluginConfig = { ...this._pluginConfig, ...fields };
|
|
520
|
+
const host = this
|
|
521
|
+
.parentElement as HTMLPerspectiveViewerElement | null;
|
|
522
|
+
(
|
|
523
|
+
host?.restore(
|
|
524
|
+
{ plugin_config: fields },
|
|
525
|
+
panel ? { panel } : undefined,
|
|
526
|
+
) as Promise<void> | undefined
|
|
527
|
+
)?.catch((e: unknown) => {
|
|
528
|
+
console.error("legend config persistence failed", e);
|
|
529
|
+
});
|
|
530
|
+
},
|
|
397
531
|
});
|
|
398
532
|
|
|
399
533
|
await transport.init({
|
|
@@ -432,6 +566,14 @@ export class HTMLPerspectiveViewerWebGLPluginElement
|
|
|
432
566
|
BLIT_MODE = mode;
|
|
433
567
|
}
|
|
434
568
|
|
|
569
|
+
static registerTileSource(spec: unknown): TileSourceSpec {
|
|
570
|
+
return registerTileSource(spec);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
static tileSources(): readonly TileSourceSpec[] {
|
|
574
|
+
return TILE_SOURCES.list();
|
|
575
|
+
}
|
|
576
|
+
|
|
435
577
|
get_static_config(): PluginStaticConfig {
|
|
436
578
|
return {
|
|
437
579
|
name: this._chartType.name,
|
|
@@ -449,23 +591,79 @@ export class HTMLPerspectiveViewerWebGLPluginElement
|
|
|
449
591
|
priority: 0,
|
|
450
592
|
can_render_column_styles:
|
|
451
593
|
!!this._chartType.default_chart_type ||
|
|
452
|
-
this._chartType.category === "Cartesian Charts"
|
|
594
|
+
this._chartType.category === "Cartesian Charts" ||
|
|
595
|
+
this._chartType.category === "Hierarchical Charts" ||
|
|
596
|
+
this._chartType.category === "Map Charts",
|
|
453
597
|
};
|
|
454
598
|
}
|
|
455
599
|
|
|
456
600
|
column_config_schema(
|
|
457
601
|
column_type: string,
|
|
458
|
-
|
|
459
|
-
|
|
602
|
+
group: string | undefined,
|
|
603
|
+
column_name: string,
|
|
460
604
|
current_value: Record<string, unknown> | null,
|
|
461
|
-
|
|
605
|
+
viewer_config?: {
|
|
606
|
+
columns?: (string | null)[];
|
|
607
|
+
group_by?: string[];
|
|
608
|
+
split_by?: string[];
|
|
609
|
+
group_rollup_mode?: string;
|
|
610
|
+
},
|
|
462
611
|
) {
|
|
463
612
|
const fields: Array<Record<string, unknown> & { kind: string }> = [];
|
|
464
613
|
|
|
614
|
+
if (group === "Color") {
|
|
615
|
+
const numeric_gradient =
|
|
616
|
+
this._chartType.category === "Hierarchical Charts"
|
|
617
|
+
? column_type === "integer" ||
|
|
618
|
+
column_type === "float" ||
|
|
619
|
+
column_type === "date" ||
|
|
620
|
+
column_type === "datetime"
|
|
621
|
+
: column_type !== "string";
|
|
622
|
+
if (numeric_gradient) {
|
|
623
|
+
fields.push({
|
|
624
|
+
kind: "GradientStops",
|
|
625
|
+
key: "gradient",
|
|
626
|
+
default: this._themeGradientStopsSpec(),
|
|
627
|
+
});
|
|
628
|
+
} else {
|
|
629
|
+
fields.push({
|
|
630
|
+
kind: "Palette",
|
|
631
|
+
key: "palette",
|
|
632
|
+
default: this._themeSeriesPaletteHex(),
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
465
637
|
// Y-series plugins expose the per-column chart_type picker; non-Y
|
|
466
638
|
// plugins leave `default_chart_type` unset.
|
|
467
639
|
const def = this._chartType.default_chart_type;
|
|
468
640
|
if (def && (column_type === "integer" || column_type === "float")) {
|
|
641
|
+
const is_series_glyph =
|
|
642
|
+
def === "bar" ||
|
|
643
|
+
def === "line" ||
|
|
644
|
+
def === "scatter" ||
|
|
645
|
+
def === "area";
|
|
646
|
+
|
|
647
|
+
if (is_series_glyph) {
|
|
648
|
+
const has_split = (viewer_config?.split_by?.length ?? 0) > 0;
|
|
649
|
+
if (has_split) {
|
|
650
|
+
fields.push({
|
|
651
|
+
kind: "Palette",
|
|
652
|
+
key: "palette",
|
|
653
|
+
default: this._themeSeriesPaletteHex(),
|
|
654
|
+
});
|
|
655
|
+
} else {
|
|
656
|
+
const slot = (viewer_config?.columns ?? [])
|
|
657
|
+
.filter((c): c is string => !!c)
|
|
658
|
+
.indexOf(column_name);
|
|
659
|
+
fields.push({
|
|
660
|
+
kind: "Color",
|
|
661
|
+
key: "color",
|
|
662
|
+
default: this._themeSeriesColorHex(Math.max(0, slot)),
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
469
667
|
fields.push({
|
|
470
668
|
kind: "Enum",
|
|
471
669
|
key: "chart_type",
|
|
@@ -493,12 +691,6 @@ export class HTMLPerspectiveViewerWebGLPluginElement
|
|
|
493
691
|
});
|
|
494
692
|
}
|
|
495
693
|
|
|
496
|
-
const is_series_glyph =
|
|
497
|
-
def === "bar" ||
|
|
498
|
-
def === "line" ||
|
|
499
|
-
def === "scatter" ||
|
|
500
|
-
def === "area";
|
|
501
|
-
|
|
502
694
|
if (is_series_glyph) {
|
|
503
695
|
fields.push({
|
|
504
696
|
kind: "Bool",
|
|
@@ -537,9 +729,20 @@ export class HTMLPerspectiveViewerWebGLPluginElement
|
|
|
537
729
|
// Per-column formatter widgets. Surfaced for every chart type so
|
|
538
730
|
// axes / tooltips / legends honor the user's format choice.
|
|
539
731
|
if (column_type === "integer" || column_type === "float") {
|
|
540
|
-
fields.push({
|
|
541
|
-
|
|
542
|
-
|
|
732
|
+
fields.push({
|
|
733
|
+
kind: "NumberFormat",
|
|
734
|
+
default: CHART_NUMBER_DEFAULTS,
|
|
735
|
+
});
|
|
736
|
+
} else if (column_type === "datetime") {
|
|
737
|
+
fields.push({
|
|
738
|
+
kind: "DatetimeFormat",
|
|
739
|
+
default: CHART_DATETIME_DEFAULTS,
|
|
740
|
+
});
|
|
741
|
+
} else if (column_type === "date") {
|
|
742
|
+
fields.push({
|
|
743
|
+
kind: "DatetimeFormat",
|
|
744
|
+
default: CHART_DATE_DEFAULTS,
|
|
745
|
+
});
|
|
543
746
|
}
|
|
544
747
|
|
|
545
748
|
return { fields };
|
|
@@ -550,11 +753,62 @@ export class HTMLPerspectiveViewerWebGLPluginElement
|
|
|
550
753
|
group_rollup_mode?: string;
|
|
551
754
|
}) {
|
|
552
755
|
const defaults = this._effectiveDefaults();
|
|
553
|
-
const
|
|
554
|
-
|
|
756
|
+
const applicable = this._chartType.applicable_plugin_fields;
|
|
757
|
+
const present = new Set(applicable);
|
|
758
|
+
|
|
759
|
+
const grouped = new Set<PluginConfigField>();
|
|
760
|
+
const groups: Array<Record<string, unknown> & { kind: string }> = [];
|
|
761
|
+
for (const group of PLUGIN_FIELD_GROUPS) {
|
|
762
|
+
const members = group.fields.filter((k) => present.has(k));
|
|
763
|
+
if (members.length >= 1) {
|
|
764
|
+
for (const k of members) {
|
|
765
|
+
grouped.add(k);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
groups.push({
|
|
769
|
+
kind: "Group",
|
|
770
|
+
key: group.key,
|
|
771
|
+
fields: members.map((k) => fieldSpec(k, defaults)),
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
const fields: Array<Record<string, unknown> & { kind: string }> =
|
|
777
|
+
applicable
|
|
778
|
+
.filter((k) => !grouped.has(k))
|
|
779
|
+
.map((k) => fieldSpec(k, defaults));
|
|
780
|
+
|
|
781
|
+
return { fields: [...fields, ...groups] };
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
private _resolvedTheme(): Theme {
|
|
785
|
+
return resolveThemeFromVars(snapshotThemeVars(this));
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
private static readonly GRADIENT_PALETTE_FALLBACK_COUNT = 6;
|
|
789
|
+
|
|
790
|
+
private _themeSeriesPaletteHex(): string {
|
|
791
|
+
const theme = this._resolvedTheme();
|
|
792
|
+
const count =
|
|
793
|
+
theme.seriesPalette.length ||
|
|
794
|
+
HTMLPerspectiveViewerWebGLPluginElement.GRADIENT_PALETTE_FALLBACK_COUNT;
|
|
795
|
+
return colorsToCss(
|
|
796
|
+
resolvePalette(theme.seriesPalette, theme.gradientStops, count),
|
|
555
797
|
);
|
|
798
|
+
}
|
|
556
799
|
|
|
557
|
-
|
|
800
|
+
private _themeSeriesColorHex(idx: number): string {
|
|
801
|
+
const theme = this._resolvedTheme();
|
|
802
|
+
const count = Math.max(theme.seriesPalette.length, idx + 1);
|
|
803
|
+
return vec3ToHexColor(
|
|
804
|
+
resolvePalette(theme.seriesPalette, theme.gradientStops, count)[
|
|
805
|
+
idx
|
|
806
|
+
],
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
private _themeGradientStopsSpec(): string {
|
|
811
|
+
return stopsToCss(this._resolvedTheme().gradientStops);
|
|
558
812
|
}
|
|
559
813
|
|
|
560
814
|
async draw(view: View): Promise<void> {
|
|
@@ -21,8 +21,11 @@
|
|
|
21
21
|
// `a_color_start` / `a_color_end` carry the segment endpoints' raw
|
|
22
22
|
// color values (numeric data value for gradient, dictionary index for
|
|
23
23
|
// categorical). The gradient LUT is sampled using the same mapping the
|
|
24
|
-
// scatter shader uses — `
|
|
25
|
-
//
|
|
24
|
+
// scatter shader uses — `u_color_range` arrives PRE-SHAPED by the host:
|
|
25
|
+
// the symmetric sign-pivot range (`colorRangePivot`) for numeric
|
|
26
|
+
// columns, so linear normalization matches the CPU `colorValueToT`
|
|
27
|
+
// used by the legend / heatmap / tree charts; raw `[0, N-1]` extents
|
|
28
|
+
// for categorical index domains. The two endpoints' colors are
|
|
26
29
|
// averaged so the segment reads as a single chord in gradient space.
|
|
27
30
|
attribute vec2 a_start;
|
|
28
31
|
attribute vec2 a_end;
|
|
@@ -47,13 +47,6 @@ void main() {
|
|
|
47
47
|
|
|
48
48
|
v_point_size = gl_PointSize;
|
|
49
49
|
|
|
50
|
-
// Color-t mapping. Linear across `[cmin, cmax]` for single-sign
|
|
51
|
-
// domains (which includes categorical `[0, N-1]` split / string
|
|
52
|
-
// indices, so the colors match `interpolatePalette`'s even sampling
|
|
53
|
-
// used by the legend). When the domain actually crosses zero we
|
|
54
|
-
// switch to sign-aware so the value 0 always lands at the 50% stop
|
|
55
|
-
// of the diverging gradient — matching heatmap and the Canvas2D
|
|
56
|
-
// tooltip paths.
|
|
57
50
|
float cmin = u_color_range.x;
|
|
58
51
|
float cmax = u_color_range.y;
|
|
59
52
|
if(cmax <= cmin) {
|