@perspective-dev/viewer-charts 4.5.1 → 5.0.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.
Files changed (70) hide show
  1. package/dist/cdn/perspective-viewer-charts.js +2 -2
  2. package/dist/cdn/perspective-viewer-charts.js.map +3 -3
  3. package/dist/esm/charts/candlestick/candlestick.d.ts +8 -10
  4. package/dist/esm/charts/chart-base.d.ts +58 -4
  5. package/dist/esm/charts/chart.d.ts +45 -9
  6. package/dist/esm/charts/series/glyphs/draw-areas.d.ts +3 -2
  7. package/dist/esm/charts/series/glyphs/draw-bars.d.ts +8 -1
  8. package/dist/esm/charts/series/glyphs/draw-lines.d.ts +3 -2
  9. package/dist/esm/charts/series/glyphs/draw-scatter.d.ts +5 -2
  10. package/dist/esm/charts/series/series-build.d.ts +11 -0
  11. package/dist/esm/charts/series/series-interact.d.ts +10 -0
  12. package/dist/esm/charts/series/series-render.d.ts +17 -1
  13. package/dist/esm/charts/series/series.d.ts +53 -10
  14. package/dist/esm/config.d.ts +19 -0
  15. package/dist/esm/data/view-reader.d.ts +10 -1
  16. package/dist/esm/event-detail.d.ts +7 -0
  17. package/dist/esm/layout/ticks.d.ts +5 -0
  18. package/dist/esm/perspective-viewer-charts.js +2 -2
  19. package/dist/esm/perspective-viewer-charts.js.map +3 -3
  20. package/dist/esm/plugin/charts.d.ts +6 -3
  21. package/dist/esm/plugin/plugin.d.ts +46 -4
  22. package/dist/esm/render/scheduler.d.ts +34 -8
  23. package/dist/esm/transport/protocol.d.ts +31 -2
  24. package/dist/esm/transport/renderer-transport.d.ts +74 -3
  25. package/dist/esm/webgl/context-manager.d.ts +100 -117
  26. package/dist/esm/webgl/context-pool.d.ts +40 -0
  27. package/dist/esm/webgl/gl-context.d.ts +54 -0
  28. package/dist/esm/webgl/instanced-attrs.d.ts +7 -1
  29. package/dist/esm/worker/renderer.worker.d.ts +12 -0
  30. package/package.json +1 -1
  31. package/src/ts/charts/candlestick/candlestick-render.ts +4 -1
  32. package/src/ts/charts/candlestick/candlestick.ts +12 -17
  33. package/src/ts/charts/cartesian/cartesian-render.ts +80 -63
  34. package/src/ts/charts/chart-base.ts +85 -5
  35. package/src/ts/charts/chart.ts +47 -9
  36. package/src/ts/charts/common/category-axis-resolver.ts +5 -1
  37. package/src/ts/charts/common/tree-data.ts +61 -16
  38. package/src/ts/charts/heatmap/heatmap-render.ts +6 -2
  39. package/src/ts/charts/series/glyphs/draw-areas.ts +10 -1
  40. package/src/ts/charts/series/glyphs/draw-bars.ts +30 -9
  41. package/src/ts/charts/series/glyphs/draw-lines.ts +10 -1
  42. package/src/ts/charts/series/glyphs/draw-scatter.ts +56 -3
  43. package/src/ts/charts/series/series-build.ts +21 -3
  44. package/src/ts/charts/series/series-interact.ts +86 -13
  45. package/src/ts/charts/series/series-render.ts +660 -17
  46. package/src/ts/charts/series/series.ts +96 -26
  47. package/src/ts/charts/sunburst/sunburst-interact.ts +2 -3
  48. package/src/ts/charts/sunburst/sunburst-render.ts +3 -1
  49. package/src/ts/charts/treemap/treemap-interact.ts +2 -5
  50. package/src/ts/charts/treemap/treemap-render.ts +3 -1
  51. package/src/ts/charts/treemap/treemap.ts +6 -1
  52. package/src/ts/config.ts +21 -1
  53. package/src/ts/data/view-reader.ts +22 -2
  54. package/src/ts/event-detail.ts +8 -0
  55. package/src/ts/index.ts +13 -7
  56. package/src/ts/interaction/raw-event-forwarder.ts +7 -0
  57. package/src/ts/interaction/zoom-controller.ts +8 -0
  58. package/src/ts/layout/ticks.ts +9 -0
  59. package/src/ts/plugin/charts.ts +20 -4
  60. package/src/ts/plugin/plugin.ts +157 -23
  61. package/src/ts/render/scheduler.ts +164 -55
  62. package/src/ts/transport/protocol.ts +33 -0
  63. package/src/ts/transport/renderer-transport.ts +185 -9
  64. package/src/ts/webgl/context-manager.ts +195 -189
  65. package/src/ts/webgl/context-pool.ts +78 -0
  66. package/src/ts/webgl/gl-context.ts +191 -0
  67. package/src/ts/webgl/instanced-attrs.ts +15 -1
  68. package/src/ts/worker/dispatch.ts +4 -1
  69. package/src/ts/worker/renderer.worker.ts +94 -22
  70. package/src/ts/worker/session-host.ts +29 -0
@@ -18,10 +18,10 @@ import {
18
18
  type SeriesChartRecord,
19
19
  } from "./series-build";
20
20
  import {
21
- renderBarFrame,
22
21
  uploadBarInstances,
23
22
  rebuildGlyphBuffers,
24
23
  rightAxisDataToPixel,
24
+ layoutForRecord,
25
25
  } from "./series-render";
26
26
 
27
27
  const POINT_HIT_RADIUS_PX = 10;
@@ -50,6 +50,12 @@ export function getHoveredBar(chart: SeriesChart): SeriesChartRecord | null {
50
50
  * Handle mouse-move across all glyph types. Tests (in reverse paint order
51
51
  * so top glyphs win): scatter points → line points → bars → areas.
52
52
  * Updates `_hoveredBarIdx` or `_hoveredSample` and re-renders on change.
53
+ *
54
+ * Faceted frames first resolve the cell under the cursor: that cell's
55
+ * layout supplies the pixel→data mapping and its index becomes the
56
+ * `splitFilter` — records of other splits share the same band-slot
57
+ * coordinates by construction, so an unfiltered hit-test would match
58
+ * a bar from a different facet.
53
59
  */
54
60
  export function handleBarHover(
55
61
  chart: SeriesChart,
@@ -60,7 +66,33 @@ export function handleBarHover(
60
66
  return;
61
67
  }
62
68
 
63
- const layout = chart._lastLayout;
69
+ let layout = chart._lastLayout;
70
+ let splitFilter: number | undefined;
71
+ if (chart._facetGrid) {
72
+ const cells = chart._facetGrid.cells;
73
+ let found = -1;
74
+ for (let i = 0; i < cells.length; i++) {
75
+ const p = cells[i].layout.plotRect;
76
+ if (
77
+ mx >= p.x &&
78
+ mx <= p.x + p.width &&
79
+ my >= p.y &&
80
+ my <= p.y + p.height
81
+ ) {
82
+ found = i;
83
+ break;
84
+ }
85
+ }
86
+
87
+ if (found < 0) {
88
+ clearHover(chart);
89
+ return;
90
+ }
91
+
92
+ layout = cells[found].layout;
93
+ splitFilter = found;
94
+ }
95
+
64
96
  const plot = layout.plotRect;
65
97
 
66
98
  if (
@@ -131,6 +163,7 @@ export function handleBarHover(
131
163
  pxPerDataX,
132
164
  pxPerDataYLeft,
133
165
  pxPerDataYRight,
166
+ splitFilter,
134
167
  );
135
168
 
136
169
  // 2. Line points (still above bars; treat as point hits).
@@ -144,6 +177,7 @@ export function handleBarHover(
144
177
  pxPerDataX,
145
178
  pxPerDataYLeft,
146
179
  pxPerDataYRight,
180
+ splitFilter,
147
181
  );
148
182
  }
149
183
 
@@ -158,6 +192,7 @@ export function handleBarHover(
158
192
  const by1 = bars.y1;
159
193
  const ax = bars.axis;
160
194
  const hidden = chart._hiddenSeries;
195
+ const P = chart._splitPrefixes.length;
161
196
  for (let i = 0; i < bars.count; i++) {
162
197
  if (ct[i] !== BAR_TYPE_BAR) {
163
198
  continue;
@@ -167,6 +202,10 @@ export function handleBarHover(
167
202
  continue;
168
203
  }
169
204
 
205
+ if (splitFilter !== undefined && sid[i] % P !== splitFilter) {
206
+ continue;
207
+ }
208
+
170
209
  const xc = xC[i];
171
210
  const halfW = hw[i];
172
211
  if (dataX < xc - halfW || dataX > xc + halfW) {
@@ -187,7 +226,13 @@ export function handleBarHover(
187
226
 
188
227
  // 4. Areas (strip hit — stacked records via `_bars`, unstacked via samples).
189
228
  if (nextBarIdx < 0 && !nextSample) {
190
- const areaHit = hitTestAreas(chart, dataX, dataYLeft, dataYRight);
229
+ const areaHit = hitTestAreas(
230
+ chart,
231
+ dataX,
232
+ dataYLeft,
233
+ dataYRight,
234
+ splitFilter,
235
+ );
191
236
  if (areaHit) {
192
237
  if (areaHit.idx >= 0) {
193
238
  nextBarIdx = areaHit.idx;
@@ -209,6 +254,7 @@ function hitTestPoints(
209
254
  pxPerDataX: number,
210
255
  pxPerDataYLeft: number,
211
256
  pxPerDataYRight: number,
257
+ splitFilter?: number,
212
258
  ): SeriesChartRecord | null {
213
259
  const N = chart._numCategories;
214
260
  const S = chart._series.length;
@@ -233,6 +279,10 @@ function hitTestPoints(
233
279
  continue;
234
280
  }
235
281
 
282
+ if (splitFilter !== undefined && s.splitIdx !== splitFilter) {
283
+ continue;
284
+ }
285
+
236
286
  const dataY = s.axis === 1 ? dataYRight : dataYLeft;
237
287
  const pyPerData = s.axis === 1 ? pxPerDataYRight : pxPerDataYLeft;
238
288
 
@@ -289,6 +339,7 @@ function hitTestAreas(
289
339
  dataX: number,
290
340
  dataYLeft: number,
291
341
  dataYRight: number,
342
+ splitFilter?: number,
292
343
  ): { idx: number; bar: SeriesChartRecord | null } | null {
293
344
  // Closest category to the mouse; an area covers every [cat - 0.5, cat + 0.5]
294
345
  // slot, so use `round(dataX)` as the candidate index.
@@ -313,6 +364,7 @@ function hitTestAreas(
313
364
  const ax = bars.axis;
314
365
  const by0 = bars.y0;
315
366
  const by1 = bars.y1;
367
+ const P = chart._splitPrefixes.length;
316
368
  for (let i = 0; i < bars.count; i++) {
317
369
  if (ct[i] !== BAR_TYPE_AREA) {
318
370
  continue;
@@ -326,6 +378,10 @@ function hitTestAreas(
326
378
  continue;
327
379
  }
328
380
 
381
+ if (splitFilter !== undefined && sid[i] % P !== splitFilter) {
382
+ continue;
383
+ }
384
+
329
385
  const dy = ax[i] === 0 ? dataYLeft : dataYRight;
330
386
  const y0 = by0[i];
331
387
  const y1 = by1[i];
@@ -346,6 +402,10 @@ function hitTestAreas(
346
402
  continue;
347
403
  }
348
404
 
405
+ if (splitFilter !== undefined && s.splitIdx !== splitFilter) {
406
+ continue;
407
+ }
408
+
349
409
  const idx = cat * S + s.seriesId;
350
410
  if (!((valid[idx >> 3] >> (idx & 7)) & 1)) {
351
411
  continue;
@@ -383,7 +443,7 @@ function clearHover(chart: SeriesChart): void {
383
443
  chart._hoveredBarIdx = -1;
384
444
  chart._hoveredSample = null;
385
445
  if (chart._glManager) {
386
- renderBarFrame(chart, chart._glManager);
446
+ chart.requestRender(chart._glManager);
387
447
  }
388
448
  }
389
449
  }
@@ -405,13 +465,17 @@ function applyHover(
405
465
  chart._hoveredBarIdx = nextBarIdx;
406
466
  chart._hoveredSample = nextSample;
407
467
  if (chart._glManager) {
408
- renderBarFrame(chart, chart._glManager);
468
+ chart.requestRender(chart._glManager);
409
469
  }
410
470
  }
411
471
 
412
472
  /**
413
473
  * Handle a click on the legend area. Returns true when the click hit a
414
474
  * legend entry (the caller should then treat the event as consumed).
475
+ *
476
+ * An entry may own several series (facet-grid mode groups the legend
477
+ * by aggregate): the toggle is all-or-nothing — any visible member
478
+ * hides the whole group, a fully-hidden group shows every member.
415
479
  */
416
480
  export function handleBarLegendClick(
417
481
  chart: SeriesChart,
@@ -430,10 +494,15 @@ export function handleBarLegendClick(
430
494
  my >= r.y &&
431
495
  my <= r.y + r.height
432
496
  ) {
433
- if (chart._hiddenSeries.has(entry.seriesId)) {
434
- chart._hiddenSeries.delete(entry.seriesId);
435
- } else {
436
- chart._hiddenSeries.add(entry.seriesId);
497
+ const anyVisible = entry.seriesIds.some(
498
+ (sid) => !chart._hiddenSeries.has(sid),
499
+ );
500
+ for (const sid of entry.seriesIds) {
501
+ if (anyVisible) {
502
+ chart._hiddenSeries.add(sid);
503
+ } else {
504
+ chart._hiddenSeries.delete(sid);
505
+ }
437
506
  }
438
507
 
439
508
  // Hidden-series change affects which bars contribute to
@@ -454,7 +523,7 @@ export function handleBarLegendClick(
454
523
  if (chart._glManager) {
455
524
  uploadBarInstances(chart, chart._glManager);
456
525
  rebuildGlyphBuffers(chart, chart._glManager);
457
- renderBarFrame(chart, chart._glManager);
526
+ chart.requestRender(chart._glManager);
458
527
  }
459
528
 
460
529
  return true;
@@ -571,7 +640,11 @@ function pinTooltip(chart: SeriesChart, b: SeriesChartRecord): void {
571
640
  return;
572
641
  }
573
642
 
574
- const layout = chart._lastLayout;
643
+ // Faceted frames anchor in the record's own cell.
644
+ const layout = layoutForRecord(chart, b);
645
+ if (!layout) {
646
+ return;
647
+ }
575
648
 
576
649
  // Anchor at the bar midpoint for bar glyphs (tooltip reads against
577
650
  // the body); at the point itself (`y1`) for line / scatter / area.
@@ -582,7 +655,7 @@ function pinTooltip(chart: SeriesChart, b: SeriesChartRecord): void {
582
655
  ? chart._isHorizontal
583
656
  ? layout.dataToPixel(anchorV, b.xCenter)
584
657
  : layout.dataToPixel(b.xCenter, anchorV)
585
- : rightAxisDataToPixel(chart, b.xCenter, anchorV);
658
+ : rightAxisDataToPixel(chart, b.xCenter, anchorV, layout);
586
659
 
587
660
  const lines = buildBarTooltipLines(chart, b);
588
661
  if (lines.length === 0) {
@@ -594,7 +667,7 @@ function pinTooltip(chart: SeriesChart, b: SeriesChartRecord): void {
594
667
  chart._hoveredBarIdx = -1;
595
668
  chart._hoveredSample = null;
596
669
  if (chart._glManager) {
597
- renderBarFrame(chart, chart._glManager);
670
+ chart.requestRender(chart._glManager);
598
671
  }
599
672
  }
600
673