@euphrasiologist/lwphylo 1.2.13 → 1.2.16
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 +78 -5
- package/dist/drawPhylogeny.cjs.map +1 -1
- package/dist/drawPhylogeny.esm.js +78 -5
- 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 +79 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +79 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -582,6 +582,54 @@ function getChildArcs(pd) {
|
|
|
582
582
|
return arcs;
|
|
583
583
|
}
|
|
584
584
|
|
|
585
|
+
function getChildArcsFan(pd) {
|
|
586
|
+
const TAU = Math.PI * 2;
|
|
587
|
+
const norm = (t) => ((t % TAU) + TAU) % TAU;
|
|
588
|
+
|
|
589
|
+
// Circular midpoint that travels CCW from a -> b by half the CCW span
|
|
590
|
+
function midCCW(a, b) {
|
|
591
|
+
const d = (b - a + TAU) % TAU; // CCW delta a->b in [0, 2π)
|
|
592
|
+
return norm(a + d / 2);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const byId = new Map(pd.map(d => [d.thisId, d]));
|
|
596
|
+
const childrenByParent = new Map(pd.map(d => [d.thisId, d.children || []]));
|
|
597
|
+
|
|
598
|
+
const child_arcs = [];
|
|
599
|
+
|
|
600
|
+
for (const parent of pd) {
|
|
601
|
+
const kids = childrenByParent.get(parent.thisId) || [];
|
|
602
|
+
if (kids.length < 2) continue;
|
|
603
|
+
|
|
604
|
+
// Sort children by angle (normalized) around the circle
|
|
605
|
+
const A = kids
|
|
606
|
+
.map(id => ({ id, a: norm(byId.get(id).angle) }))
|
|
607
|
+
.sort((u, v) => u.a - v.a);
|
|
608
|
+
|
|
609
|
+
const N = A.length;
|
|
610
|
+
for (let i = 0; i < N; i++) {
|
|
611
|
+
const prev = A[(i - 1 + N) % N];
|
|
612
|
+
const cur = A[i];
|
|
613
|
+
const next = A[(i + 1) % N];
|
|
614
|
+
|
|
615
|
+
// “fan” wedge around the child: midpoint(prev→cur) .. midpoint(cur→next)
|
|
616
|
+
const start = midCCW(prev.a, cur.a);
|
|
617
|
+
const end = midCCW(cur.a, next.a);
|
|
618
|
+
|
|
619
|
+
child_arcs.push({
|
|
620
|
+
parentId: parent.thisId,
|
|
621
|
+
childId: cur.id,
|
|
622
|
+
radius: parent.r, // IMPORTANT: draw at the PARENT circle
|
|
623
|
+
start,
|
|
624
|
+
end,
|
|
625
|
+
sweep: 0 // CCW (matches describeArcSweep usage)
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
return child_arcs;
|
|
631
|
+
}
|
|
632
|
+
|
|
585
633
|
// src/radial/radialLayout.js
|
|
586
634
|
|
|
587
635
|
/**
|
|
@@ -628,7 +676,12 @@ function radialLayout(node, opts = {}) {
|
|
|
628
676
|
: getArcs(pd);
|
|
629
677
|
|
|
630
678
|
// per-child arcs for half-arc highlighting if you already use them
|
|
631
|
-
|
|
679
|
+
let child_arcs = [];
|
|
680
|
+
if (opts.arcsStyle === "fan") {
|
|
681
|
+
child_arcs = getChildArcsFan(pd);
|
|
682
|
+
} else {
|
|
683
|
+
child_arcs = getChildArcs(pd);
|
|
684
|
+
}
|
|
632
685
|
|
|
633
686
|
return { data: pd, radii, arcs, child_arcs };
|
|
634
687
|
}
|
|
@@ -1350,6 +1403,29 @@ function drawPhylogeny(
|
|
|
1350
1403
|
return { X0, Y0, X1s: X0 + dx * t, Y1s: Y0 + dy * t, len };
|
|
1351
1404
|
}
|
|
1352
1405
|
|
|
1406
|
+
// put this next to your other radial helpers (top of file or in your lib)
|
|
1407
|
+
function arcPathCCW(cx, cy, R, a0, a1) {
|
|
1408
|
+
const TAU = Math.PI * 2;
|
|
1409
|
+
const norm = (t) => ((t % TAU) + TAU) % TAU;
|
|
1410
|
+
|
|
1411
|
+
a0 = norm(a0);
|
|
1412
|
+
a1 = norm(a1);
|
|
1413
|
+
|
|
1414
|
+
const delta = (a1 - a0 + TAU) % TAU; // CCW span a0 -> a1 in [0, 2π)
|
|
1415
|
+
if (delta < 1e-9) return ""; // degenerate; draw nothing
|
|
1416
|
+
|
|
1417
|
+
// With your polarToCartesian using y = cy - r*sin(t),
|
|
1418
|
+
// sweepFlag=0 gives a visually CCW arc segment.
|
|
1419
|
+
const largeArcFlag = delta > Math.PI ? 1 : 0;
|
|
1420
|
+
const sweepFlag = 0;
|
|
1421
|
+
|
|
1422
|
+
const p0 = polarToCartesian(cx, cy, R, a0);
|
|
1423
|
+
const p1 = polarToCartesian(cx, cy, R, a1);
|
|
1424
|
+
|
|
1425
|
+
return `M ${p0.x} ${p0.y} A ${R} ${R} 0 ${largeArcFlag} ${sweepFlag} ${p1.x} ${p1.y}`;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
|
|
1353
1429
|
// ===== SVG ROOT =====
|
|
1354
1430
|
const svg = d3__namespace
|
|
1355
1431
|
.create("svg")
|
|
@@ -1391,7 +1467,6 @@ function drawPhylogeny(
|
|
|
1391
1467
|
d.sweep
|
|
1392
1468
|
)
|
|
1393
1469
|
)
|
|
1394
|
-
|
|
1395
1470
|
.attr("fill", "none")
|
|
1396
1471
|
.attr("stroke", "#777")
|
|
1397
1472
|
.attr("stroke-width", strokeWidth);
|
|
@@ -1570,9 +1645,7 @@ function drawPhylogeny(
|
|
|
1570
1645
|
// ----- half-arc at parent radius (parent.angle → child.angle) -----
|
|
1571
1646
|
const a = arcByChild.get(cur.thisId);
|
|
1572
1647
|
if (a) {
|
|
1573
|
-
const pathD = (a.
|
|
1574
|
-
? describeArc(centerX, centerY, radiusPx(a.radius), a.start, a.end)
|
|
1575
|
-
: describeArcSweep(centerX, centerY, radiusPx(a.radius), a.start, a.end, a.sweep);
|
|
1648
|
+
const pathD = arcPathCCW(centerX, centerY, radiusPx(a.radius), a.start, a.end);
|
|
1576
1649
|
|
|
1577
1650
|
arcLayer
|
|
1578
1651
|
.append("path")
|
|
@@ -1833,6 +1906,7 @@ exports.describeArcSweep = describeArcSweep;
|
|
|
1833
1906
|
exports.drawPhylogeny = drawPhylogeny;
|
|
1834
1907
|
exports.parentFisheye = parentFisheye;
|
|
1835
1908
|
exports.phisheye = phisheye;
|
|
1909
|
+
exports.polarToCartesian = polarToCartesian;
|
|
1836
1910
|
exports.radialLayout = radialLayout;
|
|
1837
1911
|
exports.readTree = readTree;
|
|
1838
1912
|
exports.rectangleLayout = rectangleLayout;
|