@euphrasiologist/lwphylo 1.3.0 → 1.4.0

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.
@@ -1,2 +1,2 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("d3")):"function"==typeof define&&define.amd?define(["d3"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).lwPhyloPlot=e(t.d3)}(this,function(t){"use strict";function e(t){var e=Object.create(null);return t&&Object.keys(t).forEach(function(n){if("default"!==n){var a=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,a.get?a:{enumerable:!0,get:function(){return t[n]}})}}),e.default=t,Object.freeze(e)}var n=e(t);function a(t,e,n,a){return{x:t+n*Math.cos(a),y:e-n*Math.sin(a)}}function r(t,e,n,r,i){const s=2*Math.PI,l=t=>(t%s+s)%s;let o=l(r),c=l(i);if((o-c+s)%s<(c-o+s)%s){const t=o;o=c,c=t}const h=(c-o+s)%s;if(h<1e-9){const r=a(t,e,n,o);return`M ${r.x} ${r.y}`}const d=h>Math.PI?1:0,p=a(t,e,n,o),f=a(t,e,n,c);return`M ${p.x} ${p.y} A ${n} ${n} 0 ${d} 0 ${f.x} ${f.y}`}function i(t,e,n,a,r,i="ccw",s=0){if(!(n>0))return"";return`M ${t+n*Math.cos(a)} ${e-n*Math.sin(a)} A ${n} ${n} 0 ${s} ${"ccw"===i?0:1} ${t+n*Math.cos(r)} ${e-n*Math.sin(r)}`}function s(t,e=[]){e.push(t);for(let n=0;n<(t.children?.length||0);n++)e=s(t.children[n],e);return e}function l(t,e=!0){var n=[];for(const e of s(t))null===e.parent?n.push({parentId:null,parentLabel:null,thisId:e.id,thisLabel:e.label,children:e.children.map(t=>t.id),branchLength:0,isTip:!1,x:e.x,y:e.y,angle:e.angle}):n.push({parentId:e.parent.id,parentLabel:e.parent.label,thisId:e.id,thisLabel:e.label,children:e.children.map(t=>t.id),branchLength:e.branchLength,isTip:0==e.children.length,x:e.x,y:e.y,angle:e.angle});return e&&(n=n.sort(function(t,e){return t.thisId-e.thisId})),n}function o(t){const e=2*Math.PI,n=l(t,!0),a=new Map(n.map(t=>[t.thisId,t])),r=new Map(n.map(t=>[t.thisId,t.children||[]]));let i=null;for(const t of n)if(null==t.parentId){i=t.thisId;break}const s=[];!function t(e){const n=r.get(e)||[];if(0!==n.length)for(const e of n)t(e);else s.push(e)}(i);const o=Math.max(1,s.length),c=new Map;s.forEach((t,n)=>{c.set(t,n/o*e)}),function t(n){const a=r.get(n)||[];for(const e of a)t(e);if(a.length>0){let t=0,r=0;for(const e of a){const n=c.get(e);t+=Math.cos(n),r+=Math.sin(n)}c.set(n,(Math.atan2(r,t)%e+e)%e)}}(i);const h=new Map;h.set(i,0),function t(e){const n=r.get(e)||[],i=h.get(e)||0;for(const e of n){const n=a.get(e),r=n?.branchLength??0;h.set(e,i+r),t(e)}}(i);for(const t of n){const e=c.get(t.thisId)??0,n=h.get(t.thisId)??0;t.angle=e,t.r=n,t.x=n*Math.cos(e),t.y=n*Math.sin(e)}return n}const c=2*Math.PI,h=t=>(t%c+c)%c;function d(t,e={}){const{openAngleDeg:n=0,rotateDeg:a=0}=e,r=n/360*c,i=a/360*c;let s=null;const l=new Map(t.map(t=>[t.thisId,t.children||[]]));for(const e of t)if(null==e.parentId){s=e.thisId;break}const o=[];!function t(e){const n=l.get(e)||[];if(n.length)for(const e of n)t(e);else o.push(e)}(s);const d=Math.max(1,o.length),p=d>1?(c*(1-1/d)-r)/(d-1):0,f=new Map;return o.forEach((t,e)=>f.set(t,h(e*p+i))),function t(e){const n=l.get(e)||[];for(const e of n)t(e);if(n.length){const t=f.get(n[0]),a=n.map(e=>function(t,e){let n=e;for(;n<t-Math.PI;)n+=c;for(;n>t+Math.PI;)n-=c;return n}(t,f.get(e)));f.set(e,h(a.reduce((t,e)=>t+e,0)/a.length))}}(s),f}function p(t,e={}){const{angleStrategy:n="fan",arcsStyle:a="fan",openAngleDeg:r=0,rotateDeg:i=0}=e,s=o(t);if("fan"===n){const t=d(s,{openAngleDeg:r,rotateDeg:i});for(const e of s){const n=t.get(e.thisId);null!=n&&(e.angle=n,e.x=e.r*Math.cos(n),e.y=e.r*Math.sin(n))}}const l="fan"===n?function(t){const e=new Map(t.map(t=>[t.thisId,t])),n=t.find(t=>null==t.parentId)?.thisId,a=[];for(const r of t){if(r.thisId===n)continue;const t=e.get(r.parentId);if(!t)continue;const i=r.angle,s=t.r,l=r.r;a.push({parentId:t.thisId,childId:r.thisId,x0:s*Math.cos(i),y0:s*Math.sin(i),x1:l*Math.cos(i),y1:l*Math.sin(i),isTip:!!r.isTip})}return a}(s):function(t){const e=o(t),n=new Map(e.map(t=>[t.thisId,t])),a=e.find(t=>null==t.parentId)?.thisId,r=[];for(const t of e){if(t.thisId===a)continue;const e=n.get(t.parentId);if(!e)continue;const i=t.angle,s=e.r,l=t.r;r.push({parentId:e.thisId,childId:t.thisId,x0:s*Math.cos(i),y0:s*Math.sin(i),x1:l*Math.cos(i),y1:l*Math.sin(i),isTip:!!t.isTip})}return r}(t),c="fan"===a?function(t){const e=2*Math.PI,n=t=>(t%e+e)%e,a=new Map(t.map(t=>[t.thisId,t])),r=[];for(const i of t){const t=i.children||[];if(t.length<2||!(i.r>0))continue;const s=a.get(t[0])?.angle,l=a.get(t[t.length-1])?.angle;if(null==s||null==l)continue;const o=n(s),c=n(l),h=(c-o+e)%e;h<1e-9||r.push({parentId:i.parentId,thisId:i.thisId,radius:i.r,start:o,end:c,sweep:"ccw",largeArc:h>Math.PI?1:0})}return r}(s):function(t){const e=2*Math.PI;new Map(t.map(t=>[t.thisId,t]));const n=new Map;let a=null;for(const e of t)null==e.parentId&&(a=e.thisId),n.has(e.parentId)||n.set(e.parentId,[]),n.get(e.parentId).push(e);const r=[];for(const i of t){const t=i.thisId;if(t===a)continue;const s=n.get(t)||[];if(s.length<2)continue;const l=s.map(t=>(t.angle%e+e)%e).sort((t,e)=>t-e),o=l[0],c=l[l.length-1],h=c-o,d=e-h;let p,f,u;h<=d?(p=o,f=c,u=h):(p=c,f=o,u=d),u<1e-6||!isFinite(i.r)||i.r<=0||r.push({start:p,end:f,radius:i.r,thisId:t,parentId:i.parentId})}return r}(s),h=function(t){const e=new Map(t.map(t=>[t.thisId,t])),n=[];for(const a of t){if(null==a.parentId)continue;const t=e.get(a.parentId);t&&n.push({parentId:t.thisId,childId:a.thisId,radius:t.r,start:t.angle,end:a.angle})}return n}(s);return{data:s,radii:l,arcs:c,child_arcs:h}}function f(t){const e=l(t),n=new Map(e.map((t,e)=>[t.thisId,e])),a=[];!function t(e){e.children&&0!==e.children.length?e.children.forEach(t):a.push(e.id)}(t);const r=new Map(a.map((t,e)=>[t,e+1]));return function t(a){const i=n.get(a.id);if(!a.children||0===a.children.length){const t=r.get(a.id);return e[i].y0=t,e[i].y1=t,t}const s=function(t){let e=0,n=0;for(let a of t)null!=a&&(a=+a)>=a&&(++e,n+=a);if(e)return n/e}(a.children.map(t));return e[i].y0=s,e[i].y1=s,s}(t),function t(a,r){const i=n.get(a.id),s=r??0,l=s+(e[i].branchLength??0);e[i].x0=s,e[i].x1=l,a.children&&a.children.length&&a.children.forEach(e=>t(e,l))}(t,0),e.map(t=>{const{y:e,x:n,angle:a,...r}=t;return r})}function u(t){const e=f(t),n=function(t){const e=f(t),n=new Map;for(const t of e){if(null==t.parentId)continue;const e=n.get(t.parentId);e?e.push(t):n.set(t.parentId,[t])}const a=[];for(const[t,e]of n.entries()){if(!e.length)continue;const n=e.map(t=>t.y0),r=Math.min(...n),i=Math.max(...n),s=e[0].x0;a.push({parentId:t,x0:s,x1:s,y0:r,y1:i,heights:i-r})}return a}(t),a=function(t){const e=f(t),n=new Map(e.map(t=>[t.thisId,t])),a=[];for(const t of e){if(null==t.parentId)continue;const e=n.get(t.parentId);if(!e)continue;const r=t.x0,i=t.y0,s=e.y0,l=Math.min(i,s),o=Math.max(i,s);a.push({parentId:t.parentId,childId:t.thisId,x:r,y0:l,y1:o})}return a}(t);new Map(e.map(t=>[t.thisId,t]));const r=e.filter(t=>null!=t.parentId).map(t=>({parentId:t.parentId,childId:t.thisId,thisId:t.thisId,thisLabel:t.thisLabel,isTip:t.isTip,x0:t.x0,x1:t.x1,y0:t.y0,y1:t.y0}));return{data:e,vertical_lines:n,child_vertical_lines:a,horizontal_lines:r}}function g(t){null===t.parent&&(function t(e){if(!e.children||0===e.children.length)return e.ntips=1,1;let n=0;for(const a of e.children)n+=t(a);return e.ntips=n,n}(t),t.start=0,t.end=2,t.angle=0,t.ntips=function(t){var e=0;for(const n of function(t){const e=[t],n=[];for(;e.length;){const t=e.shift();n.push(t);for(const n of t.children)e.push(n)}return n}(t))0==n.children.length&&e++;return e}(t),t.x=0,t.y=0);let e=t.start;for(let n=0;n<t.children.length;n++){const a=t.children[n],r=(t.end-t.start)*(a.ntips/t.ntips);a.start=e,a.end=e+r,a.angle=a.start+(a.end-a.start)/2,e=a.end;const i=a.angle*Math.PI,s=a.branchLength??0;a.x=t.x+s*Math.sin(i),a.y=t.y+s*Math.cos(i),g(a)}return t}function I(t){var e={},n=l(g(t));return e.data=n,e.edges=function(t,e=!1){const n=[...t].sort((t,e)=>t.thisId-e.thisId),a=new Map(n.map(t=>[t.thisId,t])),r=[];for(const t of n){if(null==t.parentId)continue;const n=a.get(t.parentId);n&&(e?(r.push({x1:t.x,y1:t.y,id1:t.thisId,x2:n.x,y2:t.y,id2:void 0}),r.push({x1:n.x,y1:t.y,id1:void 0,x2:n.x,y2:n.y,id2:t.parentId})):r.push({x1:t.x,y1:t.y,id1:t.thisId,x2:n.x,y2:n.y,id2:t.parentId}))}return r}(n),e}function y(t){const e=(t=String(t).replace(/\s+/g,"")).split(/(;|\(|\)|,)/);let n=0;const a=t=>({parent:t,children:[],id:n++,label:"",branchLength:null}),r=a(null);let i=r;for(const t of e)if(t&&";"!==t)if("("===t){const t=a(i);i.children.push(t),i=t}else if(","===t){i=i.parent;const t=a(i);i.children.push(t),i=t}else if(")"===t){if(i=i.parent,null===i)break}else{const e=t.split(":");1===e.length?t.startsWith(":")?i.branchLength=parseFloat(e[0]):i.label=e[0]:2===e.length?(i.label=e[0],i.branchLength=parseFloat(e[1])):(console.warn(t,"Unhandled token with multiple ':' characters"),i.label=e[0]||"",i.branchLength=parseFloat(e[e.length-1]))}return r}return function(t,{layout:e="rect",width:a=800,height:s=800,margin:l={top:20,right:300,bottom:20,left:50},radialMargin:o=80,strokeWidth:c=1,radialMode:h="outer",tipLabels:d=!0,labelFontSize:f=10,showTooltips:g=!0,tooltipFormatter:x=(t,e)=>`${t.thisLabel??"(unnamed)"}\nroot→tip: ${(+e).toFixed(4)}`,hoverStroke:m="#1f77b4",hoverWidth:M=3,highlightTips:w=[],highlightStroke:b="#e63946",highlightWidth:k=2.5}={}){const v=t=>"number"==typeof t&&Number.isFinite(t);function _(t,{prefer:e="auto"}={}){return function(n){let a=t.get(n);if(!a)return 0;if("r"===e||"auto"===e&&"r"in a)return Number(a.r??0);if("x1"===e||"auto"===e&&"x1"in a)return Number(a.x1??0);let r=0;for(;a&&null!=a.parentId;)r+=Number(a.branchLength||0),a=t.get(a.parentId);return r}}if("rect"===e){const A=u(y(t)),L=A.horizontal_lines,$=A.vertical_lines,T=L.filter(t=>t.isTip),P=new Map(A.data.map(t=>[t.thisId,t])),j=new Map(T.map(t=>[t.thisId,t])),E=new Map(T.map(t=>[t.thisLabel,t])),S=_(P,{prefer:"x1"}),z=n.max(L,t=>t.y1),F=n.min(L,t=>t.y1),D=n.max(L,t=>t.x1),O=n.scaleLinear().domain([F-1,z+1]).range([l.top,s-l.bottom]),X=n.scaleLinear().domain([0,D]).range([l.left,a-l.right]),Y=n.create("svg").attr("width",a).attr("height",s).attr("font-family","sans-serif").attr("font-size",10),N=Y.append("g"),W=Y.append("g").attr("class","phylo_static_highlight"),B=Y.append("g").attr("class","phylo_hover_highlight");N.selectAll(".hline").data(L).join("line").attr("x1",t=>X(t.x0)).attr("y1",t=>O(t.y0)).attr("x2",t=>X(t.x1)).attr("y2",t=>O(t.y1)).attr("stroke","#555").attr("stroke-width",c),N.selectAll(".vline").data($).join("line").attr("x1",t=>X(t.x0)).attr("y1",t=>O(t.y0)).attr("x2",t=>X(t.x1)).attr("y2",t=>O(t.y1)).attr("stroke","#555").attr("stroke-width",c);const U=N.selectAll(".tip-dot").data(T).join("circle").attr("cx",t=>X(t.x1)).attr("cy",t=>O(t.y1)).attr("r",2).attr("fill","black");if(g&&U.append("title").text(t=>x(t,S(t.thisId))),U.on("mouseenter",function(t,e){B.selectAll("*").remove(),q(e.thisId,B,m,M),n.select(this).attr("r",4)}).on("mouseleave",function(){B.selectAll("*").remove(),n.select(this).attr("r",2)}),d){const C=Y.append("g").attr("class","phylo_labels").selectAll("text").data(T).join("text").attr("x",t=>X(t.x1)+4).attr("y",t=>O(t.y1)).attr("dy","0.32em").attr("font-size",f).text(t=>t.thisLabel?.replace(/_/g," ")??"");g&&C.append("title").text(t=>x(t,S(t.thisId))),C.on("mouseenter",function(t,e){B.selectAll("*").remove(),q(e.thisId,B,m,M),n.select(this).attr("font-weight",600)}).on("mouseleave",function(){B.selectAll("*").remove(),n.select(this).attr("font-weight",null)})}if(w&&w.length){new Set([...w.filter(v).map(t=>j.get(t)),...w.filter(t=>!v(t)).map(t=>E.get(t))].filter(Boolean)).forEach(t=>{q(t.thisId,W,b,k)})}function q(t,e,n,a){let r=P.get(t);for(;r&&null!=r.parentId;){const t=P.get(r.parentId);if(!t)break;e.append("line").attr("x1",X(r.x0)).attr("x2",X(r.x0)).attr("y1",O(t.y0)).attr("y2",O(r.y0)).attr("stroke",n).attr("stroke-width",a).attr("stroke-linecap","round"),e.append("line").attr("x1",X(r.x0)).attr("x2",X(r.x1)).attr("y1",O(r.y0)).attr("y2",O(r.y1)).attr("stroke",n).attr("stroke-width",a).attr("stroke-linecap","round"),r=t}}return Y.node()}if("radial"===e){if(a!==s)throw new Error("width and height must be the same for radial layout");const G=p(y(t),{angleStrategy:"fan",arcsStyle:"fan"}),H="outer"===h;if("phylo"!==h&&"outer"!==h)throw new Error("radialMode must be either 'phylo' or 'outer'");const J=3,K=0,Q=a,R=s,V=n.max(G.data,t=>t.r)??0,Z=V>0?V*(Q/2)/(Q/2-o):1,tt=Q/2,et=R/2,nt=n.scaleLinear().domain([-Z,Z]).range([0,Q]),at=n.scaleLinear().domain([-Z,Z]).range([R,0]),rt=t=>t*(Q/(2*Z)),it=new Map(G.data.map(t=>[t.thisId,t])),st=G.data.filter(t=>t.isTip),lt=st.length?n.max(st,t=>t.r):0,ot=_(it,{prefer:"r"}),ct=new Map(st.map(t=>[t.thisId,t])),ht=new Map(st.map(t=>[t.thisLabel,t]));function dt(t,e,n,a){const r=nt(t),i=at(e),s=nt(n)-r,l=at(a)-i,o=Math.hypot(s,l)||1,c=Math.max(0,(o-K)/o);return{X0:r,Y0:i,X1s:r+s*c,Y1s:i+l*c,len:o}}const pt=n.create("svg").attr("width",Q).attr("height",R).attr("font-family","sans-serif").attr("font-size",10),ft=pt.append("g"),ut=pt.append("g").attr("class","phylo_static_lines"),gt=pt.append("g").attr("class","phylo_static_arcs"),It=pt.append("g").attr("class","phylo_hover_lines"),yt=pt.append("g").attr("class","phylo_hover_arcs");ft.append("g").attr("class","phylo_arcs").selectAll("path").data(G.arcs).join("path").attr("d",t=>null==t.sweep?r(tt,et,rt(t.radius),t.start,t.end):i(tt,et,rt(t.radius),t.start,t.end,t.sweep??"ccw",t.largeArc??0)).attr("fill","none").attr("stroke","#777").attr("stroke-width",c),ft.append("g").attr("class","phylo_radii").selectAll("line").data(G.radii).join("line").each(function(t,e){const a=t.x0,r=t.y0,i=(s=t).childId??s.thisId??s.id1??null;var s;const l=null!=i?it.get(i):void 0,o=!(!l||!l.isTip);let h=t.x1,d=t.y1;H&&o&&(h=lt*Math.cos(l.angle),d=lt*Math.sin(l.angle));const{X0:p,Y0:f,X1s:u,Y1s:g}=dt(a,r,h,d);n.select(this).attr("x1",p).attr("y1",f).attr("x2",u).attr("y2",g).attr("stroke","#777").attr("stroke-width",c)});const xt=ft.append("g").attr("class","phylo_tip_dots").selectAll("circle").data(st).join("circle").each(function(t,e){const a=H?lt*Math.cos(t.angle):t.x,r=H?lt*Math.sin(t.angle):t.y;n.select(this).attr("cx",nt(a)).attr("cy",at(r)).attr("r",J).attr("fill","black").attr("stroke","black").attr("stroke-width",1.5)});g&&xt.append("title").text(t=>x(t,ot(t.thisId)));const mt=t=>"string"==typeof t?+t:t,Mt=new Map(G.radii.map(t=>[mt(t.childId??t.thisId??t.id1),t])),wt=new Map(G.child_arcs.map(t=>[mt(t.childId),t]));if(d){const kt=ft.append("g").attr("class","phylo_labels").selectAll("g.label").data(st).join("g").attr("class","label").attr("transform",t=>{const e=H?lt:t.r,n=e*Math.cos(t.angle),a=e*Math.sin(t.angle);return`translate(${nt(n)},${at(a)})`}).each(function(t){let e=180*-t.angle/Math.PI,a=10,r="start";t.angle>Math.PI/2&&t.angle<3*Math.PI/2&&(e+=180,a*=-1,r="end"),n.select(this).append("g").attr("transform",`rotate(${e})`).append("text").attr("x",a).attr("alignment-baseline","middle").attr("text-anchor",r).attr("font-size",f).attr("fill","black").text(t=>t.thisLabel?.replace(/_/g," ")??"")});g&&kt.append("title").text(t=>x(t,ot(t.thisId))),kt.on("mouseenter",function(t,e){It.selectAll("*").remove(),yt.selectAll("*").remove(),bt(e,It,yt,m,M),n.select(this).select("text").attr("font-weight",600)}).on("mouseleave",function(){It.selectAll("*").remove(),yt.selectAll("*").remove(),n.select(this).select("text").attr("font-weight",null)})}function bt(t,e,n,a="#1f77b4",s=3){let l="number"==typeof t||"string"==typeof t?it.get(t):t;if(!l)return;let o=!0;for(;l&&null!=l.parentId;){const c=Mt.get(mt(l.thisId));if(c){const p=c.x0,f=c.y0;let u=c.x1,g=c.y1;if(H&&o&&l.isTip){const M=lt;u=M*Math.cos(l.angle),g=M*Math.sin(l.angle)}const{X0:I,Y0:y,X1s:x,Y1s:m}=dt(p,f,u,g);e.append("line").attr("x1",I).attr("y1",y).attr("x2",x).attr("y2",m).attr("stroke",a).attr("stroke-width",s).attr("stroke-linecap","round")}const h=wt.get(mt(l.thisId));function d(t){const e=rt(t.radius);return null==t.sweep?r(tt,et,e,t.start,t.end):i(tt,et,e,t.start,t.end,t.sweep??"ccw",t.largeArc??0)}h&&n.append("path").attr("d",d(h)).attr("fill","none").attr("stroke",a).attr("stroke-width",s),o=!1,l=it.get(l.parentId)}}if(xt.on("mouseenter",function(t,e){It.selectAll("*").remove(),yt.selectAll("*").remove(),bt(e,It,yt,m,M),n.select(this).attr("r",J+2)}).on("mouseleave",function(){It.selectAll("*").remove(),yt.selectAll("*").remove(),n.select(this).attr("r",J)}),w&&w.length){new Set([...w.filter(v).map(t=>ct.get(t)),...w.filter(t=>!v(t)).map(t=>ht.get(t))].filter(Boolean)).forEach(t=>{bt(t.thisId,ut,gt,b,k)})}return pt.node()}if("unrooted"===e){const vt=I(y(t)),_t=a,At=s,Lt=n.extent(vt.data,t=>t.x),$t=n.extent(vt.data,t=>t.y),Tt=Math.max(Math.abs(Lt[0]),Math.abs(Lt[1])),Pt=Math.max(Math.abs($t[0]),Math.abs($t[1])),jt=Math.max(Tt,Pt)+2*o,Et=n.scaleLinear().domain([-jt,jt]).range([0,_t]),St=n.scaleLinear().domain([-jt,jt]).range([At,0]),zt=n.create("svg").attr("width",_t).attr("height",At).attr("font-family","sans-serif").attr("font-size",10),Ft=zt.append("g"),Dt=zt.append("g").attr("class","phylo_static_highlight"),Ot=zt.append("g").attr("class","phylo_hover_highlight");Ft.append("g").attr("class","phylo_lines").selectAll("line").data(vt.edges).join("line").attr("x1",t=>Et(t.x1)).attr("y1",t=>St(t.y1)).attr("x2",t=>Et(t.x2)).attr("y2",t=>St(t.y2)).attr("stroke-width",c).attr("stroke","#777");const Xt=Ft.append("g").attr("class","phylo_points").selectAll("circle").data(vt.data).join("circle").attr("class","dot").attr("r",t=>t.isTip?4:0).attr("cx",t=>Et(t.x)).attr("cy",t=>St(t.y)).attr("stroke","black").attr("stroke-width",2).attr("fill",t=>t.isTip?"black":"white"),Yt=new Map(vt.data.map(t=>[t.thisId,t])),Nt=new Map(vt.data.filter(t=>t.isTip).map(t=>[t.thisId,t])),Wt=new Map(vt.data.filter(t=>t.isTip).map(t=>[t.thisLabel,t])),Bt=_(Yt);g&&Xt.filter(t=>t.isTip).append("title").text(t=>x(t,Bt(t.thisId)));const Ut=new Map,qt=new Map(vt.data.map(t=>[t.thisId,t]));if(vt.edges.forEach(t=>{const e=qt.get(t.id1);e?.isTip&&Ut.set(t.id1,t)}),d){const Gt=Ft.append("g").attr("class","phylo_labels").selectAll("g").data(vt.data.filter(t=>t.isTip)).join("g").attr("transform",t=>`translate(${Et(t.x)},${St(t.y)})`).each(function(t){const e=Ut.get(t.thisId);if(!e)return;const a=Et(e.x1),r=St(e.y1),i=Et(e.x2)-a,s=St(e.y2)-r;let l=180*Math.atan2(s,i)/Math.PI,o=-10,c="end";(l>90||l<-90)&&(l+=180,c="start",o=10),n.select(this).append("g").attr("transform",`rotate(${l})`).append("text").attr("x",o).attr("alignment-baseline","middle").attr("text-anchor",c).attr("font-size",f).attr("fill","black").text(t.thisLabel?.replace(/_/g," ")??"")});g&&Gt.append("title").text(t=>x(t,Bt(t.thisId))),Gt.on("mouseenter",function(t,e){Ct(e.thisId,Ot,m,M),n.select(this).select("text").attr("font-weight",600)}).on("mouseleave",function(){Ot.selectAll("*").remove(),n.select(this).select("text").attr("font-weight",null)})}if(Xt.filter(t=>t.isTip).on("mouseenter",function(t,e){Ct(e.thisId,Ot,m,M),n.select(this).attr("r",6)}).on("mouseleave",function(){Ot.selectAll("*").remove(),n.select(this).attr("r",4)}),w&&w.length){new Set([...w.filter(v).map(t=>Nt.get(t)),...w.filter(t=>!v(t)).map(t=>Wt.get(t))].filter(Boolean)).forEach(t=>{Ct(t.thisId,Dt,b,k)})}function Ct(t,e,n,a){const r=new Map(vt.edges.map(t=>[t.id1,t]));e.selectAll("*").remove();let i=Yt.get(t);for(;i&&null!=i.parentId;){const t=r.get(i.thisId);t&&e.append("line").attr("x1",Et(t.x1)).attr("y1",St(t.y1)).attr("x2",Et(t.x2)).attr("y2",St(t.y2)).attr("stroke",n).attr("stroke-width",a).attr("stroke-linecap","round"),i=Yt.get(i.parentId)}}return zt.node()}throw new Error("Unsupported layout type. Use 'rect', 'radial', or 'unrooted'.")}});
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("d3")):"function"==typeof define&&define.amd?define(["d3"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).lwPhyloPlot=e(t.d3)}(this,function(t){"use strict";function e(t){var e=Object.create(null);return t&&Object.keys(t).forEach(function(n){if("default"!==n){var a=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,a.get?a:{enumerable:!0,get:function(){return t[n]}})}}),e.default=t,Object.freeze(e)}var n=e(t);function a(t,e,n,a){return{x:t+n*Math.cos(a),y:e-n*Math.sin(a)}}function r(t,e,n,r,s){const i=2*Math.PI,l=t=>(t%i+i)%i;let o=l(r),c=l(s);if((o-c+i)%i<(c-o+i)%i){const t=o;o=c,c=t}const h=(c-o+i)%i;if(h<1e-9){const r=a(t,e,n,o);return`M ${r.x} ${r.y}`}const d=h>Math.PI?1:0,p=a(t,e,n,o),f=a(t,e,n,c);return`M ${p.x} ${p.y} A ${n} ${n} 0 ${d} 0 ${f.x} ${f.y}`}function s(t,e,n,a,r,s="ccw",i=0){if(!(n>0))return"";return`M ${t+n*Math.cos(a)} ${e-n*Math.sin(a)} A ${n} ${n} 0 ${i} ${"ccw"===s?0:1} ${t+n*Math.cos(r)} ${e-n*Math.sin(r)}`}function i(t,e=[]){e.push(t);for(let n=0;n<(t.children?.length||0);n++)e=i(t.children[n],e);return e}function l(t,e=!0){var n=[];for(const e of i(t))null===e.parent?n.push({parentId:null,parentLabel:null,thisId:e.id,thisLabel:e.label,children:e.children.map(t=>t.id),branchLength:0,isTip:!1,x:e.x,y:e.y,angle:e.angle}):n.push({parentId:e.parent.id,parentLabel:e.parent.label,thisId:e.id,thisLabel:e.label,children:e.children.map(t=>t.id),branchLength:e.branchLength,isTip:0==e.children.length,x:e.x,y:e.y,angle:e.angle});return e&&(n=n.sort(function(t,e){return t.thisId-e.thisId})),n}function o(t){const e=2*Math.PI,n=l(t,!0),a=new Map(n.map(t=>[t.thisId,t])),r=new Map(n.map(t=>[t.thisId,t.children||[]]));let s=null;for(const t of n)if(null==t.parentId){s=t.thisId;break}const i=[];!function t(e){const n=r.get(e)||[];if(0!==n.length)for(const e of n)t(e);else i.push(e)}(s);const o=Math.max(1,i.length),c=new Map;i.forEach((t,n)=>{c.set(t,n/o*e)}),function t(n){const a=r.get(n)||[];for(const e of a)t(e);if(a.length>0){let t=0,r=0;for(const e of a){const n=c.get(e);t+=Math.cos(n),r+=Math.sin(n)}c.set(n,(Math.atan2(r,t)%e+e)%e)}}(s);const h=new Map;h.set(s,0),function t(e){const n=r.get(e)||[],s=h.get(e)||0;for(const e of n){const n=a.get(e),r=n?.branchLength??0;h.set(e,s+r),t(e)}}(s);for(const t of n){const e=c.get(t.thisId)??0,n=h.get(t.thisId)??0;t.angle=e,t.r=n,t.x=n*Math.cos(e),t.y=n*Math.sin(e)}return n}const c=2*Math.PI,h=t=>(t%c+c)%c;function d(t,e={}){const{openAngleDeg:n=0,rotateDeg:a=0}=e,r=n/360*c,s=a/360*c;let i=null;const l=new Map(t.map(t=>[t.thisId,t.children||[]]));for(const e of t)if(null==e.parentId){i=e.thisId;break}const o=[];!function t(e){const n=l.get(e)||[];if(n.length)for(const e of n)t(e);else o.push(e)}(i);const d=Math.max(1,o.length),p=d>1?(c*(1-1/d)-r)/(d-1):0,f=new Map;return o.forEach((t,e)=>f.set(t,h(e*p+s))),function t(e){const n=l.get(e)||[];for(const e of n)t(e);if(n.length){const t=f.get(n[0]),a=n.map(e=>function(t,e){let n=e;for(;n<t-Math.PI;)n+=c;for(;n>t+Math.PI;)n-=c;return n}(t,f.get(e)));f.set(e,h(a.reduce((t,e)=>t+e,0)/a.length))}}(i),f}function p(t,e={}){const{angleStrategy:n="fan",arcsStyle:a="fan",openAngleDeg:r=0,rotateDeg:s=0}=e,i=o(t);if("fan"===n){const t=d(i,{openAngleDeg:r,rotateDeg:s});for(const e of i){const n=t.get(e.thisId);null!=n&&(e.angle=n,e.x=e.r*Math.cos(n),e.y=e.r*Math.sin(n))}}const l="fan"===n?function(t){const e=new Map(t.map(t=>[t.thisId,t])),n=t.find(t=>null==t.parentId)?.thisId,a=[];for(const r of t){if(r.thisId===n)continue;const t=e.get(r.parentId);if(!t)continue;const s=r.angle,i=t.r,l=r.r;a.push({parentId:t.thisId,childId:r.thisId,x0:i*Math.cos(s),y0:i*Math.sin(s),x1:l*Math.cos(s),y1:l*Math.sin(s),isTip:!!r.isTip})}return a}(i):function(t){const e=o(t),n=new Map(e.map(t=>[t.thisId,t])),a=e.find(t=>null==t.parentId)?.thisId,r=[];for(const t of e){if(t.thisId===a)continue;const e=n.get(t.parentId);if(!e)continue;const s=t.angle,i=e.r,l=t.r;r.push({parentId:e.thisId,childId:t.thisId,x0:i*Math.cos(s),y0:i*Math.sin(s),x1:l*Math.cos(s),y1:l*Math.sin(s),isTip:!!t.isTip})}return r}(t),c="fan"===a?function(t){const e=2*Math.PI,n=t=>(t%e+e)%e,a=new Map(t.map(t=>[t.thisId,t])),r=[];for(const s of t){const t=s.children||[];if(t.length<2||!(s.r>0))continue;const i=a.get(t[0])?.angle,l=a.get(t[t.length-1])?.angle;if(null==i||null==l)continue;const o=n(i),c=n(l),h=(c-o+e)%e;h<1e-9||r.push({parentId:s.parentId,thisId:s.thisId,radius:s.r,start:o,end:c,sweep:"ccw",largeArc:h>Math.PI?1:0})}return r}(i):function(t){const e=2*Math.PI;new Map(t.map(t=>[t.thisId,t]));const n=new Map;let a=null;for(const e of t)null==e.parentId&&(a=e.thisId),n.has(e.parentId)||n.set(e.parentId,[]),n.get(e.parentId).push(e);const r=[];for(const s of t){const t=s.thisId;if(t===a)continue;const i=n.get(t)||[];if(i.length<2)continue;const l=i.map(t=>(t.angle%e+e)%e).sort((t,e)=>t-e),o=l[0],c=l[l.length-1],h=c-o,d=e-h;let p,f,u;h<=d?(p=o,f=c,u=h):(p=c,f=o,u=d),u<1e-6||!isFinite(s.r)||s.r<=0||r.push({start:p,end:f,radius:s.r,thisId:t,parentId:s.parentId})}return r}(i),h=function(t){const e=new Map(t.map(t=>[t.thisId,t])),n=[];for(const a of t){if(null==a.parentId)continue;const t=e.get(a.parentId);t&&n.push({parentId:t.thisId,childId:a.thisId,radius:t.r,start:t.angle,end:a.angle})}return n}(i);return{data:i,radii:l,arcs:c,child_arcs:h}}function f(t){const e=l(t),n=new Map(e.map((t,e)=>[t.thisId,e])),a=[];!function t(e){e.children&&0!==e.children.length?e.children.forEach(t):a.push(e.id)}(t);const r=new Map(a.map((t,e)=>[t,e+1]));return function t(a){const s=n.get(a.id);if(!a.children||0===a.children.length){const t=r.get(a.id);return e[s].y0=t,e[s].y1=t,t}const i=function(t){let e=0,n=0;for(let a of t)null!=a&&(a=+a)>=a&&(++e,n+=a);if(e)return n/e}(a.children.map(t));return e[s].y0=i,e[s].y1=i,i}(t),function t(a,r){const s=n.get(a.id),i=r??0,l=i+(e[s].branchLength??0);e[s].x0=i,e[s].x1=l,a.children&&a.children.length&&a.children.forEach(e=>t(e,l))}(t,0),e.map(t=>{const{y:e,x:n,angle:a,...r}=t;return r})}function u(t){const e=f(t),n=function(t){const e=f(t),n=new Map;for(const t of e){if(null==t.parentId)continue;const e=n.get(t.parentId);e?e.push(t):n.set(t.parentId,[t])}const a=[];for(const[t,e]of n.entries()){if(!e.length)continue;const n=e.map(t=>t.y0),r=Math.min(...n),s=Math.max(...n),i=e[0].x0;a.push({parentId:t,x0:i,x1:i,y0:r,y1:s,heights:s-r})}return a}(t),a=function(t){const e=f(t),n=new Map(e.map(t=>[t.thisId,t])),a=[];for(const t of e){if(null==t.parentId)continue;const e=n.get(t.parentId);if(!e)continue;const r=t.x0,s=t.y0,i=e.y0,l=Math.min(s,i),o=Math.max(s,i);a.push({parentId:t.parentId,childId:t.thisId,x:r,y0:l,y1:o})}return a}(t);new Map(e.map(t=>[t.thisId,t]));const r=e.filter(t=>null!=t.parentId).map(t=>({parentId:t.parentId,childId:t.thisId,thisId:t.thisId,thisLabel:t.thisLabel,isTip:t.isTip,x0:t.x0,x1:t.x1,y0:t.y0,y1:t.y0}));return{data:e,vertical_lines:n,child_vertical_lines:a,horizontal_lines:r}}function g(t){null===t.parent&&(function t(e){if(!e.children||0===e.children.length)return e.ntips=1,1;let n=0;for(const a of e.children)n+=t(a);return e.ntips=n,n}(t),t.start=0,t.end=2,t.angle=0,t.ntips=function(t){var e=0;for(const n of function(t){const e=[t],n=[];for(;e.length;){const t=e.shift();n.push(t);for(const n of t.children)e.push(n)}return n}(t))0==n.children.length&&e++;return e}(t),t.x=0,t.y=0);let e=t.start;for(let n=0;n<t.children.length;n++){const a=t.children[n],r=(t.end-t.start)*(a.ntips/t.ntips);a.start=e,a.end=e+r,a.angle=a.start+(a.end-a.start)/2,e=a.end;const s=a.angle*Math.PI,i=a.branchLength??0;a.x=t.x+i*Math.sin(s),a.y=t.y+i*Math.cos(s),g(a)}return t}function y(t){var e={},n=l(g(t));return e.data=n,e.edges=function(t,e=!1){const n=[...t].sort((t,e)=>t.thisId-e.thisId),a=new Map(n.map(t=>[t.thisId,t])),r=[];for(const t of n){if(null==t.parentId)continue;const n=a.get(t.parentId);n&&(e?(r.push({x1:t.x,y1:t.y,id1:t.thisId,x2:n.x,y2:t.y,id2:void 0}),r.push({x1:n.x,y1:t.y,id1:void 0,x2:n.x,y2:n.y,id2:t.parentId})):r.push({x1:t.x,y1:t.y,id1:t.thisId,x2:n.x,y2:n.y,id2:t.parentId}))}return r}(n),e}function x(t){const e=(t=String(t).replace(/\s+/g,"")).split(/(;|\(|\)|,)/);let n=0;const a=t=>({parent:t,children:[],id:n++,label:"",branchLength:null}),r=a(null);let s=r;for(const t of e)if(t&&";"!==t)if("("===t){const t=a(s);s.children.push(t),s=t}else if(","===t){s=s.parent;const t=a(s);s.children.push(t),s=t}else if(")"===t){if(s=s.parent,null===s)break}else{const e=t.split(":");1===e.length?t.startsWith(":")?s.branchLength=parseFloat(e[0]):s.label=e[0]:2===e.length?(s.label=e[0],s.branchLength=parseFloat(e[1])):(console.warn(t,"Unhandled token with multiple ':' characters"),s.label=e[0]||"",s.branchLength=parseFloat(e[e.length-1]))}return r}function I(t,{scale:e,basis:n,defaultX:a,defaultY:r,scaleBar:s,fontSize:i}){const l=!0===s||"number"==typeof s?{}:s,o="number"==typeof s?s:l.length??function(t){if(!(t>0))return 1;const e=Math.floor(Math.log10(t)),n=Math.pow(10,e),a=t/n;return(a<1.5?1:a<3.5?2:a<7.5?5:10)*n}(n/5),c=l.x??a,h=l.y??r,d=e(o)-e(0),p=t.append("g").attr("class","phylo_scale_bar");p.append("line").attr("x1",c).attr("x2",c+d).attr("y1",h).attr("y2",h).attr("stroke","#000").attr("stroke-width",1),[c,c+d].forEach(t=>{p.append("line").attr("x1",t).attr("x2",t).attr("y1",h-4).attr("y2",h+4).attr("stroke","#000").attr("stroke-width",1)}),p.append("text").attr("x",c+d/2).attr("y",h-6).attr("text-anchor","middle").attr("font-size",i).text(l.label??String(o))}return function(t,{layout:e="rect",width:a=800,height:i=800,margin:l={top:20,right:300,bottom:20,left:50},radialMargin:o=80,strokeWidth:c=1,radialMode:h="outer",tipLabels:d=!0,labelFontSize:f=10,tipRadius:g,internalNodeCircles:m=!1,internalNodeRadius:M=3,nodeLabels:b=!1,nodeLabelFontSize:w,scaleBar:k=!1,alignTipLabels:_=!1,showTooltips:v=!0,tooltipFormatter:A=(t,e)=>`${t.thisLabel??"(unnamed)"}\nroot→tip: ${(+e).toFixed(4)}`,hoverStroke:L="#1f77b4",hoverWidth:T=3,highlightTips:$=[],highlightStroke:j="#e63946",highlightWidth:z=2.5}={}){const P=t=>"number"==typeof t&&Number.isFinite(t),S=w??f;function E(t,{prefer:e="auto"}={}){return function(n){let a=t.get(n);if(!a)return 0;if("r"===e||"auto"===e&&"r"in a)return Number(a.r??0);if("x1"===e||"auto"===e&&"x1"in a)return Number(a.x1??0);let r=0;for(;a&&null!=a.parentId;)r+=Number(a.branchLength||0),a=t.get(a.parentId);return r}}if("rect"===e){const X=u(x(t)),Y=X.horizontal_lines,F=X.vertical_lines,B=Y.filter(t=>t.isTip),D=new Map(X.data.map(t=>[t.thisId,t])),N=new Map(B.map(t=>[t.thisId,t])),O=new Map(B.map(t=>[t.thisLabel,t])),W=E(D,{prefer:"x1"}),U=g??2,R=n.max(Y,t=>t.y1),q=n.min(Y,t=>t.y1),C=n.max(Y,t=>t.x1),G=n.scaleLinear().domain([q-1,R+1]).range([l.top,i-l.bottom]),H=n.scaleLinear().domain([0,C]).range([l.left,a-l.right]),J=n.create("svg").attr("width",a).attr("height",i).attr("font-family","sans-serif").attr("font-size",10),K=J.append("g"),Q=J.append("g").attr("class","phylo_static_highlight"),V=J.append("g").attr("class","phylo_hover_highlight");K.selectAll(".hline").data(Y).join("line").attr("x1",t=>H(t.x0)).attr("y1",t=>G(t.y0)).attr("x2",t=>H(t.x1)).attr("y2",t=>G(t.y1)).attr("stroke","#555").attr("stroke-width",c),K.selectAll(".vline").data(F).join("line").attr("x1",t=>H(t.x0)).attr("y1",t=>G(t.y0)).attr("x2",t=>H(t.x1)).attr("y2",t=>G(t.y1)).attr("stroke","#555").attr("stroke-width",c);const Z=K.selectAll(".tip-dot").data(B).join("circle").attr("cx",t=>H(t.x1)).attr("cy",t=>G(t.y1)).attr("r",U).attr("fill","black");if(v&&Z.append("title").text(t=>A(t,W(t.thisId))),Z.on("mouseenter",function(t,e){V.selectAll("*").remove(),et(e.thisId,V,L,T),n.select(this).attr("r",U+2)}).on("mouseleave",function(){V.selectAll("*").remove(),n.select(this).attr("r",U)}),m){const nt=X.data.filter(t=>!t.isTip),at=K.append("g").attr("class","phylo_internal_dots").selectAll("circle").data(nt).join("circle").attr("cx",t=>H(t.x1)).attr("cy",t=>G(t.y1)).attr("r",M).attr("fill","white").attr("stroke","#555").attr("stroke-width",1);v&&at.append("title").text(t=>A(t,W(t.thisId)))}if(b){const rt=X.data.filter(t=>!t.isTip&&t.thisLabel);J.append("g").attr("class","phylo_node_labels").selectAll("text").data(rt).join("text").attr("x",t=>H(t.x1)-4).attr("y",t=>G(t.y1)-4).attr("text-anchor","end").attr("font-size",S).text(t=>t.thisLabel)}const tt=H(C);if(d&&_&&K.append("g").attr("class","phylo_align_guides").selectAll("line").data(B).join("line").attr("x1",t=>H(t.x1)).attr("x2",tt).attr("y1",t=>G(t.y1)).attr("y2",t=>G(t.y1)).attr("stroke","#999").attr("stroke-width",1).attr("stroke-dasharray","2,2"),d){const st=J.append("g").attr("class","phylo_labels").selectAll("text").data(B).join("text").attr("x",t=>(_?tt:H(t.x1))+4).attr("y",t=>G(t.y1)).attr("dy","0.32em").attr("font-size",f).text(t=>t.thisLabel?.replace(/_/g," ")??"");v&&st.append("title").text(t=>A(t,W(t.thisId))),st.on("mouseenter",function(t,e){V.selectAll("*").remove(),et(e.thisId,V,L,T),n.select(this).attr("font-weight",600)}).on("mouseleave",function(){V.selectAll("*").remove(),n.select(this).attr("font-weight",null)})}if($&&$.length){new Set([...$.filter(P).map(t=>N.get(t)),...$.filter(t=>!P(t)).map(t=>O.get(t))].filter(Boolean)).forEach(t=>{et(t.thisId,Q,j,z)})}function et(t,e,n,a){let r=D.get(t);for(;r&&null!=r.parentId;){const t=D.get(r.parentId);if(!t)break;e.append("line").attr("x1",H(r.x0)).attr("x2",H(r.x0)).attr("y1",G(t.y0)).attr("y2",G(r.y0)).attr("stroke",n).attr("stroke-width",a).attr("stroke-linecap","round"),e.append("line").attr("x1",H(r.x0)).attr("x2",H(r.x1)).attr("y1",G(r.y0)).attr("y2",G(r.y1)).attr("stroke",n).attr("stroke-width",a).attr("stroke-linecap","round"),r=t}}return k&&I(J,{scale:H,basis:C,defaultX:l.left,defaultY:i-l.bottom/2,scaleBar:k,fontSize:f}),J.node()}if("radial"===e){if(a!==i)throw new Error("width and height must be the same for radial layout");const it=p(x(t),{angleStrategy:"fan",arcsStyle:"fan"}),lt="outer"===h;if("phylo"!==h&&"outer"!==h)throw new Error("radialMode must be either 'phylo' or 'outer'");const ot=g??3,ct=0,ht=a,dt=i,pt=n.max(it.data,t=>t.r)??0,ft=pt>0?pt*(ht/2)/(ht/2-o):1,ut=ht/2,gt=dt/2,yt=n.scaleLinear().domain([-ft,ft]).range([0,ht]),xt=n.scaleLinear().domain([-ft,ft]).range([dt,0]),It=t=>t*(ht/(2*ft)),mt=new Map(it.data.map(t=>[t.thisId,t])),Mt=it.data.filter(t=>t.isTip),bt=Mt.length?n.max(Mt,t=>t.r):0,wt=E(mt,{prefer:"r"}),kt=new Map(Mt.map(t=>[t.thisId,t])),_t=new Map(Mt.map(t=>[t.thisLabel,t]));function vt(t,e,n,a){const r=yt(t),s=xt(e),i=yt(n)-r,l=xt(a)-s,o=Math.hypot(i,l)||1,c=Math.max(0,(o-ct)/o);return{X0:r,Y0:s,X1s:r+i*c,Y1s:s+l*c,len:o}}const At=n.create("svg").attr("width",ht).attr("height",dt).attr("font-family","sans-serif").attr("font-size",10),Lt=At.append("g"),Tt=At.append("g").attr("class","phylo_static_lines"),$t=At.append("g").attr("class","phylo_static_arcs"),jt=At.append("g").attr("class","phylo_hover_lines"),zt=At.append("g").attr("class","phylo_hover_arcs");Lt.append("g").attr("class","phylo_arcs").selectAll("path").data(it.arcs).join("path").attr("d",t=>null==t.sweep?r(ut,gt,It(t.radius),t.start,t.end):s(ut,gt,It(t.radius),t.start,t.end,t.sweep??"ccw",t.largeArc??0)).attr("fill","none").attr("stroke","#777").attr("stroke-width",c),Lt.append("g").attr("class","phylo_radii").selectAll("line").data(it.radii).join("line").each(function(t,e){const a=t.x0,r=t.y0,s=(i=t).childId??i.thisId??i.id1??null;var i;const l=null!=s?mt.get(s):void 0,o=!(!l||!l.isTip);let h=t.x1,d=t.y1;lt&&o&&(h=bt*Math.cos(l.angle),d=bt*Math.sin(l.angle));const{X0:p,Y0:f,X1s:u,Y1s:g}=vt(a,r,h,d);n.select(this).attr("x1",p).attr("y1",f).attr("x2",u).attr("y2",g).attr("stroke","#777").attr("stroke-width",c)}),d&&_&&!lt&&Lt.append("g").attr("class","phylo_align_guides").selectAll("line").data(Mt).join("line").attr("x1",t=>yt(t.x)).attr("y1",t=>xt(t.y)).attr("x2",t=>yt(bt*Math.cos(t.angle))).attr("y2",t=>xt(bt*Math.sin(t.angle))).attr("stroke","#999").attr("stroke-width",1).attr("stroke-dasharray","2,2");const Pt=Lt.append("g").attr("class","phylo_tip_dots").selectAll("circle").data(Mt).join("circle").each(function(t,e){const a=lt?bt*Math.cos(t.angle):t.x,r=lt?bt*Math.sin(t.angle):t.y;n.select(this).attr("cx",yt(a)).attr("cy",xt(r)).attr("r",ot).attr("fill","black").attr("stroke","black").attr("stroke-width",1.5)});if(v&&Pt.append("title").text(t=>A(t,wt(t.thisId))),m){const Ft=it.data.filter(t=>!t.isTip),Bt=Lt.append("g").attr("class","phylo_internal_dots").selectAll("circle").data(Ft).join("circle").attr("cx",t=>yt(t.x)).attr("cy",t=>xt(t.y)).attr("r",M).attr("fill","white").attr("stroke","#555").attr("stroke-width",1);v&&Bt.append("title").text(t=>A(t,wt(t.thisId)))}if(b){const Dt=it.data.filter(t=>!t.isTip&&t.thisLabel);Lt.append("g").attr("class","phylo_node_labels").selectAll("text").data(Dt).join("text").attr("x",t=>yt(t.x)+4).attr("y",t=>xt(t.y)-4).attr("font-size",S).attr("fill","black").text(t=>t.thisLabel)}const St=t=>"string"==typeof t?+t:t,Et=new Map(it.radii.map(t=>[St(t.childId??t.thisId??t.id1),t])),Xt=new Map(it.child_arcs.map(t=>[St(t.childId),t]));if(d){const Nt=Lt.append("g").attr("class","phylo_labels").selectAll("g.label").data(Mt).join("g").attr("class","label").attr("transform",t=>{const e=lt||_?bt:t.r,n=e*Math.cos(t.angle),a=e*Math.sin(t.angle);return`translate(${yt(n)},${xt(a)})`}).each(function(t){let e=180*-t.angle/Math.PI,a=10,r="start";t.angle>Math.PI/2&&t.angle<3*Math.PI/2&&(e+=180,a*=-1,r="end"),n.select(this).append("g").attr("transform",`rotate(${e})`).append("text").attr("x",a).attr("alignment-baseline","middle").attr("text-anchor",r).attr("font-size",f).attr("fill","black").text(t=>t.thisLabel?.replace(/_/g," ")??"")});v&&Nt.append("title").text(t=>A(t,wt(t.thisId))),Nt.on("mouseenter",function(t,e){jt.selectAll("*").remove(),zt.selectAll("*").remove(),Yt(e,jt,zt,L,T),n.select(this).select("text").attr("font-weight",600)}).on("mouseleave",function(){jt.selectAll("*").remove(),zt.selectAll("*").remove(),n.select(this).select("text").attr("font-weight",null)})}function Yt(t,e,n,a="#1f77b4",i=3){let l="number"==typeof t||"string"==typeof t?mt.get(t):t;if(!l)return;let o=!0;for(;l&&null!=l.parentId;){const c=Et.get(St(l.thisId));if(c){const p=c.x0,f=c.y0;let u=c.x1,g=c.y1;if(lt&&o&&l.isTip){const M=bt;u=M*Math.cos(l.angle),g=M*Math.sin(l.angle)}const{X0:y,Y0:x,X1s:I,Y1s:m}=vt(p,f,u,g);e.append("line").attr("x1",y).attr("y1",x).attr("x2",I).attr("y2",m).attr("stroke",a).attr("stroke-width",i).attr("stroke-linecap","round")}const h=Xt.get(St(l.thisId));function d(t){const e=It(t.radius);return null==t.sweep?r(ut,gt,e,t.start,t.end):s(ut,gt,e,t.start,t.end,t.sweep??"ccw",t.largeArc??0)}h&&n.append("path").attr("d",d(h)).attr("fill","none").attr("stroke",a).attr("stroke-width",i),o=!1,l=mt.get(l.parentId)}}if(Pt.on("mouseenter",function(t,e){jt.selectAll("*").remove(),zt.selectAll("*").remove(),Yt(e,jt,zt,L,T),n.select(this).attr("r",ot+2)}).on("mouseleave",function(){jt.selectAll("*").remove(),zt.selectAll("*").remove(),n.select(this).attr("r",ot)}),$&&$.length){new Set([...$.filter(P).map(t=>kt.get(t)),...$.filter(t=>!P(t)).map(t=>_t.get(t))].filter(Boolean)).forEach(t=>{Yt(t.thisId,Tt,$t,j,z)})}return k&&I(At,{scale:yt,basis:pt,defaultX:20,defaultY:dt-20,scaleBar:k,fontSize:f}),At.node()}if("unrooted"===e){const Ot=y(x(t)),Wt=a,Ut=i,Rt=n.extent(Ot.data,t=>t.x),qt=n.extent(Ot.data,t=>t.y),Ct=Math.max(Math.abs(Rt[0]),Math.abs(Rt[1])),Gt=Math.max(Math.abs(qt[0]),Math.abs(qt[1])),Ht=Math.max(Ct,Gt),Jt=Ht+2*o,Kt=n.scaleLinear().domain([-Jt,Jt]).range([0,Wt]),Qt=n.scaleLinear().domain([-Jt,Jt]).range([Ut,0]),Vt=n.create("svg").attr("width",Wt).attr("height",Ut).attr("font-family","sans-serif").attr("font-size",10),Zt=Vt.append("g"),te=Vt.append("g").attr("class","phylo_static_highlight"),ee=Vt.append("g").attr("class","phylo_hover_highlight");Zt.append("g").attr("class","phylo_lines").selectAll("line").data(Ot.edges).join("line").attr("x1",t=>Kt(t.x1)).attr("y1",t=>Qt(t.y1)).attr("x2",t=>Kt(t.x2)).attr("y2",t=>Qt(t.y2)).attr("stroke-width",c).attr("stroke","#777");const ne=g??4,ae=Zt.append("g").attr("class","phylo_points").selectAll("circle").data(Ot.data).join("circle").attr("class","dot").attr("r",t=>t.isTip?ne:m?M:0).attr("cx",t=>Kt(t.x)).attr("cy",t=>Qt(t.y)).attr("stroke","black").attr("stroke-width",2).attr("fill",t=>t.isTip?"black":"white");if(b){const de=Ot.data.filter(t=>!t.isTip&&t.thisLabel);Zt.append("g").attr("class","phylo_node_labels").selectAll("text").data(de).join("text").attr("x",t=>Kt(t.x)+4).attr("y",t=>Qt(t.y)-4).attr("font-size",S).attr("fill","black").text(t=>t.thisLabel)}const re=new Map(Ot.data.map(t=>[t.thisId,t])),se=new Map(Ot.data.filter(t=>t.isTip).map(t=>[t.thisId,t])),ie=new Map(Ot.data.filter(t=>t.isTip).map(t=>[t.thisLabel,t])),le=E(re);v&&ae.filter(t=>t.isTip).append("title").text(t=>A(t,le(t.thisId)));const oe=new Map,ce=new Map(Ot.data.map(t=>[t.thisId,t]));if(Ot.edges.forEach(t=>{const e=ce.get(t.id1);e?.isTip&&oe.set(t.id1,t)}),d){const pe=Zt.append("g").attr("class","phylo_labels").selectAll("g").data(Ot.data.filter(t=>t.isTip)).join("g").attr("transform",t=>`translate(${Kt(t.x)},${Qt(t.y)})`).each(function(t){const e=oe.get(t.thisId);if(!e)return;const a=Kt(e.x1),r=Qt(e.y1),s=Kt(e.x2)-a,i=Qt(e.y2)-r;let l=180*Math.atan2(i,s)/Math.PI,o=-10,c="end";(l>90||l<-90)&&(l+=180,c="start",o=10),n.select(this).append("g").attr("transform",`rotate(${l})`).append("text").attr("x",o).attr("alignment-baseline","middle").attr("text-anchor",c).attr("font-size",f).attr("fill","black").text(t.thisLabel?.replace(/_/g," ")??"")});v&&pe.append("title").text(t=>A(t,le(t.thisId))),pe.on("mouseenter",function(t,e){he(e.thisId,ee,L,T),n.select(this).select("text").attr("font-weight",600)}).on("mouseleave",function(){ee.selectAll("*").remove(),n.select(this).select("text").attr("font-weight",null)})}if(ae.filter(t=>t.isTip).on("mouseenter",function(t,e){he(e.thisId,ee,L,T),n.select(this).attr("r",ne+2)}).on("mouseleave",function(){ee.selectAll("*").remove(),n.select(this).attr("r",ne)}),$&&$.length){new Set([...$.filter(P).map(t=>se.get(t)),...$.filter(t=>!P(t)).map(t=>ie.get(t))].filter(Boolean)).forEach(t=>{he(t.thisId,te,j,z)})}function he(t,e,n,a){const r=new Map(Ot.edges.map(t=>[t.id1,t]));e.selectAll("*").remove();let s=re.get(t);for(;s&&null!=s.parentId;){const t=r.get(s.thisId);t&&e.append("line").attr("x1",Kt(t.x1)).attr("y1",Qt(t.y1)).attr("x2",Kt(t.x2)).attr("y2",Qt(t.y2)).attr("stroke",n).attr("stroke-width",a).attr("stroke-linecap","round"),s=re.get(s.parentId)}}return k&&I(Vt,{scale:Kt,basis:Ht,defaultX:20,defaultY:Ut-20,scaleBar:k,fontSize:f}),Vt.node()}throw new Error("Unsupported layout type. Use 'rect', 'radial', or 'unrooted'.")}});
2
2
  //# sourceMappingURL=drawPhylogeny.umd.js.map