@photonviz/core 0.1.0 → 0.2.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/index.d.ts CHANGED
@@ -40,12 +40,29 @@ interface Bounds {
40
40
  /** RGBA in 0..1. */
41
41
  type Color = readonly [number, number, number, number];
42
42
 
43
+ /**
44
+ * Shared data→clip transform used by every layer's vertex shader.
45
+ *
46
+ * Two subtleties it handles:
47
+ * - **Log axes** — when `uLogX/uLogY` is set, the real coordinate is
48
+ * log10-transformed on the GPU.
49
+ * - **Float32 precision** — vertex buffers are float32 (~7 significant digits),
50
+ * which is not enough for large values like epoch-millisecond timestamps.
51
+ * Layers upload coordinates *relative to a reference* (`x - xRef`) and pass
52
+ * `uXRef`; the domain is passed in the same offset space, so the subtraction
53
+ * that computes the normalized position never suffers catastrophic
54
+ * cancellation. For log axes the reference is added back before log10.
55
+ */
56
+ declare const TRANSFORM_GLSL = "\nuniform vec2 uDomainX; // linear: (lo-ref, hi-ref) ; log: (log10 lo, log10 hi)\nuniform vec2 uDomainY;\nuniform float uXRef;\nuniform float uYRef;\nuniform float uLogX; // >0.5 => log axis\nuniform float uLogY;\n\nvec2 dataToNorm(vec2 p) {\n float cx = (uLogX > 0.5) ? log(p.x + uXRef) / 2.302585092994046 : p.x;\n float cy = (uLogY > 0.5) ? log(p.y + uYRef) / 2.302585092994046 : p.y;\n float nx = (cx - uDomainX.x) / (uDomainX.y - uDomainX.x);\n float ny = (cy - uDomainY.x) / (uDomainY.y - uDomainY.x);\n return vec2(nx, ny);\n}\n\nvec2 dataToClip(vec2 p) {\n return dataToNorm(p) * 2.0 - 1.0;\n}\n";
43
57
  /** Per-axis view state handed to a layer each frame. `lo`/`hi` are raw data-space. */
44
58
  interface AxisFrame {
45
59
  lo: number;
46
60
  hi: number;
47
61
  log: boolean;
48
62
  }
63
+ declare const TRANSFORM_UNIFORMS: readonly ["uDomainX", "uDomainY", "uXRef", "uYRef", "uLogX", "uLogY"];
64
+ /** Set the shared transform uniforms for a layer given its per-axis references. */
65
+ declare function setTransformUniforms(gl: WebGL2RenderingContext, u: Record<string, WebGLUniformLocation | null>, x: AxisFrame, y: AxisFrame, xRef: number, yRef: number): void;
49
66
 
50
67
  /** State handed to a layer each frame so it can transform data to clip space. */
51
68
  interface DrawState {
@@ -196,6 +213,51 @@ declare class BoxLayer implements Layer {
196
213
  dispose(): void;
197
214
  }
198
215
 
216
+ interface CandlestickOptions {
217
+ /** Candle positions (data space — e.g. epoch ms on a time axis). */
218
+ x: ArrayLike<number>;
219
+ open: ArrayLike<number>;
220
+ high: ArrayLike<number>;
221
+ low: ArrayLike<number>;
222
+ close: ArrayLike<number>;
223
+ /** Body width in data units. Defaults to 70% of the median spacing. */
224
+ width?: number;
225
+ /** Close ≥ open color. Default green. */
226
+ upColor?: string | Color;
227
+ /** Close < open color. Default red. */
228
+ downColor?: string | Color;
229
+ /** Wick thickness in CSS px. Default 1.5. */
230
+ wickWidth?: number;
231
+ name?: string;
232
+ yAxis?: string;
233
+ }
234
+ declare class CandlestickLayer implements Layer {
235
+ readonly id: string;
236
+ readonly name: string;
237
+ readonly colorCss: string;
238
+ readonly yAxis: string;
239
+ private gl;
240
+ private progs;
241
+ private bodyVao;
242
+ private wickVao;
243
+ private buffers;
244
+ private uBody;
245
+ private uWick;
246
+ private wickWidth;
247
+ private count;
248
+ private xRef;
249
+ private yRef;
250
+ private xBounds;
251
+ private yBounds;
252
+ constructor(gl: WebGL2RenderingContext, opts: CandlestickOptions);
253
+ bounds(): {
254
+ x: Range;
255
+ y: Range;
256
+ } | null;
257
+ draw(state: DrawState): void;
258
+ dispose(): void;
259
+ }
260
+
199
261
  type RGB = [number, number, number];
200
262
  type ColormapName = "viridis" | "plasma" | "coolwarm" | "grayscale";
201
263
  /** Returns a `(t in 0..1) => RGB` sampler for the named colormap. */
@@ -238,6 +300,68 @@ declare class ContourLayer implements Layer {
238
300
  dispose(): void;
239
301
  }
240
302
 
303
+ /** A per-point error, given as one value for all points or an array. */
304
+ type ErrInput = ArrayLike<number> | number;
305
+ interface ErrorBarOptions {
306
+ x: ArrayLike<number>;
307
+ y: ArrayLike<number>;
308
+ /** Symmetric y error (half-height). Scalar or per-point. */
309
+ yerr?: ErrInput;
310
+ /** Asymmetric y error below/above `y` (overrides `yerr`). */
311
+ yerrLow?: ErrInput;
312
+ yerrHigh?: ErrInput;
313
+ /** Symmetric x error (half-width). Scalar or per-point. */
314
+ xerr?: ErrInput;
315
+ color?: string | Color;
316
+ /** Whisker/cap thickness in CSS px. Default 1.5. */
317
+ width?: number;
318
+ /** Cap length in CSS px (0 hides caps). Default 6. */
319
+ capSize?: number;
320
+ /** Draw I-beam whiskers. Default true. */
321
+ whiskers?: boolean;
322
+ /** Fill a shaded band between the low/high y bounds. Default false. */
323
+ band?: boolean;
324
+ /** Band fill opacity. Default 0.2. */
325
+ bandOpacity?: number;
326
+ name?: string;
327
+ yAxis?: string;
328
+ }
329
+ declare class ErrorBarLayer implements Layer {
330
+ readonly id: string;
331
+ readonly name: string;
332
+ readonly colorCss: string;
333
+ readonly yAxis: string;
334
+ private gl;
335
+ private progs;
336
+ private segVao;
337
+ private capVao;
338
+ private bandVao;
339
+ private buffers;
340
+ private uSeg;
341
+ private uCap;
342
+ private uBand;
343
+ private color;
344
+ private width;
345
+ private capSize;
346
+ private bandOpacity;
347
+ private showWhiskers;
348
+ private showBand;
349
+ private segCount;
350
+ private capCount;
351
+ private bandVerts;
352
+ private xRef;
353
+ private yRef;
354
+ private xBounds;
355
+ private yBounds;
356
+ constructor(gl: WebGL2RenderingContext, opts: ErrorBarOptions);
357
+ bounds(): {
358
+ x: Range;
359
+ y: Range;
360
+ } | null;
361
+ draw(state: DrawState): void;
362
+ dispose(): void;
363
+ }
364
+
241
365
  interface HeatmapOptions {
242
366
  /** Row-major grid values, length `cols * rows` (row 0 at the bottom). */
243
367
  values: ArrayLike<number>;
@@ -309,6 +433,28 @@ declare class HexbinLayer implements Layer {
309
433
  dispose(): void;
310
434
  }
311
435
 
436
+ /**
437
+ * Shared hover-picking used by point/series layers (line, scatter, stem).
438
+ *
439
+ * The mode decides which pixel-space distance is minimized:
440
+ * - `"x"` — nearest by horizontal distance (classic crosshair-along-x)
441
+ * - `"y"` — nearest by vertical distance
442
+ * - `"xy"` — nearest by true 2D distance (checks both axes; right for point
443
+ * clouds / maps, where an x-only match would highlight the wrong
444
+ * point)
445
+ *
446
+ * Distances are computed in pixels via `project`, so x and y are compared on
447
+ * the same footing regardless of each axis's data range.
448
+ */
449
+ type PickMode = "x" | "y" | "xy";
450
+ interface Picked {
451
+ x: number;
452
+ y: number;
453
+ index: number;
454
+ }
455
+
456
+ /** How adjacent segments meet at a vertex. */
457
+ type LineJoin = "round" | "miter" | "bevel" | "butt";
312
458
  interface LineOptions {
313
459
  x: ArrayLike<number>;
314
460
  y: ArrayLike<number>;
@@ -318,8 +464,20 @@ interface LineOptions {
318
464
  name?: string;
319
465
  yAxis?: string;
320
466
  step?: "before" | "after" | "center";
321
- /** Round joins/caps (default) or square/butt ends. */
322
- join?: "round" | "butt";
467
+ /**
468
+ * How segments meet at each vertex:
469
+ * - `round` (default) — round caps and joins via an SDF; no seams.
470
+ * - `miter` — sharp mitered corners, clamped to {@link LineOptions.miterLimit}.
471
+ * - `bevel` — corners cut flat.
472
+ * - `butt` — flat ends with no join fill (segments may gap at sharp angles).
473
+ */
474
+ join?: LineJoin;
475
+ /**
476
+ * For `join: "miter"`, the max ratio of miter length to half line-width before
477
+ * a corner falls back to a bevel (prevents spikes at very sharp angles).
478
+ * Default 4.
479
+ */
480
+ miterLimit?: number;
323
481
  /**
324
482
  * Min/max decimate very large series to ~2 points per pixel column when
325
483
  * zoomed out (preserves peaks). Requires monotonic x; auto-detected. Default true.
@@ -333,18 +491,25 @@ declare class LineLayer implements Layer {
333
491
  readonly yAxis: string;
334
492
  private gl;
335
493
  private program;
494
+ private joinProgram;
336
495
  private fullVao;
337
496
  private decVao;
497
+ private joinFullVao;
498
+ private joinDecVao;
338
499
  private cornerBuf;
339
500
  private posBuf;
340
501
  private decBuf;
341
502
  private uniforms;
503
+ private joinUniforms;
342
504
  private count;
343
505
  private color;
344
506
  private width;
345
507
  private round;
508
+ private joinStyle;
509
+ private miterLimit;
346
510
  private decimateOn;
347
511
  private monotonic;
512
+ private gpuDec;
348
513
  private step?;
349
514
  private xRef;
350
515
  private yRef;
@@ -355,16 +520,15 @@ declare class LineLayer implements Layer {
355
520
  private decKey;
356
521
  private decSegments;
357
522
  constructor(gl: WebGL2RenderingContext, opts: LineOptions);
523
+ private syncGpu;
524
+ private disposeGpu;
358
525
  private configureVao;
526
+ private configureJoinVao;
359
527
  bounds(): {
360
528
  x: Range;
361
529
  y: Range;
362
530
  } | null;
363
- nearestByX(x: number): {
364
- x: number;
365
- y: number;
366
- index: number;
367
- } | null;
531
+ pick(mode: PickMode, cursorPx: number, cursorPy: number, project: (x: number, y: number) => [number, number]): Picked | null;
368
532
  /** Replace the series data and re-upload the GPU buffer (for streaming). */
369
533
  setData(x: ArrayLike<number>, y: ArrayLike<number>): void;
370
534
  /**
@@ -376,6 +540,60 @@ declare class LineLayer implements Layer {
376
540
  dispose(): void;
377
541
  }
378
542
 
543
+ interface QuiverOptions {
544
+ /** Arrow anchor positions (data space). */
545
+ x: ArrayLike<number>;
546
+ y: ArrayLike<number>;
547
+ /** Vector components at each anchor. */
548
+ u: ArrayLike<number>;
549
+ v: ArrayLike<number>;
550
+ /** Multiplier applied to (u,v) in data units. Default auto-fits the field. */
551
+ scale?: number;
552
+ color?: string | Color;
553
+ /** Shaft thickness in CSS px. Default 1.5. */
554
+ width?: number;
555
+ /** Arrowhead length in CSS px. Default 9. */
556
+ headSize?: number;
557
+ /** Color each arrow by a value (default: its magnitude) through a colormap. */
558
+ colorBy?: {
559
+ values?: ArrayLike<number>;
560
+ colormap?: ColormapName;
561
+ domain?: Range;
562
+ };
563
+ name?: string;
564
+ yAxis?: string;
565
+ }
566
+ declare class QuiverLayer implements Layer {
567
+ readonly id: string;
568
+ readonly name: string;
569
+ readonly colorCss: string;
570
+ readonly yAxis: string;
571
+ private gl;
572
+ private progs;
573
+ private shaftVao;
574
+ private headVao;
575
+ private buffers;
576
+ private uShaft;
577
+ private uHead;
578
+ private color;
579
+ private width;
580
+ private headSize;
581
+ private useVertexColor;
582
+ private count;
583
+ private xRef;
584
+ private yRef;
585
+ private xBounds;
586
+ private yBounds;
587
+ constructor(gl: WebGL2RenderingContext, opts: QuiverOptions);
588
+ private bindInstanceAttribs;
589
+ bounds(): {
590
+ x: Range;
591
+ y: Range;
592
+ } | null;
593
+ draw(state: DrawState): void;
594
+ dispose(): void;
595
+ }
596
+
379
597
  interface ScatterOptions {
380
598
  x: ArrayLike<number>;
381
599
  y: ArrayLike<number>;
@@ -384,6 +602,12 @@ interface ScatterOptions {
384
602
  size?: number;
385
603
  name?: string;
386
604
  yAxis?: string;
605
+ /**
606
+ * Optional per-point text shown when a point is clicked (one entry per point,
607
+ * parallel to `x`/`y`). Lets you attach your own info instead of the default
608
+ * coordinate readout.
609
+ */
610
+ labels?: ArrayLike<string>;
387
611
  /** Color each point by a value through a colormap. */
388
612
  colorBy?: {
389
613
  values: ArrayLike<number>;
@@ -406,6 +630,7 @@ declare class ScatterLayer implements Layer {
406
630
  private size;
407
631
  private color;
408
632
  private useVertexColor;
633
+ private labels?;
409
634
  private xRef;
410
635
  private yRef;
411
636
  private xs;
@@ -417,17 +642,61 @@ declare class ScatterLayer implements Layer {
417
642
  x: Range;
418
643
  y: Range;
419
644
  } | null;
420
- nearestByX(x: number): {
421
- x: number;
422
- y: number;
423
- index: number;
424
- } | null;
645
+ pick(mode: PickMode, cursorPx: number, cursorPy: number, project: (x: number, y: number) => [number, number]): Picked | null;
646
+ /** User-supplied text for a point, shown when it is clicked. */
647
+ infoAt(index: number): string[] | null;
425
648
  /** Replace point positions and re-upload (for streaming). Keeps uniform color. */
426
649
  setData(x: ArrayLike<number>, y: ArrayLike<number>): void;
427
650
  draw(state: DrawState): void;
428
651
  dispose(): void;
429
652
  }
430
653
 
654
+ interface StemOptions {
655
+ x: ArrayLike<number>;
656
+ y: ArrayLike<number>;
657
+ /** Where stems start. Default 0. */
658
+ baseline?: number;
659
+ color?: string | Color;
660
+ /** Stem thickness in CSS px. Default 1.5. */
661
+ width?: number;
662
+ /** Tip marker diameter in CSS px (0 hides). Default 6. */
663
+ markerSize?: number;
664
+ name?: string;
665
+ yAxis?: string;
666
+ }
667
+ declare class StemLayer implements Layer {
668
+ readonly id: string;
669
+ readonly name: string;
670
+ readonly colorCss: string;
671
+ readonly yAxis: string;
672
+ private gl;
673
+ private progs;
674
+ private stemVao;
675
+ private markerVao;
676
+ private buffers;
677
+ private uStem;
678
+ private uMarker;
679
+ private color;
680
+ private width;
681
+ private markerSize;
682
+ private count;
683
+ private baseline;
684
+ private xRef;
685
+ private yRef;
686
+ private xs;
687
+ private ys;
688
+ private xBounds;
689
+ private yBounds;
690
+ constructor(gl: WebGL2RenderingContext, opts: StemOptions);
691
+ bounds(): {
692
+ x: Range;
693
+ y: Range;
694
+ } | null;
695
+ pick(mode: PickMode, cursorPx: number, cursorPy: number, project: (x: number, y: number) => [number, number]): Picked | null;
696
+ draw(state: DrawState): void;
697
+ dispose(): void;
698
+ }
699
+
431
700
  /**
432
701
  * A scale maps data-space values to normalized [0,1] and back, and knows how to
433
702
  * generate its own "nice" ticks + default label format. `log` tells layers to
@@ -516,6 +785,11 @@ interface YAxisOptions extends AxisConfig {
516
785
  /** Axis + label color (secondary axes often match their series). */
517
786
  color?: string;
518
787
  }
788
+ /** One line of the hover tooltip header, produced by {@link PlotOptions.hoverReadout}. */
789
+ interface HoverReadoutRow {
790
+ label: string;
791
+ value: string;
792
+ }
519
793
  interface PlotOptions {
520
794
  scales?: {
521
795
  x?: AxisScaleOptions;
@@ -530,11 +804,47 @@ interface PlotOptions {
530
804
  /** Enable wheel-zoom and drag interaction. Default true. */
531
805
  interactive?: boolean;
532
806
  /** Show the built-in toolbar (home + pan/box/X/Y zoom modes). Default true. */
533
- toolbar?: boolean;
534
- /** Initial interaction mode. Default `"box"`. */
807
+ showToolbar?: boolean;
808
+ /** Initial interaction mode. Default `"pan"`. */
535
809
  mode?: InteractionMode;
536
810
  /** Enable hover crosshair + tooltip. Default true. */
537
811
  hover?: boolean;
812
+ /**
813
+ * How hover selects the highlighted point: `"x"` nearest by x (classic),
814
+ * `"y"` nearest by y, or `"xy"` nearest by 2D distance — the last checks both
815
+ * axes, which is what a scatter/map needs. Default `"x"`.
816
+ */
817
+ pick?: PickMode;
818
+ /**
819
+ * When a point's pinned detail box appears: `"click"` pins it on click (until
820
+ * you click empty space), `"hover"` shows it while the cursor is over a point.
821
+ * Default `"click"`.
822
+ */
823
+ pointInfo?: "hover" | "click";
824
+ /**
825
+ * Show dashed guide lines on *both* the X and Y axes at the cursor — on hover
826
+ * and while the pointer is pressed. When false, hover shows only the vertical
827
+ * (X) line and there are no press guides. Default true.
828
+ */
829
+ crosshair?: boolean;
830
+ /**
831
+ * Keep data-units-per-pixel equal on both axes so nothing is distorted (the
832
+ * looser axis is expanded to match). Essential for maps. Default false.
833
+ */
834
+ equalAspect?: boolean;
835
+ /**
836
+ * Constrain panning/zooming so the view can't move outside the data bounds
837
+ * (the union of all layers' extents). Zoom still works; the view is just
838
+ * kept inside the limits. Default false (a map turns it on).
839
+ */
840
+ boundedPan?: boolean;
841
+ /**
842
+ * Customize the tooltip header shown on hover. Given the cursor's data-space
843
+ * X and Y (primary y axis), return the lines to display above the series
844
+ * rows — e.g. a map converts world coords to `lon`/`lat`. When omitted, the
845
+ * header is the default single `x = …` line. Default undefined.
846
+ */
847
+ hoverReadout?: (dataX: number, dataY: number) => HoverReadoutRow[];
538
848
  }
539
849
  /**
540
850
  * The imperative core plot. Owns a stack of three canvases (grid / WebGL data /
@@ -570,7 +880,18 @@ declare class Plot {
570
880
  private toolbarHandle;
571
881
  private hoverEnabled;
572
882
  private hoverPx;
883
+ private pickMode;
884
+ private pointInfo;
885
+ private crosshair;
886
+ private equalAspect;
887
+ private boundedPan;
888
+ private hoverReadout?;
889
+ /** Cursor position while the pointer is pressed, when `crosshair`. */
890
+ private pressPx;
573
891
  private tooltip;
892
+ /** A point clicked to pin its details, until another click clears it. */
893
+ private selected;
894
+ private infoBox;
574
895
  constructor(container: HTMLElement, options?: PlotOptions);
575
896
  private makeCanvas;
576
897
  /** Margins grow to make room for extra y axes on each side. */
@@ -579,6 +900,22 @@ declare class Plot {
579
900
  /** Pixel x-position (and title x) for each y axis, by draw order per side. */
580
901
  private yAxisPositions;
581
902
  private register;
903
+ /**
904
+ * Register a layer built outside core (e.g. `@photonviz/map`). Use with
905
+ * {@link context} to construct the layer against this plot's WebGL2 context.
906
+ */
907
+ add<T extends Layer>(layer: T): T;
908
+ /** The shared WebGL2 context, for constructing custom layers. */
909
+ get context(): WebGL2RenderingContext;
910
+ /**
911
+ * Convert a client (screen) coordinate to data space — the shared x and the
912
+ * primary y. Returns null if the point is outside the plot region. Useful for
913
+ * custom hit-testing (e.g. map feature picking on click).
914
+ */
915
+ dataAt(clientX: number, clientY: number): {
916
+ x: number;
917
+ y: number;
918
+ } | null;
582
919
  addLine(opts: LineOptions): LineLayer;
583
920
  addScatter(opts: ScatterOptions): ScatterLayer;
584
921
  addBar(opts: BarOptions): BarLayer;
@@ -587,6 +924,10 @@ declare class Plot {
587
924
  addBox(opts: BoxOptions): BoxLayer;
588
925
  addHexbin(opts: HexbinOptions): HexbinLayer;
589
926
  addContour(opts: ContourOptions): ContourLayer;
927
+ addErrorBar(opts: ErrorBarOptions): ErrorBarLayer;
928
+ addStem(opts: StemOptions): StemLayer;
929
+ addQuiver(opts: QuiverOptions): QuiverLayer;
930
+ addCandlestick(opts: CandlestickOptions): CandlestickLayer;
590
931
  /** Compute an STFT of `signal` and render it as a heatmap (time × frequency). */
591
932
  addHeatmapSpectrogram(signal: ArrayLike<number>, opts?: {
592
933
  fftSize?: number;
@@ -640,6 +981,26 @@ declare class Plot {
640
981
  private panY;
641
982
  private attachInteraction;
642
983
  private setHover;
984
+ /** Update the press-crosshair position and redraw. */
985
+ private setPress;
986
+ /** Nearest point (2D, within a small radius) under the cursor, or null. */
987
+ private pickPoint;
988
+ /** Click handler: in `pointInfo:"click"` mode, pin the point under the cursor. */
989
+ private handleClick;
990
+ /** Draw the pinned point's marker and position its info box (or hide it). */
991
+ private updateInfoBox;
992
+ /** Data-space x extent across all layers, or null if empty. */
993
+ private layerBoundsX;
994
+ /** Data-space y extent across the layers bound to axis `id`, or null. */
995
+ private layerBoundsY;
996
+ /** Keep the view inside the data bounds (used when `boundedPan`). */
997
+ private clampView;
998
+ /**
999
+ * Expand the looser axis so both axes share the same data-units-per-pixel,
1000
+ * preventing distortion (maps set `equalAspect`). Linear axes only; balances
1001
+ * the primary y against x, and is idempotent once balanced.
1002
+ */
1003
+ private applyAspect;
643
1004
  private drawSelection;
644
1005
  private applySelection;
645
1006
  private zoomAround;
@@ -673,6 +1034,18 @@ interface PolarOptions {
673
1034
  /** Fixed max radius. If omitted, autoscales to the data. */
674
1035
  maxRadius?: number;
675
1036
  margin?: number;
1037
+ /** Enable wheel-zoom (r scale) and drag-rotate interaction. Default true. */
1038
+ interactive?: boolean;
1039
+ /** Enable hover: highlight the nearest point + show a tooltip. Default true. */
1040
+ hover?: boolean;
1041
+ /** Show the built-in home (reset) button. Default true. */
1042
+ showToolbar?: boolean;
1043
+ /**
1044
+ * How the pinned point-info box is triggered: `"click"` pins a point until
1045
+ * empty space is clicked; `"hover"` shows the point under the cursor
1046
+ * automatically (no click). Default `"click"`.
1047
+ */
1048
+ pointInfo?: "hover" | "click";
676
1049
  }
677
1050
  interface PolarLineOptions {
678
1051
  theta: ArrayLike<number>;
@@ -687,6 +1060,8 @@ interface PolarScatterOptions {
687
1060
  r: ArrayLike<number>;
688
1061
  color?: string | Color;
689
1062
  size?: number;
1063
+ /** Optional per-point labels (one per point), shown as the title of the click-pinned info box. */
1064
+ labels?: ArrayLike<string>;
690
1065
  }
691
1066
  /** A live handle to update a polar series with new (theta, r) data. */
692
1067
  interface PolarSeries {
@@ -697,19 +1072,37 @@ declare class PolarPlot {
697
1072
  private container;
698
1073
  private gridCanvas;
699
1074
  private dataCanvas;
1075
+ private overlayCanvas;
700
1076
  private gridCtx;
701
1077
  private dataCtx;
1078
+ private overlayCtx;
702
1079
  private gl;
703
1080
  private sharedCanvas;
704
1081
  private theme;
1082
+ private isDark;
705
1083
  private toRad;
706
1084
  private fixedR?;
707
1085
  private margin;
708
1086
  private entries;
709
1087
  private R;
1088
+ private baseR;
710
1089
  private dpr;
711
1090
  private resizeObserver;
712
1091
  private frameRequested;
1092
+ private interactive;
1093
+ private hoverEnabled;
1094
+ /** Multiplier on the fitted radius: <1 zooms in (smaller r-domain), >1 out. */
1095
+ private zoom;
1096
+ /** Angular offset (radians, CCW) applied to all series + gridlines. */
1097
+ private rotation;
1098
+ private hoverPx;
1099
+ private tooltip;
1100
+ private homeButton;
1101
+ /** A point clicked to pin its details, until another click clears it. */
1102
+ private selected;
1103
+ private infoBox;
1104
+ /** Whether the info box is triggered by `"click"` (pinned) or `"hover"`. */
1105
+ private pointInfo;
713
1106
  constructor(container: HTMLElement, options?: PolarOptions);
714
1107
  private makeCanvas;
715
1108
  private toXY;
@@ -717,6 +1110,14 @@ declare class PolarPlot {
717
1110
  addScatter(opts: PolarScatterOptions): PolarSeries;
718
1111
  private handle;
719
1112
  private refit;
1113
+ /** Re-project every series with the current rotation (called when rotation changes). */
1114
+ private retransform;
1115
+ /** Reset zoom (r-domain) and rotation back to the initial view. */
1116
+ home(): void;
1117
+ /** Current rotation offset in radians (CCW). */
1118
+ getRotation(): number;
1119
+ /** Set the rotation offset (radians, CCW) and redraw. */
1120
+ setRotation(rad: number): void;
720
1121
  destroy(): void;
721
1122
  private resize;
722
1123
  requestRender(): void;
@@ -724,6 +1125,19 @@ declare class PolarPlot {
724
1125
  private square;
725
1126
  render(): void;
726
1127
  private drawGrid;
1128
+ private setHover;
1129
+ /** Nearest data point (across all series) to a cursor position, in CSS px. */
1130
+ private pickNearest;
1131
+ /** Draw a filled, white-ringed marker on the overlay at a screen position. */
1132
+ private drawPointMarker;
1133
+ private renderHover;
1134
+ /** Click handler: pin the nearest point's details, or clear on empty space. */
1135
+ private handleClick;
1136
+ /** Draw the pinned point's marker and position its info box (or hide it). */
1137
+ private updateInfoBox;
1138
+ private updateTooltip;
1139
+ private attachInteraction;
1140
+ private makeHomeButton;
727
1141
  }
728
1142
 
729
1143
  /** Minimal column-major 4×4 matrix helpers for the 3D plots (WebGL convention). */
@@ -953,9 +1367,14 @@ interface Density {
953
1367
  */
954
1368
  declare function kde(values: ArrayLike<number>, lo: number, hi: number, points?: number, bandwidth?: number): Density;
955
1369
 
1370
+ /** Compile + link a vertex/fragment program. */
1371
+ declare function createProgram(gl: WebGL2RenderingContext, vert: string, frag: string): WebGLProgram;
1372
+ /** Cache uniform locations for a program by name. */
1373
+ declare function uniformLocations(gl: WebGL2RenderingContext, program: WebGLProgram, names: string[]): Record<string, WebGLUniformLocation | null>;
1374
+
956
1375
  /** Parse a CSS hex/rgb color string into normalized RGBA (0..1). */
957
1376
  declare function parseColor(input: string): [number, number, number, number];
958
1377
  /** Normalized RGBA (0..1) back to a CSS `rgba(...)` string. */
959
1378
  declare function toColorCss(c: readonly [number, number, number, number]): string;
960
1379
 
961
- export { AreaLayer, type AreaOptions, Axis, type AxisConfig, type AxisFrame, type AxisScaleOptions, BarLayer, type BarOptions, type Bounds, type Bounds3, type BoxGroup, BoxLayer, type BoxOptions, type BoxStats, type Color, type ColormapName, ContourLayer, type ContourOptions, type Density, type Dim, type DrawState, HeatmapLayer, type HeatmapOptions, HexbinLayer, type HexbinOptions, type Histogram, type InteractionMode, type Layer, type Layer3D, type Layout, LineLayer, type LineOptions, LinearScale, LogScale, Plot, Plot3D, type Plot3DOptions, type PlotOptions, PointCloudLayer, type PointCloudOptions, type PolarLineOptions, type PolarOptions, PolarPlot, type PolarScatterOptions, type PolarSeries, type RGB, type Range, type Scale, type ScaleType, ScatterLayer, type ScatterOptions, type Spectrogram, SurfaceLayer, type SurfaceOptions, type Theme, type Tick, type TicksSpec, TimeScale, type ToolbarHost, type ToolbarTheme, type YAxisOptions, autoTicks, boxStats, colormap, createToolbar, darkTheme, defaultFormat, fft, histogram, kde, lightTheme, makeScale, parseColor, quantileSorted, resolveTicks, spectrogram, toColorCss, withMinorTicks };
1380
+ export { AreaLayer, type AreaOptions, Axis, type AxisConfig, type AxisFrame, type AxisScaleOptions, BarLayer, type BarOptions, type Bounds, type Bounds3, type BoxGroup, BoxLayer, type BoxOptions, type BoxStats, CandlestickLayer, type CandlestickOptions, type Color, type ColormapName, ContourLayer, type ContourOptions, type Density, type Dim, type DrawState, ErrorBarLayer, type ErrorBarOptions, HeatmapLayer, type HeatmapOptions, HexbinLayer, type HexbinOptions, type Histogram, type HoverReadoutRow, type InteractionMode, type Layer, type Layer3D, type Layout, LineLayer, type LineOptions, LinearScale, LogScale, type PickMode, Plot, Plot3D, type Plot3DOptions, type PlotOptions, PointCloudLayer, type PointCloudOptions, type PolarLineOptions, type PolarOptions, PolarPlot, type PolarScatterOptions, type PolarSeries, QuiverLayer, type QuiverOptions, type RGB, type Range, type Scale, type ScaleType, ScatterLayer, type ScatterOptions, type Spectrogram, StemLayer, type StemOptions, SurfaceLayer, type SurfaceOptions, TRANSFORM_GLSL, TRANSFORM_UNIFORMS, type Theme, type Tick, type TicksSpec, TimeScale, type ToolbarHost, type ToolbarTheme, type YAxisOptions, autoTicks, boxStats, colormap, createProgram, createToolbar, darkTheme, defaultFormat, fft, histogram, kde, lightTheme, makeScale, parseColor, quantileSorted, resolveTicks, setTransformUniforms, spectrogram, toColorCss, uniformLocations, withMinorTicks };