@yuneta/gobj-ui 7.23.155 → 7.23.157

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.155",
3
+ "version": "7.23.157",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -132,11 +132,8 @@ import {
132
132
  fold_split_group_key,
133
133
  fold_root_group_key,
134
134
  } from "./treedb_fold_model.js";
135
- import {layout_tree, layout_radial, layout_compact} from "./treedb_layout.js";
136
- import {
137
- elbow_lane, elbow_rank, elbow_route, elbow_combs, curve_hits, rounded_path, CURVE_RADIUS,
138
- ELBOW_STEP,
139
- } from "./treedb_elbow.js";
135
+ import {layout_tree, layout_radial} from "./treedb_layout.js";
136
+ import {elbow_lane, elbow_route} from "./treedb_elbow.js";
140
137
 
141
138
  import {
142
139
  BaseLayout,
@@ -151,8 +148,6 @@ import {
151
148
  Toolbar,
152
149
  register,
153
150
  Polyline,
154
- Cubic,
155
- CubicHorizontal,
156
151
  } from '@antv/g6';
157
152
 
158
153
  import {Circle as CircleGeometry, Rect as RectGeometry} from '@antv/g';
@@ -357,16 +352,6 @@ const _layouts = {
357
352
  nodesep: 18,
358
353
  ranksep: 90,
359
354
  },
360
- /* The same tree packed by CONTOUR (Moen, as mxGraph drew it): a
361
- * closed branch sits beside an open one at the depth they share,
362
- * instead of beside the whole block of the open one. Same rows
363
- * and order as `treedb-tree` (treedb_layout.js). */
364
- "compact-tree": {
365
- type: 'treedb-compact',
366
- direction: 'TB',
367
- nodesep: 18,
368
- ranksep: 90,
369
- },
370
355
  "dagre": {
371
356
  type: 'dagre',
372
357
  rankdir: 'LR',
@@ -944,11 +929,8 @@ function register_layouts(gobj)
944
929
  _g6_extensions_registered = true;
945
930
  register(ExtensionCategory.LAYOUT, 'manual', ManualLayout);
946
931
  register(ExtensionCategory.LAYOUT, 'treedb-tree', TreedbTreeLayout);
947
- register(ExtensionCategory.LAYOUT, 'treedb-compact', TreedbCompactLayout);
948
932
  register(ExtensionCategory.EDGE, 'treedb-elbow-v', TreedbElbowV);
949
933
  register(ExtensionCategory.EDGE, 'treedb-elbow-h', TreedbElbowH);
950
- register(ExtensionCategory.EDGE, 'treedb-curve-v', TreedbCurveV);
951
- register(ExtensionCategory.EDGE, 'treedb-curve-h', TreedbCurveH);
952
934
  register(ExtensionCategory.LAYOUT, 'treedb-radial', TreedbRadialLayout);
953
935
  register(ExtensionCategory.NODE, 'light', LightNode);
954
936
  register(ExtensionCategory.NODE, 'treedb-card', TreedbCard);
@@ -2049,20 +2031,16 @@ function layout_direction(gobj)
2049
2031
  return str_in_list(LR_LAYOUTS, gobj.priv.layout)? "LR" : "TB";
2050
2032
  }
2051
2033
 
2052
- /* An elbow when the reader asked for one, a curve otherwise -- ours
2053
- * where the layout has rows, which keeps off the cards; G6's plain
2054
- * cubic on a layout with no rows to go round by. */
2034
+ /* A curve, or an elbow when the reader asked for one and the layout
2035
+ * has rows to run it between. */
2055
2036
  function edge_type_for(gobj)
2056
2037
  {
2057
2038
  let lr = (layout_direction(gobj) === "LR");
2058
2039
  let rowless = gobj_read_attr(gobj, "rowless_layouts") || [];
2059
- let rows = !str_in_list(rowless, gobj.priv.layout);
2060
- if(rows && gobj_read_str_attr(gobj, "edge_shape") === "elbow") {
2040
+ if(gobj_read_str_attr(gobj, "edge_shape") === "elbow" &&
2041
+ !str_in_list(rowless, gobj.priv.layout)) {
2061
2042
  return lr? "treedb-elbow-h" : "treedb-elbow-v";
2062
2043
  }
2063
- if(rows) {
2064
- return lr? "treedb-curve-h" : "treedb-curve-v";
2065
- }
2066
2044
  return lr? "cubic-horizontal" : "cubic";
2067
2045
  }
2068
2046
 
@@ -4235,9 +4213,8 @@ class TreedbTreeLayout extends BaseLayout
4235
4213
  * dragged card, a fold or a layout needs nothing else. `-v` runs
4236
4214
  * between rows (top to bottom), `-h` between columns. An edge that
4237
4215
  * does not run forward goes round the two cards, the edges joining
4238
- * the same two cards take lanes, the edges sharing an end turn at
4239
- * staggered heights, and a line that would cross any other card is
4240
- * routed round it (treedb_elbow.js).
4216
+ * the same two cards take lanes, and a line that would cross any
4217
+ * other card is routed round it (treedb_elbow.js).
4241
4218
  ************************************************************/
4242
4219
  const ELBOW_RADIUS = 6;
4243
4220
 
@@ -4309,73 +4286,12 @@ function elbow_lane_of(edge)
4309
4286
  }
4310
4287
  }
4311
4288
 
4312
- /* Where `edge` stands among the forward edges sharing one of its
4313
- * ends, for the stagger (treedb_elbow.js): the ones leaving its
4314
- * source card, and the ones reaching its target card. How far each
4315
- * runs ACROSS is measured from the real port it leaves by -- the
4316
- * hooks of one card sit at different places along its edge. */
4317
- function elbow_stagger_of(edge, vertical)
4318
- {
4319
- let graph = edge.context && edge.context.graph;
4320
- let element = edge.context && edge.context.element;
4321
- let s = edge.sourceNode && edge.sourceNode.id;
4322
- let t = edge.targetNode && edge.targetNode.id;
4323
- if(!graph || !element || s === undefined || t === undefined) {
4324
- return null;
4325
- }
4326
- let across = vertical? 0 : 1;
4327
- let along = vertical? 1 : 0;
4328
- let pos = (id) => graph.getElementPosition(id);
4329
- let port_of = (node_id, key) => {
4330
- let node = element.getElement(node_id);
4331
- let ports = (node && typeof node.getPorts === 'function')? node.getPorts() : {};
4332
- let port = key? ports[key] : null;
4333
- return port? port.getPosition() : pos(node_id);
4334
- };
4335
- try {
4336
- let ps = pos(s);
4337
- let pt = pos(t);
4338
- let leaving = graph.getRelatedEdgesData(s, 'out')
4339
- .filter((d) => d.source === s && pos(d.target)[along] > ps[along]);
4340
- /* The cards they reach, for the combs of a stack; a comb's
4341
- * run ends at its lane, so that is what its span measures. */
4342
- let combs = elbow_combs(leaving.map((d) => ({
4343
- id: d.id,
4344
- box: elbow_box(element.getElement(d.target)),
4345
- })), vertical);
4346
- let dep = leaving.map((d) => {
4347
- let comb = combs.get(d.id);
4348
- let far = comb? comb.lane : pos(d.target)[across];
4349
- return {
4350
- id: d.id,
4351
- span: Math.abs(far - port_of(s, d.style && d.style.sourcePort)[across]),
4352
- };
4353
- });
4354
- let arr = graph.getRelatedEdgesData(t, 'in')
4355
- .filter((d) => d.target === t && pos(d.source)[along] < pt[along])
4356
- .map((d) => ({
4357
- id: d.id,
4358
- span: Math.abs(port_of(d.source, d.style && d.style.sourcePort)[across] -
4359
- pt[across]),
4360
- }));
4361
- return {
4362
- dep: elbow_rank(dep, edge.id),
4363
- arr: elbow_rank(arr, edge.id),
4364
- comb: combs.get(edge.id) || null,
4365
- };
4366
- } catch(e) {
4367
- log_error(`elbow edge ${edge.id}: cannot read the edges sharing its ends: ${e}`);
4368
- return null;
4369
- }
4370
- }
4371
-
4372
4289
  class TreedbElbowV extends Polyline
4373
4290
  {
4374
4291
  getControlPoints(attributes) {
4375
4292
  let [s, t] = this.getEndpoints(attributes, false);
4376
4293
  return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode),
4377
- elbow_lane_of(this), true, elbow_obstacles(this),
4378
- elbow_stagger_of(this, true));
4294
+ elbow_lane_of(this), true, elbow_obstacles(this));
4379
4295
  }
4380
4296
 
4381
4297
  getKeyPath(attributes) {
@@ -4389,8 +4305,7 @@ class TreedbElbowH extends Polyline
4389
4305
  getControlPoints(attributes) {
4390
4306
  let [s, t] = this.getEndpoints(attributes, false);
4391
4307
  return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode),
4392
- elbow_lane_of(this), false, elbow_obstacles(this),
4393
- elbow_stagger_of(this, false));
4308
+ elbow_lane_of(this), false, elbow_obstacles(this));
4394
4309
  }
4395
4310
 
4396
4311
  getKeyPath(attributes) {
@@ -4399,59 +4314,6 @@ class TreedbElbowH extends Polyline
4399
4314
  }
4400
4315
  }
4401
4316
 
4402
- /************************************************************
4403
- * A CURVED edge that keeps off the cards. G6's cubic, as before,
4404
- * unless that very curve -- sampled, not guessed from the
4405
- * rectangle round it -- would cross a card other than its own two,
4406
- * or when it does not run forward and so would cross its own:
4407
- * the card above a lower row of a stack, a row between a parent
4408
- * and a far child. Then it goes the way an elbow would (the comb,
4409
- * the detour, the route: the same lanes and staggered turns) with
4410
- * round corners, so it still reads as a curve. `-v` for rows
4411
- * stacked top to bottom, `-h` for columns.
4412
- ************************************************************/
4413
- function curve_key_path(edge, attributes, vertical, plain)
4414
- {
4415
- let [s, t] = edge.getEndpoints(attributes, false);
4416
- let along = vertical? 1 : 0;
4417
- let box_s = elbow_box(edge.sourceNode);
4418
- let box_t = elbow_box(edge.targetNode);
4419
- let boxes = elbow_obstacles(edge);
4420
- /* An edge that does not run forward -- one of every reciprocal
4421
- * pair, an edge within one row -- runs through its OWN two cards
4422
- * as a cubic, which curve_hits does not look at: it goes round
4423
- * them, as its elbow does. */
4424
- let forward = (t[along] - s[along] > 2 * ELBOW_STEP);
4425
- if(forward && !curve_hits(plain, boxes, box_s, box_t)) {
4426
- return plain;
4427
- }
4428
- let pts = elbow_route(s, t, box_s, box_t, elbow_lane_of(edge), vertical, boxes,
4429
- elbow_stagger_of(edge, vertical));
4430
- return rounded_path([s, ...pts, t], CURVE_RADIUS);
4431
- }
4432
-
4433
- class TreedbCurveV extends Cubic
4434
- {
4435
- getKeyPath(attributes) {
4436
- return curve_key_path(this, attributes, true, super.getKeyPath(attributes));
4437
- }
4438
- }
4439
-
4440
- class TreedbCurveH extends CubicHorizontal
4441
- {
4442
- getKeyPath(attributes) {
4443
- return curve_key_path(this, attributes, false, super.getKeyPath(attributes));
4444
- }
4445
- }
4446
-
4447
- class TreedbCompactLayout extends BaseLayout
4448
- {
4449
- async execute(data, options) {
4450
- let input = treedb_layout_input(data);
4451
- return treedb_layout_output(layout_compact(input.nodes, input.edges, options));
4452
- }
4453
- }
4454
-
4455
4317
  class TreedbRadialLayout extends BaseLayout
4456
4318
  {
4457
4319
  async execute(data, options) {
@@ -555,8 +555,6 @@ function option_label(name)
555
555
  return t("manual");
556
556
  case "treedb-tree":
557
557
  return t("treedb-tree");
558
- case "compact-tree":
559
- return t("compact-tree");
560
558
  case "radial":
561
559
  return t("radial");
562
560
  case "dagre":
@@ -25,25 +25,6 @@
25
25
  * the order the edges were made, so a new edge never moves the
26
26
  * ones already drawn.
27
27
  *
28
- * - Several forward edges sharing one END: the children of one
29
- * card, or the parents of one card (all its fkeys enter by one
30
- * point). They are STAGGERED: each turns at its own height in
31
- * the channel, so their runs lie side by side instead of on top
32
- * of each other. Leaving a card, the one that runs farthest
33
- * turns highest; reaching a card, the one that comes from
34
- * farthest turns lowest -- the two orders in which the lines of
35
- * one end nest without crossing.
36
- *
37
- * - A card in a lower row of a STACK (treedb_layout.js lays a
38
- * run of leaf children out as two columns with a corridor
39
- * between them): the card above it stands in the way of the
40
- * channel, so its edge runs down the corridor in a lane of
41
- * its own -- a COMB -- and turns into the gap above its card.
42
- *
43
- * And for CURVED edges (curve_hits, rounded_path): a curve
44
- * that would cross another card follows the same way an elbow
45
- * would, with round corners, so it reads as a curve.
46
- *
47
28
  * Written for the top-down reading; left to right is the same
48
29
  * geometry with the axes swapped.
49
30
  *
@@ -51,12 +32,9 @@
51
32
  * All Rights Reserved.
52
33
  ***********************************************************************/
53
34
 
54
- import {STACK_GAP, STACK_LANE_PAD, STACK_LANE_STEP, STACK_TRUNK_MIN} from "./treedb_layout.js";
55
-
56
35
  export const ELBOW_STEP = 10; /* between two lanes */
57
36
  export const ELBOW_JETTY = 16; /* straight run out of a port before a detour turns */
58
37
  export const ELBOW_CLEAR = 24; /* how far outside the two cards a detour runs */
59
- export const ELBOW_STAGGER_PAD = 6; /* staggered turns keep this far from the rows */
60
38
 
61
39
  /************************************************************
62
40
  * The lane of `id` among `ids`, the edges joining the same two
@@ -76,24 +54,6 @@ export function elbow_lane(ids, id)
76
54
  return side * Math.ceil(k / 2);
77
55
  }
78
56
 
79
- /************************************************************
80
- * The rank of `id` among `items` ([{id, span}]): the forward
81
- * edges that share one end with it, each with how far it runs
82
- * ACROSS. Farthest first; a tie goes to the edge made first.
83
- * Returns {rank, count}.
84
- ************************************************************/
85
- export function elbow_rank(items, id)
86
- {
87
- let sorted = items.slice().sort((a, b) => {
88
- if(b.span !== a.span) {
89
- return b.span - a.span;
90
- }
91
- return String(a.id).localeCompare(String(b.id), undefined, {numeric: true});
92
- });
93
- let rank = sorted.findIndex((it) => it.id === id);
94
- return {rank: (rank < 0)? 0 : rank, count: sorted.length};
95
- }
96
-
97
57
  function swap(p)
98
58
  {
99
59
  return [p[1], p[0]];
@@ -104,154 +64,6 @@ function swap_box(b)
104
64
  return {x1: b.y1, y1: b.x1, x2: b.y2, y2: b.x2};
105
65
  }
106
66
 
107
- /* Where a forward edge turns between `lo` and `hi`: the middle, or
108
- * its staggered place among the edges sharing one of its ends --
109
- * leaving, the farthest highest; arriving, the farthest lowest. */
110
- function staggered_turn(lo, hi, st)
111
- {
112
- let mid = (lo + hi) / 2;
113
- let group = null;
114
- let k = 0;
115
- if(st.dep && st.dep.count > 1) {
116
- group = st.dep;
117
- k = st.dep.rank;
118
- } else if(st.arr && st.arr.count > 1) {
119
- group = st.arr;
120
- k = st.arr.count - 1 - st.arr.rank;
121
- }
122
- if(group) {
123
- let room = Math.max(0, hi - lo - 2 * ELBOW_STAGGER_PAD);
124
- let step = Math.min(ELBOW_STEP, room / (group.count - 1));
125
- mid = mid - (group.count - 1) * step / 2 + k * step;
126
- }
127
- return mid;
128
- }
129
-
130
- /************************************************************
131
- * The combs of the stacks under one card.
132
- *
133
- * treedb_layout.js lays a run of leaf children out as two columns
134
- * with a corridor between them. A card in the first row is reached
135
- * from the channel like any other; one in a lower row cannot be --
136
- * the card above it stands in the way -- so its edge runs down
137
- * the corridor in a LANE of its own and turns into the gap above
138
- * its card, which it shares only with the other card of its row,
139
- * reached from the other side.
140
- *
141
- * targets [{id, box}]: the forward edges leaving one card,
142
- * each with the box of the card it reaches
143
- * vertical as in elbow_points; false swaps the boxes
144
- *
145
- * Returns Map id -> {lane, z, top}: the lane, the height of the
146
- * gap it turns into, and the top of the stack's first row (where
147
- * the channel over the stack ends). Only for a card that stands
148
- * under another of the group, within a stack gap and lined up
149
- * with it on the corridor side -- what a stack looks like.
150
- *
151
- * Lanes go outermost first, row by row: a line into a higher row
152
- * keeps outside the lines going deeper, and none crosses another.
153
- ************************************************************/
154
- export function elbow_combs(targets, vertical)
155
- {
156
- let list = vertical? targets : targets.map((it) => ({id: it.id, box: swap_box(it.box)}));
157
- let cy = (b) => (b.y1 + b.y2) / 2;
158
- let near = (a, b) => Math.abs(a - b) < 1.5;
159
-
160
- let under = [];
161
- for(let it of list) {
162
- let b = it.box;
163
- let above = null;
164
- for(let o of list) {
165
- let a = o.box;
166
- if(o === it || a.y2 > b.y1 || b.y1 - a.y2 > STACK_GAP) {
167
- continue;
168
- }
169
- if(!(near(a.x2, b.x2) || near(a.x1, b.x1))) {
170
- continue;
171
- }
172
- if(!above || a.y2 > above.y2) {
173
- above = a;
174
- }
175
- }
176
- if(!above) {
177
- continue;
178
- }
179
- /* Its column: lined up on the corridor side, which is the
180
- * right edge of the first column and the left edge of the
181
- * second. Two cards of one width line up on both; then the
182
- * card beside it in its row says. */
183
- let side;
184
- if(near(above.x2, b.x2) && !near(above.x1, b.x1)) {
185
- side = 0;
186
- } else if(near(above.x1, b.x1) && !near(above.x2, b.x2)) {
187
- side = 1;
188
- } else {
189
- let left_of_it = list.some((o) => o !== it && near(cy(o.box), cy(b)) &&
190
- o.box.x2 <= b.x1);
191
- side = left_of_it? 1 : 0;
192
- }
193
- under.push({id: it.id, box: b, above: above, side: side});
194
- }
195
-
196
- /* The corridor of a card: from the first column's edge to the
197
- * second's, read off any row of the stack that has both. */
198
- let corridor = (u) => {
199
- if(u.side === 0) {
200
- let l = u.box.x2;
201
- let col = list.filter((o) => near(o.box.x2, l));
202
- let r = Infinity;
203
- for(let c of col) {
204
- for(let o of list) {
205
- if(o !== c && near(cy(o.box), cy(c.box)) && o.box.x1 >= l - 0.5) {
206
- r = Math.min(r, o.box.x1);
207
- }
208
- }
209
- }
210
- return {l: l, r: isFinite(r)? r : l + STACK_TRUNK_MIN, col: col};
211
- }
212
- let r = u.box.x1;
213
- let col = list.filter((o) => near(o.box.x1, r));
214
- let l = -Infinity;
215
- for(let c of col) {
216
- for(let o of list) {
217
- if(o !== c && near(cy(o.box), cy(c.box)) && o.box.x2 <= r + 0.5) {
218
- l = Math.max(l, o.box.x2);
219
- }
220
- }
221
- }
222
- return {l: isFinite(l)? l : r - STACK_TRUNK_MIN, r: r, col: col};
223
- };
224
-
225
- let groups = new Map();
226
- for(let u of under) {
227
- let c = corridor(u);
228
- u.top = Math.min(...c.col.map((o) => o.box.y1));
229
- let key = `${Math.round(c.l)}|${Math.round(c.r)}`;
230
- if(!groups.has(key)) {
231
- groups.set(key, {l: c.l, r: c.r, left: [], right: []});
232
- }
233
- groups.get(key)[(u.side === 0)? 'left' : 'right'].push(u);
234
- }
235
-
236
- let out = new Map();
237
- for(let g of groups.values()) {
238
- g.left.sort((a, b) => a.box.y1 - b.box.y1);
239
- g.right.sort((a, b) => a.box.y1 - b.box.y1);
240
- let n = g.left.length + g.right.length;
241
- let room = g.r - g.l - 2 * STACK_LANE_PAD;
242
- let step = (n > 1)? Math.max(0, Math.min(STACK_LANE_STEP, room / (n - 1))) : 0;
243
- g.left.forEach((u, i) => {
244
- out.set(u.id, {lane: g.l + STACK_LANE_PAD + i * step,
245
- z: (u.above.y2 + u.box.y1) / 2, top: u.top});
246
- });
247
- g.right.forEach((u, j) => {
248
- out.set(u.id, {lane: g.r - STACK_LANE_PAD - j * step,
249
- z: (u.above.y2 + u.box.y1) / 2, top: u.top});
250
- });
251
- }
252
- return out;
253
- }
254
-
255
67
  /************************************************************
256
68
  * The control points of an elbow from the port `s` to the port
257
69
  * `t` ([x, y] each), knowing the boxes of the two cards
@@ -259,39 +71,21 @@ export function elbow_combs(targets, vertical)
259
71
  *
260
72
  * vertical the rows are stacked (top to bottom); false
261
73
  * when they are side by side (left to right)
262
- * stagger {dep, arr, comb}: the edge's rank among the
263
- * forward edges leaving its source card and among
264
- * those reaching its target card (elbow_rank), and
265
- * its comb when the target is in a lower row of a
266
- * stack (elbow_combs). Absent, the channel is the
267
- * middle.
268
74
  ************************************************************/
269
- export function elbow_points(s, t, box_s, box_t, lane, vertical, stagger)
75
+ export function elbow_points(s, t, box_s, box_t, lane, vertical)
270
76
  {
271
77
  if(!vertical) {
272
- return elbow_points(swap(s), swap(t), swap_box(box_s), swap_box(box_t), lane, true,
273
- stagger).map(swap);
78
+ return elbow_points(swap(s), swap(t), swap_box(box_s), swap_box(box_t), lane, true)
79
+ .map(swap);
274
80
  }
275
81
 
276
82
  let shift = lane * ELBOW_STEP;
277
83
 
278
- /* Forward: the channel half way between the two cards, each
279
- * edge of a shared end at its own height round it, moved by the
280
- * lane, and kept between the two rows. Into a lower row of a
281
- * stack: along the channel to its corridor lane, down the lane,
282
- * and into the gap above its card. */
84
+ /* Forward: the channel half way down, moved by the lane and
85
+ * kept strictly between the two ports. */
283
86
  if(t[1] - s[1] > 2 * ELBOW_STEP) {
284
- let st = stagger || {};
285
- let lo = Math.max(s[1], box_s.y2);
286
- if(st.comb) {
287
- let c = st.comb;
288
- let turn = staggered_turn(lo, c.top, {dep: st.dep}) + shift;
289
- turn = Math.min(Math.max(turn, lo + 4), c.top - 4);
290
- return [[s[0], turn], [c.lane, turn], [c.lane, c.z], [t[0], c.z]];
291
- }
292
- let hi = Math.min(t[1], box_t.y1);
293
- let mid = staggered_turn(lo, hi, st) + shift;
294
- mid = Math.min(Math.max(mid, lo + 4), hi - 4);
87
+ let mid = (s[1] + t[1]) / 2 + shift;
88
+ mid = Math.min(Math.max(mid, s[1] + ELBOW_STEP), t[1] - ELBOW_STEP);
295
89
  return [[s[0], mid], [t[0], mid]];
296
90
  }
297
91
 
@@ -421,12 +215,8 @@ function heap_pop(h)
421
215
  /************************************************************
422
216
  * The shortest orthogonal line from `a` to `z` that enters none
423
217
  * of `boxes` (already expanded by the clearance), a turn costing
424
- * ROUTE_BEND. The line leaves `a` SIDEWAYS and reaches `z`
425
- * SIDEWAYS: the column straight under a port and the one straight
426
- * over it belong to the forward edges that share that port, which
427
- * run along them to their staggered turns -- a route going down
428
- * that column lay on top of them. So a routed line shares only
429
- * the stub between the port and `a` (or `z`).
218
+ * ROUTE_BEND. The line leaves `a` going down and ends at `z`
219
+ * going down, since after `z` it drops into a port.
430
220
  *
431
221
  * The grid is SPARSE: only the lines of the boxes' borders and
432
222
  * of the two ends, which is all an orthogonal shortest path ever
@@ -512,10 +302,7 @@ function orth_search(a, z, boxes)
512
302
  let k = state >> 2;
513
303
  let dir = state & 3;
514
304
  if(k === goal) {
515
- if(dir >= 2) {
516
- continue; /* down the port's own column: not allowed */
517
- }
518
- let total = cost + ROUTE_BEND; /* the turn into the port */
305
+ let total = cost + ((dir === 2)? 0 : ROUTE_BEND);
519
306
  if(total < found_cost) {
520
307
  found_cost = total;
521
308
  found = state;
@@ -523,9 +310,6 @@ function orth_search(a, z, boxes)
523
310
  continue;
524
311
  }
525
312
  for(let [nk, nd, len] of moves(k)) {
526
- if(k === start && nd >= 2) {
527
- continue; /* out of the port sideways, not down its column */
528
- }
529
313
  let c = cost + len + ((nd === dir)? 0 : ROUTE_BEND);
530
314
  let ns = nk * 4 + nd;
531
315
  if(c < best[ns]) {
@@ -576,21 +360,15 @@ function orth_search(a, z, boxes)
576
360
  * coincide. Nearby cards first; all of them if that finds no way;
577
361
  * the simple elbow if nothing does.
578
362
  ************************************************************/
579
- export function elbow_route(s, t, box_s, box_t, lane, vertical, boxes, stagger)
363
+ export function elbow_route(s, t, box_s, box_t, lane, vertical, boxes)
580
364
  {
581
365
  let others = boxes || [];
582
366
  if(!vertical) {
583
367
  return elbow_route(swap(s), swap(t), swap_box(box_s), swap_box(box_t), lane, true,
584
- others.map(swap_box), stagger).map(swap);
368
+ others.map(swap_box)).map(swap);
585
369
  }
586
370
 
587
- /* A comb runs where the layout left room for it: its corridor
588
- * and its gap are empty by construction. */
589
- if(stagger && stagger.comb) {
590
- return elbow_points(s, t, box_s, box_t, lane, true, stagger);
591
- }
592
-
593
- let simple = elbow_points(s, t, box_s, box_t, lane, true, stagger);
371
+ let simple = elbow_points(s, t, box_s, box_t, lane, true);
594
372
  if(!elbow_path_hits([s, ...simple, t], others, box_s, box_t)) {
595
373
  return simple;
596
374
  }
@@ -613,112 +391,3 @@ export function elbow_route(s, t, box_s, box_t, lane, vertical, boxes, stagger)
613
391
  }
614
392
  return route || simple;
615
393
  }
616
-
617
- /*----------------------------------------------------------------*
618
- * CURVED edges that would cross a card
619
- *----------------------------------------------------------------*/
620
- export const CURVE_RADIUS = 24; /* the corners of a curve that goes round */
621
- export const CURVE_STEPS = 16; /* samples of each curved stretch */
622
-
623
- /* Points along a G6 path: the ends of its runs and CURVE_STEPS
624
- * samples of each quadratic or cubic stretch. */
625
- function path_points(path)
626
- {
627
- let pts = [];
628
- let cur = null;
629
- for(let c of path) {
630
- if(c[0] === 'M' || c[0] === 'L') {
631
- cur = [c[1], c[2]];
632
- pts.push(cur);
633
- } else if(c[0] === 'C' && cur) {
634
- let [x0, y0] = cur;
635
- for(let k = 1; k <= CURVE_STEPS; k++) {
636
- let u = k / CURVE_STEPS;
637
- let v = 1 - u;
638
- pts.push([
639
- v * v * v * x0 + 3 * v * v * u * c[1] + 3 * v * u * u * c[3] + u * u * u * c[5],
640
- v * v * v * y0 + 3 * v * v * u * c[2] + 3 * v * u * u * c[4] + u * u * u * c[6],
641
- ]);
642
- }
643
- cur = [c[5], c[6]];
644
- } else if(c[0] === 'Q' && cur) {
645
- let [x0, y0] = cur;
646
- for(let k = 1; k <= CURVE_STEPS; k++) {
647
- let u = k / CURVE_STEPS;
648
- let v = 1 - u;
649
- pts.push([
650
- v * v * x0 + 2 * v * u * c[1] + u * u * c[3],
651
- v * v * y0 + 2 * v * u * c[2] + u * u * c[4],
652
- ]);
653
- }
654
- cur = [c[3], c[4]];
655
- }
656
- }
657
- return pts;
658
- }
659
-
660
- /************************************************************
661
- * Does the G6 path `path` of a curved edge cross a card other than
662
- * its own two? Measured on the curve itself -- the path G6 would
663
- * draw, sampled -- and not on the rectangle round it, which took
664
- * every card the curve merely passed near: the ports of a row
665
- * stick well into the space above it. Its own two cards are left
666
- * out: the curve starts and ends on their ports.
667
- ************************************************************/
668
- export function curve_hits(path, boxes, box_s, box_t)
669
- {
670
- let pts = path_points(path);
671
- if(pts.length < 2) {
672
- return false;
673
- }
674
- let bb = {x1: Infinity, y1: Infinity, x2: -Infinity, y2: -Infinity};
675
- for(let p of pts) {
676
- bb.x1 = Math.min(bb.x1, p[0]);
677
- bb.y1 = Math.min(bb.y1, p[1]);
678
- bb.x2 = Math.max(bb.x2, p[0]);
679
- bb.y2 = Math.max(bb.y2, p[1]);
680
- }
681
- for(let b of (boxes || [])) {
682
- if(same_box(b, box_s) || same_box(b, box_t) || !box_overlaps(b, box_expand(bb, 1))) {
683
- continue;
684
- }
685
- let inner = box_expand(b, -1);
686
- for(let k = 0; k + 1 < pts.length; k++) {
687
- if(segment_hits(pts[k], pts[k + 1], inner)) {
688
- return true;
689
- }
690
- }
691
- }
692
- return false;
693
- }
694
-
695
- /************************************************************
696
- * A G6 path (['M'|'L'|'Q', ...]) along `points` with every corner
697
- * rounded -- by `radius`, or by half the shorter of its two
698
- * segments, so a short run is never overshot. The rounding is the
699
- * quadratic G6's own polyline uses.
700
- ************************************************************/
701
- export function rounded_path(points, radius)
702
- {
703
- let path = [['M', points[0][0], points[0][1]]];
704
- for(let i = 1; i + 1 < points.length; i++) {
705
- let a = points[i - 1];
706
- let m = points[i];
707
- let b = points[i + 1];
708
- let len_in = Math.hypot(m[0] - a[0], m[1] - a[1]);
709
- let len_out = Math.hypot(b[0] - m[0], b[1] - m[1]);
710
- let r = Math.min(radius, len_in / 2, len_out / 2);
711
- let collinear = Math.abs((m[0] - a[0]) * (b[1] - m[1]) - (m[1] - a[1]) * (b[0] - m[0])) < 1e-9;
712
- if(r <= 0 || collinear) {
713
- path.push(['L', m[0], m[1]]);
714
- continue;
715
- }
716
- let p1 = [m[0] - (m[0] - a[0]) / len_in * r, m[1] - (m[1] - a[1]) / len_in * r];
717
- let p2 = [m[0] + (b[0] - m[0]) / len_out * r, m[1] + (b[1] - m[1]) / len_out * r];
718
- path.push(['L', p1[0], p1[1]]);
719
- path.push(['Q', m[0], m[1], p2[0], p2[1]]);
720
- }
721
- let last = points[points.length - 1];
722
- path.push(['L', last[0], last[1]]);
723
- return path;
724
- }