@euphrasiologist/lwphylo 1.2.18 → 1.2.19
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/dist/drawPhylogeny.cjs +42 -22
- package/dist/drawPhylogeny.cjs.map +1 -1
- package/dist/drawPhylogeny.esm.js +42 -22
- package/dist/drawPhylogeny.esm.js.map +1 -1
- package/dist/drawPhylogeny.umd.js +1 -1
- package/dist/drawPhylogeny.umd.js.map +1 -1
- package/dist/index.cjs +42 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +42 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/drawPhylogeny.cjs
CHANGED
|
@@ -475,41 +475,63 @@ function getChildArcsFan(pd) {
|
|
|
475
475
|
|
|
476
476
|
// Circular midpoint that travels CCW from a -> b by half the CCW span
|
|
477
477
|
function midCCW(a, b) {
|
|
478
|
-
const d = (b - a + TAU) % TAU;
|
|
478
|
+
const d = (b - a + TAU) % TAU; // CCW delta in [0, 2π)
|
|
479
479
|
return norm(a + d / 2);
|
|
480
480
|
}
|
|
481
481
|
|
|
482
|
-
const
|
|
483
|
-
|
|
482
|
+
const key = (x) => (typeof x === "string" ? +x : x);
|
|
483
|
+
|
|
484
|
+
const byId = new Map(pd.map(d => [key(d.thisId), d]));
|
|
485
|
+
const childrenByParent = new Map(
|
|
486
|
+
pd.map(d => [
|
|
487
|
+
key(d.thisId),
|
|
488
|
+
// normalize children to numeric IDs; drop anything we can't resolve
|
|
489
|
+
(d.children || [])
|
|
490
|
+
.map(ch => (typeof ch === "object" ? ch.thisId : ch))
|
|
491
|
+
.map(key)
|
|
492
|
+
.filter(id => byId.has(id))
|
|
493
|
+
])
|
|
494
|
+
);
|
|
484
495
|
|
|
485
496
|
const child_arcs = [];
|
|
486
497
|
|
|
487
|
-
for (const
|
|
488
|
-
const
|
|
498
|
+
for (const parentRaw of pd) {
|
|
499
|
+
const pid = key(parentRaw.thisId);
|
|
500
|
+
const kids = childrenByParent.get(pid) || [];
|
|
489
501
|
if (kids.length < 2) continue;
|
|
490
502
|
|
|
491
503
|
// Sort children by angle (normalized) around the circle
|
|
492
504
|
const A = kids
|
|
493
|
-
.map(id =>
|
|
505
|
+
.map(id => {
|
|
506
|
+
const node = byId.get(id);
|
|
507
|
+
return node ? { id, a: norm(node.angle) } : null;
|
|
508
|
+
})
|
|
509
|
+
.filter(Boolean)
|
|
494
510
|
.sort((u, v) => u.a - v.a);
|
|
495
511
|
|
|
496
512
|
const N = A.length;
|
|
513
|
+
if (N < 2) continue;
|
|
514
|
+
|
|
515
|
+
const parent = byId.get(pid);
|
|
516
|
+
const radius = parent?.r;
|
|
517
|
+
if (!(radius > 0)) continue;
|
|
518
|
+
|
|
497
519
|
for (let i = 0; i < N; i++) {
|
|
498
520
|
const prev = A[(i - 1 + N) % N];
|
|
499
521
|
const cur = A[i];
|
|
500
522
|
const next = A[(i + 1) % N];
|
|
501
523
|
|
|
502
|
-
// “fan” wedge around the child: midpoint(prev→cur) .. midpoint(cur→next)
|
|
524
|
+
// “fan” wedge around the child: midpoint(prev→cur) .. midpoint(cur→next), CCW
|
|
503
525
|
const start = midCCW(prev.a, cur.a);
|
|
504
526
|
const end = midCCW(cur.a, next.a);
|
|
505
527
|
|
|
506
528
|
child_arcs.push({
|
|
507
|
-
parentId:
|
|
508
|
-
childId:
|
|
509
|
-
radius
|
|
529
|
+
parentId: pid,
|
|
530
|
+
childId: cur.id,
|
|
531
|
+
radius,
|
|
510
532
|
start,
|
|
511
533
|
end,
|
|
512
|
-
sweep:
|
|
534
|
+
sweep: 0 // CCW (consistent with describeArcSweep and your y-flip)
|
|
513
535
|
});
|
|
514
536
|
}
|
|
515
537
|
}
|
|
@@ -1431,7 +1453,7 @@ function drawPhylogeny(
|
|
|
1431
1453
|
let first = true;
|
|
1432
1454
|
while (cur && cur.parentId != null) {
|
|
1433
1455
|
// ----- spoke (parent → child) -----
|
|
1434
|
-
const s = spokeByChild.get(cur.thisId);
|
|
1456
|
+
const s = spokeByChild.get(key(cur.thisId));
|
|
1435
1457
|
if (s) {
|
|
1436
1458
|
const px = s.x0,
|
|
1437
1459
|
py = s.y0;
|
|
@@ -1455,23 +1477,21 @@ function drawPhylogeny(
|
|
|
1455
1477
|
}
|
|
1456
1478
|
|
|
1457
1479
|
// ----- half-arc at parent radius (parent.angle → child.angle) -----
|
|
1458
|
-
const a = arcByChild.get(cur.thisId);
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1480
|
+
const a = arcByChild.get(key(cur.thisId));
|
|
1481
|
+
function pathFromArcRecord(rec) {
|
|
1482
|
+
const R = radiusPx(rec.radius);
|
|
1483
|
+
return rec.sweep == null
|
|
1484
|
+
? describeArc(centerX, centerY, R, rec.start, rec.end)
|
|
1485
|
+
: describeArcSweep(centerX, centerY, R, rec.start, rec.end, rec.sweep);
|
|
1486
|
+
}
|
|
1467
1487
|
|
|
1488
|
+
if (a) {
|
|
1468
1489
|
arcLayer
|
|
1469
1490
|
.append("path")
|
|
1470
1491
|
.attr("d", pathFromArcRecord(a))
|
|
1471
1492
|
.attr("fill", "none")
|
|
1472
1493
|
.attr("stroke", stroke)
|
|
1473
1494
|
.attr("stroke-width", width);
|
|
1474
|
-
|
|
1475
1495
|
}
|
|
1476
1496
|
|
|
1477
1497
|
first = false;
|