@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.js
CHANGED
|
@@ -567,41 +567,63 @@ function getChildArcsFan(pd) {
|
|
|
567
567
|
|
|
568
568
|
// Circular midpoint that travels CCW from a -> b by half the CCW span
|
|
569
569
|
function midCCW(a, b) {
|
|
570
|
-
const d = (b - a + TAU) % TAU;
|
|
570
|
+
const d = (b - a + TAU) % TAU; // CCW delta in [0, 2π)
|
|
571
571
|
return norm(a + d / 2);
|
|
572
572
|
}
|
|
573
573
|
|
|
574
|
-
const
|
|
575
|
-
|
|
574
|
+
const key = (x) => (typeof x === "string" ? +x : x);
|
|
575
|
+
|
|
576
|
+
const byId = new Map(pd.map(d => [key(d.thisId), d]));
|
|
577
|
+
const childrenByParent = new Map(
|
|
578
|
+
pd.map(d => [
|
|
579
|
+
key(d.thisId),
|
|
580
|
+
// normalize children to numeric IDs; drop anything we can't resolve
|
|
581
|
+
(d.children || [])
|
|
582
|
+
.map(ch => (typeof ch === "object" ? ch.thisId : ch))
|
|
583
|
+
.map(key)
|
|
584
|
+
.filter(id => byId.has(id))
|
|
585
|
+
])
|
|
586
|
+
);
|
|
576
587
|
|
|
577
588
|
const child_arcs = [];
|
|
578
589
|
|
|
579
|
-
for (const
|
|
580
|
-
const
|
|
590
|
+
for (const parentRaw of pd) {
|
|
591
|
+
const pid = key(parentRaw.thisId);
|
|
592
|
+
const kids = childrenByParent.get(pid) || [];
|
|
581
593
|
if (kids.length < 2) continue;
|
|
582
594
|
|
|
583
595
|
// Sort children by angle (normalized) around the circle
|
|
584
596
|
const A = kids
|
|
585
|
-
.map(id =>
|
|
597
|
+
.map(id => {
|
|
598
|
+
const node = byId.get(id);
|
|
599
|
+
return node ? { id, a: norm(node.angle) } : null;
|
|
600
|
+
})
|
|
601
|
+
.filter(Boolean)
|
|
586
602
|
.sort((u, v) => u.a - v.a);
|
|
587
603
|
|
|
588
604
|
const N = A.length;
|
|
605
|
+
if (N < 2) continue;
|
|
606
|
+
|
|
607
|
+
const parent = byId.get(pid);
|
|
608
|
+
const radius = parent?.r;
|
|
609
|
+
if (!(radius > 0)) continue;
|
|
610
|
+
|
|
589
611
|
for (let i = 0; i < N; i++) {
|
|
590
612
|
const prev = A[(i - 1 + N) % N];
|
|
591
613
|
const cur = A[i];
|
|
592
614
|
const next = A[(i + 1) % N];
|
|
593
615
|
|
|
594
|
-
// “fan” wedge around the child: midpoint(prev→cur) .. midpoint(cur→next)
|
|
616
|
+
// “fan” wedge around the child: midpoint(prev→cur) .. midpoint(cur→next), CCW
|
|
595
617
|
const start = midCCW(prev.a, cur.a);
|
|
596
618
|
const end = midCCW(cur.a, next.a);
|
|
597
619
|
|
|
598
620
|
child_arcs.push({
|
|
599
|
-
parentId:
|
|
600
|
-
childId:
|
|
601
|
-
radius
|
|
621
|
+
parentId: pid,
|
|
622
|
+
childId: cur.id,
|
|
623
|
+
radius,
|
|
602
624
|
start,
|
|
603
625
|
end,
|
|
604
|
-
sweep:
|
|
626
|
+
sweep: 0 // CCW (consistent with describeArcSweep and your y-flip)
|
|
605
627
|
});
|
|
606
628
|
}
|
|
607
629
|
}
|
|
@@ -1577,7 +1599,7 @@ function drawPhylogeny(
|
|
|
1577
1599
|
let first = true;
|
|
1578
1600
|
while (cur && cur.parentId != null) {
|
|
1579
1601
|
// ----- spoke (parent → child) -----
|
|
1580
|
-
const s = spokeByChild.get(cur.thisId);
|
|
1602
|
+
const s = spokeByChild.get(key(cur.thisId));
|
|
1581
1603
|
if (s) {
|
|
1582
1604
|
const px = s.x0,
|
|
1583
1605
|
py = s.y0;
|
|
@@ -1601,23 +1623,21 @@ function drawPhylogeny(
|
|
|
1601
1623
|
}
|
|
1602
1624
|
|
|
1603
1625
|
// ----- half-arc at parent radius (parent.angle → child.angle) -----
|
|
1604
|
-
const a = arcByChild.get(cur.thisId);
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
}
|
|
1612
|
-
|
|
1626
|
+
const a = arcByChild.get(key(cur.thisId));
|
|
1627
|
+
function pathFromArcRecord(rec) {
|
|
1628
|
+
const R = radiusPx(rec.radius);
|
|
1629
|
+
return rec.sweep == null
|
|
1630
|
+
? describeArc(centerX, centerY, R, rec.start, rec.end)
|
|
1631
|
+
: describeArcSweep(centerX, centerY, R, rec.start, rec.end, rec.sweep);
|
|
1632
|
+
}
|
|
1613
1633
|
|
|
1634
|
+
if (a) {
|
|
1614
1635
|
arcLayer
|
|
1615
1636
|
.append("path")
|
|
1616
1637
|
.attr("d", pathFromArcRecord(a))
|
|
1617
1638
|
.attr("fill", "none")
|
|
1618
1639
|
.attr("stroke", stroke)
|
|
1619
1640
|
.attr("stroke-width", width);
|
|
1620
|
-
|
|
1621
1641
|
}
|
|
1622
1642
|
|
|
1623
1643
|
first = false;
|