semiotic 3.3.1 → 3.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/CLAUDE.md +10 -4
- package/README.md +1 -1
- package/ai/dist/mcp-server.js +104 -9
- package/ai/schema.json +1 -1
- package/dist/components/LinkedCharts.d.ts +8 -0
- package/dist/components/charts/index.d.ts +1 -1
- package/dist/components/charts/ordinal/BarChart.d.ts +7 -1
- package/dist/components/charts/ordinal/DotPlot.d.ts +9 -1
- package/dist/components/charts/ordinal/GroupedBarChart.d.ts +2 -2
- package/dist/components/charts/ordinal/LikertChart.d.ts +5 -2
- package/dist/components/charts/ordinal/StackedBarChart.d.ts +2 -2
- package/dist/components/charts/shared/hooks.d.ts +15 -2
- package/dist/components/charts/shared/selectionUtils.d.ts +9 -7
- package/dist/components/charts/shared/tooltipUtils.d.ts +13 -1
- package/dist/components/charts/shared/types.d.ts +5 -6
- package/dist/components/charts/shared/useChartSetup.d.ts +8 -0
- package/dist/components/charts/shared/useResolvedSelection.d.ts +2 -0
- package/dist/components/realtime/types.d.ts +12 -0
- package/dist/components/semiotic-geo.d.ts +4 -0
- package/dist/components/semiotic-network.d.ts +7 -0
- package/dist/components/semiotic-ordinal.d.ts +8 -0
- package/dist/components/semiotic-xy.d.ts +9 -0
- package/dist/components/server/renderToStaticSVG.d.ts +1 -1
- package/dist/components/store/ThemeStore.d.ts +2 -0
- package/dist/components/stream/CanvasHitTester.d.ts +8 -3
- package/dist/components/stream/DataSourceAdapter.d.ts +17 -0
- package/dist/components/stream/GeoCanvasHitTester.d.ts +1 -1
- package/dist/components/stream/GeoPipelineStore.d.ts +19 -1
- package/dist/components/stream/NetworkPipelineStore.d.ts +5 -0
- package/dist/components/stream/OrdinalCanvasHitTester.d.ts +3 -1
- package/dist/components/stream/OrdinalPipelineStore.d.ts +38 -1
- package/dist/components/stream/ParticlePool.d.ts +4 -0
- package/dist/components/stream/PipelineStore.d.ts +17 -2
- package/dist/components/stream/StreamXYFrame.d.ts +17 -0
- package/dist/components/stream/geoTypes.d.ts +7 -0
- package/dist/components/stream/hoverUtils.d.ts +12 -0
- package/dist/components/stream/networkTypes.d.ts +19 -1
- package/dist/components/stream/ordinalTypes.d.ts +53 -12
- package/dist/components/stream/pipelineTransitionUtils.d.ts +21 -0
- package/dist/components/stream/quadtreeHitTest.d.ts +22 -0
- package/dist/components/stream/renderers/resolveCSSColor.d.ts +23 -6
- package/dist/components/stream/types.d.ts +18 -0
- package/dist/components/stream/useFrame.d.ts +122 -0
- package/dist/geo.min.js +1 -1
- package/dist/geo.module.min.js +1 -1
- package/dist/network.min.js +1 -1
- package/dist/network.module.min.js +1 -1
- package/dist/ordinal.min.js +1 -1
- package/dist/ordinal.module.min.js +1 -1
- package/dist/realtime.min.js +1 -1
- package/dist/realtime.module.min.js +1 -1
- package/dist/semiotic-ai.min.js +1 -1
- package/dist/semiotic-ai.module.min.js +1 -1
- package/dist/semiotic-geo.d.ts +4 -0
- package/dist/semiotic-network.d.ts +7 -0
- package/dist/semiotic-ordinal.d.ts +8 -0
- package/dist/semiotic-themes.min.js +1 -1
- package/dist/semiotic-themes.module.min.js +1 -1
- package/dist/semiotic-utils.min.js +1 -1
- package/dist/semiotic-utils.module.min.js +1 -1
- package/dist/semiotic-xy.d.ts +9 -0
- package/dist/semiotic.min.js +1 -1
- package/dist/semiotic.module.min.js +1 -1
- package/dist/server.min.js +1 -1
- package/dist/server.module.min.js +1 -1
- package/dist/test-utils/canvasMock.d.ts +26 -0
- package/dist/test-utils/ordinalFixtures.d.ts +48 -0
- package/dist/xy.min.js +1 -1
- package/dist/xy.module.min.js +1 -1
- package/package.json +15 -14
|
@@ -13,11 +13,16 @@ export interface HitResult {
|
|
|
13
13
|
* Dispatches to type-specific hit testers for optimal performance.
|
|
14
14
|
*
|
|
15
15
|
* When a quadtree spatial index is provided (for scatter/bubble charts with
|
|
16
|
-
* many points), point hit testing
|
|
17
|
-
*
|
|
16
|
+
* many points), point hit testing routes through `findHitPointInQuadtree`,
|
|
17
|
+
* which visits every candidate within the widened search radius (using
|
|
18
|
+
* `maxPointRadius` so variable-size points like BubbleChart can't hide
|
|
19
|
+
* behind a nearer non-hit). The visit is authoritative — when it returns
|
|
20
|
+
* null, no point hit exists and the linear point loop is skipped.
|
|
21
|
+
*
|
|
22
|
+
* Non-point node types (line, rect, area, heatcell, candlestick) still
|
|
18
23
|
* use the linear scan.
|
|
19
24
|
*/
|
|
20
|
-
export declare function findNearestNode(scene: SceneNode[], px: number, py: number, maxDistance?: number, pointQuadtree?: Quadtree<PointSceneNode> | null): HitResult | null;
|
|
25
|
+
export declare function findNearestNode(scene: SceneNode[], px: number, py: number, maxDistance?: number, pointQuadtree?: Quadtree<PointSceneNode> | null, maxPointRadius?: number): HitResult | null;
|
|
21
26
|
/**
|
|
22
27
|
* Find all line/area nodes at a given X pixel coordinate.
|
|
23
28
|
* For each node, interpolates the Y value at px using the path data.
|
|
@@ -32,6 +32,23 @@ export declare class DataSourceAdapter<T = Record<string, any>> {
|
|
|
32
32
|
* animation frames (bounded: false so they append without clearing).
|
|
33
33
|
*/
|
|
34
34
|
setBoundedData(data: T[]): void;
|
|
35
|
+
/**
|
|
36
|
+
* Replace the buffer contents without clearing category insertion-order
|
|
37
|
+
* memory. Intended for aggregator HOCs (e.g. LikertChart) that re-derive
|
|
38
|
+
* a full dataset from streaming input on every push — the transport is
|
|
39
|
+
* wholesale replacement, but the user perceives it as a live stream
|
|
40
|
+
* where categories should stay put across updates.
|
|
41
|
+
*
|
|
42
|
+
* Small datasets (≤ chunkThreshold) emit a single synchronous
|
|
43
|
+
* changeset — the common aggregator case. Larger datasets fall
|
|
44
|
+
* through to progressive chunking so an unexpectedly-huge replacement
|
|
45
|
+
* doesn't block the main thread. Only the first chunk carries
|
|
46
|
+
* `preserveCategoryOrder: true` (it's the one that resets the
|
|
47
|
+
* buffer and seeds the category Set); subsequent chunks are plain
|
|
48
|
+
* append-only streaming changesets, which preserve order anyway via
|
|
49
|
+
* the streaming-mode branch.
|
|
50
|
+
*/
|
|
51
|
+
setReplacementData(data: T[]): void;
|
|
35
52
|
/**
|
|
36
53
|
* Flush all buffered push data as a single changeset.
|
|
37
54
|
* Called automatically via microtask after push()/pushMany().
|
|
@@ -16,4 +16,4 @@ export interface GeoHitResult {
|
|
|
16
16
|
* The `hitCtx` parameter is a shared offscreen canvas context used for
|
|
17
17
|
* isPointInPath checks without polluting the visible canvas.
|
|
18
18
|
*/
|
|
19
|
-
export declare function findNearestGeoNode(nodes: GeoSceneNode[], mouseX: number, mouseY: number, maxDistance: number, hitCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, pointQuadtree?: Quadtree<PointSceneNode>): GeoHitResult | null;
|
|
19
|
+
export declare function findNearestGeoNode(nodes: GeoSceneNode[], mouseX: number, mouseY: number, maxDistance: number, hitCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, pointQuadtree?: Quadtree<PointSceneNode> | null, maxPointRadius?: number): GeoHitResult | null;
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import type { ZoomTransform } from "d3-zoom";
|
|
2
|
+
import { type Quadtree } from "d3-quadtree";
|
|
2
3
|
import type { GeoPipelineConfig, GeoScales, GeoSceneNode } from "./geoTypes";
|
|
3
|
-
import type { StreamLayout } from "./types";
|
|
4
|
+
import type { PointSceneNode, StreamLayout } from "./types";
|
|
4
5
|
import type { ActiveTransition } from "./pipelineTransitionUtils";
|
|
5
6
|
export declare class GeoPipelineStore {
|
|
6
7
|
config: GeoPipelineConfig;
|
|
7
8
|
scene: GeoSceneNode[];
|
|
8
9
|
scales: GeoScales | null;
|
|
9
10
|
version: number;
|
|
11
|
+
private static readonly QUADTREE_THRESHOLD;
|
|
12
|
+
private _quadtree;
|
|
13
|
+
/** Largest visual point radius in the current scene; used to widen quadtree
|
|
14
|
+
* hit-test radius when points are larger than the default maxDistance. */
|
|
15
|
+
private _maxPointRadius;
|
|
10
16
|
private projection;
|
|
11
17
|
private geoPath;
|
|
12
18
|
private baseScale;
|
|
@@ -28,6 +34,7 @@ export declare class GeoPipelineStore {
|
|
|
28
34
|
private timestampBuffer;
|
|
29
35
|
activeTransition: ActiveTransition | null;
|
|
30
36
|
private prevPositions;
|
|
37
|
+
private _hasRenderedOnce;
|
|
31
38
|
constructor(config: GeoPipelineConfig);
|
|
32
39
|
updateConfig(config: Partial<GeoPipelineConfig>): void;
|
|
33
40
|
setAreas(features: GeoJSON.Feature[]): void;
|
|
@@ -76,6 +83,17 @@ export declare class GeoPipelineStore {
|
|
|
76
83
|
translate: [number, number];
|
|
77
84
|
};
|
|
78
85
|
getPoints(): Record<string, any>[];
|
|
86
|
+
/**
|
|
87
|
+
* Build (or clear) the quadtree spatial index for point scene nodes.
|
|
88
|
+
* Only built when the point count exceeds QUADTREE_THRESHOLD; below that
|
|
89
|
+
* a linear scan is faster than indexing overhead. Also tracks the largest
|
|
90
|
+
* point radius so the hit tester can widen its query when symbols are big.
|
|
91
|
+
*/
|
|
92
|
+
private rebuildQuadtree;
|
|
93
|
+
/** Quadtree spatial index for point hit testing, or null when below threshold. */
|
|
94
|
+
get quadtree(): Quadtree<PointSceneNode> | null;
|
|
95
|
+
/** Largest visual point radius in the current scene. */
|
|
96
|
+
get maxPointRadius(): number;
|
|
79
97
|
private buildSceneNodes;
|
|
80
98
|
private applyCartogramTransform;
|
|
81
99
|
private applyDecay;
|
|
@@ -22,6 +22,11 @@ export declare class NetworkPipelineStore {
|
|
|
22
22
|
private config;
|
|
23
23
|
private tensionConfig;
|
|
24
24
|
transition: ActiveTransition | null;
|
|
25
|
+
private _hasRenderedOnce;
|
|
26
|
+
/** Snapshot of node positions from before bounded re-ingestion cleared the maps */
|
|
27
|
+
private _boundedPrevSnapshot;
|
|
28
|
+
/** Snapshot of edge positions from before bounded re-ingestion cleared the maps */
|
|
29
|
+
private _boundedEdgeSnapshot;
|
|
25
30
|
lastIngestTime: number;
|
|
26
31
|
private nodeTimestamps;
|
|
27
32
|
private edgeTimestamps;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { OrdinalSceneNode } from "./ordinalTypes";
|
|
2
|
+
import type { PointSceneNode } from "./types";
|
|
3
|
+
import type { Quadtree } from "d3-quadtree";
|
|
2
4
|
export interface OrdinalHitResult {
|
|
3
5
|
datum: any;
|
|
4
6
|
x: number;
|
|
@@ -7,4 +9,4 @@ export interface OrdinalHitResult {
|
|
|
7
9
|
category?: string;
|
|
8
10
|
stats?: import("./ordinalTypes").DistributionStats;
|
|
9
11
|
}
|
|
10
|
-
export declare function findNearestOrdinalNode(scene: OrdinalSceneNode[], px: number, py: number, maxDistance?: number): OrdinalHitResult | null;
|
|
12
|
+
export declare function findNearestOrdinalNode(scene: OrdinalSceneNode[], px: number, py: number, maxDistance?: number, pointQuadtree?: Quadtree<PointSceneNode> | null, maxPointRadius?: number): OrdinalHitResult | null;
|
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
* Consumed by: StreamOrdinalFrame (sole consumer).
|
|
16
16
|
*/
|
|
17
17
|
import { type ScaleLinear } from "d3-scale";
|
|
18
|
+
import { type Quadtree } from "d3-quadtree";
|
|
18
19
|
import type { OrdinalPipelineConfig, OrdinalScales, OrdinalSceneNode, OrdinalColumn, OrdinalLayout } from "./ordinalTypes";
|
|
19
|
-
import type { Changeset } from "./types";
|
|
20
|
+
import type { Changeset, PointSceneNode } from "./types";
|
|
20
21
|
import type { ActiveTransition } from "./pipelineTransitionUtils";
|
|
21
22
|
export declare class OrdinalPipelineStore {
|
|
22
23
|
private buffer;
|
|
@@ -52,6 +53,17 @@ export declare class OrdinalPipelineStore {
|
|
|
52
53
|
scene: OrdinalSceneNode[];
|
|
53
54
|
columns: Record<string, OrdinalColumn>;
|
|
54
55
|
version: number;
|
|
56
|
+
/** Bumped whenever the buffer is mutated. Used to invalidate per-frame caches. */
|
|
57
|
+
private _dataVersion;
|
|
58
|
+
private static readonly QUADTREE_THRESHOLD;
|
|
59
|
+
private _pointQuadtree;
|
|
60
|
+
/** Largest visual point radius in the current scene. */
|
|
61
|
+
private _maxPointRadius;
|
|
62
|
+
/** Cached datum→index map for applyDecay/applyPulse. Keyed by `_dataVersion`. */
|
|
63
|
+
private _datumIndexCache;
|
|
64
|
+
/** Cached category→indices map for applyPulse wedge path. Keyed by `_dataVersion`. */
|
|
65
|
+
private _categoryIndexCache;
|
|
66
|
+
private _hasRenderedOnce;
|
|
55
67
|
constructor(config: OrdinalPipelineConfig);
|
|
56
68
|
ingest(changeset: Changeset): boolean;
|
|
57
69
|
private pushValueExtent;
|
|
@@ -69,9 +81,34 @@ export declare class OrdinalPipelineStore {
|
|
|
69
81
|
private getColorFromScheme;
|
|
70
82
|
private resolveSummaryStyle;
|
|
71
83
|
computeDecayOpacity(bufferIndex: number, bufferSize: number): number;
|
|
84
|
+
/**
|
|
85
|
+
* Build (or return cached) datum→buffer-index map. Cached against
|
|
86
|
+
* `_dataVersion` so the per-frame applyDecay/applyPulse calls don't
|
|
87
|
+
* rebuild it during animation when the buffer hasn't changed.
|
|
88
|
+
*/
|
|
89
|
+
private getDatumIndexMap;
|
|
90
|
+
/**
|
|
91
|
+
* Build (or return cached) category→[indices] map used by applyPulse for
|
|
92
|
+
* wedge nodes. Cached against `_dataVersion` so the per-wedge inner loop
|
|
93
|
+
* collapses from O(data) to O(matches-for-this-category).
|
|
94
|
+
*/
|
|
95
|
+
private getCategoryIndexMap;
|
|
96
|
+
/**
|
|
97
|
+
* Build (or clear) a quadtree spatial index for point scene nodes.
|
|
98
|
+
* Useful for swarm plots — other ordinal types (bar/wedge/box/violin) are
|
|
99
|
+
* not indexed because they're typically few in number or already O(1) hit
|
|
100
|
+
* tests via bbox checks.
|
|
101
|
+
*/
|
|
102
|
+
private rebuildPointQuadtree;
|
|
103
|
+
/** Quadtree spatial index for point hit testing, or null when below threshold. */
|
|
104
|
+
get pointQuadtree(): Quadtree<PointSceneNode> | null;
|
|
105
|
+
/** Largest visual point radius in the current scene. */
|
|
106
|
+
get maxPointRadius(): number;
|
|
72
107
|
private applyDecay;
|
|
73
108
|
private applyPulse;
|
|
74
109
|
get hasActivePulses(): boolean;
|
|
110
|
+
/** Synthesize a zero-state prevPositionMap for animated intro (first render). */
|
|
111
|
+
private synthesizeIntroPositions;
|
|
75
112
|
/** Build a stable identity key for a scene node based on its content, not array index */
|
|
76
113
|
private getNodeKey;
|
|
77
114
|
private snapshotPositions;
|
|
@@ -4,10 +4,14 @@ import type { Particle, RealtimeEdge } from "./networkTypes";
|
|
|
4
4
|
*
|
|
5
5
|
* Pre-allocates a fixed-size array to avoid GC pressure.
|
|
6
6
|
* Particles travel along bezier paths within link bands.
|
|
7
|
+
*
|
|
8
|
+
* `_freeIndices` is a stack of currently-free slot indices. Spawn pops; step
|
|
9
|
+
* pushes when a particle expires. This makes spawn O(1) instead of O(capacity).
|
|
7
10
|
*/
|
|
8
11
|
export declare class ParticlePool {
|
|
9
12
|
particles: Particle[];
|
|
10
13
|
private capacity;
|
|
14
|
+
private _freeIndices;
|
|
11
15
|
constructor(capacity: number);
|
|
12
16
|
/**
|
|
13
17
|
* Spawn a new particle on the given edge.
|
|
@@ -76,11 +76,15 @@ export interface PipelineConfig {
|
|
|
76
76
|
strokeWidth?: number;
|
|
77
77
|
};
|
|
78
78
|
colorScheme?: string | string[];
|
|
79
|
+
/** Theme categorical palette — used as fallback when colorScheme is not an explicit array */
|
|
80
|
+
themeCategorical?: string[];
|
|
79
81
|
barColors?: Record<string, string>;
|
|
80
82
|
annotations?: Record<string, any>[];
|
|
81
83
|
decay?: DecayConfig;
|
|
82
84
|
pulse?: PulseConfig;
|
|
83
85
|
transition?: TransitionConfig;
|
|
86
|
+
/** Whether to animate elements on first render (points scale up, lines/areas clip from left, rects grow from baseline) */
|
|
87
|
+
introAnimation?: boolean;
|
|
84
88
|
staleness?: StalenessConfig;
|
|
85
89
|
heatmapAggregation?: "count" | "sum" | "mean";
|
|
86
90
|
heatmapXBins?: number;
|
|
@@ -111,6 +115,7 @@ export declare class PipelineStore {
|
|
|
111
115
|
private getPointId;
|
|
112
116
|
private timestampBuffer;
|
|
113
117
|
activeTransition: ActiveTransition | null;
|
|
118
|
+
private _hasRenderedOnce;
|
|
114
119
|
private prevPositionMap;
|
|
115
120
|
/** Previous line/area path arrays for path interpolation */
|
|
116
121
|
private prevPathMap;
|
|
@@ -140,6 +145,10 @@ export declare class PipelineStore {
|
|
|
140
145
|
/** True when the x accessor returns Date objects (auto-detected on first data ingestion) */
|
|
141
146
|
xIsDate: boolean;
|
|
142
147
|
private _quadtree;
|
|
148
|
+
/** Largest visual point radius in the current scene. The hit tester uses
|
|
149
|
+
* this to widen its quadtree query so points with big radii (bubble) don't
|
|
150
|
+
* fall outside the search region. */
|
|
151
|
+
private _maxPointRadius;
|
|
143
152
|
private static readonly QUADTREE_THRESHOLD;
|
|
144
153
|
constructor(config: PipelineConfig);
|
|
145
154
|
/**
|
|
@@ -161,6 +170,8 @@ export declare class PipelineStore {
|
|
|
161
170
|
* Returns null when chart type is not scatter/bubble or point count is below threshold.
|
|
162
171
|
*/
|
|
163
172
|
get quadtree(): Quadtree<PointSceneNode> | null;
|
|
173
|
+
/** Largest visual point radius in the current scene. */
|
|
174
|
+
get maxPointRadius(): number;
|
|
164
175
|
/**
|
|
165
176
|
* Remap existing scene node coordinates for a new layout size.
|
|
166
177
|
* Proportionally scales all pixel coordinates without rebuilding from data.
|
|
@@ -174,13 +185,17 @@ export declare class PipelineStore {
|
|
|
174
185
|
get hasActivePulses(): boolean;
|
|
175
186
|
private get transitionContext();
|
|
176
187
|
private snapshotPositions;
|
|
188
|
+
/** Synthesize a zero-state prevPositionMap/prevPathMap for animated intro (first render). */
|
|
189
|
+
private synthesizeIntroPositions;
|
|
177
190
|
private startTransition;
|
|
178
191
|
advanceTransition(now: number): boolean;
|
|
179
192
|
private groupData;
|
|
180
193
|
/**
|
|
181
194
|
* Resolve a category→color map from data using the colorAccessor.
|
|
182
|
-
* Caches the result in _colorMapCache keyed by
|
|
183
|
-
*
|
|
195
|
+
* Caches the result in _colorMapCache keyed by `_ingestVersion` (fast path)
|
|
196
|
+
* and a sorted-category fingerprint (so palette/scheme changes still
|
|
197
|
+
* invalidate). Multiple scene builders within one frame skip the data scan
|
|
198
|
+
* entirely after the first call.
|
|
184
199
|
*/
|
|
185
200
|
private resolveColorMap;
|
|
186
201
|
private resolveLineStyle;
|
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { StreamXYFrameProps, StreamXYFrameHandle } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Append a 2-char hex alpha to an existing CSS color, returning a valid
|
|
5
|
+
* CSS color string. The naive `${color}${alpha}` concatenation only works
|
|
6
|
+
* when `color` is a 6-char `#rrggbb`; shorthand `#rgb` produces the
|
|
7
|
+
* invalid 5-char `#rgbXX`, which `ctx.strokeStyle`/`fillStyle` silently
|
|
8
|
+
* rejects (falling back to `#000000` — black, invisible on dark themes).
|
|
9
|
+
* The /cookbook/marginal-graphics crosshair invisibility was caused
|
|
10
|
+
* precisely by `--semiotic-text-secondary: "#aaa"` hitting this path.
|
|
11
|
+
*
|
|
12
|
+
* Handles:
|
|
13
|
+
* • 3-char hex (`#abc`) → expanded to 6-char then concatenated
|
|
14
|
+
* • 6-char hex (`#aabbcc`) → concatenated directly
|
|
15
|
+
* • `rgb(...)` → repacked as `rgba(..., a)` with numeric alpha
|
|
16
|
+
* Any other form (named colors, hsl(), oklch(), etc.) falls back to the
|
|
17
|
+
* raw color without alpha — degrades gracefully.
|
|
18
|
+
*/
|
|
19
|
+
export declare function withAlpha(color: string, alphaHex: string): string;
|
|
3
20
|
declare const StreamXYFrame: React.ForwardRefExoticComponent<StreamXYFrameProps<Record<string, any>> & React.RefAttributes<StreamXYFrameHandle<Record<string, any>>>>;
|
|
4
21
|
export default StreamXYFrame;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { GeoProjection, GeoPath, GeoPermissibleObjects } from "d3-geo";
|
|
3
3
|
import type { Style, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig, PointSceneNode, LineSceneNode } from "./types";
|
|
4
|
+
import type { AnimateProp } from "./pipelineTransitionUtils";
|
|
4
5
|
import type { HoverAnnotationConfig, HoverData } from "../realtime/types";
|
|
5
6
|
import type { GeoParticleStyle } from "./GeoParticlePool";
|
|
6
7
|
export type ProjectionProp = GeoProjection | ProjectionName | ProjectionConfig;
|
|
@@ -75,6 +76,8 @@ export interface GeoPipelineConfig {
|
|
|
75
76
|
decay?: DecayConfig;
|
|
76
77
|
pulse?: PulseConfig;
|
|
77
78
|
transition?: TransitionConfig;
|
|
79
|
+
/** Whether to animate elements on first render */
|
|
80
|
+
introAnimation?: boolean;
|
|
78
81
|
annotations?: Record<string, any>[];
|
|
79
82
|
pointIdAccessor?: string | ((d: any) => string);
|
|
80
83
|
}
|
|
@@ -146,6 +149,10 @@ export interface StreamGeoFrameProps<T = Record<string, any>> {
|
|
|
146
149
|
decay?: DecayConfig;
|
|
147
150
|
pulse?: PulseConfig;
|
|
148
151
|
transition?: TransitionConfig;
|
|
152
|
+
/** Declarative animation: `true` for defaults (300ms ease-out), or config object.
|
|
153
|
+
* When enabled, charts animate on first render (intro) and on data change.
|
|
154
|
+
* Set `{ intro: false }` to disable the intro animation. */
|
|
155
|
+
animate?: AnimateProp;
|
|
149
156
|
staleness?: StalenessConfig;
|
|
150
157
|
backgroundGraphics?: ReactNode;
|
|
151
158
|
foregroundGraphics?: ReactNode;
|
|
@@ -7,6 +7,18 @@
|
|
|
7
7
|
* property flattening that are handled at the call site.
|
|
8
8
|
*/
|
|
9
9
|
import type { HoverData } from "../realtime/types";
|
|
10
|
+
/**
|
|
11
|
+
* Minimal shape a Stream Frame's internal hover handler needs from a pointer
|
|
12
|
+
* event. React.MouseEvent satisfies this structurally, as does the plain
|
|
13
|
+
* `{clientX, clientY}` object the rAF-coalescing path synthesizes. Using this
|
|
14
|
+
* narrower type on `hoverHandlerRef` (instead of `React.MouseEvent`) prevents
|
|
15
|
+
* downstream code from reading event fields — `currentTarget`, `target`,
|
|
16
|
+
* `preventDefault` — that wouldn't survive the coalescing cast.
|
|
17
|
+
*/
|
|
18
|
+
export interface HoverPointerCoords {
|
|
19
|
+
clientX: number;
|
|
20
|
+
clientY: number;
|
|
21
|
+
}
|
|
10
22
|
/**
|
|
11
23
|
* Spread raw datum properties onto HoverData if it's a non-null,
|
|
12
24
|
* non-array object. Class instances (Date, etc.) are included —
|
|
@@ -2,7 +2,8 @@ import type { ReactNode } from "react";
|
|
|
2
2
|
import type { OnObservationCallback } from "../store/ObservationStore";
|
|
3
3
|
import type { HoverData, AnnotationContext } from "../realtime/types";
|
|
4
4
|
import type { LegendGroup } from "../types/legendTypes";
|
|
5
|
-
import type { Style, DecayConfig, PulseConfig, StalenessConfig } from "./types";
|
|
5
|
+
import type { Style, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig } from "./types";
|
|
6
|
+
import type { AnimateProp } from "./pipelineTransitionUtils";
|
|
6
7
|
export interface TensionConfig {
|
|
7
8
|
weightChange: number;
|
|
8
9
|
newEdge: number;
|
|
@@ -52,6 +53,8 @@ export interface RealtimeEdge {
|
|
|
52
53
|
_targetY0?: number;
|
|
53
54
|
_targetY1?: number;
|
|
54
55
|
_targetSankeyWidth?: number;
|
|
56
|
+
/** Set during intro animation to allow edge interpolation from width 0 */
|
|
57
|
+
_introFromZero?: boolean;
|
|
55
58
|
direction?: string;
|
|
56
59
|
circular?: boolean;
|
|
57
60
|
circularPathData?: any;
|
|
@@ -208,6 +211,9 @@ export interface NetworkBezierEdge {
|
|
|
208
211
|
datum: any;
|
|
209
212
|
_pulseIntensity?: number;
|
|
210
213
|
_pulseColor?: string;
|
|
214
|
+
/** Lazily-built Path2D for hit testing; invalidated when pathD changes. */
|
|
215
|
+
_cachedPath2D?: Path2D;
|
|
216
|
+
_cachedPath2DSource?: string;
|
|
211
217
|
}
|
|
212
218
|
/** Ribbon edge — used by chord */
|
|
213
219
|
export interface NetworkRibbonEdge {
|
|
@@ -217,6 +223,8 @@ export interface NetworkRibbonEdge {
|
|
|
217
223
|
datum: any;
|
|
218
224
|
_pulseIntensity?: number;
|
|
219
225
|
_pulseColor?: string;
|
|
226
|
+
_cachedPath2D?: Path2D;
|
|
227
|
+
_cachedPath2DSource?: string;
|
|
220
228
|
}
|
|
221
229
|
/** Curved edge — used by tree, cluster */
|
|
222
230
|
export interface NetworkCurvedEdge {
|
|
@@ -226,6 +234,8 @@ export interface NetworkCurvedEdge {
|
|
|
226
234
|
datum: any;
|
|
227
235
|
_pulseIntensity?: number;
|
|
228
236
|
_pulseColor?: string;
|
|
237
|
+
_cachedPath2D?: Path2D;
|
|
238
|
+
_cachedPath2DSource?: string;
|
|
229
239
|
}
|
|
230
240
|
export type NetworkSceneNode = NetworkCircleNode | NetworkRectNode | NetworkArcNode;
|
|
231
241
|
export type NetworkSceneEdge = NetworkLineEdge | NetworkBezierEdge | NetworkRibbonEdge | NetworkCurvedEdge;
|
|
@@ -328,6 +338,9 @@ export interface NetworkPipelineConfig {
|
|
|
328
338
|
nodeSizeRange?: [number, number];
|
|
329
339
|
decay?: DecayConfig;
|
|
330
340
|
pulse?: PulseConfig;
|
|
341
|
+
transition?: TransitionConfig;
|
|
342
|
+
/** Whether to animate elements on first render (nodes scale up, edges fade in) */
|
|
343
|
+
introAnimation?: boolean;
|
|
331
344
|
staleness?: StalenessConfig;
|
|
332
345
|
thresholds?: ThresholdAlertConfig;
|
|
333
346
|
/** Ring arrangement mode: "flat" (all children in one ring), "solar" (one per ring),
|
|
@@ -447,6 +460,11 @@ export interface StreamNetworkFrameProps<T = Record<string, any>> {
|
|
|
447
460
|
backgroundGraphics?: ReactNode;
|
|
448
461
|
decay?: DecayConfig;
|
|
449
462
|
pulse?: PulseConfig;
|
|
463
|
+
transition?: TransitionConfig;
|
|
464
|
+
/** Declarative animation: `true` for defaults (300ms ease-out), or config object.
|
|
465
|
+
* When enabled, charts animate on first render (intro) and on data change.
|
|
466
|
+
* Set `{ intro: false }` to disable the intro animation. */
|
|
467
|
+
animate?: AnimateProp;
|
|
450
468
|
staleness?: StalenessConfig;
|
|
451
469
|
thresholds?: ThresholdAlertConfig;
|
|
452
470
|
orbitMode?: "flat" | "solar" | "atomic" | number[];
|
|
@@ -2,6 +2,7 @@ import type { ReactNode } from "react";
|
|
|
2
2
|
import type { ScaleLinear, ScaleBand } from "d3-scale";
|
|
3
3
|
import type { ArrowOfTime, WindowMode, HoverAnnotationConfig, HoverData, AnnotationContext } from "../realtime/types";
|
|
4
4
|
import type { Style, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig } from "./types";
|
|
5
|
+
import type { AnimateProp } from "./pipelineTransitionUtils";
|
|
5
6
|
import type { LegendGroup } from "../types/legendTypes";
|
|
6
7
|
export type OrdinalChartType = "bar" | "clusterbar" | "point" | "swarm" | "pie" | "donut" | "boxplot" | "violin" | "histogram" | "ridgeline" | "timeline" | "funnel" | "bar-funnel" | "swimlane";
|
|
7
8
|
export interface OrdinalScales {
|
|
@@ -28,6 +29,8 @@ export interface WedgeSceneNode {
|
|
|
28
29
|
_pulseColor?: string;
|
|
29
30
|
_pulseGlowRadius?: number;
|
|
30
31
|
_targetOpacity?: number;
|
|
32
|
+
_targetStartAngle?: number;
|
|
33
|
+
_targetEndAngle?: number;
|
|
31
34
|
_transitionKey?: string;
|
|
32
35
|
}
|
|
33
36
|
export interface BoxplotSceneNode {
|
|
@@ -153,15 +156,17 @@ export interface OrdinalPipelineConfig {
|
|
|
153
156
|
windowMode: WindowMode;
|
|
154
157
|
extentPadding: number;
|
|
155
158
|
projection: "vertical" | "horizontal" | "radial";
|
|
156
|
-
|
|
157
|
-
|
|
159
|
+
categoryAccessor?: string | ((d: any) => string);
|
|
160
|
+
valueAccessor?: string | ((d: any) => number) | Array<string | ((d: any) => number)>;
|
|
158
161
|
colorAccessor?: string | ((d: any) => string);
|
|
159
162
|
stackBy?: string | ((d: any) => string);
|
|
160
163
|
groupBy?: string | ((d: any) => string);
|
|
161
|
-
multiAxis?: boolean;
|
|
162
164
|
timeAccessor?: string | ((d: any) => number);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
+
/** @deprecated Use categoryAccessor */
|
|
166
|
+
oAccessor?: string | ((d: any) => string);
|
|
167
|
+
/** @deprecated Use valueAccessor */
|
|
168
|
+
rAccessor?: string | ((d: any) => number) | Array<string | ((d: any) => number)>;
|
|
169
|
+
multiAxis?: boolean;
|
|
165
170
|
rExtent?: [number?, number?];
|
|
166
171
|
oExtent?: string[];
|
|
167
172
|
barPadding?: number;
|
|
@@ -182,34 +187,41 @@ export interface OrdinalPipelineConfig {
|
|
|
182
187
|
amplitude?: number;
|
|
183
188
|
connectorOpacity?: number;
|
|
184
189
|
showLabels?: boolean;
|
|
185
|
-
oSort?: ((a:
|
|
190
|
+
oSort?: ((a: string, b: string) => number) | boolean | "asc" | "desc" | "auto";
|
|
186
191
|
connectorAccessor?: string | ((d: any) => string);
|
|
187
192
|
connectorStyle?: Style | ((d: any) => Style);
|
|
188
193
|
dynamicColumnWidth?: string | ((data: any[]) => number);
|
|
189
194
|
pieceStyle?: (d: any, category?: string) => Style;
|
|
190
195
|
summaryStyle?: (d: any, category?: string) => Style;
|
|
191
196
|
colorScheme?: string | string[];
|
|
197
|
+
themeCategorical?: string[];
|
|
192
198
|
barColors?: Record<string, string>;
|
|
193
199
|
/** ID accessor for remove() — extracts a unique identifier from each datum */
|
|
194
200
|
dataIdAccessor?: string | ((d: any) => string);
|
|
195
201
|
decay?: DecayConfig;
|
|
196
202
|
pulse?: PulseConfig;
|
|
197
203
|
transition?: TransitionConfig;
|
|
204
|
+
/** Whether to animate elements on first render (bars grow from baseline, wedges sweep in) */
|
|
205
|
+
introAnimation?: boolean;
|
|
198
206
|
staleness?: StalenessConfig;
|
|
199
207
|
}
|
|
200
208
|
export interface StreamOrdinalFrameProps<T = Record<string, any>> {
|
|
201
209
|
chartType: OrdinalChartType;
|
|
202
210
|
runtimeMode?: "bounded" | "streaming";
|
|
203
211
|
data?: T[];
|
|
204
|
-
|
|
205
|
-
|
|
212
|
+
/** Category field — the ordinal dimension (replaces oAccessor) */
|
|
213
|
+
categoryAccessor?: string | ((d: T) => string);
|
|
214
|
+
/** Value field — the quantitative dimension (replaces rAccessor). Can be array for multiAxis. */
|
|
215
|
+
valueAccessor?: string | ((d: T) => number) | Array<string | ((d: T) => number)>;
|
|
206
216
|
colorAccessor?: string | ((d: T) => string);
|
|
207
217
|
stackBy?: string | ((d: T) => string);
|
|
208
218
|
groupBy?: string | ((d: T) => string);
|
|
209
|
-
multiAxis?: boolean;
|
|
210
219
|
timeAccessor?: string | ((d: T) => number);
|
|
211
|
-
|
|
212
|
-
|
|
220
|
+
/** @deprecated Use categoryAccessor instead */
|
|
221
|
+
oAccessor?: string | ((d: T) => string);
|
|
222
|
+
/** @deprecated Use valueAccessor instead */
|
|
223
|
+
rAccessor?: string | ((d: T) => number) | Array<string | ((d: T) => number)>;
|
|
224
|
+
multiAxis?: boolean;
|
|
213
225
|
projection?: "vertical" | "horizontal" | "radial";
|
|
214
226
|
size?: [number, number];
|
|
215
227
|
responsiveWidth?: boolean;
|
|
@@ -238,7 +250,7 @@ export interface StreamOrdinalFrameProps<T = Record<string, any>> {
|
|
|
238
250
|
rExtent?: [number?, number?];
|
|
239
251
|
oExtent?: string[];
|
|
240
252
|
extentPadding?: number;
|
|
241
|
-
oSort?: ((a:
|
|
253
|
+
oSort?: ((a: string, b: string) => number) | boolean | "asc" | "desc" | "auto";
|
|
242
254
|
arrowOfTime?: ArrowOfTime;
|
|
243
255
|
windowMode?: WindowMode;
|
|
244
256
|
windowSize?: number;
|
|
@@ -256,9 +268,21 @@ export interface StreamOrdinalFrameProps<T = Record<string, any>> {
|
|
|
256
268
|
barColors?: Record<string, string>;
|
|
257
269
|
showAxes?: boolean;
|
|
258
270
|
showCategoryTicks?: boolean;
|
|
271
|
+
/** Category axis label */
|
|
272
|
+
categoryLabel?: string;
|
|
273
|
+
/** Value axis label */
|
|
274
|
+
valueLabel?: string;
|
|
275
|
+
/** Category tick formatter */
|
|
276
|
+
categoryFormat?: (d: string, index?: number) => string | ReactNode;
|
|
277
|
+
/** Value tick formatter */
|
|
278
|
+
valueFormat?: (d: number | string) => string;
|
|
279
|
+
/** @deprecated Use categoryLabel */
|
|
259
280
|
oLabel?: string;
|
|
281
|
+
/** @deprecated Use valueLabel */
|
|
260
282
|
rLabel?: string;
|
|
283
|
+
/** @deprecated Use categoryFormat */
|
|
261
284
|
oFormat?: (d: string, index?: number) => string | ReactNode;
|
|
285
|
+
/** @deprecated Use valueFormat */
|
|
262
286
|
rFormat?: (d: number | string) => string;
|
|
263
287
|
enableHover?: boolean;
|
|
264
288
|
hoverAnnotation?: boolean | HoverAnnotationConfig;
|
|
@@ -298,6 +322,10 @@ export interface StreamOrdinalFrameProps<T = Record<string, any>> {
|
|
|
298
322
|
decay?: DecayConfig;
|
|
299
323
|
pulse?: PulseConfig;
|
|
300
324
|
transition?: TransitionConfig;
|
|
325
|
+
/** Declarative animation: `true` for defaults (300ms ease-out), or config object.
|
|
326
|
+
* When enabled, charts animate on first render (intro) and on data change.
|
|
327
|
+
* Set `{ intro: false }` to disable the intro animation. */
|
|
328
|
+
animate?: AnimateProp;
|
|
301
329
|
staleness?: StalenessConfig;
|
|
302
330
|
/** Render a visually-hidden data table from the scene graph for screen readers */
|
|
303
331
|
accessibleTable?: boolean;
|
|
@@ -309,6 +337,19 @@ export interface StreamOrdinalFrameProps<T = Record<string, any>> {
|
|
|
309
337
|
export interface StreamOrdinalFrameHandle<T = Record<string, any>> {
|
|
310
338
|
push(datum: T): void;
|
|
311
339
|
pushMany(data: T[]): void;
|
|
340
|
+
/** Replace all data. Unlike `clear() + pushMany()`, `replace()` preserves
|
|
341
|
+
* the previous scene's position snapshot so data-change transitions fire.
|
|
342
|
+
* Use when you need to swap in a full new dataset (e.g. re-aggregated
|
|
343
|
+
* values from streaming input) and want the bars/points/etc. to animate
|
|
344
|
+
* between the old and new positions.
|
|
345
|
+
*
|
|
346
|
+
* Note: for datasets within the DataSourceAdapter chunk threshold (the
|
|
347
|
+
* common case for aggregator HOCs like LikertChart) the replacement
|
|
348
|
+
* lands in a single changeset. Larger datasets fall through to the
|
|
349
|
+
* progressive-chunked path used by the `data` prop — the first chunk
|
|
350
|
+
* resets + seeds the buffer, subsequent chunks append on successive
|
|
351
|
+
* animation frames, so replacement is not instantaneous for large N. */
|
|
352
|
+
replace(data: T[]): void;
|
|
312
353
|
/** Remove data items by ID. Requires dataIdAccessor. */
|
|
313
354
|
remove(id: string | string[]): T[];
|
|
314
355
|
/** Update data items by ID in place. Requires dataIdAccessor. Returns previous values. */
|
|
@@ -40,3 +40,24 @@ export declare function lerp(from: number, to: number, t: number): number;
|
|
|
40
40
|
* Get the current timestamp in a way that works both in browser and Node.
|
|
41
41
|
*/
|
|
42
42
|
export declare function now(): number;
|
|
43
|
+
/** The animate prop type accepted by all HOCs and Stream Frames.
|
|
44
|
+
* Single source of truth — re-exported by types.ts, ordinalTypes.ts, networkTypes.ts, geoTypes.ts. */
|
|
45
|
+
export type AnimateProp = boolean | {
|
|
46
|
+
duration?: number;
|
|
47
|
+
easing?: "linear" | "ease-out";
|
|
48
|
+
intro?: boolean;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Resolve the declarative `animate` prop into a concrete TransitionConfig.
|
|
52
|
+
* Used by all 4 Stream Frames. `animate` takes precedence over `transitionProp`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function resolveAnimateConfig(animate: AnimateProp | undefined, transitionProp: {
|
|
55
|
+
duration?: number;
|
|
56
|
+
easing?: "ease-out" | "linear";
|
|
57
|
+
} | undefined): {
|
|
58
|
+
transition: {
|
|
59
|
+
duration?: number;
|
|
60
|
+
easing?: "ease-out" | "linear";
|
|
61
|
+
} | undefined;
|
|
62
|
+
introEnabled: boolean;
|
|
63
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Quadtree } from "d3-quadtree";
|
|
2
|
+
export interface QuadtreeHit<T> {
|
|
3
|
+
node: T;
|
|
4
|
+
distance: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Find the closest point whose own hit radius contains the cursor.
|
|
8
|
+
*
|
|
9
|
+
* Uses `quadtree.visit()` to enumerate every candidate within the widened
|
|
10
|
+
* search radius (maxDistance extended by the largest point radius in the
|
|
11
|
+
* scene). `quadtree.find()` alone is insufficient because it returns the
|
|
12
|
+
* nearest candidate by center-to-center distance — a farther point with a
|
|
13
|
+
* much larger visual radius can still be a valid hit that `find()` would
|
|
14
|
+
* hide.
|
|
15
|
+
*
|
|
16
|
+
* `T` must expose `x`, `y`, and `r` — the standard `PointSceneNode` shape.
|
|
17
|
+
*/
|
|
18
|
+
export declare function findHitPointInQuadtree<T extends {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
r: number;
|
|
22
|
+
}>(qt: Quadtree<T>, px: number, py: number, maxDistance: number, maxPointRadius: number): QuadtreeHit<T> | null;
|
|
@@ -5,13 +5,30 @@
|
|
|
5
5
|
* reads the computed value from the canvas element. Otherwise returns
|
|
6
6
|
* the input unchanged.
|
|
7
7
|
*
|
|
8
|
-
* Per-canvas cache avoids repeated getComputedStyle calls
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Per-canvas cache avoids repeated `getComputedStyle` calls. Cached entries
|
|
9
|
+
* are tagged with a global version counter that's bumped whenever a theme
|
|
10
|
+
* change is detected — either through `clearCSSColorCache()` (called by
|
|
11
|
+
* Stream Frames on `currentTheme` change) or via the global observer below
|
|
12
|
+
* (catches external class toggles on `<html>` and `prefers-color-scheme`
|
|
13
|
+
* media-query changes that bypass React).
|
|
11
14
|
*/
|
|
12
15
|
export declare function resolveCSSColor(ctx: CanvasRenderingContext2D, value: string | undefined): string | undefined;
|
|
13
16
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
17
|
+
* Invalidate the CSS variable cache. Stream Frames call this from their
|
|
18
|
+
* `currentTheme` `useEffect` so the next paint reads fresh computed values.
|
|
19
|
+
*
|
|
20
|
+
* The `canvas` argument is accepted for backward compatibility but ignored —
|
|
21
|
+
* invalidation is global because theme changes are global.
|
|
22
|
+
*/
|
|
23
|
+
export declare function clearCSSColorCache(_canvas?: HTMLCanvasElement): void;
|
|
24
|
+
/**
|
|
25
|
+
* Test-only: reset all cache state, including disconnecting any installed
|
|
26
|
+
* observer/matchMedia listeners. Required for test isolation — without it,
|
|
27
|
+
* observers accumulate across files and bump `currentVersion` more than once
|
|
28
|
+
* per real DOM mutation.
|
|
29
|
+
*
|
|
30
|
+
* `currentVersion` is *incremented* (not reset to zero) so any WeakMap entries
|
|
31
|
+
* that survive from a previous test can't accidentally be re-validated by a
|
|
32
|
+
* version collision.
|
|
16
33
|
*/
|
|
17
|
-
export declare function
|
|
34
|
+
export declare function _resetCSSColorCacheForTest(): void;
|