@yuneta/gobj-ui 7.23.152 → 7.23.154
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/README.md +24 -3
- package/dist/gobj-ui.cjs.js +345 -27
- package/dist/gobj-ui.es.js +345 -27
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +68 -5
- package/src/treedb_elbow.js +231 -13
- package/src/treedb_elbow.test.js +192 -1
- package/src/treedb_layout.js +146 -14
- package/src/treedb_layout.test.js +84 -12
package/dist/gobj-ui.es.js
CHANGED
|
@@ -29326,6 +29326,14 @@ function tidy_tree_lr(nodes, edges, o) {
|
|
|
29326
29326
|
* the packing across the depths differs, so switching between the
|
|
29327
29327
|
* two moves cards sideways and never reorders them.
|
|
29328
29328
|
*
|
|
29329
|
+
* And a run of three or more LEAF children -- a hall's devices, a
|
|
29330
|
+
* region's places when none is open -- is STACKED: two columns
|
|
29331
|
+
* under the parent with a corridor between them, row after row.
|
|
29332
|
+
* That is what makes it compact when a whole level is open, where
|
|
29333
|
+
* the contour alone gains nothing: every parent needed the whole
|
|
29334
|
+
* row of its children beside it. The tree grows taller instead of
|
|
29335
|
+
* wider. Its elbow edges run down the corridor (elbow_combs).
|
|
29336
|
+
*
|
|
29329
29337
|
* The contour arithmetic is Moen's ("Drawing dynamic trees", IEEE
|
|
29330
29338
|
* Software, 1990) in the form mxGraph gave it in mxCompactTreeLayout
|
|
29331
29339
|
* -- Copyright (c) 2006-2015 JGraph Ltd, Apache License 2.0 -- read in
|
|
@@ -29406,10 +29414,81 @@ function contour_merge(p1, p2) {
|
|
|
29406
29414
|
p1.lower_head = p2.lower_head;
|
|
29407
29415
|
return total;
|
|
29408
29416
|
}
|
|
29417
|
+
function stack_trunk_width(k) {
|
|
29418
|
+
let lanes = Math.max(0, k - 2);
|
|
29419
|
+
return Math.max(36, 20 + Math.max(0, lanes - 1) * 6);
|
|
29420
|
+
}
|
|
29421
|
+
function stack_geometry(t, st, col_x, col_w) {
|
|
29422
|
+
let d = st.depth;
|
|
29423
|
+
let k = st.ids.length;
|
|
29424
|
+
let rows = Math.ceil(k / 2);
|
|
29425
|
+
let side = [0, 0];
|
|
29426
|
+
let row_len = [];
|
|
29427
|
+
for (let i = 0; i < k; i++) {
|
|
29428
|
+
let n = t.by_id.get(st.ids[i]);
|
|
29429
|
+
let r = Math.floor(i / 2);
|
|
29430
|
+
side[i % 2] = Math.max(side[i % 2], n.h);
|
|
29431
|
+
row_len[r] = Math.max(row_len[r] || 0, n.w);
|
|
29432
|
+
}
|
|
29433
|
+
row_len[0] = col_w[d];
|
|
29434
|
+
let trunk = stack_trunk_width(k);
|
|
29435
|
+
let starts = [col_x[d]];
|
|
29436
|
+
for (let r = 1; r < rows; r++) starts[r] = starts[r - 1] + row_len[r - 1] + 40;
|
|
29437
|
+
return {
|
|
29438
|
+
side,
|
|
29439
|
+
trunk,
|
|
29440
|
+
starts,
|
|
29441
|
+
row_len,
|
|
29442
|
+
len: starts[rows - 1] + row_len[rows - 1] - col_x[d],
|
|
29443
|
+
ext: side[0] + trunk + side[1]
|
|
29444
|
+
};
|
|
29445
|
+
}
|
|
29446
|
+
function place_stack(t, st, g, top, pos) {
|
|
29447
|
+
for (let i = 0; i < st.ids.length; i++) {
|
|
29448
|
+
let n = t.by_id.get(st.ids[i]);
|
|
29449
|
+
let r = Math.floor(i / 2);
|
|
29450
|
+
let across = i % 2 === 0 ? top + g.side[0] - n.h / 2 : top + g.side[0] + g.trunk + n.h / 2;
|
|
29451
|
+
pos.set(st.ids[i], {
|
|
29452
|
+
x: g.starts[r] + g.row_len[r] / 2,
|
|
29453
|
+
y: across
|
|
29454
|
+
});
|
|
29455
|
+
}
|
|
29456
|
+
}
|
|
29409
29457
|
function compact_tree_lr(nodes, edges, o) {
|
|
29410
29458
|
let t = spanning_tree(nodes, edges);
|
|
29411
|
-
let order = walk_order(t);
|
|
29412
29459
|
let pos = /* @__PURE__ */ new Map();
|
|
29460
|
+
let kids_of = /* @__PURE__ */ new Map();
|
|
29461
|
+
let stacks = /* @__PURE__ */ new Map();
|
|
29462
|
+
for (let [id, kids] of t.children) {
|
|
29463
|
+
let out = [];
|
|
29464
|
+
let run = [];
|
|
29465
|
+
let flush = () => {
|
|
29466
|
+
if (run.length >= 3) {
|
|
29467
|
+
let key = { stack: stacks.size };
|
|
29468
|
+
stacks.set(key, {
|
|
29469
|
+
ids: run,
|
|
29470
|
+
depth: t.depth.get(run[0])
|
|
29471
|
+
});
|
|
29472
|
+
out.push(key);
|
|
29473
|
+
} else out.push(...run);
|
|
29474
|
+
run = [];
|
|
29475
|
+
};
|
|
29476
|
+
for (let kid of kids) if ((t.children.get(kid) || []).length === 0) run.push(kid);
|
|
29477
|
+
else {
|
|
29478
|
+
flush();
|
|
29479
|
+
out.push(kid);
|
|
29480
|
+
}
|
|
29481
|
+
flush();
|
|
29482
|
+
kids_of.set(id, out);
|
|
29483
|
+
}
|
|
29484
|
+
let order = [];
|
|
29485
|
+
let todo = t.roots.slice().reverse();
|
|
29486
|
+
while (todo.length) {
|
|
29487
|
+
let id = todo.pop();
|
|
29488
|
+
order.push(id);
|
|
29489
|
+
let kids = kids_of.get(id) || [];
|
|
29490
|
+
for (let i = kids.length - 1; i >= 0; i--) todo.push(kids[i]);
|
|
29491
|
+
}
|
|
29413
29492
|
let col_w = [];
|
|
29414
29493
|
for (let [id, d] of t.depth) col_w[d] = Math.max(col_w[d] || 0, t.by_id.get(id).w);
|
|
29415
29494
|
let col_x = [];
|
|
@@ -29422,18 +29501,32 @@ function compact_tree_lr(nodes, edges, o) {
|
|
|
29422
29501
|
let dist = o.nodesep;
|
|
29423
29502
|
let level_distance = o.ranksep - pad;
|
|
29424
29503
|
let tn = /* @__PURE__ */ new Map();
|
|
29425
|
-
for (let id of order)
|
|
29426
|
-
|
|
29427
|
-
|
|
29428
|
-
|
|
29429
|
-
|
|
29430
|
-
|
|
29431
|
-
|
|
29432
|
-
|
|
29504
|
+
for (let id of order) {
|
|
29505
|
+
let st = stacks.get(id);
|
|
29506
|
+
if (st) {
|
|
29507
|
+
let g = stack_geometry(t, st, col_x, col_w);
|
|
29508
|
+
tn.set(id, {
|
|
29509
|
+
len: g.len,
|
|
29510
|
+
ext: g.ext,
|
|
29511
|
+
geom: g,
|
|
29512
|
+
off_x: 0,
|
|
29513
|
+
off_y: 0,
|
|
29514
|
+
y: 0,
|
|
29515
|
+
contour: null
|
|
29516
|
+
});
|
|
29517
|
+
} else tn.set(id, {
|
|
29518
|
+
len: col_w[t.depth.get(id)],
|
|
29519
|
+
ext: t.by_id.get(id).h,
|
|
29520
|
+
off_x: 0,
|
|
29521
|
+
off_y: 0,
|
|
29522
|
+
y: 0,
|
|
29523
|
+
contour: null
|
|
29524
|
+
});
|
|
29525
|
+
}
|
|
29433
29526
|
for (let i = order.length - 1; i >= 0; i--) {
|
|
29434
29527
|
let id = order[i];
|
|
29435
29528
|
let n = tn.get(id);
|
|
29436
|
-
let kids =
|
|
29529
|
+
let kids = kids_of.get(id) || [];
|
|
29437
29530
|
if (!kids.length) {
|
|
29438
29531
|
let upper = contour_line(n.len + dist, 0);
|
|
29439
29532
|
let lower_tail = contour_line(0, -n.ext - dist);
|
|
@@ -29469,7 +29562,7 @@ function compact_tree_lr(nodes, edges, o) {
|
|
|
29469
29562
|
for (let id of order) {
|
|
29470
29563
|
let n = tn.get(id);
|
|
29471
29564
|
if (!root_of.has(id)) root_of.set(id, id);
|
|
29472
|
-
let kids =
|
|
29565
|
+
let kids = kids_of.get(id) || [];
|
|
29473
29566
|
if (!kids.length) continue;
|
|
29474
29567
|
let running = n.y + tn.get(kids[0]).off_y;
|
|
29475
29568
|
tn.get(kids[0]).y = running;
|
|
@@ -29496,9 +29589,14 @@ function compact_tree_lr(nodes, edges, o) {
|
|
|
29496
29589
|
top += hi.get(r) - lo.get(r) + o.nodesep * 2;
|
|
29497
29590
|
}
|
|
29498
29591
|
for (let id of order) {
|
|
29499
|
-
let d = t.depth.get(id);
|
|
29500
29592
|
let n = tn.get(id);
|
|
29501
29593
|
let y = n.y + shift.get(root_of.get(id));
|
|
29594
|
+
let st = stacks.get(id);
|
|
29595
|
+
if (st) {
|
|
29596
|
+
place_stack(t, st, n.geom, y, pos);
|
|
29597
|
+
continue;
|
|
29598
|
+
}
|
|
29599
|
+
let d = t.depth.get(id);
|
|
29502
29600
|
pos.set(id, {
|
|
29503
29601
|
x: col_x[d] + col_w[d] / 2,
|
|
29504
29602
|
y: y + n.ext / 2
|
|
@@ -29635,6 +29733,23 @@ function elbow_lane(ids, id) {
|
|
|
29635
29733
|
if (k <= 0) return 0;
|
|
29636
29734
|
return (k % 2 ? 1 : -1) * Math.ceil(k / 2);
|
|
29637
29735
|
}
|
|
29736
|
+
/************************************************************
|
|
29737
|
+
* The rank of `id` among `items` ([{id, span}]): the forward
|
|
29738
|
+
* edges that share one end with it, each with how far it runs
|
|
29739
|
+
* ACROSS. Farthest first; a tie goes to the edge made first.
|
|
29740
|
+
* Returns {rank, count}.
|
|
29741
|
+
************************************************************/
|
|
29742
|
+
function elbow_rank(items, id) {
|
|
29743
|
+
let sorted = items.slice().sort((a, b) => {
|
|
29744
|
+
if (b.span !== a.span) return b.span - a.span;
|
|
29745
|
+
return String(a.id).localeCompare(String(b.id), void 0, { numeric: true });
|
|
29746
|
+
});
|
|
29747
|
+
let rank = sorted.findIndex((it) => it.id === id);
|
|
29748
|
+
return {
|
|
29749
|
+
rank: rank < 0 ? 0 : rank,
|
|
29750
|
+
count: sorted.length
|
|
29751
|
+
};
|
|
29752
|
+
}
|
|
29638
29753
|
function swap(p) {
|
|
29639
29754
|
return [p[1], p[0]];
|
|
29640
29755
|
}
|
|
@@ -29646,6 +29761,136 @@ function swap_box(b) {
|
|
|
29646
29761
|
y2: b.x2
|
|
29647
29762
|
};
|
|
29648
29763
|
}
|
|
29764
|
+
function staggered_turn(lo, hi, st) {
|
|
29765
|
+
let mid = (lo + hi) / 2;
|
|
29766
|
+
let group = null;
|
|
29767
|
+
let k = 0;
|
|
29768
|
+
if (st.dep && st.dep.count > 1) {
|
|
29769
|
+
group = st.dep;
|
|
29770
|
+
k = st.dep.rank;
|
|
29771
|
+
} else if (st.arr && st.arr.count > 1) {
|
|
29772
|
+
group = st.arr;
|
|
29773
|
+
k = st.arr.count - 1 - st.arr.rank;
|
|
29774
|
+
}
|
|
29775
|
+
if (group) {
|
|
29776
|
+
let room = Math.max(0, hi - lo - 12);
|
|
29777
|
+
let step = Math.min(10, room / (group.count - 1));
|
|
29778
|
+
mid = mid - (group.count - 1) * step / 2 + k * step;
|
|
29779
|
+
}
|
|
29780
|
+
return mid;
|
|
29781
|
+
}
|
|
29782
|
+
/************************************************************
|
|
29783
|
+
* The combs of the stacks under one card.
|
|
29784
|
+
*
|
|
29785
|
+
* treedb_layout.js lays a run of leaf children out as two columns
|
|
29786
|
+
* with a corridor between them. A card in the first row is reached
|
|
29787
|
+
* from the channel like any other; one in a lower row cannot be --
|
|
29788
|
+
* the card above it stands in the way -- so its edge runs down
|
|
29789
|
+
* the corridor in a LANE of its own and turns into the gap above
|
|
29790
|
+
* its card, which it shares only with the other card of its row,
|
|
29791
|
+
* reached from the other side.
|
|
29792
|
+
*
|
|
29793
|
+
* targets [{id, box}]: the forward edges leaving one card,
|
|
29794
|
+
* each with the box of the card it reaches
|
|
29795
|
+
* vertical as in elbow_points; false swaps the boxes
|
|
29796
|
+
*
|
|
29797
|
+
* Returns Map id -> {lane, z, top}: the lane, the height of the
|
|
29798
|
+
* gap it turns into, and the top of the stack's first row (where
|
|
29799
|
+
* the channel over the stack ends). Only for a card that stands
|
|
29800
|
+
* under another of the group, within a stack gap and lined up
|
|
29801
|
+
* with it on the corridor side -- what a stack looks like.
|
|
29802
|
+
*
|
|
29803
|
+
* Lanes go outermost first, row by row: a line into a higher row
|
|
29804
|
+
* keeps outside the lines going deeper, and none crosses another.
|
|
29805
|
+
************************************************************/
|
|
29806
|
+
function elbow_combs(targets, vertical) {
|
|
29807
|
+
let list = vertical ? targets : targets.map((it) => ({
|
|
29808
|
+
id: it.id,
|
|
29809
|
+
box: swap_box(it.box)
|
|
29810
|
+
}));
|
|
29811
|
+
let cy = (b) => (b.y1 + b.y2) / 2;
|
|
29812
|
+
let near = (a, b) => Math.abs(a - b) < 1.5;
|
|
29813
|
+
let under = [];
|
|
29814
|
+
for (let it of list) {
|
|
29815
|
+
let b = it.box;
|
|
29816
|
+
let above = null;
|
|
29817
|
+
for (let o of list) {
|
|
29818
|
+
let a = o.box;
|
|
29819
|
+
if (o === it || a.y2 > b.y1 || b.y1 - a.y2 > 40) continue;
|
|
29820
|
+
if (!(near(a.x2, b.x2) || near(a.x1, b.x1))) continue;
|
|
29821
|
+
if (!above || a.y2 > above.y2) above = a;
|
|
29822
|
+
}
|
|
29823
|
+
if (!above) continue;
|
|
29824
|
+
let side;
|
|
29825
|
+
if (near(above.x2, b.x2) && !near(above.x1, b.x1)) side = 0;
|
|
29826
|
+
else if (near(above.x1, b.x1) && !near(above.x2, b.x2)) side = 1;
|
|
29827
|
+
else side = list.some((o) => o !== it && near(cy(o.box), cy(b)) && o.box.x2 <= b.x1) ? 1 : 0;
|
|
29828
|
+
under.push({
|
|
29829
|
+
id: it.id,
|
|
29830
|
+
box: b,
|
|
29831
|
+
above,
|
|
29832
|
+
side
|
|
29833
|
+
});
|
|
29834
|
+
}
|
|
29835
|
+
let corridor = (u) => {
|
|
29836
|
+
if (u.side === 0) {
|
|
29837
|
+
let l = u.box.x2;
|
|
29838
|
+
let col = list.filter((o) => near(o.box.x2, l));
|
|
29839
|
+
let r = Infinity;
|
|
29840
|
+
for (let c of col) for (let o of list) if (o !== c && near(cy(o.box), cy(c.box)) && o.box.x1 >= l - .5) r = Math.min(r, o.box.x1);
|
|
29841
|
+
return {
|
|
29842
|
+
l,
|
|
29843
|
+
r: isFinite(r) ? r : l + 36,
|
|
29844
|
+
col
|
|
29845
|
+
};
|
|
29846
|
+
}
|
|
29847
|
+
let r = u.box.x1;
|
|
29848
|
+
let col = list.filter((o) => near(o.box.x1, r));
|
|
29849
|
+
let l = -Infinity;
|
|
29850
|
+
for (let c of col) for (let o of list) if (o !== c && near(cy(o.box), cy(c.box)) && o.box.x2 <= r + .5) l = Math.max(l, o.box.x2);
|
|
29851
|
+
return {
|
|
29852
|
+
l: isFinite(l) ? l : r - 36,
|
|
29853
|
+
r,
|
|
29854
|
+
col
|
|
29855
|
+
};
|
|
29856
|
+
};
|
|
29857
|
+
let groups = /* @__PURE__ */ new Map();
|
|
29858
|
+
for (let u of under) {
|
|
29859
|
+
let c = corridor(u);
|
|
29860
|
+
u.top = Math.min(...c.col.map((o) => o.box.y1));
|
|
29861
|
+
let key = `${Math.round(c.l)}|${Math.round(c.r)}`;
|
|
29862
|
+
if (!groups.has(key)) groups.set(key, {
|
|
29863
|
+
l: c.l,
|
|
29864
|
+
r: c.r,
|
|
29865
|
+
left: [],
|
|
29866
|
+
right: []
|
|
29867
|
+
});
|
|
29868
|
+
groups.get(key)[u.side === 0 ? "left" : "right"].push(u);
|
|
29869
|
+
}
|
|
29870
|
+
let out = /* @__PURE__ */ new Map();
|
|
29871
|
+
for (let g of groups.values()) {
|
|
29872
|
+
g.left.sort((a, b) => a.box.y1 - b.box.y1);
|
|
29873
|
+
g.right.sort((a, b) => a.box.y1 - b.box.y1);
|
|
29874
|
+
let n = g.left.length + g.right.length;
|
|
29875
|
+
let room = g.r - g.l - 20;
|
|
29876
|
+
let step = n > 1 ? Math.max(0, Math.min(6, room / (n - 1))) : 0;
|
|
29877
|
+
g.left.forEach((u, i) => {
|
|
29878
|
+
out.set(u.id, {
|
|
29879
|
+
lane: g.l + 10 + i * step,
|
|
29880
|
+
z: (u.above.y2 + u.box.y1) / 2,
|
|
29881
|
+
top: u.top
|
|
29882
|
+
});
|
|
29883
|
+
});
|
|
29884
|
+
g.right.forEach((u, j) => {
|
|
29885
|
+
out.set(u.id, {
|
|
29886
|
+
lane: g.r - 10 - j * step,
|
|
29887
|
+
z: (u.above.y2 + u.box.y1) / 2,
|
|
29888
|
+
top: u.top
|
|
29889
|
+
});
|
|
29890
|
+
});
|
|
29891
|
+
}
|
|
29892
|
+
return out;
|
|
29893
|
+
}
|
|
29649
29894
|
/************************************************************
|
|
29650
29895
|
* The control points of an elbow from the port `s` to the port
|
|
29651
29896
|
* `t` ([x, y] each), knowing the boxes of the two cards
|
|
@@ -29653,13 +29898,33 @@ function swap_box(b) {
|
|
|
29653
29898
|
*
|
|
29654
29899
|
* vertical the rows are stacked (top to bottom); false
|
|
29655
29900
|
* when they are side by side (left to right)
|
|
29656
|
-
|
|
29657
|
-
|
|
29658
|
-
|
|
29901
|
+
* stagger {dep, arr, comb}: the edge's rank among the
|
|
29902
|
+
* forward edges leaving its source card and among
|
|
29903
|
+
* those reaching its target card (elbow_rank), and
|
|
29904
|
+
* its comb when the target is in a lower row of a
|
|
29905
|
+
* stack (elbow_combs). Absent, the channel is the
|
|
29906
|
+
* middle.
|
|
29907
|
+
************************************************************/
|
|
29908
|
+
function elbow_points(s, t, box_s, box_t, lane, vertical, stagger) {
|
|
29909
|
+
if (!vertical) return elbow_points(swap(s), swap(t), swap_box(box_s), swap_box(box_t), lane, true, stagger).map(swap);
|
|
29659
29910
|
let shift = lane * 10;
|
|
29660
29911
|
if (t[1] - s[1] > 20) {
|
|
29661
|
-
let
|
|
29662
|
-
|
|
29912
|
+
let st = stagger || {};
|
|
29913
|
+
let lo = Math.max(s[1], box_s.y2);
|
|
29914
|
+
if (st.comb) {
|
|
29915
|
+
let c = st.comb;
|
|
29916
|
+
let turn = staggered_turn(lo, c.top, { dep: st.dep }) + shift;
|
|
29917
|
+
turn = Math.min(Math.max(turn, lo + 4), c.top - 4);
|
|
29918
|
+
return [
|
|
29919
|
+
[s[0], turn],
|
|
29920
|
+
[c.lane, turn],
|
|
29921
|
+
[c.lane, c.z],
|
|
29922
|
+
[t[0], c.z]
|
|
29923
|
+
];
|
|
29924
|
+
}
|
|
29925
|
+
let hi = Math.min(t[1], box_t.y1);
|
|
29926
|
+
let mid = staggered_turn(lo, hi, st) + shift;
|
|
29927
|
+
mid = Math.min(Math.max(mid, lo + 4), hi - 4);
|
|
29663
29928
|
return [[s[0], mid], [t[0], mid]];
|
|
29664
29929
|
}
|
|
29665
29930
|
let out = 16 + Math.abs(shift);
|
|
@@ -29753,8 +30018,12 @@ function heap_pop(h) {
|
|
|
29753
30018
|
/************************************************************
|
|
29754
30019
|
* The shortest orthogonal line from `a` to `z` that enters none
|
|
29755
30020
|
* of `boxes` (already expanded by the clearance), a turn costing
|
|
29756
|
-
* ROUTE_BEND. The line leaves `a`
|
|
29757
|
-
*
|
|
30021
|
+
* ROUTE_BEND. The line leaves `a` SIDEWAYS and reaches `z`
|
|
30022
|
+
* SIDEWAYS: the column straight under a port and the one straight
|
|
30023
|
+
* over it belong to the forward edges that share that port, which
|
|
30024
|
+
* run along them to their staggered turns -- a route going down
|
|
30025
|
+
* that column lay on top of them. So a routed line shares only
|
|
30026
|
+
* the stub between the port and `a` (or `z`).
|
|
29758
30027
|
*
|
|
29759
30028
|
* The grid is SPARSE: only the lines of the boxes' borders and
|
|
29760
30029
|
* of the two ends, which is all an orthogonal shortest path ever
|
|
@@ -29820,7 +30089,8 @@ function orth_search(a, z, boxes) {
|
|
|
29820
30089
|
let k = state >> 2;
|
|
29821
30090
|
let dir = state & 3;
|
|
29822
30091
|
if (k === goal) {
|
|
29823
|
-
|
|
30092
|
+
if (dir >= 2) continue;
|
|
30093
|
+
let total = cost + 40;
|
|
29824
30094
|
if (total < found_cost) {
|
|
29825
30095
|
found_cost = total;
|
|
29826
30096
|
found = state;
|
|
@@ -29828,6 +30098,7 @@ function orth_search(a, z, boxes) {
|
|
|
29828
30098
|
continue;
|
|
29829
30099
|
}
|
|
29830
30100
|
for (let [nk, nd, len] of moves(k)) {
|
|
30101
|
+
if (k === start && nd >= 2) continue;
|
|
29831
30102
|
let c = cost + len + (nd === dir ? 0 : 40);
|
|
29832
30103
|
let ns = nk * 4 + nd;
|
|
29833
30104
|
if (c < best[ns]) {
|
|
@@ -29868,10 +30139,11 @@ function orth_search(a, z, boxes) {
|
|
|
29868
30139
|
* coincide. Nearby cards first; all of them if that finds no way;
|
|
29869
30140
|
* the simple elbow if nothing does.
|
|
29870
30141
|
************************************************************/
|
|
29871
|
-
function elbow_route(s, t, box_s, box_t, lane, vertical, boxes) {
|
|
30142
|
+
function elbow_route(s, t, box_s, box_t, lane, vertical, boxes, stagger) {
|
|
29872
30143
|
let others = boxes || [];
|
|
29873
|
-
if (!vertical) return elbow_route(swap(s), swap(t), swap_box(box_s), swap_box(box_t), lane, true, others.map(swap_box)).map(swap);
|
|
29874
|
-
|
|
30144
|
+
if (!vertical) return elbow_route(swap(s), swap(t), swap_box(box_s), swap_box(box_t), lane, true, others.map(swap_box), stagger).map(swap);
|
|
30145
|
+
if (stagger && stagger.comb) return elbow_points(s, t, box_s, box_t, lane, true, stagger);
|
|
30146
|
+
let simple = elbow_points(s, t, box_s, box_t, lane, true, stagger);
|
|
29875
30147
|
if (!elbow_path_hits([
|
|
29876
30148
|
s,
|
|
29877
30149
|
...simple,
|
|
@@ -59272,8 +59544,9 @@ var TreedbTreeLayout = class extends BaseLayout {
|
|
|
59272
59544
|
* dragged card, a fold or a layout needs nothing else. `-v` runs
|
|
59273
59545
|
* between rows (top to bottom), `-h` between columns. An edge that
|
|
59274
59546
|
* does not run forward goes round the two cards, the edges joining
|
|
59275
|
-
* the same two cards take lanes,
|
|
59276
|
-
*
|
|
59547
|
+
* the same two cards take lanes, the edges sharing an end turn at
|
|
59548
|
+
* staggered heights, and a line that would cross any other card is
|
|
59549
|
+
* routed round it (treedb_elbow.js).
|
|
59277
59550
|
************************************************************/
|
|
59278
59551
|
var ELBOW_RADIUS = 6;
|
|
59279
59552
|
function elbow_box(node) {
|
|
@@ -59325,10 +59598,55 @@ function elbow_lane_of(edge) {
|
|
|
59325
59598
|
return 0;
|
|
59326
59599
|
}
|
|
59327
59600
|
}
|
|
59601
|
+
function elbow_stagger_of(edge, vertical) {
|
|
59602
|
+
let graph = edge.context && edge.context.graph;
|
|
59603
|
+
let element = edge.context && edge.context.element;
|
|
59604
|
+
let s = edge.sourceNode && edge.sourceNode.id;
|
|
59605
|
+
let t = edge.targetNode && edge.targetNode.id;
|
|
59606
|
+
if (!graph || !element || s === void 0 || t === void 0) return null;
|
|
59607
|
+
let across = vertical ? 0 : 1;
|
|
59608
|
+
let along = vertical ? 1 : 0;
|
|
59609
|
+
let pos = (id) => graph.getElementPosition(id);
|
|
59610
|
+
let port_of = (node_id, key) => {
|
|
59611
|
+
let node = element.getElement(node_id);
|
|
59612
|
+
let ports = node && typeof node.getPorts === "function" ? node.getPorts() : {};
|
|
59613
|
+
let port = key ? ports[key] : null;
|
|
59614
|
+
return port ? port.getPosition() : pos(node_id);
|
|
59615
|
+
};
|
|
59616
|
+
try {
|
|
59617
|
+
let ps = pos(s);
|
|
59618
|
+
let pt = pos(t);
|
|
59619
|
+
let leaving = graph.getRelatedEdgesData(s, "out").filter((d) => d.source === s && pos(d.target)[along] > ps[along]);
|
|
59620
|
+
let combs = elbow_combs(leaving.map((d) => ({
|
|
59621
|
+
id: d.id,
|
|
59622
|
+
box: elbow_box(element.getElement(d.target))
|
|
59623
|
+
})), vertical);
|
|
59624
|
+
let dep = leaving.map((d) => {
|
|
59625
|
+
let comb = combs.get(d.id);
|
|
59626
|
+
let far = comb ? comb.lane : pos(d.target)[across];
|
|
59627
|
+
return {
|
|
59628
|
+
id: d.id,
|
|
59629
|
+
span: Math.abs(far - port_of(s, d.style && d.style.sourcePort)[across])
|
|
59630
|
+
};
|
|
59631
|
+
});
|
|
59632
|
+
let arr = graph.getRelatedEdgesData(t, "in").filter((d) => d.target === t && pos(d.source)[along] < pt[along]).map((d) => ({
|
|
59633
|
+
id: d.id,
|
|
59634
|
+
span: Math.abs(port_of(d.source, d.style && d.style.sourcePort)[across] - pt[across])
|
|
59635
|
+
}));
|
|
59636
|
+
return {
|
|
59637
|
+
dep: elbow_rank(dep, edge.id),
|
|
59638
|
+
arr: elbow_rank(arr, edge.id),
|
|
59639
|
+
comb: combs.get(edge.id) || null
|
|
59640
|
+
};
|
|
59641
|
+
} catch (e) {
|
|
59642
|
+
log_error(`elbow edge ${edge.id}: cannot read the edges sharing its ends: ${e}`);
|
|
59643
|
+
return null;
|
|
59644
|
+
}
|
|
59645
|
+
}
|
|
59328
59646
|
var TreedbElbowV = class extends Polyline {
|
|
59329
59647
|
getControlPoints(attributes) {
|
|
59330
59648
|
let [s, t] = this.getEndpoints(attributes, false);
|
|
59331
|
-
return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode), elbow_lane_of(this), true, elbow_obstacles(this));
|
|
59649
|
+
return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode), elbow_lane_of(this), true, elbow_obstacles(this), elbow_stagger_of(this, true));
|
|
59332
59650
|
}
|
|
59333
59651
|
getKeyPath(attributes) {
|
|
59334
59652
|
return super.getKeyPath(Object.assign({}, attributes, { radius: attributes.radius || ELBOW_RADIUS }));
|
|
@@ -59337,7 +59655,7 @@ var TreedbElbowV = class extends Polyline {
|
|
|
59337
59655
|
var TreedbElbowH = class extends Polyline {
|
|
59338
59656
|
getControlPoints(attributes) {
|
|
59339
59657
|
let [s, t] = this.getEndpoints(attributes, false);
|
|
59340
|
-
return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode), elbow_lane_of(this), false, elbow_obstacles(this));
|
|
59658
|
+
return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode), elbow_lane_of(this), false, elbow_obstacles(this), elbow_stagger_of(this, false));
|
|
59341
59659
|
}
|
|
59342
59660
|
getKeyPath(attributes) {
|
|
59343
59661
|
return super.getKeyPath(Object.assign({}, attributes, { radius: attributes.radius || ELBOW_RADIUS }));
|
package/package.json
CHANGED
package/src/c_g6_nodes_tree.js
CHANGED
|
@@ -133,7 +133,7 @@ import {
|
|
|
133
133
|
fold_root_group_key,
|
|
134
134
|
} from "./treedb_fold_model.js";
|
|
135
135
|
import {layout_tree, layout_radial, layout_compact} from "./treedb_layout.js";
|
|
136
|
-
import {elbow_lane, elbow_route} from "./treedb_elbow.js";
|
|
136
|
+
import {elbow_lane, elbow_rank, elbow_route, elbow_combs} from "./treedb_elbow.js";
|
|
137
137
|
|
|
138
138
|
import {
|
|
139
139
|
BaseLayout,
|
|
@@ -4224,8 +4224,9 @@ class TreedbTreeLayout extends BaseLayout
|
|
|
4224
4224
|
* dragged card, a fold or a layout needs nothing else. `-v` runs
|
|
4225
4225
|
* between rows (top to bottom), `-h` between columns. An edge that
|
|
4226
4226
|
* does not run forward goes round the two cards, the edges joining
|
|
4227
|
-
* the same two cards take lanes,
|
|
4228
|
-
*
|
|
4227
|
+
* the same two cards take lanes, the edges sharing an end turn at
|
|
4228
|
+
* staggered heights, and a line that would cross any other card is
|
|
4229
|
+
* routed round it (treedb_elbow.js).
|
|
4229
4230
|
************************************************************/
|
|
4230
4231
|
const ELBOW_RADIUS = 6;
|
|
4231
4232
|
|
|
@@ -4297,12 +4298,73 @@ function elbow_lane_of(edge)
|
|
|
4297
4298
|
}
|
|
4298
4299
|
}
|
|
4299
4300
|
|
|
4301
|
+
/* Where `edge` stands among the forward edges sharing one of its
|
|
4302
|
+
* ends, for the stagger (treedb_elbow.js): the ones leaving its
|
|
4303
|
+
* source card, and the ones reaching its target card. How far each
|
|
4304
|
+
* runs ACROSS is measured from the real port it leaves by -- the
|
|
4305
|
+
* hooks of one card sit at different places along its edge. */
|
|
4306
|
+
function elbow_stagger_of(edge, vertical)
|
|
4307
|
+
{
|
|
4308
|
+
let graph = edge.context && edge.context.graph;
|
|
4309
|
+
let element = edge.context && edge.context.element;
|
|
4310
|
+
let s = edge.sourceNode && edge.sourceNode.id;
|
|
4311
|
+
let t = edge.targetNode && edge.targetNode.id;
|
|
4312
|
+
if(!graph || !element || s === undefined || t === undefined) {
|
|
4313
|
+
return null;
|
|
4314
|
+
}
|
|
4315
|
+
let across = vertical? 0 : 1;
|
|
4316
|
+
let along = vertical? 1 : 0;
|
|
4317
|
+
let pos = (id) => graph.getElementPosition(id);
|
|
4318
|
+
let port_of = (node_id, key) => {
|
|
4319
|
+
let node = element.getElement(node_id);
|
|
4320
|
+
let ports = (node && typeof node.getPorts === 'function')? node.getPorts() : {};
|
|
4321
|
+
let port = key? ports[key] : null;
|
|
4322
|
+
return port? port.getPosition() : pos(node_id);
|
|
4323
|
+
};
|
|
4324
|
+
try {
|
|
4325
|
+
let ps = pos(s);
|
|
4326
|
+
let pt = pos(t);
|
|
4327
|
+
let leaving = graph.getRelatedEdgesData(s, 'out')
|
|
4328
|
+
.filter((d) => d.source === s && pos(d.target)[along] > ps[along]);
|
|
4329
|
+
/* The cards they reach, for the combs of a stack; a comb's
|
|
4330
|
+
* run ends at its lane, so that is what its span measures. */
|
|
4331
|
+
let combs = elbow_combs(leaving.map((d) => ({
|
|
4332
|
+
id: d.id,
|
|
4333
|
+
box: elbow_box(element.getElement(d.target)),
|
|
4334
|
+
})), vertical);
|
|
4335
|
+
let dep = leaving.map((d) => {
|
|
4336
|
+
let comb = combs.get(d.id);
|
|
4337
|
+
let far = comb? comb.lane : pos(d.target)[across];
|
|
4338
|
+
return {
|
|
4339
|
+
id: d.id,
|
|
4340
|
+
span: Math.abs(far - port_of(s, d.style && d.style.sourcePort)[across]),
|
|
4341
|
+
};
|
|
4342
|
+
});
|
|
4343
|
+
let arr = graph.getRelatedEdgesData(t, 'in')
|
|
4344
|
+
.filter((d) => d.target === t && pos(d.source)[along] < pt[along])
|
|
4345
|
+
.map((d) => ({
|
|
4346
|
+
id: d.id,
|
|
4347
|
+
span: Math.abs(port_of(d.source, d.style && d.style.sourcePort)[across] -
|
|
4348
|
+
pt[across]),
|
|
4349
|
+
}));
|
|
4350
|
+
return {
|
|
4351
|
+
dep: elbow_rank(dep, edge.id),
|
|
4352
|
+
arr: elbow_rank(arr, edge.id),
|
|
4353
|
+
comb: combs.get(edge.id) || null,
|
|
4354
|
+
};
|
|
4355
|
+
} catch(e) {
|
|
4356
|
+
log_error(`elbow edge ${edge.id}: cannot read the edges sharing its ends: ${e}`);
|
|
4357
|
+
return null;
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
|
|
4300
4361
|
class TreedbElbowV extends Polyline
|
|
4301
4362
|
{
|
|
4302
4363
|
getControlPoints(attributes) {
|
|
4303
4364
|
let [s, t] = this.getEndpoints(attributes, false);
|
|
4304
4365
|
return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode),
|
|
4305
|
-
elbow_lane_of(this), true, elbow_obstacles(this)
|
|
4366
|
+
elbow_lane_of(this), true, elbow_obstacles(this),
|
|
4367
|
+
elbow_stagger_of(this, true));
|
|
4306
4368
|
}
|
|
4307
4369
|
|
|
4308
4370
|
getKeyPath(attributes) {
|
|
@@ -4316,7 +4378,8 @@ class TreedbElbowH extends Polyline
|
|
|
4316
4378
|
getControlPoints(attributes) {
|
|
4317
4379
|
let [s, t] = this.getEndpoints(attributes, false);
|
|
4318
4380
|
return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode),
|
|
4319
|
-
elbow_lane_of(this), false, elbow_obstacles(this)
|
|
4381
|
+
elbow_lane_of(this), false, elbow_obstacles(this),
|
|
4382
|
+
elbow_stagger_of(this, false));
|
|
4320
4383
|
}
|
|
4321
4384
|
|
|
4322
4385
|
getKeyPath(attributes) {
|