@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/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
- const child_arcs = getChildArcs(pd);
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.sweep == null)
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;