@weasel-js/diagram 1.14.1 → 1.14.2

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.
@@ -1260,20 +1260,7 @@ function packClusters(graph, rows, preferred2, axes, nodeGap) {
1260
1260
  const width = (n) => extent(n.bounds, axes.cross);
1261
1261
  const pref = (n) => preferred2.get(n.id) ?? 0;
1262
1262
  const insets = new Map(spans.map((s) => [s, canonical(s.group.inset, axes)]));
1263
- const centerOf = /* @__PURE__ */ new Map();
1264
- for (const span of spans) {
1265
- const inside = new Set(span.group.members);
1266
- let sum = 0;
1267
- let count = 0;
1268
- for (const row of rows) {
1269
- for (const n of row) {
1270
- if (!inside.has(n.id)) continue;
1271
- sum += pref(n) + width(n) / 2;
1272
- count++;
1273
- }
1274
- }
1275
- centerOf.set(span, count === 0 ? 0 : sum / count);
1276
- }
1263
+ const centerOf = centersOf(spans, rows, (n) => pref(n) + width(n) / 2);
1277
1264
  const itemsByRow = (owner, among) => rows.map((row, r) => {
1278
1265
  const items = [];
1279
1266
  for (const node of row) {
@@ -1317,9 +1304,15 @@ function packClusters(graph, rows, preferred2, axes, nodeGap) {
1317
1304
  const known = blocks.get(span);
1318
1305
  if (known !== void 0) return known;
1319
1306
  const byRow = itemsByRow(span, span.children);
1307
+ const own = rows.flat().filter((n) => spanOf4(n) === span);
1320
1308
  const base = Math.min(...rows.flat().filter((n) => span.group.members.includes(n.id) || spanOf4(n) === span).map(pref));
1321
- const childAt = new Map(span.children.map((c) => [c, Math.max(0, centerOf.get(c) - outer(c) / 2 - base)]));
1322
- const { nodeAt, ends: ends2 } = settle2(byRow, childAt, (n) => pref(n) - base, 0);
1309
+ const childLo = new Map(span.children.map((c) => [c, Math.max(0, centerOf.get(c) - outer(c) / 2 - base)]));
1310
+ const squeezed = closeGaps([
1311
+ ...own.map((n) => [pref(n) - base, pref(n) - base + width(n)]),
1312
+ ...span.children.map((c) => [childLo.get(c), childLo.get(c) + outer(c)])
1313
+ ], nodeGap);
1314
+ const childAt = new Map(span.children.map((c) => [c, squeezed(childLo.get(c))]));
1315
+ const { nodeAt, ends: ends2 } = settle2(byRow, childAt, (n) => squeezed(pref(n) - base), 0);
1323
1316
  const block = { width: Math.max(0, ...ends2), nodeAt, childAt };
1324
1317
  const slack = widen(block, span.group, insets.get(span), axes);
1325
1318
  for (const [id, x] of nodeAt) nodeAt.set(id, x + slack);
@@ -1342,6 +1335,33 @@ function packClusters(graph, rows, preferred2, axes, nodeGap) {
1342
1335
  for (const root of roots) place(root, start.get(root));
1343
1336
  return at2;
1344
1337
  }
1338
+ function centersOf(spans, rows, center2) {
1339
+ const out = /* @__PURE__ */ new Map();
1340
+ for (const span of spans) {
1341
+ const inside = new Set(span.group.members);
1342
+ const centers = rows.flat().filter((n) => inside.has(n.id)).map(center2);
1343
+ out.set(span, centers.length === 0 ? 0 : centers.reduce((a, b) => a + b, 0) / centers.length);
1344
+ }
1345
+ return out;
1346
+ }
1347
+ function closeGaps(spans, gap) {
1348
+ const sorted = [...spans].sort((a, b) => a[0] - b[0]);
1349
+ const cuts = [];
1350
+ let reach = sorted[0]?.[1] ?? 0;
1351
+ let removed = 0;
1352
+ for (const [lo, hi] of sorted.slice(1)) {
1353
+ if (lo - reach > gap) {
1354
+ removed += lo - reach - gap;
1355
+ cuts.push([lo, removed]);
1356
+ }
1357
+ reach = Math.max(reach, hi);
1358
+ }
1359
+ return (at2) => {
1360
+ let shift = 0;
1361
+ for (const [from, by] of cuts) if (at2 >= from) shift = by;
1362
+ return at2 - shift;
1363
+ };
1364
+ }
1345
1365
  function widen(block, group, inset2, axes) {
1346
1366
  const floor = axes.cross === "x" ? (group.minWidth ?? 0) - inset2.crossLo - inset2.crossHi : 0;
1347
1367
  const slack = Math.max(0, floor - block.width) / 2;
@@ -1969,6 +1989,7 @@ function authoredOver(edges, plan) {
1969
1989
  }
1970
1990
 
1971
1991
  // src/layered/rank.ts
1992
+ var GROUP_WEIGHT = 4;
1972
1993
  function ranksByLength(graph, back) {
1973
1994
  const index = /* @__PURE__ */ new Map();
1974
1995
  graph.nodes.forEach((node, i) => index.set(node.id, i));
@@ -1977,15 +1998,28 @@ function ranksByLength(graph, back) {
1977
1998
  const from = index.get(edge.from);
1978
1999
  const to = index.get(edge.to);
1979
2000
  if (from === void 0 || to === void 0 || from === to) continue;
1980
- arcs.push(back.has(edge.id) ? { tail: to, head: from } : { tail: from, head: to });
2001
+ arcs.push(back.has(edge.id) ? { tail: to, head: from, weight: 1, minlen: 1 } : { tail: from, head: to, weight: 1, minlen: 1 });
2002
+ }
2003
+ let count = graph.nodes.length;
2004
+ for (const group of graph.groups ?? []) {
2005
+ const members = [...new Set(group.members.map((id) => index.get(id)).filter((i) => i !== void 0))];
2006
+ if (members.length < 2) continue;
2007
+ const [top, bottom] = [count, count + 1];
2008
+ count += 2;
2009
+ for (const m of members) {
2010
+ arcs.push({ tail: top, head: m, weight: GROUP_WEIGHT, minlen: 0 });
2011
+ arcs.push({ tail: m, head: bottom, weight: GROUP_WEIGHT, minlen: 0 });
2012
+ }
1981
2013
  }
1982
- const start = longestPath(graph.nodes.length, arcs);
2014
+ const real = graph.nodes.length;
2015
+ const start = longestPath(count, arcs);
1983
2016
  const ranks = /* @__PURE__ */ new Map();
1984
- for (const part of components(graph.nodes.length, arcs)) {
2017
+ for (const part of components(count, arcs)) {
1985
2018
  const rank = part.nodes.map((g) => start[g]);
1986
2019
  simplex(part.arcs, rank);
1987
- const min = Math.min(...rank);
1988
- part.nodes.forEach((g, i) => ranks.set(graph.nodes[g].id, rank[i] - min));
2020
+ const own = part.nodes.flatMap((g, i) => g < real ? [i] : []);
2021
+ const min = Math.min(...own.map((i) => rank[i]));
2022
+ for (const i of own) ranks.set(graph.nodes[part.nodes[i]].id, rank[i] - min);
1989
2023
  }
1990
2024
  return ranks;
1991
2025
  }
@@ -1995,14 +2029,14 @@ function longestPath(count, arcs) {
1995
2029
  const out = Array.from({ length: count }, () => []);
1996
2030
  for (const arc2 of arcs) {
1997
2031
  pending[arc2.head]++;
1998
- out[arc2.tail].push(arc2.head);
2032
+ out[arc2.tail].push(arc2);
1999
2033
  }
2000
2034
  const ready = [];
2001
2035
  for (let i = 0; i < count; i++) if (pending[i] === 0) ready.push(i);
2002
2036
  for (let k = 0; k < ready.length; k++) {
2003
2037
  const u = ready[k];
2004
- for (const v of out[u]) {
2005
- rank[v] = Math.max(rank[v], rank[u] + 1);
2038
+ for (const { head: v, minlen } of out[u]) {
2039
+ rank[v] = Math.max(rank[v], rank[u] + minlen);
2006
2040
  if (--pending[v] === 0) ready.push(v);
2007
2041
  }
2008
2042
  }
@@ -2034,11 +2068,11 @@ function components(count, arcs) {
2034
2068
  const local = new Array(count);
2035
2069
  for (const p of parts) p.nodes.forEach((g, i) => local[g] = i);
2036
2070
  for (const arc2 of arcs) {
2037
- parts[part[arc2.tail]].arcs.push({ tail: local[arc2.tail], head: local[arc2.head] });
2071
+ parts[part[arc2.tail]].arcs.push({ ...arc2, tail: local[arc2.tail], head: local[arc2.head] });
2038
2072
  }
2039
2073
  return parts;
2040
2074
  }
2041
- var slackOf = (arc2, rank) => rank[arc2.head] - rank[arc2.tail] - 1;
2075
+ var slackOf = (arc2, rank) => rank[arc2.head] - rank[arc2.tail] - arc2.minlen;
2042
2076
  function simplex(arcs, rank) {
2043
2077
  if (arcs.length === 0 || arcs.some((arc2) => slackOf(arc2, rank) < 0)) return;
2044
2078
  const inTree = feasibleTree(arcs, rank);
@@ -2152,7 +2186,7 @@ function cutValue(arcs, a, tree2) {
2152
2186
  for (const arc2 of arcs) {
2153
2187
  const from = inside(arc2.tail);
2154
2188
  if (from === inside(arc2.head)) continue;
2155
- value += from === tailInside ? 1 : -1;
2189
+ value += from === tailInside ? arc2.weight : -arc2.weight;
2156
2190
  }
2157
2191
  return { value, tailInside };
2158
2192
  }
@@ -2168,7 +2202,7 @@ function tighten(rank, arcs, inTree) {
2168
2202
  const w = arc2.tail === v ? arc2.head : arc2.tail;
2169
2203
  if (seen[w]) continue;
2170
2204
  seen[w] = true;
2171
- rank[w] = arc2.tail === v ? rank[v] + 1 : rank[v] - 1;
2205
+ rank[w] = arc2.tail === v ? rank[v] + arc2.minlen : rank[v] - arc2.minlen;
2172
2206
  queue.push(w);
2173
2207
  }
2174
2208
  }
@@ -2924,6 +2958,112 @@ function holdPins(input) {
2924
2958
  return { crossAt, gaps, depths: los.map((lo, k) => his[k] - lo), rankAt, unheld };
2925
2959
  }
2926
2960
 
2961
+ // src/layered/inward.ts
2962
+ var SLACK = 1;
2963
+ function turnOutward(input) {
2964
+ const { rows, axes } = input;
2965
+ const size = (n) => extent(n.bounds, axes.cross);
2966
+ const lo = (n) => input.crossAt.get(n.id);
2967
+ const hi = (n) => lo(n) + size(n);
2968
+ const hull = drawingSpan(input, size);
2969
+ if (hull === void 0) return void 0;
2970
+ const free = (n) => n.group === void 0 && !input.pinned.has(n.id);
2971
+ const { up, down } = sidesOf(input.hops);
2972
+ const kin = (a, b) => [up, down].some((side) => (side.get(a) ?? []).some((n) => (side.get(b) ?? []).includes(n)));
2973
+ const out = rows.map((row) => [...row]);
2974
+ let changed = false;
2975
+ for (const high of [true, false]) {
2976
+ const reach = (n) => high ? hi(n) : -lo(n);
2977
+ let best;
2978
+ for (const [r, row] of out.entries()) {
2979
+ const order2 = high ? [...row].reverse() : row;
2980
+ let k = 0;
2981
+ while (k < order2.length && isPlaceholder(order2[k].id) && free(order2[k])) k++;
2982
+ const node = order2[k];
2983
+ if (k === 0 || node === void 0 || isPlaceholder(node.id) || !free(node)) continue;
2984
+ const run = order2.slice(0, k);
2985
+ if (!run.every((p) => reach(p) - (high ? hull[1] : -hull[0]) > SLACK)) continue;
2986
+ if (run.some((p) => kin(p.id, node.id))) continue;
2987
+ if (best === void 0 || reach(node) > best.by) best = { r, k, by: reach(node) };
2988
+ }
2989
+ if (best === void 0) continue;
2990
+ const order = high ? [...out[best.r]].reverse() : out[best.r];
2991
+ const turned = [order[best.k], ...order.slice(0, best.k), ...order.slice(best.k + 1)];
2992
+ out[best.r] = high ? turned.reverse() : turned;
2993
+ changed = true;
2994
+ }
2995
+ return changed ? out : void 0;
2996
+ }
2997
+ function drawingSpan(input, size) {
2998
+ let lo = Infinity;
2999
+ let hi = -Infinity;
3000
+ const take = ([a, b]) => {
3001
+ lo = Math.min(lo, a);
3002
+ hi = Math.max(hi, b);
3003
+ };
3004
+ for (const n of input.rows.flat()) {
3005
+ if (!isPlaceholder(n.id)) take([input.crossAt.get(n.id), input.crossAt.get(n.id) + size(n)]);
3006
+ }
3007
+ for (const box of groupBoxes(input, size).values()) take(box);
3008
+ return lo <= hi ? [lo, hi] : void 0;
3009
+ }
3010
+ function groupBoxes(input, size) {
3011
+ const groups = input.graph.groups ?? [];
3012
+ const byId = new Map(groups.map((g) => [g.id, g]));
3013
+ const inner = /* @__PURE__ */ new Map();
3014
+ const widen2 = (id, [a, b]) => {
3015
+ const s = inner.get(id);
3016
+ inner.set(id, s === void 0 ? [a, b] : [Math.min(s[0], a), Math.max(s[1], b)]);
3017
+ };
3018
+ for (const n of input.rows.flat()) {
3019
+ if (n.group === void 0 || isPlaceholder(n.id)) continue;
3020
+ const at2 = input.crossAt.get(n.id);
3021
+ for (let g = byId.get(n.group); g !== void 0; g = g.parent === void 0 ? void 0 : byId.get(g.parent)) widen2(g.id, [at2, at2 + size(n)]);
3022
+ }
3023
+ const depth = (id) => {
3024
+ const p = byId.get(id)?.parent;
3025
+ return p === void 0 ? 0 : 1 + depth(p);
3026
+ };
3027
+ const boxes = /* @__PURE__ */ new Map();
3028
+ for (const id of [...inner.keys()].sort((a, b) => depth(b) - depth(a))) {
3029
+ const g = byId.get(id);
3030
+ const [a, b] = inner.get(id);
3031
+ const inset2 = crossInset(g.inset, input.axes);
3032
+ const box = [a - inset2.lo, b + inset2.hi];
3033
+ boxes.set(id, box);
3034
+ if (g.parent !== void 0) widen2(g.parent, box);
3035
+ }
3036
+ return boxes;
3037
+ }
3038
+
3039
+ // src/layered/reach.ts
3040
+ function boxReach(graph, rows, axes) {
3041
+ const lo = rows.map(() => 0);
3042
+ const hi = rows.map(() => 0);
3043
+ const groups = graph.groups ?? [];
3044
+ const byId = new Map(groups.map((g) => [g.id, g]));
3045
+ const rowOf = /* @__PURE__ */ new Map();
3046
+ rows.forEach((row, r) => row.forEach((n) => rowOf.set(n.id, r)));
3047
+ const span = /* @__PURE__ */ new Map();
3048
+ for (const g of groups) {
3049
+ const rs = g.members.map((m) => rowOf.get(m)).filter((r) => r !== void 0);
3050
+ if (rs.length > 0) span.set(g.id, [Math.min(...rs), Math.max(...rs)]);
3051
+ }
3052
+ for (const g of groups) {
3053
+ const own = span.get(g.id);
3054
+ if (own === void 0) continue;
3055
+ for (const [side, out] of [[0, lo], [1, hi]]) {
3056
+ let reach = 0;
3057
+ for (let h = byId.get(g.id); h !== void 0; h = h.parent === void 0 ? void 0 : byId.get(h.parent)) {
3058
+ if (span.get(h.id)?.[side] !== own[side]) break;
3059
+ reach += rankInset(h.inset, axes)[side === 0 ? "lo" : "hi"];
3060
+ }
3061
+ out[own[side]] = Math.max(out[own[side]], reach);
3062
+ }
3063
+ }
3064
+ return { lo, hi };
3065
+ }
3066
+
2927
3067
  // src/layered/place.ts
2928
3068
  var pairKey = (upper, lower) => `${upper}\0${lower}`;
2929
3069
  function placeAcross(rows, hops, axis, nodeGap) {
@@ -3157,17 +3297,26 @@ function planOnce(graph, opts = {}) {
3157
3297
  const back = backEdges(graph);
3158
3298
  const ranks = ranksByLength(graph, back);
3159
3299
  const expanded = expand(graph, ranks, back, { axes, nodeGap });
3160
- const rows = finding ? orderRows(expanded.rows, expanded.hops, { groups: graph.groups ?? [] }) : expanded.rows;
3161
- const preferred2 = placeAcross(rows, settlePlaces(rows, expanded.hops), axes.cross, nodeGap);
3300
+ let rows = finding ? orderRows(expanded.rows, expanded.hops, { groups: graph.groups ?? [] }) : expanded.rows;
3162
3301
  const grouped = (graph.groups?.length ?? 0) > 0;
3163
- const packed = grouped ? packClusters(graph, rows, preferred2, axes, nodeGap) : preferred2;
3302
+ const pinned = pinnedSet(graph, opts);
3303
+ const across = () => {
3304
+ const preferred2 = placeAcross(rows, settlePlaces(rows, expanded.hops), axes.cross, nodeGap);
3305
+ return grouped ? packClusters(graph, rows, preferred2, axes, nodeGap) : preferred2;
3306
+ };
3307
+ let packed = across();
3308
+ for (let turn = 0; turn < rows.length; turn++) {
3309
+ const turned = turnOutward({ graph, rows, crossAt: packed, axes, pinned, hops: expanded.hops });
3310
+ if (turned === void 0) break;
3311
+ rows = turned;
3312
+ packed = across();
3313
+ }
3164
3314
  const spaced = grouped ? rankGaps(graph, rows, axes, rankGap) : rows.slice(1).map(() => rankGap);
3165
3315
  const minGaps = spaced.map((gap) => gap - rankGap + rankGap * MIN_GAP);
3166
3316
  for (const r of expanded.labelRows) {
3167
3317
  spaced[r - 1] = spaced[r - 1] - rankGap * (1 - LABEL_GAP);
3168
3318
  spaced[r] = spaced[r] - rankGap * (1 - LABEL_GAP);
3169
3319
  }
3170
- const pinned = pinnedSet(graph, opts);
3171
3320
  const { crossAt, gaps, depths: depths2, rankAt, unheld } = holdPins({ graph, rows, crossAt: packed, gaps: spaced, pinned, axes, nodeGap, minGaps });
3172
3321
  const slots = /* @__PURE__ */ new Map();
3173
3322
  const bands = [];
@@ -3198,6 +3347,7 @@ function planOnce(graph, opts = {}) {
3198
3347
  const labels = /* @__PURE__ */ new Map();
3199
3348
  const rankOf = /* @__PURE__ */ new Map();
3200
3349
  rows.forEach((row, r) => row.forEach((n) => rankOf.set(n.id, r)));
3350
+ const reach = boxReach(graph, rows, axes);
3201
3351
  const widthOf = new Map(rows.flat().map((n) => [n.id, extent(n.bounds, axes.cross)]));
3202
3352
  for (const [edge, chain2] of expanded.chains) {
3203
3353
  if (chain2.ends.some((id) => displaced.has(id))) continue;
@@ -3205,7 +3355,8 @@ function planOnce(graph, opts = {}) {
3205
3355
  const points = [];
3206
3356
  for (const id of chain2.ids) {
3207
3357
  const cross = crossAt.get(id) + (expanded.wires.get(id) ?? widthOf.get(id) / 2);
3208
- const [lo, hi] = bands[rankOf.get(id)];
3358
+ const r = rankOf.get(id);
3359
+ const [lo, hi] = [bands[r][0] - reach.lo[r], bands[r][1] + reach.hi[r]];
3209
3360
  for (const rank of chain2.back ? [hi, lo] : [lo, hi]) {
3210
3361
  const at2 = worldOf({ cross, rank }, 0, axes);
3211
3362
  points.push({ x: at2.x + offset.x, y: at2.y + offset.y });
@@ -3716,5 +3867,5 @@ var treeOnce = (graph, opts = {}) => {
3716
3867
  };
3717
3868
 
3718
3869
  export { COMPASS, DEFAULT_GROUP_INSET, DEFAULT_NODE_GAP, DEFAULT_PORTS, DEFAULT_RANK_GAP, DEVICE_SIZE, DIAGRAM_TRAIT_KEY, DIVIDER_HEIGHT, EVENT_SIZE, GATEWAY_SIZE, PORT_LABEL_GAP, SIDE_TRACK_GAP, anchorOffset, authoredOver, axesFor, backEdges, bodyOutline, bodyTrait, boxForContent, buildBody, canvasMeasure, center, chain, contentBox, createDiagramNodes, dataKeyReader, diagramEdgeOf, diagramNodeOf, expandGroupEdges, extent, footprintNode, force, forceRelaxation, forestOf, graphOrder, grownBy, insetOf, isPinned, isPromise, labelCenter, labelSpotAt, layered, layeredPlan, layeredRoutes, layoutBody, layoutOwnsPort, layoutOwnsRoute, layoutRowPorts, layoutWritesRoute, marginOf, measureBody, outlineDetail, outlineFromD, outlinePath, outlinePolyline, packAcross, packClusters, pinnedSet, planOf, plannerPlan, portLabelBox, portLabelsOf, portOf, portSitesOf, portsOf, portsOnOutline, rankGaps, ranksByLength, ranksOf, rayHit, registerOutline, resolveOutline, routeHolds, rowHeights, samePoints, seededOrder, settle, sizeToBody, subpathOf, subtreeBlocks, translated, tree, untilSettled, widenForMinWidth };
3719
- //# sourceMappingURL=chunk-VB6HUKNG.js.map
3720
- //# sourceMappingURL=chunk-VB6HUKNG.js.map
3870
+ //# sourceMappingURL=chunk-FDCODMFW.js.map
3871
+ //# sourceMappingURL=chunk-FDCODMFW.js.map