arrowjoin
Version:
ArrowJoin is a creative and functional React library that effortlessly connects two React components with a sleek arrow.
2 lines (1 loc) • 15.8 kB
JavaScript
import*as e from"react";import t,{useState as r,useRef as n,useLayoutEffect as o,useEffect as a,useContext as s}from"react";import l from"lodash";import i from"prop-types";const c=e=>{let t;return t="string"==typeof e?document.getElementById(e):e?.current,t},d=(e,t)=>{let r,n=1/0,o=1/0;return e.forEach((e=>{t.forEach((t=>{var a,s;a=e,s=t,o=Math.sqrt((a.x-s.x)**2+(a.y-s.y)**2),o<n&&(n=o,r={chosenStart:e,chosenEnd:t})}))})),r},f=e=>{if(!e)return{x:0,y:0,right:0,bottom:0};const t=e.getBoundingClientRect();return{x:t.left,y:t.top,right:t.right,bottom:t.bottom}},u=["middle","left","right","top","bottom","auto"],h=["smooth","grid","straight"],p=["circle","ellipse","line","path","polygon","polyline","rect"],m={arrow1:{svgElem:e.createElement("path",{d:"M 0 0 L 1 0.5 L 0 1 L 0.25 0.5 z"}),offsetForward:.25},heart:{svgElem:e.createElement("path",{d:"M 0,0.25 A 0.125,0.125 0,0,1 0.5,0.25 A 0.125,0.125 0,0,1 1,0.25 Q 1,0.625 0.5,1 Q 0,0.625 0,0.25 z"}),offsetForward:.1},circle:{svgElem:e.createElement("circle",{r:.5,cx:.5,cy:.5}),offsetForward:0}},y=Object.keys(m),x=e=>{let t=(Array.isArray(e)?e:[e]).map((e=>"string"==typeof e?{position:e}:e));t=t.filter((e=>u.includes(e.position))),0==t.length&&(t=[{position:"auto"}]);let r=t.filter((e=>"auto"===e.position));r.length>0&&(t=t.filter((e=>"auto"!==e.position)),t.push(...r.flatMap((e=>["left","right","top","bottom"].map((t=>({...e,position:t})))))));let n=t.map((e=>{if("object"==typeof e){let t=e;return t.position||(t.position="auto"),t.offset||(t.offset={x:0,y:0}),t.offset.y||(t.offset.y=0),t.offset.x||(t.offset.x=0),t}return e}));return n},b=e=>("string"==typeof e&&(e in m?e=m[e]:(console.warn(`'${e}' is not supported arrow shape. the supported arrow shapes is one of ${y}.\n reverting to default shape.`),e=m.arrow1)),void 0===e?.offsetForward&&(e.offsetForward=.25),void 0===e?.svgElem&&(e.svgElem="path"),e),g=e=>{let t=(e=>{if("string"!=typeof e)return{abs:0,relative:.5};let t=e.split("%"),r=0,n=0;if(1==t.length){let e=parseFloat(t[0]);if(!isNaN(e))return r=e,{abs:r,relative:0}}else if(2==t.length){let[e,o]=[parseFloat(t[0]),parseFloat(t[1])];if(isNaN(e)||(n=e/100),isNaN(o)||(r=o),!isNaN(e)||!isNaN(o))return{abs:r,relative:n}}})(e);return t||(t={relative:.5,abs:0}),t},v=(e,t)=>(t&&(t.current=!0),e),w=e=>e,E=(e,t,r)=>v(e,r),P=(e,t,r)=>v(Number(e),r),S={start:e=>c(e),end:e=>c(e),startAnchor:(e,t,r)=>v(x(e),r),endAnchor:(e,t,r)=>v(x(e),r),labels:e=>(e=>{let r={start:null,middle:null,end:null};if(e)if("string"==typeof e||t.isValidElement(e))r.middle=e;else for(let t in e)r[t]=e[t];return r})(e),color:w,lineColor:(e,t)=>e||t.color,headColor:(e,t)=>e||t.color,tailColor:(e,t)=>e||t.color,strokeWidth:P,showHead:E,headSize:P,showTail:E,tailSize:P,path:E,curveness:P,gridBreak:(e,t,r)=>v(g(e),r),dashness:(e,t)=>((e,t)=>{let r,n=0,o=0;return"object"==typeof e?(n=e.strokeLen||2*t.strokeWidth,o=e.strokeLen?e.nonStrokeLen:t.strokeWidth,r=e.animation?e.animation:null):"boolean"==typeof e&&e&&(n=2*t.strokeWidth,o=t.strokeWidth,r=null),{strokeLen:n,nonStrokeLen:o,animation:r,animDirection:1}})(e,t),headShape:e=>b(e),tailShape:e=>b(e),showXarrow:w,animateDrawing:w,zIndex:e=>Number(e),passProps:w,className:null,onClick:null,arrowBodyProps:E,arrowHeadProps:E,arrowTailProps:E,SVGcanvasProps:E,divContainerProps:E,divContainerStyle:E,SVGcanvasStyle:E,_extendSVGcanvas:E,_debug:E,_cpx1Offset:E,_cpy1Offset:E,_cpx2Offset:E,_cpy2Offset:E},O={};for(let e in S)O[e]=[e];for(let e of["lineColor","headColor","tailColor"])O[e].push("color");const k={start:null,end:null,startAnchor:"auto",endAnchor:"auto",labels:null,color:"CornflowerBlue",lineColor:null,headColor:null,tailColor:null,strokeWidth:4,showHead:!0,headSize:6,showTail:!1,tailSize:6,path:"smooth",curveness:.8,gridBreak:"50%",dashness:!1,headShape:"arrow1",tailShape:"arrow1",showXarrow:!0,animateDrawing:!1,zIndex:0,passProps:{},arrowBodyProps:{},arrowHeadProps:{},arrowTailProps:{},SVGcanvasProps:{},divContainerProps:{},divContainerStyle:{},SVGcanvasStyle:{},_extendSVGcanvas:0,className:null,onClick:null,_debug:!1,_cpx1Offset:0,_cpy1Offset:0,_cpx2Offset:0,_cpy2Offset:0};let C={};C=((e,t)=>{for(let[r,n]of Object.entries(e))t[r]=S?.[r]?.(n,t);return t})(k,C),console.log("initialParsedProps",C);const M={startPos:{x:0,y:0,right:0,bottom:0},endPos:{x:0,y:0,right:0,bottom:0}};function L(e){const t=n();var r,o;return r=e,o=t.current,l.isEqual(r,o)||(t.current=e),t.current}function $(e,t){o(e,t.map(L))}const T=t.createContext(null),N=t.createContext(null),R={};let z=0;const _=({children:e,instanceCount:n})=>{const[,o]=r({}),s=()=>o({});return a((()=>{n.current=z,R[n.current]=s}),[]),t.createElement(N.Provider,{value:s},e)},D=({children:e,instanceCount:r})=>t.createElement(T.Provider,{value:R[r.current]},e),A=({children:e})=>{const o=n(z),[,s]=r({});return a((()=>(z++,s({}),()=>{delete R[o.current]})),[]),t.createElement(D,{instanceCount:o},t.createElement(_,{instanceCount:o},e))},j=i.oneOf(u),F=i.exact({position:j.isRequired,offset:i.exact({x:i.number,y:i.number}).isRequired}),H=i.oneOfType([j,F]),B=i.oneOfType([H,i.arrayOf(H)]),V=i.oneOfType([i.string,i.exact({current:i.any})]),G=i.oneOfType([i.element,i.string]),W=i.exact({start:G,middle:G,end:G}),I=i.oneOf(Object.keys(m)),q=i.any,U=i.oneOfType([I,i.exact({svgElem:q,offsetForward:i.number}).isRequired]),X={start:V.isRequired,end:V.isRequired,startAnchor:B,endAnchor:B,labels:i.oneOfType([G,W]),color:i.string,lineColor:i.string,showHead:i.bool,headColor:i.string,headSize:i.number,tailSize:i.number,tailColor:i.string,strokeWidth:i.number,showTail:i.bool,path:i.oneOf(h),showXarrow:i.bool,curveness:i.number,gridBreak:i.string,dashness:i.oneOfType([i.bool,i.object]),headShape:U,tailShape:U,animateDrawing:i.oneOfType([i.bool,i.number]),zIndex:i.number,passProps:i.object,arrowBodyProps:i.object,arrowHeadProps:i.object,arrowTailProps:i.object,SVGcanvasProps:i.object,divContainerProps:i.object,_extendSVGcanvas:i.number,_debug:i.bool,_cpx1Offset:i.number,_cpy1Offset:i.number,_cpx2Offset:i.number,_cpy2Offset:i.number},Q=(e,t)=>e.map((e=>{let r=(n=t.right-t.x,o=t.bottom-t.y,{middle:{x:.5*n,y:.5*o},left:{x:0,y:.5*o},right:{x:n,y:.5*o},top:{x:.5*n,y:0},bottom:{x:.5*n,y:o}});var n,o;let{x:a,y:s}=r[e.position];return{x:t.x+a+e.offset.x,y:t.y+s+e.offset.y,anchor:e}})),J=(e,t,r,n)=>o=>(1-o)**3*e+3*(1-o)**2*o*t+3*(1-o)*o**2*r+o**3*n,K=(e,t,r,n)=>{const o=J(e,t,r,n),a=-6*e+12*t-6*r,s=(-6*e+12*t-6*r)**2-4*(3*t-3*e)*(-3*e+9*t-9*r+3*n),l=2*(-3*e+9*t-9*r+3*n);return[o((a+Math.sqrt(s))/l),o((a-Math.sqrt(s))/l)]},Y=(e,t)=>{let[r,n]=e,{startAnchor:o,endAnchor:a,strokeWidth:s,showHead:i,headSize:c,showTail:f,tailSize:u,path:p,curveness:m,gridBreak:y,headShape:x,tailShape:b,_extendSVGcanvas:g,_cpx1Offset:v,_cpy1Offset:w,_cpx2Offset:E,_cpy2Offset:P}=r;const{startPos:S,endPos:O}=n,{svgRef:k,lineRef:C}=t.current;let M=0,L=0,$=Q(o,S),T=Q(a,O),{chosenStart:N,chosenEnd:R}=d($,T),z=N.anchor.position,_=R.anchor.position,D=l.pick(N,["x","y"]),A=l.pick(R,["x","y"]),j=(e=>{if(!e.current)return{x:0,y:0};let{left:t,top:r}=e.current.getBoundingClientRect(),n=getComputedStyle(e.current);return{x:t-Number(n.left.slice(0,-2)),y:r-Number(n.top.slice(0,-2))}})(k),F=Math.min(D.x,A.x)-j.x,H=Math.min(D.y,A.y)-j.y,B=A.x-D.x,V=A.y-D.y,G=Math.abs(A.x-D.x),W=Math.abs(A.y-D.y),I=B>0?1:-1,q=V>0?1:-1,[U,X]=[x.offsetForward,b.offsetForward],Y=c*s,Z=u*s,ee=0,te=0,re=0,ne=0,oe=Y*U,ae=Z*X,se=Number(m);h.includes(p)||(p="smooth"),"straight"===p&&(se=0,p="smooth");let le=s+s*(c>u?c:u)/2,ie=le,ce=le,de=le,fe=le;ce+=Number(g),ie+=Number(g),de+=Number(g),fe+=Number(g);let ue=0,he=G,pe=0,me=W;if(B<0&&([ue,he]=[he,ue]),V<0&&([pe,me]=[me,pe]),0===se){let e=Math.atan(W/G);i&&(he-=Y*(1-U)*I*Math.cos(e),me-=Y*(1-U)*q*Math.sin(e),e*=q,I<0&&(e=(Math.PI-e*I)*I),ee=Math.cos(e)*oe-Math.sin(e)*Y/2,te=Math.cos(e)*Y/2+Math.sin(e)*oe,M=180*e/Math.PI);let t=Math.atan(W/G);f&&(ue+=Z*(1-X)*I*Math.cos(t),pe+=Z*(1-X)*q*Math.sin(t),t*=-q,I>0&&(t=(Math.PI-t*I)*I),re=Math.cos(t)*ae-Math.sin(t)*Z/2,ne=Math.cos(t)*Z/2+Math.sin(t)*ae,L=180*t/Math.PI)}else"middle"===_&&(_=G>W?I?"left":"right":q?"top":"bottom"),i&&(["left","right"].includes(_)?(ee+=oe*I,he-=Y*(1-U)*I,te+=Y*I/2,"left"===_?(M=0,I<0&&(M+=180)):(M=180,I>0&&(M+=180))):["top","bottom"].includes(_)&&(ee+=Y*-q/2,te+=oe*q,me-=Y*q-te,"top"===_?(M=270,q>0&&(M+=180)):(M=90,q<0&&(M+=180))));f&&0!==se&&(["left","right"].includes(z)?(re+=ae*-I,ue+=Z*I+re,ne+=-Z*I/2,"left"===z?(L=180,I<0&&(L+=180)):(L=0,I>0&&(L+=180))):["top","bottom"].includes(z)&&(ne+=ae*-q,pe+=Z*q+ne,re+=Z*q/2,"top"===z?(L=90,q>0&&(L+=180)):(L=270,q<0&&(L+=180))));let ye={x:ee,y:te},xe={x:re,y:ne},be=ue,ge=pe,ve=he,we=me,Ee={};"smooth"===p?Ee={hh:()=>{be+=G*se*I,ve-=G*se*I},vv:()=>{ge+=W*se*q,we-=W*se*q},hv:()=>{be+=G*se*I,we-=W*se*q},vh:()=>{ge+=W*se*q,ve-=G*se*I}}:"grid"===p&&(Ee={hh:()=>{be+=(G*y.relative+y.abs)*I,ve-=(G*(1-y.relative)-y.abs)*I,i&&(be-=Y*(1-U)/2*I,ve+=Y*(1-U)/2*I),f&&(be-=Z*(1-X)/2*I,ve+=Z*(1-X)/2*I)},vv:()=>{ge+=(W*y.relative+y.abs)*q,we-=(W*(1-y.relative)-y.abs)*q,i&&(ge-=Y*(1-U)/2*q,we+=Y*(1-U)/2*q),f&&(ge-=Z*(1-X)/2*q,we+=Z*(1-X)/2*q)},hv:()=>{be=he},vh:()=>{ge=me}});let Pe="";["left","right"].includes(z)?Pe+="h":["bottom","top"].includes(z)?Pe+="v":"middle"===z&&(Pe+="m"),["left","right"].includes(_)?Pe+="h":["bottom","top"].includes(_)?Pe+="v":"middle"===_&&(Pe+="m"),Pe=G>W?Pe.replace(/m/g,"h"):Pe.replace(/m/g,"v"),Ee[Pe](),be+=v,ge+=w,ve+=E,we+=P;const[Se,Oe]=K(ue,be,ve,he),[ke,Ce]=K(pe,ge,we,me);Se<0&&(ce+=-Se),Oe>G&&(ie+=Oe-G),ke<0&&(de+=-ke),Ce>W&&(fe+=Ce-W),"grid"===p&&(ce+=le,ie+=le,de+=le,fe+=le),ue+=ce,he+=ce,pe+=de,me+=de,be+=ce,ve+=ce,ge+=de,we+=de;const Me=G+ce+ie,Le=W+de+fe;F-=ce,H-=de;const $e=J(ue,be,ve,he),Te=J(pe,ge,we,me),Ne={x:$e(.01),y:Te(.01)},Re={x:$e(.5),y:Te(.5)},ze={x:$e(.99),y:Te(.99)};let _e;return"grid"===p?_e=`M ${ue} ${pe} L ${be} ${ge} L ${ve} ${we} ${he} ${me}`:"smooth"===p&&(_e=`M ${ue} ${pe} C ${be} ${ge}, ${ve} ${we}, ${he} ${me}`),{cx0:F,cy0:H,x1:ue,x2:he,y1:pe,y2:me,cw:Me,ch:Le,cpx1:be,cpy1:ge,cpx2:ve,cpy2:we,dx:B,dy:V,absDx:G,absDy:W,headOrient:M,tailOrient:L,labelStartPos:Ne,labelMiddlePos:Re,labelEndPos:ze,excLeft:ce,excRight:ie,excUp:de,excDown:fe,headOffset:oe,arrowHeadOffset:ye,arrowTailOffset:xe,startPoints:$,endPoints:T,mainDivPos:j,xSign:I,ySign:q,lineLength:C.current?.getTotalLength()??0,fHeadSize:Y,fTailSize:Z,arrowPath:_e}},Z=e=>{const l=n({svgRef:n(null),lineRef:n(null),headRef:n(null),tailRef:n(null),lineDrawAnimRef:n(null),lineDashAnimRef:n(null),headOpacityAnimRef:n(null)}),{svgRef:i,lineRef:c,headRef:d,lineDrawAnimRef:u,lineDashAnimRef:h,headOpacityAnimRef:p}=l.current;s(N);const m=(e=>{const[t,a]=r(C),s=n(!1);t.shouldUpdatePosition=s;const l={...k,...e};for(let r in k)o((()=>{t[r]=S?.[r]?.(l[r],t,s),a({...t})}),O[r].map((t=>e[t])));const[i,c]=r(M),d=f(t.start);$((()=>{i.startPos=d,s.current=!0,c({...i})}),[d]);const u=f(t.end);return $((()=>{i.endPos=u,s.current=!0,c({...i})}),[u]),o((()=>{s.current=!0,c({...i})}),[t.headShape.svgElem,t.tailShape.svgElem]),[t,i]})(e,l.current),[y]=m;let{labels:x,lineColor:b,headColor:g,tailColor:v,strokeWidth:w,showHead:E,showTail:P,dashness:L,headShape:T,tailShape:R,showXarrow:z,animateDrawing:_,zIndex:D,passProps:A,arrowBodyProps:j,arrowHeadProps:F,arrowTailProps:H,SVGcanvasProps:B,divContainerProps:V,divContainerStyle:G,SVGcanvasStyle:W,_debug:I,shouldUpdatePosition:q}=y;_=e.animateDrawing;const[U,X]=r(!_),[,Q]=r({}),J=()=>Q({}),[K,Z]=r({cx0:0,cy0:0,cw:0,ch:0,x1:0,y1:0,x2:0,y2:0,dx:0,dy:0,absDx:0,absDy:0,cpx1:0,cpy1:0,cpx2:0,cpy2:0,headOrient:0,tailOrient:0,arrowHeadOffset:{x:0,y:0},arrowTailOffset:{x:0,y:0},headOffset:0,excRight:0,excLeft:0,excUp:0,excDown:0,startPoints:[],endPoints:[],mainDivPos:{x:0,y:0},xSign:1,ySign:1,lineLength:0,fHeadSize:1,fTailSize:1,arrowPath:"",labelStartPos:{x:0,y:0},labelMiddlePos:{x:0,y:0},labelEndPos:{x:0,y:0}});o((()=>{if(q.current){const e=Y(m,l);Z(e),q.current=!1}}));const ee=K.x2-K.arrowHeadOffset.x,te=K.y2-K.arrowHeadOffset.y,re=K.x1-K.arrowTailOffset.x,ne=K.y1-K.arrowTailOffset.y;let oe=L.strokeLen+L.nonStrokeLen,ae=1;L.animation<0&&(L.animation*=-1,ae=-1);let se,le,ie,ce,de=0;return _&&0==U?("boolean"==typeof _&&(_=1),le=_+"s",se=K.lineLength,ce=K.lineLength,ie=1,_<0&&([ce,de]=[de,ce],le=-1*_+"s")):(se=`${L.strokeLen} ${L.nonStrokeLen}`,le=1/L.animation+"s",ce=oe*ae,ie="indefinite",de=0),o((()=>{c.current&&Z((e=>({...e,lineLength:c.current?.getTotalLength()??0})))}),[c.current]),a((()=>{const e=(()=>{window.addEventListener("resize",J);const e=()=>{X(!0),p.current?.beginElement(),h.current?.beginElement()},t=()=>d.current.style.opacity="0";return u.current&&d.current&&(u.current.addEventListener("endEvent",e),u.current.addEventListener("beginEvent",t)),()=>{window.removeEventListener("resize",J),u.current&&(u.current.removeEventListener("endEvent",e),d.current&&u.current.removeEventListener("beginEvent",t))}})();return()=>{X(!1),e()}}),[z]),t.createElement("div",Object.assign({},V,{style:{position:"absolute",zIndex:D,...G}}),z?t.createElement(t.Fragment,null,t.createElement("svg",Object.assign({ref:i,width:K.cw,height:K.ch,onClick:()=>{e.onClick&&e.onClick(c)},style:{position:"absolute",cursor:"pointer",left:K.cx0,top:K.cy0,pointerEvents:"none",border:I?"1px dashed yellow":null,...W},overflow:"auto"},B),t.createElement("path",Object.assign({ref:c,d:K.arrowPath,stroke:b,strokeDasharray:se,className:e.className,strokeWidth:w,fill:"transparent",pointerEvents:"visibleStroke"},A,j,{onClick:()=>{e.onClick&&e.onClick(c)}}),t.createElement(t.Fragment,null,U?t.createElement(t.Fragment,null,L.animation?t.createElement("animate",{ref:h,attributeName:"stroke-dashoffset",values:oe*ae+";0",dur:1/L.animation+"s",repeatCount:"indefinite"}):null):t.createElement(t.Fragment,null,_?t.createElement("animate",{ref:u,id:"svgEndAnimate",attributeName:"stroke-dashoffset",values:`${ce};${de}`,dur:le,repeatCount:ie}):null))),P?t.createElement("g",Object.assign({fill:v,pointerEvents:"auto",transform:`translate(${re},${ne}) rotate(${K.tailOrient}) scale(${K.fTailSize})`},A,H),R.svgElem):null,E?t.createElement("g",Object.assign({ref:d,fill:g,pointerEvents:"auto",transform:`translate(${ee},${te}) rotate(${K.headOrient}) scale(${K.fHeadSize})`,opacity:_&&!U?0:1},A,F),t.createElement("animate",{ref:p,dur:"0.4",attributeName:"opacity",from:"0",to:"1",begin:"indefinite",repeatCount:"0",fill:"freeze"}),T.svgElem):null,I?t.createElement(t.Fragment,null,t.createElement("circle",{r:"5",cx:K.cpx1,cy:K.cpy1,fill:"green"}),t.createElement("circle",{r:"5",cx:K.cpx2,cy:K.cpy2,fill:"blue"}),t.createElement("rect",{x:K.excLeft,y:K.excUp,width:K.absDx,height:K.absDy,fill:"none",stroke:"pink",strokeWidth:"2px"})):null),x.start?t.createElement("div",{style:{transform:K.dx<0?"translate(-100% , -50%)":"translate(-0% , -50%)",width:"max-content",position:"absolute",left:K.cx0+K.labelStartPos.x,top:K.cy0+K.labelStartPos.y-w-5}},x.start):null,x.middle?t.createElement("div",{style:{display:"table",width:"max-content",transform:"translate(-50% , -50%)",position:"absolute",left:K.cx0+K.labelMiddlePos.x,top:K.cy0+K.labelMiddlePos.y}},x.middle):null,x.end?t.createElement("div",{style:{transform:K.dx>0?"translate(-100% , -50%)":"translate(-0% , -50%)",width:"max-content",position:"absolute",left:K.cx0+K.labelEndPos.x,top:K.cy0+K.labelEndPos.y+w+5}},x.end):null,I?t.createElement(t.Fragment,null,[...K.startPoints,...K.endPoints].map(((e,r)=>t.createElement("div",{key:r,style:{background:"gray",opacity:.5,borderRadius:"50%",transform:"translate(-50%, -50%)",height:5,width:5,position:"absolute",left:e.x-K.mainDivPos.x,top:e.y-K.mainDivPos.y}})))):null):null)};Z.propTypes=X;const ee=()=>{},te=()=>{const[,e]=r({});let t=s(T);return t||(t=ee),o((()=>{t()})),()=>e({})};export{A as Xwrapper,m as arrowShapes,u as cAnchorEdge,y as cArrowShapes,h as cPaths,p as cSvgElems,Z as default,te as useXarrow};