@tisoap/react-flow-smart-edge
Version:
Custom React Flow Edge that never intersects with other nodes
3 lines (2 loc) • 7.27 kB
JavaScript
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("react/jsx-runtime"),k=require("@xyflow/react"),j=require("react"),K=(t,e,n)=>{const o=new Array(e);for(let s=0;s<e;s++){const r=new Array(t);for(let l=0;l<t;l++){const x=!!(n?n[s]?.[l]:void 0),h=n?!x:!0;r[l]={x:l,y:s,walkable:h}}o[s]=r}return o},X=(t,e,n,o)=>n>=0&&n<t&&o>=0&&o<e,R=(t,e,n)=>{const o=K(t,e,n),s=(h,i)=>o[i][h],r=(h,i)=>X(t,e,h,i)&&o[i][h].walkable;return{width:t,height:e,nodes:o,getNodeAt:s,isWalkableAt:r,setWalkableAt:(h,i,a)=>{X(t,e,h,i)&&(o[i][h].walkable=a)},getNeighbors:(h,i)=>{const a=h.x,c=h.y,g=[],S=r(a,c-1),E=r(a+1,c),m=r(a,c+1),M=r(a-1,c);S&&g.push(s(a,c-1)),E&&g.push(s(a+1,c)),m&&g.push(s(a,c+1)),M&&g.push(s(a-1,c));const w=r(a+1,c-1),d=r(a+1,c+1),u=r(a-1,c+1),f=r(a-1,c-1);return i==="Never"||(w&&g.push(s(a+1,c-1)),d&&g.push(s(a+1,c+1)),u&&g.push(s(a-1,c+1)),f&&g.push(s(a-1,c-1))),g},isInside:(h,i)=>X(t,e,h,i),clone:()=>{const h=o.map(i=>i.map(a=>a.walkable?0:1));return R(t,e,h)}}},F=(t,e)=>{switch(e){case"top":return{x:t.x,y:t.y-1};case"bottom":return{x:t.x,y:t.y+1};case"left":return{x:t.x-1,y:t.y};case"right":return{x:t.x+1,y:t.y}}},Y=(t,e,n)=>{let o=t.getNodeAt(e.x,e.y);for(;!o.walkable;){t.setWalkableAt(o.x,o.y,!0);const s=F(o,n);o=t.getNodeAt(s.x,s.y)}},B=(t,e,n,o)=>{const s=(t.x-e)/o+1,r=(t.y-n)/o+1;return{x:s,y:r}},D=(t,e,n,o)=>{const s=(t.x-1)*o+e,r=(t.y-1)*o+n;return{x:s,y:r}},C=(t,e=10)=>Math.round(t/e)*e,P=(t,e=10)=>Math.floor(t/e)*e,N=(t,e=10)=>Math.ceil(t/e)*e,_=(t,e=0)=>{let n=Math.max(Math.round(t),e);return n=Number.isInteger(n)?n:e,n=n>=e?n:e,n},V=(t,e,n,o,s=2)=>{const{xMin:r,yMin:l,width:y,height:x}=t,h=N(y,s)/s+1,i=N(x,s)/s+1,a=R(h,i);e.forEach(w=>{const d=B(w.topLeft,r,l,s),u=B(w.bottomRight,r,l,s);for(let f=d.x;f<u.x;f++)for(let b=d.y;b<u.y;b++)a.setWalkableAt(f,b,!1)});const c=B({x:C(n.x,s),y:C(n.y,s)},r,l,s),g=B({x:C(o.x,s),y:C(o.y,s)},r,l,s),S=a.getNodeAt(c.x,c.y);Y(a,S,n.position);const E=a.getNodeAt(g.x,g.y);Y(a,E,o.position);const m=F(S,n.position),M=F(E,o.position);return{grid:a,start:m,end:M}},z=(t,e,n)=>{let o=`M ${String(t.x)}, ${String(t.y)} `;return n.forEach(s=>{const[r,l]=s;o+=`L ${String(r)}, ${String(l)} `}),o+=`L ${String(e.x)}, ${String(e.y)} `,o},I=(t,e,n)=>{const o=[[t.x,t.y],...n,[e.x,e.y]];return tt(o)},tt=t=>{let o=t[0];const s=t[0];let r=`M${String(s[0])},${String(s[1])}M`;for(const y of t){const x=et(o[0],o[1],y[0],y[1]);r+=` ${String(x[0])},${String(x[1])}`,r+=`Q${String(y[0])},${String(y[1])}`,o=y}const l=t[t.length-1];return r+=` ${String(l[0])},${String(l[1])}`,r},et=(t,e,n,o)=>{const s=(t-n)/2+n,r=(e-o)/2+o;return[s,r]},nt=(t,e)=>t+e,ot=(t,e)=>{const n=Math.SQRT2-1;return t<e?n*t+e:n*e+t},st=t=>{const e=[];let n=t;for(;n;)e.push([n.x,n.y]),n=n.parent;return e.reverse()},rt=t=>t==="Never"?nt:ot,at=t=>{let e=0;for(let n=1;n<t.length;n++)(t[n].estimatedTotalCost??1/0)<(t[e].estimatedTotalCost??1/0)&&(e=n);return t.splice(e,1)[0]},ct=(t,e,n,o,s,r)=>{if(t.closed)return;const l=Math.abs(t.x-e.x),y=Math.abs(t.y-e.y),x=(e.costFromStart??0)+(l===0||y===0?1:Math.SQRT2);(!t.opened||x<(t.costFromStart??1/0))&&(t.costFromStart=x,t.heuristicCostToGoal=t.heuristicCostToGoal??r*s(Math.abs(t.x-n.x),Math.abs(t.y-n.y)),t.estimatedTotalCost=(t.costFromStart??0)+(t.heuristicCostToGoal??0),t.parent=e,t.opened||(t.opened=!0,o.push(t)))},T=(t={})=>{const e=t.diagonalMovement??"Never",n=t.heuristic??rt(e),o=t.weight??1;return{findPath:(r,l,y,x,h)=>{const i=h.getNodeAt(r,l),a=h.getNodeAt(y,x),c=[];for(i.costFromStart=0,i.heuristicCostToGoal=0,i.estimatedTotalCost=0,i.opened=!0,c.push(i);c.length>0;){const g=at(c);if(g.closed=!0,g===a)return st(a);const S=h.getNeighbors(g,e);for(const E of S)ct(E,g,a,c,n,o)}return[]}}},v=(t,e,n)=>{try{const s=T({diagonalMovement:"Always"}).findPath(e.x,e.y,n.x,n.y,t);if(s.length===0)throw new Error("No path found");return s}catch(o){throw o instanceof Error?o:new Error(`Unknown error: ${String(o)}`)}},it=(t,e,n)=>{try{const s=T({diagonalMovement:"Never"}).findPath(e.x,e.y,n.x,n.y,t);if(s.length===0)throw new Error("No path found");return s}catch(o){throw o instanceof Error?o:new Error(`Unknown error: ${String(o)}`)}},lt=(t,e=2,n=2)=>{let o=Number.MIN_SAFE_INTEGER,s=Number.MIN_SAFE_INTEGER,r=Number.MAX_SAFE_INTEGER,l=Number.MAX_SAFE_INTEGER;const y=t.map(m=>{const M=Math.max(m.measured?.width??0,1),w=Math.max(m.measured?.height??0,1),d={x:m.position.x,y:m.position.y},u={x:d.x-e,y:d.y-e},f={x:d.x-e,y:d.y+w+e},b={x:d.x+M+e,y:d.y-e},p={x:d.x+M+e,y:d.y+w+e};return n>0&&(u.x=P(u.x,n),u.y=P(u.y,n),f.x=P(f.x,n),f.y=N(f.y,n),b.x=N(b.x,n),b.y=P(b.y,n),p.x=N(p.x,n),p.y=N(p.y,n)),u.y<l&&(l=u.y),u.x<r&&(r=u.x),p.y>s&&(s=p.y),p.x>o&&(o=p.x),{id:m.id,width:M,height:w,topLeft:u,bottomLeft:f,topRight:b,bottomRight:p}}),x=e*2;o=N(o+x,n),s=N(s+x,n),r=P(r-x,n),l=P(l-x,n);const h={x:r,y:l},i={x:r,y:s},a={x:o,y:l},c={x:o,y:s},g=Math.abs(h.x-a.x),S=Math.abs(h.y-i.y);return{nodeBoxes:y,graphBox:{topLeft:h,bottomLeft:i,topRight:a,bottomRight:c,width:g,height:S,xMax:o,yMax:s,xMin:r,yMin:l}}},q=({options:t={},nodes:e=[],sourceX:n,sourceY:o,targetX:s,targetY:r,sourcePosition:l,targetPosition:y})=>{try{const{drawEdge:x=I,generatePath:h=v}=t;let{gridRatio:i=10,nodePadding:a=10}=t;i=_(i),a=_(a);const{graphBox:c,nodeBoxes:g}=lt(e,a,i);t.debug?.enabled&&t.debug.setGraphBox&&t.debug.setGraphBox({x:c.topLeft.x,y:c.topLeft.y,width:c.width,height:c.height});const S={x:n,y:o,position:l},E={x:s,y:r,position:y},{grid:m,start:M,end:w}=V(c,g,S,E,i),u=h(m,M,w),f=u.map(H=>{const[O,J]=H,W=D({x:O,y:J},c.xMin,c.yMin,i);return[W.x,W.y]}),b=x(S,E,f),p=Math.floor(u.length/2),G=u[p],[$,U]=G,{x:Q,y:Z}=D({x:$,y:U},c.xMin,c.yMin,i);return{svgPathString:b,edgeCenterX:Q,edgeCenterY:Z}}catch(x){return x instanceof Error?x:new Error(`Unknown error: ${String(x)}`)}},ht=j.createContext({enabled:!1,graphBox:null,setGraphBox:()=>{}}),xt=()=>j.useContext(ht);function L({nodes:t,options:e,...n}){const{enabled:o,setGraphBox:s}=xt(),{sourceX:r,sourceY:l,sourcePosition:y,targetX:x,targetY:h,targetPosition:i,style:a,label:c,labelStyle:g,labelShowBg:S,labelBgStyle:E,labelBgPadding:m,labelBgBorderRadius:M,markerEnd:w,markerStart:d,interactionWidth:u}=n,f=q({sourcePosition:y,targetPosition:i,sourceX:r,sourceY:l,targetX:x,targetY:h,options:{...e,debug:{enabled:o,setGraphBox:s}},nodes:t}),b=e.fallback??k.BezierEdge;if(f instanceof Error)return o&&console.error(f),A.jsx(b,{...n});const{edgeCenterX:p,edgeCenterY:G,svgPathString:$}=f;return A.jsx(k.BaseEdge,{path:$,labelX:p,labelY:G,label:c,labelStyle:g,labelShowBg:S,labelBgStyle:E,labelBgPadding:m,labelBgBorderRadius:M,style:a,markerStart:d,markerEnd:w,interactionWidth:u})}const gt={drawEdge:I,generatePath:v,fallback:k.BezierEdge};function ut(t){const e=k.useNodes();return A.jsx(L,{...t,options:gt,nodes:e})}const yt={drawEdge:z,generatePath:v,fallback:k.StraightEdge};function ft(t){const e=k.useNodes();return A.jsx(L,{...t,options:yt,nodes:e})}const dt={drawEdge:z,generatePath:it,fallback:k.StepEdge};function St(t){const e=k.useNodes();return A.jsx(L,{...t,options:dt,nodes:e})}exports.SmartBezierEdge=ut;exports.SmartStepEdge=St;exports.SmartStraightEdge=ft;exports.getSmartEdge=q;exports.pathfindingAStarDiagonal=v;exports.svgDrawSmoothLinePath=I;
//# sourceMappingURL=index.cjs.map
;