semiotic 3.0.1 → 3.1.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 (122) hide show
  1. package/CLAUDE.md +227 -27
  2. package/README.md +43 -11
  3. package/ai/examples.md +358 -18
  4. package/ai/schema.json +64 -2
  5. package/ai/system-prompt.md +50 -12
  6. package/dist/components/Legend.d.ts +7 -1
  7. package/dist/components/charts/geo/ChoroplethMap.d.ts +53 -0
  8. package/dist/components/charts/geo/DistanceCartogram.d.ts +90 -0
  9. package/dist/components/charts/geo/FlowMap.d.ts +83 -0
  10. package/dist/components/charts/geo/ProportionalSymbolMap.d.ts +67 -0
  11. package/dist/components/charts/geo/index.d.ts +8 -0
  12. package/dist/components/charts/index.d.ts +2 -0
  13. package/dist/components/charts/network/ChordDiagram.d.ts +6 -5
  14. package/dist/components/charts/network/CirclePack.d.ts +2 -2
  15. package/dist/components/charts/network/ForceDirectedGraph.d.ts +9 -7
  16. package/dist/components/charts/network/OrbitDiagram.d.ts +21 -20
  17. package/dist/components/charts/network/SankeyDiagram.d.ts +6 -5
  18. package/dist/components/charts/network/TreeDiagram.d.ts +2 -2
  19. package/dist/components/charts/network/Treemap.d.ts +2 -2
  20. package/dist/components/charts/ordinal/BarChart.d.ts +7 -5
  21. package/dist/components/charts/ordinal/BoxPlot.d.ts +8 -6
  22. package/dist/components/charts/ordinal/DonutChart.d.ts +8 -6
  23. package/dist/components/charts/ordinal/DotPlot.d.ts +8 -6
  24. package/dist/components/charts/ordinal/GroupedBarChart.d.ts +7 -5
  25. package/dist/components/charts/ordinal/Histogram.d.ts +8 -5
  26. package/dist/components/charts/ordinal/PieChart.d.ts +8 -6
  27. package/dist/components/charts/ordinal/RidgelinePlot.d.ts +2 -0
  28. package/dist/components/charts/ordinal/StackedBarChart.d.ts +7 -5
  29. package/dist/components/charts/ordinal/SwarmPlot.d.ts +8 -6
  30. package/dist/components/charts/ordinal/ViolinPlot.d.ts +8 -5
  31. package/dist/components/charts/realtime/RealtimeHeatmap.d.ts +24 -6
  32. package/dist/components/charts/realtime/RealtimeHistogram.d.ts +28 -7
  33. package/dist/components/charts/realtime/RealtimeLineChart.d.ts +23 -5
  34. package/dist/components/charts/realtime/RealtimeSwarmChart.d.ts +24 -6
  35. package/dist/components/charts/realtime/RealtimeWaterfallChart.d.ts +23 -5
  36. package/dist/components/charts/shared/colorUtils.d.ts +5 -0
  37. package/dist/components/charts/shared/hooks.d.ts +13 -1
  38. package/dist/components/charts/shared/legendUtils.d.ts +2 -3
  39. package/dist/components/charts/shared/statisticalOverlays.d.ts +1 -2
  40. package/dist/components/charts/shared/statisticalOverlaysLazy.d.ts +10 -0
  41. package/dist/components/charts/shared/tooltipUtils.d.ts +1 -1
  42. package/dist/components/charts/shared/types.d.ts +10 -4
  43. package/dist/components/charts/shared/useChartSetup.d.ts +112 -0
  44. package/dist/components/charts/shared/useStreamingLegend.d.ts +65 -0
  45. package/dist/components/charts/xy/AreaChart.d.ts +11 -6
  46. package/dist/components/charts/xy/BubbleChart.d.ts +11 -6
  47. package/dist/components/charts/xy/ConnectedScatterplot.d.ts +7 -6
  48. package/dist/components/charts/xy/Heatmap.d.ts +16 -5
  49. package/dist/components/charts/xy/LineChart.d.ts +21 -5
  50. package/dist/components/charts/xy/MinimapChart.d.ts +3 -0
  51. package/dist/components/charts/xy/QuadrantChart.d.ts +120 -0
  52. package/dist/components/charts/xy/Scatterplot.d.ts +9 -6
  53. package/dist/components/charts/xy/StackedAreaChart.d.ts +11 -6
  54. package/dist/components/geo/mergeData.d.ts +18 -0
  55. package/dist/components/geo/referenceGeography.d.ts +10 -0
  56. package/dist/components/geo/useReferenceAreas.d.ts +13 -0
  57. package/dist/components/realtime/RingBuffer.d.ts +1 -0
  58. package/dist/components/realtime/types.d.ts +17 -0
  59. package/dist/components/semiotic-data.d.ts +1 -0
  60. package/dist/components/semiotic-geo.d.ts +16 -0
  61. package/dist/components/semiotic-server.d.ts +1 -1
  62. package/dist/components/semiotic-xy.d.ts +1 -0
  63. package/dist/components/semiotic.d.ts +4 -4
  64. package/dist/components/server/renderToStaticSVG.d.ts +4 -2
  65. package/dist/components/stream/AccessibleDataTable.d.ts +50 -0
  66. package/dist/components/stream/CanvasHitTester.d.ts +8 -2
  67. package/dist/components/stream/DataSourceAdapter.d.ts +33 -4
  68. package/dist/components/stream/GeoCanvasHitTester.d.ts +19 -0
  69. package/dist/components/stream/GeoParticlePool.d.ts +46 -0
  70. package/dist/components/stream/GeoPipelineStore.d.ts +81 -0
  71. package/dist/components/stream/GeoTileRenderer.d.ts +31 -0
  72. package/dist/components/stream/NetworkPipelineStore.d.ts +16 -4
  73. package/dist/components/stream/NetworkSVGOverlay.d.ts +4 -1
  74. package/dist/components/stream/OrdinalPipelineStore.d.ts +8 -4
  75. package/dist/components/stream/OrdinalSVGOverlay.d.ts +23 -1
  76. package/dist/components/stream/PipelineStore.d.ts +57 -5
  77. package/dist/components/stream/SVGOverlay.d.ts +28 -1
  78. package/dist/components/stream/SceneGraph.d.ts +7 -3
  79. package/dist/components/stream/SceneToSVG.d.ts +2 -0
  80. package/dist/components/stream/StreamGeoFrame.d.ts +4 -0
  81. package/dist/components/stream/accessorUtils.d.ts +1 -0
  82. package/dist/components/stream/canvasSetup.d.ts +26 -0
  83. package/dist/components/stream/geoTypes.d.ts +186 -0
  84. package/dist/components/stream/layouts/forceLayoutPlugin.d.ts +0 -7
  85. package/dist/components/stream/layouts/index.d.ts +2 -1
  86. package/dist/components/stream/layouts/orbitLayoutPlugin.d.ts +2 -0
  87. package/dist/components/stream/legendRenderer.d.ts +33 -0
  88. package/dist/components/stream/networkTypes.d.ts +49 -1
  89. package/dist/components/stream/ordinalTypes.d.ts +10 -0
  90. package/dist/components/stream/pipelineTransitionUtils.d.ts +42 -0
  91. package/dist/components/stream/renderers/geoCanvasRenderer.d.ts +9 -0
  92. package/dist/components/stream/renderers/heatmapCanvasRenderer.d.ts +2 -1
  93. package/dist/components/stream/renderers/lineCanvasRenderer.d.ts +1 -0
  94. package/dist/components/stream/renderers/renderPulse.d.ts +50 -0
  95. package/dist/components/stream/types.d.ts +77 -3
  96. package/dist/components/types/legendTypes.d.ts +27 -3
  97. package/dist/geo.min.js +1 -0
  98. package/dist/geo.module.min.js +1 -0
  99. package/dist/network.min.js +1 -1
  100. package/dist/network.module.min.js +1 -1
  101. package/dist/ordinal.min.js +1 -1
  102. package/dist/ordinal.module.min.js +1 -1
  103. package/dist/realtime.min.js +1 -1
  104. package/dist/realtime.module.min.js +1 -1
  105. package/dist/semiotic-ai.min.js +1 -1
  106. package/dist/semiotic-ai.module.min.js +1 -1
  107. package/dist/semiotic-data.d.ts +1 -0
  108. package/dist/semiotic-data.min.js +1 -1
  109. package/dist/semiotic-data.module.min.js +1 -1
  110. package/dist/semiotic-geo.d.ts +16 -0
  111. package/dist/semiotic-server.d.ts +1 -1
  112. package/dist/semiotic-xy.d.ts +1 -0
  113. package/dist/semiotic.d.ts +4 -4
  114. package/dist/semiotic.min.js +1 -1
  115. package/dist/semiotic.module.min.js +1 -1
  116. package/dist/server.min.js +1 -1
  117. package/dist/server.module.min.js +1 -1
  118. package/dist/test-utils/canvasMock.d.ts +3 -0
  119. package/dist/xy.min.js +1 -1
  120. package/dist/xy.module.min.js +1 -1
  121. package/package.json +29 -7
  122. package/dist/test/canvasMock.d.ts +0 -2
@@ -1,5 +1,7 @@
1
+ import { type Quadtree } from "d3-quadtree";
1
2
  import { RingBuffer } from "../realtime/RingBuffer";
2
- import type { Changeset, StreamChartType, StreamScales, StreamLayout, SceneNode, CandlestickStyle, Style, ArrowOfTime, WindowMode, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig } from "./types";
3
+ import type { Changeset, StreamChartType, StreamScales, StreamLayout, SceneNode, PointSceneNode, CandlestickStyle, Style, ArrowOfTime, WindowMode, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig, CurveType } from "./types";
4
+ import type { ActiveTransition } from "./pipelineTransitionUtils";
3
5
  export interface PipelineConfig {
4
6
  chartType: StreamChartType;
5
7
  runtimeMode?: "streaming" | "bounded";
@@ -7,6 +9,7 @@ export interface PipelineConfig {
7
9
  windowMode: WindowMode;
8
10
  arrowOfTime: ArrowOfTime;
9
11
  extentPadding: number;
12
+ maxCapacity?: number;
10
13
  xAccessor?: string | ((d: any) => number);
11
14
  yAccessor?: string | ((d: any) => number);
12
15
  timeAccessor?: string | ((d: any) => number);
@@ -16,6 +19,8 @@ export interface PipelineConfig {
16
19
  groupAccessor?: string | ((d: any) => string);
17
20
  categoryAccessor?: string | ((d: any) => string);
18
21
  lineDataAccessor?: string;
22
+ xScaleType?: "linear" | "log";
23
+ yScaleType?: "linear" | "log";
19
24
  xExtent?: [number | undefined, number | undefined] | [number];
20
25
  yExtent?: [number | undefined, number | undefined] | [number];
21
26
  sizeRange?: [number, number];
@@ -64,7 +69,10 @@ export interface PipelineConfig {
64
69
  heatmapAggregation?: "count" | "sum" | "mean";
65
70
  heatmapXBins?: number;
66
71
  heatmapYBins?: number;
72
+ showValues?: boolean;
73
+ heatmapValueFormat?: (v: number) => string;
67
74
  pointIdAccessor?: string | ((d: any) => string);
75
+ curve?: CurveType;
68
76
  }
69
77
  export declare class PipelineStore {
70
78
  private buffer;
@@ -86,17 +94,33 @@ export declare class PipelineStore {
86
94
  private getClose;
87
95
  private getPointId;
88
96
  private timestampBuffer;
89
- activeTransition: {
90
- startTime: number;
91
- duration: number;
92
- } | null;
97
+ activeTransition: ActiveTransition | null;
93
98
  private prevPositionMap;
99
+ /** Previous line/area path arrays for path interpolation */
100
+ private prevPathMap;
101
+ /** Exit nodes awaiting fade-out removal */
102
+ exitNodes: SceneNode[];
94
103
  lastIngestTime: number;
104
+ /** Unified color map cache keyed by sorted category set — shared across point, swarm, etc. */
105
+ private _colorMapCache;
106
+ /** Separate group→color map for resolveGroupColor (insertion-order based, never invalidates _colorMapCache) */
107
+ private _groupColorMap;
108
+ private _barCategoryCache;
109
+ /** Cache stacked area cumulative sums to skip recalculation when buffer hasn't changed */
110
+ private _stackExtentCache;
111
+ /** Monotonic counter incremented on each ingest — used as part of cache keys */
112
+ private _ingestVersion;
113
+ /** Cached materialized array from buffer.toArray() — only rebuilt when buffer changes */
114
+ private _bufferArrayCache;
115
+ /** True when the buffer has been mutated since last toArray() call */
116
+ private _bufferDirty;
95
117
  private needsFullRebuild;
96
118
  private lastLayout;
97
119
  scales: StreamScales | null;
98
120
  scene: SceneNode[];
99
121
  version: number;
122
+ private _quadtree;
123
+ private static readonly QUADTREE_THRESHOLD;
100
124
  constructor(config: PipelineConfig);
101
125
  /**
102
126
  * Process a changeset from DataSourceAdapter.
@@ -107,6 +131,16 @@ export declare class PipelineStore {
107
131
  * Recompute scales and scene graph for the current buffer contents.
108
132
  */
109
133
  computeScene(layout: StreamLayout): void;
134
+ /**
135
+ * Build or clear the quadtree spatial index for point scene nodes.
136
+ * Only built for scatter/bubble charts with >QUADTREE_THRESHOLD points.
137
+ */
138
+ private rebuildQuadtree;
139
+ /**
140
+ * Get the quadtree spatial index, if available.
141
+ * Returns null when chart type is not scatter/bubble or point count is below threshold.
142
+ */
143
+ get quadtree(): Quadtree<PointSceneNode> | null;
110
144
  /**
111
145
  * Remap existing scene node coordinates for a new layout size.
112
146
  * Proportionally scales all pixel coordinates without rebuilding from data.
@@ -161,6 +195,7 @@ export declare class PipelineStore {
161
195
  private getNodeIdentity;
162
196
  /**
163
197
  * After scene rebuild, set up transition from old to new positions.
198
+ * Detects entering nodes (new, no prev match) and exiting nodes (prev, no new match).
164
199
  */
165
200
  private startTransition;
166
201
  /**
@@ -168,8 +203,25 @@ export declare class PipelineStore {
168
203
  */
169
204
  advanceTransition(now: number): boolean;
170
205
  private groupData;
206
+ /**
207
+ * Resolve a category→color map from data using the colorAccessor.
208
+ * Caches the result in _colorMapCache keyed by sorted category set —
209
+ * only rebuilds when the set of categories changes.
210
+ */
211
+ private resolveColorMap;
171
212
  private resolveLineStyle;
172
213
  private resolveAreaStyle;
214
+ /** Resolve a group name to a color from the cached color map or a dedicated group palette.
215
+ * First checks _colorMapCache (populated by resolveColorMap when colorAccessor is set).
216
+ * Falls back to _groupColorMap (insertion-order, never mutates _colorMapCache). */
217
+ private resolveGroupColor;
218
+ /**
219
+ * Return a cached materialized array of the buffer contents.
220
+ * Only calls buffer.toArray() when the buffer has actually changed
221
+ * (new push, resize, or clear), avoiding per-frame allocation on
222
+ * transition ticks, hover redraws, and other non-data-changing renders.
223
+ */
224
+ private getBufferArray;
173
225
  getData(): Record<string, any>[];
174
226
  getExtents(): {
175
227
  x: [number, number];
@@ -2,7 +2,7 @@ import * as React from "react";
2
2
  import type { StreamScales, MarginalGraphicsConfig } from "./types";
3
3
  import type { AnnotationContext } from "../realtime/types";
4
4
  import type { ReactNode } from "react";
5
- import type { LegendGroup } from "../types/legendTypes";
5
+ import type { LegendGroup, GradientLegendConfig } from "../types/legendTypes";
6
6
  export interface AxisConfig {
7
7
  orient: "left" | "right" | "top" | "bottom";
8
8
  label?: string;
@@ -36,6 +36,8 @@ interface SVGOverlayProps {
36
36
  title?: string | ReactNode;
37
37
  legend?: ReactNode | {
38
38
  legendGroups: LegendGroup[];
39
+ } | {
40
+ gradient: GradientLegendConfig;
39
41
  };
40
42
  /** Callback when hovering a legend item */
41
43
  legendHoverBehavior?: (item: {
@@ -49,6 +51,8 @@ interface SVGOverlayProps {
49
51
  legendHighlightedCategory?: string | null;
50
52
  /** Set of isolated category labels (for click isolation) */
51
53
  legendIsolatedCategories?: Set<string>;
54
+ /** Legend position relative to chart area */
55
+ legendPosition?: "right" | "left" | "top" | "bottom";
52
56
  foregroundGraphics?: ReactNode;
53
57
  marginalGraphics?: MarginalGraphicsConfig;
54
58
  xValues?: number[];
@@ -65,7 +69,30 @@ interface SVGOverlayProps {
65
69
  y: number;
66
70
  r: number;
67
71
  }[];
72
+ /** Curve interpolation type for envelope annotations */
73
+ curve?: string;
74
+ /** When true, grid lines and axis baselines are skipped (rendered by SVGUnderlay instead) */
75
+ underlayRendered?: boolean;
68
76
  children?: ReactNode;
69
77
  }
78
+ interface SVGUnderlayProps {
79
+ width: number;
80
+ height: number;
81
+ totalWidth: number;
82
+ totalHeight: number;
83
+ margin: {
84
+ top: number;
85
+ right: number;
86
+ bottom: number;
87
+ left: number;
88
+ };
89
+ scales: StreamScales | null;
90
+ showAxes?: boolean;
91
+ axes?: AxisConfig[];
92
+ showGrid?: boolean;
93
+ xFormat?: (d: any) => string;
94
+ yFormat?: (d: any) => string;
95
+ }
96
+ export declare function SVGUnderlay(props: SVGUnderlayProps): React.JSX.Element | null;
70
97
  export declare function SVGOverlay(props: SVGOverlayProps): React.JSX.Element | null;
71
98
  export {};
@@ -1,13 +1,17 @@
1
- import type { SceneNode, LineSceneNode, AreaSceneNode, PointSceneNode, RectSceneNode, HeatcellSceneNode, Style, StreamScales } from "./types";
1
+ import type { SceneNode, LineSceneNode, AreaSceneNode, PointSceneNode, RectSceneNode, HeatcellSceneNode, Style, StreamScales, CurveType } from "./types";
2
2
  export declare function buildLineNode(data: Record<string, any>[], scales: StreamScales, xGet: (d: Record<string, any>) => number, yGet: (d: Record<string, any>) => number, style: Style, group?: string): LineSceneNode;
3
3
  export declare function buildAreaNode(data: Record<string, any>[], scales: StreamScales, xGet: (d: Record<string, any>) => number, yGet: (d: Record<string, any>) => number, baselineY: number, style: Style, group?: string, y0Get?: (d: Record<string, any>) => number): AreaSceneNode;
4
4
  export declare function buildStackedAreaNodes(groups: {
5
5
  key: string;
6
6
  data: Record<string, any>[];
7
- }[], scales: StreamScales, xGet: (d: Record<string, any>) => number, yGet: (d: Record<string, any>) => number, styleFn: (group: string, sampleDatum?: Record<string, any>) => Style, normalize?: boolean): AreaSceneNode[];
7
+ }[], scales: StreamScales, xGet: (d: Record<string, any>) => number, yGet: (d: Record<string, any>) => number, styleFn: (group: string, sampleDatum?: Record<string, any>) => Style, normalize?: boolean, curve?: CurveType): AreaSceneNode[];
8
8
  export declare function buildPointNode(datum: Record<string, any>, scales: StreamScales, xGet: (d: Record<string, any>) => number, yGet: (d: Record<string, any>) => number, r: number, style: Style, pointId?: string): PointSceneNode | null;
9
9
  export declare function buildRectNode(x: number, y: number, w: number, h: number, style: Style, datum: any, group?: string): RectSceneNode;
10
- export declare function buildHeatcellNode(x: number, y: number, w: number, h: number, fill: string, datum: any): HeatcellSceneNode;
10
+ export declare function buildHeatcellNode(x: number, y: number, w: number, h: number, fill: string, datum: any, options?: {
11
+ value?: number;
12
+ showValues?: boolean;
13
+ valueFormat?: (v: number) => string;
14
+ }): HeatcellSceneNode;
11
15
  export interface SceneGraphData {
12
16
  nodes: SceneNode[];
13
17
  version: number;
@@ -8,11 +8,13 @@ import * as React from "react";
8
8
  import type { SceneNode } from "./types";
9
9
  import type { NetworkSceneNode, NetworkSceneEdge, NetworkLabel } from "./networkTypes";
10
10
  import type { OrdinalSceneNode } from "./ordinalTypes";
11
+ import type { GeoSceneNode } from "./geoTypes";
11
12
  export declare function xySceneNodeToSVG(node: SceneNode, i: number): React.ReactNode;
12
13
  export declare function networkSceneNodeToSVG(node: NetworkSceneNode, i: number): React.ReactNode;
13
14
  export declare function networkSceneEdgeToSVG(edge: NetworkSceneEdge, i: number): React.ReactNode;
14
15
  export declare function networkLabelToSVG(label: NetworkLabel, i: number): React.ReactNode;
15
16
  export declare function ordinalSceneNodeToSVG(node: OrdinalSceneNode, i: number): React.ReactNode;
17
+ export declare function geoSceneNodeToSVG(node: GeoSceneNode, i: number): React.ReactNode;
16
18
  /**
17
19
  * Returns true when running in a true server/Node.js context where
18
20
  * window and document are not available.
@@ -0,0 +1,4 @@
1
+ import * as React from "react";
2
+ import type { StreamGeoFrameProps, StreamGeoFrameHandle } from "./geoTypes";
3
+ declare const StreamGeoFrame: React.ForwardRefExoticComponent<StreamGeoFrameProps<Record<string, any>> & React.RefAttributes<StreamGeoFrameHandle>>;
4
+ export default StreamGeoFrame;
@@ -1,2 +1,3 @@
1
1
  export declare function resolveAccessor<T>(accessor: string | ((d: T) => number) | undefined, fallback: string): (d: T) => number;
2
+ export declare function resolveRawAccessor<T>(accessor: string | ((d: T) => any) | undefined, fallback: string): (d: T) => any;
2
3
  export declare function resolveStringAccessor<T>(accessor: string | ((d: T) => string) | undefined, fallback?: string): ((d: T) => string) | undefined;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Shared canvas setup utilities used by all Stream Frames.
3
+ *
4
+ * Eliminates duplicated DPR / sizing / transform logic across
5
+ * StreamXYFrame, StreamGeoFrame, StreamNetworkFrame, and StreamOrdinalFrame.
6
+ */
7
+ export interface CanvasMargin {
8
+ top: number;
9
+ right: number;
10
+ bottom: number;
11
+ left: number;
12
+ }
13
+ /**
14
+ * Set a canvas element's physical (pixel) and CSS (logical) dimensions,
15
+ * accounting for devicePixelRatio. Returns the 2D context ready for drawing
16
+ * with the DPR transform and margin translation already applied.
17
+ *
18
+ * After this call the context's coordinate space is:
19
+ * (0, 0) = top-left of the chart area (inside margins)
20
+ * (-margin.left, -margin.top) = top-left of the full canvas
21
+ */
22
+ export declare function prepareCanvas(canvas: HTMLCanvasElement, size: [number, number], margin: CanvasMargin, dpr: number): CanvasRenderingContext2D | null;
23
+ /**
24
+ * Get the current devicePixelRatio, defaulting to 1 in non-browser environments.
25
+ */
26
+ export declare function getDevicePixelRatio(): number;
@@ -0,0 +1,186 @@
1
+ import type { ReactNode } from "react";
2
+ import type { GeoProjection, GeoPath, GeoPermissibleObjects } from "d3-geo";
3
+ import type { Style, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig, PointSceneNode, LineSceneNode } from "./types";
4
+ import type { HoverAnnotationConfig } from "../realtime/types";
5
+ import type { GeoParticleStyle } from "./GeoParticlePool";
6
+ export type ProjectionProp = GeoProjection | ProjectionName | ProjectionConfig;
7
+ export type ProjectionName = "mercator" | "equalEarth" | "albersUsa" | "orthographic" | "naturalEarth" | "equirectangular";
8
+ export interface ProjectionConfig {
9
+ type: ProjectionName;
10
+ rotate?: [number, number] | [number, number, number];
11
+ center?: [number, number];
12
+ parallels?: [number, number];
13
+ }
14
+ export interface GraticuleConfig {
15
+ step?: [number, number];
16
+ stroke?: string;
17
+ strokeWidth?: number;
18
+ strokeDasharray?: string;
19
+ showLabels?: boolean;
20
+ }
21
+ export interface DistanceCartogramConfig {
22
+ center: string;
23
+ centerAccessor?: string | ((d: any) => string);
24
+ costAccessor: string | ((d: any) => number);
25
+ strength?: number;
26
+ lineMode?: "straight" | "fractional";
27
+ }
28
+ export interface GeoAreaSceneNode {
29
+ type: "geoarea";
30
+ /** Pre-computed SVG path string from d3.geoPath(projection)(feature) */
31
+ pathData: string;
32
+ /** Centroid in screen coords (for tooltip/annotation positioning) */
33
+ centroid: [number, number];
34
+ /** Bounding box in screen coords [[x0,y0],[x1,y1]] */
35
+ bounds: [[number, number], [number, number]];
36
+ /** Screen-space area in px² */
37
+ screenArea: number;
38
+ style: Style;
39
+ datum: any;
40
+ group?: string;
41
+ interactive?: boolean;
42
+ /** Lazily-cached Path2D parsed from pathData (avoids re-parsing on every hit test) */
43
+ _cachedPath2D?: Path2D;
44
+ _decayOpacity?: number;
45
+ _pulseIntensity?: number;
46
+ _pulseColor?: string;
47
+ }
48
+ /** Union of all scene node types that GeoFrame produces */
49
+ export type GeoSceneNode = GeoAreaSceneNode | PointSceneNode | LineSceneNode;
50
+ export interface GeoScales {
51
+ projection: GeoProjection;
52
+ geoPath: GeoPath<any, GeoPermissibleObjects>;
53
+ projectedPoint: (lon: number, lat: number) => [number, number] | null;
54
+ invertedPoint: (px: number, py: number) => [number, number] | null;
55
+ }
56
+ export interface GeoPipelineConfig {
57
+ projection: ProjectionProp;
58
+ projectionExtent?: [[number, number], [number, number]];
59
+ /** Padding fraction for auto-fit projection. 0.1 = 10% inset from edges. @default 0 */
60
+ fitPadding?: number;
61
+ xAccessor?: string | ((d: any) => number);
62
+ yAccessor?: string | ((d: any) => number);
63
+ lineDataAccessor?: string | ((d: any) => any[]);
64
+ lineType?: "geo" | "line";
65
+ /** Flow rendering style: "basic" (straight/great-circle), "offset" (bidirectional offset), "arc" (curved arcs) @default "basic" */
66
+ flowStyle?: "basic" | "offset" | "arc";
67
+ areaStyle?: Style | ((d: any) => Style);
68
+ pointStyle?: (d: any) => Style & {
69
+ r?: number;
70
+ };
71
+ lineStyle?: Style | ((d: any, group?: string) => Style);
72
+ colorScheme?: string | string[];
73
+ graticule?: boolean | GraticuleConfig;
74
+ projectionTransform?: DistanceCartogramConfig;
75
+ decay?: DecayConfig;
76
+ pulse?: PulseConfig;
77
+ transition?: TransitionConfig;
78
+ annotations?: Record<string, any>[];
79
+ pointIdAccessor?: string | ((d: any) => string);
80
+ }
81
+ export interface StreamGeoFrameProps<T = Record<string, any>> {
82
+ projection: ProjectionProp;
83
+ projectionExtent?: [[number, number], [number, number]];
84
+ /** Padding fraction for auto-fit projection. 0.1 = 10% inset from edges. @default 0 */
85
+ fitPadding?: number;
86
+ areas?: GeoJSON.Feature[];
87
+ points?: T[];
88
+ lines?: T[];
89
+ xAccessor?: string | ((d: T) => number);
90
+ yAccessor?: string | ((d: T) => number);
91
+ lineDataAccessor?: string | ((d: T) => any[]);
92
+ pointIdAccessor?: string | ((d: T) => string);
93
+ lineType?: "geo" | "line";
94
+ /** Flow rendering style: "basic" (straight/great-circle), "offset" (bidirectional offset), "arc" (curved arcs) @default "basic" */
95
+ flowStyle?: "basic" | "offset" | "arc";
96
+ graticule?: boolean | GraticuleConfig;
97
+ zoomable?: boolean;
98
+ zoomExtent?: [number, number];
99
+ onZoom?: (state: {
100
+ projection: GeoProjection;
101
+ zoom: number;
102
+ }) => void;
103
+ /**
104
+ * When true, drag gestures rotate the projection (globe spinning)
105
+ * instead of panning. Defaults to true for orthographic projection.
106
+ * Scroll-wheel zoom still works normally.
107
+ */
108
+ dragRotate?: boolean;
109
+ projectionTransform?: DistanceCartogramConfig;
110
+ /** Show animated particles flowing along line paths */
111
+ showParticles?: boolean;
112
+ /** Particle appearance and behavior config */
113
+ particleStyle?: GeoParticleStyle;
114
+ /** Raster tile URL template or function. Enables tile basemap (Mercator only). */
115
+ tileURL?: string | ((z: number, x: number, y: number, dpr: number) => string);
116
+ /** Attribution text for tile provider (e.g., "© OpenStreetMap contributors") */
117
+ tileAttribution?: string;
118
+ /** Max cached tiles @default 256 */
119
+ tileCacheSize?: number;
120
+ size?: [number, number];
121
+ width?: number;
122
+ height?: number;
123
+ responsiveWidth?: boolean;
124
+ responsiveHeight?: boolean;
125
+ margin?: {
126
+ top?: number;
127
+ right?: number;
128
+ bottom?: number;
129
+ left?: number;
130
+ };
131
+ className?: string;
132
+ background?: string;
133
+ runtimeMode?: "bounded" | "streaming";
134
+ areaStyle?: Style | ((d: any) => Style);
135
+ pointStyle?: (d: any) => Style & {
136
+ r?: number;
137
+ };
138
+ lineStyle?: Style | ((d: any, group?: string) => Style);
139
+ colorScheme?: string | string[];
140
+ enableHover?: boolean;
141
+ hoverAnnotation?: boolean | HoverAnnotationConfig;
142
+ tooltipContent?: (d: any) => ReactNode;
143
+ customClickBehavior?: (d: any) => void;
144
+ customHoverBehavior?: (d: any) => void;
145
+ annotations?: Record<string, any>[];
146
+ decay?: DecayConfig;
147
+ pulse?: PulseConfig;
148
+ transition?: TransitionConfig;
149
+ staleness?: StalenessConfig;
150
+ backgroundGraphics?: ReactNode;
151
+ foregroundGraphics?: ReactNode;
152
+ title?: string | ReactNode;
153
+ legend?: any;
154
+ legendPosition?: "right" | "left" | "top" | "bottom";
155
+ legendHoverBehavior?: (item: {
156
+ label: string;
157
+ } | null) => void;
158
+ legendClickBehavior?: (item: {
159
+ label: string;
160
+ }) => void;
161
+ legendHighlightedCategory?: string | null;
162
+ legendIsolatedCategories?: Set<string>;
163
+ showAxes?: boolean;
164
+ /** Render a visually-hidden data table from the scene graph for screen readers (first 50 rows) */
165
+ accessibleTable?: boolean;
166
+ }
167
+ export interface StreamGeoFrameHandle {
168
+ push(datum: Record<string, any>): void;
169
+ pushMany(data: Record<string, any>[]): void;
170
+ clear(): void;
171
+ getProjection(): GeoProjection | null;
172
+ getGeoPath(): GeoPath<any, GeoPermissibleObjects> | null;
173
+ /** Get cartogram layout info (center position, max cost, radius) */
174
+ getCartogramLayout(): {
175
+ cx: number;
176
+ cy: number;
177
+ maxCost: number;
178
+ availableRadius: number;
179
+ } | null;
180
+ /** Get current zoom level (1 = default) */
181
+ getZoom(): number;
182
+ /** Animate back to initial view */
183
+ resetZoom(): void;
184
+ /** Get current data points */
185
+ getData(): Record<string, any>[];
186
+ }
@@ -1,9 +1,2 @@
1
1
  import type { NetworkLayoutPlugin } from "../networkTypes";
2
- /**
3
- * Force-directed layout plugin — uses d3-force for physics-based node positioning.
4
- *
5
- * Produces circle scene nodes and line scene edges. Runs the force simulation
6
- * synchronously for a configurable number of iterations, using phyllotaxis
7
- * spiral for deterministic initial positions.
8
- */
9
2
  export declare const forceLayoutPlugin: NetworkLayoutPlugin;
@@ -3,9 +3,10 @@ import { sankeyLayoutPlugin } from "./sankeyLayoutPlugin";
3
3
  import { forceLayoutPlugin } from "./forceLayoutPlugin";
4
4
  import { chordLayoutPlugin } from "./chordLayoutPlugin";
5
5
  import { hierarchyLayoutPlugin } from "./hierarchyLayoutPlugin";
6
+ import { orbitLayoutPlugin } from "./orbitLayoutPlugin";
6
7
  /**
7
8
  * Registry mapping network chart types to their layout plugins.
8
9
  */
9
10
  export declare const networkLayoutRegistry: Record<string, NetworkLayoutPlugin>;
10
11
  export declare function getLayoutPlugin(chartType: NetworkChartType): NetworkLayoutPlugin | undefined;
11
- export { sankeyLayoutPlugin, forceLayoutPlugin, chordLayoutPlugin, hierarchyLayoutPlugin };
12
+ export { sankeyLayoutPlugin, forceLayoutPlugin, chordLayoutPlugin, hierarchyLayoutPlugin, orbitLayoutPlugin };
@@ -0,0 +1,2 @@
1
+ import type { NetworkLayoutPlugin } from "../networkTypes";
2
+ export declare const orbitLayoutPlugin: NetworkLayoutPlugin;
@@ -0,0 +1,33 @@
1
+ import type { ReactNode } from "react";
2
+ import type { LegendGroup, GradientLegendConfig } from "../types/legendTypes";
3
+ export interface LegendRenderConfig {
4
+ legend: ReactNode | {
5
+ legendGroups: LegendGroup[];
6
+ } | {
7
+ gradient: GradientLegendConfig;
8
+ };
9
+ totalWidth: number;
10
+ totalHeight: number;
11
+ margin: {
12
+ top: number;
13
+ right: number;
14
+ bottom: number;
15
+ left: number;
16
+ };
17
+ legendPosition?: "right" | "left" | "top" | "bottom";
18
+ title?: string | ReactNode;
19
+ legendHoverBehavior?: (item: {
20
+ label: string;
21
+ } | null) => void;
22
+ legendClickBehavior?: (item: {
23
+ label: string;
24
+ }) => void;
25
+ legendHighlightedCategory?: string | null;
26
+ legendIsolatedCategories?: Set<string>;
27
+ legendInteraction?: string;
28
+ }
29
+ /**
30
+ * Renders a legend (categorical, gradient, or custom ReactNode) inside an SVG overlay.
31
+ * Computes position based on `legendPosition` and chart dimensions.
32
+ */
33
+ export declare function renderLegendFromConfig(config: LegendRenderConfig): ReactNode;
@@ -124,7 +124,7 @@ export interface RealtimeNetworkFrameProps {
124
124
  background?: string;
125
125
  className?: string;
126
126
  }
127
- export type NetworkChartType = "force" | "sankey" | "chord" | "tree" | "cluster" | "treemap" | "circlepack" | "partition";
127
+ export type NetworkChartType = "force" | "sankey" | "chord" | "tree" | "cluster" | "treemap" | "circlepack" | "orbit" | "partition";
128
128
  /** Circle node — used by force, tree, cluster, circlepack */
129
129
  export interface NetworkCircleNode {
130
130
  type: "circle";
@@ -240,6 +240,17 @@ export interface NetworkLayoutPlugin {
240
240
  supportsStreaming: boolean;
241
241
  /** Whether this layout uses hierarchical (tree) input instead of nodes+edges */
242
242
  hierarchical: boolean;
243
+ /**
244
+ * Whether this layout drives continuous animation (e.g. orbiting nodes).
245
+ * When true, StreamNetworkFrame keeps its RAF loop alive and calls `tick()` each frame.
246
+ */
247
+ supportsAnimation?: boolean;
248
+ /**
249
+ * Advance one animation frame. Called by StreamNetworkFrame on each RAF tick
250
+ * when `supportsAnimation` is true. Should mutate node positions in-place.
251
+ * Returns true if the scene needs a rebuild (always true for orbit animation).
252
+ */
253
+ tick?: (nodes: RealtimeNode[], edges: RealtimeEdge[], config: NetworkPipelineConfig, size: [number, number], deltaTime: number) => boolean;
243
254
  }
244
255
  /** Threshold alerting configuration for streaming network nodes */
245
256
  export interface ThresholdAlertConfig {
@@ -284,6 +295,7 @@ export interface NetworkPipelineConfig {
284
295
  edgeStyle?: (d: any) => Record<string, any>;
285
296
  nodeLabel?: string | ((d: any) => string);
286
297
  showLabels?: boolean;
298
+ labelMode?: "leaf" | "parent" | "all";
287
299
  colorBy?: string | ((d: any) => string | number);
288
300
  colorScheme?: string | string[];
289
301
  edgeColorBy?: "source" | "target" | "gradient" | ((d: any) => string);
@@ -295,6 +307,30 @@ export interface NetworkPipelineConfig {
295
307
  pulse?: PulseConfig;
296
308
  staleness?: StalenessConfig;
297
309
  thresholds?: ThresholdAlertConfig;
310
+ /** Ring arrangement mode: "flat" (all children in one ring), "solar" (one per ring),
311
+ * "atomic" ([2,8] electron shell), or custom capacities. @default "flat" */
312
+ orbitMode?: "flat" | "solar" | "atomic" | number[];
313
+ /** Ring size divisor per depth. Larger = tighter orbits. @default 2.95 */
314
+ orbitSize?: number | ((node: any) => number);
315
+ /** Orbit speed multiplier (higher = faster rotation). @default 0.25 */
316
+ orbitSpeed?: number;
317
+ /** Per-node speed modifier. @default (node) => 1 / (node.depth + 1) */
318
+ orbitRevolution?: (node: any) => number;
319
+ /**
320
+ * Built-in revolution style presets:
321
+ * - "locked": children rotate with parent at decreasing speed (default)
322
+ * - "decay": each depth level progressively slower, independent of parent
323
+ * - "alternate": odd-depth rings reverse direction
324
+ * Ignored when `orbitRevolution` is provided.
325
+ * @default "locked"
326
+ */
327
+ orbitRevolutionStyle?: "locked" | "decay" | "alternate";
328
+ /** Vertical squash for elliptical orbits. 1 = circle. @default 1 */
329
+ orbitEccentricity?: number | ((node: any) => number);
330
+ /** Show orbital ring ellipses as foreground graphics. @default true */
331
+ orbitShowRings?: boolean;
332
+ /** Enable orbit animation. @default true */
333
+ orbitAnimated?: boolean;
298
334
  }
299
335
  export interface StreamNetworkFrameProps<T = Record<string, any>> {
300
336
  chartType: NetworkChartType;
@@ -337,6 +373,7 @@ export interface StreamNetworkFrameProps<T = Record<string, any>> {
337
373
  nodeSizeRange?: [number, number];
338
374
  nodeLabel?: string | ((d: any) => string);
339
375
  showLabels?: boolean;
376
+ labelMode?: "leaf" | "parent" | "all";
340
377
  size?: [number, number];
341
378
  responsiveWidth?: boolean;
342
379
  responsiveHeight?: boolean;
@@ -377,6 +414,7 @@ export interface StreamNetworkFrameProps<T = Record<string, any>> {
377
414
  legend?: ReactNode | {
378
415
  legendGroups: LegendGroup[];
379
416
  };
417
+ legendPosition?: "right" | "left" | "top" | "bottom";
380
418
  legendHoverBehavior?: (item: {
381
419
  label: string;
382
420
  } | null) => void;
@@ -392,6 +430,16 @@ export interface StreamNetworkFrameProps<T = Record<string, any>> {
392
430
  pulse?: PulseConfig;
393
431
  staleness?: StalenessConfig;
394
432
  thresholds?: ThresholdAlertConfig;
433
+ orbitMode?: "flat" | "solar" | "atomic" | number[];
434
+ orbitSize?: number | ((node: any) => number);
435
+ orbitSpeed?: number;
436
+ orbitRevolution?: (node: any) => number;
437
+ orbitRevolutionStyle?: "locked" | "decay" | "alternate";
438
+ orbitEccentricity?: number | ((node: any) => number);
439
+ orbitShowRings?: boolean;
440
+ orbitAnimated?: boolean;
441
+ /** Render a visually-hidden data table from the scene graph for screen readers (first 50 rows) */
442
+ accessibleTable?: boolean;
395
443
  }
396
444
  export interface StreamNetworkFrameHandle {
397
445
  push(edge: EdgePush): void;
@@ -24,6 +24,8 @@ export interface WedgeSceneNode {
24
24
  _pulseIntensity?: number;
25
25
  /** Pulse color */
26
26
  _pulseColor?: string;
27
+ /** Animation target opacity (set during enter/exit transitions) */
28
+ _targetOpacity?: number;
27
29
  }
28
30
  export interface BoxplotSceneNode {
29
31
  type: "boxplot";
@@ -49,6 +51,7 @@ export interface BoxplotSceneNode {
49
51
  value: number;
50
52
  datum: any;
51
53
  }[];
54
+ _targetOpacity?: number;
52
55
  }
53
56
  export interface DistributionStats {
54
57
  n: number;
@@ -86,6 +89,7 @@ export interface ViolinSceneNode {
86
89
  style: Style;
87
90
  datum: any;
88
91
  category?: string;
92
+ _targetOpacity?: number;
89
93
  }
90
94
  export interface ConnectorSceneNode {
91
95
  type: "connector";
@@ -96,6 +100,7 @@ export interface ConnectorSceneNode {
96
100
  style: Style;
97
101
  datum: any;
98
102
  group?: string;
103
+ _targetOpacity?: number;
99
104
  }
100
105
  export type { Style, PointSceneNode, RectSceneNode } from "./types";
101
106
  import type { PointSceneNode, RectSceneNode } from "./types";
@@ -211,6 +216,8 @@ export interface StreamOrdinalFrameProps<T = Record<string, any>> {
211
216
  showGrid?: boolean;
212
217
  legend?: ReactNode | {
213
218
  legendGroups: LegendGroup[];
219
+ } | {
220
+ gradient: import("../types/legendTypes").GradientLegendConfig;
214
221
  };
215
222
  legendHoverBehavior?: (item: {
216
223
  label: string;
@@ -220,6 +227,7 @@ export interface StreamOrdinalFrameProps<T = Record<string, any>> {
220
227
  }) => void;
221
228
  legendHighlightedCategory?: string | null;
222
229
  legendIsolatedCategories?: Set<string>;
230
+ legendPosition?: "right" | "left" | "top" | "bottom";
223
231
  backgroundGraphics?: ReactNode;
224
232
  foregroundGraphics?: ReactNode;
225
233
  title?: string | ReactNode;
@@ -230,6 +238,8 @@ export interface StreamOrdinalFrameProps<T = Record<string, any>> {
230
238
  pulse?: PulseConfig;
231
239
  transition?: TransitionConfig;
232
240
  staleness?: StalenessConfig;
241
+ /** Render a visually-hidden data table from the scene graph for screen readers (first 50 rows) */
242
+ accessibleTable?: boolean;
233
243
  }
234
244
  export interface StreamOrdinalFrameHandle<T = Record<string, any>> {
235
245
  push(datum: T): void;