sketchmark 1.1.6 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of sketchmark might be problematic. Click here for more details.
- package/README.md +193 -147
- package/dist/animation/index.d.ts +2 -0
- package/dist/animation/index.d.ts.map +1 -1
- package/dist/ast/types.d.ts +3 -0
- package/dist/ast/types.d.ts.map +1 -1
- package/dist/index.cjs +228 -95
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +228 -95
- package/dist/index.js.map +1 -1
- package/dist/layout/index.d.ts +8 -0
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/parser/index.d.ts +2 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/tokenizer.d.ts.map +1 -1
- package/dist/plugins.d.ts +12 -0
- package/dist/plugins.d.ts.map +1 -0
- package/dist/render.d.ts +2 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/renderer/shared.d.ts +1 -1
- package/dist/renderer/shared.d.ts.map +1 -1
- package/dist/renderer/svg/index.d.ts.map +1 -1
- package/dist/scene/index.d.ts +2 -0
- package/dist/scene/index.d.ts.map +1 -1
- package/dist/sketchmark.iife.js +228 -95
- package/dist/ui/canvas.d.ts +2 -0
- package/dist/ui/canvas.d.ts.map +1 -1
- package/dist/ui/embed.d.ts +2 -0
- package/dist/ui/embed.d.ts.map +1 -1
- package/package.json +18 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { parse, ParseError } from "./parser";
|
|
2
2
|
export type { DiagramAST } from "./parser";
|
|
3
|
+
export type { ParseOptions, SketchmarkPlugin } from "./plugins";
|
|
3
4
|
export { buildSceneGraph, nodeMap, groupMap, markdownMap } from "./scene";
|
|
4
5
|
export type { SceneGraph, SceneNode, SceneEdge, SceneGroup, SceneMarkdown, } from "./scene";
|
|
5
6
|
export { layout, connPoint } from "./layout";
|
|
@@ -11,7 +12,7 @@ export { AnimationController, ANIMATION_CSS } from "./animation";
|
|
|
11
12
|
export type { AnimationEvent, AnimationEventType } from "./animation";
|
|
12
13
|
export { exportSVG, exportPNG, exportCanvasPNG, exportHTML, exportGIF, exportMP4, getSVGBlob, svgToPNGDataURL, } from "./export";
|
|
13
14
|
export type { ExportFormat, ExportOptions } from "./export";
|
|
14
|
-
export type { NodeShape, EdgeConnector, LayoutType, AlignItems, JustifyContent, AnimationAction, AnimationTrigger, StyleProps, StepPace, ASTNode, ASTEdge, ASTGroup, ASTStep, ASTBeat, ASTStepItem, ASTChart, ASTTable, GroupChildRef, RootItemRef, ASTMarkdown, } from "./ast/types";
|
|
15
|
+
export type { NodeShape, EdgeConnector, EdgeAnchor, LayoutType, AlignItems, JustifyContent, AnimationAction, AnimationTrigger, StyleProps, StepPace, ASTNode, ASTEdge, ASTGroup, ASTStep, ASTBeat, ASTStepItem, ASTChart, ASTTable, GroupChildRef, RootItemRef, ASTMarkdown, } from "./ast/types";
|
|
15
16
|
export { hashStr, clamp, lerp, parseHex, sleep, throttle, debounce, EventEmitter, } from "./utils";
|
|
16
17
|
export { render } from "./render";
|
|
17
18
|
export type { RenderOptions, DiagramInstance } from "./render";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC7C,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC1E,YAAY,EACV,UAAU,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG7C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1D,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EACL,cAAc,EACd,eAAe,EACf,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGtE,OAAO,EACL,SAAS,EACT,SAAS,EACT,eAAe,EACf,UAAU,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,eAAe,GAChB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG5D,YAAY,EACV,SAAS,EACT,aAAa,EACb,UAAU,EACV,UAAU,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,OAAO,EACP,OAAO,EACP,QAAQ,EACR,OAAO,EACP,OAAO,EACP,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,WAAW,EACX,WAAW,GACZ,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,OAAO,EACP,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,YAAY,GACb,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,uBAAuB,EACvB,sBAAsB,EACtB,iCAAiC,GAClC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,YAAY,EACV,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,WAAW,GACZ,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC7C,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC1E,YAAY,EACV,UAAU,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG7C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1D,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EACL,cAAc,EACd,eAAe,EACf,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGtE,OAAO,EACL,SAAS,EACT,SAAS,EACT,eAAe,EACf,UAAU,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,eAAe,GAChB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG5D,YAAY,EACV,SAAS,EACT,aAAa,EACb,UAAU,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,OAAO,EACP,OAAO,EACP,QAAQ,EACR,OAAO,EACP,OAAO,EACP,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,WAAW,EACX,WAAW,GACZ,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,OAAO,EACP,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,YAAY,GACb,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,uBAAuB,EACvB,sBAAsB,EACtB,iCAAiC,GAClC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,YAAY,EACV,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,WAAW,GACZ,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -144,10 +144,16 @@ function tokenize$1(src) {
|
|
|
144
144
|
val += "\n";
|
|
145
145
|
else if (esc === "t")
|
|
146
146
|
val += "\t";
|
|
147
|
+
else if (esc === "r")
|
|
148
|
+
val += "\r";
|
|
147
149
|
else if (esc === "\\")
|
|
148
150
|
val += "\\";
|
|
151
|
+
else if (esc === q)
|
|
152
|
+
val += q;
|
|
153
|
+
else if (esc)
|
|
154
|
+
val += `\\${esc}`;
|
|
149
155
|
else
|
|
150
|
-
val +=
|
|
156
|
+
val += "\\";
|
|
151
157
|
}
|
|
152
158
|
else
|
|
153
159
|
val += src[i];
|
|
@@ -224,6 +230,47 @@ function tokenize$1(src) {
|
|
|
224
230
|
return tokens;
|
|
225
231
|
}
|
|
226
232
|
|
|
233
|
+
function pluginMessage(plugin, stage, error) {
|
|
234
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
235
|
+
return `Plugin "${plugin.name}" ${stage} failed: ${detail}`;
|
|
236
|
+
}
|
|
237
|
+
function applyPluginPreprocessors(source, plugins = []) {
|
|
238
|
+
let nextSource = source;
|
|
239
|
+
for (const plugin of plugins) {
|
|
240
|
+
if (!plugin.preprocess)
|
|
241
|
+
continue;
|
|
242
|
+
try {
|
|
243
|
+
const transformed = plugin.preprocess(nextSource);
|
|
244
|
+
if (typeof transformed !== "string") {
|
|
245
|
+
throw new Error("preprocess must return a string");
|
|
246
|
+
}
|
|
247
|
+
nextSource = transformed;
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
throw new Error(pluginMessage(plugin, "preprocess", error));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return nextSource;
|
|
254
|
+
}
|
|
255
|
+
function applyPluginAstTransforms(ast, plugins = []) {
|
|
256
|
+
let nextAst = ast;
|
|
257
|
+
for (const plugin of plugins) {
|
|
258
|
+
if (!plugin.transformAst)
|
|
259
|
+
continue;
|
|
260
|
+
try {
|
|
261
|
+
const transformed = plugin.transformAst(nextAst);
|
|
262
|
+
if (!transformed || transformed.kind !== "diagram") {
|
|
263
|
+
throw new Error('transformAst must return a DiagramAST with kind="diagram"');
|
|
264
|
+
}
|
|
265
|
+
nextAst = transformed;
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
throw new Error(pluginMessage(plugin, "transformAst", error));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return nextAst;
|
|
272
|
+
}
|
|
273
|
+
|
|
227
274
|
// ============================================================
|
|
228
275
|
// sketchmark - Parser (Tokens -> DiagramAST)
|
|
229
276
|
// ============================================================
|
|
@@ -310,9 +357,10 @@ function isValueToken(t) {
|
|
|
310
357
|
function isPropKeyToken(t) {
|
|
311
358
|
return !!t && (t.type === "IDENT" || t.type === "KEYWORD");
|
|
312
359
|
}
|
|
313
|
-
function parse(src) {
|
|
360
|
+
function parse(src, options = {}) {
|
|
314
361
|
resetUid();
|
|
315
|
-
const
|
|
362
|
+
const preparedSource = applyPluginPreprocessors(src, options.plugins);
|
|
363
|
+
const tokens = tokenize$1(preparedSource).filter((t) => t.type !== "NEWLINE" || t.value === "\n");
|
|
316
364
|
const flat = [];
|
|
317
365
|
let lastNL = false;
|
|
318
366
|
for (const t of tokens) {
|
|
@@ -495,6 +543,7 @@ function parse(src) {
|
|
|
495
543
|
const toks = lineTokens();
|
|
496
544
|
const id = requireExplicitId(keywordTok, toks);
|
|
497
545
|
const props = parseSimpleProps(toks, 1);
|
|
546
|
+
const meta = extractNodeMeta(props);
|
|
498
547
|
const node = {
|
|
499
548
|
kind: "node",
|
|
500
549
|
id,
|
|
@@ -509,6 +558,7 @@ function parse(src) {
|
|
|
509
558
|
...(props.dy ? { dy: parseFloat(props.dy) } : {}),
|
|
510
559
|
...(props.factor ? { factor: parseFloat(props.factor) } : {}),
|
|
511
560
|
...(props.theme ? { theme: props.theme } : {}),
|
|
561
|
+
...(meta ? { meta } : {}),
|
|
512
562
|
style: propsToStyle(props),
|
|
513
563
|
};
|
|
514
564
|
if (props.url)
|
|
@@ -533,12 +583,14 @@ function parse(src) {
|
|
|
533
583
|
j = 2;
|
|
534
584
|
}
|
|
535
585
|
Object.assign(props, parseSimpleProps(toks, j));
|
|
586
|
+
const meta = extractNodeMeta(props);
|
|
536
587
|
return {
|
|
537
588
|
kind: "node",
|
|
538
589
|
id,
|
|
539
590
|
shape: "note",
|
|
540
591
|
label: (props.label ?? "").replace(/\\n/g, "\n"),
|
|
541
592
|
theme: props.theme,
|
|
593
|
+
...(meta ? { meta } : {}),
|
|
542
594
|
style: propsToStyle(props),
|
|
543
595
|
...(props.width ? { width: parseFloat(props.width) } : {}),
|
|
544
596
|
...(props.height ? { height: parseFloat(props.height) } : {}),
|
|
@@ -550,6 +602,13 @@ function parse(src) {
|
|
|
550
602
|
...(props.factor ? { factor: parseFloat(props.factor) } : {}),
|
|
551
603
|
};
|
|
552
604
|
}
|
|
605
|
+
function extractNodeMeta(props) {
|
|
606
|
+
const meta = {};
|
|
607
|
+
if (props["animation-parent"]) {
|
|
608
|
+
meta.animationParent = props["animation-parent"];
|
|
609
|
+
}
|
|
610
|
+
return Object.keys(meta).length ? meta : undefined;
|
|
611
|
+
}
|
|
553
612
|
function parseGroup() {
|
|
554
613
|
const keywordTok = cur();
|
|
555
614
|
skip();
|
|
@@ -622,6 +681,8 @@ function parse(src) {
|
|
|
622
681
|
to: toTok.value,
|
|
623
682
|
connector: connector,
|
|
624
683
|
label: props.label,
|
|
684
|
+
fromAnchor: props["anchor-from"],
|
|
685
|
+
toAnchor: props["anchor-to"],
|
|
625
686
|
dashed,
|
|
626
687
|
bidirectional,
|
|
627
688
|
style: propsToStyle(props),
|
|
@@ -935,6 +996,7 @@ function parse(src) {
|
|
|
935
996
|
registerAuthoredId(grp.id, "group", t);
|
|
936
997
|
if (isBare) {
|
|
937
998
|
grp.label = "";
|
|
999
|
+
grp.padding = grp.padding ?? 0;
|
|
938
1000
|
grp.style = {
|
|
939
1001
|
...grp.style,
|
|
940
1002
|
fill: grp.style?.fill ?? "none",
|
|
@@ -1105,7 +1167,7 @@ function parse(src) {
|
|
|
1105
1167
|
node.style = { ...ast.styles[node.id], ...node.style };
|
|
1106
1168
|
}
|
|
1107
1169
|
}
|
|
1108
|
-
return ast;
|
|
1170
|
+
return applyPluginAstTransforms(ast, options.plugins);
|
|
1109
1171
|
}
|
|
1110
1172
|
|
|
1111
1173
|
// ============================================================
|
|
@@ -3552,6 +3614,8 @@ function buildSceneGraph(ast) {
|
|
|
3552
3614
|
to: e.to,
|
|
3553
3615
|
connector: e.connector,
|
|
3554
3616
|
label: e.label,
|
|
3617
|
+
fromAnchor: e.fromAnchor,
|
|
3618
|
+
toAnchor: e.toAnchor,
|
|
3555
3619
|
dashed: e.dashed ?? false,
|
|
3556
3620
|
bidirectional: e.bidirectional ?? false,
|
|
3557
3621
|
style: e.style ?? {},
|
|
@@ -4129,28 +4193,13 @@ function connMeta(connector) {
|
|
|
4129
4193
|
return { arrowAt: "start", dashed };
|
|
4130
4194
|
return { arrowAt: "end", dashed };
|
|
4131
4195
|
}
|
|
4132
|
-
// ── Generic rect connection point ────────────────────────────────────────
|
|
4133
|
-
function rectConnPoint$1(rx, ry, rw, rh, ox, oy) {
|
|
4134
|
-
const cx = rx + rw / 2, cy = ry + rh / 2;
|
|
4135
|
-
const dx = ox - cx, dy = oy - cy;
|
|
4136
|
-
if (Math.abs(dx) < 0.01 && Math.abs(dy) < 0.01)
|
|
4137
|
-
return [cx, cy];
|
|
4138
|
-
const hw = rw / 2 - 2, hh = rh / 2 - 2;
|
|
4139
|
-
const tx = Math.abs(dx) > 0.01 ? hw / Math.abs(dx) : 1e9;
|
|
4140
|
-
const ty = Math.abs(dy) > 0.01 ? hh / Math.abs(dy) : 1e9;
|
|
4141
|
-
const t = Math.min(tx, ty);
|
|
4142
|
-
return [cx + t * dx, cy + t * dy];
|
|
4143
|
-
}
|
|
4144
4196
|
// ── Resolve an endpoint entity by ID across all maps ─────────────────────
|
|
4145
4197
|
function resolveEndpoint(id, nm, tm, gm, cm) {
|
|
4146
4198
|
return nm.get(id) ?? tm.get(id) ?? gm.get(id) ?? cm.get(id) ?? null;
|
|
4147
4199
|
}
|
|
4148
4200
|
// ── Get connection point for any entity ──────────────────────────────────
|
|
4149
|
-
function getConnPoint(src, dstCX, dstCY) {
|
|
4150
|
-
|
|
4151
|
-
return connPoint(src, { x: dstCX - 1, y: dstCY - 1, w: 2, h: 2});
|
|
4152
|
-
}
|
|
4153
|
-
return rectConnPoint$1(src.x, src.y, src.w, src.h, dstCX, dstCY);
|
|
4201
|
+
function getConnPoint(src, dstCX, dstCY, anchor) {
|
|
4202
|
+
return anchoredConnPoint(src, anchor, dstCX, dstCY);
|
|
4154
4203
|
}
|
|
4155
4204
|
// ── Group depth (for paint order) ────────────────────────────────────────
|
|
4156
4205
|
function groupDepth(g, gm) {
|
|
@@ -4585,6 +4634,50 @@ function connPoint(n, other) {
|
|
|
4585
4634
|
const t = Math.min(tx, ty);
|
|
4586
4635
|
return [cx + t * dx, cy + t * dy];
|
|
4587
4636
|
}
|
|
4637
|
+
function clampInset(value) {
|
|
4638
|
+
return Math.max(2, value);
|
|
4639
|
+
}
|
|
4640
|
+
function anchoredConnPoint(entity, anchor, otherCX, otherCY) {
|
|
4641
|
+
if (!anchor) {
|
|
4642
|
+
if (entity.shape && otherCX != null && otherCY != null) {
|
|
4643
|
+
return connPoint(entity, { x: otherCX - 1, y: otherCY - 1, w: 2, h: 2});
|
|
4644
|
+
}
|
|
4645
|
+
if (otherCX != null && otherCY != null) {
|
|
4646
|
+
return rectConnPoint(entity.x, entity.y, entity.w, entity.h, otherCX, otherCY);
|
|
4647
|
+
}
|
|
4648
|
+
return [entity.x + entity.w / 2, entity.y + entity.h / 2];
|
|
4649
|
+
}
|
|
4650
|
+
const insetX = clampInset(Math.min(10, entity.w / 2));
|
|
4651
|
+
const insetY = clampInset(Math.min(10, entity.h / 2));
|
|
4652
|
+
const left = entity.x + insetX;
|
|
4653
|
+
const right = entity.x + entity.w - insetX;
|
|
4654
|
+
const top = entity.y + insetY;
|
|
4655
|
+
const bottom = entity.y + entity.h - insetY;
|
|
4656
|
+
const cx = entity.x + entity.w / 2;
|
|
4657
|
+
const cy = entity.y + entity.h / 2;
|
|
4658
|
+
switch (anchor) {
|
|
4659
|
+
case "top":
|
|
4660
|
+
return [cx, top];
|
|
4661
|
+
case "right":
|
|
4662
|
+
return [right, cy];
|
|
4663
|
+
case "bottom":
|
|
4664
|
+
return [cx, bottom];
|
|
4665
|
+
case "left":
|
|
4666
|
+
return [left, cy];
|
|
4667
|
+
case "center":
|
|
4668
|
+
return [cx, cy];
|
|
4669
|
+
case "top-left":
|
|
4670
|
+
return [left, top];
|
|
4671
|
+
case "top-right":
|
|
4672
|
+
return [right, top];
|
|
4673
|
+
case "bottom-left":
|
|
4674
|
+
return [left, bottom];
|
|
4675
|
+
case "bottom-right":
|
|
4676
|
+
return [right, bottom];
|
|
4677
|
+
default:
|
|
4678
|
+
return [cx, cy];
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4588
4681
|
function rectConnPoint(rx, ry, rw, rh, ox, oy) {
|
|
4589
4682
|
const cx = rx + rw / 2, cy = ry + rh / 2;
|
|
4590
4683
|
const dx = ox - cx, dy = oy - cy;
|
|
@@ -4616,17 +4709,6 @@ function routeEdges(sg) {
|
|
|
4616
4709
|
return c;
|
|
4617
4710
|
return null;
|
|
4618
4711
|
}
|
|
4619
|
-
function connPt(src, dstCX, dstCY) {
|
|
4620
|
-
// SceneNode has a .shape field; use the existing connPoint for it
|
|
4621
|
-
if ("shape" in src && src.shape) {
|
|
4622
|
-
return connPoint(src, {
|
|
4623
|
-
x: dstCX - 1,
|
|
4624
|
-
y: dstCY - 1,
|
|
4625
|
-
w: 2,
|
|
4626
|
-
h: 2});
|
|
4627
|
-
}
|
|
4628
|
-
return rectConnPoint(src.x, src.y, src.w, src.h, dstCX, dstCY);
|
|
4629
|
-
}
|
|
4630
4712
|
for (const e of sg.edges) {
|
|
4631
4713
|
const src = resolve(e.from);
|
|
4632
4714
|
const dst = resolve(e.to);
|
|
@@ -4636,7 +4718,10 @@ function routeEdges(sg) {
|
|
|
4636
4718
|
}
|
|
4637
4719
|
const dstCX = dst.x + dst.w / 2, dstCY = dst.y + dst.h / 2;
|
|
4638
4720
|
const srcCX = src.x + src.w / 2, srcCY = src.y + src.h / 2;
|
|
4639
|
-
e.points = [
|
|
4721
|
+
e.points = [
|
|
4722
|
+
anchoredConnPoint(src, e.fromAnchor, dstCX, dstCY),
|
|
4723
|
+
anchoredConnPoint(dst, e.toAnchor, srcCX, srcCY),
|
|
4724
|
+
];
|
|
4640
4725
|
}
|
|
4641
4726
|
}
|
|
4642
4727
|
function computeBounds(sg, margin) {
|
|
@@ -7777,8 +7862,8 @@ function renderToSVG(sg, container, options = {}) {
|
|
|
7777
7862
|
continue;
|
|
7778
7863
|
const dstCX = dst.x + dst.w / 2, dstCY = dst.y + dst.h / 2;
|
|
7779
7864
|
const srcCX = src.x + src.w / 2, srcCY = src.y + src.h / 2;
|
|
7780
|
-
const [x1, y1] = getConnPoint(src, dstCX, dstCY);
|
|
7781
|
-
const [x2, y2] = getConnPoint(dst, srcCX, srcCY);
|
|
7865
|
+
const [x1, y1] = getConnPoint(src, dstCX, dstCY, e.fromAnchor);
|
|
7866
|
+
const [x2, y2] = getConnPoint(dst, srcCX, srcCY, e.toAnchor);
|
|
7782
7867
|
const eg = mkGroup(`edge-${e.from}-${e.to}`, "eg");
|
|
7783
7868
|
if (e.style?.opacity != null)
|
|
7784
7869
|
eg.setAttribute("opacity", String(e.style.opacity));
|
|
@@ -7855,6 +7940,8 @@ function renderToSVG(sg, container, options = {}) {
|
|
|
7855
7940
|
ng.dataset.h = String(n.h);
|
|
7856
7941
|
if (n.pathData)
|
|
7857
7942
|
ng.dataset.pathData = n.pathData;
|
|
7943
|
+
if (n.meta?.animationParent)
|
|
7944
|
+
ng.dataset.animationParent = n.meta.animationParent;
|
|
7858
7945
|
if (n.style?.opacity != null)
|
|
7859
7946
|
ng.setAttribute("opacity", String(n.style.opacity));
|
|
7860
7947
|
// ── Static transform (deg, dx, dy, factor) ──────────
|
|
@@ -8508,8 +8595,8 @@ function renderToCanvas(sg, canvas, options = {}) {
|
|
|
8508
8595
|
continue;
|
|
8509
8596
|
const dstCX = dst.x + dst.w / 2, dstCY = dst.y + dst.h / 2;
|
|
8510
8597
|
const srcCX = src.x + src.w / 2, srcCY = src.y + src.h / 2;
|
|
8511
|
-
const [x1, y1] = getConnPoint(src, dstCX, dstCY);
|
|
8512
|
-
const [x2, y2] = getConnPoint(dst, srcCX, srcCY);
|
|
8598
|
+
const [x1, y1] = getConnPoint(src, dstCX, dstCY, e.fromAnchor);
|
|
8599
|
+
const [x2, y2] = getConnPoint(dst, srcCX, srcCY, e.toAnchor);
|
|
8513
8600
|
if (e.style?.opacity != null)
|
|
8514
8601
|
ctx.globalAlpha = Number(e.style.opacity);
|
|
8515
8602
|
const ecol = String(e.style?.stroke ?? palette.edgeStroke);
|
|
@@ -9366,6 +9453,13 @@ class AnimationController {
|
|
|
9366
9453
|
this.drawTargetNodes.delete(`node-${s.target}`);
|
|
9367
9454
|
}
|
|
9368
9455
|
}
|
|
9456
|
+
this._relatedElementIdsByPrimaryId = this._buildRelatedElementIndex();
|
|
9457
|
+
for (const nodeId of Array.from(this.drawTargetNodes)) {
|
|
9458
|
+
const relatedIds = this._relatedElementIdsByPrimaryId.get(nodeId);
|
|
9459
|
+
if (!relatedIds)
|
|
9460
|
+
continue;
|
|
9461
|
+
relatedIds.forEach((id) => this.drawTargetNodes.add(id));
|
|
9462
|
+
}
|
|
9369
9463
|
this._drawStepIndexByElementId = this._buildDrawStepIndex();
|
|
9370
9464
|
const { parentGroupByElementId, groupDescendantIds } = this._buildGroupVisibilityIndex();
|
|
9371
9465
|
this._parentGroupByElementId = parentGroupByElementId;
|
|
@@ -9396,10 +9490,30 @@ class AnimationController {
|
|
|
9396
9490
|
const el = resolveNonEdgeDrawEl(this.svg, step.target);
|
|
9397
9491
|
if (el && !drawStepIndexByElementId.has(el.id)) {
|
|
9398
9492
|
drawStepIndexByElementId.set(el.id, stepIndex);
|
|
9493
|
+
this._relatedElementIdsByPrimaryId.get(el.id)?.forEach((relatedId) => {
|
|
9494
|
+
if (!drawStepIndexByElementId.has(relatedId)) {
|
|
9495
|
+
drawStepIndexByElementId.set(relatedId, stepIndex);
|
|
9496
|
+
}
|
|
9497
|
+
});
|
|
9399
9498
|
}
|
|
9400
9499
|
});
|
|
9401
9500
|
return drawStepIndexByElementId;
|
|
9402
9501
|
}
|
|
9502
|
+
_buildRelatedElementIndex() {
|
|
9503
|
+
const relatedElementIdsByPrimaryId = new Map();
|
|
9504
|
+
this.svg.querySelectorAll(POSITIONABLE_SELECTOR).forEach((el) => {
|
|
9505
|
+
const animationParent = el.dataset.animationParent;
|
|
9506
|
+
if (!animationParent)
|
|
9507
|
+
return;
|
|
9508
|
+
const primaryEl = resolveNonEdgeDrawEl(this.svg, animationParent);
|
|
9509
|
+
if (!primaryEl || primaryEl.id === el.id)
|
|
9510
|
+
return;
|
|
9511
|
+
const related = relatedElementIdsByPrimaryId.get(primaryEl.id) ?? new Set();
|
|
9512
|
+
related.add(el.id);
|
|
9513
|
+
relatedElementIdsByPrimaryId.set(primaryEl.id, related);
|
|
9514
|
+
});
|
|
9515
|
+
return relatedElementIdsByPrimaryId;
|
|
9516
|
+
}
|
|
9403
9517
|
_buildGroupVisibilityIndex() {
|
|
9404
9518
|
const parentGroupByElementId = new Map();
|
|
9405
9519
|
const directChildIdsByGroup = new Map();
|
|
@@ -9478,10 +9592,18 @@ class AnimationController {
|
|
|
9478
9592
|
const el = resolveEl(this.svg, target);
|
|
9479
9593
|
if (!el)
|
|
9480
9594
|
return [];
|
|
9481
|
-
if (!el.id.startsWith("group-"))
|
|
9482
|
-
|
|
9595
|
+
if (!el.id.startsWith("group-")) {
|
|
9596
|
+
const ids = new Set([el.id]);
|
|
9597
|
+
this._relatedElementIdsByPrimaryId.get(el.id)?.forEach((id) => ids.add(id));
|
|
9598
|
+
return Array.from(ids)
|
|
9599
|
+
.map((id) => getEl(this.svg, id))
|
|
9600
|
+
.filter((candidate) => candidate != null);
|
|
9601
|
+
}
|
|
9483
9602
|
const ids = new Set([el.id]);
|
|
9484
9603
|
this._groupDescendantIds.get(el.id)?.forEach((id) => ids.add(id));
|
|
9604
|
+
Array.from(ids).forEach((id) => {
|
|
9605
|
+
this._relatedElementIdsByPrimaryId.get(id)?.forEach((relatedId) => ids.add(relatedId));
|
|
9606
|
+
});
|
|
9485
9607
|
return Array.from(ids)
|
|
9486
9608
|
.map((id) => getEl(this.svg, id))
|
|
9487
9609
|
.filter((candidate) => candidate != null);
|
|
@@ -9890,9 +10012,11 @@ class AnimationController {
|
|
|
9890
10012
|
// ── highlight ────────────────────────────────────────────
|
|
9891
10013
|
_doHighlight(target) {
|
|
9892
10014
|
this.svg
|
|
9893
|
-
.querySelectorAll(".ng.hl, .tg.hl, .ntg.hl, .cg.hl, .eg.hl")
|
|
10015
|
+
.querySelectorAll(".ng.hl, .gg.hl, .tg.hl, .ntg.hl, .cg.hl, .mdg.hl, .eg.hl")
|
|
9894
10016
|
.forEach((e) => e.classList.remove("hl"));
|
|
9895
|
-
|
|
10017
|
+
for (const el of this._resolveCascadeTargets(target)) {
|
|
10018
|
+
el.classList.add("hl");
|
|
10019
|
+
}
|
|
9896
10020
|
}
|
|
9897
10021
|
// ── fade / unfade ─────────────────────────────────────────
|
|
9898
10022
|
_doFade(target, doFade) {
|
|
@@ -9928,8 +10052,8 @@ class AnimationController {
|
|
|
9928
10052
|
}
|
|
9929
10053
|
// ── move ──────────────────────────────────────────────────
|
|
9930
10054
|
_doMove(target, step, silent) {
|
|
9931
|
-
const
|
|
9932
|
-
if (!
|
|
10055
|
+
const targets = this._resolveCascadeTargets(target);
|
|
10056
|
+
if (!targets.length)
|
|
9933
10057
|
return;
|
|
9934
10058
|
const cur = this._transforms.get(target) ?? {
|
|
9935
10059
|
tx: 0,
|
|
@@ -9942,12 +10066,14 @@ class AnimationController {
|
|
|
9942
10066
|
tx: cur.tx + (step.dx ?? 0),
|
|
9943
10067
|
ty: cur.ty + (step.dy ?? 0),
|
|
9944
10068
|
});
|
|
9945
|
-
|
|
10069
|
+
for (const el of targets) {
|
|
10070
|
+
this._writeTransform(el, target, silent, step.duration ?? 420);
|
|
10071
|
+
}
|
|
9946
10072
|
}
|
|
9947
10073
|
// ── scale ─────────────────────────────────────────────────
|
|
9948
10074
|
_doScale(target, step, silent) {
|
|
9949
|
-
const
|
|
9950
|
-
if (!
|
|
10075
|
+
const targets = this._resolveCascadeTargets(target);
|
|
10076
|
+
if (!targets.length)
|
|
9951
10077
|
return;
|
|
9952
10078
|
const cur = this._transforms.get(target) ?? {
|
|
9953
10079
|
tx: 0,
|
|
@@ -9956,12 +10082,14 @@ class AnimationController {
|
|
|
9956
10082
|
rotate: 0,
|
|
9957
10083
|
};
|
|
9958
10084
|
this._transforms.set(target, { ...cur, scale: step.factor ?? 1 });
|
|
9959
|
-
|
|
10085
|
+
for (const el of targets) {
|
|
10086
|
+
this._writeTransform(el, target, silent, step.duration ?? 350);
|
|
10087
|
+
}
|
|
9960
10088
|
}
|
|
9961
10089
|
// ── rotate ────────────────────────────────────────────────
|
|
9962
10090
|
_doRotate(target, step, silent) {
|
|
9963
|
-
const
|
|
9964
|
-
if (!
|
|
10091
|
+
const targets = this._resolveCascadeTargets(target);
|
|
10092
|
+
if (!targets.length)
|
|
9965
10093
|
return;
|
|
9966
10094
|
const cur = this._transforms.get(target) ?? {
|
|
9967
10095
|
tx: 0,
|
|
@@ -9973,7 +10101,9 @@ class AnimationController {
|
|
|
9973
10101
|
...cur,
|
|
9974
10102
|
rotate: cur.rotate + (step.deg ?? 0),
|
|
9975
10103
|
});
|
|
9976
|
-
|
|
10104
|
+
for (const el of targets) {
|
|
10105
|
+
this._writeTransform(el, target, silent, step.duration ?? 400);
|
|
10106
|
+
}
|
|
9977
10107
|
}
|
|
9978
10108
|
_doDraw(step, silent) {
|
|
9979
10109
|
const { target } = step;
|
|
@@ -10117,18 +10247,20 @@ class AnimationController {
|
|
|
10117
10247
|
return;
|
|
10118
10248
|
}
|
|
10119
10249
|
// ── Node draw ──────────────────────────────────────
|
|
10120
|
-
const
|
|
10121
|
-
if (!
|
|
10250
|
+
const nodeEls = this._resolveCascadeTargets(target).filter((el) => el.classList.contains("ng"));
|
|
10251
|
+
if (!nodeEls.length)
|
|
10122
10252
|
return;
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
10253
|
+
for (const nodeEl of nodeEls) {
|
|
10254
|
+
showDrawEl(nodeEl);
|
|
10255
|
+
if (silent) {
|
|
10256
|
+
revealNodeInstant(nodeEl);
|
|
10257
|
+
}
|
|
10258
|
+
else {
|
|
10259
|
+
if (!nodeGuidePathEl(nodeEl) && !nodeEl.querySelector("path")?.style.strokeDasharray) {
|
|
10260
|
+
prepareNodeForDraw(nodeEl);
|
|
10261
|
+
}
|
|
10262
|
+
animateNodeDraw(nodeEl, step.duration ?? ANIMATION.nodeStrokeDur, step.duration ?? ANIMATION.textRevealMs);
|
|
10130
10263
|
}
|
|
10131
|
-
animateNodeDraw(nodeEl, step.duration ?? ANIMATION.nodeStrokeDur, step.duration ?? ANIMATION.textRevealMs);
|
|
10132
10264
|
}
|
|
10133
10265
|
}
|
|
10134
10266
|
// ── erase ─────────────────────────────────────────────────
|
|
@@ -10149,45 +10281,44 @@ class AnimationController {
|
|
|
10149
10281
|
}
|
|
10150
10282
|
// ── pulse ─────────────────────────────────────────────────
|
|
10151
10283
|
_doPulse(target, duration = 500) {
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
|
|
10284
|
+
for (const el of this._resolveCascadeTargets(target)) {
|
|
10285
|
+
el.animate([
|
|
10286
|
+
{ filter: "brightness(1)" },
|
|
10287
|
+
{ filter: "brightness(1.6)" },
|
|
10288
|
+
{ filter: "brightness(1)" },
|
|
10289
|
+
], { duration, iterations: 3 });
|
|
10290
|
+
}
|
|
10157
10291
|
}
|
|
10158
10292
|
// ── color ─────────────────────────────────────────────────
|
|
10159
10293
|
_doColor(target, color) {
|
|
10160
10294
|
if (!color)
|
|
10161
10295
|
return;
|
|
10162
|
-
const el
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
|
|
10167
|
-
|
|
10168
|
-
|
|
10169
|
-
|
|
10170
|
-
|
|
10171
|
-
|
|
10172
|
-
|
|
10173
|
-
|
|
10174
|
-
|
|
10175
|
-
|
|
10176
|
-
|
|
10177
|
-
|
|
10178
|
-
|
|
10179
|
-
|
|
10180
|
-
|
|
10181
|
-
|
|
10182
|
-
if (attrFill === null && c.tagName === "path")
|
|
10183
|
-
return;
|
|
10184
|
-
c.style.fill = color;
|
|
10185
|
-
hit = true;
|
|
10186
|
-
});
|
|
10187
|
-
if (!hit) {
|
|
10188
|
-
el.querySelectorAll("text").forEach((t) => {
|
|
10189
|
-
t.style.fill = color;
|
|
10296
|
+
for (const el of this._resolveCascadeTargets(target)) {
|
|
10297
|
+
if (parseEdgeTarget(target)) {
|
|
10298
|
+
el.querySelectorAll("path, line, polyline").forEach((p) => {
|
|
10299
|
+
p.style.stroke = color;
|
|
10300
|
+
});
|
|
10301
|
+
el.querySelectorAll("polygon").forEach((p) => {
|
|
10302
|
+
p.style.fill = color;
|
|
10303
|
+
p.style.stroke = color;
|
|
10304
|
+
});
|
|
10305
|
+
continue;
|
|
10306
|
+
}
|
|
10307
|
+
let hit = false;
|
|
10308
|
+
el.querySelectorAll("path, rect, ellipse, polygon").forEach((c) => {
|
|
10309
|
+
const attrFill = c.getAttribute("fill");
|
|
10310
|
+
if (attrFill === "none")
|
|
10311
|
+
return;
|
|
10312
|
+
if (attrFill === null && c.tagName === "path")
|
|
10313
|
+
return;
|
|
10314
|
+
c.style.fill = color;
|
|
10315
|
+
hit = true;
|
|
10190
10316
|
});
|
|
10317
|
+
if (!hit) {
|
|
10318
|
+
el.querySelectorAll("text").forEach((t) => {
|
|
10319
|
+
t.style.fill = color;
|
|
10320
|
+
});
|
|
10321
|
+
}
|
|
10191
10322
|
}
|
|
10192
10323
|
}
|
|
10193
10324
|
// ── narration ───────────────────────────────────────────
|
|
@@ -10781,7 +10912,7 @@ class EventEmitter {
|
|
|
10781
10912
|
}
|
|
10782
10913
|
|
|
10783
10914
|
function render(options) {
|
|
10784
|
-
const { container: rawContainer, dsl, renderer = "svg", injectCSS = true, tts, svgOptions = {}, canvasOptions = {}, onNodeClick, onReady, } = options;
|
|
10915
|
+
const { container: rawContainer, dsl, plugins, renderer = "svg", injectCSS = true, tts, svgOptions = {}, canvasOptions = {}, onNodeClick, onReady, } = options;
|
|
10785
10916
|
if (injectCSS && !document.getElementById("ai-diagram-css")) {
|
|
10786
10917
|
const style = document.createElement("style");
|
|
10787
10918
|
style.id = "ai-diagram-css";
|
|
@@ -10797,7 +10928,7 @@ function render(options) {
|
|
|
10797
10928
|
else {
|
|
10798
10929
|
el = rawContainer;
|
|
10799
10930
|
}
|
|
10800
|
-
const ast = parse(dsl);
|
|
10931
|
+
const ast = parse(dsl, { plugins });
|
|
10801
10932
|
const scene = buildSceneGraph(ast);
|
|
10802
10933
|
layout(scene);
|
|
10803
10934
|
let svg;
|
|
@@ -11141,6 +11272,7 @@ class SketchmarkCanvas {
|
|
|
11141
11272
|
const instance = render({
|
|
11142
11273
|
container: this.diagramWrap,
|
|
11143
11274
|
dsl: this.dsl,
|
|
11275
|
+
plugins: this.options.plugins,
|
|
11144
11276
|
renderer: this.renderer,
|
|
11145
11277
|
svgOptions: { interactive: true, showTitle: true, theme: this.options.svgOptions?.theme ?? this.theme, ...this.options.svgOptions },
|
|
11146
11278
|
canvasOptions: this.options.canvasOptions,
|
|
@@ -12218,6 +12350,7 @@ class SketchmarkEmbed {
|
|
|
12218
12350
|
const instance = render({
|
|
12219
12351
|
container: this.diagramWrap,
|
|
12220
12352
|
dsl: this.dsl,
|
|
12353
|
+
plugins: this.options.plugins,
|
|
12221
12354
|
renderer: "svg",
|
|
12222
12355
|
svgOptions: {
|
|
12223
12356
|
showTitle: true,
|