@yuneta/gobj-ui 7.23.147 → 7.23.149

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 CHANGED
@@ -1387,8 +1387,8 @@ G6 5.1 registers these layouts, and this is how each meets that shape:
1387
1387
  | `circular`, `concentric`, `grid`, `mds`, `random` | rings, rings by degree, a grid, projection, noise | none knows a parent from a child |
1388
1388
  | `combo-combined`, `fishbone` | combos / cause-effect | not this data |
1389
1389
 
1390
- So two of our own, in `treedb_layout.js` (pure, tested), registered as G6
1391
- layouts by two thin adapters in `c_g6_nodes_tree.js`:
1390
+ So three of our own, in `treedb_layout.js` (pure, tested), registered as G6
1391
+ layouts by three thin adapters in `c_g6_nodes_tree.js`:
1392
1392
 
1393
1393
  - **`treedb-tree`** — the classic tidy tree, **top to bottom**. A row per
1394
1394
  depth as tall as its tallest card, a node centred over the block of its
@@ -1402,6 +1402,18 @@ layouts by two thin adapters in `c_g6_nodes_tree.js`:
1402
1402
  keeps the other reading for a host that wants it). The outline that shipped
1403
1403
  beside it (`treedb-outline`, one row per node) was removed in `7.23.75`: a
1404
1404
  list that indents is a JSON viewer, and this library already has one.
1405
+ - **`compact-tree`** (`treedb-compact`, `7.23.148`) — the same tree packed by
1406
+ **contour** instead of by block. The tidy tree gives each subtree its whole
1407
+ block, so a hall opened with twenty-four devices pushes the siblings of its
1408
+ ancestors apart at depths where nothing of theirs touches; here every
1409
+ sibling slides against the outline of the ones before it, and a closed
1410
+ branch sits beside an open one at the depth they share. Same rows and order
1411
+ as `treedb-tree`, so switching moves cards sideways and never reorders them.
1412
+ One region open with a 24-device hall is 70% of the tidy width on a treedb
1413
+ shaped like a real one; a uniform tree is the same width. The contour
1414
+ arithmetic is Moen's (1990) as mxGraph wrote it in `mxCompactTreeLayout`
1415
+ (JGraph Ltd, Apache-2.0), read in maxGraph — a port, not a dependency,
1416
+ because maxGraph's layouts drive its own graph model.
1405
1417
  - **`radial`** (`treedb-radial`) — the root in the middle, a ring per depth,
1406
1418
  every subtree an angular **sector** proportional to its leaves, and the
1407
1419
  radius of each ring the largest of three: one `ranksep` out from the ring
@@ -1413,7 +1425,20 @@ layouts by two thin adapters in `c_g6_nodes_tree.js`:
1413
1425
  construction, across the ring or along the radius; several roots share the
1414
1426
  circle around an empty centre.
1415
1427
 
1416
- Both take the **same spanning tree**, chosen deterministically: roots are the
1428
+ **Elbow edges** (`7.23.149`) are an option of the edges, not a layout: the
1429
+ toolbar's `GRAPH_EDGE_ELBOW` toggle sets `edge_shape` to `elbow`, and every
1430
+ edge goes straight out of the parent's port to the channel half way to the
1431
+ child, along it, and straight into the child's port — mxGraph's tree routing.
1432
+ The children of one hook share a row and a port, so they share the channel
1433
+ and read as one bus. The two edge types (`treedb-elbow-v` / `-h`) subclass
1434
+ G6's `Polyline` and compute the elbow from the ports on every draw, so
1435
+ dragging, folding and relayout need nothing else. It follows the reading
1436
+ direction, and a layout with no rows (`rowless_layouts`: `radial`,
1437
+ `d3-force`, `force-atlas2`) keeps the curve, with the toggle disabled.
1438
+ `edge_shape` is `SDF_PERSIST` on `C_YUI_TREEDB_GRAPH`, a preference per
1439
+ treedb like `node_labels`. Consumer key: `elbow edges`.
1440
+
1441
+ All three take the **same spanning tree**, chosen deterministically: roots are the
1417
1442
  nodes with no incoming edge, in node order; a node belongs to the **first
1418
1443
  parent that reaches it** in a breadth-first walk (the place, not the
1419
1444
  controller, because the place's column came first) and its other links are
@@ -29314,6 +29314,203 @@ function tidy_tree_lr(nodes, edges, o) {
29314
29314
  }
29315
29315
  return pos;
29316
29316
  }
29317
+ /************************************************************
29318
+ * The compact tree.
29319
+ *
29320
+ * The tidy tree above gives every subtree its whole BLOCK: open a
29321
+ * hall with twenty-four devices and its block widens, and with it
29322
+ * every block above it, so the siblings of its ancestors move apart
29323
+ * at depths where nothing of theirs touches. This one keeps the
29324
+ * CONTOUR of each subtree instead -- its outline on each side, depth
29325
+ * by depth -- and slides every sibling against the outline of the
29326
+ * ones before it. A folded region then sits as close to an open one
29327
+ * as their cards allow at each depth, which is what a folded treedb
29328
+ * is: one branch open among closed ones.
29329
+ *
29330
+ * Same spanning tree, same order, same rows as the tidy tree: only
29331
+ * the packing across the depths differs, so switching between the
29332
+ * two moves cards sideways and never reorders them.
29333
+ *
29334
+ * The contour arithmetic is Moen's ("Drawing dynamic trees", IEEE
29335
+ * Software, 1990) in the form mxGraph gave it in mxCompactTreeLayout
29336
+ * -- Copyright (c) 2006-2015 JGraph Ltd, Apache License 2.0 -- read in
29337
+ * maxGraph's CompactTreeLayout.ts: leaf, join, merge, offset and
29338
+ * bridge below follow that form. What is ours: it runs on the
29339
+ * spanning tree of a FOREST, every depth is a row as wide as its
29340
+ * widest card (mxGraph's `alignRanks`), several roots sit side by
29341
+ * side, and there is no recursion.
29342
+ ************************************************************/
29343
+ function layout_compact(nodes, edges, opts) {
29344
+ let o = Object.assign({}, DEFAULTS, opts || {});
29345
+ if (o.direction === "LR") return compact_tree_lr(nodes, edges, o);
29346
+ let lr = compact_tree_lr(nodes.map((n) => Object.assign({}, n, {
29347
+ w: n.h,
29348
+ h: n.w
29349
+ })), edges, o);
29350
+ let pos = /* @__PURE__ */ new Map();
29351
+ for (let [id, p] of lr) pos.set(id, {
29352
+ x: p.y,
29353
+ y: p.x
29354
+ });
29355
+ return pos;
29356
+ }
29357
+ function contour_line(dx, dy, next) {
29358
+ return {
29359
+ dx,
29360
+ dy,
29361
+ next: next || null
29362
+ };
29363
+ }
29364
+ function contour_offset(p1, p2, a1, a2, b1, b2) {
29365
+ if (b1 <= p1 || p1 + a1 <= 0) return 0;
29366
+ let d;
29367
+ if (b1 * a2 - a1 * b2 > 0) {
29368
+ if (p1 < 0) d = p1 * a2 / a1 - p2;
29369
+ else if (p1 > 0) d = p1 * b2 / b1 - p2;
29370
+ else d = -p2;
29371
+ } else if (b1 < p1 + a1) d = b2 - (p2 + (b1 - p1) * a2 / a1);
29372
+ else if (b1 > p1 + a1) d = (a1 + p1) * b2 / b1 - (p2 + a2);
29373
+ else d = b2 - (p2 + a2);
29374
+ return d > 0 ? d : 0;
29375
+ }
29376
+ function contour_bridge(line1, x1, y1, line2, x2, y2) {
29377
+ let dx = x2 + line2.dx - x1;
29378
+ let dy = line2.dx === 0 ? line2.dy : dx * line2.dy / line2.dx;
29379
+ let r = contour_line(dx, dy, line2.next);
29380
+ line1.next = contour_line(0, y2 + line2.dy - dy - y1, r);
29381
+ return r;
29382
+ }
29383
+ function contour_merge(p1, p2) {
29384
+ let x = 0;
29385
+ let y = 0;
29386
+ let total = 0;
29387
+ let upper = p1.lower_head;
29388
+ let lower = p2.upper_head;
29389
+ while (lower && upper) {
29390
+ let d = contour_offset(x, y, lower.dx, lower.dy, upper.dx, upper.dy);
29391
+ y += d;
29392
+ total += d;
29393
+ if (x + lower.dx <= upper.dx) {
29394
+ x += lower.dx;
29395
+ y += lower.dy;
29396
+ lower = lower.next;
29397
+ } else {
29398
+ x -= upper.dx;
29399
+ y -= upper.dy;
29400
+ upper = upper.next;
29401
+ }
29402
+ }
29403
+ if (lower) {
29404
+ let b = contour_bridge(p1.upper_tail, 0, 0, lower, x, y);
29405
+ p1.upper_tail = b.next ? p2.upper_tail : b;
29406
+ p1.lower_tail = p2.lower_tail;
29407
+ } else {
29408
+ let b = contour_bridge(p2.lower_tail, x, y, upper, 0, 0);
29409
+ if (!b.next) p1.lower_tail = b;
29410
+ }
29411
+ p1.lower_head = p2.lower_head;
29412
+ return total;
29413
+ }
29414
+ function compact_tree_lr(nodes, edges, o) {
29415
+ let t = spanning_tree(nodes, edges);
29416
+ let order = walk_order(t);
29417
+ let pos = /* @__PURE__ */ new Map();
29418
+ let col_w = [];
29419
+ for (let [id, d] of t.depth) col_w[d] = Math.max(col_w[d] || 0, t.by_id.get(id).w);
29420
+ let col_x = [];
29421
+ let x = 0;
29422
+ for (let d = 0; d < col_w.length; d++) {
29423
+ col_x[d] = x;
29424
+ x += (col_w[d] || 0) + o.ranksep;
29425
+ }
29426
+ let pad = o.nodesep / 2;
29427
+ let dist = o.nodesep;
29428
+ let level_distance = o.ranksep - pad;
29429
+ let tn = /* @__PURE__ */ new Map();
29430
+ for (let id of order) tn.set(id, {
29431
+ len: col_w[t.depth.get(id)],
29432
+ ext: t.by_id.get(id).h,
29433
+ off_x: 0,
29434
+ off_y: 0,
29435
+ y: 0,
29436
+ contour: null
29437
+ });
29438
+ for (let i = order.length - 1; i >= 0; i--) {
29439
+ let id = order[i];
29440
+ let n = tn.get(id);
29441
+ let kids = t.children.get(id) || [];
29442
+ if (!kids.length) {
29443
+ let upper = contour_line(n.len + dist, 0);
29444
+ let lower_tail = contour_line(0, -n.ext - dist);
29445
+ n.contour = {
29446
+ upper_head: upper,
29447
+ upper_tail: upper,
29448
+ lower_tail,
29449
+ lower_head: contour_line(n.len + dist, 0, lower_tail)
29450
+ };
29451
+ continue;
29452
+ }
29453
+ let first = tn.get(kids[0]);
29454
+ n.contour = first.contour;
29455
+ let h = first.ext + dist;
29456
+ let span = h;
29457
+ for (let k = 1; k < kids.length; k++) {
29458
+ let kid = tn.get(kids[k]);
29459
+ let d = contour_merge(n.contour, kid.contour);
29460
+ kid.off_y = d + h;
29461
+ kid.off_x = 0;
29462
+ h = kid.ext + dist;
29463
+ span += d + h;
29464
+ }
29465
+ let gap = pad + level_distance;
29466
+ let y2 = (span - n.ext) / 2 - pad;
29467
+ let y1 = y2 + n.ext + 2 * pad - span;
29468
+ first.off_x = gap + n.len;
29469
+ first.off_y = y1;
29470
+ n.contour.upper_head = contour_line(n.len, 0, contour_line(gap, y1, n.contour.upper_head));
29471
+ n.contour.lower_head = contour_line(n.len, 0, contour_line(gap, y2, n.contour.lower_head));
29472
+ }
29473
+ let root_of = /* @__PURE__ */ new Map();
29474
+ for (let id of order) {
29475
+ let n = tn.get(id);
29476
+ if (!root_of.has(id)) root_of.set(id, id);
29477
+ let kids = t.children.get(id) || [];
29478
+ if (!kids.length) continue;
29479
+ let running = n.y + tn.get(kids[0]).off_y;
29480
+ tn.get(kids[0]).y = running;
29481
+ root_of.set(kids[0], root_of.get(id));
29482
+ for (let k = 1; k < kids.length; k++) {
29483
+ let kid = tn.get(kids[k]);
29484
+ kid.y = running + kid.off_y;
29485
+ running = kid.y;
29486
+ root_of.set(kids[k], root_of.get(id));
29487
+ }
29488
+ }
29489
+ let lo = /* @__PURE__ */ new Map();
29490
+ let hi = /* @__PURE__ */ new Map();
29491
+ for (let id of order) {
29492
+ let r = root_of.get(id);
29493
+ let n = tn.get(id);
29494
+ lo.set(r, Math.min(lo.has(r) ? lo.get(r) : Infinity, n.y));
29495
+ hi.set(r, Math.max(hi.has(r) ? hi.get(r) : -Infinity, n.y + n.ext));
29496
+ }
29497
+ let shift = /* @__PURE__ */ new Map();
29498
+ let top = 0;
29499
+ for (let r of t.roots) {
29500
+ shift.set(r, top - lo.get(r));
29501
+ top += hi.get(r) - lo.get(r) + o.nodesep * 2;
29502
+ }
29503
+ for (let id of order) {
29504
+ let d = t.depth.get(id);
29505
+ let n = tn.get(id);
29506
+ let y = n.y + shift.get(root_of.get(id));
29507
+ pos.set(id, {
29508
+ x: col_x[d] + col_w[d] / 2,
29509
+ y: y + n.ext / 2
29510
+ });
29511
+ }
29512
+ return pos;
29513
+ }
29317
29514
  function extent_at(n, a) {
29318
29515
  if (!n) return 0;
29319
29516
  return Math.abs(n.w * Math.cos(a)) + Math.abs(n.h * Math.sin(a));
@@ -45447,7 +45644,7 @@ var _excluded$1 = ["style"];
45447
45644
  /**
45448
45645
  * Polyline inherits the marker-related capabilities of Polygon.
45449
45646
  */
45450
- var Polyline = /*#__PURE__*/ function(_Polygon) {
45647
+ var Polyline$1 = /*#__PURE__*/ function(_Polygon) {
45451
45648
  function Polyline() {
45452
45649
  var _ref = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, style = _ref.style, rest = _objectWithoutProperties(_ref, _excluded$1);
45453
45650
  _classCallCheck(this, Polyline);
@@ -45539,7 +45736,7 @@ var Polyline = /*#__PURE__*/ function(_Polygon) {
45539
45736
  }
45540
45737
  ]);
45541
45738
  }(Polygon);
45542
- Polyline.PARSED_STYLE_LIST = new Set([].concat(_toConsumableArray(Polygon.PARSED_STYLE_LIST), [
45739
+ Polyline$1.PARSED_STYLE_LIST = new Set([].concat(_toConsumableArray(Polygon.PARSED_STYLE_LIST), [
45543
45740
  "points",
45544
45741
  "markerStart",
45545
45742
  "markerMid",
@@ -56297,6 +56494,12 @@ var _layouts = {
56297
56494
  nodesep: 18,
56298
56495
  ranksep: 90
56299
56496
  },
56497
+ "compact-tree": {
56498
+ type: "treedb-compact",
56499
+ direction: "TB",
56500
+ nodesep: 18,
56501
+ ranksep: 90
56502
+ },
56300
56503
  "dagre": {
56301
56504
  type: "dagre",
56302
56505
  rankdir: "LR",
@@ -56368,6 +56571,12 @@ var attrs_table$4 = [
56368
56571
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "main_topic", 0, "", "The topic the tree hangs from; empty = deduced (the one whose hooks reach the most others). Its parentless records are the roots; a parentless record of a topic linked to it is LOOSE and shown only on request"),
56369
56572
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_LIST, "loose_topics", 0, "[]", "Topics whose loose records (no parent, in a topic the schema hangs from the main one) are shown as roots"),
56370
56573
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "node_mode", 0, "expanded", "How a record is drawn: `expanded` = the card with its pills and ports; `compact` = a one-line pill with the name and small ports; `shape` = a figure of the topic's colour (square, circle, diamond... per node or topic, from the node properties), no ports, no text -- the topology alone. One node can be toggled against it (EV_TOGGLE_NODE_MODE)"),
56574
+ (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "edge_shape", 0, "curved", "How an edge is drawn: `curved` (the default) or `elbow` -- straight out of its port to the channel between the two rows, along it, and straight into the other port: the bus of an org chart, as mxGraph drew its trees. Layouts with no rows (`rowless_layouts`) keep the curve"),
56575
+ (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_LIST, "rowless_layouts", _yuneta_gobj_js.sdata_flag_t.SDF_RD, JSON.stringify([
56576
+ "radial",
56577
+ "d3-force",
56578
+ "force-atlas2"
56579
+ ]), "Layouts with no rows for an elbow to run between: their edges stay curved whatever `edge_shape` says (read-only, for the parent to query)"),
56371
56580
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "node_labels", 0, true, "A `shape` node says its name under the figure. Off, it is a coloured figure and nothing else"),
56372
56581
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "confirm_delete_node", 0, true, "Ask confirmation before deleting a node"),
56373
56582
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "confirm_unlink_edge", 0, true, "Ask confirmation before unlinking an edge"),
@@ -56618,6 +56827,9 @@ function register_layouts(gobj) {
56618
56827
  _g6_extensions_registered = true;
56619
56828
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "manual", ManualLayout);
56620
56829
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-tree", TreedbTreeLayout);
56830
+ (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-compact", TreedbCompactLayout);
56831
+ (0, _antv_g6.register)(_antv_g6.ExtensionCategory.EDGE, "treedb-elbow-v", TreedbElbowV);
56832
+ (0, _antv_g6.register)(_antv_g6.ExtensionCategory.EDGE, "treedb-elbow-h", TreedbElbowH);
56621
56833
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-radial", TreedbRadialLayout);
56622
56834
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.NODE, "light", LightNode);
56623
56835
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.NODE, "treedb-card", TreedbCard);
@@ -57310,7 +57522,10 @@ function layout_direction(gobj) {
57310
57522
  return (0, _yuneta_gobj_js.str_in_list)(LR_LAYOUTS, gobj.priv.layout) ? "LR" : "TB";
57311
57523
  }
57312
57524
  function edge_type_for(gobj) {
57313
- return layout_direction(gobj) === "LR" ? "cubic-horizontal" : "cubic";
57525
+ let lr = layout_direction(gobj) === "LR";
57526
+ let rowless = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "rowless_layouts") || [];
57527
+ if ((0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "edge_shape") === "elbow" && !(0, _yuneta_gobj_js.str_in_list)(rowless, gobj.priv.layout)) return lr ? "treedb-elbow-h" : "treedb-elbow-v";
57528
+ return lr ? "cubic-horizontal" : "cubic";
57314
57529
  }
57315
57530
  /************************************************************
57316
57531
  * Where the ports sit, by direction: fkeys (the way in from a
@@ -58785,6 +59000,44 @@ var TreedbTreeLayout = class extends _antv_g6.BaseLayout {
58785
59000
  return treedb_layout_output(layout_tree(input.nodes, input.edges, options));
58786
59001
  }
58787
59002
  };
59003
+ /************************************************************
59004
+ * An ELBOW edge, the way mxGraph drew a tree: straight out of
59005
+ * the parent's port to the channel half way to the child, along
59006
+ * it, and straight into the child's port. The children of one
59007
+ * hook sit on one row and leave by one port, so they share the
59008
+ * channel and the lines read as one bus.
59009
+ *
59010
+ * Computed on every draw from where the two ends ARE, so a
59011
+ * dragged card, a fold or a layout needs nothing else. `-v` runs
59012
+ * between rows (top to bottom), `-h` between columns.
59013
+ ************************************************************/
59014
+ var ELBOW_RADIUS = 6;
59015
+ var TreedbElbowV = class extends _antv_g6.Polyline {
59016
+ getControlPoints(attributes) {
59017
+ let [s, t] = this.getEndpoints(attributes, false);
59018
+ let mid = (s[1] + t[1]) / 2;
59019
+ return [[s[0], mid], [t[0], mid]];
59020
+ }
59021
+ getKeyPath(attributes) {
59022
+ return super.getKeyPath(Object.assign({}, attributes, { radius: attributes.radius || ELBOW_RADIUS }));
59023
+ }
59024
+ };
59025
+ var TreedbElbowH = class extends _antv_g6.Polyline {
59026
+ getControlPoints(attributes) {
59027
+ let [s, t] = this.getEndpoints(attributes, false);
59028
+ let mid = (s[0] + t[0]) / 2;
59029
+ return [[mid, s[1]], [mid, t[1]]];
59030
+ }
59031
+ getKeyPath(attributes) {
59032
+ return super.getKeyPath(Object.assign({}, attributes, { radius: attributes.radius || ELBOW_RADIUS }));
59033
+ }
59034
+ };
59035
+ var TreedbCompactLayout = class extends _antv_g6.BaseLayout {
59036
+ async execute(data, options) {
59037
+ let input = treedb_layout_input(data);
59038
+ return treedb_layout_output(layout_compact(input.nodes, input.edges, options));
59039
+ }
59040
+ };
58788
59041
  var TreedbRadialLayout = class extends _antv_g6.BaseLayout {
58789
59042
  async execute(data, options) {
58790
59043
  let input = treedb_layout_input(data);
@@ -63222,6 +63475,20 @@ function ac_set_node_labels(gobj, event, kw, src) {
63222
63475
  return 0;
63223
63476
  }
63224
63477
  /************************************************************
63478
+ * Curved or elbow edges (the host's toggle). Nothing moves: every
63479
+ * edge takes the type that goes with the shape and the layout,
63480
+ * and draws again.
63481
+ ************************************************************/
63482
+ function ac_set_edge_shape(gobj, event, kw, src) {
63483
+ let priv = gobj.priv;
63484
+ let shape = kw && kw.edge_shape === "elbow" ? "elbow" : "curved";
63485
+ (0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "edge_shape", shape);
63486
+ if (!priv.graph || !priv.graph_rendered) return 0;
63487
+ apply_layout_direction(gobj);
63488
+ graph_draw(gobj);
63489
+ return 0;
63490
+ }
63491
+ /************************************************************
63225
63492
  * ONE node opened or closed against the mode (a double click,
63226
63493
  * or the context menu). It holds still on screen while the
63227
63494
  * rest of the graph makes room, as a fold does.
@@ -63781,6 +64048,11 @@ function create_gclass$4(gclass_name) {
63781
64048
  ac_set_node_labels,
63782
64049
  null
63783
64050
  ],
64051
+ [
64052
+ "EV_SET_EDGE_SHAPE",
64053
+ ac_set_edge_shape,
64054
+ null
64055
+ ],
63784
64056
  [
63785
64057
  "EV_TOGGLE_NODE_MODE",
63786
64058
  ac_toggle_node_mode,
@@ -63902,6 +64174,7 @@ function create_gclass$4(gclass_name) {
63902
64174
  ["EV_SET_LOOSE_TOPICS", 0],
63903
64175
  ["EV_SET_NODE_MODE", 0],
63904
64176
  ["EV_SET_NODE_LABELS", 0],
64177
+ ["EV_SET_EDGE_SHAPE", 0],
63905
64178
  ["EV_TOGGLE_NODE_MODE", 0],
63906
64179
  ["EV_NODE_DBLCLICK", 0],
63907
64180
  ["EV_LEGEND_STATE", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
@@ -63978,6 +64251,7 @@ var attrs_table$3 = [
63978
64251
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "main_topic", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, "", "The topic the tree hangs from; empty = deduced by the graph. User preference, per treedb"),
63979
64252
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_LIST, "loose_topics", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, "[]", "Topics whose LOOSE records (no parent) are shown. User preference, per treedb"),
63980
64253
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "node_mode", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, "expanded", "How the records are drawn: `expanded` = the cards with their pills and ports, `compact` = one-line pills with the name, `shape` = coloured figures, the topology alone. User preference"),
64254
+ (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "edge_shape", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, "curved", "How the edges are drawn: `curved` or `elbow` (the bus of an org chart). User preference"),
63981
64255
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "node_labels", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, true, "A `shape` node says its name under its figure. User preference"),
63982
64256
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_DICT, "camera", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, "{}", "Where the reader left the viewport: {zoom, x, y}. Handed to the engine on creation and written back when a move settles, so the graph opens where it was left. User preference, per treedb"),
63983
64257
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_INTEGER, "fold_level", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, 0, "The level of the MAIN tree the toolbar's stepper stands on: 1 = the main topic's roots, N = N-1 levels under them; 0 = never stepped, `expand_depth`. Handed to the engine on creation, so the graph opens at the level it was left. User preference, per treedb"),
@@ -64070,6 +64344,7 @@ function mt_create$3(gobj) {
64070
64344
  loose_topics: (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "loose_topics") || [],
64071
64345
  node_mode: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "node_mode") || "expanded",
64072
64346
  node_labels: (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "node_labels"),
64347
+ edge_shape: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "edge_shape") || "curved",
64073
64348
  camera: (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "camera") || {}
64074
64349
  }, gobj);
64075
64350
  populate_nodes_tree_options(gobj);
@@ -64256,6 +64531,7 @@ function option_label(name) {
64256
64531
  case "edition": return (0, i18next.t)("edition");
64257
64532
  case "manual": return (0, i18next.t)("manual");
64258
64533
  case "treedb-tree": return (0, i18next.t)("treedb-tree");
64534
+ case "compact-tree": return (0, i18next.t)("compact-tree");
64259
64535
  case "radial": return (0, i18next.t)("radial");
64260
64536
  case "dagre": return (0, i18next.t)("dagre");
64261
64537
  case "antv-dagre": return (0, i18next.t)("antv-dagre");
@@ -64279,58 +64555,82 @@ function option_label(name) {
64279
64555
  * its context menu (the child's business).
64280
64556
  ************************************************************/
64281
64557
  function node_shape_items(gobj, wide) {
64282
- return [[
64283
- "div",
64284
- {
64285
- class: "GRAPH_NODE_MODE buttons has-addons",
64286
- style: "margin:0 0 0 .5rem; flex:0 0 auto; flex-wrap:nowrap;"
64287
- },
64288
- NODE_MODES.map((mode) => {
64289
- let key = NODE_MODE_LABELS[mode];
64290
- return [
64291
- "button",
64292
- {
64293
- class: "GRAPH_NODE_MODE_BTN button",
64294
- type: "button",
64295
- "data-mode": mode,
64296
- style: {
64297
- height: wide,
64298
- width: "2.5em"
64558
+ return [
64559
+ [
64560
+ "div",
64561
+ {
64562
+ class: "GRAPH_NODE_MODE buttons has-addons",
64563
+ style: "margin:0 0 0 .5rem; flex:0 0 auto; flex-wrap:nowrap;"
64564
+ },
64565
+ NODE_MODES.map((mode) => {
64566
+ let key = NODE_MODE_LABELS[mode];
64567
+ return [
64568
+ "button",
64569
+ {
64570
+ class: "GRAPH_NODE_MODE_BTN button",
64571
+ type: "button",
64572
+ "data-mode": mode,
64573
+ style: {
64574
+ height: wide,
64575
+ width: "2.5em"
64576
+ },
64577
+ title: (0, i18next.t)(key),
64578
+ "data-i18n-title": key,
64579
+ "aria-label": (0, i18next.t)(key),
64580
+ "data-i18n-aria-label": key,
64581
+ "aria-pressed": "false"
64299
64582
  },
64300
- title: (0, i18next.t)(key),
64301
- "data-i18n-title": key,
64302
- "aria-label": (0, i18next.t)(key),
64303
- "data-i18n-aria-label": key,
64304
- "aria-pressed": "false"
64583
+ yui_toolbar_icon(NODE_MODE_ICONS[mode]),
64584
+ { click: (evt) => {
64585
+ evt.stopPropagation();
64586
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SET_NODE_MODE", { node_mode: mode }, gobj);
64587
+ } }
64588
+ ];
64589
+ })
64590
+ ],
64591
+ [
64592
+ "button",
64593
+ {
64594
+ class: "GRAPH_NODE_LABELS button",
64595
+ type: "button",
64596
+ style: {
64597
+ height: wide,
64598
+ width: "2.5em"
64305
64599
  },
64306
- yui_toolbar_icon(NODE_MODE_ICONS[mode]),
64307
- { click: (evt) => {
64308
- evt.stopPropagation();
64309
- (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SET_NODE_MODE", { node_mode: mode }, gobj);
64310
- } }
64311
- ];
64312
- })
64313
- ], [
64314
- "button",
64315
- {
64316
- class: "GRAPH_NODE_LABELS button",
64317
- type: "button",
64318
- style: {
64319
- height: wide,
64320
- width: "2.5em"
64600
+ title: (0, i18next.t)("node labels"),
64601
+ "data-i18n-title": "node labels",
64602
+ "aria-label": (0, i18next.t)("node labels"),
64603
+ "data-i18n-aria-label": "node labels",
64604
+ "aria-pressed": "false"
64321
64605
  },
64322
- title: (0, i18next.t)("node labels"),
64323
- "data-i18n-title": "node labels",
64324
- "aria-label": (0, i18next.t)("node labels"),
64325
- "data-i18n-aria-label": "node labels",
64326
- "aria-pressed": "false"
64327
- },
64328
- yui_toolbar_icon("yi-font"),
64329
- { click: (evt) => {
64330
- evt.stopPropagation();
64331
- (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_NODE_LABELS", {}, gobj);
64332
- } }
64333
- ]];
64606
+ yui_toolbar_icon("yi-font"),
64607
+ { click: (evt) => {
64608
+ evt.stopPropagation();
64609
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_NODE_LABELS", {}, gobj);
64610
+ } }
64611
+ ],
64612
+ [
64613
+ "button",
64614
+ {
64615
+ class: "GRAPH_EDGE_ELBOW button",
64616
+ type: "button",
64617
+ style: {
64618
+ height: wide,
64619
+ width: "2.5em"
64620
+ },
64621
+ title: (0, i18next.t)("elbow edges"),
64622
+ "data-i18n-title": "elbow edges",
64623
+ "aria-label": (0, i18next.t)("elbow edges"),
64624
+ "data-i18n-aria-label": "elbow edges",
64625
+ "aria-pressed": "false"
64626
+ },
64627
+ yui_toolbar_icon("yi-diagram-project"),
64628
+ { click: (evt) => {
64629
+ evt.stopPropagation();
64630
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_EDGE_SHAPE", {}, gobj);
64631
+ } }
64632
+ ]
64633
+ ];
64334
64634
  }
64335
64635
  var NODE_MODES = [
64336
64636
  "expanded",
@@ -64363,6 +64663,16 @@ function refresh_node_shape_buttons(gobj, $root) {
64363
64663
  $labels.setAttribute("aria-pressed", labels ? "true" : "false");
64364
64664
  $labels.disabled = mode !== "shape";
64365
64665
  }
64666
+ let elbow = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "edge_shape") === "elbow";
64667
+ set_pressed_state($root, ".GRAPH_EDGE_ELBOW", elbow);
64668
+ let $elbow = $root.querySelector(".GRAPH_EDGE_ELBOW");
64669
+ if ($elbow) {
64670
+ $elbow.setAttribute("aria-pressed", elbow ? "true" : "false");
64671
+ let child = gobj.priv.gobj_nodes_tree;
64672
+ let rowless = child ? (0, _yuneta_gobj_js.gobj_read_attr)(child, "rowless_layouts") || [] : [];
64673
+ let layout = child ? (0, _yuneta_gobj_js.gobj_read_str_attr)(child, "layout") : "";
64674
+ $elbow.disabled = rowless.includes(layout);
64675
+ }
64366
64676
  }
64367
64677
  /************************************************************
64368
64678
  * The fold STEPPER: one level less, where the tree stands, one
@@ -64911,6 +65221,7 @@ function populate_nodes_tree_options(gobj) {
64911
65221
  let current_layout = (0, _yuneta_gobj_js.gobj_read_str_attr)(priv.gobj_nodes_tree, "layout");
64912
65222
  if (current_layout) $layout_select.value = current_layout;
64913
65223
  refresh_layout_stepper(gobj);
65224
+ refresh_node_shape_buttons(gobj, $container);
64914
65225
  }
64915
65226
  let $operation_mode_select = $container.querySelector(".GRAPH_MODE_SELECT");
64916
65227
  $operation_mode_select.value = priv.operation_mode;
@@ -65604,6 +65915,7 @@ function ac_set_layout(gobj, event, kw, src) {
65604
65915
  $layout_select.value = priv.layout;
65605
65916
  (0, _yuneta_gobj_js.gobj_send_event)(priv.gobj_nodes_tree, "EV_SET_LAYOUT", { layout }, gobj);
65606
65917
  refresh_layout_stepper(gobj);
65918
+ refresh_node_shape_buttons(gobj, priv.$container);
65607
65919
  return 0;
65608
65920
  }
65609
65921
  /************************************************************
@@ -65955,6 +66267,7 @@ function ac_layout_autoset(gobj, event, kw, src) {
65955
66267
  if (!$select || !layout) return 0;
65956
66268
  $select.value = layout;
65957
66269
  refresh_layout_stepper(gobj);
66270
+ refresh_node_shape_buttons(gobj, $container);
65958
66271
  return 0;
65959
66272
  }
65960
66273
  /************************************************************
@@ -66027,6 +66340,15 @@ function ac_set_node_mode(gobj, event, kw, src) {
66027
66340
  if (priv.gobj_nodes_tree) (0, _yuneta_gobj_js.gobj_send_event)(priv.gobj_nodes_tree, "EV_SET_NODE_MODE", { node_mode: mode }, gobj);
66028
66341
  return 0;
66029
66342
  }
66343
+ function ac_toggle_edge_shape(gobj, event, kw, src) {
66344
+ let priv = gobj.priv;
66345
+ let shape = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "edge_shape") === "elbow" ? "curved" : "elbow";
66346
+ (0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "edge_shape", shape);
66347
+ (0, _yuneta_gobj_js.gobj_save_persistent_attrs)(gobj, "edge_shape");
66348
+ refresh_node_shape_buttons(gobj, priv.$container);
66349
+ if (priv.gobj_nodes_tree) (0, _yuneta_gobj_js.gobj_send_event)(priv.gobj_nodes_tree, "EV_SET_EDGE_SHAPE", { edge_shape: shape }, gobj);
66350
+ return 0;
66351
+ }
66030
66352
  function ac_toggle_node_labels(gobj, event, kw, src) {
66031
66353
  let priv = gobj.priv;
66032
66354
  let labels = !(0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "node_labels");
@@ -66271,6 +66593,11 @@ function create_gclass$3(gclass_name) {
66271
66593
  ac_toggle_node_labels,
66272
66594
  null
66273
66595
  ],
66596
+ [
66597
+ "EV_TOGGLE_EDGE_SHAPE",
66598
+ ac_toggle_edge_shape,
66599
+ null
66600
+ ],
66274
66601
  [
66275
66602
  "EV_LAYOUT_AUTOSET",
66276
66603
  ac_layout_autoset,
@@ -66348,6 +66675,7 @@ function create_gclass$3(gclass_name) {
66348
66675
  ["EV_COLLAPSE_LEVEL", 0],
66349
66676
  ["EV_SET_NODE_MODE", 0],
66350
66677
  ["EV_TOGGLE_NODE_LABELS", 0],
66678
+ ["EV_TOGGLE_EDGE_SHAPE", 0],
66351
66679
  ["EV_FIND_RESULT", 0],
66352
66680
  ["EV_LAYOUT_AUTOSET", 0],
66353
66681
  ["EV_CAMERA_CHANGED", 0],