@euphrasiologist/lwphylo 1.4.0 → 1.5.1

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,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'.")}});
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 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,{scale:e,basis:n,defaultX:a,defaultY:r,scaleBar:i,fontSize:s}){const l=!0===i||"number"==typeof i?{}:i,o="number"==typeof i?i: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",s).text(l.label??String(o))}return function t(e,a={}){const{layout:l="rect",width:o=800,height:c=800,margin:h={top:20,right:300,bottom:20,left:50},radialMargin:d=80,strokeWidth:f=1,radialMode:g="outer",tipLabels:I=!0,labelFontSize:m=10,tipRadius:M,internalNodeRadius:b=3,nodeLabels:w=!1,nodeLabelFontSize:k,scaleBar:_=!1,alignTipLabels:v=!1,container:A,rotateOnClick:L=!1,onNodeClick:T,showTooltips:$=!0,tooltipFormatter:j=(t,e)=>`${t.thisLabel??"(unnamed)"}\nroot→tip: ${(+e).toFixed(4)}`,hoverStroke:S="#1f77b4",hoverWidth:z=3,highlightTips:P=[],highlightStroke:E="#e63946",highlightWidth:X=2.5}=a,Y=a.internalNodeCircles??L,F=t=>"number"==typeof t&&Number.isFinite(t),O=k??m,B=e&&"object"==typeof e&&Array.isArray(e.children)?e:function(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}(e),D="string"==typeof A?"undefined"!=typeof document?document.querySelector(A):null:A??null;if(L&&!D)throw new Error("rotateOnClick requires a `container` (a DOM element or CSS selector) so drawPhylogeny can mount the redrawn SVG after each rotation.");const N=T||L?(e,n)=>{"function"==typeof T&&T(e,n),L&&(!function(t,e=t.id){const n=s(t).find(t=>t.id===e);if(!n)throw new Error(`No node with id ${e} found in tree`);n.children.reverse()}(B,e.thisId),t(B,a))}:void 0;function C(t){return D&&(D.innerHTML="",D.appendChild(t)),t}function W(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"===l){const q=u(B),U=q.horizontal_lines,R=q.vertical_lines,G=U.filter(t=>t.isTip),H=new Map(q.data.map(t=>[t.thisId,t])),V=new Map(G.map(t=>[t.thisId,t])),J=new Map(G.map(t=>[t.thisLabel,t])),K=W(H,{prefer:"x1"}),Q=M??2,Z=n.max(U,t=>t.y1),tt=n.min(U,t=>t.y1),et=n.max(U,t=>t.x1),nt=n.scaleLinear().domain([tt-1,Z+1]).range([h.top,c-h.bottom]),at=n.scaleLinear().domain([0,et]).range([h.left,o-h.right]),rt=n.create("svg").attr("width",o).attr("height",c).attr("font-family","sans-serif").attr("font-size",10),it=rt.append("g"),st=rt.append("g").attr("class","phylo_static_highlight"),lt=rt.append("g").attr("class","phylo_hover_highlight");it.selectAll(".hline").data(U).join("line").attr("x1",t=>at(t.x0)).attr("y1",t=>nt(t.y0)).attr("x2",t=>at(t.x1)).attr("y2",t=>nt(t.y1)).attr("stroke","#555").attr("stroke-width",f),it.selectAll(".vline").data(R).join("line").attr("x1",t=>at(t.x0)).attr("y1",t=>nt(t.y0)).attr("x2",t=>at(t.x1)).attr("y2",t=>nt(t.y1)).attr("stroke","#555").attr("stroke-width",f);const ot=it.selectAll(".tip-dot").data(G).join("circle").attr("cx",t=>at(t.x1)).attr("cy",t=>nt(t.y1)).attr("r",Q).attr("fill","black");if($&&ot.append("title").text(t=>j(t,K(t.thisId))),ot.on("mouseenter",function(t,e){lt.selectAll("*").remove(),ht(e.thisId,lt,S,z),n.select(this).attr("r",Q+2)}).on("mouseleave",function(){lt.selectAll("*").remove(),n.select(this).attr("r",Q)}),Y){const dt=q.data.filter(t=>!t.isTip),pt=it.append("g").attr("class","phylo_internal_dots").selectAll("circle").data(dt).join("circle").attr("cx",t=>at(t.x1)).attr("cy",t=>nt(t.y1)).attr("r",b).attr("fill","white").attr("stroke","#555").attr("stroke-width",1);$&&pt.append("title").text(t=>j(t,K(t.thisId))),N&&pt.style("cursor","pointer").on("click",(t,e)=>N(e,t))}if(w){const ft=q.data.filter(t=>!t.isTip&&t.thisLabel);rt.append("g").attr("class","phylo_node_labels").selectAll("text").data(ft).join("text").attr("x",t=>at(t.x1)-4).attr("y",t=>nt(t.y1)-4).attr("text-anchor","end").attr("font-size",O).text(t=>t.thisLabel)}const ct=at(et);if(I&&v&&it.append("g").attr("class","phylo_align_guides").selectAll("line").data(G).join("line").attr("x1",t=>at(t.x1)).attr("x2",ct).attr("y1",t=>nt(t.y1)).attr("y2",t=>nt(t.y1)).attr("stroke","#999").attr("stroke-width",1).attr("stroke-dasharray","2,2"),I){const ut=rt.append("g").attr("class","phylo_labels").selectAll("text").data(G).join("text").attr("x",t=>(v?ct:at(t.x1))+4).attr("y",t=>nt(t.y1)).attr("dy","0.32em").attr("font-size",m).text(t=>t.thisLabel?.replace(/_/g," ")??"");$&&ut.append("title").text(t=>j(t,K(t.thisId))),ut.on("mouseenter",function(t,e){lt.selectAll("*").remove(),ht(e.thisId,lt,S,z),n.select(this).attr("font-weight",600)}).on("mouseleave",function(){lt.selectAll("*").remove(),n.select(this).attr("font-weight",null)})}if(P&&P.length){new Set([...P.filter(F).map(t=>V.get(t)),...P.filter(t=>!F(t)).map(t=>J.get(t))].filter(Boolean)).forEach(t=>{ht(t.thisId,st,E,X)})}function ht(t,e,n,a){let r=H.get(t);for(;r&&null!=r.parentId;){const t=H.get(r.parentId);if(!t)break;e.append("line").attr("x1",at(r.x0)).attr("x2",at(r.x0)).attr("y1",nt(t.y0)).attr("y2",nt(r.y0)).attr("stroke",n).attr("stroke-width",a).attr("stroke-linecap","round"),e.append("line").attr("x1",at(r.x0)).attr("x2",at(r.x1)).attr("y1",nt(r.y0)).attr("y2",nt(r.y1)).attr("stroke",n).attr("stroke-width",a).attr("stroke-linecap","round"),r=t}}return _&&x(rt,{scale:at,basis:et,defaultX:h.left,defaultY:c-h.bottom/2,scaleBar:_,fontSize:m}),C(rt.node())}if("radial"===l){if(o!==c)throw new Error("width and height must be the same for radial layout");const gt=p(B,{angleStrategy:"fan",arcsStyle:"fan"}),yt="outer"===g;if("phylo"!==g&&"outer"!==g)throw new Error("radialMode must be either 'phylo' or 'outer'");const xt=M??3,It=0,mt=o,Mt=c,bt=n.max(gt.data,t=>t.r)??0,wt=bt>0?bt*(mt/2)/(mt/2-d):1,kt=mt/2,_t=Mt/2,vt=n.scaleLinear().domain([-wt,wt]).range([0,mt]),At=n.scaleLinear().domain([-wt,wt]).range([Mt,0]),Lt=t=>t*(mt/(2*wt)),Tt=new Map(gt.data.map(t=>[t.thisId,t])),$t=gt.data.filter(t=>t.isTip),jt=$t.length?n.max($t,t=>t.r):0,St=W(Tt,{prefer:"r"}),zt=new Map($t.map(t=>[t.thisId,t])),Pt=new Map($t.map(t=>[t.thisLabel,t]));function Et(t,e,n,a){const r=vt(t),i=At(e),s=vt(n)-r,l=At(a)-i,o=Math.hypot(s,l)||1,c=Math.max(0,(o-It)/o);return{X0:r,Y0:i,X1s:r+s*c,Y1s:i+l*c,len:o}}const Xt=n.create("svg").attr("width",mt).attr("height",Mt).attr("font-family","sans-serif").attr("font-size",10),Yt=Xt.append("g"),Ft=Xt.append("g").attr("class","phylo_static_lines"),Ot=Xt.append("g").attr("class","phylo_static_arcs"),Bt=Xt.append("g").attr("class","phylo_hover_lines"),Dt=Xt.append("g").attr("class","phylo_hover_arcs");Yt.append("g").attr("class","phylo_arcs").selectAll("path").data(gt.arcs).join("path").attr("d",t=>null==t.sweep?r(kt,_t,Lt(t.radius),t.start,t.end):i(kt,_t,Lt(t.radius),t.start,t.end,t.sweep??"ccw",t.largeArc??0)).attr("fill","none").attr("stroke","#777").attr("stroke-width",f),Yt.append("g").attr("class","phylo_radii").selectAll("line").data(gt.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?Tt.get(i):void 0,o=!(!l||!l.isTip);let c=t.x1,h=t.y1;yt&&o&&(c=jt*Math.cos(l.angle),h=jt*Math.sin(l.angle));const{X0:d,Y0:p,X1s:u,Y1s:g}=Et(a,r,c,h);n.select(this).attr("x1",d).attr("y1",p).attr("x2",u).attr("y2",g).attr("stroke","#777").attr("stroke-width",f)}),I&&v&&!yt&&Yt.append("g").attr("class","phylo_align_guides").selectAll("line").data($t).join("line").attr("x1",t=>vt(t.x)).attr("y1",t=>At(t.y)).attr("x2",t=>vt(jt*Math.cos(t.angle))).attr("y2",t=>At(jt*Math.sin(t.angle))).attr("stroke","#999").attr("stroke-width",1).attr("stroke-dasharray","2,2");const Nt=Yt.append("g").attr("class","phylo_tip_dots").selectAll("circle").data($t).join("circle").each(function(t,e){const a=yt?jt*Math.cos(t.angle):t.x,r=yt?jt*Math.sin(t.angle):t.y;n.select(this).attr("cx",vt(a)).attr("cy",At(r)).attr("r",xt).attr("fill","black").attr("stroke","black").attr("stroke-width",1.5)});if($&&Nt.append("title").text(t=>j(t,St(t.thisId))),Y){const Rt=gt.data.filter(t=>!t.isTip),Gt=Yt.append("g").attr("class","phylo_internal_dots").selectAll("circle").data(Rt).join("circle").attr("cx",t=>vt(t.x)).attr("cy",t=>At(t.y)).attr("r",b).attr("fill","white").attr("stroke","#555").attr("stroke-width",1);$&&Gt.append("title").text(t=>j(t,St(t.thisId))),N&&Gt.style("cursor","pointer").on("click",(t,e)=>N(e,t))}if(w){const Ht=gt.data.filter(t=>!t.isTip&&t.thisLabel);Yt.append("g").attr("class","phylo_node_labels").selectAll("text").data(Ht).join("text").attr("x",t=>vt(t.x)+4).attr("y",t=>At(t.y)-4).attr("font-size",O).attr("fill","black").text(t=>t.thisLabel)}const Ct=t=>"string"==typeof t?+t:t,Wt=new Map(gt.radii.map(t=>[Ct(t.childId??t.thisId??t.id1),t])),qt=new Map(gt.child_arcs.map(t=>[Ct(t.childId),t]));if(I){const Vt=Yt.append("g").attr("class","phylo_labels").selectAll("g.label").data($t).join("g").attr("class","label").attr("transform",t=>{const e=yt||v?jt:t.r,n=e*Math.cos(t.angle),a=e*Math.sin(t.angle);return`translate(${vt(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",m).attr("fill","black").text(t=>t.thisLabel?.replace(/_/g," ")??"")});$&&Vt.append("title").text(t=>j(t,St(t.thisId))),Vt.on("mouseenter",function(t,e){Bt.selectAll("*").remove(),Dt.selectAll("*").remove(),Ut(e,Bt,Dt,S,z),n.select(this).select("text").attr("font-weight",600)}).on("mouseleave",function(){Bt.selectAll("*").remove(),Dt.selectAll("*").remove(),n.select(this).select("text").attr("font-weight",null)})}function Ut(t,e,n,a="#1f77b4",s=3){let l="number"==typeof t||"string"==typeof t?Tt.get(t):t;if(!l)return;let o=!0;for(;l&&null!=l.parentId;){const c=Wt.get(Ct(l.thisId));if(c){const p=c.x0,f=c.y0;let u=c.x1,g=c.y1;if(yt&&o&&l.isTip){const M=jt;u=M*Math.cos(l.angle),g=M*Math.sin(l.angle)}const{X0:y,Y0:x,X1s:I,Y1s:m}=Et(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",s).attr("stroke-linecap","round")}const h=qt.get(Ct(l.thisId));function d(t){const e=Lt(t.radius);return null==t.sweep?r(kt,_t,e,t.start,t.end):i(kt,_t,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=Tt.get(l.parentId)}}if(Nt.on("mouseenter",function(t,e){Bt.selectAll("*").remove(),Dt.selectAll("*").remove(),Ut(e,Bt,Dt,S,z),n.select(this).attr("r",xt+2)}).on("mouseleave",function(){Bt.selectAll("*").remove(),Dt.selectAll("*").remove(),n.select(this).attr("r",xt)}),P&&P.length){new Set([...P.filter(F).map(t=>zt.get(t)),...P.filter(t=>!F(t)).map(t=>Pt.get(t))].filter(Boolean)).forEach(t=>{Ut(t.thisId,Ft,Ot,E,X)})}return _&&x(Xt,{scale:vt,basis:bt,defaultX:20,defaultY:Mt-20,scaleBar:_,fontSize:m}),C(Xt.node())}if("unrooted"===l){const Jt=y(B),Kt=o,Qt=c,Zt=n.extent(Jt.data,t=>t.x),te=n.extent(Jt.data,t=>t.y),ee=Math.max(Math.abs(Zt[0]),Math.abs(Zt[1])),ne=Math.max(Math.abs(te[0]),Math.abs(te[1])),ae=Math.max(ee,ne),re=ae+2*d,ie=n.scaleLinear().domain([-re,re]).range([0,Kt]),se=n.scaleLinear().domain([-re,re]).range([Qt,0]),le=n.create("svg").attr("width",Kt).attr("height",Qt).attr("font-family","sans-serif").attr("font-size",10),oe=le.append("g"),ce=le.append("g").attr("class","phylo_static_highlight"),he=le.append("g").attr("class","phylo_hover_highlight");oe.append("g").attr("class","phylo_lines").selectAll("line").data(Jt.edges).join("line").attr("x1",t=>ie(t.x1)).attr("y1",t=>se(t.y1)).attr("x2",t=>ie(t.x2)).attr("y2",t=>se(t.y2)).attr("stroke-width",f).attr("stroke","#777");const de=M??4,pe=oe.append("g").attr("class","phylo_points").selectAll("circle").data(Jt.data).join("circle").attr("class","dot").attr("r",t=>t.isTip?de:Y?b:0).attr("cx",t=>ie(t.x)).attr("cy",t=>se(t.y)).attr("stroke","black").attr("stroke-width",2).attr("fill",t=>t.isTip?"black":"white");if(Y&&N&&pe.filter(t=>!t.isTip).style("cursor","pointer").on("click",(t,e)=>N(e,t)),w){const Me=Jt.data.filter(t=>!t.isTip&&t.thisLabel);oe.append("g").attr("class","phylo_node_labels").selectAll("text").data(Me).join("text").attr("x",t=>ie(t.x)+4).attr("y",t=>se(t.y)-4).attr("font-size",O).attr("fill","black").text(t=>t.thisLabel)}const fe=new Map(Jt.data.map(t=>[t.thisId,t])),ue=new Map(Jt.data.filter(t=>t.isTip).map(t=>[t.thisId,t])),ge=new Map(Jt.data.filter(t=>t.isTip).map(t=>[t.thisLabel,t])),ye=W(fe);$&&pe.filter(t=>t.isTip).append("title").text(t=>j(t,ye(t.thisId)));const xe=new Map,Ie=new Map(Jt.data.map(t=>[t.thisId,t]));if(Jt.edges.forEach(t=>{const e=Ie.get(t.id1);e?.isTip&&xe.set(t.id1,t)}),I){const be=oe.append("g").attr("class","phylo_labels").selectAll("g").data(Jt.data.filter(t=>t.isTip)).join("g").attr("transform",t=>`translate(${ie(t.x)},${se(t.y)})`).each(function(t){const e=xe.get(t.thisId);if(!e)return;const a=ie(e.x1),r=se(e.y1),i=ie(e.x2)-a,s=se(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",m).attr("fill","black").text(t.thisLabel?.replace(/_/g," ")??"")});$&&be.append("title").text(t=>j(t,ye(t.thisId))),be.on("mouseenter",function(t,e){me(e.thisId,he,S,z),n.select(this).select("text").attr("font-weight",600)}).on("mouseleave",function(){he.selectAll("*").remove(),n.select(this).select("text").attr("font-weight",null)})}if(pe.filter(t=>t.isTip).on("mouseenter",function(t,e){me(e.thisId,he,S,z),n.select(this).attr("r",de+2)}).on("mouseleave",function(){he.selectAll("*").remove(),n.select(this).attr("r",de)}),P&&P.length){new Set([...P.filter(F).map(t=>ue.get(t)),...P.filter(t=>!F(t)).map(t=>ge.get(t))].filter(Boolean)).forEach(t=>{me(t.thisId,ce,E,X)})}function me(t,e,n,a){const r=new Map(Jt.edges.map(t=>[t.id1,t]));e.selectAll("*").remove();let i=fe.get(t);for(;i&&null!=i.parentId;){const t=r.get(i.thisId);t&&e.append("line").attr("x1",ie(t.x1)).attr("y1",se(t.y1)).attr("x2",ie(t.x2)).attr("y2",se(t.y2)).attr("stroke",n).attr("stroke-width",a).attr("stroke-linecap","round"),i=fe.get(i.parentId)}}return _&&x(le,{scale:ie,basis:ae,defaultX:20,defaultY:Qt-20,scaleBar:_,fontSize:m}),C(le.node())}throw new Error("Unsupported layout type. Use 'rect', 'radial', or 'unrooted'.")}});
2
2
  //# sourceMappingURL=drawPhylogeny.umd.js.map