libpetri 2.4.0 → 2.6.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.
@@ -30,13 +30,14 @@ function discoverClusters(svg) {
30
30
  if (!raw.startsWith("cluster_")) continue;
31
31
  const prefix = raw.slice("cluster_".length);
32
32
  if (out.has(prefix)) continue;
33
+ const rect = clusterRect(g);
33
34
  let nodeCount = 0;
34
35
  for (const node of allNodes) {
35
36
  if (node.getAttribute("data-instance")) continue;
36
37
  const nodeTitle = directChild(node, "title");
37
38
  if (!nodeTitle) continue;
38
39
  const id = (nodeTitle.textContent ?? "").trim();
39
- if (nodeBelongsToPrefix(id, prefix)) {
40
+ if (nodeBelongsToCluster(id, node, prefix, rect)) {
40
41
  node.setAttribute("data-instance", prefix);
41
42
  nodeCount++;
42
43
  }
@@ -50,9 +51,77 @@ function discoverClusters(svg) {
50
51
  }
51
52
  return out;
52
53
  }
54
+ function nodeBelongsToCluster(nodeId, node, prefix, rect) {
55
+ if (nodeBelongsToPrefix(nodeId, prefix)) return true;
56
+ if (rect) {
57
+ const c = nodeCenter(node);
58
+ if (c && c.x >= rect.minX && c.x <= rect.maxX && c.y >= rect.minY && c.y <= rect.maxY) {
59
+ return true;
60
+ }
61
+ }
62
+ return false;
63
+ }
53
64
  function nodeBelongsToPrefix(nodeId, prefix) {
54
65
  return nodeId === prefix || nodeId.startsWith(`${prefix}/`) || nodeId.startsWith(`p_${prefix}_`) || nodeId.startsWith(`t_${prefix}_`) || nodeId.startsWith(`j_${prefix}_`);
55
66
  }
67
+ function clusterRect(group) {
68
+ const border = directChild(group, "polygon") ?? directChild(group, "path");
69
+ if (!border) return null;
70
+ const raw = border.getAttribute("points") ?? border.getAttribute("d") ?? "";
71
+ return boundsOf(raw);
72
+ }
73
+ function nodeCenter(node) {
74
+ const ellipse = directChild(node, "ellipse");
75
+ if (ellipse) {
76
+ const x = parseFloat(ellipse.getAttribute("cx") ?? "");
77
+ const y = parseFloat(ellipse.getAttribute("cy") ?? "");
78
+ if (!Number.isNaN(x) && !Number.isNaN(y)) return { x, y };
79
+ }
80
+ const shape = directChild(node, "polygon") ?? directChild(node, "path");
81
+ if (shape) {
82
+ const bounds = boundsOf(
83
+ shape.getAttribute("points") ?? shape.getAttribute("d") ?? ""
84
+ );
85
+ if (bounds) {
86
+ return {
87
+ x: (bounds.minX + bounds.maxX) / 2,
88
+ y: (bounds.minY + bounds.maxY) / 2
89
+ };
90
+ }
91
+ }
92
+ return null;
93
+ }
94
+ function boundsOf(coords) {
95
+ const nums = coords.match(/-?\d+(?:\.\d+)?/g);
96
+ if (!nums || nums.length < 2) return null;
97
+ let minX = Infinity;
98
+ let minY = Infinity;
99
+ let maxX = -Infinity;
100
+ let maxY = -Infinity;
101
+ for (let i = 0; i + 1 < nums.length; i += 2) {
102
+ const x = parseFloat(nums[i]);
103
+ const y = parseFloat(nums[i + 1]);
104
+ if (x < minX) minX = x;
105
+ if (x > maxX) maxX = x;
106
+ if (y < minY) minY = y;
107
+ if (y > maxY) maxY = y;
108
+ }
109
+ if (minX === Infinity) return null;
110
+ return { minX, minY, maxX, maxY };
111
+ }
112
+ function nodeClusterMap(svg) {
113
+ const map = /* @__PURE__ */ new Map();
114
+ svg.querySelectorAll("g.node[data-instance]").forEach((node) => {
115
+ const di = node.getAttribute("data-instance");
116
+ const title = directChild(node, "title");
117
+ const id = (title?.textContent ?? "").trim();
118
+ if (di && id) map.set(id, di);
119
+ });
120
+ return map;
121
+ }
122
+ function endpointInCluster(id, prefix, clusterMap) {
123
+ return nodeBelongsToPrefix(id, prefix) || clusterMap.get(id) === prefix;
124
+ }
56
125
  function colorForPrefix(prefix) {
57
126
  let h = 2166136261;
58
127
  for (let i = 0; i < prefix.length; i++) {
@@ -84,6 +153,7 @@ function setClusterCollapsed(cluster, collapsed) {
84
153
  node.classList.add("petri-collapsed-inside");
85
154
  hidden.push(node);
86
155
  });
156
+ const clusterMap = nodeClusterMap(root);
87
157
  root.querySelectorAll("g.edge").forEach((edge) => {
88
158
  const titleEl = directChild(edge, "title");
89
159
  if (!titleEl) return;
@@ -92,7 +162,7 @@ function setClusterCollapsed(cluster, collapsed) {
92
162
  if (arrow < 0) return;
93
163
  const from = t.slice(0, arrow);
94
164
  const to = t.slice(arrow + 2);
95
- if (nodeBelongsToPrefix(from, cluster.prefix) && nodeBelongsToPrefix(to, cluster.prefix)) {
165
+ if (endpointInCluster(from, cluster.prefix, clusterMap) && endpointInCluster(to, cluster.prefix, clusterMap)) {
96
166
  edge.classList.add("petri-collapsed-inside");
97
167
  hidden.push(edge);
98
168
  }
@@ -135,6 +205,7 @@ function applyFilter(svg, prefix) {
135
205
  }
136
206
  svg.setAttribute("data-active-filter", prefix);
137
207
  svg.classList.add("has-active-filter");
208
+ const clusterMap = nodeClusterMap(svg);
138
209
  svg.querySelectorAll("g.node").forEach((node) => {
139
210
  const di = node.getAttribute("data-instance");
140
211
  const match = !!di && (di === prefix || di.indexOf(prefix + "_") === 0 || di.indexOf(prefix + "/") === 0);
@@ -152,7 +223,7 @@ function applyFilter(svg, prefix) {
152
223
  }
153
224
  const from = titleText.slice(0, arrow);
154
225
  const to = titleText.slice(arrow + 2);
155
- const matches = (name) => name.indexOf(prefix + "/") >= 0 || name.indexOf(prefix + "_") >= 0 || name === prefix;
226
+ const matches = (name) => name.indexOf(prefix + "/") >= 0 || name.indexOf(prefix + "_") >= 0 || name === prefix || clusterMap.get(name) === prefix;
156
227
  if (matches(from) || matches(to)) edge.classList.remove("petri-dimmed");
157
228
  else edge.classList.add("petri-dimmed");
158
229
  });
@@ -160,9 +231,10 @@ function applyFilter(svg, prefix) {
160
231
  function isInsideCollapsedCluster(svg, clusters, collapsedPrefixes, graphId) {
161
232
  if (collapsedPrefixes.size === 0) return false;
162
233
  if (!svg) return false;
234
+ const clusterMap = nodeClusterMap(svg);
163
235
  for (const prefix of collapsedPrefixes) {
164
236
  if (!clusters.has(prefix)) continue;
165
- if (nodeBelongsToPrefix(graphId, prefix)) return true;
237
+ if (endpointInCluster(graphId, prefix, clusterMap)) return true;
166
238
  }
167
239
  return false;
168
240
  }