@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/index.cjs
CHANGED
|
@@ -588,41 +588,63 @@ function getChildArcsFan(pd) {
|
|
|
588
588
|
|
|
589
589
|
// Circular midpoint that travels CCW from a -> b by half the CCW span
|
|
590
590
|
function midCCW(a, b) {
|
|
591
|
-
const d = (b - a + TAU) % TAU;
|
|
591
|
+
const d = (b - a + TAU) % TAU; // CCW delta in [0, 2π)
|
|
592
592
|
return norm(a + d / 2);
|
|
593
593
|
}
|
|
594
594
|
|
|
595
|
-
const
|
|
596
|
-
|
|
595
|
+
const key = (x) => (typeof x === "string" ? +x : x);
|
|
596
|
+
|
|
597
|
+
const byId = new Map(pd.map(d => [key(d.thisId), d]));
|
|
598
|
+
const childrenByParent = new Map(
|
|
599
|
+
pd.map(d => [
|
|
600
|
+
key(d.thisId),
|
|
601
|
+
// normalize children to numeric IDs; drop anything we can't resolve
|
|
602
|
+
(d.children || [])
|
|
603
|
+
.map(ch => (typeof ch === "object" ? ch.thisId : ch))
|
|
604
|
+
.map(key)
|
|
605
|
+
.filter(id => byId.has(id))
|
|
606
|
+
])
|
|
607
|
+
);
|
|
597
608
|
|
|
598
609
|
const child_arcs = [];
|
|
599
610
|
|
|
600
|
-
for (const
|
|
601
|
-
const
|
|
611
|
+
for (const parentRaw of pd) {
|
|
612
|
+
const pid = key(parentRaw.thisId);
|
|
613
|
+
const kids = childrenByParent.get(pid) || [];
|
|
602
614
|
if (kids.length < 2) continue;
|
|
603
615
|
|
|
604
616
|
// Sort children by angle (normalized) around the circle
|
|
605
617
|
const A = kids
|
|
606
|
-
.map(id =>
|
|
618
|
+
.map(id => {
|
|
619
|
+
const node = byId.get(id);
|
|
620
|
+
return node ? { id, a: norm(node.angle) } : null;
|
|
621
|
+
})
|
|
622
|
+
.filter(Boolean)
|
|
607
623
|
.sort((u, v) => u.a - v.a);
|
|
608
624
|
|
|
609
625
|
const N = A.length;
|
|
626
|
+
if (N < 2) continue;
|
|
627
|
+
|
|
628
|
+
const parent = byId.get(pid);
|
|
629
|
+
const radius = parent?.r;
|
|
630
|
+
if (!(radius > 0)) continue;
|
|
631
|
+
|
|
610
632
|
for (let i = 0; i < N; i++) {
|
|
611
633
|
const prev = A[(i - 1 + N) % N];
|
|
612
634
|
const cur = A[i];
|
|
613
635
|
const next = A[(i + 1) % N];
|
|
614
636
|
|
|
615
|
-
// “fan” wedge around the child: midpoint(prev→cur) .. midpoint(cur→next)
|
|
637
|
+
// “fan” wedge around the child: midpoint(prev→cur) .. midpoint(cur→next), CCW
|
|
616
638
|
const start = midCCW(prev.a, cur.a);
|
|
617
639
|
const end = midCCW(cur.a, next.a);
|
|
618
640
|
|
|
619
641
|
child_arcs.push({
|
|
620
|
-
parentId:
|
|
621
|
-
childId:
|
|
622
|
-
radius
|
|
642
|
+
parentId: pid,
|
|
643
|
+
childId: cur.id,
|
|
644
|
+
radius,
|
|
623
645
|
start,
|
|
624
646
|
end,
|
|
625
|
-
sweep:
|
|
647
|
+
sweep: 0 // CCW (consistent with describeArcSweep and your y-flip)
|
|
626
648
|
});
|
|
627
649
|
}
|
|
628
650
|
}
|
|
@@ -1598,7 +1620,7 @@ function drawPhylogeny(
|
|
|
1598
1620
|
let first = true;
|
|
1599
1621
|
while (cur && cur.parentId != null) {
|
|
1600
1622
|
// ----- spoke (parent → child) -----
|
|
1601
|
-
const s = spokeByChild.get(cur.thisId);
|
|
1623
|
+
const s = spokeByChild.get(key(cur.thisId));
|
|
1602
1624
|
if (s) {
|
|
1603
1625
|
const px = s.x0,
|
|
1604
1626
|
py = s.y0;
|
|
@@ -1622,23 +1644,21 @@ function drawPhylogeny(
|
|
|
1622
1644
|
}
|
|
1623
1645
|
|
|
1624
1646
|
// ----- half-arc at parent radius (parent.angle → child.angle) -----
|
|
1625
|
-
const a = arcByChild.get(cur.thisId);
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
}
|
|
1633
|
-
|
|
1647
|
+
const a = arcByChild.get(key(cur.thisId));
|
|
1648
|
+
function pathFromArcRecord(rec) {
|
|
1649
|
+
const R = radiusPx(rec.radius);
|
|
1650
|
+
return rec.sweep == null
|
|
1651
|
+
? describeArc(centerX, centerY, R, rec.start, rec.end)
|
|
1652
|
+
: describeArcSweep(centerX, centerY, R, rec.start, rec.end, rec.sweep);
|
|
1653
|
+
}
|
|
1634
1654
|
|
|
1655
|
+
if (a) {
|
|
1635
1656
|
arcLayer
|
|
1636
1657
|
.append("path")
|
|
1637
1658
|
.attr("d", pathFromArcRecord(a))
|
|
1638
1659
|
.attr("fill", "none")
|
|
1639
1660
|
.attr("stroke", stroke)
|
|
1640
1661
|
.attr("stroke-width", width);
|
|
1641
|
-
|
|
1642
1662
|
}
|
|
1643
1663
|
|
|
1644
1664
|
first = false;
|