@perspective-dev/viewer-charts 5.3.0 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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/cartesian/cartesian.d.ts +6 -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 +2 -0
- package/dist/esm/charts/chart.d.ts +77 -6
- package/dist/esm/charts/common/draw-tooltip-box.d.ts +2 -1
- package/dist/esm/charts/common/tree-interact.d.ts +1 -1
- 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.d.ts +6 -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 +20 -0
- package/dist/esm/theme/gradient.d.ts +1 -0
- package/dist/esm/transport/protocol.d.ts +45 -3
- package/dist/esm/transport/renderer-transport.d.ts +3 -0
- package/dist/esm/worker/renderer.worker.d.ts +19 -1
- package/package.json +6 -6
- 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-interact.ts +46 -40
- package/src/ts/charts/candlestick/candlestick-render.ts +73 -10
- package/src/ts/charts/cartesian/cartesian-interact.ts +9 -3
- package/src/ts/charts/cartesian/cartesian-render.ts +369 -75
- package/src/ts/charts/cartesian/cartesian.ts +9 -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 +34 -32
- package/src/ts/charts/chart.ts +106 -7
- package/src/ts/charts/common/draw-tooltip-box.ts +13 -30
- 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-interact.ts +65 -7
- package/src/ts/charts/heatmap/heatmap-render.ts +100 -24
- package/src/ts/charts/map/map.ts +3 -5
- package/src/ts/charts/series/series-build.ts +14 -2
- package/src/ts/charts/series/series-interact.ts +12 -11
- package/src/ts/charts/series/series-render.ts +305 -132
- package/src/ts/charts/series/series.ts +10 -0
- package/src/ts/charts/sunburst/sunburst-render.ts +7 -1
- package/src/ts/charts/treemap/treemap-render.ts +7 -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 +12 -0
- 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 +236 -67
- package/src/ts/shaders/line.vert.glsl +5 -2
- package/src/ts/shaders/scatter.vert.glsl +0 -7
- package/src/ts/theme/gradient.ts +24 -0
- package/src/ts/transport/protocol.ts +46 -2
- package/src/ts/transport/renderer-transport.ts +83 -4
- package/src/ts/worker/dispatch.ts +6 -2
- package/src/ts/worker/renderer.worker.ts +78 -2
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import type { CandlestickChart } from "./candlestick";
|
|
14
14
|
import { renderCandlestickChromeOverlay } from "./candlestick-render";
|
|
15
|
+
import { tooltipStyleOf } from "../../interaction/tooltip-grid";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Pixels of horizontal slack around the wick centerline so narrow
|
|
@@ -163,24 +164,24 @@ export function showCandlestickPinnedTooltip(
|
|
|
163
164
|
return;
|
|
164
165
|
}
|
|
165
166
|
|
|
166
|
-
const
|
|
167
|
-
if (
|
|
167
|
+
const grid = buildCandlestickTooltipLines(chart, idx);
|
|
168
|
+
if (grid.length === 0) {
|
|
168
169
|
return;
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
const xCenter = candles.xCenter[idx];
|
|
172
173
|
const yMid = (candles.high[idx] + candles.low[idx]) / 2;
|
|
173
174
|
const pos = chart._lastLayout.dataToPixel(xCenter, yMid);
|
|
174
|
-
|
|
175
|
-
// CSS bounds come from the chart's own layout, which is populated
|
|
176
|
-
// by the render path regardless of where the chart runs.
|
|
177
175
|
const cssWidth = chart._lastLayout.cssWidth;
|
|
178
176
|
const cssHeight = chart._lastLayout.cssHeight;
|
|
179
177
|
|
|
180
|
-
chart._tooltip.pin(
|
|
178
|
+
chart._tooltip.pin(
|
|
179
|
+
grid,
|
|
180
|
+
pos,
|
|
181
|
+
{ cssWidth, cssHeight },
|
|
182
|
+
tooltipStyleOf(chart._pluginConfig),
|
|
183
|
+
);
|
|
181
184
|
|
|
182
|
-
// Pinning hides the inline hover tooltip but does not change the
|
|
183
|
-
// WebGL pass — only the chrome overlay needs to redraw.
|
|
184
185
|
chart._hoveredIdx = -1;
|
|
185
186
|
renderCandlestickChromeOverlay(chart);
|
|
186
187
|
}
|
|
@@ -190,19 +191,14 @@ export function dismissCandlestickPinnedTooltip(chart: CandlestickChart): void {
|
|
|
190
191
|
chart._pinnedIdx = -1;
|
|
191
192
|
}
|
|
192
193
|
|
|
193
|
-
/**
|
|
194
|
-
* Build tooltip lines for candle at index `idx` in the columnar
|
|
195
|
-
* storage. Indexed access avoids materializing a `CandleRecord` POJO
|
|
196
|
-
* on the hot tooltip path.
|
|
197
|
-
*/
|
|
198
194
|
export function buildCandlestickTooltipLines(
|
|
199
195
|
chart: CandlestickChart,
|
|
200
196
|
idx: number,
|
|
201
|
-
): string[] {
|
|
202
|
-
const
|
|
197
|
+
): string[][] {
|
|
198
|
+
const grid: string[][] = [];
|
|
203
199
|
const candles = chart._candles;
|
|
204
200
|
if (idx < 0 || idx >= candles.count) {
|
|
205
|
-
return
|
|
201
|
+
return grid;
|
|
206
202
|
}
|
|
207
203
|
|
|
208
204
|
const catIdx = candles.catIdx[idx];
|
|
@@ -212,6 +208,34 @@ export function buildCandlestickTooltipLines(
|
|
|
212
208
|
const high = candles.high[idx];
|
|
213
209
|
const low = candles.low[idx];
|
|
214
210
|
|
|
211
|
+
const categoryText = candleCategoryText(chart, catIdx);
|
|
212
|
+
if (categoryText !== "") {
|
|
213
|
+
grid.push([categoryText]);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (splitIdx >= 0 && chart._splitPrefixes.length > 1) {
|
|
217
|
+
const prefix = chart._splitPrefixes[splitIdx];
|
|
218
|
+
if (prefix) {
|
|
219
|
+
grid.push([prefix]);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const openFmt = chart.getColumnFormatter(chart._columnSlots[0], "value");
|
|
224
|
+
const closeFmt = chart.getColumnFormatter(chart._columnSlots[1], "value");
|
|
225
|
+
const highFmt = chart.getColumnFormatter(chart._columnSlots[2], "value");
|
|
226
|
+
const lowFmt = chart.getColumnFormatter(chart._columnSlots[3], "value");
|
|
227
|
+
grid.push(["Open", openFmt(open)]);
|
|
228
|
+
grid.push(["Close", closeFmt(close)]);
|
|
229
|
+
grid.push(["High", highFmt(high)]);
|
|
230
|
+
grid.push(["Low", lowFmt(low)]);
|
|
231
|
+
|
|
232
|
+
return grid;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function candleCategoryText(
|
|
236
|
+
chart: CandlestickChart,
|
|
237
|
+
catIdx: number,
|
|
238
|
+
): string {
|
|
215
239
|
if (
|
|
216
240
|
chart._categoryAxisMode === "numeric" &&
|
|
217
241
|
chart._numericCategoryDomain &&
|
|
@@ -219,8 +243,10 @@ export function buildCandlestickTooltipLines(
|
|
|
219
243
|
) {
|
|
220
244
|
const v = chart._categoryPositions[catIdx];
|
|
221
245
|
const xColumn = chart._groupBy[0];
|
|
222
|
-
|
|
223
|
-
}
|
|
246
|
+
return chart.getColumnFormatter(xColumn, "value")(v);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (chart._rowPaths.length > 0) {
|
|
224
250
|
const parts: string[] = [];
|
|
225
251
|
for (const rp of chart._rowPaths) {
|
|
226
252
|
const s = rp.labels[catIdx] ?? "";
|
|
@@ -229,28 +255,8 @@ export function buildCandlestickTooltipLines(
|
|
|
229
255
|
}
|
|
230
256
|
}
|
|
231
257
|
|
|
232
|
-
|
|
233
|
-
lines.push(parts.join(" › "));
|
|
234
|
-
}
|
|
235
|
-
} else {
|
|
236
|
-
lines.push(`Row ${catIdx + chart._rowOffset}`);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (splitIdx >= 0 && chart._splitPrefixes.length > 1) {
|
|
240
|
-
const prefix = chart._splitPrefixes[splitIdx];
|
|
241
|
-
if (prefix) {
|
|
242
|
-
lines.push(prefix);
|
|
243
|
-
}
|
|
258
|
+
return parts.join(" › ");
|
|
244
259
|
}
|
|
245
260
|
|
|
246
|
-
|
|
247
|
-
const closeFmt = chart.getColumnFormatter(chart._columnSlots[1], "value");
|
|
248
|
-
const highFmt = chart.getColumnFormatter(chart._columnSlots[2], "value");
|
|
249
|
-
const lowFmt = chart.getColumnFormatter(chart._columnSlots[3], "value");
|
|
250
|
-
lines.push(`Open: ${openFmt(open)}`);
|
|
251
|
-
lines.push(`Close: ${closeFmt(close)}`);
|
|
252
|
-
lines.push(`High: ${highFmt(high)}`);
|
|
253
|
-
lines.push(`Low: ${lowFmt(low)}`);
|
|
254
|
-
|
|
255
|
-
return lines;
|
|
261
|
+
return `Row ${catIdx + chart._rowOffset}`;
|
|
256
262
|
}
|
|
@@ -16,7 +16,12 @@ import { PlotLayout } from "../../layout/plot-layout";
|
|
|
16
16
|
import { sampleGradient } from "../../theme/gradient";
|
|
17
17
|
import { renderInPlotFrame } from "../../webgl/plot-frame";
|
|
18
18
|
import { renderCanvasTooltip } from "../../interaction/tooltip-controller";
|
|
19
|
-
import {
|
|
19
|
+
import { tooltipStyleOf } from "../../interaction/tooltip-grid";
|
|
20
|
+
import {
|
|
21
|
+
renderAxisHoverIndicators,
|
|
22
|
+
type AxisIndicator,
|
|
23
|
+
} from "../../interaction/axis-indicators";
|
|
24
|
+
import { computeNiceTicks, stepTickFormatter } from "../../layout/ticks";
|
|
20
25
|
import { type AxisDomain } from "../../axis/numeric-axis";
|
|
21
26
|
import {
|
|
22
27
|
renderBarAxesChrome,
|
|
@@ -27,7 +32,10 @@ import {
|
|
|
27
32
|
measureCategoricalAxisHeight,
|
|
28
33
|
type CategoricalDomain,
|
|
29
34
|
} from "../../axis/categorical-axis";
|
|
30
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
buildCandlestickTooltipLines,
|
|
37
|
+
candleCategoryText,
|
|
38
|
+
} from "./candlestick-interact";
|
|
31
39
|
import {
|
|
32
40
|
computeVisibleExtent,
|
|
33
41
|
type VisibleExtent,
|
|
@@ -321,18 +329,73 @@ function renderCandlestickTooltip(chart: CandlestickChart): void {
|
|
|
321
329
|
const pos = layout.dataToPixel(xCenter, yMid);
|
|
322
330
|
const lines = buildCandlestickTooltipLines(chart, i);
|
|
323
331
|
const theme = chart._resolveTheme();
|
|
324
|
-
|
|
332
|
+
const dpr = chart._glManager?.dpr ?? 1;
|
|
333
|
+
|
|
334
|
+
let valueColumn = chart._columnSlots[1];
|
|
335
|
+
let value = candles.close[i];
|
|
336
|
+
if (valueColumn == null || !Number.isFinite(value)) {
|
|
337
|
+
valueColumn =
|
|
338
|
+
chart._columnSlots[0] ??
|
|
339
|
+
chart._columnSlots[2] ??
|
|
340
|
+
chart._columnSlots[3];
|
|
341
|
+
value = candles.open[i];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const datumPos = layout.dataToPixel(xCenter, value);
|
|
345
|
+
const indicators: AxisIndicator[] = [];
|
|
346
|
+
|
|
347
|
+
let categoryText: string;
|
|
348
|
+
if (
|
|
349
|
+
chart._categoryAxisMode === "numeric" &&
|
|
350
|
+
chart._numericCategoryDomain &&
|
|
351
|
+
chart._categoryPositions
|
|
352
|
+
) {
|
|
353
|
+
const catFmt =
|
|
354
|
+
chart.getColumnFormatter(chart._groupBy[0], "tick") ??
|
|
355
|
+
stepTickFormatter(
|
|
356
|
+
chart._numericCategoryDomain.isDate,
|
|
357
|
+
chart._lastCatTicks,
|
|
358
|
+
);
|
|
359
|
+
categoryText = catFmt(chart._categoryPositions[candles.catIdx[i]]);
|
|
360
|
+
} else {
|
|
361
|
+
categoryText = candleCategoryText(chart, candles.catIdx[i]);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (categoryText !== "") {
|
|
365
|
+
indicators.push({
|
|
366
|
+
side: "bottom",
|
|
367
|
+
px: datumPos.px,
|
|
368
|
+
py: datumPos.py,
|
|
369
|
+
text: categoryText,
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (Number.isFinite(value)) {
|
|
374
|
+
const valueFmt =
|
|
375
|
+
chart.getColumnFormatter(valueColumn, "tick") ??
|
|
376
|
+
stepTickFormatter(chart._lastYDomain?.isDate, chart._lastYTicks);
|
|
377
|
+
indicators.push({
|
|
378
|
+
side: "left",
|
|
379
|
+
px: datumPos.px,
|
|
380
|
+
py: datumPos.py,
|
|
381
|
+
text: valueFmt(value),
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
renderAxisHoverIndicators(
|
|
325
386
|
chart._chromeCanvas,
|
|
326
|
-
pos,
|
|
327
|
-
lines,
|
|
328
387
|
layout,
|
|
329
388
|
theme,
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
highlightRadius: 0,
|
|
334
|
-
},
|
|
389
|
+
dpr,
|
|
390
|
+
indicators,
|
|
391
|
+
chart._pluginConfig.tooltip_opacity,
|
|
335
392
|
);
|
|
393
|
+
|
|
394
|
+
renderCanvasTooltip(chart._chromeCanvas, pos, lines, layout, theme, dpr, {
|
|
395
|
+
...tooltipStyleOf(chart._pluginConfig),
|
|
396
|
+
crosshair: false,
|
|
397
|
+
highlightRadius: 0,
|
|
398
|
+
});
|
|
336
399
|
}
|
|
337
400
|
|
|
338
401
|
/**
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import type { CartesianChart } from "./cartesian";
|
|
14
14
|
import { renderCartesianChromeOverlay } from "./cartesian-render";
|
|
15
|
+
import { tooltipStyleOf } from "../../interaction/tooltip-grid";
|
|
15
16
|
|
|
16
17
|
const TOOLTIP_RADIUS_PX = 24;
|
|
17
18
|
|
|
@@ -311,7 +312,7 @@ export function showCartesianPinnedTooltip(
|
|
|
311
312
|
);
|
|
312
313
|
|
|
313
314
|
const serial = chart._lazyTooltip.beginPin();
|
|
314
|
-
chart.glyph.buildTooltipLines(chart, pointIdx).then((
|
|
315
|
+
chart.glyph.buildTooltipLines(chart, pointIdx).then((grid) => {
|
|
315
316
|
// Abandon the pin if the user moved on (another pin/dismiss
|
|
316
317
|
// between click and resolve) or the underlying view changed.
|
|
317
318
|
if (!chart._lazyTooltip.isPinFresh(serial)) {
|
|
@@ -322,11 +323,16 @@ export function showCartesianPinnedTooltip(
|
|
|
322
323
|
return;
|
|
323
324
|
}
|
|
324
325
|
|
|
325
|
-
if (
|
|
326
|
+
if (grid.length === 0) {
|
|
326
327
|
return;
|
|
327
328
|
}
|
|
328
329
|
|
|
329
|
-
chart._tooltip.pin(
|
|
330
|
+
chart._tooltip.pin(
|
|
331
|
+
grid,
|
|
332
|
+
pos,
|
|
333
|
+
layout,
|
|
334
|
+
tooltipStyleOf(chart._pluginConfig),
|
|
335
|
+
);
|
|
330
336
|
});
|
|
331
337
|
|
|
332
338
|
chart._hoveredIndex = -1;
|