@yuneta/gobj-ui 7.23.154 → 7.23.156
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 +21 -3
- package/dist/gobj-ui.cjs.js +365 -72
- package/dist/gobj-ui.es.js +366 -73
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +61 -5
- package/src/treedb_elbow.js +113 -0
- package/src/treedb_elbow.test.js +45 -1
- package/src/treedb_layout.js +274 -83
- package/src/treedb_layout.test.js +95 -2
|
@@ -325,7 +325,7 @@ describe("the tidy tree, read right", () => {
|
|
|
325
325
|
|
|
326
326
|
describe("the radial tree", () => {
|
|
327
327
|
test("one root sits at the centre, its children on a ring around it", () => {
|
|
328
|
-
let pos = layout_radial(nodes, edges, {nodesep: 10, ranksep: 100});
|
|
328
|
+
let pos = layout_radial(nodes, edges, {nodesep: 10, ranksep: 100, stack: false});
|
|
329
329
|
expect(pos.get("es")).toEqual({x: 0, y: 0});
|
|
330
330
|
let r = Math.hypot(pos.get("norte").x, pos.get("norte").y);
|
|
331
331
|
expect(r).toBeGreaterThanOrEqual(100);
|
|
@@ -346,7 +346,7 @@ describe("the radial tree", () => {
|
|
|
346
346
|
many.push(N(`k${i}`, 172, 96));
|
|
347
347
|
e.push({source: "root", target: `k${i}`, rank: 0});
|
|
348
348
|
}
|
|
349
|
-
let pos = layout_radial(many, e, {nodesep: 10, ranksep: 100});
|
|
349
|
+
let pos = layout_radial(many, e, {nodesep: 10, ranksep: 100, stack: false});
|
|
350
350
|
let r = Math.hypot(pos.get("k0").x, pos.get("k0").y);
|
|
351
351
|
/* 40 diagonals of ~197 plus gaps on the circumference */
|
|
352
352
|
expect(2 * Math.PI * r).toBeGreaterThanOrEqual(40 * (Math.hypot(172, 96) + 10) - 1e-6);
|
|
@@ -380,6 +380,99 @@ describe("the radial tree", () => {
|
|
|
380
380
|
});
|
|
381
381
|
});
|
|
382
382
|
|
|
383
|
+
/* No two cards of `list` overlap (axis-aligned boxes). */
|
|
384
|
+
function expect_no_card_overlap(list, pos)
|
|
385
|
+
{
|
|
386
|
+
for(let i = 0; i < list.length; i++) {
|
|
387
|
+
for(let j = i + 1; j < list.length; j++) {
|
|
388
|
+
let a = list[i];
|
|
389
|
+
let b = list[j];
|
|
390
|
+
let pa = pos.get(a.id);
|
|
391
|
+
let pb = pos.get(b.id);
|
|
392
|
+
let apart_x = Math.abs(pa.x - pb.x) >= (a.w + b.w) / 2 - 1e-6;
|
|
393
|
+
let apart_y = Math.abs(pa.y - pb.y) >= (a.h + b.h) / 2 - 1e-6;
|
|
394
|
+
expect(apart_x || apart_y, `${a.id} and ${b.id} overlap`).toBe(true);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/* A treedb shaped like the central one: a root, 25 regions with a
|
|
400
|
+
* few places each, and one hall with 24 devices. */
|
|
401
|
+
function central_like()
|
|
402
|
+
{
|
|
403
|
+
let list = [N("es", 172, 96)];
|
|
404
|
+
let links = [];
|
|
405
|
+
let seed = 7;
|
|
406
|
+
let rnd = () => {
|
|
407
|
+
seed = (seed * 1103515245 + 12345) & 0x7fffffff;
|
|
408
|
+
return seed / 0x7fffffff;
|
|
409
|
+
};
|
|
410
|
+
for(let p = 0; p < 25; p++) {
|
|
411
|
+
list.push(N(`p${p}`, 172, 96));
|
|
412
|
+
links.push({source: "es", target: `p${p}`});
|
|
413
|
+
let n = 3 + Math.floor(rnd() * 5);
|
|
414
|
+
for(let s = 0; s < n; s++) {
|
|
415
|
+
list.push(N(`p${p}s${s}`, 172, 96));
|
|
416
|
+
links.push({source: `p${p}`, target: `p${p}s${s}`});
|
|
417
|
+
if(p === 3 && s === 1) {
|
|
418
|
+
for(let d = 0; d < 24; d++) {
|
|
419
|
+
list.push(N(`p${p}s${s}d${d}`, 116, 40));
|
|
420
|
+
links.push({source: `p${p}s${s}`, target: `p${p}s${s}d${d}`});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return {list, links};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
describe("the radial tree stacks a run of leaves", () => {
|
|
429
|
+
const HUB = [N("hub", 172, 96)].concat([...Array(24).keys()].map((i) => N(`d${i}`, 116, 40)));
|
|
430
|
+
const SPOKES = HUB.slice(1).map((n) => ({source: "hub", target: n.id}));
|
|
431
|
+
const OPTS = {nodesep: 24, ranksep: 180};
|
|
432
|
+
const reach = (list, pos) => Math.max(...list.map((n) => Math.hypot(pos.get(n.id).x, pos.get(n.id).y)));
|
|
433
|
+
|
|
434
|
+
test("a hub with 24 leaves: rows outward instead of one wide ring", () => {
|
|
435
|
+
let flat = layout_radial(HUB, SPOKES, Object.assign({stack: false}, OPTS));
|
|
436
|
+
let pos = layout_radial(HUB, SPOKES, OPTS);
|
|
437
|
+
/* Small cards wholly round their parent: each row makes room
|
|
438
|
+
* for a card at its worst slant, so the gain is least here --
|
|
439
|
+
* smaller all the same, and nothing overlaps. */
|
|
440
|
+
expect(reach(HUB, pos)).toBeLessThan(reach(HUB, flat));
|
|
441
|
+
expect_no_card_overlap(HUB, pos);
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
test("big cards round a parent, alone on their ring: no two overlap", () => {
|
|
445
|
+
/* 25 regions under a root, cards 172x96: rings round it, where
|
|
446
|
+
* a card stands at every angle. */
|
|
447
|
+
let list = [N("es", 172, 96)].concat([...Array(25).keys()].map((i) => N(`p${i}`, 172, 96)));
|
|
448
|
+
let links = list.slice(1).map((n) => ({source: "es", target: n.id}));
|
|
449
|
+
expect_no_card_overlap(list, layout_radial(list, links, OPTS));
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
test("the rows of a stack go outward, filled in order", () => {
|
|
453
|
+
let pos = layout_radial(HUB, SPOKES, OPTS);
|
|
454
|
+
let r = (id) => Math.hypot(pos.get(id).x, pos.get(id).y);
|
|
455
|
+
for(let i = 1; i < 24; i++) {
|
|
456
|
+
expect(r(`d${i}`)).toBeGreaterThanOrEqual(r(`d${i - 1}`) - 1e-6);
|
|
457
|
+
}
|
|
458
|
+
expect(r("d23")).toBeGreaterThan(r("d0"));
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test("a treedb shaped like a real one: no two cards overlap, and it is smaller", () => {
|
|
462
|
+
let {list, links} = central_like();
|
|
463
|
+
let flat = layout_radial(list, links, Object.assign({stack: false}, OPTS));
|
|
464
|
+
let pos = layout_radial(list, links, OPTS);
|
|
465
|
+
expect_no_card_overlap(list, pos);
|
|
466
|
+
expect(reach(list, pos)).toBeLessThan(reach(list, flat));
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
test("without leaves in runs it is the radial it was", () => {
|
|
470
|
+
let few = [N("r", 172, 96), N("a", 172, 96), N("b", 172, 96)];
|
|
471
|
+
let e2 = [{source: "r", target: "a"}, {source: "r", target: "b"}];
|
|
472
|
+
expect(layout_radial(few, e2, OPTS)).toEqual(layout_radial(few, e2, Object.assign({stack: false}, OPTS)));
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
|
|
383
476
|
describe("a deep tree", () => {
|
|
384
477
|
/* A self-referent hook -- a place inside a place inside a place --
|
|
385
478
|
* is as deep as the data says. The walks are iterative for exactly
|