@yuneta/gobj-ui 7.23.68 → 7.23.70
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 +49 -0
- package/dist/gobj-ui.cjs.js +438 -6
- package/dist/gobj-ui.es.js +438 -6
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +103 -2
- package/src/c_yui_treedb_graph.js +15 -4
- package/src/treedb_layout.js +380 -0
- package/src/treedb_layout.test.js +172 -0
package/README.md
CHANGED
|
@@ -1266,6 +1266,55 @@ a level or two, with a count on every cut.
|
|
|
1266
1266
|
|
|
1267
1267
|
One consumer key came with it: `show more`, the chip's tooltip.
|
|
1268
1268
|
|
|
1269
|
+
### Layouts: what G6 offers, and the two made for a treedb
|
|
1270
|
+
|
|
1271
|
+
What a treedb graph IS, once folded: a **forest read left to right**. A main
|
|
1272
|
+
topic is a tree (places: country, region, site, hall), the other topics hang
|
|
1273
|
+
from its nodes through hooks, a record may hang from two parents (a device
|
|
1274
|
+
from its place AND its controller), and every visible node was reached from a
|
|
1275
|
+
root. Tens to a few hundred cards on screen, never the store.
|
|
1276
|
+
|
|
1277
|
+
G6 5.1 registers these layouts, and this is how each meets that shape:
|
|
1278
|
+
|
|
1279
|
+
| layout | what it does | for a treedb |
|
|
1280
|
+
|---|---|---|
|
|
1281
|
+
| `dagre` / `antv-dagre` | layered DAG: longest-path ranks, crossing minimisation, one direction | the right reading (LR); but the crossing heuristic **reorders the siblings on every run** — open one hook and the column next to it shuffles — and it is the one thing that takes time on a big expansion |
|
|
1282
|
+
| `compact-box`, `indented`, `dendrogram`, `mindmap` | @antv/hierarchy tree layouts | the shape wanted, but G6 runs them on a tree it **builds from the edges** (`createTreeStructure`): a node with two parents lands under whichever parent the builder met first, unstably |
|
|
1283
|
+
| `radial` | MDS on graph distances from a focus node, a ring per depth, overlaps pushed apart afterwards | the right idea — a hall with a hundred devices is a **fan**, not a column — but the ring radius is one it is TOLD: twenty cards of 172px on a ring of radius 200 have 52px each and pile up. Tried, and replaced by our own (below) |
|
|
1284
|
+
| `force`, `d3-force`, `force-atlas2`, `fruchterman` | physics | scatter a tree: the pile with springs. `d3-force` and `force-atlas2` stay in the picker for the rare flat treedb |
|
|
1285
|
+
| `circular`, `concentric`, `grid`, `mds`, `random` | rings, rings by degree, a grid, projection, noise | none knows a parent from a child |
|
|
1286
|
+
| `combo-combined`, `fishbone` | combos / cause-effect | not this data |
|
|
1287
|
+
|
|
1288
|
+
So three of our own, in `treedb_layout.js` (pure, tested), registered as G6
|
|
1289
|
+
layouts by three thin adapters in `c_g6_nodes_tree.js`:
|
|
1290
|
+
|
|
1291
|
+
- **`treedb-tree`** — the classic tidy tree, left to right. A column per
|
|
1292
|
+
depth as wide as its widest card, a node centred on the block of its
|
|
1293
|
+
children, siblings stacked with `nodesep`. **The default** for a treedb
|
|
1294
|
+
nobody has arranged (was `dagre`).
|
|
1295
|
+
- **`treedb-outline`** — one node per row, indented by depth: what a JSON
|
|
1296
|
+
viewer draws, and what a treedb is when read as one. Tall, but nothing is
|
|
1297
|
+
ever beside anything.
|
|
1298
|
+
- **`radial`** (`treedb-radial`) — the root in the middle, a ring per depth,
|
|
1299
|
+
every subtree an angular **sector** proportional to its leaves, and the
|
|
1300
|
+
radius of each ring the larger of one step out from the ring before and
|
|
1301
|
+
the length its cards need side by side. A fan that cannot overlap by
|
|
1302
|
+
construction; several roots share the circle around an empty centre.
|
|
1303
|
+
|
|
1304
|
+
Both take the **same spanning tree**, chosen deterministically: roots are the
|
|
1305
|
+
nodes with no incoming edge, in node order; a node belongs to the **first
|
|
1306
|
+
parent that reaches it** in a breadth-first walk (the place, not the
|
|
1307
|
+
controller, because the place's column came first) and its other links are
|
|
1308
|
+
drawn as edges across the tree; the children of a node are ordered by the
|
|
1309
|
+
**hook they hang from** (the parent's port order — the schema's column order)
|
|
1310
|
+
and then by node order (record order, the pages' order); a cycle nothing
|
|
1311
|
+
reaches gets a root. Consequences that dagre cannot give: O(n), no crossing
|
|
1312
|
+
heuristic, and **opening a hook moves nothing that is not under or beside
|
|
1313
|
+
it** — the cards keep their order, the eye keeps its place, and the `+N` chip
|
|
1314
|
+
sits at the end of its own hook's children. The hook rank comes from the
|
|
1315
|
+
edge's `sourcePort` looked up in the parent's ports, so the adapter needs no
|
|
1316
|
+
model, only the G6 data.
|
|
1317
|
+
|
|
1269
1318
|
### The legend is the graph's layer control
|
|
1270
1319
|
|
|
1271
1320
|
The legend strip under the toolbar is **always there** now (the *Legend*
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -27314,6 +27314,329 @@ function fold_reveal(model, state, node_key) {
|
|
|
27314
27314
|
return true;
|
|
27315
27315
|
}
|
|
27316
27316
|
//#endregion
|
|
27317
|
+
//#region src/treedb_layout.js
|
|
27318
|
+
/***********************************************************************
|
|
27319
|
+
* treedb_layout.js
|
|
27320
|
+
*
|
|
27321
|
+
* Two layouts made for a treedb, and nothing else.
|
|
27322
|
+
*
|
|
27323
|
+
* What a treedb graph IS, once it is folded (treedb_fold_model.js):
|
|
27324
|
+
* a forest read left to right. A main topic is a tree (places:
|
|
27325
|
+
* country, region, site, hall), the other topics hang from its
|
|
27326
|
+
* nodes through hooks (devices, users, controllers), a record may
|
|
27327
|
+
* hang from two parents (a device from its place AND its
|
|
27328
|
+
* controller), and every visible node was reached from a root.
|
|
27329
|
+
* Tens to a few hundred cards on screen, never the whole store.
|
|
27330
|
+
*
|
|
27331
|
+
* G6's own layouts either do not know that or pay for not knowing:
|
|
27332
|
+
*
|
|
27333
|
+
* - `dagre` gets the reading direction right and then ranks by
|
|
27334
|
+
* longest path and minimises crossings with a heuristic that
|
|
27335
|
+
* REORDERS the siblings on every run -- open one hook and the
|
|
27336
|
+
* column next to it shuffles. It is O(n·m) per sweep and it is
|
|
27337
|
+
* the one thing that takes time on a big expansion.
|
|
27338
|
+
* - the tree layouts (`compact-box`, `indented`, `dendrogram`,
|
|
27339
|
+
* `mindmap`) draw exactly the shape wanted, but G6 runs them on
|
|
27340
|
+
* a TREE it builds from the edges: a node with two parents is
|
|
27341
|
+
* placed by whichever parent the builder met first, unstably.
|
|
27342
|
+
* - the force family scatters a tree, which is the pile with
|
|
27343
|
+
* physics.
|
|
27344
|
+
*
|
|
27345
|
+
* So: a tidy tree (`tree`) and an outline (`outline`), both fed by
|
|
27346
|
+
* the SAME spanning tree, chosen deterministically:
|
|
27347
|
+
*
|
|
27348
|
+
* - roots are the nodes with no incoming edge, in node order;
|
|
27349
|
+
* - a node belongs to the FIRST parent that reaches it in a
|
|
27350
|
+
* breadth-first walk from the roots -- the place, not the
|
|
27351
|
+
* controller, because the place's column came first -- and the
|
|
27352
|
+
* other links are drawn as edges across the tree;
|
|
27353
|
+
* - the children of a node are ordered by the HOOK they hang from
|
|
27354
|
+
* (the parent's port order, which is the schema's column order)
|
|
27355
|
+
* and then by node order (record order, the pages' order);
|
|
27356
|
+
* - a node nothing reaches (a cycle) is a root too.
|
|
27357
|
+
*
|
|
27358
|
+
* `tree`: the classic tidy tree, left to right. Each depth is a
|
|
27359
|
+
* column as wide as its widest card; a node is centred on the
|
|
27360
|
+
* block of its children; siblings stack with `nodesep` between
|
|
27361
|
+
* them. O(n), and opening a hook moves NOTHING that is not below
|
|
27362
|
+
* or beside it -- the cards keep their order, the eye keeps its
|
|
27363
|
+
* place.
|
|
27364
|
+
*
|
|
27365
|
+
* `outline`: one node per row, indented by depth -- what a JSON
|
|
27366
|
+
* viewer draws, and what a treedb is when read as one. Tall, but
|
|
27367
|
+
* nothing is ever beside anything: the reader scrolls a list.
|
|
27368
|
+
*
|
|
27369
|
+
* Pure: takes plain nodes and edges, returns positions. The G6
|
|
27370
|
+
* classes in c_g6_nodes_tree.js are two thin adapters over it.
|
|
27371
|
+
*
|
|
27372
|
+
* Copyright (c) 2026, ArtGins.
|
|
27373
|
+
* All Rights Reserved.
|
|
27374
|
+
***********************************************************************/
|
|
27375
|
+
var DEFAULTS = {
|
|
27376
|
+
nodesep: 18,
|
|
27377
|
+
ranksep: 110,
|
|
27378
|
+
indent: 48
|
|
27379
|
+
};
|
|
27380
|
+
/************************************************************
|
|
27381
|
+
* The spanning tree of a graph, deterministic.
|
|
27382
|
+
*
|
|
27383
|
+
* nodes [{id, w, h, order}] order: creation index
|
|
27384
|
+
* edges [{source, target, rank}] rank: the hook's position in
|
|
27385
|
+
* the parent's ports (0 = first)
|
|
27386
|
+
*
|
|
27387
|
+
* Returns {roots: [id], children: Map<id, [id]>, depth: Map<id, n>,
|
|
27388
|
+
* by_id: Map<id, node>}
|
|
27389
|
+
************************************************************/
|
|
27390
|
+
function spanning_tree(nodes, edges) {
|
|
27391
|
+
let by_id = /* @__PURE__ */ new Map();
|
|
27392
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
27393
|
+
let n = nodes[i];
|
|
27394
|
+
by_id.set(n.id, Object.assign({ order: i }, n));
|
|
27395
|
+
}
|
|
27396
|
+
let out = /* @__PURE__ */ new Map();
|
|
27397
|
+
let has_parent = /* @__PURE__ */ new Set();
|
|
27398
|
+
for (let e of edges) {
|
|
27399
|
+
if (!by_id.has(e.source) || !by_id.has(e.target) || e.source === e.target) continue;
|
|
27400
|
+
if (!out.has(e.source)) out.set(e.source, []);
|
|
27401
|
+
out.get(e.source).push({
|
|
27402
|
+
id: e.target,
|
|
27403
|
+
rank: e.rank > 0 ? e.rank : 0
|
|
27404
|
+
});
|
|
27405
|
+
has_parent.add(e.target);
|
|
27406
|
+
}
|
|
27407
|
+
for (let list of out.values()) list.sort((a, b) => {
|
|
27408
|
+
if (a.rank !== b.rank) return a.rank - b.rank;
|
|
27409
|
+
return by_id.get(a.id).order - by_id.get(b.id).order;
|
|
27410
|
+
});
|
|
27411
|
+
let roots = [];
|
|
27412
|
+
for (let n of by_id.values()) if (!has_parent.has(n.id)) roots.push(n.id);
|
|
27413
|
+
let children = /* @__PURE__ */ new Map();
|
|
27414
|
+
let depth = /* @__PURE__ */ new Map();
|
|
27415
|
+
let assign = (start) => {
|
|
27416
|
+
let queue = [start];
|
|
27417
|
+
depth.set(start, 0);
|
|
27418
|
+
while (queue.length) {
|
|
27419
|
+
let id = queue.shift();
|
|
27420
|
+
let kids = [];
|
|
27421
|
+
for (let link of out.get(id) || []) {
|
|
27422
|
+
if (depth.has(link.id)) continue;
|
|
27423
|
+
depth.set(link.id, depth.get(id) + 1);
|
|
27424
|
+
kids.push(link.id);
|
|
27425
|
+
queue.push(link.id);
|
|
27426
|
+
}
|
|
27427
|
+
children.set(id, kids);
|
|
27428
|
+
}
|
|
27429
|
+
};
|
|
27430
|
+
for (let root of roots) assign(root);
|
|
27431
|
+
for (let n of by_id.values()) if (!depth.has(n.id)) {
|
|
27432
|
+
roots.push(n.id);
|
|
27433
|
+
assign(n.id);
|
|
27434
|
+
}
|
|
27435
|
+
return {
|
|
27436
|
+
roots,
|
|
27437
|
+
children,
|
|
27438
|
+
depth,
|
|
27439
|
+
by_id
|
|
27440
|
+
};
|
|
27441
|
+
}
|
|
27442
|
+
/************************************************************
|
|
27443
|
+
* The tidy tree, left to right.
|
|
27444
|
+
*
|
|
27445
|
+
* Returns Map<id, {x, y}> with the CENTRE of each node, the way G6
|
|
27446
|
+
* positions a node.
|
|
27447
|
+
************************************************************/
|
|
27448
|
+
function layout_tree(nodes, edges, opts) {
|
|
27449
|
+
let o = Object.assign({}, DEFAULTS, opts || {});
|
|
27450
|
+
let t = spanning_tree(nodes, edges);
|
|
27451
|
+
let pos = /* @__PURE__ */ new Map();
|
|
27452
|
+
let col_w = [];
|
|
27453
|
+
for (let [id, d] of t.depth) {
|
|
27454
|
+
let w = t.by_id.get(id).w;
|
|
27455
|
+
col_w[d] = Math.max(col_w[d] || 0, w);
|
|
27456
|
+
}
|
|
27457
|
+
let col_x = [];
|
|
27458
|
+
let x = 0;
|
|
27459
|
+
for (let d = 0; d < col_w.length; d++) {
|
|
27460
|
+
col_x[d] = x;
|
|
27461
|
+
x += (col_w[d] || 0) + o.ranksep;
|
|
27462
|
+
}
|
|
27463
|
+
let height = /* @__PURE__ */ new Map();
|
|
27464
|
+
let measure = (id) => {
|
|
27465
|
+
let kids = t.children.get(id) || [];
|
|
27466
|
+
let own = t.by_id.get(id).h;
|
|
27467
|
+
if (!kids.length) {
|
|
27468
|
+
height.set(id, own);
|
|
27469
|
+
return own;
|
|
27470
|
+
}
|
|
27471
|
+
let sum = 0;
|
|
27472
|
+
for (let i = 0; i < kids.length; i++) {
|
|
27473
|
+
sum += measure(kids[i]);
|
|
27474
|
+
if (i > 0) sum += o.nodesep;
|
|
27475
|
+
}
|
|
27476
|
+
let h = Math.max(own, sum);
|
|
27477
|
+
height.set(id, h);
|
|
27478
|
+
return h;
|
|
27479
|
+
};
|
|
27480
|
+
for (let root of t.roots) measure(root);
|
|
27481
|
+
let place = (id, top) => {
|
|
27482
|
+
let n = t.by_id.get(id);
|
|
27483
|
+
let d = t.depth.get(id);
|
|
27484
|
+
let kids = t.children.get(id) || [];
|
|
27485
|
+
let block = height.get(id);
|
|
27486
|
+
let cx = col_x[d] + (col_w[d] - n.w) / 2 + n.w / 2;
|
|
27487
|
+
if (!kids.length) {
|
|
27488
|
+
pos.set(id, {
|
|
27489
|
+
x: cx,
|
|
27490
|
+
y: top + block / 2
|
|
27491
|
+
});
|
|
27492
|
+
return;
|
|
27493
|
+
}
|
|
27494
|
+
let kids_h = 0;
|
|
27495
|
+
for (let i = 0; i < kids.length; i++) {
|
|
27496
|
+
kids_h += height.get(kids[i]);
|
|
27497
|
+
if (i > 0) kids_h += o.nodesep;
|
|
27498
|
+
}
|
|
27499
|
+
let cursor = top + (block - kids_h) / 2;
|
|
27500
|
+
for (let kid of kids) {
|
|
27501
|
+
place(kid, cursor);
|
|
27502
|
+
cursor += height.get(kid) + o.nodesep;
|
|
27503
|
+
}
|
|
27504
|
+
pos.set(id, {
|
|
27505
|
+
x: cx,
|
|
27506
|
+
y: top + block / 2
|
|
27507
|
+
});
|
|
27508
|
+
};
|
|
27509
|
+
let top = 0;
|
|
27510
|
+
for (let root of t.roots) {
|
|
27511
|
+
place(root, top);
|
|
27512
|
+
top += height.get(root) + o.nodesep * 2;
|
|
27513
|
+
}
|
|
27514
|
+
return pos;
|
|
27515
|
+
}
|
|
27516
|
+
/************************************************************
|
|
27517
|
+
* The radial tree: the root in the middle, a ring per depth.
|
|
27518
|
+
*
|
|
27519
|
+
* G6's `radial` places by MDS on the graph distances and pushes
|
|
27520
|
+
* overlaps apart afterwards, with a ring radius it is TOLD; twenty
|
|
27521
|
+
* cards of 172px on a ring of radius 200 have 52px each and pile
|
|
27522
|
+
* up. This one is the radial form of the tidy tree above: every
|
|
27523
|
+
* subtree gets an angular SECTOR proportional to its leaves, a node
|
|
27524
|
+
* sits in the middle of its sector, and the radius of each ring is
|
|
27525
|
+
* the larger of "one step further out than the ring before" and
|
|
27526
|
+
* "long enough for its nodes to sit side by side" -- so a hall
|
|
27527
|
+
* with a hundred devices is a wide, sparse fan, and nothing
|
|
27528
|
+
* overlaps by construction. Several roots share the circle around
|
|
27529
|
+
* a virtual centre.
|
|
27530
|
+
*
|
|
27531
|
+
* ranksep the step between rings
|
|
27532
|
+
* nodesep the gap between neighbours on a ring
|
|
27533
|
+
************************************************************/
|
|
27534
|
+
function layout_radial(nodes, edges, opts) {
|
|
27535
|
+
let o = Object.assign({}, DEFAULTS, opts || {});
|
|
27536
|
+
let t = spanning_tree(nodes, edges);
|
|
27537
|
+
let pos = /* @__PURE__ */ new Map();
|
|
27538
|
+
if (!t.roots.length) return pos;
|
|
27539
|
+
let leaves = /* @__PURE__ */ new Map();
|
|
27540
|
+
let count = (id) => {
|
|
27541
|
+
let kids = t.children.get(id) || [];
|
|
27542
|
+
if (!kids.length) {
|
|
27543
|
+
leaves.set(id, 1);
|
|
27544
|
+
return 1;
|
|
27545
|
+
}
|
|
27546
|
+
let n = 0;
|
|
27547
|
+
for (let kid of kids) n += count(kid);
|
|
27548
|
+
leaves.set(id, n);
|
|
27549
|
+
return n;
|
|
27550
|
+
};
|
|
27551
|
+
let total = 0;
|
|
27552
|
+
for (let root of t.roots) total += count(root);
|
|
27553
|
+
let single = t.roots.length === 1;
|
|
27554
|
+
let ring_of = (id) => t.depth.get(id) + (single ? 0 : 1);
|
|
27555
|
+
let angle = /* @__PURE__ */ new Map();
|
|
27556
|
+
let rings = [];
|
|
27557
|
+
let sector = (id, from, span) => {
|
|
27558
|
+
let a = from + span / 2;
|
|
27559
|
+
angle.set(id, a);
|
|
27560
|
+
let ring = ring_of(id);
|
|
27561
|
+
if (!rings[ring]) rings[ring] = [];
|
|
27562
|
+
let n = t.by_id.get(id);
|
|
27563
|
+
rings[ring].push({
|
|
27564
|
+
id,
|
|
27565
|
+
angle: a,
|
|
27566
|
+
diag: Math.hypot(n.w, n.h)
|
|
27567
|
+
});
|
|
27568
|
+
let cursor = from;
|
|
27569
|
+
for (let kid of t.children.get(id) || []) {
|
|
27570
|
+
let part = span * leaves.get(kid) / leaves.get(id);
|
|
27571
|
+
sector(kid, cursor, part);
|
|
27572
|
+
cursor += part;
|
|
27573
|
+
}
|
|
27574
|
+
};
|
|
27575
|
+
if (single) {
|
|
27576
|
+
let root = t.roots[0];
|
|
27577
|
+
angle.set(root, 0);
|
|
27578
|
+
let cursor = -Math.PI / 2;
|
|
27579
|
+
for (let kid of t.children.get(root) || []) {
|
|
27580
|
+
let part = 2 * Math.PI * leaves.get(kid) / leaves.get(root);
|
|
27581
|
+
sector(kid, cursor, part);
|
|
27582
|
+
cursor += part;
|
|
27583
|
+
}
|
|
27584
|
+
} else {
|
|
27585
|
+
let cursor = -Math.PI / 2;
|
|
27586
|
+
for (let root of t.roots) {
|
|
27587
|
+
let part = 2 * Math.PI * leaves.get(root) / total;
|
|
27588
|
+
sector(root, cursor, part);
|
|
27589
|
+
cursor += part;
|
|
27590
|
+
}
|
|
27591
|
+
}
|
|
27592
|
+
let radius = [0];
|
|
27593
|
+
for (let ring = 1; ring < rings.length; ring++) {
|
|
27594
|
+
let r = radius[ring - 1] + o.ranksep;
|
|
27595
|
+
let list = (rings[ring] || []).slice().sort((a, b) => a.angle - b.angle);
|
|
27596
|
+
for (let i = 0; i < list.length && list.length > 1; i++) {
|
|
27597
|
+
let a = list[i];
|
|
27598
|
+
let b = list[(i + 1) % list.length];
|
|
27599
|
+
let gap = i + 1 < list.length ? b.angle - a.angle : b.angle + 2 * Math.PI - a.angle;
|
|
27600
|
+
if (gap > 1e-9) r = Math.max(r, (a.diag / 2 + b.diag / 2 + o.nodesep) / gap);
|
|
27601
|
+
}
|
|
27602
|
+
radius[ring] = r;
|
|
27603
|
+
}
|
|
27604
|
+
for (let [id, a] of angle) {
|
|
27605
|
+
let r = radius[ring_of(id)] || 0;
|
|
27606
|
+
pos.set(id, {
|
|
27607
|
+
x: r * Math.cos(a),
|
|
27608
|
+
y: r * Math.sin(a)
|
|
27609
|
+
});
|
|
27610
|
+
}
|
|
27611
|
+
return pos;
|
|
27612
|
+
}
|
|
27613
|
+
/************************************************************
|
|
27614
|
+
* The outline: one node per row, indented by depth, in the
|
|
27615
|
+
* pre-order of the spanning tree. Rows are left-aligned on
|
|
27616
|
+
* their indent, so a column of chips reads as a list.
|
|
27617
|
+
************************************************************/
|
|
27618
|
+
function layout_outline(nodes, edges, opts) {
|
|
27619
|
+
let o = Object.assign({}, DEFAULTS, opts || {});
|
|
27620
|
+
let t = spanning_tree(nodes, edges);
|
|
27621
|
+
let pos = /* @__PURE__ */ new Map();
|
|
27622
|
+
let y = 0;
|
|
27623
|
+
let visit = (id) => {
|
|
27624
|
+
let n = t.by_id.get(id);
|
|
27625
|
+
let d = t.depth.get(id);
|
|
27626
|
+
pos.set(id, {
|
|
27627
|
+
x: d * o.indent + n.w / 2,
|
|
27628
|
+
y: y + n.h / 2
|
|
27629
|
+
});
|
|
27630
|
+
y += n.h + o.nodesep;
|
|
27631
|
+
for (let kid of t.children.get(id) || []) visit(kid);
|
|
27632
|
+
};
|
|
27633
|
+
for (let root of t.roots) {
|
|
27634
|
+
visit(root);
|
|
27635
|
+
y += o.nodesep;
|
|
27636
|
+
}
|
|
27637
|
+
return pos;
|
|
27638
|
+
}
|
|
27639
|
+
//#endregion
|
|
27317
27640
|
//#region node_modules/@babel/runtime/helpers/esm/typeof.js
|
|
27318
27641
|
function _typeof(o) {
|
|
27319
27642
|
"@babel/helpers - typeof";
|
|
@@ -54134,6 +54457,16 @@ var SELECT_RING = "rgba(59,130,246,0.95)";
|
|
|
54134
54457
|
***************************************************************/
|
|
54135
54458
|
var _layouts = {
|
|
54136
54459
|
"manual": { type: "manual" },
|
|
54460
|
+
"treedb-tree": {
|
|
54461
|
+
type: "treedb-tree",
|
|
54462
|
+
nodesep: 18,
|
|
54463
|
+
ranksep: 110
|
|
54464
|
+
},
|
|
54465
|
+
"treedb-outline": {
|
|
54466
|
+
type: "treedb-outline",
|
|
54467
|
+
nodesep: 12,
|
|
54468
|
+
indent: 48
|
|
54469
|
+
},
|
|
54137
54470
|
"dagre": {
|
|
54138
54471
|
type: "dagre",
|
|
54139
54472
|
rankdir: "LR",
|
|
@@ -54146,6 +54479,11 @@ var _layouts = {
|
|
|
54146
54479
|
nodesep: 30,
|
|
54147
54480
|
ranksep: 80
|
|
54148
54481
|
},
|
|
54482
|
+
"radial": {
|
|
54483
|
+
type: "treedb-radial",
|
|
54484
|
+
nodesep: 24,
|
|
54485
|
+
ranksep: 180
|
|
54486
|
+
},
|
|
54149
54487
|
"d3-force": {
|
|
54150
54488
|
type: "d3-force",
|
|
54151
54489
|
link: {
|
|
@@ -54425,6 +54763,9 @@ function register_layouts(gobj) {
|
|
|
54425
54763
|
if (!_g6_extensions_registered) {
|
|
54426
54764
|
_g6_extensions_registered = true;
|
|
54427
54765
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "manual", ManualLayout);
|
|
54766
|
+
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-tree", TreedbTreeLayout);
|
|
54767
|
+
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-outline", TreedbOutlineLayout);
|
|
54768
|
+
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-radial", TreedbRadialLayout);
|
|
54428
54769
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.NODE, "light", LightNode);
|
|
54429
54770
|
}
|
|
54430
54771
|
}
|
|
@@ -55036,8 +55377,13 @@ function build_ports(gobj, desc) {
|
|
|
55036
55377
|
* included, because the saved arrangements were made with the
|
|
55037
55378
|
* ports on the top and bottom edges.
|
|
55038
55379
|
************************************************************/
|
|
55380
|
+
var LR_LAYOUTS = [
|
|
55381
|
+
"dagre",
|
|
55382
|
+
"treedb-tree",
|
|
55383
|
+
"treedb-outline"
|
|
55384
|
+
];
|
|
55039
55385
|
function layout_direction(gobj) {
|
|
55040
|
-
return gobj.priv.layout
|
|
55386
|
+
return (0, _yuneta_gobj_js.str_in_list)(LR_LAYOUTS, gobj.priv.layout) ? "LR" : "TB";
|
|
55041
55387
|
}
|
|
55042
55388
|
function edge_type_for(gobj) {
|
|
55043
55389
|
return layout_direction(gobj) === "LR" ? "cubic-horizontal" : "cubic";
|
|
@@ -56037,6 +56383,73 @@ var ManualLayout = class extends _antv_g6.BaseLayout {
|
|
|
56037
56383
|
}
|
|
56038
56384
|
};
|
|
56039
56385
|
/************************************************************
|
|
56386
|
+
* Custom G6 layouts: TreedbTreeLayout / TreedbOutlineLayout.
|
|
56387
|
+
*
|
|
56388
|
+
* Thin adapters over treedb_layout.js: the nodes with their sizes,
|
|
56389
|
+
* the edges with the RANK of the hook they leave by (the position
|
|
56390
|
+
* of the source port in the parent's ports, which is the schema's
|
|
56391
|
+
* column order), and the positions back. A `+N` chip's edge has a
|
|
56392
|
+
* source port too, so the chip sits at the end of its hook's
|
|
56393
|
+
* children, where the page ends.
|
|
56394
|
+
************************************************************/
|
|
56395
|
+
function treedb_layout_input(data) {
|
|
56396
|
+
const { nodes = [], edges = [] } = data;
|
|
56397
|
+
let ports_of = /* @__PURE__ */ new Map();
|
|
56398
|
+
return {
|
|
56399
|
+
nodes: nodes.map((node) => {
|
|
56400
|
+
let size = node.style && node.style.size || [172, 96];
|
|
56401
|
+
let w = (0, _yuneta_gobj_js.is_array)(size) ? size[0] : size;
|
|
56402
|
+
let h = (0, _yuneta_gobj_js.is_array)(size) ? size.length > 1 ? size[1] : size[0] : size;
|
|
56403
|
+
let ports = node.style && (0, _yuneta_gobj_js.is_array)(node.style.ports) ? node.style.ports : [];
|
|
56404
|
+
ports_of.set(node.id, ports.map((p) => p.key));
|
|
56405
|
+
return {
|
|
56406
|
+
id: node.id,
|
|
56407
|
+
w,
|
|
56408
|
+
h
|
|
56409
|
+
};
|
|
56410
|
+
}),
|
|
56411
|
+
edges: edges.map((edge) => {
|
|
56412
|
+
let port = edge.style ? edge.style.sourcePort : void 0;
|
|
56413
|
+
let keys = ports_of.get(edge.source) || [];
|
|
56414
|
+
let rank = port ? keys.indexOf(port) : -1;
|
|
56415
|
+
return {
|
|
56416
|
+
source: edge.source,
|
|
56417
|
+
target: edge.target,
|
|
56418
|
+
rank: rank >= 0 ? rank : 0
|
|
56419
|
+
};
|
|
56420
|
+
})
|
|
56421
|
+
};
|
|
56422
|
+
}
|
|
56423
|
+
function treedb_layout_output(pos) {
|
|
56424
|
+
let out = [];
|
|
56425
|
+
for (let [id, p] of pos) out.push({
|
|
56426
|
+
id,
|
|
56427
|
+
style: {
|
|
56428
|
+
x: p.x,
|
|
56429
|
+
y: p.y
|
|
56430
|
+
}
|
|
56431
|
+
});
|
|
56432
|
+
return { nodes: out };
|
|
56433
|
+
}
|
|
56434
|
+
var TreedbTreeLayout = class extends _antv_g6.BaseLayout {
|
|
56435
|
+
async execute(data, options) {
|
|
56436
|
+
let input = treedb_layout_input(data);
|
|
56437
|
+
return treedb_layout_output(layout_tree(input.nodes, input.edges, options));
|
|
56438
|
+
}
|
|
56439
|
+
};
|
|
56440
|
+
var TreedbOutlineLayout = class extends _antv_g6.BaseLayout {
|
|
56441
|
+
async execute(data, options) {
|
|
56442
|
+
let input = treedb_layout_input(data);
|
|
56443
|
+
return treedb_layout_output(layout_outline(input.nodes, input.edges, options));
|
|
56444
|
+
}
|
|
56445
|
+
};
|
|
56446
|
+
var TreedbRadialLayout = class extends _antv_g6.BaseLayout {
|
|
56447
|
+
async execute(data, options) {
|
|
56448
|
+
let input = treedb_layout_input(data);
|
|
56449
|
+
return treedb_layout_output(layout_radial(input.nodes, input.edges, options));
|
|
56450
|
+
}
|
|
56451
|
+
};
|
|
56452
|
+
/************************************************************
|
|
56040
56453
|
* Node selection and resize handles
|
|
56041
56454
|
************************************************************/
|
|
56042
56455
|
var RESIZE_HANDLE_SIZE = 8;
|
|
@@ -57698,7 +58111,7 @@ function auto_layout(gobj) {
|
|
|
57698
58111
|
if (priv._layout_asked) return false;
|
|
57699
58112
|
if (priv._nodes_total > 0 && priv._nodes_placed * 2 > priv._nodes_total) return false;
|
|
57700
58113
|
if (!priv.graph) return false;
|
|
57701
|
-
let name = "
|
|
58114
|
+
let name = "treedb-tree";
|
|
57702
58115
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "layout", name);
|
|
57703
58116
|
try {
|
|
57704
58117
|
priv.graph.setLayout(_layouts[name]);
|
|
@@ -60535,6 +60948,9 @@ function option_label(name) {
|
|
|
60535
60948
|
case "writing": return (0, i18next.t)("writing");
|
|
60536
60949
|
case "edition": return (0, i18next.t)("edition");
|
|
60537
60950
|
case "manual": return (0, i18next.t)("manual");
|
|
60951
|
+
case "treedb-tree": return (0, i18next.t)("treedb-tree");
|
|
60952
|
+
case "treedb-outline": return (0, i18next.t)("treedb-outline");
|
|
60953
|
+
case "radial": return (0, i18next.t)("radial");
|
|
60538
60954
|
case "dagre": return (0, i18next.t)("dagre");
|
|
60539
60955
|
case "antv-dagre": return (0, i18next.t)("antv-dagre");
|
|
60540
60956
|
case "d3-force": return (0, i18next.t)("d3-force");
|
|
@@ -61638,6 +62054,7 @@ function ac_set_operation_mode(gobj, event, kw, src) {
|
|
|
61638
62054
|
* card's graph icon travels — as EV_TOPIC_SELECTED, which the host turns
|
|
61639
62055
|
* into the URL, so what you are looking at stays linkable.
|
|
61640
62056
|
************************************************************/
|
|
62057
|
+
var LEGEND_GLYPH_STYLE = "font-size:1.5em; line-height:1; color:inherit;";
|
|
61641
62058
|
function refresh_legend(gobj) {
|
|
61642
62059
|
let priv = gobj.priv;
|
|
61643
62060
|
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
@@ -61707,7 +62124,11 @@ function refresh_legend(gobj) {
|
|
|
61707
62124
|
"aria-label": (0, i18next.t)("main topic"),
|
|
61708
62125
|
"aria-pressed": "true"
|
|
61709
62126
|
},
|
|
61710
|
-
|
|
62127
|
+
[[
|
|
62128
|
+
"span",
|
|
62129
|
+
{ style: LEGEND_GLYPH_STYLE },
|
|
62130
|
+
"★"
|
|
62131
|
+
]],
|
|
61711
62132
|
{ click: (evt) => {
|
|
61712
62133
|
evt.stopPropagation();
|
|
61713
62134
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_LEGEND_TOPIC", {
|
|
@@ -61724,7 +62145,11 @@ function refresh_legend(gobj) {
|
|
|
61724
62145
|
title: (0, i18next.t)("main topic"),
|
|
61725
62146
|
"data-i18n-title": "main topic"
|
|
61726
62147
|
},
|
|
61727
|
-
|
|
62148
|
+
[[
|
|
62149
|
+
"span",
|
|
62150
|
+
{ style: LEGEND_GLYPH_STYLE },
|
|
62151
|
+
"★"
|
|
62152
|
+
]]
|
|
61728
62153
|
]);
|
|
61729
62154
|
else if (!hidden) extras.push([
|
|
61730
62155
|
"button",
|
|
@@ -61736,7 +62161,11 @@ function refresh_legend(gobj) {
|
|
|
61736
62161
|
"data-i18n-title": "main topic",
|
|
61737
62162
|
"aria-label": (0, i18next.t)("main topic")
|
|
61738
62163
|
},
|
|
61739
|
-
|
|
62164
|
+
[[
|
|
62165
|
+
"span",
|
|
62166
|
+
{ style: LEGEND_GLYPH_STYLE },
|
|
62167
|
+
"☆"
|
|
62168
|
+
]],
|
|
61740
62169
|
{ click: (evt) => {
|
|
61741
62170
|
evt.stopPropagation();
|
|
61742
62171
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_LEGEND_TOPIC", {
|
|
@@ -61776,7 +62205,10 @@ function refresh_legend(gobj) {
|
|
|
61776
62205
|
"aria-label": (0, i18next.t)("highlight topic"),
|
|
61777
62206
|
"aria-pressed": focused ? "true" : "false"
|
|
61778
62207
|
},
|
|
61779
|
-
[["i", {
|
|
62208
|
+
[["i", {
|
|
62209
|
+
class: "yi-location-crosshairs",
|
|
62210
|
+
style: LEGEND_GLYPH_STYLE
|
|
62211
|
+
}]],
|
|
61780
62212
|
{ click: (evt) => {
|
|
61781
62213
|
evt.stopPropagation();
|
|
61782
62214
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_LEGEND_TOPIC", {
|