@neoloopy/cld-canvas 0.1.4 → 0.1.8

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.
@@ -13,7 +13,7 @@
13
13
  * Pure of canvas-view state: it owns only its measure context and memo, and is
14
14
  * handed the graph + interaction caches to build from.
15
15
  */
16
- import { buildEdgeGeoms, buildNodeBoxes, collectEdges, computeBadges, nodeBounds, } from "./geometry";
16
+ import { buildEdgeGeoms, buildNodeBoxes, buildSfdPipeGeoms, collectCldMaterialProjectionEdges, collectInfoEdges, computeBadges, loopsForMode, sceneBounds, sfdRenderPositions, } from "./geometry";
17
17
  import { LABEL_FONT, LABEL_TRACKING } from "./painter";
18
18
  /**
19
19
  * A canvas-backed label measurer matching the painter font (and the app's
@@ -64,24 +64,32 @@ export class SceneCache {
64
64
  * reference when no geometric input moved; otherwise recomputes boxes, edges,
65
65
  * and badges. Returns `null` for a null graph.
66
66
  */
67
- build(graph, bowSigns, badgeOverrides) {
67
+ build(graph, bowSigns, badgeOverrides, mode = "cld") {
68
68
  if (!graph) {
69
69
  this.scene = null;
70
70
  this.lastGraph = null;
71
71
  this.lastSig = null;
72
72
  return null;
73
73
  }
74
- const sig = this.signature(graph, bowSigns, badgeOverrides);
74
+ const sig = this.signature(graph, bowSigns, badgeOverrides, mode);
75
75
  if (this.scene && graph === this.lastGraph && sig === this.lastSig)
76
76
  return this.scene;
77
- const boxes = buildNodeBoxes(graph.nodes, (s) => this.measure(s));
78
- const edges = buildEdgeGeoms(collectEdges(graph.nodes), boxes, bowSigns);
79
- const badges = computeBadges(graph.loops, boxes, badgeOverrides);
77
+ const boxes = buildNodeBoxes(graph.nodes, (s) => this.measure(s), mode === "sfd" ? sfdRenderPositions(graph.nodes) : undefined);
78
+ const edgeRefs = collectInfoEdges(graph.nodes, mode);
79
+ if (mode === "cld") {
80
+ edgeRefs.push(...collectCldMaterialProjectionEdges(graph.nodes, graph.loops));
81
+ }
82
+ const edges = buildEdgeGeoms(edgeRefs, boxes, bowSigns);
83
+ const pipes = mode === "sfd" ? buildSfdPipeGeoms(graph.nodes, boxes) : [];
84
+ const loops = loopsForMode(graph.loops, mode);
85
+ const badges = computeBadges(loops, boxes, badgeOverrides);
80
86
  this.scene = {
87
+ mode,
81
88
  nodes: graph.nodes,
82
89
  boxes,
83
90
  edges,
84
- loops: graph.loops,
91
+ pipes,
92
+ loops,
85
93
  labels: graph.labels,
86
94
  badges,
87
95
  };
@@ -90,7 +98,7 @@ export class SceneCache {
90
98
  // `bowSigns`, which feeds the signature — so the pre-build `sig` is already
91
99
  // stale. Record the post-build signature instead, or the next unchanged call
92
100
  // would needlessly rebuild once before the cache settles.
93
- this.lastSig = this.signature(graph, bowSigns, badgeOverrides);
101
+ this.lastSig = this.signature(graph, bowSigns, badgeOverrides, mode);
94
102
  return this.scene;
95
103
  }
96
104
  /**
@@ -103,7 +111,7 @@ export class SceneCache {
103
111
  return false;
104
112
  if (width === 0 || height === 0)
105
113
  return false;
106
- camera.fit(nodeBounds(this.scene.boxes), width, height);
114
+ camera.fit(sceneBounds(this.scene.boxes, this.scene.pipes), width, height);
107
115
  return true;
108
116
  }
109
117
  /**
@@ -113,10 +121,18 @@ export class SceneCache {
113
121
  * session-only badge overrides. Link polarity/flags don't affect geometry and
114
122
  * arrive via a fresh graph (caught by the identity check), so they're omitted.
115
123
  */
116
- signature(graph, bowSigns, badgeOverrides) {
117
- const parts = [];
124
+ signature(graph, bowSigns, badgeOverrides, mode) {
125
+ const parts = [mode];
118
126
  for (const n of graph.nodes) {
119
- parts.push(`${n.id}:${n.x}:${n.y}:${n.type}:${n.label}`);
127
+ const sfd = n.extra["sfd"];
128
+ const sfdSig = sfd && typeof sfd === "object" && !Array.isArray(sfd)
129
+ ? `${String(sfd["x"] ?? "")},${String(sfd["y"] ?? "")}`
130
+ : "";
131
+ const flow = n.extra["flow"];
132
+ const flowSig = flow && typeof flow === "object" && !Array.isArray(flow)
133
+ ? `${String(flow["from"] ?? "")}->${String(flow["to"] ?? "")}`
134
+ : "";
135
+ parts.push(`${n.id}:${n.x}:${n.y}:${sfdSig}:${n.type}:${n.label}:${flowSig}`);
120
136
  for (const l of n.links)
121
137
  parts.push(`>${l.to}:${l.curvature ?? ""}`);
122
138
  }
@@ -127,8 +143,14 @@ export class SceneCache {
127
143
  for (const [k, p] of badgeOverrides)
128
144
  parts.push(`${k}=${p.x},${p.y}`);
129
145
  parts.push("|");
130
- for (const l of graph.loops)
146
+ for (const l of graph.loops) {
131
147
  parts.push(l.key);
148
+ for (const leg of l.canvasPath?.legs ?? []) {
149
+ parts.push(leg.kind === "causal"
150
+ ? `c:${leg.edgeId}`
151
+ : `m:${leg.flowId}>${leg.stockId}:${leg.cldEdgeId}:${leg.polarity}`);
152
+ }
153
+ }
132
154
  return parts.join(";");
133
155
  }
134
156
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neoloopy/cld-canvas",
3
- "version": "0.1.4",
3
+ "version": "0.1.8",
4
4
  "author": "neoloopy",
5
5
  "license": "MIT",
6
6
  "description": "Framework-agnostic CLD canvas renderer + in-memory edit engine (shared by the neoloopy Obsidian plugin and neoloopy.com).",
@@ -40,5 +40,5 @@
40
40
  },
41
41
  "homepage": "https://github.com/frozenabe/neoloopy-obsidian/tree/main/packages/cld-canvas#readme",
42
42
  "bugs": { "url": "https://github.com/frozenabe/neoloopy-obsidian/issues" },
43
- "scripts": { "build": "tsc -p tsconfig.json" }
43
+ "scripts": { "build": "tsc -p tsconfig.json", "prepack": "npm run build" }
44
44
  }