@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
|
@@ -12,6 +12,13 @@
|
|
|
12
12
|
|
|
13
13
|
import type { Context2D } from "../canvas-types";
|
|
14
14
|
import type { Theme } from "../../theme/theme";
|
|
15
|
+
import {
|
|
16
|
+
measureTooltipGrid,
|
|
17
|
+
paintTooltipGrid,
|
|
18
|
+
DEFAULT_TOOLTIP_STYLE,
|
|
19
|
+
type TooltipContent,
|
|
20
|
+
type TooltipStyle,
|
|
21
|
+
} from "../../interaction/tooltip-grid";
|
|
15
22
|
|
|
16
23
|
/**
|
|
17
24
|
* Draw a freestanding tooltip box anchored near (cx, cy), measuring
|
|
@@ -22,32 +29,21 @@ import type { Theme } from "../../theme/theme";
|
|
|
22
29
|
export function drawTooltipBox(
|
|
23
30
|
ctx: Context2D,
|
|
24
31
|
theme: Theme,
|
|
25
|
-
|
|
32
|
+
grid: TooltipContent,
|
|
26
33
|
cx: number,
|
|
27
34
|
cy: number,
|
|
28
35
|
cssWidth: number,
|
|
29
36
|
cssHeight: number,
|
|
30
37
|
fontFamily: string,
|
|
38
|
+
style: TooltipStyle = DEFAULT_TOOLTIP_STYLE,
|
|
31
39
|
): void {
|
|
32
|
-
if (
|
|
40
|
+
if (grid.length === 0) {
|
|
33
41
|
return;
|
|
34
42
|
}
|
|
35
43
|
|
|
36
|
-
const { tooltipBg, tooltipText, tooltipBorder } = theme;
|
|
37
|
-
|
|
38
44
|
ctx.font = `11px ${fontFamily}`;
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
let maxWidth = 0;
|
|
42
|
-
for (const line of lines) {
|
|
43
|
-
const w = ctx.measureText(line).width;
|
|
44
|
-
if (w > maxWidth) {
|
|
45
|
-
maxWidth = w;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const boxW = maxWidth + padding * 2;
|
|
50
|
-
const boxH = lines.length * lineHeight + padding * 2 - 4;
|
|
45
|
+
const measured = measureTooltipGrid(ctx, grid, style.maxColumnPx);
|
|
46
|
+
const { boxW, boxH } = measured;
|
|
51
47
|
|
|
52
48
|
let tx = cx + 12;
|
|
53
49
|
let ty = cy - boxH - 8;
|
|
@@ -67,18 +63,5 @@ export function drawTooltipBox(
|
|
|
67
63
|
ty = cssHeight - boxH - 4;
|
|
68
64
|
}
|
|
69
65
|
|
|
70
|
-
ctx
|
|
71
|
-
ctx.strokeStyle = tooltipBorder;
|
|
72
|
-
ctx.lineWidth = 1;
|
|
73
|
-
ctx.beginPath();
|
|
74
|
-
ctx.roundRect(tx, ty, boxW, boxH, 4);
|
|
75
|
-
ctx.fill();
|
|
76
|
-
ctx.stroke();
|
|
77
|
-
|
|
78
|
-
ctx.fillStyle = tooltipText;
|
|
79
|
-
ctx.textAlign = "left";
|
|
80
|
-
ctx.textBaseline = "top";
|
|
81
|
-
for (let i = 0; i < lines.length; i++) {
|
|
82
|
-
ctx.fillText(lines[i], tx + padding, ty + padding + i * lineHeight);
|
|
83
|
-
}
|
|
66
|
+
paintTooltipGrid(ctx, measured, tx, ty, theme, style.opacity);
|
|
84
67
|
}
|
|
@@ -40,6 +40,10 @@ export function firstNonMetadataColumn(columns: ColumnDataMap): string {
|
|
|
40
40
|
* layout modules can read/write them without friction.
|
|
41
41
|
*/
|
|
42
42
|
export abstract class TreeChartBase extends AbstractChart {
|
|
43
|
+
protected override colorScaleColumn(): string | null {
|
|
44
|
+
return this._columnSlots[1] || null;
|
|
45
|
+
}
|
|
46
|
+
|
|
43
47
|
// Shared column-slot resolution
|
|
44
48
|
_sizeName = "";
|
|
45
49
|
_colorName = "";
|
|
@@ -17,12 +17,21 @@ import type { GradientStop } from "../../theme/gradient";
|
|
|
17
17
|
import type { Vec3 } from "../../theme/palette";
|
|
18
18
|
import type { Theme } from "../../theme/theme";
|
|
19
19
|
import {
|
|
20
|
+
gradientLegendAutoFit,
|
|
21
|
+
legendAutoFit,
|
|
20
22
|
renderCategoricalLegend,
|
|
21
23
|
renderCategoricalLegendAt,
|
|
22
24
|
renderLegend,
|
|
25
|
+
renderLegendAt,
|
|
26
|
+
type LegendPaintView,
|
|
23
27
|
} from "../../axis/legend";
|
|
28
|
+
import {
|
|
29
|
+
legendSidebarWidth,
|
|
30
|
+
resolveLegendMode,
|
|
31
|
+
} from "../../interaction/legend-controller";
|
|
24
32
|
import type { TreeChartBase } from "./tree-chart";
|
|
25
33
|
import { drawTooltipBox } from "./draw-tooltip-box";
|
|
34
|
+
import { tooltipStyleOf } from "../../interaction/tooltip-grid";
|
|
26
35
|
|
|
27
36
|
/**
|
|
28
37
|
* Click target for one breadcrumb segment. Tree-chart hit-testing
|
|
@@ -112,23 +121,24 @@ export function renderTreeTooltip(
|
|
|
112
121
|
cssHeight: number,
|
|
113
122
|
fontFamily: string,
|
|
114
123
|
): void {
|
|
115
|
-
const
|
|
124
|
+
const grid =
|
|
116
125
|
chart._lazyTooltip.hoveredTarget === nodeId
|
|
117
|
-
? (chart._lazyTooltip.
|
|
126
|
+
? (chart._lazyTooltip.grid ?? [])
|
|
118
127
|
: [];
|
|
119
|
-
if (
|
|
128
|
+
if (grid.length === 0) {
|
|
120
129
|
return;
|
|
121
130
|
}
|
|
122
131
|
|
|
123
132
|
drawTooltipBox(
|
|
124
133
|
ctx,
|
|
125
134
|
chart._resolveTheme(),
|
|
126
|
-
|
|
135
|
+
grid,
|
|
127
136
|
cx,
|
|
128
137
|
cy,
|
|
129
138
|
cssWidth,
|
|
130
139
|
cssHeight,
|
|
131
140
|
fontFamily,
|
|
141
|
+
tooltipStyleOf(chart._pluginConfig),
|
|
132
142
|
);
|
|
133
143
|
}
|
|
134
144
|
|
|
@@ -159,50 +169,119 @@ export function renderTreeColorLegend(
|
|
|
159
169
|
cssHeight: number,
|
|
160
170
|
categoricalRect: PlotRect | null = null,
|
|
161
171
|
): void {
|
|
162
|
-
|
|
163
|
-
|
|
172
|
+
const cfg = chart._pluginConfig;
|
|
173
|
+
const hasCategorical =
|
|
174
|
+
chart._colorMode === "series" && chart._uniqueColorLabels.size > 1;
|
|
175
|
+
const hasNumeric =
|
|
176
|
+
chart._colorMode === "numeric" && chart._colorMin < chart._colorMax;
|
|
177
|
+
const mode = resolveLegendMode(
|
|
178
|
+
cfg,
|
|
179
|
+
hasCategorical ? chart._uniqueColorLabels.size : 0,
|
|
180
|
+
);
|
|
181
|
+
if (mode === "none" || (!hasCategorical && !hasNumeric)) {
|
|
182
|
+
chart._legend.clearPainted();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const floating = mode === "floating";
|
|
187
|
+
const view: LegendPaintView = {
|
|
188
|
+
mode: floating ? "floating" : "sidebar",
|
|
189
|
+
legend: chart._legend,
|
|
190
|
+
title: chart._colorName || "Legend",
|
|
191
|
+
opacity: cfg.legend_opacity,
|
|
192
|
+
};
|
|
193
|
+
const floatBox = floating
|
|
194
|
+
? chart._legend.floatingBox(
|
|
195
|
+
cfg,
|
|
196
|
+
cssWidth,
|
|
197
|
+
cssHeight,
|
|
198
|
+
hasCategorical
|
|
199
|
+
? legendAutoFit(
|
|
200
|
+
canvas,
|
|
201
|
+
theme,
|
|
202
|
+
chart._uniqueColorLabels.size,
|
|
203
|
+
() => chart._uniqueColorLabels.keys(),
|
|
204
|
+
{ title: view.title },
|
|
205
|
+
)
|
|
206
|
+
: gradientLegendAutoFit(
|
|
207
|
+
canvas,
|
|
208
|
+
theme,
|
|
209
|
+
{ min: chart._colorMin, max: chart._colorMax },
|
|
210
|
+
undefined,
|
|
211
|
+
view.title,
|
|
212
|
+
),
|
|
213
|
+
)
|
|
214
|
+
: null;
|
|
215
|
+
|
|
216
|
+
if (hasCategorical) {
|
|
217
|
+
if (floatBox) {
|
|
218
|
+
renderCategoricalLegendAt(
|
|
219
|
+
canvas,
|
|
220
|
+
floatBox,
|
|
221
|
+
chart._uniqueColorLabels,
|
|
222
|
+
palette,
|
|
223
|
+
theme,
|
|
224
|
+
view,
|
|
225
|
+
);
|
|
226
|
+
} else if (categoricalRect) {
|
|
164
227
|
renderCategoricalLegendAt(
|
|
165
228
|
canvas,
|
|
166
229
|
categoricalRect,
|
|
167
230
|
chart._uniqueColorLabels,
|
|
168
231
|
palette,
|
|
169
232
|
theme,
|
|
233
|
+
{ ...view, sidebarGutter: categoricalRect.width },
|
|
170
234
|
);
|
|
171
235
|
} else {
|
|
172
236
|
renderCategoricalLegend(
|
|
173
237
|
canvas,
|
|
174
|
-
syntheticLegendLayout(cssWidth, cssHeight),
|
|
238
|
+
syntheticLegendLayout(cssWidth, cssHeight, cfg),
|
|
175
239
|
chart._uniqueColorLabels,
|
|
176
240
|
palette,
|
|
177
241
|
theme,
|
|
242
|
+
view,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
const colorDomain = {
|
|
247
|
+
min: chart._colorMin,
|
|
248
|
+
max: chart._colorMax,
|
|
249
|
+
label: chart._colorName,
|
|
250
|
+
};
|
|
251
|
+
const formatter = chart.getColumnFormatter(chart._colorName, "value");
|
|
252
|
+
if (floatBox) {
|
|
253
|
+
renderLegendAt(
|
|
254
|
+
canvas,
|
|
255
|
+
floatBox,
|
|
256
|
+
colorDomain,
|
|
257
|
+
stops,
|
|
258
|
+
theme,
|
|
259
|
+
formatter,
|
|
260
|
+
view,
|
|
261
|
+
);
|
|
262
|
+
} else {
|
|
263
|
+
renderLegend(
|
|
264
|
+
canvas,
|
|
265
|
+
syntheticLegendLayout(cssWidth, cssHeight, cfg),
|
|
266
|
+
colorDomain,
|
|
267
|
+
stops,
|
|
268
|
+
theme,
|
|
269
|
+
formatter,
|
|
270
|
+
view,
|
|
178
271
|
);
|
|
179
272
|
}
|
|
180
|
-
} else if (
|
|
181
|
-
chart._colorMode === "numeric" &&
|
|
182
|
-
chart._colorMin < chart._colorMax
|
|
183
|
-
) {
|
|
184
|
-
renderLegend(
|
|
185
|
-
canvas,
|
|
186
|
-
syntheticLegendLayout(cssWidth, cssHeight),
|
|
187
|
-
{
|
|
188
|
-
min: chart._colorMin,
|
|
189
|
-
max: chart._colorMax,
|
|
190
|
-
label: chart._colorName,
|
|
191
|
-
},
|
|
192
|
-
stops,
|
|
193
|
-
theme,
|
|
194
|
-
chart.getColumnFormatter(chart._colorName, "value"),
|
|
195
|
-
);
|
|
196
273
|
}
|
|
197
274
|
}
|
|
198
275
|
|
|
199
276
|
function syntheticLegendLayout(
|
|
200
277
|
cssWidth: number,
|
|
201
278
|
cssHeight: number,
|
|
279
|
+
cfg: TreeChartBase["_pluginConfig"],
|
|
202
280
|
): PlotLayout {
|
|
203
281
|
return new PlotLayout(cssWidth, cssHeight, {
|
|
204
282
|
hasXLabel: false,
|
|
205
283
|
hasYLabel: false,
|
|
206
284
|
hasLegend: true,
|
|
285
|
+
rightExtra: legendSidebarWidth(cfg, 80),
|
|
207
286
|
});
|
|
208
287
|
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import type { TreeChartBase } from "./tree-chart";
|
|
14
14
|
import { NULL_NODE, ancestorNames } from "./node-store";
|
|
15
15
|
import { rebuildBreadcrumbs } from "./tree-data";
|
|
16
|
+
import { tooltipStyleOf } from "../../interaction/tooltip-grid";
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Common subset of `TreemapChart` / `SunburstChart` reached by the
|
|
@@ -73,9 +74,9 @@ export async function emitTreeNodeEvent(
|
|
|
73
74
|
export async function buildTreeTooltipLines(
|
|
74
75
|
chart: TreeInteractChart,
|
|
75
76
|
nodeId: number,
|
|
76
|
-
): Promise<string[]> {
|
|
77
|
+
): Promise<string[][]> {
|
|
77
78
|
const store = chart._nodeStore;
|
|
78
|
-
const
|
|
79
|
+
const grid: string[][] = [];
|
|
79
80
|
|
|
80
81
|
const pathNames: string[] = [];
|
|
81
82
|
let p = nodeId;
|
|
@@ -86,19 +87,17 @@ export async function buildTreeTooltipLines(
|
|
|
86
87
|
|
|
87
88
|
pathNames.reverse();
|
|
88
89
|
if (pathNames.length > 0) {
|
|
89
|
-
|
|
90
|
+
grid.push([pathNames.join(" › ")]);
|
|
90
91
|
} else {
|
|
91
|
-
|
|
92
|
+
grid.push([store.name[nodeId]]);
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
const sizeFmt = chart.getColumnFormatter(chart._sizeName, "value");
|
|
95
|
-
|
|
96
|
+
grid.push(["Value", sizeFmt(store.value[nodeId])]);
|
|
96
97
|
|
|
97
98
|
if (chart._colorName && !isNaN(store.colorValue[nodeId])) {
|
|
98
99
|
const colorFmt = chart.getColumnFormatter(chart._colorName, "value");
|
|
99
|
-
|
|
100
|
-
`${chart._colorName}: ${colorFmt(store.colorValue[nodeId])}`,
|
|
101
|
-
);
|
|
100
|
+
grid.push([chart._colorName, colorFmt(store.colorValue[nodeId])]);
|
|
102
101
|
}
|
|
103
102
|
|
|
104
103
|
const rowIdx = store.leafRowIdx[nodeId];
|
|
@@ -117,20 +116,21 @@ export async function buildTreeTooltipLines(
|
|
|
117
116
|
}
|
|
118
117
|
|
|
119
118
|
if (typeof value === "number") {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
grid.push([
|
|
120
|
+
name,
|
|
121
|
+
chart.getColumnFormatter(name, "value")(value),
|
|
122
|
+
]);
|
|
123
123
|
} else {
|
|
124
|
-
|
|
124
|
+
grid.push([name, String(value)]);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
if (store.firstChild[nodeId] !== NULL_NODE) {
|
|
130
|
-
|
|
130
|
+
grid.push(["Children", String(store.childCount[nodeId])]);
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
return
|
|
133
|
+
return grid;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/**
|
|
@@ -150,19 +150,20 @@ export function showTreePinnedTooltip(
|
|
|
150
150
|
const cssWidth = chart._glManager?.cssWidth ?? 0;
|
|
151
151
|
const cssHeight = chart._glManager?.cssHeight ?? 0;
|
|
152
152
|
|
|
153
|
-
buildTreeTooltipLines(chart, nodeId).then((
|
|
153
|
+
buildTreeTooltipLines(chart, nodeId).then((grid) => {
|
|
154
154
|
if (chart._pinnedNodeId !== nodeId) {
|
|
155
155
|
return;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
if (
|
|
158
|
+
if (grid.length === 0) {
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
chart._tooltip.pin(
|
|
163
|
-
|
|
163
|
+
grid,
|
|
164
164
|
{ px: anchor.cx, py: anchor.cy },
|
|
165
165
|
{ cssWidth, cssHeight },
|
|
166
|
+
tooltipStyleOf(chart._pluginConfig),
|
|
166
167
|
);
|
|
167
168
|
});
|
|
168
169
|
|
|
@@ -128,7 +128,13 @@ export function buildHeatmapPipeline(
|
|
|
128
128
|
rowPaths: xLevels,
|
|
129
129
|
numCategories: numX,
|
|
130
130
|
rowOffset,
|
|
131
|
-
} = resolveCategoryAxis(
|
|
131
|
+
} = resolveCategoryAxis(
|
|
132
|
+
columns,
|
|
133
|
+
numRows,
|
|
134
|
+
groupBy.length,
|
|
135
|
+
levelTypes,
|
|
136
|
+
xAxisMode,
|
|
137
|
+
);
|
|
132
138
|
|
|
133
139
|
// Numeric X domain: sourced from `__ROW_PATH_0__`'s raw values when
|
|
134
140
|
// the single group_by is non-string.
|
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
import type { HeatmapChart } from "./heatmap";
|
|
14
14
|
import type { HeatmapCell } from "./heatmap-build";
|
|
15
15
|
import { renderCanvasTooltip } from "../../interaction/tooltip-controller";
|
|
16
|
+
import {
|
|
17
|
+
renderAxisHoverIndicators,
|
|
18
|
+
type AxisIndicator,
|
|
19
|
+
} from "../../interaction/axis-indicators";
|
|
20
|
+
import { computeNiceTicks, stepTickFormatter } from "../../layout/ticks";
|
|
21
|
+
import { tooltipStyleOf } from "../../interaction/tooltip-grid";
|
|
16
22
|
import type { CategoricalLevel } from "../../axis/categorical-axis";
|
|
17
23
|
|
|
18
24
|
/**
|
|
@@ -215,6 +221,9 @@ export function renderHeatmapTooltip(chart: HeatmapChart): void {
|
|
|
215
221
|
let layout: import("../../layout/plot-layout").PlotLayout | null;
|
|
216
222
|
let xLevels: CategoricalLevel[];
|
|
217
223
|
let yLevels: CategoricalLevel[];
|
|
224
|
+
let xPositions: Float64Array | null;
|
|
225
|
+
let yPositions: Float64Array | null;
|
|
226
|
+
let xNumericDomain: { isDate?: boolean } | null;
|
|
218
227
|
let facetLabel: string | null = null;
|
|
219
228
|
|
|
220
229
|
if (chart._hoveredFacetIdx >= 0) {
|
|
@@ -226,6 +235,9 @@ export function renderHeatmapTooltip(chart: HeatmapChart): void {
|
|
|
226
235
|
layout = facet.layout;
|
|
227
236
|
xLevels = facet.pipeline.xLevels;
|
|
228
237
|
yLevels = facet.pipeline.yLevels;
|
|
238
|
+
xPositions = facet.pipeline.xPositions;
|
|
239
|
+
yPositions = facet.pipeline.yPositions;
|
|
240
|
+
xNumericDomain = facet.pipeline.xNumericDomain;
|
|
229
241
|
facetLabel = facet.label;
|
|
230
242
|
} else {
|
|
231
243
|
if (!chart._lastLayout) {
|
|
@@ -235,6 +247,9 @@ export function renderHeatmapTooltip(chart: HeatmapChart): void {
|
|
|
235
247
|
layout = chart._lastLayout;
|
|
236
248
|
xLevels = chart._xLevels;
|
|
237
249
|
yLevels = chart._yLevels;
|
|
250
|
+
xPositions = chart._xPositions;
|
|
251
|
+
yPositions = chart._yPositions;
|
|
252
|
+
xNumericDomain = chart._xNumericDomain;
|
|
238
253
|
}
|
|
239
254
|
|
|
240
255
|
const cell = chart._hoveredCell;
|
|
@@ -244,31 +259,83 @@ export function renderHeatmapTooltip(chart: HeatmapChart): void {
|
|
|
244
259
|
// many pixels.
|
|
245
260
|
const pos = { px: chart._hoveredMouseX, py: chart._hoveredMouseY };
|
|
246
261
|
|
|
247
|
-
const
|
|
262
|
+
const grid: string[][] = [];
|
|
248
263
|
if (facetLabel) {
|
|
249
|
-
|
|
264
|
+
grid.push([facetLabel]);
|
|
250
265
|
}
|
|
251
266
|
|
|
252
|
-
const xPath =
|
|
267
|
+
const xPath =
|
|
268
|
+
chart._xAxisMode.mode === "numeric" && xPositions
|
|
269
|
+
? chart.getColumnFormatter(
|
|
270
|
+
chart._groupBy[0],
|
|
271
|
+
"value",
|
|
272
|
+
)(xPositions[cell.xIdx])
|
|
273
|
+
: formatHierarchicalPath(xLevels, cell.xIdx);
|
|
253
274
|
const yPath = formatHierarchicalPath(yLevels, cell.yIdx);
|
|
254
275
|
if (xPath) {
|
|
255
|
-
|
|
276
|
+
grid.push([xPath]);
|
|
256
277
|
}
|
|
257
278
|
|
|
258
279
|
if (yPath) {
|
|
259
|
-
|
|
280
|
+
grid.push([yPath]);
|
|
260
281
|
}
|
|
261
282
|
|
|
262
283
|
const valueFmt = chart.getColumnFormatter(chart._columnSlots[0], "value");
|
|
263
|
-
|
|
284
|
+
grid.push(["Value", valueFmt(cell.value)]);
|
|
264
285
|
|
|
265
286
|
const theme = chart._resolveTheme();
|
|
287
|
+
const dpr = chart._glManager?.dpr ?? 1;
|
|
288
|
+
|
|
289
|
+
const cellPos = layout.dataToPixel(
|
|
290
|
+
xPositions ? xPositions[cell.xIdx] : cell.xIdx,
|
|
291
|
+
yPositions ? yPositions[cell.yIdx] : cell.yIdx,
|
|
292
|
+
);
|
|
293
|
+
const badgeX =
|
|
294
|
+
chart._xAxisMode.mode === "numeric" && xPositions
|
|
295
|
+
? (
|
|
296
|
+
chart.getColumnFormatter(chart._groupBy[0], "tick") ??
|
|
297
|
+
stepTickFormatter(
|
|
298
|
+
xNumericDomain?.isDate,
|
|
299
|
+
computeNiceTicks(layout.paddedXMin, layout.paddedXMax, 6),
|
|
300
|
+
)
|
|
301
|
+
)(xPositions[cell.xIdx])
|
|
302
|
+
: xPath;
|
|
303
|
+
|
|
304
|
+
const indicators: AxisIndicator[] = [];
|
|
305
|
+
if (badgeX) {
|
|
306
|
+
indicators.push({
|
|
307
|
+
side: "bottom",
|
|
308
|
+
px: cellPos.px,
|
|
309
|
+
py: cellPos.py,
|
|
310
|
+
text: badgeX,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (yPath) {
|
|
315
|
+
indicators.push({
|
|
316
|
+
side: "left",
|
|
317
|
+
px: cellPos.px,
|
|
318
|
+
py: cellPos.py,
|
|
319
|
+
text: yPath,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
renderAxisHoverIndicators(
|
|
324
|
+
chart._chromeCanvas,
|
|
325
|
+
layout,
|
|
326
|
+
theme,
|
|
327
|
+
dpr,
|
|
328
|
+
indicators,
|
|
329
|
+
chart._pluginConfig.tooltip_opacity,
|
|
330
|
+
);
|
|
331
|
+
|
|
266
332
|
renderCanvasTooltip(
|
|
267
333
|
chart._chromeCanvas,
|
|
268
334
|
pos,
|
|
269
|
-
|
|
335
|
+
grid,
|
|
270
336
|
layout,
|
|
271
337
|
theme,
|
|
272
|
-
|
|
338
|
+
dpr,
|
|
339
|
+
tooltipStyleOf(chart._pluginConfig),
|
|
273
340
|
);
|
|
274
341
|
}
|