vizcraft 0.2.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/LICENSE.txt +21 -0
- package/README.md +104 -2
- package/dist/anim/animationBuilder.d.ts +2 -0
- package/dist/anim/animationBuilder.js +6 -1
- package/dist/anim/spec.d.ts +1 -1
- package/dist/anim/vizcraftAdapter.js +68 -1
- package/dist/builder.d.ts +70 -2
- package/dist/builder.js +719 -118
- package/dist/edgeLabels.d.ts +15 -0
- package/dist/edgeLabels.js +26 -0
- package/dist/edgePaths.d.ts +43 -0
- package/dist/edgePaths.js +253 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/overlayBuilder.d.ts +50 -0
- package/dist/overlayBuilder.js +80 -0
- package/dist/overlays.d.ts +113 -21
- package/dist/overlays.js +319 -1
- package/dist/runtimePatcher.d.ts +3 -3
- package/dist/runtimePatcher.js +231 -31
- package/dist/shapes.d.ts +25 -3
- package/dist/shapes.js +1009 -0
- package/dist/styles.d.ts +1 -1
- package/dist/styles.js +24 -0
- package/dist/types.d.ts +207 -1
- package/dist/types.js +2 -1
- package/package.json +1 -1
- package/dist/anim/player.test.d.ts +0 -1
- package/dist/anim/player.test.js +0 -49
- package/dist/index.test.d.ts +0 -1
- package/dist/index.test.js +0 -66
package/dist/styles.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const DEFAULT_VIZ_CSS = "\n.viz-canvas {\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.viz-node-label,\n.viz-edge-label {\n text-anchor: middle;\n dominant-baseline: middle;\n alignment-baseline: middle;\n transform: translateY(0);\n}\n\n.viz-canvas svg {\n width: 100%;\n height: 100%;\n overflow: visible;\n}\n\n/* Keyframes */\n@keyframes vizFlow {\n from {\n stroke-dashoffset: 20;\n }\n to {\n stroke-dashoffset: 0;\n }\n}\n\n/* Animation Classes */\n\n/* Flow Animation (Dashed line moving) */\n.viz-anim-flow .viz-edge {\n stroke-dasharray: 5, 5;\n animation: vizFlow var(--viz-anim-duration, 2s) linear infinite;\n}\n\n/* Node Transition */\n.viz-node-group {\n transition: transform 0.3s ease-out, opacity 0.3s ease-out;\n}\n\n/* Overlay Classes */\n.viz-grid-label {\n fill: #6B7280;\n font-size: 14px;\n font-weight: 600;\n opacity: 1;\n}\n\n.viz-signal {\n fill: #3B82F6;\n cursor: pointer;\n pointer-events: all; \n transition: transform 0.2s ease-out, fill 0.2s ease-out;\n}\n\n.viz-signal .viz-signal-shape {\n fill: inherit;\n}\n\n.viz-signal:hover {\n fill: #60A5FA;\n transform: scale(1.5);\n}\n\n.viz-data-point {\n fill: #F59E0B;\n transition: cx 0.3s ease-out, cy 0.3s ease-out;\n}\n";
|
|
1
|
+
export declare const DEFAULT_VIZ_CSS = "\n.viz-canvas {\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.viz-node-label,\n.viz-edge-label {\n text-anchor: middle;\n dominant-baseline: middle;\n alignment-baseline: middle;\n transform: translateY(0);\n}\n\n.viz-canvas svg {\n width: 100%;\n height: 100%;\n overflow: visible;\n}\n\n/* Keyframes */\n@keyframes vizFlow {\n from {\n stroke-dashoffset: 20;\n }\n to {\n stroke-dashoffset: 0;\n }\n}\n\n/* Animation Classes */\n\n/* Flow Animation (Dashed line moving) */\n.viz-anim-flow .viz-edge {\n stroke-dasharray: 5, 5;\n animation: vizFlow var(--viz-anim-duration, 2s) linear infinite;\n}\n\n/* Edge base styling (path elements need explicit fill:none) */\n.viz-edge {\n fill: none;\n stroke: currentColor;\n}\n\n.viz-edge-hit {\n fill: none;\n}\n\n/* Node Transition */\n.viz-node-group {\n transition: transform 0.3s ease-out, opacity 0.3s ease-out;\n}\n\n/* Overlay Classes */\n.viz-grid-label {\n fill: #6B7280;\n font-size: 14px;\n font-weight: 600;\n opacity: 1;\n}\n\n.viz-signal {\n fill: #3B82F6;\n cursor: pointer;\n pointer-events: all; \n transition: transform 0.2s ease-out, fill 0.2s ease-out;\n}\n\n.viz-signal .viz-signal-shape {\n fill: inherit;\n}\n\n.viz-signal:hover {\n fill: #60A5FA;\n transform: scale(1.5);\n}\n\n.viz-data-point {\n fill: #F59E0B;\n transition: cx 0.3s ease-out, cy 0.3s ease-out;\n}\n\n/* Connection ports (hidden by default, shown on node hover) */\n.viz-port {\n fill: #3B82F6;\n stroke: white;\n stroke-width: 1.5;\n opacity: 0;\n pointer-events: all;\n cursor: crosshair;\n transition: opacity 0.15s ease-out;\n}\n.viz-node-group:hover .viz-port {\n opacity: 1;\n}\n";
|
package/dist/styles.js
CHANGED
|
@@ -39,6 +39,16 @@ export const DEFAULT_VIZ_CSS = `
|
|
|
39
39
|
animation: vizFlow var(--viz-anim-duration, 2s) linear infinite;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/* Edge base styling (path elements need explicit fill:none) */
|
|
43
|
+
.viz-edge {
|
|
44
|
+
fill: none;
|
|
45
|
+
stroke: currentColor;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.viz-edge-hit {
|
|
49
|
+
fill: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
42
52
|
/* Node Transition */
|
|
43
53
|
.viz-node-group {
|
|
44
54
|
transition: transform 0.3s ease-out, opacity 0.3s ease-out;
|
|
@@ -72,4 +82,18 @@ export const DEFAULT_VIZ_CSS = `
|
|
|
72
82
|
fill: #F59E0B;
|
|
73
83
|
transition: cx 0.3s ease-out, cy 0.3s ease-out;
|
|
74
84
|
}
|
|
85
|
+
|
|
86
|
+
/* Connection ports (hidden by default, shown on node hover) */
|
|
87
|
+
.viz-port {
|
|
88
|
+
fill: #3B82F6;
|
|
89
|
+
stroke: white;
|
|
90
|
+
stroke-width: 1.5;
|
|
91
|
+
opacity: 0;
|
|
92
|
+
pointer-events: all;
|
|
93
|
+
cursor: crosshair;
|
|
94
|
+
transition: opacity 0.15s ease-out;
|
|
95
|
+
}
|
|
96
|
+
.viz-node-group:hover .viz-port {
|
|
97
|
+
opacity: 1;
|
|
98
|
+
}
|
|
75
99
|
`;
|
package/dist/types.d.ts
CHANGED
|
@@ -15,6 +15,89 @@ export type NodeShape = {
|
|
|
15
15
|
kind: 'diamond';
|
|
16
16
|
w: number;
|
|
17
17
|
h: number;
|
|
18
|
+
} | {
|
|
19
|
+
kind: 'cylinder';
|
|
20
|
+
w: number;
|
|
21
|
+
h: number;
|
|
22
|
+
arcHeight?: number;
|
|
23
|
+
} | {
|
|
24
|
+
kind: 'hexagon';
|
|
25
|
+
r: number;
|
|
26
|
+
orientation?: 'pointy' | 'flat';
|
|
27
|
+
} | {
|
|
28
|
+
kind: 'ellipse';
|
|
29
|
+
rx: number;
|
|
30
|
+
ry: number;
|
|
31
|
+
} | {
|
|
32
|
+
kind: 'arc';
|
|
33
|
+
r: number;
|
|
34
|
+
startAngle: number;
|
|
35
|
+
endAngle: number;
|
|
36
|
+
closed?: boolean;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'blockArrow';
|
|
39
|
+
length: number;
|
|
40
|
+
bodyWidth: number;
|
|
41
|
+
headWidth: number;
|
|
42
|
+
headLength: number;
|
|
43
|
+
direction?: 'right' | 'left' | 'up' | 'down';
|
|
44
|
+
} | {
|
|
45
|
+
kind: 'callout';
|
|
46
|
+
w: number;
|
|
47
|
+
h: number;
|
|
48
|
+
rx?: number;
|
|
49
|
+
pointerSide?: 'bottom' | 'top' | 'left' | 'right';
|
|
50
|
+
pointerHeight?: number;
|
|
51
|
+
pointerWidth?: number;
|
|
52
|
+
pointerPosition?: number;
|
|
53
|
+
} | {
|
|
54
|
+
kind: 'cloud';
|
|
55
|
+
w: number;
|
|
56
|
+
h: number;
|
|
57
|
+
} | {
|
|
58
|
+
kind: 'cross';
|
|
59
|
+
size: number;
|
|
60
|
+
barWidth?: number;
|
|
61
|
+
} | {
|
|
62
|
+
kind: 'cube';
|
|
63
|
+
w: number;
|
|
64
|
+
h: number;
|
|
65
|
+
depth?: number;
|
|
66
|
+
} | {
|
|
67
|
+
kind: 'path';
|
|
68
|
+
d: string;
|
|
69
|
+
w: number;
|
|
70
|
+
h: number;
|
|
71
|
+
} | {
|
|
72
|
+
kind: 'document';
|
|
73
|
+
w: number;
|
|
74
|
+
h: number;
|
|
75
|
+
waveHeight?: number;
|
|
76
|
+
} | {
|
|
77
|
+
kind: 'note';
|
|
78
|
+
w: number;
|
|
79
|
+
h: number;
|
|
80
|
+
foldSize?: number;
|
|
81
|
+
} | {
|
|
82
|
+
kind: 'parallelogram';
|
|
83
|
+
w: number;
|
|
84
|
+
h: number;
|
|
85
|
+
skew?: number;
|
|
86
|
+
} | {
|
|
87
|
+
kind: 'star';
|
|
88
|
+
points: number;
|
|
89
|
+
outerR: number;
|
|
90
|
+
innerR?: number;
|
|
91
|
+
} | {
|
|
92
|
+
kind: 'trapezoid';
|
|
93
|
+
topW: number;
|
|
94
|
+
bottomW: number;
|
|
95
|
+
h: number;
|
|
96
|
+
} | {
|
|
97
|
+
kind: 'triangle';
|
|
98
|
+
w: number;
|
|
99
|
+
h: number;
|
|
100
|
+
direction?: 'up' | 'down' | 'left' | 'right';
|
|
18
101
|
};
|
|
19
102
|
export type NodeLabel = {
|
|
20
103
|
text: string;
|
|
@@ -48,6 +131,48 @@ export type VizRuntimeEdgeProps = Partial<{
|
|
|
48
131
|
strokeDashoffset: number;
|
|
49
132
|
opacity: number;
|
|
50
133
|
}>;
|
|
134
|
+
export interface ContainerConfig {
|
|
135
|
+
/** Layout direction for children (default 'free') */
|
|
136
|
+
layout?: 'free' | 'vertical' | 'horizontal';
|
|
137
|
+
/** Padding inside the container */
|
|
138
|
+
padding?: {
|
|
139
|
+
top: number;
|
|
140
|
+
right: number;
|
|
141
|
+
bottom: number;
|
|
142
|
+
left: number;
|
|
143
|
+
};
|
|
144
|
+
/** Whether the container auto-resizes to fit children */
|
|
145
|
+
autoSize?: boolean;
|
|
146
|
+
/** Header height for swimlane-style headers */
|
|
147
|
+
headerHeight?: number;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* A named connection port (anchor point) on a node.
|
|
151
|
+
*
|
|
152
|
+
* Ports let edges connect to specific positions on a shape rather than
|
|
153
|
+
* the generic boundary intersection.
|
|
154
|
+
*/
|
|
155
|
+
export interface NodePort {
|
|
156
|
+
/** Unique port id within the node (e.g. `'top'`, `'left'`, `'out-1'`). */
|
|
157
|
+
id: string;
|
|
158
|
+
/**
|
|
159
|
+
* Position **relative to the node center** (absolute pixel offset).
|
|
160
|
+
*
|
|
161
|
+
* For example, on a 120×60 rect centered at the node's `pos`:
|
|
162
|
+
* - top port: `{ x: 0, y: -30 }`
|
|
163
|
+
* - right port: `{ x: 60, y: 0 }`
|
|
164
|
+
*/
|
|
165
|
+
offset: Vec2;
|
|
166
|
+
/**
|
|
167
|
+
* Optional direction hint for edge routing (outgoing tangent angle in **degrees**).
|
|
168
|
+
*
|
|
169
|
+
* - `0` = right
|
|
170
|
+
* - `90` = down
|
|
171
|
+
* - `180` = left
|
|
172
|
+
* - `270` = up
|
|
173
|
+
*/
|
|
174
|
+
direction?: number;
|
|
175
|
+
}
|
|
51
176
|
export interface VizNode {
|
|
52
177
|
id: string;
|
|
53
178
|
pos: Vec2;
|
|
@@ -64,6 +189,21 @@ export interface VizNode {
|
|
|
64
189
|
data?: unknown;
|
|
65
190
|
onClick?: (id: string, node: VizNode) => void;
|
|
66
191
|
animations?: VizAnimSpec[];
|
|
192
|
+
/**
|
|
193
|
+
* Named connection ports on this node.
|
|
194
|
+
*
|
|
195
|
+
* When an edge references a port via `fromPort` / `toPort`, the endpoint
|
|
196
|
+
* is resolved to `node.pos + port.offset` instead of the generic
|
|
197
|
+
* boundary intersection.
|
|
198
|
+
*
|
|
199
|
+
* If omitted, default ports for the node's shape are available automatically
|
|
200
|
+
* (see `getDefaultPorts`). Explicit ports override defaults entirely.
|
|
201
|
+
*/
|
|
202
|
+
ports?: NodePort[];
|
|
203
|
+
/** If set, this node is a child of the node with this id. */
|
|
204
|
+
parentId?: string;
|
|
205
|
+
/** Container-specific configuration (only on parent nodes). */
|
|
206
|
+
container?: ContainerConfig;
|
|
67
207
|
}
|
|
68
208
|
export interface EdgeLabel {
|
|
69
209
|
text: string;
|
|
@@ -72,20 +212,86 @@ export interface EdgeLabel {
|
|
|
72
212
|
dx?: number;
|
|
73
213
|
dy?: number;
|
|
74
214
|
}
|
|
215
|
+
/** Edge routing algorithm. */
|
|
216
|
+
export type EdgeRouting = 'straight' | 'curved' | 'orthogonal';
|
|
217
|
+
/**
|
|
218
|
+
* Edge marker/arrowhead types.
|
|
219
|
+
*
|
|
220
|
+
* - `'none'`: No marker
|
|
221
|
+
* - `'arrow'`: Filled triangle (default arrowhead)
|
|
222
|
+
* - `'arrowOpen'`: Open/unfilled triangle (V shape)
|
|
223
|
+
* - `'diamond'`: Filled diamond (UML composition)
|
|
224
|
+
* - `'diamondOpen'`: Open diamond (UML aggregation)
|
|
225
|
+
* - `'circle'`: Filled circle
|
|
226
|
+
* - `'circleOpen'`: Open circle
|
|
227
|
+
* - `'square'`: Filled square
|
|
228
|
+
* - `'bar'`: Perpendicular line (T shape, for cardinality)
|
|
229
|
+
* - `'halfArrow'`: Single-sided arrow (one wing)
|
|
230
|
+
*/
|
|
231
|
+
export type EdgeMarkerType = 'none' | 'arrow' | 'arrowOpen' | 'diamond' | 'diamondOpen' | 'circle' | 'circleOpen' | 'square' | 'bar' | 'halfArrow';
|
|
75
232
|
export interface VizEdge {
|
|
76
233
|
id: string;
|
|
77
234
|
from: string;
|
|
78
235
|
to: string;
|
|
236
|
+
/** @deprecated Use `labels` for multi-position support. Kept for backwards compatibility. */
|
|
79
237
|
label?: EdgeLabel;
|
|
238
|
+
/** Multiple labels at different positions along the edge. */
|
|
239
|
+
labels?: EdgeLabel[];
|
|
80
240
|
runtime?: VizRuntimeEdgeProps;
|
|
81
|
-
|
|
241
|
+
/** Marker at the target (end) of the edge. */
|
|
242
|
+
markerEnd?: EdgeMarkerType;
|
|
243
|
+
/** Marker at the source (start) of the edge. */
|
|
244
|
+
markerStart?: EdgeMarkerType;
|
|
245
|
+
/** Port id on the source node. When set, the edge starts at the port's position instead of the boundary. */
|
|
246
|
+
fromPort?: string;
|
|
247
|
+
/** Port id on the target node. When set, the edge ends at the port's position instead of the boundary. */
|
|
248
|
+
toPort?: string;
|
|
82
249
|
anchor?: 'center' | 'boundary';
|
|
250
|
+
/** Per-edge visual styling. Overrides the CSS defaults when set. */
|
|
251
|
+
style?: {
|
|
252
|
+
stroke?: string;
|
|
253
|
+
strokeWidth?: number;
|
|
254
|
+
fill?: string;
|
|
255
|
+
opacity?: number;
|
|
256
|
+
};
|
|
83
257
|
className?: string;
|
|
84
258
|
hitArea?: number;
|
|
85
259
|
data?: unknown;
|
|
86
260
|
onClick?: (id: string, edge: VizEdge) => void;
|
|
87
261
|
animations?: VizAnimSpec[];
|
|
262
|
+
/** Routing algorithm for the edge path (default: 'straight'). */
|
|
263
|
+
routing?: EdgeRouting;
|
|
264
|
+
/** User-defined intermediate waypoints the edge must pass through. */
|
|
265
|
+
waypoints?: Vec2[];
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Overlay kind -> params mapping.
|
|
269
|
+
*
|
|
270
|
+
* This interface is intentionally empty in core and is meant to be augmented by:
|
|
271
|
+
* - core overlays (in this repo)
|
|
272
|
+
* - downstream libraries/apps (via TS module augmentation)
|
|
273
|
+
*/
|
|
274
|
+
export interface OverlayKindRegistry {
|
|
88
275
|
}
|
|
276
|
+
/** Internal runtime flag used to mark overlays as needing a DOM update. */
|
|
277
|
+
export declare const OVERLAY_RUNTIME_DIRTY: unique symbol;
|
|
278
|
+
/** String overlay ids that are known/typed via `OverlayKindRegistry`. */
|
|
279
|
+
export type KnownOverlayId = Extract<keyof OverlayKindRegistry, string>;
|
|
280
|
+
/** Any overlay id (typed known ids + arbitrary custom ids). */
|
|
281
|
+
export type OverlayId = KnownOverlayId | (string & {});
|
|
282
|
+
/**
|
|
283
|
+
* Params type for a given overlay id.
|
|
284
|
+
* - Known ids resolve to their registered params type.
|
|
285
|
+
* - Unknown/custom ids fall back to `unknown` (escape hatch).
|
|
286
|
+
*/
|
|
287
|
+
export type OverlayParams<K extends string> = K extends KnownOverlayId ? OverlayKindRegistry[K] : unknown;
|
|
288
|
+
/** A type-safe overlay spec keyed by overlay id. */
|
|
289
|
+
export type TypedVizOverlaySpec<K extends OverlayId = OverlayId> = {
|
|
290
|
+
id: K;
|
|
291
|
+
key?: string;
|
|
292
|
+
params: OverlayParams<K>;
|
|
293
|
+
className?: string;
|
|
294
|
+
};
|
|
89
295
|
export type VizOverlaySpec<T = any> = {
|
|
90
296
|
id: string;
|
|
91
297
|
key?: string;
|
package/dist/types.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
/** Internal runtime flag used to mark overlays as needing a DOM update. */
|
|
2
|
+
export const OVERLAY_RUNTIME_DIRTY = Symbol('vizcraft.overlay.runtimeDirty');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vizcraft",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "A fluent, type-safe SVG scene builder for composing nodes, edges, animations, and overlays with incremental DOM updates and no framework dependency.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"visualization",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/anim/player.test.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { createPlayer } from './player';
|
|
3
|
-
describe('anim/player', () => {
|
|
4
|
-
it('chains sequential tweens on the same property', () => {
|
|
5
|
-
const state = new Map([['node:a|x', 120]]);
|
|
6
|
-
const adapter = {
|
|
7
|
-
get(target, prop) {
|
|
8
|
-
return state.get(`${target}|${prop}`);
|
|
9
|
-
},
|
|
10
|
-
set(target, prop, value) {
|
|
11
|
-
state.set(`${target}|${prop}`, value);
|
|
12
|
-
},
|
|
13
|
-
flush() {
|
|
14
|
-
// no-op
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
const spec = {
|
|
18
|
-
version: 'viz-anim/1',
|
|
19
|
-
tweens: [
|
|
20
|
-
{
|
|
21
|
-
kind: 'tween',
|
|
22
|
-
target: 'node:a',
|
|
23
|
-
property: 'x',
|
|
24
|
-
to: 320,
|
|
25
|
-
duration: 1200,
|
|
26
|
-
delay: 0,
|
|
27
|
-
easing: 'linear',
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
kind: 'tween',
|
|
31
|
-
target: 'node:a',
|
|
32
|
-
property: 'x',
|
|
33
|
-
to: 120,
|
|
34
|
-
duration: 1200,
|
|
35
|
-
delay: 1800,
|
|
36
|
-
easing: 'linear',
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
};
|
|
40
|
-
const player = createPlayer(adapter);
|
|
41
|
-
player.load(spec);
|
|
42
|
-
player.seek(600);
|
|
43
|
-
// Halfway from 120 -> 320
|
|
44
|
-
expect(state.get('node:a|x')).toBeCloseTo(220, 5);
|
|
45
|
-
player.seek(2400);
|
|
46
|
-
// Halfway from 320 -> 120 (1200ms into the second tween)
|
|
47
|
-
expect(state.get('node:a|x')).toBeCloseTo(220, 5);
|
|
48
|
-
});
|
|
49
|
-
});
|
package/dist/index.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/index.test.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { viz } from './index';
|
|
3
|
-
describe('vizcraft core', () => {
|
|
4
|
-
it('exports viz builder', () => {
|
|
5
|
-
expect(viz).toBeDefined();
|
|
6
|
-
expect(typeof viz).toBe('function');
|
|
7
|
-
});
|
|
8
|
-
it('creates a builder instance', () => {
|
|
9
|
-
const builder = viz();
|
|
10
|
-
expect(builder).toBeDefined();
|
|
11
|
-
// Verify default viewbox
|
|
12
|
-
const view = builder._getViewBox();
|
|
13
|
-
expect(view).toEqual({ w: 800, h: 600 });
|
|
14
|
-
});
|
|
15
|
-
it('supports data-only builder.animate(cb) and stores specs on the scene', () => {
|
|
16
|
-
const builder = viz();
|
|
17
|
-
builder.node('a').at(0, 0);
|
|
18
|
-
builder.node('b').at(10, 10);
|
|
19
|
-
builder.edge('a', 'b');
|
|
20
|
-
const spec = builder.animate((anim) => anim.node('a').to({ x: 200, opacity: 0.5 }, { duration: 600 }));
|
|
21
|
-
expect(spec.version).toBe('viz-anim/1');
|
|
22
|
-
expect(spec.tweens.length).toBe(2);
|
|
23
|
-
expect(spec.tweens[0]).toBeDefined();
|
|
24
|
-
expect(spec.tweens[0].target).toBe('node:a');
|
|
25
|
-
const scene = builder.build();
|
|
26
|
-
expect(scene.animationSpecs?.length).toBe(1);
|
|
27
|
-
expect(scene.animationSpecs?.[0]).toEqual(spec);
|
|
28
|
-
});
|
|
29
|
-
it('keeps legacy .animate("flow") behavior separate from data-only specs', () => {
|
|
30
|
-
const builder = viz();
|
|
31
|
-
builder.node('a').at(0, 0);
|
|
32
|
-
builder.node('b').at(10, 10);
|
|
33
|
-
builder.edge('a', 'b').animate('flow', { duration: '1s' });
|
|
34
|
-
const scene = builder.build();
|
|
35
|
-
expect(scene.animationSpecs).toBeUndefined();
|
|
36
|
-
expect(scene.edges[0]).toBeDefined();
|
|
37
|
-
expect(scene.edges[0].animations?.[0]?.id).toBe('flow');
|
|
38
|
-
});
|
|
39
|
-
it('supports element-level .animate(cb) and animateTo(...) sugar', () => {
|
|
40
|
-
const builder = viz();
|
|
41
|
-
builder.node('a').at(0, 0).animateTo({ x: 123 }, { duration: 400 });
|
|
42
|
-
builder.node('b').at(10, 10);
|
|
43
|
-
builder
|
|
44
|
-
.edge('a', 'b')
|
|
45
|
-
.animate((anim) => anim.to({ strokeDashoffset: -100 }, { duration: 1000 }));
|
|
46
|
-
const scene = builder.build();
|
|
47
|
-
expect(scene.animationSpecs?.length).toBe(2);
|
|
48
|
-
const nodeSpec = scene.animationSpecs?.[0];
|
|
49
|
-
const edgeSpec = scene.animationSpecs?.[1];
|
|
50
|
-
expect(nodeSpec).toBeDefined();
|
|
51
|
-
expect(edgeSpec).toBeDefined();
|
|
52
|
-
expect(nodeSpec.tweens[0]).toBeDefined();
|
|
53
|
-
expect(edgeSpec.tweens[0]).toBeDefined();
|
|
54
|
-
expect(nodeSpec.tweens[0].target).toBe('node:a');
|
|
55
|
-
expect(edgeSpec.tweens[0].target).toBe('edge:a->b');
|
|
56
|
-
});
|
|
57
|
-
it('allows animating edges with custom ids via anim.edge(from, to, id)', () => {
|
|
58
|
-
const builder = viz();
|
|
59
|
-
builder.node('a').at(0, 0);
|
|
60
|
-
builder.node('b').at(10, 10);
|
|
61
|
-
builder.edge('a', 'b', 'e1');
|
|
62
|
-
const spec = builder.animate((anim) => anim.edge('a', 'b', 'e1').to({ strokeDashoffset: -50 }, { duration: 250 }));
|
|
63
|
-
expect(spec.tweens.length).toBe(1);
|
|
64
|
-
expect(spec.tweens[0].target).toBe('edge:e1');
|
|
65
|
-
});
|
|
66
|
-
});
|