drawui-core 0.1.0 → 0.2.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.
- package/LICENSE +21 -0
- package/README.md +56 -0
- package/dist/index.cjs +4 -4
- package/dist/index.d.cts +481 -47
- package/dist/index.d.ts +481 -47
- package/dist/index.js +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var K={identity(){return {a:1,b:0,c:0,d:1,e:0,f:0}},translation(u,t){return {a:1,b:0,c:0,d:1,e:u,f:t}},rotation(u){let t=Math.cos(u),e=Math.sin(u);return {a:t,b:e,c:-e,d:t,e:0,f:0}},scale(u,t){return {a:u,b:0,c:0,d:t,e:0,f:0}},multiply(u,t){return {a:u.a*t.a+u.b*t.c,b:u.a*t.b+u.b*t.d,c:u.c*t.a+u.d*t.c,d:u.c*t.b+u.d*t.d,e:u.e*t.a+u.f*t.c+t.e,f:u.e*t.b+u.f*t.d+t.f}},apply(u,t){return {x:u.a*t.x+u.c*t.y+u.e,y:u.b*t.x+u.d*t.y+u.f}},invert(u){let t=u.a*u.d-u.b*u.c;if(Math.abs(t)<1e-10)return null;let e=1/t;return {a:u.d*e,b:-u.b*e,c:-u.c*e,d:u.a*e,e:(u.c*u.f-u.d*u.e)*e,f:(u.b*u.e-u.a*u.f)*e}},createCameraMatrix(u){let t=K.scale(u.zoom,u.zoom),e=K.translation(u.x,u.y);return K.multiply(e,t)}};var q=class{x=0;y=0;zoom=1;minZoom=.1;maxZoom=10;getMatrix(){return K.createCameraMatrix({x:this.x,y:this.y,zoom:this.zoom})}getInverseMatrix(){return K.invert(this.getMatrix())}screenToPage(t){let e=this.getInverseMatrix();return e?K.apply(e,t):t}pageToScreen(t){return K.apply(this.getMatrix(),t)}translate(t,e){this.x+=t,this.y+=e;}zoomAt(t,e){let i=this.screenToPage(t);this.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.zoom*e));let n=this.pageToScreen(i);this.x+=t.x-n.x,this.y+=t.y-n.y;}reset(){this.x=0,this.y=0,this.zoom=1;}getZoom(){return this.zoom}fitBounds(t,e=50){let i=window.innerWidth,n=window.innerHeight,s=(i-e*2)/t.width,r=(n-e*2)/t.height,o=Math.min(s,r,this.maxZoom);this.zoom=Math.max(this.minZoom,o),this.x=(i-t.width*this.zoom)/2-t.x*this.zoom,this.y=(n-t.height*this.zoom)/2-t.y*this.zoom;}};var G={selection:{outline:"#3b82f6",handleStroke:"#3b82f6",handleFill:"#ffffff",outlineFill:"rgba(59, 130, 246, 0.1)",shadow:"#3b82f6"},grid:"#e5e7eb",text:"#1f2937",editBorder:"#3b82f6"};function gt(){return G}var H=class{context;constructor(t){this.context=t;}getCursor(t){return null}dispose(){}};var yt={strokeColor:"#1f2937",fillColor:"transparent",strokeWidth:2,strokeDash:null},pt={rectangle:{width:120,height:60},"rounded-rectangle":{width:120,height:60,borderRadius:8},circle:{width:80,height:80},ellipse:{width:100,height:70},diamond:{width:100,height:80},triangle:{width:100,height:90},hexagon:{width:100,height:90},parallelogram:{width:120,height:60},trapezoid:{width:120,height:70},pentagon:{width:100,height:90},octagon:{width:100,height:90},star:{width:100,height:100}},$=14,L=22,Y=36,N=14,D=8,j=160,ft=["rectangle","rounded-rectangle","circle","ellipse","diamond","triangle","hexagon","parallelogram","trapezoid","pentagon","octagon","star","uml-class","uml-interface"];function rt(u){return ft.includes(u)}function lt(u,t,e){let i=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,n=pt[u]||{width:120,height:60},s=n.width,r=n.height,o=n.radius??s/2,a=n.borderRadius??8,l=e??{...yt};switch(u){case "rounded-rectangle":return {id:i,type:"rounded-rectangle",x:t.x,y:t.y,width:s,height:r,borderRadius:a,rotation:0,style:l};case "circle":return {id:i,type:"circle",x:t.x,y:t.y,radius:o,rotation:0,style:l};case "ellipse":return {id:i,type:"ellipse",x:t.x,y:t.y,width:s,height:r,rotation:0,style:l};case "diamond":return {id:i,type:"diamond",x:t.x,y:t.y,width:s,height:r,rotation:0,style:l};case "triangle":return {id:i,type:"triangle",x:t.x,y:t.y,width:s,height:r,rotation:0,style:l};case "hexagon":return {id:i,type:"hexagon",x:t.x,y:t.y,width:s,height:r,rotation:0,style:l};case "parallelogram":return {id:i,type:"parallelogram",x:t.x,y:t.y,width:s,height:r,rotation:0,style:l};case "trapezoid":return {id:i,type:"trapezoid",x:t.x,y:t.y,width:s,height:r,rotation:0,style:l};case "pentagon":return {id:i,type:"pentagon",x:t.x,y:t.y,width:s,height:r,rotation:0,style:l};case "octagon":return {id:i,type:"octagon",x:t.x,y:t.y,width:s,height:r,rotation:0,style:l};case "star":return {id:i,type:"star",x:t.x,y:t.y,width:s,height:r,rotation:0,style:l};case "uml-class":{let h="ClassName",d=[{id:`attr_${Date.now()}_1`,visibility:"+",name:"field",type:"string"}],c=[{id:`meth_${Date.now()}_1`,visibility:"+",name:"method",params:"param",returnType:"void"}],{width:g,height:y}=ot(h,d,c);return {id:i,type:"uml-class",x:t.x,y:t.y,width:g,height:y,className:h,attributes:d,methods:c,rotation:0,style:{...l,fillColor:"#ffffff"}}}case "uml-interface":{let h="Interface",d=[{id:`meth_${Date.now()}_1`,visibility:"+",name:"method",params:"type",returnType:"type"}],c=$*.6,g=d.map(S=>`${S.visibility} ${S.name}(${S.params}): ${S.returnType}`),y=Math.max(h.length,...g.map(S=>S.length),0),p=Math.max(j,y*c+N*2),f=d.length>0?d.length*L+D*2:D*2,T=Y+f;return {id:i,type:"uml-interface",x:t.x,y:t.y,width:p,height:T,className:h,methods:d,rotation:0,style:{...l,fillColor:"#ffffff"}}}default:return {id:i,type:"rectangle",x:t.x,y:t.y,width:s,height:r,rotation:0,style:l}}}function ot(u,t,e){let i=$*.6,n=[u];for(let d of t)n.push(`${d.visibility} ${d.name}: ${d.type}`);for(let d of e)n.push(`${d.visibility} ${d.name}(${d.params}): ${d.returnType}`);let r=Math.max(...n.map(d=>d.length),0)*i+N*2,o=Math.max(j,r),a=t.length>0?t.length*L+D*2:D*2,l=e.length>0?e.length*L+D*2:D*2,h=Y+a+l;return {width:o,height:h}}var R=class extends H{type;constructor(t,e){super(t),this.type=e;}onPointerDown(t,e){let i=lt(this.type,t);this.context.commitHistory(),this.context.addShape(i),this.context.selectShape(i.id,false);}onPointerMove(t,e){}onPointerUp(t,e){this.context.setActiveTool("select");}onKeyDown(t){}onKeyUp(t){}getCursor(){return "crosshair"}};var J=class u{ctx;width=0;height=0;dpr=window.devicePixelRatio||1;showGrid=false;textLayoutCache=new Map;static TEXT_CACHE_LIMIT=500;constructor(t){let e=t.getContext("2d");if(!e)throw new Error("Failed to get Canvas 2D context");this.ctx=e;}resize(t,e){this.width=t,this.height=e;let i=Math.ceil(t*this.dpr),n=Math.ceil(e*this.dpr);(this.ctx.canvas.width!==i||this.ctx.canvas.height!==n)&&(this.ctx.canvas.width=i,this.ctx.canvas.height=n,this.ctx.canvas.style.width=`${t}px`,this.ctx.canvas.style.height=`${e}px`);}setShowGrid(t){this.showGrid=t;}render(t,e,i,n,s,r,o){let a=this.ctx,l=e.getZoom(),h=e.x,d=e.y;a.setTransform(1,0,0,1,0,0),a.clearRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);let c=this.dpr*l;a.setTransform(c,0,0,c,c*h,c*d),this.showGrid&&this.drawGrid(a,l,h,d);let g=null;for(let p of t)if(p.type==="arrow"&&(p.startBinding||p.endBinding)){g=new Map,t.forEach(f=>g.set(f.id,f));break}let y=g??new Map;t.forEach(p=>{a.save(),a.translate(p.x,p.y),a.rotate(p.rotation);let f=i.has(p.id);this.drawShape(a,p,f,l,y),a.restore();}),o&&this.drawGenerationPreview(a,o,l),n&&this.drawBrushRect(a,n,l),s&&s.length>0&&this.drawSnapGuides(a,s,l),r&&this.drawConnectingTargetHighlight(a,r,t,l),a.setTransform(1,0,0,1,0,0);}drawConnectingTargetHighlight(t,e,i,n){let s=i.find(l=>l.id===e);if(!s||s.type==="line"||s.type==="arrow"||s.type==="draw")return;let r=this.getShapeWorldBounds(s),o=[{x:r.x+r.width/2,y:r.y},{x:r.x+r.width,y:r.y+r.height/2},{x:r.x+r.width/2,y:r.y+r.height},{x:r.x,y:r.y+r.height/2}],a=6/n;t.save(),o.forEach(l=>{t.beginPath(),t.arc(l.x,l.y,a,0,Math.PI*2),t.fillStyle="#ffffff",t.fill(),t.strokeStyle="#3b82f6",t.lineWidth=2/n,t.stroke();}),t.restore();}getShapeWorldBounds(t){let e=this.getShapeBounds(t);return {x:t.x+e.x,y:t.y+e.y,width:e.width,height:e.height}}drawBrushRect(t,e,i){t.save(),t.fillStyle="rgba(59, 130, 246, 0.08)",t.strokeStyle="rgba(59, 130, 246, 0.8)",t.lineWidth=1.5/i,t.setLineDash([4/i,4/i]),t.beginPath(),t.rect(e.x,e.y,e.width,e.height),t.fill(),t.stroke(),t.restore();}drawGrid(t,e,i,n){let s=-i,r=-n,o=s+this.width/e,a=r+this.height/e,l=20;for(;l*e<10;)l*=2;t.strokeStyle=G.grid,t.lineWidth=1/e,t.beginPath();for(let h=Math.floor(s/l)*l;h<=o;h+=l)t.moveTo(h,r),t.lineTo(h,a);for(let h=Math.floor(r/l)*l;h<=a;h+=l)t.moveTo(s,h),t.lineTo(o,h);t.stroke();}drawShape(t,e,i,n,s){switch(this.applyStyle(t,e.style,n),e.type){case "rectangle":this.drawRectangle(t,e,i);break;case "rounded-rectangle":this.drawRoundedRectangle(t,e,i);break;case "circle":this.drawCircle(t,e,i);break;case "ellipse":this.drawEllipse(t,e,i);break;case "diamond":this.drawDiamond(t,e,i);break;case "triangle":this.drawTriangle(t,e,i);break;case "hexagon":this.drawHexagon(t,e,i);break;case "parallelogram":this.drawParallelogram(t,e,i);break;case "trapezoid":this.drawTrapezoid(t,e,i);break;case "pentagon":this.drawPentagon(t,e,i);break;case "octagon":this.drawOctagon(t,e,i);break;case "star":this.drawStar(t,e,i);break;case "uml-class":this.drawUmlClass(t,e,i);break;case "uml-interface":this.drawUmlInterface(t,e,i);break;case "line":this.drawLine(t,e,s,i,n);break;case "arrow":this.drawArrow(t,e,s,i,n);break;case "text":this.drawText(t,e);break;case "draw":this.drawFreehand(t,e);break}e.text&&e.type!=="text"&&e.type!=="line"&&e.type!=="arrow"&&e.type!=="draw"&&this.drawShapeText(t,e),i&&(e.type==="line"||e.type==="arrow"||e.type==="draw"||this.drawSelectionOutline(t,e,n),this.drawSelectionHandles(t,e,n));}applyStyle(t,e,i){t.strokeStyle=e.strokeColor,t.fillStyle=e.fillColor,t.lineWidth=e.strokeWidth/i,t.lineCap="round",t.lineJoin="round",e.strokeDash?t.setLineDash(e.strokeDash):t.setLineDash([]);}drawRectangle(t,e,i){t.beginPath(),t.rect(-e.width/2,-e.height/2,e.width,e.height),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawRoundedRectangle(t,e,i){let{width:n,height:s,borderRadius:r}=e;t.beginPath(),t.roundRect(-n/2,-s/2,n,s,r),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawCircle(t,e,i){t.beginPath(),t.arc(0,0,e.radius,0,Math.PI*2),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawEllipse(t,e,i){t.beginPath(),t.ellipse(0,0,e.width/2,e.height/2,0,0,Math.PI*2),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawDiamond(t,e,i){t.beginPath(),t.moveTo(0,-e.height/2),t.lineTo(e.width/2,0),t.lineTo(0,e.height/2),t.lineTo(-e.width/2,0),t.closePath(),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawTriangle(t,e,i){t.beginPath(),t.moveTo(0,-e.height/2),t.lineTo(e.width/2,e.height/2),t.lineTo(-e.width/2,e.height/2),t.closePath(),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawHexagon(t,e,i){let n=e.width/2,s=e.height/2;t.beginPath();for(let r=0;r<6;r++){let o=r*Math.PI/3-Math.PI/2,a=n*Math.cos(o),l=s*Math.sin(o);r===0?t.moveTo(a,l):t.lineTo(a,l);}t.closePath(),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawParallelogram(t,e,i){let{width:n,height:s}=e,r=n*.2;t.beginPath(),t.moveTo(-n/2+r,-s/2),t.lineTo(n/2,-s/2),t.lineTo(n/2-r,s/2),t.lineTo(-n/2,s/2),t.closePath(),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawTrapezoid(t,e,i){let{width:n,height:s}=e,r=n*.15;t.beginPath(),t.moveTo(-n/2+r,-s/2),t.lineTo(n/2-r,-s/2),t.lineTo(n/2,s/2),t.lineTo(-n/2,s/2),t.closePath(),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawPentagon(t,e,i){let n=e.width/2,s=e.height/2;t.beginPath();for(let r=0;r<5;r++){let o=r*2*Math.PI/5-Math.PI/2,a=n*Math.cos(o),l=s*Math.sin(o);r===0?t.moveTo(a,l):t.lineTo(a,l);}t.closePath(),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawOctagon(t,e,i){let n=e.width/2,s=e.height/2;t.beginPath();for(let r=0;r<8;r++){let o=r*Math.PI/4-Math.PI/8,a=n*Math.cos(o),l=s*Math.sin(o);r===0?t.moveTo(a,l):t.lineTo(a,l);}t.closePath(),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawStar(t,e,i){let n=e.width/2,s=e.height/2,r=5,o=.4;t.beginPath();for(let a=0;a<r*2;a++){let l=a*Math.PI/r-Math.PI/2,h=a%2===0?1:o,d=n*h*Math.cos(l),c=s*h*Math.sin(l);a===0?t.moveTo(d,c):t.lineTo(d,c);}t.closePath(),e.style.fillColor!=="transparent"&&t.fill(),t.stroke();}drawUmlClass(t,e,i){let{width:n,height:s,className:r,attributes:o,methods:a}=e,l=n/2,h=s/2,d=Y,c=o.length>0?o.length*L+D*2:D*2;t.beginPath(),t.rect(-l,-h,n,s),e.style.fillColor!=="transparent"&&(t.fillStyle=e.style.fillColor,t.fill()),t.stroke(),t.beginPath(),t.moveTo(-l,-h+d),t.lineTo(l,-h+d),t.moveTo(-l,-h+d+c),t.lineTo(l,-h+d+c),t.stroke(),t.save(),t.textBaseline="middle";let g=n-N*2,y=(S,I)=>{if(t.measureText(S).width<=g)return S;let b="\u2026",w=0,M=S.length;for(;w<M;){let C=w+M+1>>1;t.measureText(S.slice(0,C)+b).width<=g?w=C:M=C-1;}return S.slice(0,w)+b},p=(S,I,b,w,M,C,O)=>{let U=w||$,z=M||"#1f2937";t.font=`${U}px sans-serif`,t.fillStyle=z,t.textAlign=O;let A=y(S,t.font);if(t.fillText(A,I,b),C){let V=t.measureText(A).width,it=I;t.strokeStyle=z,t.beginPath(),t.moveTo(it,b),t.lineTo(it+V,b),t.stroke();}};t.font=`bold ${e.fontSize||$}px sans-serif`,t.textAlign="center",t.fillStyle=e.textColor||"#1f2937",t.fillText(y(r,t.font),0,-h+d/2);let f=-h+d+D+L/2;o.forEach((S,I)=>{let b=`${S.visibility} ${S.name}: ${S.type}`;p(b,-l+N,f+I*L,S.fontSize||e.fontSize||0,S.textColor||e.textColor||"",!!S.strikethrough,"left");});let T=-h+d+c+D+L/2;a.forEach((S,I)=>{let b=`${S.visibility} ${S.name}(${S.params}): ${S.returnType}`;p(b,-l+N,T+I*L,S.fontSize||e.fontSize||0,S.textColor||e.textColor||"",!!S.strikethrough,"left");}),t.restore();}drawUmlInterface(t,e,i){let{width:n,height:s,className:r,methods:o}=e,a=n/2,l=s/2,h=Y;t.beginPath(),t.rect(-a,-l,n,s),e.style.fillColor!=="transparent"&&(t.fillStyle=e.style.fillColor,t.fill()),t.stroke(),t.beginPath(),t.moveTo(-a,-l+h),t.lineTo(a,-l+h),t.stroke(),t.save(),t.textBaseline="middle";let d=n-N*2,c=(f,T)=>{if(t.measureText(f).width<=d)return f;let S="\u2026",I=0,b=f.length;for(;I<b;){let w=I+b+1>>1;t.measureText(f.slice(0,w)+S).width<=d?I=w:b=w-1;}return f.slice(0,I)+S},g=(f,T,S,I,b,w,M)=>{let C=I||$,O=b||"#1f2937";t.font=`${C}px sans-serif`,t.fillStyle=O,t.textAlign=M;let U=c(f,t.font);if(t.fillText(U,T,S),w){let z=t.measureText(U).width,A=T;t.strokeStyle=O,t.beginPath(),t.moveTo(A,S),t.lineTo(A+z,S),t.stroke();}};t.font=`bold ${e.fontSize||$}px sans-serif`,t.textAlign="center",t.fillStyle=e.textColor||"#1f2937";let y=`<<${r||"Interface"}>>`;t.fillText(c(y,t.font),0,-l+h/2);let p=-l+h+D+L/2;o.forEach((f,T)=>{let S=`${f.visibility} ${f.name}(${f.params}): ${f.returnType}`;g(S,-a+N,p+T*L,f.fontSize||e.fontSize||0,f.textColor||e.textColor||"",!!f.strikethrough,"left");}),t.restore();}static DEFAULT_CORNER_RADIUS=10;static ROUTE_CLEARANCE=30;static CONNECTION_LEAD=24;static CONNECTED_PAD=8;drawLine(t,e,i,n,s){if(e.points.length<2)return;let r=e.points.map(h=>({x:h.x,y:h.y}));r.length>=2&&(r[0]=this.clampToShapeOutline(r[0],i,e.id,r[r.length-1]),r[r.length-1]=this.clampToShapeOutline(r[r.length-1],i,e.id,r[0]));let o=r.map(h=>({x:h.x-e.x,y:h.y-e.y})),a=e.connectionType||"straight",l=a==="straight"?this.getAlignedPoints(o):this.buildPathPoints(o,a,this.collectRoutingObstacles(e.id,o[0],o[o.length-1],i,{x:e.x,y:e.y}),{fromN:this.getDockNormal(r[0],i,e.id),toN:this.getDockNormal(r[r.length-1],i,e.id)});if(a==="straight"){t.beginPath(),t.moveTo(o[0].x,o[0].y);for(let h=1;h<o.length;h++)t.lineTo(o[h].x,o[h].y);t.stroke(),t.setLineDash([]);}else a==="orthogonal"?this.drawSharpPolyline(t,l):this.drawRoundedPolyline(t,l,u.DEFAULT_CORNER_RADIUS),t.stroke(),t.setLineDash([]);n&&this.drawLinearHighlight(t,l,s);}drawArrow(t,e,i,n,s){if(e.points.length<2)return;let r=e.points.map(c=>({x:c.x,y:c.y}));if(e.startBinding){let c=i.get(e.startBinding.toShapeId);c&&(r[0]=this.getBindingPoint(c,e.startBinding));}if(e.endBinding){let c=i.get(e.endBinding.toShapeId);c&&(r[r.length-1]=this.getBindingPoint(c,e.endBinding));}r[0]=this.clampToShapeOutline(r[0],i,e.id,r[r.length-1]),r[r.length-1]=this.clampToShapeOutline(r[r.length-1],i,e.id,r[0]);let o=r.map(c=>({x:c.x-e.x,y:c.y-e.y})),a=e.connectionType||"straight",l=e.arrowHead??"end";!!e.dashed?t.setLineDash([8,5]):t.setLineDash([]);let d;if(a==="straight"){let c=this.getAlignedPoints(o);d=c,t.beginPath(),t.moveTo(c[0].x,c[0].y);for(let g=1;g<c.length;g++)t.lineTo(c[g].x,c[g].y);t.stroke(),this.drawArrowHeads(t,c,l);}else d=this.buildPathPoints(o,a,this.collectRoutingObstacles(e.id,o[0],o[o.length-1],i,{x:e.x,y:e.y}),{fromN:this.getDockNormal(r[0],i,e.id),toN:this.getDockNormal(r[r.length-1],i,e.id)}),a==="orthogonal"?this.drawSharpPolyline(t,d):this.drawRoundedPolyline(t,d,u.DEFAULT_CORNER_RADIUS),t.stroke(),this.drawArrowHeads(t,d,l);t.setLineDash([]),n&&this.drawLinearHighlight(t,d,s);}drawLinearHighlight(t,e,i){if(!(!e||e.length<2)){t.save(),t.strokeStyle="rgba(59, 130, 246, 0.4)",t.lineWidth=7/i,t.lineCap="round",t.lineJoin="round",t.setLineDash([]),t.beginPath(),t.moveTo(e[0].x,e[0].y);for(let n=1;n<e.length;n++)t.lineTo(e[n].x,e[n].y);t.stroke(),t.restore();}}drawGenerationPreview(t,e,i){let{from:n,to:s,type:r}=e;t.save(),t.beginPath(),t.arc(n.x,n.y,7/i,0,Math.PI*2),t.fillStyle="#3b82f6",t.fill(),t.strokeStyle="rgba(59, 130, 246, 0.55)",t.lineWidth=2/i,t.setLineDash([5/i,4/i]),t.lineCap="round",t.beginPath(),t.moveTo(n.x,n.y),t.lineTo(s.x,s.y),t.stroke(),r&&this.drawPreviewShapeOutline(t,s,r,i),t.restore();}drawPreviewShapeOutline(t,e,i,n){let l=e.x,h=e.y;switch(t.strokeStyle="rgba(59, 130, 246, 0.55)",t.lineWidth=1.5/n,t.setLineDash([6/n,4/n]),t.beginPath(),i){case "circle":case "ellipse":t.ellipse(l,h,i==="circle"?40:120/2,i==="circle"?40:60/2,0,0,Math.PI*2);break;case "diamond":t.moveTo(l,h-30),t.lineTo(l+60,h),t.lineTo(l,h+30),t.lineTo(l-60,h),t.closePath();break;case "triangle":t.moveTo(l,h-30),t.lineTo(l+60,h+30),t.lineTo(l-60,h+30),t.closePath();break;case "hexagon":for(let d=0;d<6;d++){let c=d*Math.PI/3-Math.PI/2,g=l+60*Math.cos(c),y=h+30*Math.sin(c);d===0?t.moveTo(g,y):t.lineTo(g,y);}t.closePath();break;case "parallelogram":t.moveTo(l-60+18,h-30),t.lineTo(l+60,h-30),t.lineTo(l+60-18,h+30),t.lineTo(l-60,h+30),t.closePath();break;default:t.roundRect(l-60,h-30,120,60,i==="rounded-rectangle"?8:4);break}t.stroke();}static ALIGN_TOLERANCE=8;getAlignedPoints(t){if(t.length<2)return t;let e=t[0],i=t[t.length-1],n=i.x-e.x,s=i.y-e.y,r=u.ALIGN_TOLERANCE;if(Math.abs(s)<=r){let o=(e.y+i.y)/2;return t.map(a=>({x:a.x,y:o}))}if(Math.abs(n)<=r){let o=(e.x+i.x)/2;return t.map(a=>({x:o,y:a.y}))}return t}buildPathPoints(t,e,i=[],n={}){if(t.length<2||e==="straight")return t;switch(e){case "polyline":return this.generatePolylinePoints(t,i,n);case "orthogonal":return this.generateOrthogonalPoints(t,i,n);case "curve":return this.generateCurvePoints(t);default:return t}}drawRoundedPolyline(t,e,i){if(t.beginPath(),!(e.length<2)){if(e.length===2||i<=0){t.moveTo(e[0].x,e[0].y);for(let n=1;n<e.length;n++)t.lineTo(e[n].x,e[n].y);return}t.moveTo(e[0].x,e[0].y);for(let n=1;n<e.length-1;n++){let s=e[n-1],r=e[n],o=e[n+1],a=r.x-s.x,l=r.y-s.y,h=o.x-r.x,d=o.y-r.y,c=Math.hypot(a,l),g=Math.hypot(h,d);if(c<1e-6||g<1e-6){t.lineTo(r.x,r.y);continue}let y=Math.min(i,c*.5,g*.5),p=r.x-a/c*y,f=r.y-l/c*y,T=r.x+h/g*y,S=r.y+d/g*y;t.lineTo(p,f),t.arcTo(r.x,r.y,T,S,y);}t.lineTo(e[e.length-1].x,e[e.length-1].y);}}drawSharpPolyline(t,e){if(t.beginPath(),!(e.length<2)){t.moveTo(e[0].x,e[0].y);for(let i=1;i<e.length;i++)t.lineTo(e[i].x,e[i].y);}}drawSnapGuides(t,e,i){t.save(),t.strokeStyle="rgba(59, 130, 246, 0.6)",t.lineWidth=1/i,t.setLineDash([6/i,4/i]),t.beginPath();for(let n of e)n.type==="horizontal"?(t.moveTo(n.start,n.position),t.lineTo(n.end,n.position)):(t.moveTo(n.position,n.start),t.lineTo(n.position,n.end));t.stroke(),t.restore();}generatePolylinePoints(t,e=[],i={}){if(t.length<2)return t;let n=[];n.push(t[0]);let s=t.length-1,r=u.CONNECTION_LEAD;for(let o=1;o<t.length;o++){let a=t[o-1],l=t[o],h=o===1,d=o===s,c=h&&i.fromN?{x:a.x+i.fromN.x*r,y:a.y+i.fromN.y*r}:a,g=d&&i.toN?{x:l.x+i.toN.x*r,y:l.y+i.toN.y*r}:l;h&&i.fromN&&n.push(c);let y=this.computeOrthogonalRoute(c,g,e);for(let p of y)n.push(p);d&&i.toN&&n.push(l);}return this.collapseLinePoints(n)}generateOrthogonalPoints(t,e=[],i={}){return this.generatePolylinePoints(t,e,i)}collapseLinePoints(t){let e=[];for(let i of t){let n=e.length;if(!(n>0&&Math.abs(e[n-1].x-i.x)<1e-6&&Math.abs(e[n-1].y-i.y)<1e-6)){if(n>=2){let s=e[n-2],r=e[n-1];if(Math.abs(s.y-r.y)<1e-6&&Math.abs(r.y-i.y)<1e-6||Math.abs(s.x-r.x)<1e-6&&Math.abs(r.x-i.x)<1e-6){e[n-1]=i;continue}}e.push(i);}}return e}computeOrthogonalRoute(t,e,i=[]){let n=e.x-t.x,s=e.y-t.y;if(Math.abs(n)<1||Math.abs(s)<1)return [e];let r=t.x+n/2,o=t.y+s/2,a=i.length>0,l=[[{x:r,y:t.y},{x:r,y:e.y},e],[{x:t.x,y:o},{x:e.x,y:o},e],[{x:e.x,y:t.y},e],[{x:t.x,y:e.y},e]];if(a){for(let d of l)if(!this.routeHitsObstacles(t,d,i))return d;let h=this.routeOrthogonalAvoidance(t,e,i);return h&&h.length>0?h:i.length>0&&!this.routeHitsObstacles(t,l[0],i)?l[0]:this.routeHitsObstacles(t,l[1],i)?[e]:l[1]}return Math.abs(n)>=Math.abs(s)?[{x:r,y:t.y},{x:r,y:e.y},e]:[{x:t.x,y:o},{x:e.x,y:o},e]}collectRoutingObstacles(t,e,i,n,s){if(!n||n.size===0)return [];let r=[];return n.forEach((o,a)=>{if(a===t)return;let l=this.getShapeBounds(o),h={x:o.x+l.x-s.x,y:o.y+l.y-s.y,width:l.width,height:l.height};h.pad=this.pointInRect(e,h)||this.pointInRect(i,h)?u.CONNECTED_PAD:u.ROUTE_CLEARANCE,r.push(h);}),r}pointInRect(t,e){return t.x>=e.x&&t.x<=e.x+e.width&&t.y>=e.y&&t.y<=e.y+e.height}routeHitsObstacles(t,e,i){let n=[t,...e];for(let s=1;s<n.length;s++)if(this.segmentHitsObstacle(n[s-1],n[s],i))return true;return false}segmentHitsObstacle(t,e,i){for(let n of i){let s=n.pad??u.ROUTE_CLEARANCE,r=n.y-s,o=n.y+n.height+s,a=n.x-s,l=n.x+n.width+s;if(Math.abs(t.y-e.y)<.5){if(t.y>=r&&t.y<=o){let h=Math.min(t.x,e.x);if(Math.max(t.x,e.x)>=a&&h<=l)return true}}else if(t.x>=a&&t.x<=l){let h=Math.min(t.y,e.y);if(Math.max(t.y,e.y)>=r&&h<=o)return true}}return false}routeOrthogonalAvoidance(t,e,i){let n=new Set([t.x,e.x]),s=new Set([t.y,e.y]);for(let m of i){let x=m.pad??u.ROUTE_CLEARANCE;n.add(m.x-x),n.add(m.x+m.width+x),s.add(m.y-x),s.add(m.y+m.height+x);}let r=[...n].sort((m,x)=>m-x),o=[...s].sort((m,x)=>m-x),a=r.length,l=o.length,h=m=>{for(let x=0;x<a;x++)if(Math.abs(r[x]-m)<1e-6)return x;return 0},d=m=>{for(let x=0;x<l;x++)if(Math.abs(o[x]-m)<1e-6)return x;return 0},c=h(t.x),g=d(t.y),y=h(e.x),p=d(e.y),f=[],T=[];for(let m=0;m<a;m++)f.push(new Array(l).fill(true)),T.push(new Array(l).fill(true));for(let m of i){let x=m.pad??u.ROUTE_CLEARANCE,v=m.x-x,P=m.x+m.width+x,k=m.y-x,B=m.y+m.height+x;for(let E=0;E<a-1;E++)if(!(r[E+1]<=v||r[E]>=P))for(let _=0;_<l;_++)o[_]>k&&o[_]<B&&(f[E][_]=false);for(let E=0;E<l-1;E++)if(!(o[E+1]<=k||o[E]>=B))for(let _=0;_<a;_++)r[_]>v&&r[_]<P&&(T[_][E]=false);}let S=a*l,I=1/0,b=new Float64Array(S).fill(I),w=new Int32Array(S).fill(-1),M=new Uint8Array(S),C=m=>{let x=m%a,v=m/a|0;return Math.abs(r[x]-e.x)+Math.abs(o[v]-e.y)},O=(m,x)=>m%a===x%a,U=g*a+c,z=p*a+y;b[U]=0;let A=[U],V=[C(U)],it=m=>{let x=b[m]+C(m);A.push(m),V.push(x);let v=A.length-1;for(;v>0;){let P=v-1>>1;if(V[P]<=V[v])break;[A[P],A[v]]=[A[v],A[P]],[V[P],V[v]]=[V[v],V[P]],v=P;}},ut=()=>{let m=A[0],x=A.pop(),v=V.pop();if(A.length){A[0]=x,V[0]=v;let P=0;for(;;){let k=P*2+1,B=k+1,E=P;if(k<A.length&&V[k]<V[E]&&(E=k),B<A.length&&V[B]<V[E]&&(E=B),E===P)break;[A[E],A[P]]=[A[P],A[E]],[V[E],V[P]]=[V[P],V[E]],P=E;}}return m},st=(m,x,v)=>{let P=m%a,k=x%a,B=b[m]+(Math.abs(k-P)===0?Math.abs(o[x/a|0]-o[m/a|0]):Math.abs(r[k]-r[P]))+v;B<b[x]&&(b[x]=B,w[x]=m,M[x]||it(x));};for(;A.length;){let m=ut();if(m===z||M[m]){if(m===z)break;continue}M[m]=1;let x=m%a,v=m/a|0,P=w[m],k=P>=0?O(P,m)?"v":"h":"",B=E=>{let _=O(m,E)?"v":"h";return k!==""&&k!==_?24:0};x+1<a&&f[x][v]&&st(m,v*a+x+1,B(v*a+x+1)),x-1>=0&&f[x-1][v]&&st(m,v*a+x-1,B(v*a+x-1)),v+1<l&&T[x][v]&&st(m,(v+1)*a+x,B((v+1)*a+x)),v-1>=0&&T[x][v-1]&&st(m,(v-1)*a+x,B((v-1)*a+x));}if(b[z]===I)return null;let ht=[];for(let m=z;m!==-1;m=w[m])ht.push({x:r[m%a],y:o[m/a|0]});ht.reverse();let F=[];for(let m of ht){let x=F.length;if(x>=2){let v=F[x-2],P=F[x-1];if(Math.abs(v.y-P.y)<1e-6&&Math.abs(P.y-m.y)<1e-6||Math.abs(v.x-P.x)<1e-6&&Math.abs(P.x-m.x)<1e-6){F[x-1]=m;continue}}F.push(m);}return F.slice(1)}generateCurvePoints(t){if(t.length<2)return t;let e=[],i=20,n=t[0],s=n;e.push(n);for(let r=1;r<t.length;r++){let o=t[r],a=this.computeCurveControlPoint(s,o);for(let l=1;l<=i;l++){let h=l/i,d=(1-h)*(1-h)*s.x+2*(1-h)*h*a.x+h*h*o.x,c=(1-h)*(1-h)*s.y+2*(1-h)*h*a.y+h*h*o.y;e.push({x:d,y:c});}s=o;}return e}computeCurveControlPoint(t,e){let i=e.x-t.x,n=e.y-t.y,s=Math.sqrt(i*i+n*n);if(s<1)return {x:t.x,y:t.y};let r=(t.x+e.x)/2,o=(t.y+e.y)/2,a=-n/s,l=i/s,h=Math.min(s*.2,30);return {x:r+a*h,y:o+l*h}}getDisplayLines(t,e,i,n,s,r){let o=n*1.3,a=Math.max(1,Math.floor(r/o)),l=`${e.id}\0${i}\0${n}\0${s}x${r}\0${a}`,h=this.textLayoutCache.get(l);if(h)return h;let d=i.split(`
|
|
2
|
-
`),c=[];for(let y of d){let p=this.wrapLine(t,y,s);for(let f of p)c.push(f);}let g=c.slice(0,a);return c.length>a&&g.length>0&&(g[g.length-1]=this.truncateLine(t,g[g.length-1],s)),this.textLayoutCache.size>=u.TEXT_CACHE_LIMIT&&this.textLayoutCache.clear(),this.textLayoutCache.set(l,g),g}drawShapeText(t,e){let i=e.text||"";if(!i)return;let n=e.fontSize||16;t.font=`${n}px sans-serif`,t.fillStyle=e.textColor||"#1f2937";let s=this.getTextBounds(e),r=n*1.3,o=this.getDisplayLines(t,e,i,n,s.width,s.height),l=-(o.length*r)/2+r/2;t.textAlign="center",t.textBaseline="middle",o.forEach((h,d)=>{let c=l+d*r;t.fillText(h,0,c);});}getTextBounds(t){switch(t.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":return {width:t.width*.85,height:t.height*.85};case "circle":return {width:t.radius*2*.85,height:t.radius*2*.85};default:return {width:100,height:40}}}wrapLine(t,e,i){if(!e)return [""];let n=[],s="";for(let r of e){let o=s+r;t.measureText(o).width>i&&s?(n.push(s),s=r):s=o;}return s&&n.push(s),n}truncateLine(t,e,i){if(!e)return "...";let n="...",s=e;for(;s.length>0&&t.measureText(s+n).width>i;)s=s.slice(0,-1);return s+n}getBindingPoint(t,e){if(e.isPrecise&&e.normalizedAnchor){let i=this.getShapePageBounds(t),n={x:i.x+i.width*e.normalizedAnchor.x,y:i.y+i.height*e.normalizedAnchor.y},s={x:t.x,y:t.y};return this.nearestPointOnShapeOutline(t,s,n)}if(e.handle){let i=this.getShapeBounds(t);switch(e.handle){case "top":return {x:t.x,y:t.y+i.y};case "bottom":return {x:t.x,y:t.y+i.y+i.height};case "left":return {x:t.x+i.x,y:t.y};case "right":return {x:t.x+i.x+i.width,y:t.y}}}return {x:t.x,y:t.y}}getDockNormal(t,e,i){if(!e||e.size===0)return;let n=null,s=1/0,r=.5;if(e.forEach((h,d)=>{if(d===i)return;let c=this.getShapePageBounds(h);if(t.x>=c.x-r&&t.x<=c.x+c.width+r&&t.y>=c.y-r&&t.y<=c.y+c.height+r){let g=(t.x-h.x)**2+(t.y-h.y)**2;g<s&&(s=g,n=h);}}),!n)return;let o=n,a=t.x-o.x,l=t.y-o.y;return Math.abs(l)>Math.abs(a)?{x:0,y:l<0?-1:1}:{x:a<0?-1:1,y:0}}getShapePageBounds(t){let e=this.getShapeBounds(t);return {x:t.x+e.x,y:t.y+e.y,width:e.width,height:e.height}}clampToShapeOutline(t,e,i,n){if(!e||e.size===0)return t;let s=null,r=1/0;if(e.forEach((a,l)=>{if(l===i)return;let h=this.getShapePageBounds(a);if(t.x>h.x&&t.x<h.x+h.width&&t.y>h.y&&t.y<h.y+h.height){let d=(a.x-n.x)**2+(a.y-n.y)**2;d<r&&(r=d,s=a);}}),!s)return t;let o=s;return this.nearestPointOnShapeOutline(o,{x:o.x,y:o.y},t)}nearestPointOnShapeOutline(t,e,i){let n=i.x-e.x,s=i.y-e.y,r=Math.hypot(n,s);if(r<1e-6)return {x:e.x,y:e.y};let o=n/r,a=s/r,l=Math.max(1e4,r*2),h={x:e.x+o*l,y:e.y+a*l},d=this.intersectShapeOutlineWithSegment(t,e,h);if(d.length===0)return i;let c=d[0],g=(c.x-e.x)**2+(c.y-e.y)**2;for(let y=1;y<d.length;y++){let p=(d[y].x-e.x)**2+(d[y].y-e.y)**2;p<g&&(g=p,c=d[y]);}return c}intersectShapeOutlineWithSegment(t,e,i){let n={x:e.x-t.x,y:e.y-t.y},s={x:i.x-t.x,y:i.y-t.y};return this.intersectLocalShapeOutlineWithSegment(t,n,s).map(o=>({x:o.x+t.x,y:o.y+t.y}))}intersectLocalShapeOutlineWithSegment(t,e,i){switch(t.type){case "rectangle":case "rounded-rectangle":{let n=t.width,s=t.height,r={x:-n/2,y:-s/2,width:n,height:s};return this.intersectSegmentRect(e,i,r)}case "ellipse":case "diamond":case "triangle":{let n=t.width,s=t.height,r={x:-n/2,y:-s/2,width:n,height:s};return this.intersectSegmentRect(e,i,r)}case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":{let n=t.width,s=t.height,r={x:-n/2,y:-s/2,width:n,height:s};return this.intersectSegmentRect(e,i,r)}case "circle":{let n=t.radius;return this.intersectSegmentCircle(e,i,{x:0,y:0},n)}default:return []}}intersectSegmentRect(t,e,i){let n=i.x,s=i.y,r=i.width,o=i.height,a=[[{x:n,y:s},{x:n+r,y:s}],[{x:n+r,y:s},{x:n+r,y:s+o}],[{x:n+r,y:s+o},{x:n,y:s+o}],[{x:n,y:s+o},{x:n,y:s}]],l=[];for(let[h,d]of a){let c=this.segmentIntersection(t,e,h,d);c&&l.push(c);}return l}segmentIntersection(t,e,i,n){let s=t.x,r=t.y,o=e.x,a=e.y,l=i.x,h=i.y,d=n.x,c=n.y,g=(s-o)*(h-c)-(r-a)*(l-d);if(Math.abs(g)<1e-9)return null;let y=((s-l)*(h-c)-(r-h)*(l-d))/g,p=-((s-o)*(r-h)-(r-a)*(s-l))/g;return y<0||y>1||p<0||p>1?null:{x:s+y*(o-s),y:r+y*(a-r)}}intersectSegmentCircle(t,e,i,n){let s=e.x-t.x,r=e.y-t.y,o=t.x-i.x,a=t.y-i.y,l=s*s+r*r,h=2*(o*s+a*r),d=o*o+a*a-n*n,c=h*h-4*l*d;if(c<0)return [];c=Math.sqrt(c);let g=(-h-c)/(2*l),y=(-h+c)/(2*l),p=[];return g>=0&&g<=1&&p.push({x:t.x+g*s,y:t.y+g*r}),y>=0&&y<=1&&Math.abs(y-g)>1e-6&&p.push({x:t.x+y*s,y:t.y+y*r}),p}drawArrowHead(t,e,i){let n=Math.atan2(i.y-e.y,i.x-e.x),s=12;t.beginPath(),t.moveTo(i.x,i.y),t.lineTo(i.x-s*Math.cos(n-Math.PI/6),i.y-s*Math.sin(n-Math.PI/6)),t.moveTo(i.x,i.y),t.lineTo(i.x-s*Math.cos(n+Math.PI/6),i.y-s*Math.sin(n+Math.PI/6)),t.stroke();}drawInheritanceHead(t,e,i){let n=Math.atan2(i.y-e.y,i.x-e.x),s=14,r=i.x,o=i.y,a=i.x-s*Math.cos(n),l=i.y-s*Math.sin(n),h=a+s*.5*Math.cos(n-Math.PI/2),d=l+s*.5*Math.sin(n-Math.PI/2),c=a+s*.5*Math.cos(n+Math.PI/2),g=l+s*.5*Math.sin(n+Math.PI/2);t.save(),t.fillStyle="#ffffff",t.beginPath(),t.moveTo(r,o),t.lineTo(h,d),t.lineTo(c,g),t.closePath(),t.fill(),t.stroke(),t.restore();}drawDiamondHead(t,e,i,n){let s=Math.atan2(i.y-e.y,i.x-e.x),r=14,o=i.x,a=i.y,l=i.x-r*.5*Math.cos(s),h=i.y-r*.5*Math.sin(s),d=i.x-r*Math.cos(s),c=i.y-r*Math.sin(s),g=l+r*.4*Math.cos(s-Math.PI/2),y=h+r*.4*Math.sin(s-Math.PI/2),p=l+r*.4*Math.cos(s+Math.PI/2),f=h+r*.4*Math.sin(s+Math.PI/2);t.save(),t.fillStyle=n?"#1f2937":"#ffffff",t.beginPath(),t.moveTo(o,a),t.lineTo(g,y),t.lineTo(d,c),t.lineTo(p,f),t.closePath(),t.fill(),t.stroke(),t.restore();}drawArrowHeads(t,e,i){if(i!=="none"){if(i==="start"||i==="both"){let n=e[0],s=e[1];this.drawArrowHead(t,s,n);}if(i==="end"||i==="both"){let n=e.length,s=e[n-2],r=e[n-1];this.drawArrowHead(t,s,r);}if(i==="inheritance"){let n=e.length,s=e[n-2],r=e[n-1];this.drawInheritanceHead(t,s,r);}if(i==="aggregation"){let n=e[0],s=e[1];this.drawDiamondHead(t,s,n,false);}if(i==="composition"){let n=e[0],s=e[1];this.drawDiamondHead(t,s,n,true);}}}drawText(t,e){if(!e.text)return;let i=e.fontSize;t.font=`${i}px sans-serif`,t.textAlign="center",t.textBaseline="middle";let n=e.width,s=e.height,r=i*1.3,o=this.getDisplayLines(t,e,e.text,i,n,s),a=o.length*r,l=-a/2+r/2;if(e.highlightColor&&e.highlightColor!=="transparent"){t.fillStyle=e.highlightColor;let h=i*.15;t.beginPath(),t.roundRect(-n/2-h,-a/2-h,n+h*2,a+h*2,4),t.fill();}t.fillStyle=e.textColor||"#1f2937",o.forEach((h,d)=>{let c=l+d*r;t.fillText(h,0,c);});}drawFreehand(t,e){if(e.points.length<2)return;let i=e.points.map(n=>({x:n.x-e.x,y:n.y-e.y}));t.beginPath(),t.moveTo(i[0].x,i[0].y);for(let n=1;n<i.length-1;n++){let s=(i[n].x+i[n+1].x)/2,r=(i[n].y+i[n+1].y)/2;t.quadraticCurveTo(i[n].x,i[n].y,s,r);}t.lineTo(i[i.length-1].x,i[i.length-1].y),t.stroke();}drawSelectionOutline(t,e,i){let n=this.getShapeBounds(e);t.strokeStyle=G.selection.outline,t.lineWidth=1/i,t.setLineDash([]),t.save(),t.shadowColor=G.selection.shadow,t.shadowBlur=8,t.shadowOffsetX=0,t.shadowOffsetY=0,t.beginPath(),t.roundRect(n.x-2,n.y-2,n.width+4,n.height+4,4),t.stroke(),t.restore(),t.fillStyle=G.selection.outlineFill,t.beginPath(),t.roundRect(n.x-2,n.y-2,n.width+4,n.height+4,4),t.fill();}drawSelectionHandles(t,e,i){let n=8/i;if((e.type==="line"||e.type==="arrow"||e.type==="draw")&&e.points&&e.points.length>=2){let r=e.points.map(d=>({x:d.x-e.x,y:d.y-e.y})),o=r[0],a=r[r.length-1];t.fillStyle=G.selection.handleFill,t.strokeStyle=G.selection.handleStroke,t.lineWidth=2/i,t.setLineDash([]),[o,a].forEach(d=>{t.beginPath(),t.arc(d.x,d.y,n/2,0,Math.PI*2),t.fill(),t.stroke();});let l=(o.x+a.x)/2,h=(o.y+a.y)/2;t.beginPath(),t.arc(l,h,7/i,0,Math.PI*2),t.fillStyle="#ffffff",t.fill(),t.strokeStyle="#3b82f6",t.lineWidth=1.5/i,t.stroke(),t.beginPath(),t.arc(l,h,3/i,0,Math.PI*2),t.fillStyle="#3b82f6",t.fill();}else {let r=this.getShapeBounds(e),o=n,a=[{x:r.x,y:r.y},{x:r.x+r.width,y:r.y},{x:r.x+r.width,y:r.y+r.height},{x:r.x,y:r.y+r.height}];t.fillStyle=G.selection.handleFill,t.strokeStyle=G.selection.handleStroke,t.lineWidth=2/i,t.setLineDash([]),a.forEach(y=>{t.beginPath(),t.roundRect(y.x-o/2,y.y-o/2,o,o,2),t.fill(),t.stroke();});let l=9/i;[{x:r.x+r.width/2,y:r.y},{x:r.x+r.width,y:r.y+r.height/2},{x:r.x+r.width/2,y:r.y+r.height},{x:r.x,y:r.y+r.height/2}].forEach(y=>{t.beginPath(),t.arc(y.x,y.y,l,0,Math.PI*2),t.fillStyle="#ffffff",t.fill(),t.strokeStyle="#3b82f6",t.lineWidth=1.5/i,t.stroke(),t.beginPath(),t.arc(y.x,y.y,l*.45,0,Math.PI*2),t.fillStyle="#3b82f6",t.fill();});let d=26/i,c=r.x+r.width/2,g=r.y-d;t.strokeStyle="#94a3b8",t.lineWidth=1.5/i,t.setLineDash([]),t.beginPath(),t.moveTo(c,r.y),t.lineTo(c,g),t.stroke(),t.beginPath(),t.arc(c,g,8/i,0,Math.PI*2),t.fillStyle="#ffffff",t.fill(),t.strokeStyle="#3b82f6",t.lineWidth=1.6/i,t.stroke(),this.drawRotateIcon(t,c,g,i);}}drawRotateIcon(t,e,i,n){let s=8/n;t.save(),t.translate(e,i),t.strokeStyle="#3b82f6",t.lineWidth=1.8/n,t.lineCap="round",t.beginPath(),t.arc(0,0,s*.5,Math.PI*.18,Math.PI*1.6,false),t.stroke();let r=Math.PI*.18,o=Math.cos(r)*s*.5,a=Math.sin(r)*s*.5,l=1;t.beginPath(),t.moveTo(o,a),t.lineTo(o-Math.cos(r)*s*.26+l*Math.sin(r)*s*.16,a-Math.sin(r)*s*.26-l*Math.cos(r)*s*.16),t.moveTo(o,a),t.lineTo(o-Math.cos(r)*s*.26-l*Math.sin(r)*s*.16,a-Math.sin(r)*s*.26+l*Math.cos(r)*s*.16),t.stroke(),t.restore();}getShapeBounds(t){switch(t.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":return {x:-t.width/2,y:-t.height/2,width:t.width,height:t.height};case "circle":return {x:-t.radius,y:-t.radius,width:t.radius*2,height:t.radius*2};case "line":case "arrow":case "draw":if(t.points.length===0)return {x:0,y:0,width:0,height:0};let e=1/0,i=1/0,n=-1/0,s=-1/0;return t.points.forEach(r=>{e=Math.min(e,r.x-t.x),i=Math.min(i,r.y-t.y),n=Math.max(n,r.x-t.x),s=Math.max(s,r.y-t.y);}),{x:e,y:i,width:n-e,height:s-i};case "text":{let r=t;return {x:-r.width/2,y:-r.height/2,width:r.width,height:r.height}}default:return {x:0,y:0,width:0,height:0}}}};var X={create(u=0,t=0){return {x:u,y:t}},add(u,t){return {x:u.x+t.x,y:u.y+t.y}},subtract(u,t){return {x:u.x-t.x,y:u.y-t.y}},multiply(u,t){return {x:u.x*t,y:u.y*t}},divide(u,t){return {x:u.x/t,y:u.y/t}},dot(u,t){return u.x*t.x+u.y*t.y},length(u){return Math.sqrt(u.x*u.x+u.y*u.y)},normalize(u){let t=X.length(u);return t===0?{x:0,y:0}:{x:u.x/t,y:u.y/t}},distance(u,t){return X.length(X.subtract(u,t))},rotate(u,t){let e=Math.cos(t),i=Math.sin(t);return {x:u.x*e-u.y*i,y:u.x*i+u.y*e}},clone(u){return {x:u.x,y:u.y}},equals(u,t){return u.x===t.x&&u.y===t.y}};function W(u,t,e,i=8){let n=[];if(e==="horizontal"){let s=Math.min(u.x,t.x),r=Math.max(u.x+u.width,t.x+t.width),o=Math.abs(u.y-t.y)<=i,a=Math.abs(u.y+u.height-(t.y+t.height))<=i,l=Math.abs(u.y+u.height/2-(t.y+t.height/2))<=i;o&&n.push({type:"horizontal",position:(u.y+t.y)/2,start:s,end:r}),a&&n.push({type:"horizontal",position:(u.y+u.height+t.y+t.height)/2,start:s,end:r}),l&&!(o&&a)&&n.push({type:"horizontal",position:(u.y+u.height/2+t.y+t.height/2)/2,start:s,end:r});}else {let s=Math.min(u.y,t.y),r=Math.max(u.y+u.height,t.y+t.height),o=Math.abs(u.x-t.x)<=i,a=Math.abs(u.x+u.width-(t.x+t.width))<=i,l=Math.abs(u.x+u.width/2-(t.x+t.width/2))<=i;o&&n.push({type:"vertical",position:(u.x+t.x)/2,start:s,end:r}),a&&n.push({type:"vertical",position:(u.x+u.width+t.x+t.width)/2,start:s,end:r}),l&&!(o&&a)&&n.push({type:"vertical",position:(u.x+u.width/2+t.x+t.width/2)/2,start:s,end:r});}return n}var Q=class u extends H{type="select";state="idle";translatingState=null;resizingState=null;generatingState=null;hoverGenPoint=null;rotatingState=null;draggingArrowId=null;draggingTerminal=null;pendingHistoryCommit=false;brushStart={x:0,y:0};brushShiftKey=false;defaultGenType(t){if(t){let e=this.context.getShapes().find(i=>i.id===t);if(e&&rt(e.type))return e.type}return "rectangle"}genPreviewOf(t,e){return {from:t.point,to:e,type:this.defaultGenType(t.sourceShapeId)}}genContext(t,e){return {from:t.point,to:e,sourceShapeId:t.sourceShapeId,edge:t.edge}}onPointerDown(t,e){let i=this.context.getShapes(),n=this.context.getSelectedIds(),s=this.hitTestArrowTerminal(t,i);if(s&&n.includes(s.shapeId)){this.state="dragging-terminal",this.draggingArrowId=s.shapeId,this.draggingTerminal=s.terminal,this.pendingHistoryCommit=true,this.context.updateArrowBinding(s.shapeId,s.terminal,null);return}let r=this.hitGenPoint(t,i,n);if(r){this.state="generating",this.generatingState={source:r,startPoint:t,hasMoved:false},this.pendingHistoryCommit=true,this.context.setGenerationPreview(this.genPreviewOf(r,this.genPreviewTarget(r,t,false)));return}let o=this.hitTest(t,i,n);if(o.handle==="rotation"){this.state="rotating",this.pendingHistoryCommit=true;let a=o.shape;this.rotatingState={shapeId:a.id,center:{x:a.x,y:a.y},startAngle:Math.atan2(t.y-a.y,t.x-a.x),startRotation:a.rotation};return}if(o.handle){this.state="resizing",this.resizingState={startPoint:t,startShape:o.shape,handle:o.handle},this.pendingHistoryCommit=true;return}if(o.shape){let a=o.shape,l=a.type==="line"||a.type==="arrow"||a.type==="draw",h=n.includes(a.id);if(l&&!h){this.context.selectShape(a.id,e.shiftKey);return}this.state="translating",this.pendingHistoryCommit=true,h||this.context.selectShape(a.id,e.shiftKey);let d=this.context.getSelectedIds(),c=new Map,g=new Map,y=new Map;d.forEach(p=>{let f=i.find(T=>T.id===p);f&&(c.set(p,{x:f.x,y:f.y}),g.set(p,f.rotation),y.set(p,this.getShapeWorldBounds(f)));}),this.translatingState={startPoint:t,startPositions:c,startRotation:g,startBounds:y};}else this.state="brushing",this.brushStart=t,this.brushShiftKey=e.shiftKey,e.shiftKey||this.context.selectShape("",false);}onPointerMove(t,e){let i=this.context.getShapes();if(this.state==="translating"&&this.translatingState)this.pendingHistoryCommit&&(this.context.commitHistory(),this.pendingHistoryCommit=false),this.handleTranslating(t,e);else if(this.state==="generating"&&this.generatingState)this.pendingHistoryCommit&&(this.context.commitHistory(),this.pendingHistoryCommit=false),this.handleGenerating(t,i);else if(this.state==="rotating"&&this.rotatingState)this.pendingHistoryCommit&&(this.context.commitHistory(),this.pendingHistoryCommit=false),this.handleRotating(t,e);else if(this.state==="resizing"&&this.resizingState)this.pendingHistoryCommit&&(this.context.commitHistory(),this.pendingHistoryCommit=false),this.handleResizing(t);else if(this.state==="dragging-terminal"&&this.draggingArrowId&&this.draggingTerminal){this.pendingHistoryCommit&&(this.context.commitHistory(),this.pendingHistoryCommit=false);let n=i.find(s=>s.id===this.draggingArrowId);if(n){let s=this.draggingTerminal==="start"?t:n.points[n.points.length-1],r=this.draggingTerminal==="start"?n.points[0]:t,o=this.computeSnapGuidesForArrow(s,r,t,n,i);this.context.setSnapGuides(o);let a=t;if(o.length>0){let d=o.filter(g=>g.type==="horizontal"),c=o.filter(g=>g.type==="vertical");if(d.length>0){let g=d[0].position,y=Math.abs(t.y-g);for(let p of d){let f=Math.abs(t.y-p.position);f<y&&(y=f,g=p.position);}a={...a,y:g};}else if(c.length>0){let g=c[0].position,y=Math.abs(t.x-g);for(let p of c){let f=Math.abs(t.x-p.position);f<y&&(y=f,g=p.position);}a={...a,x:g};}}let l=this.draggingTerminal==="start"?0:n.points.length-1,h=[...n.points];h[l]=a,this.context.updateShape(this.draggingArrowId,{points:h});}}else if(this.state==="brushing")this.handleBrushing(t);else {let n=this.context.getSelectedIds(),s=this.hitGenPoint(t,i,n);s?(this.hoverGenPoint=s,this.context.setGenerationPreview(this.genPreviewOf(s,this.genPreviewTarget(s,t,false)))):this.hoverGenPoint&&(this.hoverGenPoint=null,this.context.setGenerationPreview(null));}}onPointerUp(t,e){if(this.state==="dragging-terminal"&&this.draggingArrowId&&this.draggingTerminal){let i=this.context.getShapes(),n=this.findBindingNearPoint(t,i,this.draggingArrowId);n&&this.context.updateArrowBinding(this.draggingArrowId,this.draggingTerminal,n.toShapeId,n.binding);}if(this.state==="generating"&&this.generatingState){let i=this.generatingState,n=this.context.getShapes(),s=i.source,r=this.findBindingNearPoint(t,n,s.sourceShapeId);if(r)this.context.connectToExisting(this.genContext(s,t),r.toShapeId,r.binding);else if(!i.hasMoved)this.context.createGeneratedConnection(this.genContext(s,this.genPreviewTarget(s,s.point,false)),{type:this.defaultGenType(s.sourceShapeId)});else {let o=this.context.createFloatingLine(this.genContext(s,t));this.context.openGenerationMenu({context:this.genContext(s,t),existingArrowId:o,defaultShapeType:this.defaultGenType(s.sourceShapeId)});}this.generatingState=null,this.context.setGenerationPreview(null);}this.state==="brushing"&&this.context.setBrushRect(null),this.context.setConnectingTarget(null),this.hoverGenPoint=null,this.pendingHistoryCommit=false,this.state="idle",this.draggingArrowId=null,this.draggingTerminal=null,this.translatingState=null,this.resizingState=null,this.rotatingState=null,this.context.setSnapGuides([]);}onKeyDown(t){if(t.key==="Delete"||t.key==="Backspace"){let e=this.context.getSelectedIds();e.length>0&&(this.context.commitHistory(),e.forEach(i=>{this.context.deleteShape(i);}));}t.key==="Escape"&&(this.context.selectShape("",false),this.context.setSnapGuides([]),this.state="idle"),(t.key==="+"||t.key==="=")&&t.shiftKey&&(this.context.commitHistory(),this.handleRotation(15)),t.key==="-"&&t.shiftKey&&(this.context.commitHistory(),this.handleRotation(-15)),t.key==="ArrowUp"&&(t.preventDefault(),this.context.commitHistory(),this.handleNudge(0,-5)),t.key==="ArrowDown"&&(t.preventDefault(),this.context.commitHistory(),this.handleNudge(0,5)),t.key==="ArrowLeft"&&(t.preventDefault(),this.context.commitHistory(),this.handleNudge(-5,0)),t.key==="ArrowRight"&&(t.preventDefault(),this.context.commitHistory(),this.handleNudge(5,0));}onKeyUp(t){}getCursor(t){switch(this.state){case "translating":return "grabbing";case "generating":return "crosshair";case "rotating":return "grabbing";case "resizing":return this.resizingState?this.getHandleCursor(this.resizingState.handle,this.resizingState.startShape):"default";case "dragging-terminal":return "crosshair";case "brushing":return "crosshair"}let e=this.context.getShapes(),i=this.context.getSelectedIds();if(this.hitGenPoint(t,e,i))return "crosshair";if(this.hitTestArrowTerminal(t,e)&&i.includes(this.hitTestArrowTerminal(t,e).shapeId))return "move";let n=this.hitTest(t,e,i);return n.handle==="rotation"?"grab":n.handle?this.getHandleCursor(n.handle,n.shape):n.shape?"move":null}getHandleCursor(t,e){let n={e:0,se:45,s:90,sw:135,w:180,nw:225,n:270,ne:315}[t];if(n===void 0)return "grab";let s=((n+e.rotation*180/Math.PI)%360+360)%360,r=Math.round(s/45)%4;return ["ew-resize","nwse-resize","ns-resize","nesw-resize"][r]}static ALIGN_SNAP_THRESHOLD=8;handleTranslating(t,e){if(!this.translatingState)return;let i=X.subtract(t,this.translatingState.startPoint),n={...i};e.shiftKey&&(Math.abs(i.x)>Math.abs(i.y)?n.y=0:n.x=0);let s=this.context.getShapes(),r=this.context.getSelectedIds(),o=new Set(r),a=[],l=[];if(this.translatingState.startBounds.forEach(h=>{l.push({x:h.x+n.x,y:h.y+n.y,width:h.width,height:h.height});}),!e.shiftKey&&l.length>0){let h=[];for(let g of s)o.has(g.id)||g.type==="line"||g.type==="arrow"||g.type==="draw"||h.push(this.getShapeWorldBounds(g));let d=[],c=[];for(let g of l){let y=[g.y,g.y+g.height/2,g.y+g.height],p=[g.x,g.x+g.width/2,g.x+g.width];for(let f of h){let T=[f.y,f.y+f.height/2,f.y+f.height];for(let I of y)for(let b of T){let w=b-I;Math.abs(w)<=u.ALIGN_SNAP_THRESHOLD&&d.push(w);}let S=[f.x,f.x+f.width/2,f.x+f.width];for(let I of p)for(let b of S){let w=b-I;Math.abs(w)<=u.ALIGN_SNAP_THRESHOLD&&c.push(w);}}}if(d.length>0){let g=d[0];for(let y of d)Math.abs(y)<Math.abs(g)&&(g=y);n.y+=g;}if(c.length>0){let g=c[0];for(let y of c)Math.abs(y)<Math.abs(g)&&(g=y);n.x+=g;}this.translatingState.startBounds.forEach(g=>{let y={x:g.x+n.x,y:g.y+n.y,width:g.width,height:g.height};for(let p of h)a.push(...W(y,p,"horizontal",1)),a.push(...W(y,p,"vertical",1));});}this.translatingState.startPositions.forEach((h,d)=>{this.context.updateShape(d,{x:h.x+n.x,y:h.y+n.y});}),this.context.setSnapGuides(this.mergeGuides(a));}handleResizing(t){if(!this.resizingState)return;let e=this.resizingState.startShape,i=this.resizingState.handle,n=this.resizingState.startPoint;if(!i||i==="rotation")return;let r={nw:[-1,-1],n:[0,-1],ne:[1,-1],w:[-1,0],e:[1,0],sw:[-1,1],s:[0,1],se:[1,1]}[i];if(!r)return;let[o,a]=r,l=X.subtract(t,n),h=[];for(let w of this.context.getShapes())w.id!==e.id&&(w.type==="line"||w.type==="arrow"||w.type==="draw"||h.push(this.getShapeWorldBounds(w)));let d=20,c=this.getShapeWorldBounds(e),g=c.x,y=c.y,p=c.x+c.width,f=c.y+c.height;o===1?p=Math.max(g+d,p+l.x):o===-1&&(g=Math.min(p-d,g+l.x)),a===1?f=Math.max(y+d,f+l.y):a===-1&&(y=Math.min(f-d,y+l.y));let T=(w,M)=>{let C=null;for(let O of M){let U=O-w;Math.abs(U)<=u.ALIGN_SNAP_THRESHOLD&&(C===null||Math.abs(U)<Math.abs(C))&&(C=U);}return C};if(o!==0&&h.length>0){let w=[];for(let C of h)w.push(C.x,C.x+C.width/2,C.x+C.width);let M=T(o===1?p:g,w);M!==null&&(o===1?p+=M:g+=M);}if(a!==0&&h.length>0){let w=[];for(let C of h)w.push(C.y,C.y+C.height/2,C.y+C.height);let M=T(a===1?f:y,w);M!==null&&(a===1?f+=M:y+=M);}let S={x:g,y,width:p-g,height:f-y},I=[];for(let w of h)o!==0&&I.push(...W(S,w,"vertical",1)),a!==0&&I.push(...W(S,w,"horizontal",1));this.context.setSnapGuides(this.mergeGuides(I));let b={};if(e.type==="circle"){let w=Math.max(10,Math.max(o!==0?S.width/2:0,a!==0?S.height/2:0));if(b.radius=w,o!==0){let M=o===1?c.x:c.x+c.width;b.x=o===1?M+w:M-w;}if(a!==0){let M=a===1?c.y:c.y+c.height;b.y=a===1?M+w:M-w;}}else "width"in e&&o!==0&&(b.width=S.width,b.x=S.x+S.width/2),"height"in e&&a!==0&&(b.height=S.height,b.y=S.y+S.height/2);Object.keys(b).length>0&&this.context.updateShape(e.id,b);}mergeGuides(t){let e=new Map;for(let i of t){let n=`${i.type}\0${Math.round(i.position*2)/2}`,s=e.get(n);s?(s.start=Math.min(s.start,i.start),s.end=Math.max(s.end,i.end)):e.set(n,{...i});}return [...e.values()]}handleRotation(t){let e=this.context.getSelectedIds(),i=this.context.getShapes();e.forEach(n=>{let s=i.find(r=>r.id===n);s&&this.context.updateShape(n,{rotation:s.rotation+t*Math.PI/180});});}handleNudge(t,e){let i=this.context.getSelectedIds(),n=this.context.getShapes();i.forEach(s=>{let r=n.find(o=>o.id===s);r&&this.context.updateShape(s,{x:r.x+t,y:r.y+e});});}handleBrushing(t){let e=Math.min(this.brushStart.x,t.x),i=Math.min(this.brushStart.y,t.y),n=Math.abs(t.x-this.brushStart.x),s=Math.abs(t.y-this.brushStart.y);this.context.setBrushRect({x:e,y:i,width:n,height:s});let r=this.context.getShapes(),o=[];for(let a of r){let l=this.getShapeWorldBounds(a);this.rectsIntersect({x:e,y:i,width:n,height:s},l)&&o.push(a.id);}if(this.brushShiftKey){let a=this.context.getSelectedIds(),l=new Set([...a,...o]);this.context.selectShapes([...l]);}else this.context.selectShapes(o);}getShapeWorldBounds(t){switch(t.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":return {x:t.x-t.width/2,y:t.y-t.height/2,width:t.width,height:t.height};case "circle":return {x:t.x-t.radius,y:t.y-t.radius,width:t.radius*2,height:t.radius*2};case "line":case "arrow":case "draw":{if(!t.points||t.points.length===0)return {x:t.x,y:t.y,width:0,height:0};let e=1/0,i=1/0,n=-1/0,s=-1/0;return t.points.forEach(r=>{e=Math.min(e,r.x),i=Math.min(i,r.y),n=Math.max(n,r.x),s=Math.max(s,r.y);}),{x:e,y:i,width:n-e,height:s-i}}case "text":{let e=t;return {x:t.x-e.width/2,y:t.y-e.height/2,width:e.width,height:e.height}}default:{let e=t;return {x:e.x,y:e.y,width:0,height:0}}}}rectsIntersect(t,e){return t.x<e.x+e.width&&t.x+t.width>e.x&&t.y<e.y+e.height&&t.y+t.height>e.y}hitTest(t,e,i){for(let n=e.length-1;n>=0;n--){let s=e[n];if(i.includes(s.id)){let r=this.getHitHandle(t,s);if(r)return {shape:s,handle:r}}if(this.isPointInShape(t,s))return {shape:s,handle:null}}return {shape:null,handle:null}}getHitHandle(t,e){let n=this.getShapeBounds(e),s=Math.cos(-e.rotation),r=Math.sin(-e.rotation),o=t.x-e.x,a=t.y-e.y,l=o*s-a*r,h=o*r+a*s,d=[{type:"nw",x:n.x,y:n.y},{type:"ne",x:n.x+n.width,y:n.y},{type:"se",x:n.x+n.width,y:n.y+n.height},{type:"sw",x:n.x,y:n.y+n.height},{type:"rotation",x:n.x+n.width/2,y:n.y-26}];for(let c of d)if(Math.abs(l-c.x)<14&&Math.abs(h-c.y)<14)return c.type;return null}static GEN_HIT_THRESHOLD=14;static CLICK_MOVE_THRESHOLD=6;computeGenPoints(t,e){let i=[];for(let n of e){let s=t.find(r=>r.id===n);if(s){if(s.type==="line"||s.type==="arrow"||s.type==="draw"){if(s.points&&s.points.length>=2){let r=this.getShapeWorldBounds(s);i.push({point:{x:r.x+r.width/2,y:r.y+r.height/2},sourceShapeId:s.id});}}else if(s.type==="rectangle"||s.type==="rounded-rectangle"||s.type==="ellipse"||s.type==="diamond"||s.type==="triangle"||s.type==="hexagon"||s.type==="parallelogram"||s.type==="trapezoid"||s.type==="pentagon"||s.type==="octagon"||s.type==="star"||s.type==="uml-class"||s.type==="uml-interface"||s.type==="circle"){let r=this.getShapeBounds(s),o={x:s.x,y:s.y};i.push({point:{x:o.x+r.x+r.width/2,y:o.y+r.y},edge:"n",sourceShapeId:s.id}),i.push({point:{x:o.x+r.x+r.width,y:o.y+r.y+r.height/2},edge:"e",sourceShapeId:s.id}),i.push({point:{x:o.x+r.x+r.width/2,y:o.y+r.y+r.height},edge:"s",sourceShapeId:s.id}),i.push({point:{x:o.x+r.x,y:o.y+r.y+r.height/2},edge:"w",sourceShapeId:s.id});}}}return i}hitGenPoint(t,e,i){let n=u.GEN_HIT_THRESHOLD,s=null,r=n;for(let o of this.computeGenPoints(e,i)){let a=Math.hypot(o.point.x-t.x,o.point.y-t.y);a<=r&&(r=a,s=o);}return s}genPreviewTarget(t,e,i){if(i)return e;let n=96;if(t.edge){this.getShapeWorldBounds(this.context.getShapes().find(r=>r.id===t.sourceShapeId));switch(t.edge){case "n":return {x:t.point.x,y:t.point.y-n};case "s":return {x:t.point.x,y:t.point.y+n};case "e":return {x:t.point.x+n,y:t.point.y};case "w":return {x:t.point.x-n,y:t.point.y}}}return {x:t.point.x,y:t.point.y-n}}handleGenerating(t,e){if(!this.generatingState)return;let i=this.generatingState,n=i.source;Math.hypot(t.x-i.startPoint.x,t.y-i.startPoint.y)>u.CLICK_MOVE_THRESHOLD&&(i.hasMoved=true);let r=this.findBindingNearPoint(t,e,n.sourceShapeId),o=r?this.bindingPosition(r.toShapeId,r.binding,e):i.hasMoved?t:this.genPreviewTarget(n,t,false);this.context.setConnectingTarget(r?r.toShapeId:null),this.context.setGenerationPreview({from:n.point,to:o,type:r?void 0:this.defaultGenType(n.sourceShapeId)});}handleRotating(t,e){if(!this.rotatingState)return;let i=this.rotatingState,n=Math.atan2(t.y-i.center.y,t.x-i.center.x),s=i.startRotation+(n-i.startAngle);e.shiftKey&&(s=Math.round(s/(Math.PI/12))*(Math.PI/12)),this.context.updateShape(i.shapeId,{rotation:s});}edgeMidpointWorld(t,e,i){let n=t.x,s=t.y;switch(i){case "n":return {x:n+e.x+e.width/2,y:s+e.y};case "s":return {x:n+e.x+e.width/2,y:s+e.y+e.height};case "e":return {x:n+e.x+e.width,y:s+e.y+e.height/2};case "w":return {x:n+e.x,y:s+e.y+e.height/2}}}bindingPosition(t,e,i){let n=i.find(r=>r.id===t);if(!n)return {x:0,y:0};let s=this.getShapeWorldBounds(n);if(e.handle)switch(e.handle){case "top":return {x:n.x,y:s.y};case "bottom":return {x:n.x,y:s.y+s.height};case "left":return {x:s.x,y:n.y};case "right":return {x:s.x+s.width,y:n.y}}return e.normalizedAnchor?{x:s.x+s.width*e.normalizedAnchor.x,y:s.y+s.height*e.normalizedAnchor.y}:{x:n.x,y:n.y}}isPointInShape(t,e){let i=t.x-e.x,n=t.y-e.y;switch(e.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":return Math.abs(i)<=e.width/2&&Math.abs(n)<=e.height/2;case "circle":return i*i+n*n<=e.radius*e.radius;case "hexagon":return this.isPointInHexagon(i,n,e.width,e.height);case "line":case "arrow":case "draw":for(let s=0;s<e.points.length-1;s++){let r=e.points[s],o=e.points[s+1];if(this.pointToLineDistance(t,r,o)<10)return true}return false;case "text":return Math.abs(i)<=50&&Math.abs(n)<=e.fontSize/2;default:return false}}isPointInHexagon(t,e,i,n){let s=Math.abs(t),r=Math.abs(e),o=i/2,a=n/2;return s<=o&&r<=a&&s/o+r/a<=1.5}pointToLineDistance(t,e,i){let n=t.x-e.x,s=t.y-e.y,r=i.x-e.x,o=i.y-e.y,a=n*r+s*o,l=r*r+o*o,h=-1;l!==0&&(h=a/l);let d,c;h<0?(d=e.x,c=e.y):h>1?(d=i.x,c=i.y):(d=e.x+h*r,c=e.y+h*o);let g=t.x-d,y=t.y-c;return Math.sqrt(g*g+y*y)}getShapeBounds(t){switch(t.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":return {x:-t.width/2,y:-t.height/2,width:t.width,height:t.height};case "circle":return {x:-t.radius,y:-t.radius,width:t.radius*2,height:t.radius*2};case "hexagon":return {x:-t.width/2,y:-t.height/2,width:t.width,height:t.height};case "line":case "arrow":case "draw":if(t.points.length===0)return {x:0,y:0,width:0,height:0};let e=1/0,i=1/0,n=-1/0,s=-1/0;return t.points.forEach(r=>{e=Math.min(e,r.x-t.x),i=Math.min(i,r.y-t.y),n=Math.max(n,r.x-t.x),s=Math.max(s,r.y-t.y);}),{x:e,y:i,width:n-e,height:s-i};case "text":return {x:-50,y:-t.fontSize/2,width:100,height:t.fontSize};default:return {x:0,y:0,width:0,height:0}}}hitTestArrowTerminal(t,e){for(let n of e){if(n.type!=="arrow")continue;let s=n;if(s.points.length<2)continue;let r=s.points[0],o=s.points[s.points.length-1],a=Math.sqrt(Math.pow(t.x-r.x,2)+Math.pow(t.y-r.y,2)),l=Math.sqrt(Math.pow(t.x-o.x,2)+Math.pow(t.y-o.y,2));if(a<20)return {shapeId:s.id,terminal:"start"};if(l<20)return {shapeId:s.id,terminal:"end"}}return null}findShapeNearPoint(t,e,i){for(let s=e.length-1;s>=0;s--){let r=e[s];if(i&&r.id===i||r.type==="arrow"||r.type==="line"||r.type==="draw")continue;let o;switch(r.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":o=this.pointToRectDistance(t,{x:r.x-r.width/2,y:r.y-r.height/2,width:r.width,height:r.height});break;case "circle":o=Math.sqrt(Math.pow(t.x-r.x,2)+Math.pow(t.y-r.y,2))-r.radius;break;case "hexagon":{let a=r.width/2,l=r.height/2,h=Math.abs(t.x-r.x),d=Math.abs(t.y-r.y);o=h/a+d/l-1;break}default:continue}if(o<=30)return r}return null}pointToRectDistance(t,e){let i=Math.max(e.x,Math.min(t.x,e.x+e.width)),n=Math.max(e.y,Math.min(t.y,e.y+e.height));return Math.sqrt(Math.pow(t.x-i,2)+Math.pow(t.y-n,2))}static SNAP_THRESHOLD=32;static HANDLE_SNAP_DISTANCE=18;static ANCHOR_EPS=.001;computeSnapGuidesForArrow(t,e,i,n,s){let r=this.draggingTerminal==="start"?n.endBinding:n.startBinding,o=r?s.find(y=>y.id===r.toShapeId):null;if(!o)return [];let a=this.findShapeNearPoint(i,s,n.id);if(!a)return [];let l=this.getShapeWorldBounds(o),h=this.getShapeWorldBounds(a),d=e.x-t.x,c=e.y-t.y,g=Math.abs(d)>=Math.abs(c)?"horizontal":"vertical";return W(l,h,g)}findBindingNearPoint(t,e,i){let n;for(let s=e.length-1;s>=0;s--){let r=e[s];if(i&&r.id===i||r.type==="arrow"||r.type==="line"||r.type==="draw")continue;let o=this.getPageBounds(r),a=u.SNAP_THRESHOLD;if(t.x<o.x-a||t.x>o.x+o.width+a||t.y<o.y-a||t.y>o.y+o.height+a)continue;let l={x:r.x,y:r.y},h=[{handle:"top",pos:{x:l.x,y:o.y}},{handle:"bottom",pos:{x:l.x,y:o.y+o.height}},{handle:"left",pos:{x:o.x,y:l.y}},{handle:"right",pos:{x:o.x+o.width,y:l.y}}];for(let c of h){let g=Math.hypot(c.pos.x-t.x,c.pos.y-t.y);g<=u.HANDLE_SNAP_DISTANCE&&(!n||g<n.distance)&&(n={toShapeId:r.id,binding:{toShapeId:r.id,handle:c.handle,isPrecise:false},distance:g});}let d=this.nearestPointOnShapeOutline(r,t);if(d&&d.distance<=u.SNAP_THRESHOLD&&(!n||d.distance<n.distance)){let c=this.computeNormalizedAnchor(o,d.point);n={toShapeId:r.id,binding:{toShapeId:r.id,isPrecise:true,normalizedAnchor:c},distance:d.distance};}}if(n)return {toShapeId:n.toShapeId,binding:n.binding}}getPageBounds(t){switch(t.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":return {x:t.x-t.width/2,y:t.y-t.height/2,width:t.width,height:t.height};case "circle":return {x:t.x-t.radius,y:t.y-t.radius,width:t.radius*2,height:t.radius*2};default:return {x:t.x-50,y:t.y-50,width:100,height:100}}}computeNormalizedAnchor(t,e){let i=u.ANCHOR_EPS,n=t.width>0?(e.x-t.x)/t.width:.5,s=t.height>0?(e.y-t.y)/t.height:.5;return n=Math.max(i,Math.min(1-i,n)),s=Math.max(i,Math.min(1-i,s)),{x:n,y:s}}nearestPointOnShapeOutline(t,e){let i={x:e.x-t.x,y:e.y-t.y},n=this.nearestLocalPointOnShapeOutline(t,i);if(!n)return null;let s={x:n.point.x+t.x,y:n.point.y+t.y};return {point:s,distance:Math.hypot(s.x-e.x,s.y-e.y)}}nearestLocalPointOnShapeOutline(t,e){switch(t.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":{let i=t.width,n=t.height;return this.nearestPointOnRectOutlineLocal(e,{x:-i/2,y:-n/2,width:i,height:n})}case "circle":{let i=t.radius;return this.nearestPointOnCircleOutlineLocal(e,{x:0,y:0},i)}default:return null}}nearestPointOnRectOutlineLocal(t,e){let i=[[{x:e.x,y:e.y},{x:e.x+e.width,y:e.y}],[{x:e.x+e.width,y:e.y},{x:e.x+e.width,y:e.y+e.height}],[{x:e.x+e.width,y:e.y+e.height},{x:e.x,y:e.y+e.height}],[{x:e.x,y:e.y+e.height},{x:e.x,y:e.y}]],n=null;for(let[s,r]of i){let o=this.nearestPointOnSegment(t,s,r);(!n||o.distance<n.distance)&&(n=o);}return n}nearestPointOnCircleOutlineLocal(t,e,i){let n=t.x-e.x,s=t.y-e.y,r=Math.hypot(n,s);if(r<1e-9)return {point:{x:e.x+i,y:e.y},distance:i};let o=e.x+n/r*i,a=e.y+s/r*i,l={x:o,y:a};return {point:l,distance:Math.hypot(l.x-t.x,l.y-t.y)}}nearestPointOnSegment(t,e,i){let n=i.x-e.x,s=i.y-e.y,r=n*n+s*s,o=r>0?((t.x-e.x)*n+(t.y-e.y)*s)/r:0;o=Math.max(0,Math.min(1,o));let a=e.x+o*n,l=e.y+o*s,h={x:a,y:l};return {point:h,distance:Math.hypot(h.x-t.x,h.y-t.y)}}};var tt=class u extends H{type="hand";state="idle";startScreenPoint={x:0,y:0};initialCameraPos={x:0,y:0};static DRAG_THRESHOLD=4;onPointerDown(t,e){this.startScreenPoint={x:e.clientX,y:e.clientY};let i=this.context.getCamera();this.initialCameraPos={x:i.x,y:i.y},this.state="pointing";}onPointerMove(t,e){if(this.state!=="idle"){if(this.state==="pointing"){let i=e.clientX-this.startScreenPoint.x,n=e.clientY-this.startScreenPoint.y;if(Math.hypot(i,n)<u.DRAG_THRESHOLD)return;this.state="dragging",this.applyCameraDelta(i,n);return}if(this.state==="dragging"){let i=e.clientX-this.startScreenPoint.x,n=e.clientY-this.startScreenPoint.y;this.applyCameraDelta(i,n);}}}onPointerUp(t,e){if(this.state!=="idle"){if(this.state==="dragging"){let i=this.context.getCamera();this.initialCameraPos={x:i.x,y:i.y},this.startScreenPoint={x:e.clientX,y:e.clientY};}this.state="idle";}}onKeyDown(t){t.key==="Escape"&&this.state!=="idle"&&(this.context.setCameraPosition(this.initialCameraPos.x,this.initialCameraPos.y),this.state="idle");}onKeyUp(t){}getCursor(t){return this.state==="dragging"||this.state==="pointing"?"grabbing":"grab"}applyCameraDelta(t,e){this.context.setCameraPosition(this.initialCameraPos.x+t,this.initialCameraPos.y+e);}};var mt={strokeColor:"#1f2937",fillColor:"transparent",strokeWidth:2,strokeDash:null},et=class extends H{type="line";isDrawing=false;startPoint={x:0,y:0};currentShape=null;onPointerDown(t,e){this.isDrawing=true,this.startPoint=t,this.currentShape={id:`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,type:"line",x:t.x,y:t.y,points:[t],rotation:0,style:{...mt}},this.context.commitHistory(),this.context.addShape(this.currentShape);}onPointerMove(t,e){!this.isDrawing||!this.currentShape||this.context.updateShape(this.currentShape.id,{points:[this.startPoint,t]});}onPointerUp(t,e){this.isDrawing=false,this.currentShape=null,this.context.setActiveTool("select");}onKeyDown(t){}onKeyUp(t){}getCursor(){return "crosshair"}};var xt={strokeColor:"#1f2937",fillColor:"transparent",strokeWidth:4,strokeDash:null},St={strokeColor:"rgba(255, 235, 59, 0.5)",fillColor:"transparent",strokeWidth:16,strokeDash:null},wt=4e3,Z=class extends H{type;mode;isDrawing=false;points=[];currentShapeId=null;committed=false;fadeTimer=null;constructor(t,e){super(t),this.mode=e,this.type=e==="pen"?"pen":"highlighter";}onPointerDown(t,e){this.isDrawing=true,this.committed=false,this.currentShapeId=null,this.points=[{...t}];}onPointerMove(t,e){if(this.isDrawing)if(this.points.push({...t}),!this.committed&&this.points.length>=2){this.context.commitHistory();let i=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`;this.currentShapeId=i;let n=this.points[0],s=this.mode==="pen"?{...xt}:{...St},r={id:i,type:"draw",x:n.x,y:n.y,points:this.points.map(o=>({...o})),rotation:0,style:s};this.context.addShape(r),this.committed=true;}else this.committed&&this.currentShapeId&&this.context.updateShape(this.currentShapeId,{points:this.points.map(i=>({...i}))});}onPointerUp(t,e){if(!this.isDrawing||(this.isDrawing=false,!this.committed||!this.currentShapeId))return;let i=this.currentShapeId;this.currentShapeId=null,this.mode==="highlighter"&&(this.fadeTimer=setTimeout(()=>{this.context.deleteShape(i);},wt));}onKeyDown(t){}onKeyUp(t){}getCursor(){return "crosshair"}dispose(){this.fadeTimer&&(clearTimeout(this.fadeTimer),this.fadeTimer=null);}};var bt={strokeColor:"#1f2937",fillColor:"transparent",strokeWidth:2,strokeDash:null},nt=class extends H{type="arrow";isDrawing=false;startPoint={x:0,y:0};currentShapeId=null;startBindingInfo=null;onPointerDown(t,e){this.isDrawing=true,this.startPoint=t,this.startBindingInfo=null;let i=this.context.getShapes(),n=this.findShapeBinding(t,i),s=t;n&&(s=this.getBindingPosition(n.toShapeId,n.handle,i),this.startBindingInfo={...n,position:s});let r=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`;this.currentShapeId=r;let o={id:r,type:"arrow",x:s.x,y:s.y,points:[s],rotation:0,style:{...bt},startBinding:n?{toShapeId:n.toShapeId,handle:n.handle}:void 0,connectionType:"straight",arrowHead:"end",dashed:false};this.context.commitHistory(),this.context.addShape(o);}onPointerMove(t,e){if(!this.isDrawing||!this.currentShapeId)return;let i=this.context.getShapes(),n=this.findShapeBinding(t,i),s=t;n&&(s=this.getBindingPosition(n.toShapeId,n.handle,i));let r=this.startBindingInfo?.position||this.startPoint,o=this.computeSnapGuides(r,s,n,i);this.context.setSnapGuides(o),this.context.updateShape(this.currentShapeId,{points:[r,s],endBinding:n?{toShapeId:n.toShapeId,handle:n.handle}:void 0});}onPointerUp(t,e){this.isDrawing=false,this.currentShapeId=null,this.startBindingInfo=null,this.context.setSnapGuides([]),this.context.setActiveTool("select");}onKeyDown(t){}onKeyUp(t){}getCursor(){return "crosshair"}computeSnapGuides(t,e,i,n){let s=this.startBindingInfo?n.find(c=>c.id===this.startBindingInfo.toShapeId):null,r=i?n.find(c=>c.id===i.toShapeId):null;if(!s||!r)return [];let o=this.getShapeBounds(s),a=this.getShapeBounds(r),l=e.x-t.x,h=e.y-t.y,d=Math.abs(l)>=Math.abs(h)?"horizontal":"vertical";return W(o,a,d)}getShapeBounds(t){switch(t.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":return {x:t.x-t.width/2,y:t.y-t.height/2,width:t.width,height:t.height};case "circle":return {x:t.x-t.radius,y:t.y-t.radius,width:t.radius*2,height:t.radius*2};case "text":return {x:t.x-t.width/2,y:t.y-t.height/2,width:t.width,height:t.height};default:return {x:t.x-50,y:t.y-20,width:100,height:40}}}findShapeBinding(t,e){for(let n=e.length-1;n>=0;n--){let s=e[n];if(s.type==="arrow"||s.type==="line"||s.type==="draw")continue;let r;switch(s.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "uml-class":case "uml-interface":r=this.pointToRectDistance(t,{x:s.x-s.width/2,y:s.y-s.height/2,width:s.width,height:s.height});break;case "circle":{let o=Math.sqrt(Math.pow(t.x-s.x,2)+Math.pow(t.y-s.y,2));r=Math.abs(o-s.radius);break}case "hexagon":{let o=s.width/2,a=s.height/2,l=Math.abs(t.x-s.x),h=Math.abs(t.y-s.y);r=l/o+h/a-1;break}default:continue}if(r<=40){let o=this.getClosestHandle(t,s);return {toShapeId:s.id,handle:o}}}}pointToRectDistance(t,e){let i=Math.max(e.x,Math.min(t.x,e.x+e.width)),n=Math.max(e.y,Math.min(t.y,e.y+e.height));return Math.sqrt(Math.pow(t.x-i,2)+Math.pow(t.y-n,2))}getClosestHandle(t,e){let i=t.x-e.x,n=t.y-e.y;if(e.type==="circle"||e.type==="hexagon"){let l=Math.atan2(n,i);return l>=-Math.PI/4&&l<Math.PI/4?"right":l>=Math.PI/4&&l<3*Math.PI/4?"bottom":l>=3*Math.PI/4||l<-(3*Math.PI)/4?"left":"top"}let s="width"in e?e.width:100,r="height"in e?e.height:100,o=Math.abs(i)/(s/2),a=Math.abs(n)/(r/2);return o>a?i>0?"right":"left":n>0?"bottom":"top"}getBindingPosition(t,e,i){let n=i.find(s=>s.id===t);if(!n)return {x:0,y:0};switch(n.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":return this.getRectBindingPosition(n,e);case "circle":return this.getCircleBindingPosition(n,e);case "hexagon":return this.getRectBindingPosition(n,e);default:return {x:n.x,y:n.y}}}getRectBindingPosition(t,e){switch(e){case "top":return {x:t.x,y:t.y-t.height/2};case "bottom":return {x:t.x,y:t.y+t.height/2};case "left":return {x:t.x-t.width/2,y:t.y};case "right":return {x:t.x+t.width/2,y:t.y}}}getCircleBindingPosition(t,e){switch(e){case "top":return {x:t.x,y:t.y-t.radius};case "bottom":return {x:t.x,y:t.y+t.radius};case "left":return {x:t.x-t.radius,y:t.y};case "right":return {x:t.x+t.radius,y:t.y}}}};var vt={strokeColor:"transparent",fillColor:"transparent",strokeWidth:0,strokeDash:null},at=class extends H{type="text";onPointerDown(t,e){let i=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,n={id:i,type:"text",x:t.x,y:t.y,rotation:0,style:{...vt},text:"",fontSize:16,textColor:"#1f2937",width:200,height:24};this.context.commitHistory(),this.context.addShape(n),this.context.enterEditing(i);}onPointerMove(t,e){}onPointerUp(t,e){}onKeyDown(t){}onKeyUp(t){}getCursor(){return "text"}};var dt="drawui-canvas-data",Tt=50,ct=class{canvas;renderer;camera;tools=new Map;activeTool="select";shapes=[];selectedIds=[];listeners=new Set;notificationListeners=new Set;uiListeners=new Set;isPanning=false;panStart={x:0,y:0};dragStartPositions=new Map;lastClickTime=0;lastClickShapeId=null;editingShapeId=null;textInput=null;textOverlay=null;isNewTextShape=false;originalTextValue="";undoStack=[];redoStack=[];isUndoing=false;brushRect=null;snapGuides=[];connectingTargetId=null;genPreview=null;pendingGen=null;renderScheduled=false;pointerIsDown=false;notifyScheduled=false;constructor(t){this.canvas=t;let e=t.getBoundingClientRect();this.renderer=new J(t),this.renderer.resize(e.width,e.height),this.camera=new q;let i={addShape:n=>this.addShape(n),updateShape:(n,s)=>this.updateShape(n,s),deleteShape:n=>this.deleteShape(n),selectShape:(n,s)=>this.selectShape(n,s),selectShapes:n=>this.selectShapes(n),getShapes:()=>[...this.shapes],getSelectedIds:()=>[...this.selectedIds],setActiveTool:n=>this.setActiveTool(n),screenToPage:n=>this.screenToPage(n),getCamera:()=>this.camera,panBy:(n,s)=>this.panBy(n,s),setCameraPosition:(n,s)=>this.setCameraPosition(n,s),getShapeAtPoint:(n,s)=>this.getShapeAtPoint(n,s),updateArrowBinding:(n,s,r,o)=>this.updateArrowBinding(n,s,r,o),enterEditing:n=>this.enterEditing(n),exitEditing:()=>this.exitEditing(),commitHistory:()=>this.commitHistory(),setBrushRect:n=>this.setBrushRect(n),setSnapGuides:n=>this.setSnapGuides(n),setConnectingTarget:n=>this.setConnectingTarget(n),setGenerationPreview:n=>this.setGenerationPreview(n),openGenerationMenu:n=>this.openGenerationMenu(n),createGeneratedConnection:(n,s)=>this.createGeneratedConnection(n,s),createFloatingLine:n=>this.createFloatingLine(n),connectToExisting:(n,s,r)=>this.connectToExisting(n,s,r),updateSelectedShapesStyle:n=>this.updateSelectedShapesStyle(n),updateSelectedShapesText:n=>this.updateSelectedShapesText(n),updateConnectionType:n=>this.updateConnectionType(n)};this.tools.set("select",new Q(i)),this.tools.set("hand",new tt(i)),this.tools.set("rectangle",new R(i,"rectangle")),this.tools.set("rounded-rectangle",new R(i,"rounded-rectangle")),this.tools.set("circle",new R(i,"circle")),this.tools.set("ellipse",new R(i,"ellipse")),this.tools.set("diamond",new R(i,"diamond")),this.tools.set("triangle",new R(i,"triangle")),this.tools.set("hexagon",new R(i,"hexagon")),this.tools.set("parallelogram",new R(i,"parallelogram")),this.tools.set("trapezoid",new R(i,"trapezoid")),this.tools.set("pentagon",new R(i,"pentagon")),this.tools.set("octagon",new R(i,"octagon")),this.tools.set("star",new R(i,"star")),this.tools.set("uml-class",new R(i,"uml-class")),this.tools.set("uml-interface",new R(i,"uml-interface")),this.tools.set("line",new et(i)),this.tools.set("arrow",new nt(i)),this.tools.set("text",new at(i)),this.tools.set("pen",new Z(i,"pen")),this.tools.set("highlighter",new Z(i,"highlighter")),this.setupEventListeners(),this.loadFromStorage(),this.render();}setupEventListeners(){this.canvas.addEventListener("pointerdown",this.handlePointerDown),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerup",this.handlePointerUp),this.canvas.addEventListener("pointerleave",this.handlePointerUp),this.canvas.addEventListener("wheel",this.handleWheel,{passive:false}),window.addEventListener("keydown",this.handleKeyDown),window.addEventListener("keyup",this.handleKeyUp),window.addEventListener("resize",this.handleResize);}handlePointerDown=t=>{if(this.editingShapeId)return this.textInput&&t.target===this.textInput,void 0;if(this.pointerIsDown=true,t.button===1||t.button===0&&t.altKey){this.isPanning=true,this.panStart={x:t.clientX,y:t.clientY},this.canvas.setPointerCapture(t.pointerId),this.canvas.style.cursor="grabbing";return}let e=this.screenToPage({x:t.clientX,y:t.clientY});if(this.activeTool==="select"){let n=Date.now(),s=this.getShapeAtPoint(e);if(n-this.lastClickTime<400&&this.lastClickShapeId&&s&&s.id===this.lastClickShapeId&&this.canEditShape(s)){this.enterEditing(s.id),this.lastClickTime=0,this.lastClickShapeId=null;return}this.lastClickTime=n,this.lastClickShapeId=s?.id||null,s&&(this.dragStartPositions.clear(),this.selectedIds.forEach(r=>{let o=this.shapes.find(a=>a.id===r);o&&this.dragStartPositions.set(r,{x:o.x,y:o.y});}));}this.tools.get(this.activeTool)?.onPointerDown(e,t),this.updateCursor(e),this.render();};handlePointerMove=t=>{if(this.editingShapeId)return;if(this.isPanning){let n=t.clientX-this.panStart.x,s=t.clientY-this.panStart.y;this.camera.translate(n,s),this.panStart={x:t.clientX,y:t.clientY},this.scheduleRender(),this.notifyListeners();return}let e=this.screenToPage({x:t.clientX,y:t.clientY});this.tools.get(this.activeTool)?.onPointerMove(e,t),this.updateCursor(e),this.scheduleRender();};handlePointerUp=t=>{if(this.pointerIsDown=false,this.editingShapeId)return;if(this.isPanning){this.isPanning=false,this.updateCursor(this.screenToPage({x:t.clientX,y:t.clientY}));return}let e=this.screenToPage({x:t.clientX,y:t.clientY});this.tools.get(this.activeTool)?.onPointerUp(e,t),this.updateCursor(e),this.scheduleRender();};updateCursor(t){let i=this.tools.get(this.activeTool)?.getCursor(t)??"default";this.canvas.style.cursor!==i&&(this.canvas.style.cursor=i);}handleWheel=t=>{t.preventDefault();let e=t.deltaY>0?.9:1.1;this.camera.zoomAt({x:t.clientX,y:t.clientY},e),this.scheduleRender(),this.notifyListeners();};handleKeyDown=t=>{if(this.editingShapeId)return;if((t.ctrlKey||t.metaKey)&&t.key.toLowerCase()==="z"){t.preventDefault(),t.shiftKey?this.redo():this.undo();return}if((t.ctrlKey||t.metaKey)&&t.key.toLowerCase()==="y"){t.preventDefault(),this.redo();return}if((t.ctrlKey||t.metaKey)&&t.key.toLowerCase()==="s"){t.preventDefault(),this.saveToStorage();return}if(!t.ctrlKey&&!t.metaKey&&!t.altKey){if(t.key==="v"||t.key==="V"){this.setActiveTool("select"),t.preventDefault();return}if(t.key==="h"||t.key==="H"){this.setActiveTool("hand"),t.preventDefault();return}}this.tools.get(this.activeTool)?.onKeyDown(t),this.scheduleRender();};handleKeyUp=t=>{if(this.editingShapeId)return;this.tools.get(this.activeTool)?.onKeyUp(t),this.scheduleRender();};handleResize=()=>{this.renderer.resize(window.innerWidth,window.innerHeight),this.scheduleRender();};screenToPage(t){let e=this.canvas.getBoundingClientRect();return this.camera.screenToPage({x:t.x-e.left,y:t.y-e.top})}addShape(t){this.shapes.push(t),this.notifyListeners();}updateShape(t,e){let i=this.shapes.findIndex(n=>n.id===t);i!==-1&&(this.shapes[i]={...this.shapes[i],...e},(e.x!==void 0||e.y!==void 0)&&this.updateBoundArrows(t),this.notifyListeners());}updateBoundArrows(t){let e=this.shapes.find(i=>i.id===t);e&&this.shapes.forEach(i=>{if(i.type==="arrow"){let n=i,s={};if(n.startBinding?.toShapeId===t){let r=this.getBindingPosition(e,n.startBinding.handle||"top");s.points=n.points.map((o,a)=>a===0?r:o);}if(n.endBinding?.toShapeId===t){let r=this.getBindingPosition(e,n.endBinding.handle||"top"),o=s.points||[...n.points];s.points=o.map((a,l)=>l===o.length-1?r:a);}s.points&&(this.shapes[this.shapes.indexOf(i)]={...n,...s});}});}getBindingPosition(t,e){switch(t.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":switch(e){case "top":return {x:t.x,y:t.y-t.height/2};case "bottom":return {x:t.x,y:t.y+t.height/2};case "left":return {x:t.x-t.width/2,y:t.y};case "right":return {x:t.x+t.width/2,y:t.y}}case "circle":switch(e){case "top":return {x:t.x,y:t.y-t.radius};case "bottom":return {x:t.x,y:t.y+t.radius};case "left":return {x:t.x-t.radius,y:t.y};case "right":return {x:t.x+t.radius,y:t.y}}case "hexagon":switch(e){case "top":return {x:t.x,y:t.y-t.height/2};case "bottom":return {x:t.x,y:t.y+t.height/2};case "left":return {x:t.x-t.width/2,y:t.y};case "right":return {x:t.x+t.width/2,y:t.y}}default:return {x:t.x,y:t.y}}}deleteShape(t){this.shapes=this.shapes.filter(e=>e.id!==t),this.selectedIds=this.selectedIds.filter(e=>e!==t),this.shapes=this.shapes.map(e=>{if(e.type==="arrow"){let i=e;if(i.startBinding?.toShapeId===t)return {...i,startBinding:void 0};if(i.endBinding?.toShapeId===t)return {...i,endBinding:void 0}}return e}),this.notifyListeners(),this.scheduleRender();}selectShape(t,e){if(!t)this.selectedIds=[];else if(e){let i=this.selectedIds.indexOf(t);i===-1?this.selectedIds.push(t):this.selectedIds.splice(i,1);}else this.selectedIds=[t];this.notifyListeners(),this.scheduleRender();}selectShapes(t){this.selectedIds=[...t],this.notifyListeners(),this.scheduleRender();}setBrushRect(t){this.brushRect=t,this.scheduleRender();}setSnapGuides(t){this.snapGuides=t;}setConnectingTarget(t){this.connectingTargetId!==t&&(this.connectingTargetId=t,this.scheduleRender());}setGenerationPreview(t){this.genPreview?.from.x===t?.from.x&&this.genPreview?.from.y===t?.from.y&&this.genPreview?.to.x===t?.to.x&&this.genPreview?.to.y===t?.to.y&&this.genPreview?.type===t?.type||(this.genPreview=t,this.scheduleRender());}openGenerationMenu(t){this.pendingGen={...t.context,existingArrowId:t.existingArrowId};let e=this.camera.getZoom(),i=(t.context.to.x+this.camera.x)*e,n=(t.context.to.y+this.camera.y)*e;this.emitUi({kind:"shapeTypeMenu",screenX:i,screenY:n,context:t.context,existingArrowId:t.existingArrowId,defaultShapeType:t.defaultShapeType});}lineStyle(){return {strokeColor:"#1f2937",fillColor:"transparent",strokeWidth:2,strokeDash:null}}computeSourceBinding(t){if(!t.sourceShapeId||!t.edge)return;let e=this.shapes.find(n=>n.id===t.sourceShapeId);if(!e)return;let i={n:"top",e:"right",s:"bottom",w:"left"};return {toShapeId:e.id,handle:i[t.edge]}}connectHandle(t,e){let i=e.x-t.x,n=e.y-t.y;return Math.abs(i)>=Math.abs(n)?i>=0?"left":"right":n>=0?"top":"bottom"}createFloatingLine(t){this.commitHistory();let e=t.from,i=t.to,n=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,s={id:n,type:"arrow",x:e.x,y:e.y,points:[{x:e.x,y:e.y},{x:i.x,y:i.y}],rotation:0,style:this.lineStyle(),startBinding:this.computeSourceBinding(t),connectionType:"polyline",arrowHead:"end",dashed:false};return this.addShape(s),this.selectedIds=[n],this.pendingGen={...t,existingArrowId:n},this.notifyListeners(),this.render(),n}createGeneratedConnection(t,e){this.commitHistory();let i=e.type,n;if(t.sourceShapeId){let a=this.shapes.find(l=>l.id===t.sourceShapeId);a&&rt(a.type)&&(n={...a.style});}let s=lt(i,t.to,n);this.addShape(s);let r=t.from,o={toShapeId:s.id,handle:this.connectHandle(r,t.to)};if(e.existingArrowId)this.updateArrowBinding(e.existingArrowId,"end",s.id,{toShapeId:s.id,handle:this.connectHandle(r,t.to)});else {let l={id:`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,type:"arrow",x:r.x,y:r.y,points:[{x:r.x,y:r.y},{x:t.to.x,y:t.to.y}],rotation:0,style:this.lineStyle(),startBinding:this.computeSourceBinding(t),endBinding:o,connectionType:"polyline",arrowHead:"end",dashed:false};this.addShape(l);}this.selectedIds=[s.id],this.pendingGen=null,this.notifyListeners(),this.render();}connectToExisting(t,e,i){this.commitHistory();let n=this.shapes.find(h=>h.id===e);if(!n)return;let s=t.from,r=i?.handle??this.connectHandle(s,{x:n.x,y:n.y}),o=this.getBindingPosition(n,r),a=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,l={id:a,type:"arrow",x:s.x,y:s.y,points:[{x:s.x,y:s.y},{x:o.x,y:o.y}],rotation:0,style:this.lineStyle(),startBinding:this.computeSourceBinding(t),endBinding:{toShapeId:e,handle:r},connectionType:"polyline",arrowHead:"end",dashed:false};this.addShape(l),this.selectedIds=[a],this.pendingGen=null,this.notifyListeners(),this.render();}subscribeUi(t){return this.uiListeners.add(t),()=>this.uiListeners.delete(t)}emitUi(t){this.uiListeners.forEach(e=>e(t));}updateSelectedShapesStyle(t){this.selectedIds.length!==0&&(this.commitHistory(),this.selectedIds.forEach(e=>{let i=this.shapes.findIndex(n=>n.id===e);i!==-1&&(this.shapes[i]={...this.shapes[i],style:{...this.shapes[i].style,...t}});}),this.notifyListeners(),this.render());}updateSelectedShapesText(t){this.selectedIds.length!==0&&(this.commitHistory(),this.selectedIds.forEach(e=>{let i=this.shapes.findIndex(n=>n.id===e);i!==-1&&(this.shapes[i]={...this.shapes[i],...t});}),this.notifyListeners(),this.render());}updateConnectionType(t){this.selectedIds.length!==0&&(this.commitHistory(),this.selectedIds.forEach(e=>{let i=this.shapes.findIndex(n=>n.id===e);if(i!==-1){let n=this.shapes[i];(n.type==="line"||n.type==="arrow")&&(this.shapes[i]={...n,connectionType:t});}}),this.notifyListeners(),this.render());}updateArrowHeadType(t){this.selectedIds.length!==0&&(this.commitHistory(),this.selectedIds.forEach(e=>{let i=this.shapes.findIndex(n=>n.id===e);if(i!==-1){let n=this.shapes[i];n.type==="arrow"&&(this.shapes[i]={...n,arrowHead:t});}}),this.notifyListeners(),this.render());}updateArrowDashed(t){this.selectedIds.length!==0&&(this.commitHistory(),this.selectedIds.forEach(e=>{let i=this.shapes.findIndex(n=>n.id===e);if(i!==-1){let n=this.shapes[i];n.type==="arrow"&&(this.shapes[i]={...n,dashed:t});}}),this.notifyListeners(),this.render());}updateUmlClass(t,e){let i=this.shapes.findIndex(h=>h.id===t);if(i===-1)return;let n=this.shapes[i];if(n.type!=="uml-class")return;this.commitHistory();let s=e.className??n.className,r=e.attributes??n.attributes,o=e.methods??n.methods,{width:a,height:l}=ot(s,r,o);this.shapes[i]={...n,className:s,attributes:r,methods:o,width:a,height:l},this.notifyListeners(),this.render();}updateUmlInterface(t,e){let i=this.shapes.findIndex(y=>y.id===t);if(i===-1)return;let n=this.shapes[i];if(n.type!=="uml-interface")return;this.commitHistory();let s=n,r=e.className??s.className,o=e.methods??s.methods,a=$*.6,l=o.map(y=>`${y.visibility} ${y.name}(${y.params}): ${y.returnType}`),h=Math.max(r.length,...l.map(y=>y.length),0),d=Math.max(j,h*a+N*2),c=o.length>0?o.length*L+D*2:D*2,g=Y+c;this.shapes[i]={...n,className:r,methods:o,width:d,height:g},this.notifyListeners(),this.render();}getSelectedUml(){if(this.selectedIds.length!==1)return null;let t=this.shapes.find(e=>e.id===this.selectedIds[0]);return t&&(t.type==="uml-class"||t.type==="uml-interface")?t:null}getUmlById(t){let e=this.shapes.find(i=>i.id===t);return e&&(e.type==="uml-class"||e.type==="uml-interface")?e:null}addUmlAttribute(t){let e=this.shapes.find(n=>n.id===t);if(!e||e.type!=="uml-class")return;let i={id:`attr_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,visibility:"+",name:"newField",type:"string"};this.updateUmlClass(t,{attributes:[...e.attributes,i]});}addUmlMethod(t){let e=this.getUmlById(t);if(!e)return;let i={id:`meth_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,visibility:"+",name:"newMethod",params:"",returnType:"void"};e.type==="uml-class"?this.updateUmlClass(t,{methods:[...e.methods,i]}):this.updateUmlInterface(t,{methods:[...e.methods,i]});}removeUmlAttribute(t,e){let i=this.shapes.find(n=>n.id===t);!i||i.type!=="uml-class"||this.updateUmlClass(t,{attributes:i.attributes.filter(n=>n.id!==e)});}removeUmlMethod(t,e){let i=this.getUmlById(t);if(!i)return;let n=i.methods.filter(s=>s.id!==e);i.type==="uml-class"?this.updateUmlClass(t,{methods:n}):this.updateUmlInterface(t,{methods:n});}reorderUmlAttribute(t,e,i){let n=this.shapes.find(o=>o.id===t);if(!n||n.type!=="uml-class"||e===i)return;let s=[...n.attributes];if(e<0||e>=s.length||i<0||i>=s.length)return;let[r]=s.splice(e,1);s.splice(i,0,r),this.updateUmlClass(t,{attributes:s});}reorderUmlMethod(t,e,i){let n=this.getUmlById(t);if(!n||e===i)return;let s=[...n.methods];if(e<0||e>=s.length||i<0||i>=s.length)return;let[r]=s.splice(e,1);s.splice(i,0,r),n.type==="uml-class"?this.updateUmlClass(t,{methods:s}):this.updateUmlInterface(t,{methods:s});}updateUmlRowStyle(t,e,i,n){let s=this.getUmlById(t);if(s)if(e==="attribute"){if(s.type!=="uml-class")return;let r=s.attributes.map(o=>o.id===i?{...o,textColor:n.textColor===null?void 0:n.textColor??o.textColor,fontSize:n.fontSize===null?void 0:n.fontSize??o.fontSize,strikethrough:n.strikethrough===null?void 0:n.strikethrough??o.strikethrough}:o);this.updateUmlClass(t,{attributes:r});}else {let r=s.methods.map(o=>o.id===i?{...o,textColor:n.textColor===null?void 0:n.textColor??o.textColor,fontSize:n.fontSize===null?void 0:n.fontSize??o.fontSize,strikethrough:n.strikethrough===null?void 0:n.strikethrough??o.strikethrough}:o);s.type==="uml-class"?this.updateUmlClass(t,{methods:r}):this.updateUmlInterface(t,{methods:r});}}getUmlRowAtScreenPoint(t){let e=this.camera.screenToPage(t);for(let i=this.shapes.length-1;i>=0;i--){let n=this.shapes[i];if(n.type!=="uml-class"&&n.type!=="uml-interface")continue;let s=n.width/2,r=n.height/2;if(e.x<n.x-s||e.x>n.x+s||e.y<n.y-r||e.y>n.y+r)continue;let o=Y,a=e.y-n.y;if(a>=-r&&a<=-r+o)return {shape:n,section:"className",rowIndex:-1,text:n.className};if(n.type==="uml-interface"){let y=-r+o,p=r;if(n.methods.length>0&&a>=y&&a<=p){let f=Math.floor((a-y-D)/L);if(f>=0&&f<n.methods.length){let T=n.methods[f];return {shape:n,section:"method",rowIndex:f,text:`${T.visibility} ${T.name}(${T.params}): ${T.returnType}`}}return {shape:n,section:"method",rowIndex:-1,text:""}}return {shape:n,section:"className",rowIndex:-1,text:n.className}}let l=n.attributes.length>0?n.attributes.length*L+D*2:D*2,h=-r+o,d=h+l;if(n.attributes.length>0&&a>=h&&a<=d){let y=Math.floor((a-h-D)/L);if(y>=0&&y<n.attributes.length){let p=n.attributes[y];return {shape:n,section:"attribute",rowIndex:y,text:`${p.visibility} ${p.name}: ${p.type}`}}return {shape:n,section:"attribute",rowIndex:-1,text:""}}let c=d,g=r;if(n.methods.length>0&&a>=c&&a<=g){let y=Math.floor((a-c-D)/L);if(y>=0&&y<n.methods.length){let p=n.methods[y];return {shape:n,section:"method",rowIndex:y,text:`${p.visibility} ${p.name}(${p.params}): ${p.returnType}`}}return {shape:n,section:"method",rowIndex:-1,text:""}}return {shape:n,section:"className",rowIndex:-1,text:n.className}}return null}setActiveTool(t){this.tools.has(t)&&(this.activeTool=t,this.notifyListeners());}getActiveTool(){return this.activeTool}getShapes(){return [...this.shapes]}getSelectedIds(){return [...this.selectedIds]}getCamera(){return this.camera}isPointerDown(){return this.pointerIsDown}zoomIn(){this.camera.zoomAt({x:window.innerWidth/2,y:window.innerHeight/2},1.2),this.scheduleRender(),this.notifyListeners();}zoomOut(){this.camera.zoomAt({x:window.innerWidth/2,y:window.innerHeight/2},.8),this.scheduleRender(),this.notifyListeners();}resetZoom(){this.camera.reset(),this.scheduleRender(),this.notifyListeners();}panBy(t,e){this.camera.translate(t,e),this.scheduleRender(),this.notifyListeners();}setCameraPosition(t,e){this.camera.x=t,this.camera.y=e,this.scheduleRender(),this.notifyListeners();}requestRender(){this.scheduleRender(),this.notifyListeners();}setShowGrid(t){this.renderer.setShowGrid(t),this.scheduleRender();}render(){this.renderer.render(this.shapes,this.camera,new Set(this.selectedIds),this.brushRect,this.snapGuides,this.connectingTargetId,this.genPreview);}scheduleRender(){this.renderScheduled||(this.renderScheduled=true,requestAnimationFrame(()=>{this.renderScheduled=false,this.render();}));}subscribe(t){return this.listeners.add(t),()=>this.listeners.delete(t)}subscribeNotifications(t){return this.notificationListeners.add(t),()=>this.notificationListeners.delete(t)}notify(t){this.notificationListeners.forEach(e=>e(t));}notifyListeners(){this.notifyScheduled||(this.notifyScheduled=true,queueMicrotask(()=>{this.notifyScheduled=false,this.listeners.forEach(t=>t());}));}cloneShapes(t){return t.map(e=>{let i={...e,style:{...e.style}};return Array.isArray(e.points)&&(i.points=e.points.map(n=>({...n}))),e.startBinding&&(i.startBinding={...e.startBinding}),e.endBinding&&(i.endBinding={...e.endBinding}),i})}commitHistory(){if(this.isUndoing)return;let t={shapes:this.cloneShapes(this.shapes),selectedIds:[...this.selectedIds]};this.undoStack.push(t),this.undoStack.length>Tt&&this.undoStack.shift(),this.redoStack=[];}mark(){this.commitHistory();}undo(){if(this.undoStack.length!==0){this.isUndoing=true;try{this.redoStack.push({shapes:this.cloneShapes(this.shapes),selectedIds:[...this.selectedIds]});let t=this.undoStack.pop();this.shapes=this.cloneShapes(t.shapes),this.selectedIds=[...t.selectedIds];}finally{this.isUndoing=false;}this.notifyListeners(),this.render();}}redo(){if(this.redoStack.length!==0){this.isUndoing=true;try{this.undoStack.push({shapes:this.cloneShapes(this.shapes),selectedIds:[...this.selectedIds]});let t=this.redoStack.pop();this.shapes=this.cloneShapes(t.shapes),this.selectedIds=[...t.selectedIds];}finally{this.isUndoing=false;}this.notifyListeners(),this.render();}}canUndo(){return this.undoStack.length>0}canRedo(){return this.redoStack.length>0}saveToStorage(){try{let t=JSON.stringify({version:1,shapes:this.shapes,savedAt:Date.now()});return localStorage.setItem(dt,t),this.notifyListeners(),this.notify("\u5DF2\u4FDD\u5B58"),!0}catch(t){return console.error("\u4FDD\u5B58\u5931\u8D25:",t),this.notify("\u4FDD\u5B58\u5931\u8D25"),false}}loadFromStorage(){try{let t=localStorage.getItem(dt);if(!t)return !1;let e=JSON.parse(t);return e.shapes&&Array.isArray(e.shapes)?(this.shapes=e.shapes,this.selectedIds=[],this.undoStack=[],this.redoStack=[],this.notifyListeners(),this.scheduleRender(),!0):!1}catch(t){return console.error("\u52A0\u8F7D\u5931\u8D25:",t),false}}clearStorage(){localStorage.removeItem(dt);}exportJSON(){return JSON.stringify({version:1,shapes:this.shapes,savedAt:Date.now()},null,2)}importJSON(t){try{let e=JSON.parse(t);return e.shapes&&Array.isArray(e.shapes)?(this.commitHistory(),this.shapes=e.shapes,this.selectedIds=[],this.notifyListeners(),this.render(),!0):!1}catch(e){return console.error("\u5BFC\u5165\u5931\u8D25:",e),false}}getEditingShapeId(){return this.editingShapeId}canEditShape(t){return !(t.type==="line"||t.type==="arrow"||t.type==="draw"||t.type==="uml-class"||t.type==="uml-interface")}enterEditing(t){let e=this.shapes.find(i=>i.id===t);!e||!this.canEditShape(e)||(this.editingShapeId=t,this.selectedIds=[t],this.isNewTextShape=e.type==="text"&&!e.text,this.originalTextValue=e.text||"",this.notifyListeners(),this.scheduleRender(),requestAnimationFrame(()=>{this.createTextInput(e);}));}exitEditing(){if(!this.editingShapeId)return;let t=this.editingShapeId,e=this.shapes.find(n=>n.id===t),i=this.textInput?this.textInput.value:"";if(this.removeTextInput(),e)if(e.type==="text")if(this.commitHistory(),!i.trim()&&this.isNewTextShape)this.shapes=this.shapes.filter(n=>n.id!==t),this.selectedIds=this.selectedIds.filter(n=>n!==t);else {let n=e,s=n.fontSize||16,r=s*1.3,o=n.width||200,a=i.split(`
|
|
3
|
-
`),
|
|
4
|
-
`+
|
|
1
|
+
var Y={identity(){return {a:1,b:0,c:0,d:1,e:0,f:0}},translation(d,e){return {a:1,b:0,c:0,d:1,e:d,f:e}},rotation(d){let e=Math.cos(d),t=Math.sin(d);return {a:e,b:t,c:-t,d:e,e:0,f:0}},scale(d,e){return {a:d,b:0,c:0,d:e,e:0,f:0}},multiply(d,e){return {a:d.a*e.a+d.b*e.c,b:d.a*e.b+d.b*e.d,c:d.c*e.a+d.d*e.c,d:d.c*e.b+d.d*e.d,e:d.e*e.a+d.f*e.c+e.e,f:d.e*e.b+d.f*e.d+e.f}},apply(d,e){return {x:d.a*e.x+d.c*e.y+d.e,y:d.b*e.x+d.d*e.y+d.f}},invert(d){let e=d.a*d.d-d.b*d.c;if(Math.abs(e)<1e-10)return null;let t=1/e;return {a:d.d*t,b:-d.b*t,c:-d.c*t,d:d.a*t,e:(d.c*d.f-d.d*d.e)*t,f:(d.b*d.e-d.a*d.f)*t}},createCameraMatrix(d){let e=Y.scale(d.zoom,d.zoom),t=Y.translation(d.x,d.y);return Y.multiply(t,e)}};var ee=class{x=0;y=0;zoom=1;minZoom=.1;maxZoom=10;getMatrix(){return Y.createCameraMatrix({x:this.x,y:this.y,zoom:this.zoom})}getInverseMatrix(){return Y.invert(this.getMatrix())}screenToPage(e){let t=this.getInverseMatrix();return t?Y.apply(t,e):e}pageToScreen(e){return Y.apply(this.getMatrix(),e)}translate(e,t){this.x+=e,this.y+=t;}zoomAt(e,t){let i=this.screenToPage(e);this.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.zoom*t));let n=this.pageToScreen(i);this.x+=e.x-n.x,this.y+=e.y-n.y;}reset(){this.x=0,this.y=0,this.zoom=1;}getZoom(){return this.zoom}fitBounds(e,t=50){let i=window.innerWidth,n=window.innerHeight,s=(i-t*2)/e.width,r=(n-t*2)/e.height,o=Math.min(s,r,this.maxZoom);this.zoom=Math.max(this.minZoom,o),this.x=(i-e.width*this.zoom)/2-e.x*this.zoom,this.y=(n-e.height*this.zoom)/2-e.y*this.zoom;}};var Ne={primary:"#3b82f6",selection:{outline:"#3b82f6",handleStroke:"#3b82f6",handleFill:"#ffffff",outlineFill:"rgba(59, 130, 246, 0.1)",shadow:"#3b82f6"},grid:"#e5e7eb",text:"#1f2937",editBorder:"#3b82f6",brushFill:"rgba(59, 130, 246, 0.08)",brushStroke:"rgba(59, 130, 246, 0.8)",guide:"rgba(59, 130, 246, 0.6)",lineHighlight:"rgba(59, 130, 246, 0.4)",genDot:"#3b82f6",genLine:"rgba(59, 130, 246, 0.55)"},v={...Ne,selection:{...Ne.selection}},Me=new Set;function Ge(d){return Me.add(d),()=>Me.delete(d)}function de(d){d.selection&&Object.assign(v.selection,d.selection);for(let e of Object.keys(d)){if(e==="selection")continue;let t=d[e];t!==void 0&&(v[e]=t);}Me.forEach(e=>e());}function Oe(){return v}function q(d,e){let t=Re(d);if(!t)return d;let i=parseInt(t,16),n=i>>16&255,s=i>>8&255,r=i&255;return `rgba(${n}, ${s}, ${r}, ${e})`}function ze(d,e){let t=Re(d);if(!t)return d;let i=parseInt(t,16),n=e<0?0:255,s=Math.abs(e),r=o=>Math.round((n-o)*s+o).toString(16).padStart(2,"0");return `#${r(i>>16&255)}${r(i>>8&255)}${r(i&255)}`}function Re(d){let e=d.replace("#","").trim();return /^[0-9a-fA-F]{3}$|^[0-9a-fA-F]{6}$/.test(e)?e.length===3?e.split("").map(t=>t+t).join(""):e:null}var H=class{context;constructor(e){this.context=e;}getCursor(e){return null}dispose(){}};var He={"zh-CN":{"save.success":"\u5DF2\u4FDD\u5B58","save.fail":"\u4FDD\u5B58\u5931\u8D25","tool.select":"\u9009\u62E9\u5DE5\u5177","tool.hand":"\u62D6\u62FD\u89C6\u53E3","tool.rectangle":"\u77E9\u5F62","tool.rounded-rectangle":"\u5706\u89D2\u77E9\u5F62","tool.circle":"\u5706\u5F62","tool.ellipse":"\u692D\u5706","tool.diamond":"\u83F1\u5F62","tool.triangle":"\u4E09\u89D2\u5F62","tool.hexagon":"\u516D\u8FB9\u5F62","tool.parallelogram":"\u5E73\u884C\u56DB\u8FB9\u5F62","tool.trapezoid":"\u68AF\u5F62","tool.pentagon":"\u4E94\u8FB9\u5F62","tool.octagon":"\u516B\u8FB9\u5F62","tool.star":"\u661F\u5F62","tool.uml-class":"UML \u7C7B\u56FE","tool.uml-interface":"UML \u63A5\u53E3","tool.line":"\u76F4\u7EBF","tool.arrow":"\u7EBF\u6761","tool.text":"\u6587\u672C","tool.draw":"\u753B\u7B14","tool.pen":"\u753B\u7B14","tool.highlighter":"\u8367\u5149\u7B14","tool.eraser":"\u6A61\u76AE\u64E6","status.none":"\u672A\u9009\u62E9","status.selected":"\u5DF2\u9009\u62E9 {n} \u4E2A\u56FE\u5F62","toolbar.select":"\u9009\u62E9 (V)","toolbar.hand":"\u62D6\u62FD\u89C6\u53E3 (H)","toolbar.shapes":"\u5F62\u72B6","toolbar.grid":"\u7F51\u683C","toolbar.undo":"\u64A4\u9500 (Ctrl+Z)","toolbar.redo":"\u91CD\u505A (Ctrl+Shift+Z)","toolbar.arrow":"\u7BAD\u5934","toolbar.text":"\u6587\u672C","toolbar.pen":"\u753B\u7B14","toolbar.highlighter":"\u8367\u5149\u7B14","toolbar.eraser":"\u6A61\u76AE\u64E6","toolbar.uml-class":"UML \u7C7B\u56FE","toolbar.uml-interface":"UML \u63A5\u53E3","zoom.in":"\u653E\u5927","zoom.out":"\u7F29\u5C0F","zoom.reset":"\u91CD\u7F6E","style.stroke":"\u8FB9\u6846","style.fill":"\u586B\u5145","style.text":"\u6587\u5B57","style.highlight":"\u9AD8\u4EAE","style.none":"\u65E0","style.connection":"\u8FDE\u7EBF","style.arrow":"\u7BAD\u5934","style.dashed":"\u865A\u7EBF","style.solid":"\u5B9E\u7EBF","style.connection.straight":"\u76F4\u7EBF","style.connection.polyline":"\u6298\u7EBF","style.connection.orthogonal":"\u76F4\u89D2\u6298\u7EBF","style.connection.curve":"\u66F2\u7EBF","style.arrowhead.none":"\u65E0\u7BAD\u5934","style.arrowhead.end":"\u7EC8\u70B9\u7BAD\u5934","style.arrowhead.start":"\u8D77\u70B9\u7BAD\u5934","style.arrowhead.both":"\u53CC\u7BAD\u5934","style.arrowhead.inheritance":"\u7EE7\u627F","style.arrowhead.composition":"\u7EC4\u5408","style.arrowhead.aggregation":"\u805A\u5408","menu.title":"\u9009\u62E9\u65B0\u56FE\u5F62","menu.cancel":"\u70B9\u51FB\u7A7A\u767D\u5904\u53D6\u6D88","shape.rectangle":"\u77E9\u5F62","shape.rounded-rectangle":"\u5706\u89D2","shape.circle":"\u5706\u5F62","shape.ellipse":"\u692D\u5706","shape.diamond":"\u83F1\u5F62","shape.triangle":"\u4E09\u89D2","shape.hexagon":"\u516D\u8FB9\u5F62","shape.parallelogram":"\u5E73\u884C","shape.trapezoid":"\u68AF\u5F62","shape.pentagon":"\u4E94\u8FB9\u5F62","shape.octagon":"\u516B\u8FB9\u5F62","shape.star":"\u661F\u5F62","shape.uml-class":"\u7C7B\u56FE","shape.uml-interface":"\u63A5\u53E3","uml.drag":"\u62D6\u62FD\u6392\u5E8F","uml.delete":"\u5220\u9664\u8BE5\u884C","uml.textColor":"\u6587\u5B57\u989C\u8272","uml.defaultColor":"\u9ED8\u8BA4\u989C\u8272","uml.fontSize":"\u5B57\u53F7","uml.strikethrough":"\u5220\u9664\u7EBF","uml.attribute":"\u5C5E\u6027","uml.method":"\u65B9\u6CD5","minimap.title":"\u5C0F\u5730\u56FE","minimap.expand":"\u5C55\u5F00\u5C0F\u5730\u56FE","minimap.collapse":"\u6536\u8D77\u5C0F\u5730\u56FE","tool.mind-map":"\u601D\u7EF4\u5BFC\u56FE","toolbar.mind-map":"\u601D\u7EF4\u5BFC\u56FE","shape.mind-map":"\u601D\u7EF4\u5BFC\u56FE","mindmap.defaultRoot":"\u4E2D\u5FC3\u4E3B\u9898","mindmap.defaultBranch":"\u5206\u652F\u4E3B\u9898","mindmap.nodeText":"\u8282\u70B9\u6587\u672C","mindmap.addChild":"\u5B50\u8282\u70B9","mindmap.addSibling":"\u5144\u5F1F\u8282\u70B9","mindmap.deleteNode":"\u5220\u9664\u8282\u70B9","mindmap.color":"\u989C\u8272","mindmap.levelColor":"\u9ED8\u8BA4\u5C42\u7EA7\u8272","mindmap.icon":"\u56FE\u6807","mindmap.noIcon":"\u65E0\u56FE\u6807","mindmap.note":"\u5C5E\u6027\u8BF4\u660E","mindmap.notePlaceholder":"\u8BF4\u660E\u5185\u5BB9\uFF08\u53EF\u9009\uFF09","mindmap.noteColor":"\u8BF4\u660E\u989C\u8272","mindmap.noteColorDefault":"\u540C\u8282\u70B9\u8272","mindmap.collapse":"\u6298\u53E0","mindmap.expand":"\u5C55\u5F00","mindmap.close":"\u5173\u95ED\u7F16\u8F91","mindmap.more":"\u66F4\u591A\u8BBE\u7F6E"},"en-US":{"save.success":"Saved","save.fail":"Save failed","tool.select":"Select tool","tool.hand":"Pan view","tool.rectangle":"Rectangle","tool.rounded-rectangle":"Rounded rectangle","tool.circle":"Circle","tool.ellipse":"Ellipse","tool.diamond":"Diamond","tool.triangle":"Triangle","tool.hexagon":"Hexagon","tool.parallelogram":"Parallelogram","tool.trapezoid":"Trapezoid","tool.pentagon":"Pentagon","tool.octagon":"Octagon","tool.star":"Star","tool.uml-class":"UML class","tool.uml-interface":"UML interface","tool.line":"Line","tool.arrow":"Line","tool.text":"Text","tool.draw":"Pen","tool.pen":"Pen","tool.highlighter":"Highlighter","tool.eraser":"Eraser","status.none":"Nothing selected","status.selected":"{n} shapes selected","toolbar.select":"Select (V)","toolbar.hand":"Pan view (H)","toolbar.shapes":"Shapes","toolbar.grid":"Grid","toolbar.undo":"Undo (Ctrl+Z)","toolbar.redo":"Redo (Ctrl+Shift+Z)","toolbar.arrow":"Arrow","toolbar.text":"Text","toolbar.pen":"Pen","toolbar.highlighter":"Highlighter","toolbar.eraser":"Eraser","toolbar.uml-class":"UML class","toolbar.uml-interface":"UML interface","zoom.in":"Zoom in","zoom.out":"Zoom out","zoom.reset":"Reset","style.stroke":"Border","style.fill":"Fill","style.text":"Text","style.highlight":"Highlight","style.none":"None","style.connection":"Connection","style.arrow":"Arrow head","style.dashed":"Dashed","style.solid":"Solid","style.connection.straight":"Straight","style.connection.polyline":"Polyline","style.connection.orthogonal":"Orthogonal","style.connection.curve":"Curve","style.arrowhead.none":"None","style.arrowhead.end":"End","style.arrowhead.start":"Start","style.arrowhead.both":"Both","style.arrowhead.inheritance":"Inheritance","style.arrowhead.composition":"Composition","style.arrowhead.aggregation":"Aggregation","menu.title":"Create shape","menu.cancel":"Click empty space to cancel","shape.rectangle":"Rectangle","shape.rounded-rectangle":"Rounded","shape.circle":"Circle","shape.ellipse":"Ellipse","shape.diamond":"Diamond","shape.triangle":"Triangle","shape.hexagon":"Hexagon","shape.parallelogram":"Parallelogram","shape.trapezoid":"Trapezoid","shape.pentagon":"Pentagon","shape.octagon":"Octagon","shape.star":"Star","shape.uml-class":"Class","shape.uml-interface":"Interface","uml.drag":"Drag to reorder","uml.delete":"Delete row","uml.textColor":"Text color","uml.defaultColor":"Default color","uml.fontSize":"Font size","uml.strikethrough":"Strikethrough","uml.attribute":"Attributes","uml.method":"Methods","minimap.title":"Minimap","minimap.expand":"Expand minimap","minimap.collapse":"Collapse minimap","tool.mind-map":"Mind map","toolbar.mind-map":"Mind map","shape.mind-map":"Mind map","mindmap.defaultRoot":"Central topic","mindmap.defaultBranch":"Branch topic","mindmap.nodeText":"Node text","mindmap.addChild":"Child","mindmap.addSibling":"Sibling","mindmap.deleteNode":"Delete node","mindmap.color":"Color","mindmap.levelColor":"Default level color","mindmap.icon":"Icon","mindmap.noIcon":"No icon","mindmap.note":"Note","mindmap.notePlaceholder":"Note content (optional)","mindmap.noteColor":"Note color","mindmap.noteColorDefault":"Same as node","mindmap.collapse":"Collapse","mindmap.expand":"Expand","mindmap.close":"Close editor","mindmap.more":"More settings"}},ce="zh-CN",ve=new Set;function ue(d){ce!==d&&(ce=d,ve.forEach(e=>e()));}function $e(){return ce}function Ke(d){return ve.add(d),()=>ve.delete(d)}function z(d,e){let i=He[ce][d]??He["zh-CN"][d];if(e)for(let[n,s]of Object.entries(e))i=i.replace(new RegExp(`\\{${n}\\}`,"g"),String(s));return i}var Te=["#ef4444","#f59e0b","#10b981","#3b82f6","#8b5cf6","#ec4899"],pe=14,We=40,Ye=80,Xe=240;function ge(d,e){return d.color??Te[e%Te.length]}function Ve(d){let e=d.text||"",t=0;for(let n of e)t+=/[\u2e80-\u9fff\uf900-\ufaff\uff00-\uffef\u3000-\u303f]/.test(n)?1:.6;let i=Math.max(80,Math.min(240,Math.ceil(t*14)+24));return d.icon&&(i+=26),{width:i,height:40}}function ye(d){let e={...d};return d.children&&(e.children=d.children.map(t=>ye(t))),e}function me(d,e,t){if(d.id===e)return {...d,...t};let i=d.children??[],n=i.map(s=>me(s,e,t));return n.some((s,r)=>s!==i[r])?{...d,children:n}:d}function Pe(d,e,t){if(d.id===e)return {...d,children:[...d.children??[],t],collapsed:false};let i=d.children??[],n=i.map(s=>Pe(s,e,t));return n.some((s,r)=>s!==i[r])?{...d,children:n}:d}function Ie(d,e,t){let i=d.children??[];for(let n=0;n<i.length;n++){if(i[n].id===e){let r=[...i];return r.splice(n+1,0,t),{...d,children:r}}let s=Ie(i[n],e,t);if(s!==i[n])return {...d,children:i.map(r=>r===i[n]?s:r)}}return d}function Ce(d,e){if(d.id===e)return null;let t=d.children??[],i=t.map(n=>Ce(n,e)).filter(n=>n!==null);return i.length!==t.length||i.some((n,s)=>n!==t[s])?{...d,children:i}:d}function F(d,e){if(d.id===e)return d;for(let t of d.children??[]){let i=F(t,e);if(i)return i}return null}function ke(d,e){if(d.id===e)return 0;for(let t of d.children??[]){let i=ke(t,e);if(i!==-1)return i+1}return -1}function te(d,e){for(let t of d.children??[]){if(t.id===e)return d;let i=te(t,e);if(i)return i}return null}function Be(d){let e=1;for(let t of d.children??[])e+=Be(t);return e}function _e(d,e){e.set(d.id,Ve(d));for(let t of d.children??[])_e(t,e);}function k(d){let e=new Map;_e(d,e);let t=new Map,i=c=>{let p=c.collapsed?[]:c.children??[];if(p.length===0)t.set(c.id,e.get(c.id).height);else {let g=0;for(let m of p)g+=i(m);g+=16*(p.length-1),t.set(c.id,Math.max(e.get(c.id).height,g));}return t.get(c.id)};i(d);let n=new Map,s=(c,p,g,m)=>{let y=t.get(c.id),w=e.get(c.id);if(n.set(c.id,{x:g,y:m+y/2,depth:p,width:w.width,height:w.height}),c.collapsed)return;let f=m;for(let T of c.children??[]){let M=e.get(T.id);s(T,p+1,g+w.width/2+48+M.width/2,f),f+=t.get(T.id)+16;}};s(d,0,0,-t.get(d.id)/2);let r=1/0,o=-1/0,a=1/0,h=-1/0;n.forEach(c=>{r=Math.min(r,c.x-c.width/2),o=Math.max(o,c.x+c.width/2),a=Math.min(a,c.y-c.height/2),h=Math.max(h,c.y+c.height/2);});let l=(r+o)/2,u=(a+h)/2;return n.forEach(c=>{c.x-=l,c.y-=u;}),{positions:n,width:o-r,height:h-a}}var Fe={strokeColor:"#1f2937",fillColor:"transparent",strokeWidth:2,strokeDash:null},Ze={rectangle:{width:120,height:60},"rounded-rectangle":{width:120,height:60,borderRadius:8},circle:{width:80,height:80},ellipse:{width:100,height:70},diamond:{width:100,height:80},triangle:{width:100,height:90},hexagon:{width:100,height:90},parallelogram:{width:120,height:60},trapezoid:{width:120,height:70},pentagon:{width:100,height:90},octagon:{width:100,height:90},star:{width:100,height:100}},W=14,V=22,X=36,$=14,L=8,ne=160,qe=["rectangle","rounded-rectangle","circle","ellipse","diamond","triangle","hexagon","parallelogram","trapezoid","pentagon","octagon","star","uml-class","uml-interface","mind-map"];function fe(d){return qe.includes(d)}function Ee(d,e,t){let i=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,n=Ze[d]||{width:120,height:60},s=n.width,r=n.height,o=n.radius??s/2,a=n.borderRadius??8,h=t??{...Fe};switch(d){case "rounded-rectangle":return {id:i,type:"rounded-rectangle",x:e.x,y:e.y,width:s,height:r,borderRadius:a,rotation:0,style:h};case "circle":return {id:i,type:"circle",x:e.x,y:e.y,radius:o,rotation:0,style:h};case "ellipse":return {id:i,type:"ellipse",x:e.x,y:e.y,width:s,height:r,rotation:0,style:h};case "diamond":return {id:i,type:"diamond",x:e.x,y:e.y,width:s,height:r,rotation:0,style:h};case "triangle":return {id:i,type:"triangle",x:e.x,y:e.y,width:s,height:r,rotation:0,style:h};case "hexagon":return {id:i,type:"hexagon",x:e.x,y:e.y,width:s,height:r,rotation:0,style:h};case "parallelogram":return {id:i,type:"parallelogram",x:e.x,y:e.y,width:s,height:r,rotation:0,style:h};case "trapezoid":return {id:i,type:"trapezoid",x:e.x,y:e.y,width:s,height:r,rotation:0,style:h};case "pentagon":return {id:i,type:"pentagon",x:e.x,y:e.y,width:s,height:r,rotation:0,style:h};case "octagon":return {id:i,type:"octagon",x:e.x,y:e.y,width:s,height:r,rotation:0,style:h};case "star":return {id:i,type:"star",x:e.x,y:e.y,width:s,height:r,rotation:0,style:h};case "uml-class":{let l="ClassName",u=[{id:`attr_${Date.now()}_1`,visibility:"+",name:"field",type:"string"}],c=[{id:`meth_${Date.now()}_1`,visibility:"+",name:"method",params:"param",returnType:"void"}],{width:p,height:g}=xe(l,u,c);return {id:i,type:"uml-class",x:e.x,y:e.y,width:p,height:g,className:l,attributes:u,methods:c,rotation:0,style:{...h,fillColor:"#ffffff"}}}case "uml-interface":{let l="Interface",u=[{id:`meth_${Date.now()}_1`,visibility:"+",name:"method",params:"type",returnType:"type"}],c=W*.6,p=u.map(f=>`${f.visibility} ${f.name}(${f.params}): ${f.returnType}`),g=Math.max(l.length,...p.map(f=>f.length),0),m=Math.max(ne,g*c+$*2),y=u.length>0?u.length*V+L*2:L*2,w=X+y;return {id:i,type:"uml-interface",x:e.x,y:e.y,width:m,height:w,className:l,methods:u,rotation:0,style:{...h,fillColor:"#ffffff"}}}case "mind-map":{let l=g=>`mm_${g}_${Date.now()}_${Math.random().toString(36).substr(2,6)}`,u={id:l("root"),text:z("mindmap.defaultRoot"),children:[{id:l("b1"),text:z("mindmap.defaultBranch")},{id:l("b2"),text:z("mindmap.defaultBranch")},{id:l("b3"),text:z("mindmap.defaultBranch")}]},{width:c,height:p}=k(u);return {id:i,type:"mind-map",x:e.x,y:e.y,width:c,height:p,root:u,rotation:0,style:{...h,fillColor:"#ffffff"}}}default:return {id:i,type:"rectangle",x:e.x,y:e.y,width:s,height:r,rotation:0,style:h}}}function xe(d,e,t){let i=W*.6,n=[d];for(let u of e)n.push(`${u.visibility} ${u.name}: ${u.type}`);for(let u of t)n.push(`${u.visibility} ${u.name}(${u.params}): ${u.returnType}`);let r=Math.max(...n.map(u=>u.length),0)*i+$*2,o=Math.max(ne,r),a=e.length>0?e.length*V+L*2:L*2,h=t.length>0?t.length*V+L*2:L*2,l=X+a+h;return {width:o,height:l}}var R=class extends H{type;constructor(e,t){super(e),this.type=t;}onPointerDown(e,t){let i=Ee(this.type,e);this.context.commitHistory(),this.context.addShape(i),this.context.selectShape(i.id,false);}onPointerMove(e,t){}onPointerUp(e,t){this.context.setActiveTool("select");}onKeyDown(e){}onKeyUp(e){}getCursor(e){return this.context.getMindMapCursorHitAtPoint(e)?"pointer":"crosshair"}};var De=14,Se=class extends H{type="eraser";erasing=false;lastPoint=null;erasedIds=new Set;onPointerDown(e){this.erasing=true,this.lastPoint=e,this.erasedIds.clear(),this.context.commitHistory(),this.context.setEraserPoint(e),this.eraseAt(e);}onPointerMove(e){if(!this.erasing||!this.lastPoint)return;let t=this.lastPoint,i=Math.hypot(e.x-t.x,e.y-t.y),n=Math.max(1,Math.ceil(i/Math.max(this.brushRadius()*.5,1)));for(let s=1;s<=n;s++){let r=s/n;this.eraseAt({x:t.x+(e.x-t.x)*r,y:t.y+(e.y-t.y)*r});}this.lastPoint=e,this.context.setEraserPoint(e);}onPointerUp(){this.erasing=false,this.lastPoint=null,this.erasedIds.clear(),this.context.setEraserPoint(null);}onKeyDown(){}onKeyUp(){}getCursor(){return this.erasing?"grabbing":"crosshair"}dispose(){this.erasing=false,this.lastPoint=null,this.erasedIds.clear(),this.context.setEraserPoint(null);}brushRadius(){return De/this.context.getCamera().getZoom()}eraseAt(e){let t=this.context.getShapesInBrushRadius(e,this.brushRadius());for(let i of t)this.erasedIds.has(i.id)||(this.erasedIds.add(i.id),this.context.deleteShape(i.id));}};var ie=class d{ctx;width=0;height=0;dpr=window.devicePixelRatio||1;showGrid=false;textLayoutCache=new Map;static TEXT_CACHE_LIMIT=500;constructor(e){let t=e.getContext("2d");if(!t)throw new Error("Failed to get Canvas 2D context");this.ctx=t;}resize(e,t){this.width=e,this.height=t;let i=Math.ceil(e*this.dpr),n=Math.ceil(t*this.dpr);(this.ctx.canvas.width!==i||this.ctx.canvas.height!==n)&&(this.ctx.canvas.width=i,this.ctx.canvas.height=n,this.ctx.canvas.style.width=`${e}px`,this.ctx.canvas.style.height=`${t}px`);}setShowGrid(e){this.showGrid=e;}render(e,t,i,n,s,r,o,a,h,l){let u=this.ctx,c=t.getZoom(),p=t.x,g=t.y;u.setTransform(1,0,0,1,0,0),u.clearRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);let m=this.dpr*c;u.setTransform(m,0,0,m,m*p,m*g),this.showGrid&&this.drawGrid(u,c,p,g);let y=null;for(let f of e)if(f.type==="arrow"&&(f.startBinding||f.endBinding)){y=new Map,e.forEach(T=>y.set(T.id,T));break}let w=y??new Map;e.forEach(f=>{u.save(),u.translate(f.x,f.y),u.rotate(f.rotation);let T=i.has(f.id);this.drawShape(u,f,T,c,w,h,l),u.restore();}),o&&this.drawGenerationPreview(u,o,c),n&&this.drawBrushRect(u,n,c),s&&s.length>0&&this.drawSnapGuides(u,s,c),r&&this.drawConnectingTargetHighlight(u,r,e,c),a&&this.drawEraserBrush(u,a,c),u.setTransform(1,0,0,1,0,0);}drawEraserBrush(e,t,i){let n=De/i;e.beginPath(),e.arc(t.x,t.y,n,0,Math.PI*2),e.fillStyle=q(v.primary,.12),e.fill(),e.strokeStyle=q(v.primary,.55),e.lineWidth=1.5/i,e.stroke();}drawConnectingTargetHighlight(e,t,i,n){let s=i.find(h=>h.id===t);if(!s||s.type==="line"||s.type==="arrow"||s.type==="draw")return;let r=this.getShapeWorldBounds(s),o=[{x:r.x+r.width/2,y:r.y},{x:r.x+r.width,y:r.y+r.height/2},{x:r.x+r.width/2,y:r.y+r.height},{x:r.x,y:r.y+r.height/2}],a=6/n;e.save(),o.forEach(h=>{e.beginPath(),e.arc(h.x,h.y,a,0,Math.PI*2),e.fillStyle=v.selection.handleFill,e.fill(),e.strokeStyle=v.primary,e.lineWidth=2/n,e.stroke();}),e.restore();}getShapeWorldBounds(e){let t=this.getShapeBounds(e);return {x:e.x+t.x,y:e.y+t.y,width:t.width,height:t.height}}drawBrushRect(e,t,i){e.save(),e.fillStyle=v.brushFill,e.strokeStyle=v.brushStroke,e.lineWidth=1.5/i,e.setLineDash([4/i,4/i]),e.beginPath(),e.rect(t.x,t.y,t.width,t.height),e.fill(),e.stroke(),e.restore();}drawGrid(e,t,i,n){let s=-i,r=-n,o=s+this.width/t,a=r+this.height/t,h=20;for(;h*t<10;)h*=2;e.strokeStyle=v.grid,e.lineWidth=1/t,e.beginPath();for(let l=Math.floor(s/h)*h;l<=o;l+=h)e.moveTo(l,r),e.lineTo(l,a);for(let l=Math.floor(r/h)*h;l<=a;l+=h)e.moveTo(s,l),e.lineTo(o,l);e.stroke();}drawShape(e,t,i,n,s,r,o){switch(this.applyStyle(e,t.style,n),t.type){case "rectangle":this.drawRectangle(e,t,i);break;case "rounded-rectangle":this.drawRoundedRectangle(e,t,i);break;case "circle":this.drawCircle(e,t,i);break;case "ellipse":this.drawEllipse(e,t,i);break;case "diamond":this.drawDiamond(e,t,i);break;case "triangle":this.drawTriangle(e,t,i);break;case "hexagon":this.drawHexagon(e,t,i);break;case "parallelogram":this.drawParallelogram(e,t,i);break;case "trapezoid":this.drawTrapezoid(e,t,i);break;case "pentagon":this.drawPentagon(e,t,i);break;case "octagon":this.drawOctagon(e,t,i);break;case "star":this.drawStar(e,t,i);break;case "uml-class":this.drawUmlClass(e,t,i);break;case "uml-interface":this.drawUmlInterface(e,t,i);break;case "mind-map":this.drawMindMap(e,t,i,r,o);break;case "line":this.drawLine(e,t,s,i,n);break;case "arrow":this.drawArrow(e,t,s,i,n);break;case "text":this.drawText(e,t);break;case "draw":this.drawFreehand(e,t);break}if(t.text&&t.type!=="text"&&t.type!=="line"&&t.type!=="arrow"&&t.type!=="draw"&&this.drawShapeText(e,t),i){let a=t.type==="line"||t.type==="arrow"||t.type==="draw";t.type==="mind-map"||(a?this.drawSelectionHandles(e,t,n):(this.drawSelectionOutline(e,t,n),this.drawSelectionHandles(e,t,n)));}}applyStyle(e,t,i){e.strokeStyle=t.strokeColor,e.fillStyle=t.fillColor,e.lineWidth=t.strokeWidth/i,e.lineCap="round",e.lineJoin="round",t.strokeDash?e.setLineDash(t.strokeDash):e.setLineDash([]);}drawRectangle(e,t,i){e.beginPath(),e.rect(-t.width/2,-t.height/2,t.width,t.height),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawRoundedRectangle(e,t,i){let{width:n,height:s,borderRadius:r}=t;e.beginPath(),e.roundRect(-n/2,-s/2,n,s,r),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawCircle(e,t,i){e.beginPath(),e.arc(0,0,t.radius,0,Math.PI*2),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawEllipse(e,t,i){e.beginPath(),e.ellipse(0,0,t.width/2,t.height/2,0,0,Math.PI*2),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawDiamond(e,t,i){e.beginPath(),e.moveTo(0,-t.height/2),e.lineTo(t.width/2,0),e.lineTo(0,t.height/2),e.lineTo(-t.width/2,0),e.closePath(),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawTriangle(e,t,i){e.beginPath(),e.moveTo(0,-t.height/2),e.lineTo(t.width/2,t.height/2),e.lineTo(-t.width/2,t.height/2),e.closePath(),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawHexagon(e,t,i){let n=t.width/2,s=t.height/2;e.beginPath();for(let r=0;r<6;r++){let o=r*Math.PI/3-Math.PI/2,a=n*Math.cos(o),h=s*Math.sin(o);r===0?e.moveTo(a,h):e.lineTo(a,h);}e.closePath(),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawParallelogram(e,t,i){let{width:n,height:s}=t,r=n*.2;e.beginPath(),e.moveTo(-n/2+r,-s/2),e.lineTo(n/2,-s/2),e.lineTo(n/2-r,s/2),e.lineTo(-n/2,s/2),e.closePath(),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawTrapezoid(e,t,i){let{width:n,height:s}=t,r=n*.15;e.beginPath(),e.moveTo(-n/2+r,-s/2),e.lineTo(n/2-r,-s/2),e.lineTo(n/2,s/2),e.lineTo(-n/2,s/2),e.closePath(),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawPentagon(e,t,i){let n=t.width/2,s=t.height/2;e.beginPath();for(let r=0;r<5;r++){let o=r*2*Math.PI/5-Math.PI/2,a=n*Math.cos(o),h=s*Math.sin(o);r===0?e.moveTo(a,h):e.lineTo(a,h);}e.closePath(),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawOctagon(e,t,i){let n=t.width/2,s=t.height/2;e.beginPath();for(let r=0;r<8;r++){let o=r*Math.PI/4-Math.PI/8,a=n*Math.cos(o),h=s*Math.sin(o);r===0?e.moveTo(a,h):e.lineTo(a,h);}e.closePath(),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawStar(e,t,i){let n=t.width/2,s=t.height/2,r=5,o=.4;e.beginPath();for(let a=0;a<r*2;a++){let h=a*Math.PI/r-Math.PI/2,l=a%2===0?1:o,u=n*l*Math.cos(h),c=s*l*Math.sin(h);a===0?e.moveTo(u,c):e.lineTo(u,c);}e.closePath(),t.style.fillColor!=="transparent"&&e.fill(),e.stroke();}drawUmlClass(e,t,i){let{width:n,height:s,className:r,attributes:o,methods:a}=t,h=n/2,l=s/2,u=X,c=o.length>0?o.length*V+L*2:L*2;e.beginPath(),e.rect(-h,-l,n,s),t.style.fillColor!=="transparent"&&(e.fillStyle=t.style.fillColor,e.fill()),e.stroke(),e.beginPath(),e.moveTo(-h,-l+u),e.lineTo(h,-l+u),e.moveTo(-h,-l+u+c),e.lineTo(h,-l+u+c),e.stroke(),e.save(),e.textBaseline="middle";let p=n-$*2,g=f=>{if(e.measureText(f).width<=p)return f;let T="\u2026",M=0,b=f.length;for(;M<b;){let I=M+b+1>>1;e.measureText(f.slice(0,I)+T).width<=p?M=I:b=I-1;}return f.slice(0,M)+T},m=(f,T,M,b,I,E,B)=>{let O=b||W,K=I||"#1f2937";e.font=`${O}px sans-serif`,e.fillStyle=K,e.textAlign=B;let A=g(f);if(e.fillText(A,T,M),E){let N=e.measureText(A).width,he=T;e.strokeStyle=K,e.beginPath(),e.moveTo(he,M),e.lineTo(he+N,M),e.stroke();}};e.font=`bold ${t.fontSize||W}px sans-serif`,e.textAlign="center",e.fillStyle=t.textColor||"#1f2937",e.fillText(g(r),0,-l+u/2);let y=-l+u+L+V/2;o.forEach((f,T)=>{let M=`${f.visibility} ${f.name}: ${f.type}`;m(M,-h+$,y+T*V,f.fontSize||t.fontSize||0,f.textColor||t.textColor||"",!!f.strikethrough,"left");});let w=-l+u+c+L+V/2;a.forEach((f,T)=>{let M=`${f.visibility} ${f.name}(${f.params}): ${f.returnType}`;m(M,-h+$,w+T*V,f.fontSize||t.fontSize||0,f.textColor||t.textColor||"",!!f.strikethrough,"left");}),e.restore();}drawUmlInterface(e,t,i){let{width:n,height:s,className:r,methods:o}=t,a=n/2,h=s/2,l=X;e.beginPath(),e.rect(-a,-h,n,s),t.style.fillColor!=="transparent"&&(e.fillStyle=t.style.fillColor,e.fill()),e.stroke(),e.beginPath(),e.moveTo(-a,-h+l),e.lineTo(a,-h+l),e.stroke(),e.save(),e.textBaseline="middle";let u=n-$*2,c=y=>{if(e.measureText(y).width<=u)return y;let w="\u2026",f=0,T=y.length;for(;f<T;){let M=f+T+1>>1;e.measureText(y.slice(0,M)+w).width<=u?f=M:T=M-1;}return y.slice(0,f)+w},p=(y,w,f,T,M,b,I)=>{let E=T||W,B=M||"#1f2937";e.font=`${E}px sans-serif`,e.fillStyle=B,e.textAlign=I;let O=c(y);if(e.fillText(O,w,f),b){let K=e.measureText(O).width,A=w;e.strokeStyle=B,e.beginPath(),e.moveTo(A,f),e.lineTo(A+K,f),e.stroke();}};e.font=`bold ${t.fontSize||W}px sans-serif`,e.textAlign="center",e.fillStyle=t.textColor||"#1f2937";let g=`<<${r||"Interface"}>>`;e.fillText(c(g),0,-h+l/2);let m=-h+l+L+V/2;o.forEach((y,w)=>{let f=`${y.visibility} ${y.name}(${y.params}): ${y.returnType}`;p(f,-a+$,m+w*V,y.fontSize||t.fontSize||0,y.textColor||t.textColor||"",!!y.strikethrough,"left");}),e.restore();}static DEFAULT_CORNER_RADIUS=10;static ROUTE_CLEARANCE=30;static CONNECTION_LEAD=24;static CONNECTED_PAD=8;drawMindMap(e,t,i,n,s){let o=k(t.root).positions;this.drawMindMapConnections(e,t.root,o),this.drawMindMapNodes(e,t,o,n,s);}drawMindMapConnections(e,t,i){let n=s=>{if(s.collapsed)return;let r=i.get(s.id);if(r)for(let o of s.children??[]){let a=i.get(o.id);if(!a)continue;let h=ge(o,a.depth);e.strokeStyle=h,e.lineWidth=2,e.lineCap="round",e.beginPath(),e.moveTo(r.x+r.width/2,r.y);let l=(r.x+r.width/2+(a.x-a.width/2))/2;e.bezierCurveTo(l,r.y,l,a.y,a.x-a.width/2,a.y),e.stroke(),n(o);}};n(t);}drawMindMapNodes(e,t,i,n,s){let r=t.root,o=a=>{let h=i.get(a.id);if(!h)return;let l=ge(a,h.depth),u=h.width/2,c=h.height/2;if(e.fillStyle="#ffffff",e.strokeStyle=l,e.lineWidth=2,e.beginPath(),e.roundRect(h.x-u,h.y-c,h.width,h.height,6),e.fill(),e.stroke(),s&&s.shapeId===t.id&&s.nodeId===a.id&&(e.fillStyle=q(v.primary,.06),e.strokeStyle=q(v.primary,.55),e.lineWidth=2,e.beginPath(),e.roundRect(h.x-u,h.y-c,h.width,h.height,6),e.fill(),e.stroke()),n&&n.shapeId===t.id&&n.nodeId===a.id&&(e.fillStyle=q(v.primary,.12),e.strokeStyle=v.primary,e.lineWidth=2.5,e.beginPath(),e.roundRect(h.x-u,h.y-c,h.width,h.height,6),e.fill(),e.stroke()),a.children&&a.children.length>0&&(e.fillStyle="#ffffff",e.strokeStyle=l,e.lineWidth=2,e.beginPath(),e.arc(h.x+u+10,h.y,8,0,Math.PI*2),e.fill(),e.stroke(),e.fillStyle=l,e.font="bold 13px sans-serif",e.textAlign="center",e.textBaseline="middle",e.fillText(a.collapsed?"+":"\u2212",h.x+u+10,h.y+.5)),a.note){let I=a.noteColor??l;e.font="11px sans-serif";let E=Math.min(e.measureText(a.note).width+12,130),B=16;e.fillStyle=I,e.beginPath(),e.roundRect(h.x-u,h.y-c-B+2,E,B,4),e.fill(),e.fillStyle="#ffffff",e.font="11px sans-serif",e.textAlign="left",e.textBaseline="middle",e.fillText(e.measureText(a.note).width+12>130?a.note.slice(0,12)+"\u2026":a.note,h.x-u+6,h.y-c-B/2+2);}e.font=`${14}px sans-serif`;let y=a.icon?18:0,w=h.width-y-(a.icon?8:0)-16,f=this.ellipsizeText(e,a.text||"",w),T=e.measureText(f).width,M=y+(y?8:0)+T,b=h.x-M/2;if(e.textBaseline="middle",a.icon&&(e.font="16px sans-serif",e.textAlign="left",e.fillStyle="#1f2937",e.fillText(a.icon,b,h.y+1),b+=y+8),e.font=`${14}px sans-serif`,e.textAlign="left",e.fillStyle="#1f2937",e.fillText(f,b,h.y),!a.collapsed)for(let I of a.children??[])o(I);};o(r);}ellipsizeText(e,t,i){if(i<=0)return "";if(e.measureText(t).width<=i)return t;let n="\u2026",s=0,r=t.length;for(;s<r;){let o=s+r+1>>1;e.measureText(t.slice(0,o)+n).width<=i?s=o:r=o-1;}return t.slice(0,s)+n}drawLine(e,t,i,n,s){if(t.points.length<2)return;let r=t.points.map(l=>({x:l.x,y:l.y}));r.length>=2&&(r[0]=this.clampToShapeOutline(r[0],i,t.id,r[r.length-1]),r[r.length-1]=this.clampToShapeOutline(r[r.length-1],i,t.id,r[0]));let o=r.map(l=>({x:l.x-t.x,y:l.y-t.y})),a=t.connectionType||"straight",h=a==="straight"?this.getAlignedPoints(o):this.buildPathPoints(o,a,this.collectRoutingObstacles(t.id,o[0],o[o.length-1],i,{x:t.x,y:t.y}),{fromN:this.getDockNormal(r[0],i,t.id),toN:this.getDockNormal(r[r.length-1],i,t.id)});if(a==="straight"){e.beginPath(),e.moveTo(o[0].x,o[0].y);for(let l=1;l<o.length;l++)e.lineTo(o[l].x,o[l].y);e.stroke(),e.setLineDash([]);}else a==="orthogonal"?this.drawSharpPolyline(e,h):this.drawRoundedPolyline(e,h,d.DEFAULT_CORNER_RADIUS),e.stroke(),e.setLineDash([]);n&&this.drawLinearHighlight(e,h,s);}drawArrow(e,t,i,n,s){if(t.points.length<2)return;let r=t.points.map(c=>({x:c.x,y:c.y}));if(t.startBinding){let c=i.get(t.startBinding.toShapeId);c&&(r[0]=this.getBindingPoint(c,t.startBinding));}if(t.endBinding){let c=i.get(t.endBinding.toShapeId);c&&(r[r.length-1]=this.getBindingPoint(c,t.endBinding));}r[0]=this.clampToShapeOutline(r[0],i,t.id,r[r.length-1]),r[r.length-1]=this.clampToShapeOutline(r[r.length-1],i,t.id,r[0]);let o=r.map(c=>({x:c.x-t.x,y:c.y-t.y})),a=t.connectionType||"straight",h=t.arrowHead??"end";!!t.dashed?e.setLineDash([8,5]):e.setLineDash([]);let u;if(a==="straight"){let c=this.getAlignedPoints(o);u=c,e.beginPath(),e.moveTo(c[0].x,c[0].y);for(let p=1;p<c.length;p++)e.lineTo(c[p].x,c[p].y);e.stroke(),this.drawArrowHeads(e,c,h);}else u=this.buildPathPoints(o,a,this.collectRoutingObstacles(t.id,o[0],o[o.length-1],i,{x:t.x,y:t.y}),{fromN:this.getDockNormal(r[0],i,t.id),toN:this.getDockNormal(r[r.length-1],i,t.id)}),a==="orthogonal"?this.drawSharpPolyline(e,u):this.drawRoundedPolyline(e,u,d.DEFAULT_CORNER_RADIUS),e.stroke(),this.drawArrowHeads(e,u,h);e.setLineDash([]),n&&this.drawLinearHighlight(e,u,s);}drawLinearHighlight(e,t,i){if(!(!t||t.length<2)){e.save(),e.strokeStyle=v.lineHighlight,e.lineWidth=7/i,e.lineCap="round",e.lineJoin="round",e.setLineDash([]),e.beginPath(),e.moveTo(t[0].x,t[0].y);for(let n=1;n<t.length;n++)e.lineTo(t[n].x,t[n].y);e.stroke(),e.restore();}}drawGenerationPreview(e,t,i){let{from:n,to:s,type:r}=t;e.save(),e.beginPath(),e.arc(n.x,n.y,7/i,0,Math.PI*2),e.fillStyle=v.genDot,e.fill(),e.strokeStyle=v.genLine,e.lineWidth=2/i,e.setLineDash([5/i,4/i]),e.lineCap="round",e.beginPath(),e.moveTo(n.x,n.y),e.lineTo(s.x,s.y),e.stroke(),r&&this.drawPreviewShapeOutline(e,s,r,i),e.restore();}drawPreviewShapeOutline(e,t,i,n){let h=t.x,l=t.y;switch(e.strokeStyle=v.genLine,e.lineWidth=1.5/n,e.setLineDash([6/n,4/n]),e.beginPath(),i){case "circle":case "ellipse":e.ellipse(h,l,i==="circle"?40:120/2,i==="circle"?40:60/2,0,0,Math.PI*2);break;case "diamond":e.moveTo(h,l-30),e.lineTo(h+60,l),e.lineTo(h,l+30),e.lineTo(h-60,l),e.closePath();break;case "triangle":e.moveTo(h,l-30),e.lineTo(h+60,l+30),e.lineTo(h-60,l+30),e.closePath();break;case "hexagon":for(let u=0;u<6;u++){let c=u*Math.PI/3-Math.PI/2,p=h+60*Math.cos(c),g=l+30*Math.sin(c);u===0?e.moveTo(p,g):e.lineTo(p,g);}e.closePath();break;case "parallelogram":e.moveTo(h-60+18,l-30),e.lineTo(h+60,l-30),e.lineTo(h+60-18,l+30),e.lineTo(h-60,l+30),e.closePath();break;default:e.roundRect(h-60,l-30,120,60,i==="rounded-rectangle"?8:4);break}e.stroke();}static ALIGN_TOLERANCE=8;getAlignedPoints(e){if(e.length<2)return e;let t=e[0],i=e[e.length-1],n=i.x-t.x,s=i.y-t.y,r=d.ALIGN_TOLERANCE;if(Math.abs(s)<=r){let o=(t.y+i.y)/2;return e.map(a=>({x:a.x,y:o}))}if(Math.abs(n)<=r){let o=(t.x+i.x)/2;return e.map(a=>({x:o,y:a.y}))}return e}buildPathPoints(e,t,i=[],n={}){if(e.length<2||t==="straight")return e;switch(t){case "polyline":return this.generatePolylinePoints(e,i,n);case "orthogonal":return this.generateOrthogonalPoints(e,i,n);case "curve":return this.generateCurvePoints(e);default:return e}}drawRoundedPolyline(e,t,i){if(e.beginPath(),!(t.length<2)){if(t.length===2||i<=0){e.moveTo(t[0].x,t[0].y);for(let n=1;n<t.length;n++)e.lineTo(t[n].x,t[n].y);return}e.moveTo(t[0].x,t[0].y);for(let n=1;n<t.length-1;n++){let s=t[n-1],r=t[n],o=t[n+1],a=r.x-s.x,h=r.y-s.y,l=o.x-r.x,u=o.y-r.y,c=Math.hypot(a,h),p=Math.hypot(l,u);if(c<1e-6||p<1e-6){e.lineTo(r.x,r.y);continue}let g=Math.min(i,c*.5,p*.5),m=r.x-a/c*g,y=r.y-h/c*g,w=r.x+l/p*g,f=r.y+u/p*g;e.lineTo(m,y),e.arcTo(r.x,r.y,w,f,g);}e.lineTo(t[t.length-1].x,t[t.length-1].y);}}drawSharpPolyline(e,t){if(e.beginPath(),!(t.length<2)){e.moveTo(t[0].x,t[0].y);for(let i=1;i<t.length;i++)e.lineTo(t[i].x,t[i].y);}}drawSnapGuides(e,t,i){e.save(),e.strokeStyle=v.guide,e.lineWidth=1/i,e.setLineDash([6/i,4/i]),e.beginPath();for(let n of t)n.type==="horizontal"?(e.moveTo(n.start,n.position),e.lineTo(n.end,n.position)):(e.moveTo(n.position,n.start),e.lineTo(n.position,n.end));e.stroke(),e.restore();}generatePolylinePoints(e,t=[],i={}){if(e.length<2)return e;let n=[];n.push(e[0]);let s=e.length-1,r=d.CONNECTION_LEAD;for(let o=1;o<e.length;o++){let a=e[o-1],h=e[o],l=o===1,u=o===s,c=l&&i.fromN?{x:a.x+i.fromN.x*r,y:a.y+i.fromN.y*r}:a,p=u&&i.toN?{x:h.x+i.toN.x*r,y:h.y+i.toN.y*r}:h;l&&i.fromN&&n.push(c);let g=this.computeOrthogonalRoute(c,p,t);for(let m of g)n.push(m);u&&i.toN&&n.push(h);}return this.collapseLinePoints(n)}generateOrthogonalPoints(e,t=[],i={}){return this.generatePolylinePoints(e,t,i)}collapseLinePoints(e){let t=[];for(let i of e){let n=t.length;if(!(n>0&&Math.abs(t[n-1].x-i.x)<1e-6&&Math.abs(t[n-1].y-i.y)<1e-6)){if(n>=2){let s=t[n-2],r=t[n-1];if(Math.abs(s.y-r.y)<1e-6&&Math.abs(r.y-i.y)<1e-6||Math.abs(s.x-r.x)<1e-6&&Math.abs(r.x-i.x)<1e-6){t[n-1]=i;continue}}t.push(i);}}return t}computeOrthogonalRoute(e,t,i=[]){let n=t.x-e.x,s=t.y-e.y;if(Math.abs(n)<1||Math.abs(s)<1)return [t];let r=e.x+n/2,o=e.y+s/2,a=i.length>0,h=[[{x:r,y:e.y},{x:r,y:t.y},t],[{x:e.x,y:o},{x:t.x,y:o},t],[{x:t.x,y:e.y},t],[{x:e.x,y:t.y},t]];if(a){for(let u of h)if(!this.routeHitsObstacles(e,u,i))return u;let l=this.routeOrthogonalAvoidance(e,t,i);return l&&l.length>0?l:i.length>0&&!this.routeHitsObstacles(e,h[0],i)?h[0]:this.routeHitsObstacles(e,h[1],i)?[t]:h[1]}return Math.abs(n)>=Math.abs(s)?[{x:r,y:e.y},{x:r,y:t.y},t]:[{x:e.x,y:o},{x:t.x,y:o},t]}collectRoutingObstacles(e,t,i,n,s){if(!n||n.size===0)return [];let r=[];return n.forEach((o,a)=>{if(a===e)return;let h=this.getShapeBounds(o),l={x:o.x+h.x-s.x,y:o.y+h.y-s.y,width:h.width,height:h.height};l.pad=this.pointInRect(t,l)||this.pointInRect(i,l)?d.CONNECTED_PAD:d.ROUTE_CLEARANCE,r.push(l);}),r}pointInRect(e,t){return e.x>=t.x&&e.x<=t.x+t.width&&e.y>=t.y&&e.y<=t.y+t.height}routeHitsObstacles(e,t,i){let n=[e,...t];for(let s=1;s<n.length;s++)if(this.segmentHitsObstacle(n[s-1],n[s],i))return true;return false}segmentHitsObstacle(e,t,i){for(let n of i){let s=n.pad??d.ROUTE_CLEARANCE,r=n.y-s,o=n.y+n.height+s,a=n.x-s,h=n.x+n.width+s;if(Math.abs(e.y-t.y)<.5){if(e.y>=r&&e.y<=o){let l=Math.min(e.x,t.x);if(Math.max(e.x,t.x)>=a&&l<=h)return true}}else if(e.x>=a&&e.x<=h){let l=Math.min(e.y,t.y);if(Math.max(e.y,t.y)>=r&&l<=o)return true}}return false}routeOrthogonalAvoidance(e,t,i){let n=new Set([e.x,t.x]),s=new Set([e.y,t.y]);for(let x of i){let S=x.pad??d.ROUTE_CLEARANCE;n.add(x.x-S),n.add(x.x+x.width+S),s.add(x.y-S),s.add(x.y+x.height+S);}let r=[...n].sort((x,S)=>x-S),o=[...s].sort((x,S)=>x-S),a=r.length,h=o.length,l=x=>{for(let S=0;S<a;S++)if(Math.abs(r[S]-x)<1e-6)return S;return 0},u=x=>{for(let S=0;S<h;S++)if(Math.abs(o[S]-x)<1e-6)return S;return 0},c=l(e.x),p=u(e.y),g=l(t.x),m=u(t.y),y=[],w=[];for(let x=0;x<a;x++)y.push(new Array(h).fill(true)),w.push(new Array(h).fill(true));for(let x of i){let S=x.pad??d.ROUTE_CLEARANCE,P=x.x-S,C=x.x+x.width+S,_=x.y-S,U=x.y+x.height+S;for(let D=0;D<a-1;D++)if(!(r[D+1]<=P||r[D]>=C))for(let G=0;G<h;G++)o[G]>_&&o[G]<U&&(y[D][G]=false);for(let D=0;D<h-1;D++)if(!(o[D+1]<=_||o[D]>=U))for(let G=0;G<a;G++)r[G]>P&&r[G]<C&&(w[G][D]=false);}let f=a*h,T=1/0,M=new Float64Array(f).fill(T),b=new Int32Array(f).fill(-1),I=new Uint8Array(f),E=x=>{let S=x%a,P=x/a|0;return Math.abs(r[S]-t.x)+Math.abs(o[P]-t.y)},B=(x,S)=>x%a===S%a,O=p*a+c,K=m*a+g;M[O]=0;let A=[O],N=[E(O)],he=x=>{let S=M[x]+E(x);A.push(x),N.push(S);let P=A.length-1;for(;P>0;){let C=P-1>>1;if(N[C]<=N[P])break;[A[C],A[P]]=[A[P],A[C]],[N[C],N[P]]=[N[P],N[C]],P=C;}},Ue=()=>{let x=A[0],S=A.pop(),P=N.pop();if(A.length){A[0]=S,N[0]=P;let C=0;for(;;){let _=C*2+1,U=_+1,D=C;if(_<A.length&&N[_]<N[D]&&(D=_),U<A.length&&N[U]<N[D]&&(D=U),D===C)break;[A[D],A[C]]=[A[C],A[D]],[N[D],N[C]]=[N[C],N[D]],C=D;}}return x},le=(x,S,P)=>{let C=x%a,_=S%a,U=M[x]+(Math.abs(_-C)===0?Math.abs(o[S/a|0]-o[x/a|0]):Math.abs(r[_]-r[C]))+P;U<M[S]&&(M[S]=U,b[S]=x,I[S]||he(S));};for(;A.length;){let x=Ue();if(x===K||I[x]){if(x===K)break;continue}I[x]=1;let S=x%a,P=x/a|0,C=b[x],_=C>=0?B(C,x)?"v":"h":"",U=D=>{let G=B(x,D)?"v":"h";return _!==""&&_!==G?24:0};S+1<a&&y[S][P]&&le(x,P*a+S+1,U(P*a+S+1)),S-1>=0&&y[S-1][P]&&le(x,P*a+S-1,U(P*a+S-1)),P+1<h&&w[S][P]&&le(x,(P+1)*a+S,U((P+1)*a+S)),P-1>=0&&w[S][P-1]&&le(x,(P-1)*a+S,U((P-1)*a+S));}if(M[K]===T)return null;let be=[];for(let x=K;x!==-1;x=b[x])be.push({x:r[x%a],y:o[x/a|0]});be.reverse();let J=[];for(let x of be){let S=J.length;if(S>=2){let P=J[S-2],C=J[S-1];if(Math.abs(P.y-C.y)<1e-6&&Math.abs(C.y-x.y)<1e-6||Math.abs(P.x-C.x)<1e-6&&Math.abs(C.x-x.x)<1e-6){J[S-1]=x;continue}}J.push(x);}return J.slice(1)}generateCurvePoints(e){if(e.length<2)return e;let t=[],i=20,n=e[0],s=n;t.push(n);for(let r=1;r<e.length;r++){let o=e[r],a=this.computeCurveControlPoint(s,o);for(let h=1;h<=i;h++){let l=h/i,u=(1-l)*(1-l)*s.x+2*(1-l)*l*a.x+l*l*o.x,c=(1-l)*(1-l)*s.y+2*(1-l)*l*a.y+l*l*o.y;t.push({x:u,y:c});}s=o;}return t}computeCurveControlPoint(e,t){let i=t.x-e.x,n=t.y-e.y,s=Math.sqrt(i*i+n*n);if(s<1)return {x:e.x,y:e.y};let r=(e.x+t.x)/2,o=(e.y+t.y)/2,a=-n/s,h=i/s,l=Math.min(s*.2,30);return {x:r+a*l,y:o+h*l}}getDisplayLines(e,t,i,n,s,r){let o=n*1.3,a=Math.max(1,Math.floor(r/o)),h=`${t.id}\0${i}\0${n}\0${s}x${r}\0${a}`,l=this.textLayoutCache.get(h);if(l)return l;let u=i.split(`
|
|
2
|
+
`),c=[];for(let g of u){let m=this.wrapLine(e,g,s);for(let y of m)c.push(y);}let p=c.slice(0,a);return c.length>a&&p.length>0&&(p[p.length-1]=this.truncateLine(e,p[p.length-1],s)),this.textLayoutCache.size>=d.TEXT_CACHE_LIMIT&&this.textLayoutCache.clear(),this.textLayoutCache.set(h,p),p}drawShapeText(e,t){let i=t.text||"";if(!i)return;let n=t.fontSize||16;e.font=`${n}px sans-serif`,e.fillStyle=t.textColor||"#1f2937";let s=this.getTextBounds(t),r=n*1.3,o=this.getDisplayLines(e,t,i,n,s.width,s.height),h=-(o.length*r)/2+r/2;e.textAlign="center",e.textBaseline="middle",o.forEach((l,u)=>{let c=h+u*r;e.fillText(l,0,c);});}getTextBounds(e){switch(e.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":return {width:e.width*.85,height:e.height*.85};case "circle":return {width:e.radius*2*.85,height:e.radius*2*.85};default:return {width:100,height:40}}}wrapLine(e,t,i){if(!t)return [""];let n=[],s="";for(let r of t){let o=s+r;e.measureText(o).width>i&&s?(n.push(s),s=r):s=o;}return s&&n.push(s),n}truncateLine(e,t,i){if(!t)return "...";let n="...",s=t;for(;s.length>0&&e.measureText(s+n).width>i;)s=s.slice(0,-1);return s+n}getBindingPoint(e,t){if(t.isPrecise&&t.normalizedAnchor){let i=this.getShapePageBounds(e),n={x:i.x+i.width*t.normalizedAnchor.x,y:i.y+i.height*t.normalizedAnchor.y},s={x:e.x,y:e.y};return this.nearestPointOnShapeOutline(e,s,n)}if(t.handle){let i=this.getShapeBounds(e);switch(t.handle){case "top":return {x:e.x,y:e.y+i.y};case "bottom":return {x:e.x,y:e.y+i.y+i.height};case "left":return {x:e.x+i.x,y:e.y};case "right":return {x:e.x+i.x+i.width,y:e.y}}}return {x:e.x,y:e.y}}getDockNormal(e,t,i){if(!t||t.size===0)return;let n=null,s=1/0,r=.5;if(t.forEach((l,u)=>{if(u===i)return;let c=this.getShapePageBounds(l);if(e.x>=c.x-r&&e.x<=c.x+c.width+r&&e.y>=c.y-r&&e.y<=c.y+c.height+r){let p=(e.x-l.x)**2+(e.y-l.y)**2;p<s&&(s=p,n=l);}}),!n)return;let o=n,a=e.x-o.x,h=e.y-o.y;return Math.abs(h)>Math.abs(a)?{x:0,y:h<0?-1:1}:{x:a<0?-1:1,y:0}}getShapePageBounds(e){let t=this.getShapeBounds(e);return {x:e.x+t.x,y:e.y+t.y,width:t.width,height:t.height}}clampToShapeOutline(e,t,i,n){if(!t||t.size===0)return e;let s=null,r=1/0;if(t.forEach((a,h)=>{if(h===i)return;let l=this.getShapePageBounds(a);if(e.x>l.x&&e.x<l.x+l.width&&e.y>l.y&&e.y<l.y+l.height){let u=(a.x-n.x)**2+(a.y-n.y)**2;u<r&&(r=u,s=a);}}),!s)return e;let o=s;return this.nearestPointOnShapeOutline(o,{x:o.x,y:o.y},e)}nearestPointOnShapeOutline(e,t,i){let n=i.x-t.x,s=i.y-t.y,r=Math.hypot(n,s);if(r<1e-6)return {x:t.x,y:t.y};let o=n/r,a=s/r,h=Math.max(1e4,r*2),l={x:t.x+o*h,y:t.y+a*h},u=this.intersectShapeOutlineWithSegment(e,t,l);if(u.length===0)return i;let c=u[0],p=(c.x-t.x)**2+(c.y-t.y)**2;for(let g=1;g<u.length;g++){let m=(u[g].x-t.x)**2+(u[g].y-t.y)**2;m<p&&(p=m,c=u[g]);}return c}intersectShapeOutlineWithSegment(e,t,i){let n={x:t.x-e.x,y:t.y-e.y},s={x:i.x-e.x,y:i.y-e.y};return this.intersectLocalShapeOutlineWithSegment(e,n,s).map(o=>({x:o.x+e.x,y:o.y+e.y}))}intersectLocalShapeOutlineWithSegment(e,t,i){switch(e.type){case "rectangle":case "rounded-rectangle":{let n=e.width,s=e.height,r={x:-n/2,y:-s/2,width:n,height:s};return this.intersectSegmentRect(t,i,r)}case "ellipse":case "diamond":case "triangle":{let n=e.width,s=e.height,r={x:-n/2,y:-s/2,width:n,height:s};return this.intersectSegmentRect(t,i,r)}case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":{let n=e.width,s=e.height,r={x:-n/2,y:-s/2,width:n,height:s};return this.intersectSegmentRect(t,i,r)}case "circle":{let n=e.radius;return this.intersectSegmentCircle(t,i,{x:0,y:0},n)}default:return []}}intersectSegmentRect(e,t,i){let n=i.x,s=i.y,r=i.width,o=i.height,a=[[{x:n,y:s},{x:n+r,y:s}],[{x:n+r,y:s},{x:n+r,y:s+o}],[{x:n+r,y:s+o},{x:n,y:s+o}],[{x:n,y:s+o},{x:n,y:s}]],h=[];for(let[l,u]of a){let c=this.segmentIntersection(e,t,l,u);c&&h.push(c);}return h}segmentIntersection(e,t,i,n){let s=e.x,r=e.y,o=t.x,a=t.y,h=i.x,l=i.y,u=n.x,c=n.y,p=(s-o)*(l-c)-(r-a)*(h-u);if(Math.abs(p)<1e-9)return null;let g=((s-h)*(l-c)-(r-l)*(h-u))/p,m=-((s-o)*(r-l)-(r-a)*(s-h))/p;return g<0||g>1||m<0||m>1?null:{x:s+g*(o-s),y:r+g*(a-r)}}intersectSegmentCircle(e,t,i,n){let s=t.x-e.x,r=t.y-e.y,o=e.x-i.x,a=e.y-i.y,h=s*s+r*r,l=2*(o*s+a*r),u=o*o+a*a-n*n,c=l*l-4*h*u;if(c<0)return [];c=Math.sqrt(c);let p=(-l-c)/(2*h),g=(-l+c)/(2*h),m=[];return p>=0&&p<=1&&m.push({x:e.x+p*s,y:e.y+p*r}),g>=0&&g<=1&&Math.abs(g-p)>1e-6&&m.push({x:e.x+g*s,y:e.y+g*r}),m}drawArrowHead(e,t,i){let n=Math.atan2(i.y-t.y,i.x-t.x),s=12;e.beginPath(),e.moveTo(i.x,i.y),e.lineTo(i.x-s*Math.cos(n-Math.PI/6),i.y-s*Math.sin(n-Math.PI/6)),e.moveTo(i.x,i.y),e.lineTo(i.x-s*Math.cos(n+Math.PI/6),i.y-s*Math.sin(n+Math.PI/6)),e.stroke();}drawInheritanceHead(e,t,i){let n=Math.atan2(i.y-t.y,i.x-t.x),s=14,r=i.x,o=i.y,a=i.x-s*Math.cos(n),h=i.y-s*Math.sin(n),l=a+s*.5*Math.cos(n-Math.PI/2),u=h+s*.5*Math.sin(n-Math.PI/2),c=a+s*.5*Math.cos(n+Math.PI/2),p=h+s*.5*Math.sin(n+Math.PI/2);e.save(),e.fillStyle="#ffffff",e.beginPath(),e.moveTo(r,o),e.lineTo(l,u),e.lineTo(c,p),e.closePath(),e.fill(),e.stroke(),e.restore();}drawDiamondHead(e,t,i,n){let s=Math.atan2(i.y-t.y,i.x-t.x),r=14,o=i.x,a=i.y,h=i.x-r*.5*Math.cos(s),l=i.y-r*.5*Math.sin(s),u=i.x-r*Math.cos(s),c=i.y-r*Math.sin(s),p=h+r*.4*Math.cos(s-Math.PI/2),g=l+r*.4*Math.sin(s-Math.PI/2),m=h+r*.4*Math.cos(s+Math.PI/2),y=l+r*.4*Math.sin(s+Math.PI/2);e.save(),e.fillStyle=n?"#1f2937":"#ffffff",e.beginPath(),e.moveTo(o,a),e.lineTo(p,g),e.lineTo(u,c),e.lineTo(m,y),e.closePath(),e.fill(),e.stroke(),e.restore();}drawArrowHeads(e,t,i){if(i!=="none"){if(i==="start"||i==="both"){let n=t[0],s=t[1];this.drawArrowHead(e,s,n);}if(i==="end"||i==="both"){let n=t.length,s=t[n-2],r=t[n-1];this.drawArrowHead(e,s,r);}if(i==="inheritance"){let n=t.length,s=t[n-2],r=t[n-1];this.drawInheritanceHead(e,s,r);}if(i==="aggregation"){let n=t[0],s=t[1];this.drawDiamondHead(e,s,n,false);}if(i==="composition"){let n=t[0],s=t[1];this.drawDiamondHead(e,s,n,true);}}}drawText(e,t){if(!t.text)return;let i=t.fontSize;e.font=`${i}px sans-serif`,e.textAlign="center",e.textBaseline="middle";let n=t.width,s=t.height,r=i*1.3,o=this.getDisplayLines(e,t,t.text,i,n,s),a=o.length*r,h=-a/2+r/2;if(t.highlightColor&&t.highlightColor!=="transparent"){e.fillStyle=t.highlightColor;let l=i*.15;e.beginPath(),e.roundRect(-n/2-l,-a/2-l,n+l*2,a+l*2,4),e.fill();}e.fillStyle=t.textColor||"#1f2937",o.forEach((l,u)=>{let c=h+u*r;e.fillText(l,0,c);});}drawFreehand(e,t){if(t.points.length<2)return;let i=t.points.map(n=>({x:n.x-t.x,y:n.y-t.y}));e.beginPath(),e.moveTo(i[0].x,i[0].y);for(let n=1;n<i.length-1;n++){let s=(i[n].x+i[n+1].x)/2,r=(i[n].y+i[n+1].y)/2;e.quadraticCurveTo(i[n].x,i[n].y,s,r);}e.lineTo(i[i.length-1].x,i[i.length-1].y),e.stroke();}drawSelectionOutline(e,t,i){let n=this.getShapeBounds(t);e.strokeStyle=v.selection.outline,e.lineWidth=1/i,e.setLineDash([]),e.save(),e.shadowColor=v.selection.shadow,e.shadowBlur=8,e.shadowOffsetX=0,e.shadowOffsetY=0,e.beginPath(),e.roundRect(n.x-2,n.y-2,n.width+4,n.height+4,4),e.stroke(),e.restore(),e.fillStyle=v.selection.outlineFill,e.beginPath(),e.roundRect(n.x-2,n.y-2,n.width+4,n.height+4,4),e.fill();}drawSelectionHandles(e,t,i){let n=8/i;if((t.type==="line"||t.type==="arrow"||t.type==="draw")&&t.points&&t.points.length>=2){let r=t.points.map(u=>({x:u.x-t.x,y:u.y-t.y})),o=r[0],a=r[r.length-1];e.fillStyle=v.selection.handleFill,e.strokeStyle=v.selection.handleStroke,e.lineWidth=2/i,e.setLineDash([]),[o,a].forEach(u=>{e.beginPath(),e.arc(u.x,u.y,n/2,0,Math.PI*2),e.fill(),e.stroke();});let h=(o.x+a.x)/2,l=(o.y+a.y)/2;e.beginPath(),e.arc(h,l,7/i,0,Math.PI*2),e.fillStyle=v.selection.handleFill,e.fill(),e.strokeStyle=v.primary,e.lineWidth=1.5/i,e.stroke(),e.beginPath(),e.arc(h,l,3/i,0,Math.PI*2),e.fillStyle=v.genDot,e.fill();}else {let r=this.getShapeBounds(t),o=n,a=[{x:r.x,y:r.y},{x:r.x+r.width,y:r.y},{x:r.x+r.width,y:r.y+r.height},{x:r.x,y:r.y+r.height}];e.fillStyle=v.selection.handleFill,e.strokeStyle=v.selection.handleStroke,e.lineWidth=2/i,e.setLineDash([]),a.forEach(g=>{e.beginPath(),e.roundRect(g.x-o/2,g.y-o/2,o,o,2),e.fill(),e.stroke();});let h=9/i;[{x:r.x+r.width/2,y:r.y},{x:r.x+r.width,y:r.y+r.height/2},{x:r.x+r.width/2,y:r.y+r.height},{x:r.x,y:r.y+r.height/2}].forEach(g=>{e.beginPath(),e.arc(g.x,g.y,h,0,Math.PI*2),e.fillStyle=v.selection.handleFill,e.fill(),e.strokeStyle=v.primary,e.lineWidth=1.5/i,e.stroke(),e.beginPath(),e.arc(g.x,g.y,h*.45,0,Math.PI*2),e.fillStyle=v.primary,e.fill();});let u=26/i,c=r.x+r.width/2,p=r.y-u;e.strokeStyle="#94a3b8",e.lineWidth=1.5/i,e.setLineDash([]),e.beginPath(),e.moveTo(c,r.y),e.lineTo(c,p),e.stroke(),e.beginPath(),e.arc(c,p,8/i,0,Math.PI*2),e.fillStyle=v.selection.handleFill,e.fill(),e.strokeStyle=v.primary,e.lineWidth=1.6/i,e.stroke(),this.drawRotateIcon(e,c,p,i);}}drawRotateIcon(e,t,i,n){let s=8/n;e.save(),e.translate(t,i),e.strokeStyle=v.primary,e.lineWidth=1.8/n,e.lineCap="round",e.beginPath(),e.arc(0,0,s*.5,Math.PI*.18,Math.PI*1.6,false),e.stroke();let r=Math.PI*.18,o=Math.cos(r)*s*.5,a=Math.sin(r)*s*.5,h=1;e.beginPath(),e.moveTo(o,a),e.lineTo(o-Math.cos(r)*s*.26+h*Math.sin(r)*s*.16,a-Math.sin(r)*s*.26-h*Math.cos(r)*s*.16),e.moveTo(o,a),e.lineTo(o-Math.cos(r)*s*.26-h*Math.sin(r)*s*.16,a-Math.sin(r)*s*.26+h*Math.cos(r)*s*.16),e.stroke(),e.restore();}getShapeBounds(e){switch(e.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":case "mind-map":return {x:-e.width/2,y:-e.height/2,width:e.width,height:e.height};case "circle":return {x:-e.radius,y:-e.radius,width:e.radius*2,height:e.radius*2};case "line":case "arrow":case "draw":if(e.points.length===0)return {x:0,y:0,width:0,height:0};let t=1/0,i=1/0,n=-1/0,s=-1/0;return e.points.forEach(r=>{t=Math.min(t,r.x-e.x),i=Math.min(i,r.y-e.y),n=Math.max(n,r.x-e.x),s=Math.max(s,r.y-e.y);}),{x:t,y:i,width:n-t,height:s-i};case "text":{let r=e;return {x:-r.width/2,y:-r.height/2,width:r.width,height:r.height}}default:return {x:0,y:0,width:0,height:0}}}};var j={create(d=0,e=0){return {x:d,y:e}},add(d,e){return {x:d.x+e.x,y:d.y+e.y}},subtract(d,e){return {x:d.x-e.x,y:d.y-e.y}},multiply(d,e){return {x:d.x*e,y:d.y*e}},divide(d,e){return {x:d.x/e,y:d.y/e}},dot(d,e){return d.x*e.x+d.y*e.y},length(d){return Math.sqrt(d.x*d.x+d.y*d.y)},normalize(d){let e=j.length(d);return e===0?{x:0,y:0}:{x:d.x/e,y:d.y/e}},distance(d,e){return j.length(j.subtract(d,e))},rotate(d,e){let t=Math.cos(e),i=Math.sin(e);return {x:d.x*t-d.y*i,y:d.x*i+d.y*t}},clone(d){return {x:d.x,y:d.y}},equals(d,e){return d.x===e.x&&d.y===e.y}};function Z(d,e,t,i=8){let n=[];if(t==="horizontal"){let s=Math.min(d.x,e.x),r=Math.max(d.x+d.width,e.x+e.width),o=Math.abs(d.y-e.y)<=i,a=Math.abs(d.y+d.height-(e.y+e.height))<=i,h=Math.abs(d.y+d.height/2-(e.y+e.height/2))<=i;o&&n.push({type:"horizontal",position:(d.y+e.y)/2,start:s,end:r}),a&&n.push({type:"horizontal",position:(d.y+d.height+e.y+e.height)/2,start:s,end:r}),h&&!(o&&a)&&n.push({type:"horizontal",position:(d.y+d.height/2+e.y+e.height/2)/2,start:s,end:r});}else {let s=Math.min(d.y,e.y),r=Math.max(d.y+d.height,e.y+e.height),o=Math.abs(d.x-e.x)<=i,a=Math.abs(d.x+d.width-(e.x+e.width))<=i,h=Math.abs(d.x+d.width/2-(e.x+e.width/2))<=i;o&&n.push({type:"vertical",position:(d.x+e.x)/2,start:s,end:r}),a&&n.push({type:"vertical",position:(d.x+d.width+e.x+e.width)/2,start:s,end:r}),h&&!(o&&a)&&n.push({type:"vertical",position:(d.x+d.width/2+e.x+e.width/2)/2,start:s,end:r});}return n}var se=class d extends H{type="select";state="idle";translatingState=null;resizingState=null;generatingState=null;hoverGenPoint=null;rotatingState=null;draggingArrowId=null;draggingTerminal=null;pendingHistoryCommit=false;brushStart={x:0,y:0};brushShiftKey=false;defaultGenType(e){if(e){let t=this.context.getShapes().find(i=>i.id===e);if(t&&fe(t.type))return t.type}return "rectangle"}genPreviewOf(e,t){return {from:e.point,to:t,type:this.defaultGenType(e.sourceShapeId)}}genContext(e,t){return {from:e.point,to:t,sourceShapeId:e.sourceShapeId,edge:e.edge}}onPointerDown(e,t){let i=this.context.getShapes(),n=this.context.getSelectedIds(),s=this.hitTestArrowTerminal(e,i);if(s&&n.includes(s.shapeId)){this.state="dragging-terminal",this.draggingArrowId=s.shapeId,this.draggingTerminal=s.terminal,this.pendingHistoryCommit=true,this.context.updateArrowBinding(s.shapeId,s.terminal,null);return}let r=this.hitGenPoint(e,i,n);if(r){this.state="generating",this.generatingState={source:r,startPoint:e,hasMoved:false},this.pendingHistoryCommit=true,this.context.setGenerationPreview(this.genPreviewOf(r,this.genPreviewTarget(r,e,false)));return}let o=this.hitTest(e,i,n);if(o.handle==="rotation"){this.state="rotating",this.pendingHistoryCommit=true;let a=o.shape;this.rotatingState={shapeId:a.id,center:{x:a.x,y:a.y},startAngle:Math.atan2(e.y-a.y,e.x-a.x),startRotation:a.rotation};return}if(o.handle&&o.shape&&o.shape.type!=="mind-map"){this.state="resizing",this.resizingState={startPoint:e,startShape:o.shape,handle:o.handle},this.pendingHistoryCommit=true;return}if(o.shape){let a=o.shape,h=a.type==="line"||a.type==="arrow"||a.type==="draw",l=n.includes(a.id);if(h&&!l){this.context.selectShape(a.id,t.shiftKey);return}this.state="translating",this.pendingHistoryCommit=true,l||this.context.selectShape(a.id,t.shiftKey);let u=this.context.getSelectedIds(),c=new Map,p=new Map,g=new Map;u.forEach(m=>{let y=i.find(w=>w.id===m);y&&(c.set(m,{x:y.x,y:y.y}),p.set(m,y.rotation),g.set(m,this.getShapeWorldBounds(y)));}),this.translatingState={startPoint:e,startPositions:c,startRotation:p,startBounds:g};}else this.state="brushing",this.brushStart=e,this.brushShiftKey=t.shiftKey,t.shiftKey||this.context.selectShape("",false);}onPointerMove(e,t){let i=this.context.getShapes();if(this.state==="translating"&&this.translatingState)this.pendingHistoryCommit&&(this.context.commitHistory(),this.pendingHistoryCommit=false),this.handleTranslating(e,t);else if(this.state==="generating"&&this.generatingState)this.pendingHistoryCommit&&(this.context.commitHistory(),this.pendingHistoryCommit=false),this.handleGenerating(e,i);else if(this.state==="rotating"&&this.rotatingState)this.pendingHistoryCommit&&(this.context.commitHistory(),this.pendingHistoryCommit=false),this.handleRotating(e,t);else if(this.state==="resizing"&&this.resizingState)this.pendingHistoryCommit&&(this.context.commitHistory(),this.pendingHistoryCommit=false),this.handleResizing(e);else if(this.state==="dragging-terminal"&&this.draggingArrowId&&this.draggingTerminal){this.pendingHistoryCommit&&(this.context.commitHistory(),this.pendingHistoryCommit=false);let n=i.find(s=>s.id===this.draggingArrowId);if(n){let s=this.draggingTerminal==="start"?e:n.points[n.points.length-1],r=this.draggingTerminal==="start"?n.points[0]:e,o=this.computeSnapGuidesForArrow(s,r,e,n,i);this.context.setSnapGuides(o);let a=e;if(o.length>0){let u=o.filter(p=>p.type==="horizontal"),c=o.filter(p=>p.type==="vertical");if(u.length>0){let p=u[0].position,g=Math.abs(e.y-p);for(let m of u){let y=Math.abs(e.y-m.position);y<g&&(g=y,p=m.position);}a={...a,y:p};}else if(c.length>0){let p=c[0].position,g=Math.abs(e.x-p);for(let m of c){let y=Math.abs(e.x-m.position);y<g&&(g=y,p=m.position);}a={...a,x:p};}}let h=this.draggingTerminal==="start"?0:n.points.length-1,l=[...n.points];l[h]=a,this.context.updateShape(this.draggingArrowId,{points:l});}}else if(this.state==="brushing")this.handleBrushing(e);else {let n=this.context.getSelectedIds(),s=this.hitGenPoint(e,i,n);s?(this.hoverGenPoint=s,this.context.setGenerationPreview(this.genPreviewOf(s,this.genPreviewTarget(s,e,false)))):this.hoverGenPoint&&(this.hoverGenPoint=null,this.context.setGenerationPreview(null));}}onPointerUp(e,t){if(this.state==="dragging-terminal"&&this.draggingArrowId&&this.draggingTerminal){let i=this.context.getShapes(),n=this.findBindingNearPoint(e,i,this.draggingArrowId);n&&this.context.updateArrowBinding(this.draggingArrowId,this.draggingTerminal,n.toShapeId,n.binding);}if(this.state==="generating"&&this.generatingState){let i=this.generatingState,n=this.context.getShapes(),s=i.source,r=this.findBindingNearPoint(e,n,s.sourceShapeId);if(r)this.context.connectToExisting(this.genContext(s,e),r.toShapeId,r.binding);else if(!i.hasMoved)this.context.createGeneratedConnection(this.genContext(s,this.genPreviewTarget(s,s.point,false)),{type:this.defaultGenType(s.sourceShapeId)});else {let o=this.context.createFloatingLine(this.genContext(s,e));this.context.openGenerationMenu({context:this.genContext(s,e),existingArrowId:o,defaultShapeType:this.defaultGenType(s.sourceShapeId)});}this.generatingState=null,this.context.setGenerationPreview(null);}this.state==="brushing"&&this.context.setBrushRect(null),this.context.setConnectingTarget(null),this.hoverGenPoint=null,this.pendingHistoryCommit=false,this.state="idle",this.draggingArrowId=null,this.draggingTerminal=null,this.translatingState=null,this.resizingState=null,this.rotatingState=null,this.context.setSnapGuides([]);}onKeyDown(e){if(e.key==="Delete"||e.key==="Backspace"){let t=this.context.getSelectedIds();t.length>0&&(this.context.commitHistory(),t.forEach(i=>{this.context.deleteShape(i);}));}e.key==="Escape"&&(this.context.selectShape("",false),this.context.setSnapGuides([]),this.state="idle"),(e.key==="+"||e.key==="=")&&e.shiftKey&&(this.context.commitHistory(),this.handleRotation(15)),e.key==="-"&&e.shiftKey&&(this.context.commitHistory(),this.handleRotation(-15)),e.key==="ArrowUp"&&(e.preventDefault(),this.context.commitHistory(),this.handleNudge(0,-5)),e.key==="ArrowDown"&&(e.preventDefault(),this.context.commitHistory(),this.handleNudge(0,5)),e.key==="ArrowLeft"&&(e.preventDefault(),this.context.commitHistory(),this.handleNudge(-5,0)),e.key==="ArrowRight"&&(e.preventDefault(),this.context.commitHistory(),this.handleNudge(5,0));}onKeyUp(e){}getCursor(e){switch(this.state){case "translating":return "grabbing";case "generating":return "crosshair";case "rotating":return "grabbing";case "resizing":return this.resizingState?this.getHandleCursor(this.resizingState.handle,this.resizingState.startShape):"default";case "dragging-terminal":return "crosshair";case "brushing":return "crosshair"}let t=this.context.getShapes(),i=this.context.getSelectedIds();if(this.context.getMindMapCursorHitAtPoint(e))return "pointer";if(this.hitGenPoint(e,t,i))return "crosshair";if(this.hitTestArrowTerminal(e,t)&&i.includes(this.hitTestArrowTerminal(e,t).shapeId))return "move";let n=this.hitTest(e,t,i);return n.handle==="rotation"?"grab":n.handle?this.getHandleCursor(n.handle,n.shape):n.shape?"move":null}getHandleCursor(e,t){let n={e:0,se:45,s:90,sw:135,w:180,nw:225,n:270,ne:315}[e];if(n===void 0)return "grab";let s=((n+t.rotation*180/Math.PI)%360+360)%360,r=Math.round(s/45)%4;return ["ew-resize","nwse-resize","ns-resize","nesw-resize"][r]}static ALIGN_SNAP_THRESHOLD=8;handleTranslating(e,t){if(!this.translatingState)return;let i=j.subtract(e,this.translatingState.startPoint),n={...i};t.shiftKey&&(Math.abs(i.x)>Math.abs(i.y)?n.y=0:n.x=0);let s=this.context.getShapes(),r=this.context.getSelectedIds(),o=new Set(r),a=[],h=[];if(this.translatingState.startBounds.forEach(l=>{h.push({x:l.x+n.x,y:l.y+n.y,width:l.width,height:l.height});}),!t.shiftKey&&h.length>0){let l=[];for(let p of s)o.has(p.id)||p.type==="line"||p.type==="arrow"||p.type==="draw"||l.push(this.getShapeWorldBounds(p));let u=[],c=[];for(let p of h){let g=[p.y,p.y+p.height/2,p.y+p.height],m=[p.x,p.x+p.width/2,p.x+p.width];for(let y of l){let w=[y.y,y.y+y.height/2,y.y+y.height];for(let T of g)for(let M of w){let b=M-T;Math.abs(b)<=d.ALIGN_SNAP_THRESHOLD&&u.push(b);}let f=[y.x,y.x+y.width/2,y.x+y.width];for(let T of m)for(let M of f){let b=M-T;Math.abs(b)<=d.ALIGN_SNAP_THRESHOLD&&c.push(b);}}}if(u.length>0){let p=u[0];for(let g of u)Math.abs(g)<Math.abs(p)&&(p=g);n.y+=p;}if(c.length>0){let p=c[0];for(let g of c)Math.abs(g)<Math.abs(p)&&(p=g);n.x+=p;}this.translatingState.startBounds.forEach(p=>{let g={x:p.x+n.x,y:p.y+n.y,width:p.width,height:p.height};for(let m of l)a.push(...Z(g,m,"horizontal",1)),a.push(...Z(g,m,"vertical",1));});}this.translatingState.startPositions.forEach((l,u)=>{this.context.updateShape(u,{x:l.x+n.x,y:l.y+n.y});}),this.context.setSnapGuides(this.mergeGuides(a));}handleResizing(e){if(!this.resizingState)return;let t=this.resizingState.startShape,i=this.resizingState.handle,n=this.resizingState.startPoint;if(!i||i==="rotation")return;let r={nw:[-1,-1],n:[0,-1],ne:[1,-1],w:[-1,0],e:[1,0],sw:[-1,1],s:[0,1],se:[1,1]}[i];if(!r)return;let[o,a]=r,h=j.subtract(e,n),l=[];for(let b of this.context.getShapes())b.id!==t.id&&(b.type==="line"||b.type==="arrow"||b.type==="draw"||l.push(this.getShapeWorldBounds(b)));let u=20,c=this.getShapeWorldBounds(t),p=c.x,g=c.y,m=c.x+c.width,y=c.y+c.height;o===1?m=Math.max(p+u,m+h.x):o===-1&&(p=Math.min(m-u,p+h.x)),a===1?y=Math.max(g+u,y+h.y):a===-1&&(g=Math.min(y-u,g+h.y));let w=(b,I)=>{let E=null;for(let B of I){let O=B-b;Math.abs(O)<=d.ALIGN_SNAP_THRESHOLD&&(E===null||Math.abs(O)<Math.abs(E))&&(E=O);}return E};if(o!==0&&l.length>0){let b=[];for(let E of l)b.push(E.x,E.x+E.width/2,E.x+E.width);let I=w(o===1?m:p,b);I!==null&&(o===1?m+=I:p+=I);}if(a!==0&&l.length>0){let b=[];for(let E of l)b.push(E.y,E.y+E.height/2,E.y+E.height);let I=w(a===1?y:g,b);I!==null&&(a===1?y+=I:g+=I);}let f={x:p,y:g,width:m-p,height:y-g},T=[];for(let b of l)o!==0&&T.push(...Z(f,b,"vertical",1)),a!==0&&T.push(...Z(f,b,"horizontal",1));this.context.setSnapGuides(this.mergeGuides(T));let M={};if(t.type==="circle"){let b=Math.max(10,Math.max(o!==0?f.width/2:0,a!==0?f.height/2:0));if(M.radius=b,o!==0){let I=o===1?c.x:c.x+c.width;M.x=o===1?I+b:I-b;}if(a!==0){let I=a===1?c.y:c.y+c.height;M.y=a===1?I+b:I-b;}}else "width"in t&&o!==0&&(M.width=f.width,M.x=f.x+f.width/2),"height"in t&&a!==0&&(M.height=f.height,M.y=f.y+f.height/2);Object.keys(M).length>0&&this.context.updateShape(t.id,M);}mergeGuides(e){let t=new Map;for(let i of e){let n=`${i.type}\0${Math.round(i.position*2)/2}`,s=t.get(n);s?(s.start=Math.min(s.start,i.start),s.end=Math.max(s.end,i.end)):t.set(n,{...i});}return [...t.values()]}handleRotation(e){let t=this.context.getSelectedIds(),i=this.context.getShapes();t.forEach(n=>{let s=i.find(r=>r.id===n);s&&this.context.updateShape(n,{rotation:s.rotation+e*Math.PI/180});});}handleNudge(e,t){let i=this.context.getSelectedIds(),n=this.context.getShapes();i.forEach(s=>{let r=n.find(o=>o.id===s);r&&this.context.updateShape(s,{x:r.x+e,y:r.y+t});});}handleBrushing(e){let t=Math.min(this.brushStart.x,e.x),i=Math.min(this.brushStart.y,e.y),n=Math.abs(e.x-this.brushStart.x),s=Math.abs(e.y-this.brushStart.y);this.context.setBrushRect({x:t,y:i,width:n,height:s});let r=this.context.getShapes(),o=[];for(let a of r){let h=this.getShapeWorldBounds(a);this.rectsIntersect({x:t,y:i,width:n,height:s},h)&&o.push(a.id);}if(this.brushShiftKey){let a=this.context.getSelectedIds(),h=new Set([...a,...o]);this.context.selectShapes([...h]);}else this.context.selectShapes(o);}getShapeWorldBounds(e){switch(e.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":case "mind-map":return {x:e.x-e.width/2,y:e.y-e.height/2,width:e.width,height:e.height};case "circle":return {x:e.x-e.radius,y:e.y-e.radius,width:e.radius*2,height:e.radius*2};case "line":case "arrow":case "draw":{if(!e.points||e.points.length===0)return {x:e.x,y:e.y,width:0,height:0};let t=1/0,i=1/0,n=-1/0,s=-1/0;return e.points.forEach(r=>{t=Math.min(t,r.x),i=Math.min(i,r.y),n=Math.max(n,r.x),s=Math.max(s,r.y);}),{x:t,y:i,width:n-t,height:s-i}}case "text":{let t=e;return {x:e.x-t.width/2,y:e.y-t.height/2,width:t.width,height:t.height}}default:{let t=e;return {x:t.x,y:t.y,width:0,height:0}}}}rectsIntersect(e,t){return e.x<t.x+t.width&&e.x+e.width>t.x&&e.y<t.y+t.height&&e.y+e.height>t.y}hitTest(e,t,i){for(let n=t.length-1;n>=0;n--){let s=t[n];if(i.includes(s.id)){let r=this.getHitHandle(e,s);if(r)return {shape:s,handle:r}}if(this.isPointInShape(e,s))return {shape:s,handle:null}}return {shape:null,handle:null}}getHitHandle(e,t){if(t.type==="mind-map")return null;let i=14,n=this.getShapeBounds(t),s=Math.cos(-t.rotation),r=Math.sin(-t.rotation),o=e.x-t.x,a=e.y-t.y,h=o*s-a*r,l=o*r+a*s,u=[{type:"nw",x:n.x,y:n.y},{type:"ne",x:n.x+n.width,y:n.y},{type:"se",x:n.x+n.width,y:n.y+n.height},{type:"sw",x:n.x,y:n.y+n.height},{type:"rotation",x:n.x+n.width/2,y:n.y-26}];for(let c of u)if(Math.abs(h-c.x)<i&&Math.abs(l-c.y)<i)return c.type;return null}static GEN_HIT_THRESHOLD=14;static CLICK_MOVE_THRESHOLD=6;computeGenPoints(e,t){let i=[];for(let n of t){let s=e.find(r=>r.id===n);if(s){if(s.type==="line"||s.type==="arrow"||s.type==="draw"){if(s.points&&s.points.length>=2){let r=this.getShapeWorldBounds(s);i.push({point:{x:r.x+r.width/2,y:r.y+r.height/2},sourceShapeId:s.id});}}else if(s.type==="rectangle"||s.type==="rounded-rectangle"||s.type==="ellipse"||s.type==="diamond"||s.type==="triangle"||s.type==="hexagon"||s.type==="parallelogram"||s.type==="trapezoid"||s.type==="pentagon"||s.type==="octagon"||s.type==="star"||s.type==="uml-class"||s.type==="uml-interface"||s.type==="circle"){let r=this.getShapeBounds(s),o={x:s.x,y:s.y};i.push({point:{x:o.x+r.x+r.width/2,y:o.y+r.y},edge:"n",sourceShapeId:s.id}),i.push({point:{x:o.x+r.x+r.width,y:o.y+r.y+r.height/2},edge:"e",sourceShapeId:s.id}),i.push({point:{x:o.x+r.x+r.width/2,y:o.y+r.y+r.height},edge:"s",sourceShapeId:s.id}),i.push({point:{x:o.x+r.x,y:o.y+r.y+r.height/2},edge:"w",sourceShapeId:s.id});}}}return i}hitGenPoint(e,t,i){let n=d.GEN_HIT_THRESHOLD,s=null,r=n;for(let o of this.computeGenPoints(t,i)){let a=Math.hypot(o.point.x-e.x,o.point.y-e.y);a<=r&&(r=a,s=o);}return s}genPreviewTarget(e,t,i){if(i)return t;let n=96;if(e.edge)switch(e.edge){case "n":return {x:e.point.x,y:e.point.y-n};case "s":return {x:e.point.x,y:e.point.y+n};case "e":return {x:e.point.x+n,y:e.point.y};case "w":return {x:e.point.x-n,y:e.point.y}}return {x:e.point.x,y:e.point.y-n}}handleGenerating(e,t){if(!this.generatingState)return;let i=this.generatingState,n=i.source;Math.hypot(e.x-i.startPoint.x,e.y-i.startPoint.y)>d.CLICK_MOVE_THRESHOLD&&(i.hasMoved=true);let r=this.findBindingNearPoint(e,t,n.sourceShapeId),o=r?this.bindingPosition(r.toShapeId,r.binding,t):i.hasMoved?e:this.genPreviewTarget(n,e,false);this.context.setConnectingTarget(r?r.toShapeId:null),this.context.setGenerationPreview({from:n.point,to:o,type:r?void 0:this.defaultGenType(n.sourceShapeId)});}handleRotating(e,t){if(!this.rotatingState)return;let i=this.rotatingState,n=Math.atan2(e.y-i.center.y,e.x-i.center.x),s=i.startRotation+(n-i.startAngle);t.shiftKey&&(s=Math.round(s/(Math.PI/12))*(Math.PI/12)),this.context.updateShape(i.shapeId,{rotation:s});}bindingPosition(e,t,i){let n=i.find(r=>r.id===e);if(!n)return {x:0,y:0};let s=this.getShapeWorldBounds(n);if(t.handle)switch(t.handle){case "top":return {x:n.x,y:s.y};case "bottom":return {x:n.x,y:s.y+s.height};case "left":return {x:s.x,y:n.y};case "right":return {x:s.x+s.width,y:n.y}}return t.normalizedAnchor?{x:s.x+s.width*t.normalizedAnchor.x,y:s.y+s.height*t.normalizedAnchor.y}:{x:n.x,y:n.y}}isPointInShape(e,t){let i=e.x-t.x,n=e.y-t.y;switch(t.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":case "mind-map":return Math.abs(i)<=t.width/2&&Math.abs(n)<=t.height/2;case "circle":return i*i+n*n<=t.radius*t.radius;case "hexagon":return this.isPointInHexagon(i,n,t.width,t.height);case "line":case "arrow":case "draw":for(let s=0;s<t.points.length-1;s++){let r=t.points[s],o=t.points[s+1];if(this.pointToLineDistance(e,r,o)<10)return true}return false;case "text":return Math.abs(i)<=50&&Math.abs(n)<=t.fontSize/2;default:return false}}isPointInHexagon(e,t,i,n){let s=Math.abs(e),r=Math.abs(t),o=i/2,a=n/2;return s<=o&&r<=a&&s/o+r/a<=1.5}pointToLineDistance(e,t,i){let n=e.x-t.x,s=e.y-t.y,r=i.x-t.x,o=i.y-t.y,a=n*r+s*o,h=r*r+o*o,l=-1;h!==0&&(l=a/h);let u,c;l<0?(u=t.x,c=t.y):l>1?(u=i.x,c=i.y):(u=t.x+l*r,c=t.y+l*o);let p=e.x-u,g=e.y-c;return Math.sqrt(p*p+g*g)}getShapeBounds(e){switch(e.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":case "mind-map":return {x:-e.width/2,y:-e.height/2,width:e.width,height:e.height};case "circle":return {x:-e.radius,y:-e.radius,width:e.radius*2,height:e.radius*2};case "hexagon":return {x:-e.width/2,y:-e.height/2,width:e.width,height:e.height};case "line":case "arrow":case "draw":if(e.points.length===0)return {x:0,y:0,width:0,height:0};let t=1/0,i=1/0,n=-1/0,s=-1/0;return e.points.forEach(r=>{t=Math.min(t,r.x-e.x),i=Math.min(i,r.y-e.y),n=Math.max(n,r.x-e.x),s=Math.max(s,r.y-e.y);}),{x:t,y:i,width:n-t,height:s-i};case "text":return {x:-50,y:-e.fontSize/2,width:100,height:e.fontSize};default:return {x:0,y:0,width:0,height:0}}}hitTestArrowTerminal(e,t){for(let n of t){if(n.type!=="arrow")continue;let s=n;if(s.points.length<2)continue;let r=s.points[0],o=s.points[s.points.length-1],a=Math.sqrt(Math.pow(e.x-r.x,2)+Math.pow(e.y-r.y,2)),h=Math.sqrt(Math.pow(e.x-o.x,2)+Math.pow(e.y-o.y,2));if(a<20)return {shapeId:s.id,terminal:"start"};if(h<20)return {shapeId:s.id,terminal:"end"}}return null}findShapeNearPoint(e,t,i){for(let s=t.length-1;s>=0;s--){let r=t[s];if(i&&r.id===i||r.type==="arrow"||r.type==="line"||r.type==="draw")continue;let o;switch(r.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":o=this.pointToRectDistance(e,{x:r.x-r.width/2,y:r.y-r.height/2,width:r.width,height:r.height});break;case "circle":o=Math.sqrt(Math.pow(e.x-r.x,2)+Math.pow(e.y-r.y,2))-r.radius;break;case "hexagon":{let a=r.width/2,h=r.height/2,l=Math.abs(e.x-r.x),u=Math.abs(e.y-r.y);o=l/a+u/h-1;break}default:continue}if(o<=30)return r}return null}pointToRectDistance(e,t){let i=Math.max(t.x,Math.min(e.x,t.x+t.width)),n=Math.max(t.y,Math.min(e.y,t.y+t.height));return Math.sqrt(Math.pow(e.x-i,2)+Math.pow(e.y-n,2))}static SNAP_THRESHOLD=32;static HANDLE_SNAP_DISTANCE=18;static ANCHOR_EPS=.001;computeSnapGuidesForArrow(e,t,i,n,s){let r=this.draggingTerminal==="start"?n.endBinding:n.startBinding,o=r?s.find(g=>g.id===r.toShapeId):null;if(!o)return [];let a=this.findShapeNearPoint(i,s,n.id);if(!a)return [];let h=this.getShapeWorldBounds(o),l=this.getShapeWorldBounds(a),u=t.x-e.x,c=t.y-e.y,p=Math.abs(u)>=Math.abs(c)?"horizontal":"vertical";return Z(h,l,p)}findBindingNearPoint(e,t,i){let n;for(let s=t.length-1;s>=0;s--){let r=t[s];if(i&&r.id===i||r.type==="arrow"||r.type==="line"||r.type==="draw")continue;let o=this.getPageBounds(r),a=d.SNAP_THRESHOLD;if(e.x<o.x-a||e.x>o.x+o.width+a||e.y<o.y-a||e.y>o.y+o.height+a)continue;let h={x:r.x,y:r.y},l=[{handle:"top",pos:{x:h.x,y:o.y}},{handle:"bottom",pos:{x:h.x,y:o.y+o.height}},{handle:"left",pos:{x:o.x,y:h.y}},{handle:"right",pos:{x:o.x+o.width,y:h.y}}];for(let c of l){let p=Math.hypot(c.pos.x-e.x,c.pos.y-e.y);p<=d.HANDLE_SNAP_DISTANCE&&(!n||p<n.distance)&&(n={toShapeId:r.id,binding:{toShapeId:r.id,handle:c.handle,isPrecise:false},distance:p});}let u=this.nearestPointOnShapeOutline(r,e);if(u&&u.distance<=d.SNAP_THRESHOLD&&(!n||u.distance<n.distance)){let c=this.computeNormalizedAnchor(o,u.point);n={toShapeId:r.id,binding:{toShapeId:r.id,isPrecise:true,normalizedAnchor:c},distance:u.distance};}}if(n)return {toShapeId:n.toShapeId,binding:n.binding}}getPageBounds(e){switch(e.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":return {x:e.x-e.width/2,y:e.y-e.height/2,width:e.width,height:e.height};case "circle":return {x:e.x-e.radius,y:e.y-e.radius,width:e.radius*2,height:e.radius*2};default:return {x:e.x-50,y:e.y-50,width:100,height:100}}}computeNormalizedAnchor(e,t){let i=d.ANCHOR_EPS,n=e.width>0?(t.x-e.x)/e.width:.5,s=e.height>0?(t.y-e.y)/e.height:.5;return n=Math.max(i,Math.min(1-i,n)),s=Math.max(i,Math.min(1-i,s)),{x:n,y:s}}nearestPointOnShapeOutline(e,t){let i={x:t.x-e.x,y:t.y-e.y},n=this.nearestLocalPointOnShapeOutline(e,i);if(!n)return null;let s={x:n.point.x+e.x,y:n.point.y+e.y};return {point:s,distance:Math.hypot(s.x-t.x,s.y-t.y)}}nearestLocalPointOnShapeOutline(e,t){switch(e.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":{let i=e.width,n=e.height;return this.nearestPointOnRectOutlineLocal(t,{x:-i/2,y:-n/2,width:i,height:n})}case "circle":{let i=e.radius;return this.nearestPointOnCircleOutlineLocal(t,{x:0,y:0},i)}default:return null}}nearestPointOnRectOutlineLocal(e,t){let i=[[{x:t.x,y:t.y},{x:t.x+t.width,y:t.y}],[{x:t.x+t.width,y:t.y},{x:t.x+t.width,y:t.y+t.height}],[{x:t.x+t.width,y:t.y+t.height},{x:t.x,y:t.y+t.height}],[{x:t.x,y:t.y+t.height},{x:t.x,y:t.y}]],n=null;for(let[s,r]of i){let o=this.nearestPointOnSegment(e,s,r);(!n||o.distance<n.distance)&&(n=o);}return n}nearestPointOnCircleOutlineLocal(e,t,i){let n=e.x-t.x,s=e.y-t.y,r=Math.hypot(n,s);if(r<1e-9)return {point:{x:t.x+i,y:t.y},distance:i};let o=t.x+n/r*i,a=t.y+s/r*i,h={x:o,y:a};return {point:h,distance:Math.hypot(h.x-e.x,h.y-e.y)}}nearestPointOnSegment(e,t,i){let n=i.x-t.x,s=i.y-t.y,r=n*n+s*s,o=r>0?((e.x-t.x)*n+(e.y-t.y)*s)/r:0;o=Math.max(0,Math.min(1,o));let a=t.x+o*n,h=t.y+o*s,l={x:a,y:h};return {point:l,distance:Math.hypot(l.x-e.x,l.y-e.y)}}};var re=class d extends H{type="hand";state="idle";startScreenPoint={x:0,y:0};initialCameraPos={x:0,y:0};static DRAG_THRESHOLD=4;onPointerDown(e,t){this.startScreenPoint={x:t.clientX,y:t.clientY};let i=this.context.getCamera();this.initialCameraPos={x:i.x,y:i.y},this.state="pointing";}onPointerMove(e,t){if(this.state!=="idle"){if(this.state==="pointing"){let i=t.clientX-this.startScreenPoint.x,n=t.clientY-this.startScreenPoint.y;if(Math.hypot(i,n)<d.DRAG_THRESHOLD)return;this.state="dragging",this.applyCameraDelta(i,n);return}if(this.state==="dragging"){let i=t.clientX-this.startScreenPoint.x,n=t.clientY-this.startScreenPoint.y;this.applyCameraDelta(i,n);}}}onPointerUp(e,t){if(this.state!=="idle"){if(this.state==="dragging"){let i=this.context.getCamera();this.initialCameraPos={x:i.x,y:i.y},this.startScreenPoint={x:t.clientX,y:t.clientY};}this.state="idle";}}onKeyDown(e){e.key==="Escape"&&this.state!=="idle"&&(this.context.setCameraPosition(this.initialCameraPos.x,this.initialCameraPos.y),this.state="idle");}onKeyUp(e){}getCursor(e){return this.state==="dragging"||this.state==="pointing"?"grabbing":"grab"}applyCameraDelta(e,t){this.context.setCameraPosition(this.initialCameraPos.x+e,this.initialCameraPos.y+t);}};var je={strokeColor:"#1f2937",fillColor:"transparent",strokeWidth:2,strokeDash:null},oe=class extends H{type="line";isDrawing=false;startPoint={x:0,y:0};currentShape=null;onPointerDown(e,t){this.isDrawing=true,this.startPoint=e,this.currentShape={id:`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,type:"line",x:e.x,y:e.y,points:[e],rotation:0,style:{...je}},this.context.commitHistory(),this.context.addShape(this.currentShape);}onPointerMove(e,t){!this.isDrawing||!this.currentShape||this.context.updateShape(this.currentShape.id,{points:[this.startPoint,e]});}onPointerUp(e,t){this.isDrawing=false,this.currentShape=null,this.context.setActiveTool("select");}onKeyDown(e){}onKeyUp(e){}getCursor(){return "crosshair"}};var Je={strokeColor:"#1f2937",fillColor:"transparent",strokeWidth:4,strokeDash:null},Qe={strokeColor:"rgba(255, 235, 59, 0.5)",fillColor:"transparent",strokeWidth:16,strokeDash:null},et=4e3,Q=class extends H{type;mode;isDrawing=false;points=[];currentShapeId=null;committed=false;fadeTimer=null;constructor(e,t){super(e),this.mode=t,this.type=t==="pen"?"pen":"highlighter";}onPointerDown(e,t){this.isDrawing=true,this.committed=false,this.currentShapeId=null,this.points=[{...e}];}onPointerMove(e,t){if(this.isDrawing)if(this.points.push({...e}),!this.committed&&this.points.length>=2){this.context.commitHistory();let i=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`;this.currentShapeId=i;let n=this.points[0],s=this.mode==="pen"?{...Je}:{...Qe},r={id:i,type:"draw",x:n.x,y:n.y,points:this.points.map(o=>({...o})),rotation:0,style:s};this.context.addShape(r),this.committed=true;}else this.committed&&this.currentShapeId&&this.context.updateShape(this.currentShapeId,{points:this.points.map(i=>({...i}))});}onPointerUp(e,t){if(!this.isDrawing||(this.isDrawing=false,!this.committed||!this.currentShapeId))return;let i=this.currentShapeId;this.currentShapeId=null,this.mode==="highlighter"&&(this.fadeTimer=setTimeout(()=>{this.context.deleteShape(i);},et));}onKeyDown(e){}onKeyUp(e){}getCursor(){return "crosshair"}dispose(){this.fadeTimer&&(clearTimeout(this.fadeTimer),this.fadeTimer=null);}};var tt={strokeColor:"#1f2937",fillColor:"transparent",strokeWidth:2,strokeDash:null},ae=class extends H{type="arrow";isDrawing=false;startPoint={x:0,y:0};currentShapeId=null;startBindingInfo=null;onPointerDown(e,t){this.isDrawing=true,this.startPoint=e,this.startBindingInfo=null;let i=this.context.getShapes(),n=this.findShapeBinding(e,i),s=e;n&&(s=this.getBindingPosition(n.toShapeId,n.handle,i),this.startBindingInfo={...n,position:s});let r=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`;this.currentShapeId=r;let o={id:r,type:"arrow",x:s.x,y:s.y,points:[s],rotation:0,style:{...tt},startBinding:n?{toShapeId:n.toShapeId,handle:n.handle}:void 0,connectionType:"straight",arrowHead:"end",dashed:false};this.context.commitHistory(),this.context.addShape(o);}onPointerMove(e,t){if(!this.isDrawing||!this.currentShapeId)return;let i=this.context.getShapes(),n=this.findShapeBinding(e,i),s=e;n&&(s=this.getBindingPosition(n.toShapeId,n.handle,i));let r=this.startBindingInfo?.position||this.startPoint,o=this.computeSnapGuides(r,s,n,i);this.context.setSnapGuides(o),this.context.updateShape(this.currentShapeId,{points:[r,s],endBinding:n?{toShapeId:n.toShapeId,handle:n.handle}:void 0});}onPointerUp(e,t){this.isDrawing=false,this.currentShapeId=null,this.startBindingInfo=null,this.context.setSnapGuides([]),this.context.setActiveTool("select");}onKeyDown(e){}onKeyUp(e){}getCursor(){return "crosshair"}computeSnapGuides(e,t,i,n){let s=this.startBindingInfo?n.find(c=>c.id===this.startBindingInfo.toShapeId):null,r=i?n.find(c=>c.id===i.toShapeId):null;if(!s||!r)return [];let o=this.getShapeBounds(s),a=this.getShapeBounds(r),h=t.x-e.x,l=t.y-e.y,u=Math.abs(h)>=Math.abs(l)?"horizontal":"vertical";return Z(o,a,u)}getShapeBounds(e){switch(e.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":return {x:e.x-e.width/2,y:e.y-e.height/2,width:e.width,height:e.height};case "circle":return {x:e.x-e.radius,y:e.y-e.radius,width:e.radius*2,height:e.radius*2};case "text":return {x:e.x-e.width/2,y:e.y-e.height/2,width:e.width,height:e.height};default:return {x:e.x-50,y:e.y-20,width:100,height:40}}}findShapeBinding(e,t){for(let n=t.length-1;n>=0;n--){let s=t[n];if(s.type==="arrow"||s.type==="line"||s.type==="draw")continue;let r;switch(s.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "uml-class":case "uml-interface":r=this.pointToRectDistance(e,{x:s.x-s.width/2,y:s.y-s.height/2,width:s.width,height:s.height});break;case "circle":{let o=Math.sqrt(Math.pow(e.x-s.x,2)+Math.pow(e.y-s.y,2));r=Math.abs(o-s.radius);break}case "hexagon":{let o=s.width/2,a=s.height/2,h=Math.abs(e.x-s.x),l=Math.abs(e.y-s.y);r=h/o+l/a-1;break}default:continue}if(r<=40){let o=this.getClosestHandle(e,s);return {toShapeId:s.id,handle:o}}}}pointToRectDistance(e,t){let i=Math.max(t.x,Math.min(e.x,t.x+t.width)),n=Math.max(t.y,Math.min(e.y,t.y+t.height));return Math.sqrt(Math.pow(e.x-i,2)+Math.pow(e.y-n,2))}getClosestHandle(e,t){let i=e.x-t.x,n=e.y-t.y;if(t.type==="circle"||t.type==="hexagon"){let h=Math.atan2(n,i);return h>=-Math.PI/4&&h<Math.PI/4?"right":h>=Math.PI/4&&h<3*Math.PI/4?"bottom":h>=3*Math.PI/4||h<-(3*Math.PI)/4?"left":"top"}let s="width"in t?t.width:100,r="height"in t?t.height:100,o=Math.abs(i)/(s/2),a=Math.abs(n)/(r/2);return o>a?i>0?"right":"left":n>0?"bottom":"top"}getBindingPosition(e,t,i){let n=i.find(s=>s.id===e);if(!n)return {x:0,y:0};switch(n.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":return this.getRectBindingPosition(n,t);case "circle":return this.getCircleBindingPosition(n,t);case "hexagon":return this.getRectBindingPosition(n,t);default:return {x:n.x,y:n.y}}}getRectBindingPosition(e,t){switch(t){case "top":return {x:e.x,y:e.y-e.height/2};case "bottom":return {x:e.x,y:e.y+e.height/2};case "left":return {x:e.x-e.width/2,y:e.y};case "right":return {x:e.x+e.width/2,y:e.y}}}getCircleBindingPosition(e,t){switch(t){case "top":return {x:e.x,y:e.y-e.radius};case "bottom":return {x:e.x,y:e.y+e.radius};case "left":return {x:e.x-e.radius,y:e.y};case "right":return {x:e.x+e.radius,y:e.y}}}};var nt={strokeColor:"transparent",fillColor:"transparent",strokeWidth:0,strokeDash:null},we=class extends H{type="text";onPointerDown(e,t){let i=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,n={id:i,type:"text",x:e.x,y:e.y,rotation:0,style:{...nt},text:"",fontSize:16,textColor:"#1f2937",width:200,height:24};this.context.commitHistory(),this.context.addShape(n),this.context.enterEditing(i);}onPointerMove(e,t){}onPointerUp(e,t){}onKeyDown(e){}onKeyUp(e){}getCursor(){return "text"}};var Ae="drawui-canvas-data",it=50,Le=class{canvas;renderer;camera;tools=new Map;activeTool="select";shapes=[];selectedIds=[];listeners=new Set;notificationListeners=new Set;uiListeners=new Set;isPanning=false;panStart={x:0,y:0};dragStartPositions=new Map;lastClickTime=0;lastClickShapeId=null;editingShapeId=null;textInput=null;textOverlay=null;isNewTextShape=false;originalTextValue="";undoStack=[];redoStack=[];isUndoing=false;brushRect=null;snapGuides=[];connectingTargetId=null;genPreview=null;eraserPoint=null;mindMapEditingShapeId=null;mindMapSelectedNode=null;mindMapHoverNode=null;renderScheduled=false;pointerIsDown=false;notifyScheduled=false;persist=true;constructor(e,t={}){this.canvas=e,this.persist=t.persist??!t.shapes,t.theme&&de(t.theme),t.language&&ue(t.language);let i=e.getBoundingClientRect();this.renderer=new ie(e),this.renderer.resize(i.width,i.height),this.camera=new ee;let n={addShape:s=>this.addShape(s),updateShape:(s,r)=>this.updateShape(s,r),deleteShape:s=>this.deleteShape(s),selectShape:(s,r)=>this.selectShape(s,r),selectShapes:s=>this.selectShapes(s),getShapes:()=>[...this.shapes],getSelectedIds:()=>[...this.selectedIds],setActiveTool:s=>this.setActiveTool(s),screenToPage:s=>this.screenToPage(s),getCamera:()=>this.camera,panBy:(s,r)=>this.panBy(s,r),setCameraPosition:(s,r)=>this.setCameraPosition(s,r),getShapeAtPoint:(s,r)=>this.getShapeAtPoint(s,r),getShapesInBrushRadius:(s,r)=>this.getShapesInBrushRadius(s,r),setEraserPoint:s=>this.setEraserPoint(s),updateArrowBinding:(s,r,o,a)=>this.updateArrowBinding(s,r,o,a),enterEditing:s=>this.enterEditing(s),exitEditing:()=>this.exitEditing(),commitHistory:()=>this.commitHistory(),setBrushRect:s=>this.setBrushRect(s),setSnapGuides:s=>this.setSnapGuides(s),setConnectingTarget:s=>this.setConnectingTarget(s),setGenerationPreview:s=>this.setGenerationPreview(s),openGenerationMenu:s=>this.openGenerationMenu(s),createGeneratedConnection:(s,r)=>this.createGeneratedConnection(s,r),createFloatingLine:s=>this.createFloatingLine(s),connectToExisting:(s,r,o)=>this.connectToExisting(s,r,o),updateSelectedShapesStyle:s=>this.updateSelectedShapesStyle(s),updateSelectedShapesText:s=>this.updateSelectedShapesText(s),updateConnectionType:s=>this.updateConnectionType(s),getMindMapCursorHitAtPoint:s=>this.getMindMapCursorHitAtPoint(s),selectMindMapNode:(s,r)=>this.selectMindMapNode(s,r)};this.tools.set("select",new se(n)),this.tools.set("hand",new re(n)),this.tools.set("rectangle",new R(n,"rectangle")),this.tools.set("rounded-rectangle",new R(n,"rounded-rectangle")),this.tools.set("circle",new R(n,"circle")),this.tools.set("ellipse",new R(n,"ellipse")),this.tools.set("diamond",new R(n,"diamond")),this.tools.set("triangle",new R(n,"triangle")),this.tools.set("hexagon",new R(n,"hexagon")),this.tools.set("parallelogram",new R(n,"parallelogram")),this.tools.set("trapezoid",new R(n,"trapezoid")),this.tools.set("pentagon",new R(n,"pentagon")),this.tools.set("octagon",new R(n,"octagon")),this.tools.set("star",new R(n,"star")),this.tools.set("uml-class",new R(n,"uml-class")),this.tools.set("uml-interface",new R(n,"uml-interface")),this.tools.set("line",new oe(n)),this.tools.set("arrow",new ae(n)),this.tools.set("text",new we(n)),this.tools.set("pen",new Q(n,"pen")),this.tools.set("highlighter",new Q(n,"highlighter")),this.tools.set("eraser",new Se(n)),this.tools.set("mind-map",new R(n,"mind-map")),this.setupEventListeners(),t.shapes?this.shapes=t.shapes.map(s=>({...s,style:{...s.style}})):this.persist&&this.loadFromStorage(),this.render();}setupEventListeners(){this.canvas.addEventListener("pointerdown",this.handlePointerDown),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerup",this.handlePointerUp),this.canvas.addEventListener("pointerleave",this.handlePointerUp),this.canvas.addEventListener("wheel",this.handleWheel,{passive:false}),window.addEventListener("keydown",this.handleKeyDown),window.addEventListener("keyup",this.handleKeyUp),window.addEventListener("resize",this.handleResize);}handlePointerDown=e=>{if(this.editingShapeId)return this.textInput&&e.target===this.textInput,void 0;if(this.pointerIsDown=true,e.button===1||e.button===0&&e.altKey){this.isPanning=true,this.panStart={x:e.clientX,y:e.clientY},this.canvas.setPointerCapture(e.pointerId),this.canvas.style.cursor="grabbing";return}let t=this.screenToPage({x:e.clientX,y:e.clientY}),i=this.activeTool==="select"?this.getMindMapCollapseHitAtPoint(t):null;if(i){this.toggleMindMapCollapse(i.shapeId,i.nodeId);return}if(this.activeTool==="select"){let s=Date.now(),r=this.getShapeAtPoint(t);if(s-this.lastClickTime<400&&this.lastClickShapeId&&r&&r.id===this.lastClickShapeId&&this.canEditShape(r)){this.enterEditing(r.id),this.lastClickTime=0,this.lastClickShapeId=null;return}if(this.lastClickTime=s,this.lastClickShapeId=r?.id||null,r&&r.type==="mind-map"&&this.mindMapEditingShapeId===r.id){let o=this.getMindMapNodeAtPoint(t);o&&(this.mindMapSelectedNode=o,this.notifyListeners(),this.render());return}r&&(this.dragStartPositions.clear(),this.selectedIds.forEach(o=>{let a=this.shapes.find(h=>h.id===o);a&&this.dragStartPositions.set(o,{x:a.x,y:a.y});}));}this.tools.get(this.activeTool)?.onPointerDown(t,e),this.updateCursor(t),this.render();};handlePointerMove=e=>{if(this.editingShapeId)return;if(this.isPanning){let n=e.clientX-this.panStart.x,s=e.clientY-this.panStart.y;this.camera.translate(n,s),this.panStart={x:e.clientX,y:e.clientY},this.scheduleRender(),this.notifyListeners();return}let t=this.screenToPage({x:e.clientX,y:e.clientY});this.tools.get(this.activeTool)?.onPointerMove(t,e),this.updateCursor(t),this.scheduleRender();};handlePointerUp=e=>{if(this.pointerIsDown=false,e.type==="pointerleave"&&(this.mindMapHoverNode=null),this.editingShapeId)return;if(this.isPanning){this.isPanning=false,this.updateCursor(this.screenToPage({x:e.clientX,y:e.clientY}));return}let t=this.screenToPage({x:e.clientX,y:e.clientY});this.tools.get(this.activeTool)?.onPointerUp(t,e),this.updateCursor(t),this.scheduleRender();};updateCursor(e){let i=this.tools.get(this.activeTool)?.getCursor(e)??"default";if(this.canvas.style.cursor!==i&&(this.canvas.style.cursor=i),!this.pointerIsDown){let n=this.getMindMapCursorHitAtPoint(e);(n?.shapeId!==this.mindMapHoverNode?.shapeId||n?.nodeId!==this.mindMapHoverNode?.nodeId)&&(this.mindMapHoverNode=n,this.scheduleRender());}}handleWheel=e=>{if(e.preventDefault(),e.ctrlKey||e.metaKey){let n=e.deltaY>0?.9:1.1;this.camera.zoomAt({x:e.clientX,y:e.clientY},n),this.scheduleRender(),this.notifyListeners();return}let t=e.deltaX||0,i=e.deltaY||0;e.deltaMode===1?(t*=40,i*=40):e.deltaMode===2&&(t*=120,i*=120),e.shiftKey&&(t=t||i,i=0),this.camera.translate(-t,-i),this.scheduleRender(),this.notifyListeners();};handleKeyDown=e=>{if(this.editingShapeId)return;if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()==="z"){e.preventDefault(),e.shiftKey?this.redo():this.undo();return}if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()==="y"){e.preventDefault(),this.redo();return}if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()==="s"){e.preventDefault(),this.saveToStorage();return}if(!e.ctrlKey&&!e.metaKey&&!e.altKey){if(e.key==="v"||e.key==="V"){this.setActiveTool("select"),e.preventDefault();return}if(e.key==="h"||e.key==="H"){this.setActiveTool("hand"),e.preventDefault();return}}this.tools.get(this.activeTool)?.onKeyDown(e),this.scheduleRender();};handleKeyUp=e=>{if(this.editingShapeId)return;this.tools.get(this.activeTool)?.onKeyUp(e),this.scheduleRender();};handleResize=()=>{this.renderer.resize(window.innerWidth,window.innerHeight),this.scheduleRender();};screenToPage(e){let t=this.canvas.getBoundingClientRect();return this.camera.screenToPage({x:e.x-t.left,y:e.y-t.top})}addShape(e){this.shapes.push(e),this.notifyListeners();}updateShape(e,t){let i=this.shapes.findIndex(n=>n.id===e);i!==-1&&(this.shapes[i]={...this.shapes[i],...t},(t.x!==void 0||t.y!==void 0)&&this.updateBoundArrows(e),this.notifyListeners());}updateBoundArrows(e){let t=this.shapes.find(i=>i.id===e);t&&this.shapes.forEach(i=>{if(i.type==="arrow"){let n=i,s={};if(n.startBinding?.toShapeId===e){let r=this.getBindingPosition(t,n.startBinding.handle||"top");s.points=n.points.map((o,a)=>a===0?r:o);}if(n.endBinding?.toShapeId===e){let r=this.getBindingPosition(t,n.endBinding.handle||"top"),o=s.points||[...n.points];s.points=o.map((a,h)=>h===o.length-1?r:a);}s.points&&(this.shapes[this.shapes.indexOf(i)]={...n,...s});}});}getBindingPosition(e,t){switch(e.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":switch(t){case "top":return {x:e.x,y:e.y-e.height/2};case "bottom":return {x:e.x,y:e.y+e.height/2};case "left":return {x:e.x-e.width/2,y:e.y};case "right":return {x:e.x+e.width/2,y:e.y}}case "circle":switch(t){case "top":return {x:e.x,y:e.y-e.radius};case "bottom":return {x:e.x,y:e.y+e.radius};case "left":return {x:e.x-e.radius,y:e.y};case "right":return {x:e.x+e.radius,y:e.y}}case "hexagon":switch(t){case "top":return {x:e.x,y:e.y-e.height/2};case "bottom":return {x:e.x,y:e.y+e.height/2};case "left":return {x:e.x-e.width/2,y:e.y};case "right":return {x:e.x+e.width/2,y:e.y}}default:return {x:e.x,y:e.y}}}deleteShape(e){this.shapes=this.shapes.filter(t=>t.id!==e),this.selectedIds=this.selectedIds.filter(t=>t!==e),this.shapes=this.shapes.map(t=>{if(t.type==="arrow"){let i=t;if(i.startBinding?.toShapeId===e)return {...i,startBinding:void 0};if(i.endBinding?.toShapeId===e)return {...i,endBinding:void 0}}return t}),this.notifyListeners(),this.scheduleRender();}selectShape(e,t){if(!e)this.selectedIds=[];else if(t){let i=this.selectedIds.indexOf(e);i===-1?this.selectedIds.push(e):this.selectedIds.splice(i,1);}else this.selectedIds=[e];this.notifyListeners(),this.scheduleRender();}selectShapes(e){this.selectedIds=[...e],this.notifyListeners(),this.scheduleRender();}setBrushRect(e){this.brushRect=e,this.scheduleRender();}setSnapGuides(e){this.snapGuides=e;}setConnectingTarget(e){this.connectingTargetId!==e&&(this.connectingTargetId=e,this.scheduleRender());}setGenerationPreview(e){this.genPreview?.from.x===e?.from.x&&this.genPreview?.from.y===e?.from.y&&this.genPreview?.to.x===e?.to.x&&this.genPreview?.to.y===e?.to.y&&this.genPreview?.type===e?.type||(this.genPreview=e,this.scheduleRender());}openGenerationMenu(e){let t=this.camera.getZoom(),i=(e.context.to.x+this.camera.x)*t,n=(e.context.to.y+this.camera.y)*t;this.emitUi({kind:"shapeTypeMenu",screenX:i,screenY:n,context:e.context,existingArrowId:e.existingArrowId,defaultShapeType:e.defaultShapeType});}lineStyle(){return {strokeColor:"#1f2937",fillColor:"transparent",strokeWidth:2,strokeDash:null}}computeSourceBinding(e){if(!e.sourceShapeId||!e.edge)return;let t=this.shapes.find(n=>n.id===e.sourceShapeId);if(!t)return;let i={n:"top",e:"right",s:"bottom",w:"left"};return {toShapeId:t.id,handle:i[e.edge]}}connectHandle(e,t){let i=t.x-e.x,n=t.y-e.y;return Math.abs(i)>=Math.abs(n)?i>=0?"left":"right":n>=0?"top":"bottom"}createFloatingLine(e){this.commitHistory();let t=e.from,i=e.to,n=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,s={id:n,type:"arrow",x:t.x,y:t.y,points:[{x:t.x,y:t.y},{x:i.x,y:i.y}],rotation:0,style:this.lineStyle(),startBinding:this.computeSourceBinding(e),connectionType:"polyline",arrowHead:"end",dashed:false};return this.addShape(s),this.selectedIds=[n],this.notifyListeners(),this.render(),n}createGeneratedConnection(e,t){this.commitHistory();let i=t.type,n;if(e.sourceShapeId){let a=this.shapes.find(h=>h.id===e.sourceShapeId);a&&fe(a.type)&&(n={...a.style});}let s=Ee(i,e.to,n);this.addShape(s);let r=e.from,o={toShapeId:s.id,handle:this.connectHandle(r,e.to)};if(t.existingArrowId)this.updateArrowBinding(t.existingArrowId,"end",s.id,{toShapeId:s.id,handle:this.connectHandle(r,e.to)});else {let h={id:`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,type:"arrow",x:r.x,y:r.y,points:[{x:r.x,y:r.y},{x:e.to.x,y:e.to.y}],rotation:0,style:this.lineStyle(),startBinding:this.computeSourceBinding(e),endBinding:o,connectionType:"polyline",arrowHead:"end",dashed:false};this.addShape(h);}this.selectedIds=[s.id],this.notifyListeners(),this.render();}connectToExisting(e,t,i){this.commitHistory();let n=this.shapes.find(l=>l.id===t);if(!n)return;let s=e.from,r=i?.handle??this.connectHandle(s,{x:n.x,y:n.y}),o=this.getBindingPosition(n,r),a=`shape_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,h={id:a,type:"arrow",x:s.x,y:s.y,points:[{x:s.x,y:s.y},{x:o.x,y:o.y}],rotation:0,style:this.lineStyle(),startBinding:this.computeSourceBinding(e),endBinding:{toShapeId:t,handle:r},connectionType:"polyline",arrowHead:"end",dashed:false};this.addShape(h),this.selectedIds=[a],this.notifyListeners(),this.render();}subscribeUi(e){return this.uiListeners.add(e),()=>this.uiListeners.delete(e)}emitUi(e){this.uiListeners.forEach(t=>t(e));}updateSelectedShapesStyle(e){this.selectedIds.length!==0&&(this.commitHistory(),this.selectedIds.forEach(t=>{let i=this.shapes.findIndex(n=>n.id===t);i!==-1&&(this.shapes[i]={...this.shapes[i],style:{...this.shapes[i].style,...e}});}),this.notifyListeners(),this.render());}updateSelectedShapesText(e){this.selectedIds.length!==0&&(this.commitHistory(),this.selectedIds.forEach(t=>{let i=this.shapes.findIndex(n=>n.id===t);i!==-1&&(this.shapes[i]={...this.shapes[i],...e});}),this.notifyListeners(),this.render());}updateConnectionType(e){this.selectedIds.length!==0&&(this.commitHistory(),this.selectedIds.forEach(t=>{let i=this.shapes.findIndex(n=>n.id===t);if(i!==-1){let n=this.shapes[i];(n.type==="line"||n.type==="arrow")&&(this.shapes[i]={...n,connectionType:e});}}),this.notifyListeners(),this.render());}updateArrowHeadType(e){this.selectedIds.length!==0&&(this.commitHistory(),this.selectedIds.forEach(t=>{let i=this.shapes.findIndex(n=>n.id===t);if(i!==-1){let n=this.shapes[i];n.type==="arrow"&&(this.shapes[i]={...n,arrowHead:e});}}),this.notifyListeners(),this.render());}updateArrowDashed(e){this.selectedIds.length!==0&&(this.commitHistory(),this.selectedIds.forEach(t=>{let i=this.shapes.findIndex(n=>n.id===t);if(i!==-1){let n=this.shapes[i];n.type==="arrow"&&(this.shapes[i]={...n,dashed:e});}}),this.notifyListeners(),this.render());}updateUmlClass(e,t){let i=this.shapes.findIndex(l=>l.id===e);if(i===-1)return;let n=this.shapes[i];if(n.type!=="uml-class")return;this.commitHistory();let s=t.className??n.className,r=t.attributes??n.attributes,o=t.methods??n.methods,{width:a,height:h}=xe(s,r,o);this.shapes[i]={...n,className:s,attributes:r,methods:o,width:a,height:h},this.notifyListeners(),this.render();}updateUmlInterface(e,t){let i=this.shapes.findIndex(g=>g.id===e);if(i===-1)return;let n=this.shapes[i];if(n.type!=="uml-interface")return;this.commitHistory();let s=n,r=t.className??s.className,o=t.methods??s.methods,a=W*.6,h=o.map(g=>`${g.visibility} ${g.name}(${g.params}): ${g.returnType}`),l=Math.max(r.length,...h.map(g=>g.length),0),u=Math.max(ne,l*a+$*2),c=o.length>0?o.length*V+L*2:L*2,p=X+c;this.shapes[i]={...n,className:r,methods:o,width:u,height:p},this.notifyListeners(),this.render();}getSelectedUml(){if(this.selectedIds.length!==1)return null;let e=this.shapes.find(t=>t.id===this.selectedIds[0]);return e&&(e.type==="uml-class"||e.type==="uml-interface")?e:null}getUmlById(e){let t=this.shapes.find(i=>i.id===e);return t&&(t.type==="uml-class"||t.type==="uml-interface")?t:null}getSelectedMindMap(){if(this.selectedIds.length!==1)return null;let e=this.shapes.find(t=>t.id===this.selectedIds[0]);return e&&e.type==="mind-map"?e:null}getMindMapNodeAtPoint(e){for(let t=this.shapes.length-1;t>=0;t--){let i=this.shapes[t];if(i.type!=="mind-map")continue;let n=i,s=e.x-n.x,r=e.y-n.y,o=Math.cos(n.rotation),a=Math.sin(n.rotation),h=s*o+r*a,l=-s*a+r*o;if(Math.abs(h)>n.width/2||Math.abs(l)>n.height/2)continue;let u=k(n.root);for(let[c,p]of u.positions)if(Math.abs(h-p.x)<=p.width/2&&Math.abs(l-p.y)<=p.height/2)return {shapeId:n.id,nodeId:c};return {shapeId:n.id,nodeId:n.root.id}}return null}getMindMapNodeAtScreenPoint(e){return this.getMindMapNodeAtPoint(this.screenToPage(e))}getMindMapCursorHitAtPoint(e){let t=this.getMindMapCollapseHitAtPoint(e);if(t)return t;for(let i=this.shapes.length-1;i>=0;i--){let n=this.shapes[i];if(n.type!=="mind-map")continue;let s=n,r=e.x-s.x,o=e.y-s.y,a=Math.cos(s.rotation),h=Math.sin(s.rotation),l=r*a+o*h,u=-r*h+o*a,c=k(s.root);for(let[p,g]of c.positions)if(Math.abs(l-g.x)<=g.width/2&&Math.abs(u-g.y)<=g.height/2)return {shapeId:s.id,nodeId:p}}return null}selectMindMapNode(e,t){let i=this.shapes.find(n=>n.id===e);!i||i.type!=="mind-map"||(this.selectedIds=[e],this.mindMapSelectedNode={shapeId:e,nodeId:t},this.notifyListeners(),this.render());}getMindMapEditingShapeId(){return this.mindMapEditingShapeId}getMindMapSelectedNode(){return this.mindMapSelectedNode}getMindMapNode(e,t){let i=this.shapes.find(n=>n.id===e);return !i||i.type!=="mind-map"?null:F(i.root,t)}getMindMapNodeScreenRect(e,t){let i=this.shapes.find(w=>w.id===e);if(!i||i.type!=="mind-map")return null;let n=i,r=k(n.root).positions.get(t);if(!r)return null;let o=this.camera.getZoom(),a=r.x,h=r.y,l=Math.cos(n.rotation),u=Math.sin(n.rotation),c=a*l-h*u,p=a*u+h*l,g=this.camera.pageToScreen({x:n.x,y:n.y}),m=g.x+c*o,y=g.y+p*o;return {x:m-r.width*o/2,y:y-r.height*o/2,width:r.width*o,height:r.height*o}}getMindMapCollapseHitAtPoint(e){for(let t of this.shapes){if(t.type!=="mind-map")continue;let i=t,n=k(i.root),s=e.x-i.x,r=e.y-i.y,o=Math.cos(i.rotation),a=Math.sin(i.rotation),h=s*o+r*a,l=-s*a+r*o;for(let[u,c]of n.positions){let p=F(i.root,u);if(!p||!p.children||p.children.length===0)continue;let g=c.x+c.width/2+10,m=c.y,y=h-g,w=l-m;if(y*y+w*w<=121)return {shapeId:t.id,nodeId:u}}}return null}beginMindMapEdit(e,t){let i=this.shapes.find(s=>s.id===e);if(!i||i.type!=="mind-map")return;let n=i;this.mindMapEditingShapeId=e,this.mindMapSelectedNode={shapeId:e,nodeId:t&&F(n.root,t)?t:n.root.id},this.selectedIds=[e],this.notifyListeners(),this.render();}exitMindMapEdit(){this.mindMapEditingShapeId=null,this.mindMapSelectedNode=null,this.notifyListeners(),this.render();}updateMindMapNode(e,t,i,n=true){let s=this.shapes.findIndex(p=>p.id===e);if(s===-1)return;let r=this.shapes[s];if(r.type!=="mind-map")return;let o=r,a=F(o.root,t);if(!a||!Object.keys(i).some(p=>a[p]!==i[p]))return;n&&this.commitHistory();let l=me(o.root,t,i),{width:u,height:c}=k(l);this.shapes[s]={...o,root:l,width:u,height:c},this.notifyListeners(),this.render();}addMindMapChild(e,t){let i=this.shapes.findIndex(l=>l.id===e);if(i===-1)return;let n=this.shapes[i];if(n.type!=="mind-map")return;let s=n,r={id:`mm_${Date.now()}_${Math.random().toString(36).substr(2,6)}`,text:z("mindmap.defaultBranch")},o=Pe(s.root,t,r);this.commitHistory();let{width:a,height:h}=k(o);this.shapes[i]={...s,root:o,width:a,height:h},this.mindMapSelectedNode={shapeId:e,nodeId:r.id},this.notifyListeners(),this.render();}addMindMapSibling(e,t){let i=this.shapes.findIndex(l=>l.id===e);if(i===-1)return;let n=this.shapes[i];if(n.type!=="mind-map")return;let s=n;if(!te(s.root,t))return;let r={id:`mm_${Date.now()}_${Math.random().toString(36).substr(2,6)}`,text:z("mindmap.defaultBranch")},o=Ie(s.root,t,r);this.commitHistory();let{width:a,height:h}=k(o);this.shapes[i]={...s,root:o,width:a,height:h},this.mindMapSelectedNode={shapeId:e,nodeId:r.id},this.notifyListeners(),this.render();}deleteMindMapNode(e,t){let i=this.shapes.findIndex(l=>l.id===e);if(i===-1)return;let n=this.shapes[i];if(n.type!=="mind-map")return;let s=n;if(s.root.id===t){this.commitHistory(),this.shapes=this.shapes.filter(l=>l.id!==e),this.selectedIds=this.selectedIds.filter(l=>l!==e),this.mindMapEditingShapeId=null,this.mindMapSelectedNode=null,this.notifyListeners(),this.render();return}let r=Ce(s.root,t);if(!r)return;this.commitHistory();let{width:o,height:a}=k(r);this.shapes[i]={...s,root:r,width:o,height:a};let h=te(s.root,t);this.mindMapSelectedNode=h?{shapeId:e,nodeId:h.id}:{shapeId:e,nodeId:r.id},this.notifyListeners(),this.render();}toggleMindMapCollapse(e,t){let i=this.shapes.findIndex(l=>l.id===e);if(i===-1)return;let n=this.shapes[i];if(n.type!=="mind-map")return;let s=n,r=F(s.root,t);if(!r||!r.children||r.children.length===0)return;this.commitHistory();let o=me(s.root,t,{collapsed:!r.collapsed}),{width:a,height:h}=k(o);this.shapes[i]={...s,root:o,width:a,height:h},this.notifyListeners(),this.render();}addUmlAttribute(e){let t=this.shapes.find(n=>n.id===e);if(!t||t.type!=="uml-class")return;let i={id:`attr_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,visibility:"+",name:"newField",type:"string"};this.updateUmlClass(e,{attributes:[...t.attributes,i]});}addUmlMethod(e){let t=this.getUmlById(e);if(!t)return;let i={id:`meth_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,visibility:"+",name:"newMethod",params:"",returnType:"void"};t.type==="uml-class"?this.updateUmlClass(e,{methods:[...t.methods,i]}):this.updateUmlInterface(e,{methods:[...t.methods,i]});}removeUmlAttribute(e,t){let i=this.shapes.find(n=>n.id===e);!i||i.type!=="uml-class"||this.updateUmlClass(e,{attributes:i.attributes.filter(n=>n.id!==t)});}removeUmlMethod(e,t){let i=this.getUmlById(e);if(!i)return;let n=i.methods.filter(s=>s.id!==t);i.type==="uml-class"?this.updateUmlClass(e,{methods:n}):this.updateUmlInterface(e,{methods:n});}reorderUmlAttribute(e,t,i){let n=this.shapes.find(o=>o.id===e);if(!n||n.type!=="uml-class"||t===i)return;let s=[...n.attributes];if(t<0||t>=s.length||i<0||i>=s.length)return;let[r]=s.splice(t,1);s.splice(i,0,r),this.updateUmlClass(e,{attributes:s});}reorderUmlMethod(e,t,i){let n=this.getUmlById(e);if(!n||t===i)return;let s=[...n.methods];if(t<0||t>=s.length||i<0||i>=s.length)return;let[r]=s.splice(t,1);s.splice(i,0,r),n.type==="uml-class"?this.updateUmlClass(e,{methods:s}):this.updateUmlInterface(e,{methods:s});}updateUmlRowStyle(e,t,i,n){let s=this.getUmlById(e);if(s)if(t==="attribute"){if(s.type!=="uml-class")return;let r=s.attributes.map(o=>o.id===i?{...o,textColor:n.textColor===null?void 0:n.textColor??o.textColor,fontSize:n.fontSize===null?void 0:n.fontSize??o.fontSize,strikethrough:n.strikethrough===null?void 0:n.strikethrough??o.strikethrough}:o);this.updateUmlClass(e,{attributes:r});}else {let r=s.methods.map(o=>o.id===i?{...o,textColor:n.textColor===null?void 0:n.textColor??o.textColor,fontSize:n.fontSize===null?void 0:n.fontSize??o.fontSize,strikethrough:n.strikethrough===null?void 0:n.strikethrough??o.strikethrough}:o);s.type==="uml-class"?this.updateUmlClass(e,{methods:r}):this.updateUmlInterface(e,{methods:r});}}getUmlRowAtScreenPoint(e){let t=this.camera.screenToPage(e);for(let i=this.shapes.length-1;i>=0;i--){let n=this.shapes[i];if(n.type!=="uml-class"&&n.type!=="uml-interface")continue;let s=n.width/2,r=n.height/2;if(t.x<n.x-s||t.x>n.x+s||t.y<n.y-r||t.y>n.y+r)continue;let o=X,a=t.y-n.y;if(a>=-r&&a<=-r+o)return {shape:n,section:"className",rowIndex:-1,text:n.className};if(n.type==="uml-interface"){let g=-r+o,m=r;if(n.methods.length>0&&a>=g&&a<=m){let y=Math.floor((a-g-L)/V);if(y>=0&&y<n.methods.length){let w=n.methods[y];return {shape:n,section:"method",rowIndex:y,text:`${w.visibility} ${w.name}(${w.params}): ${w.returnType}`}}return {shape:n,section:"method",rowIndex:-1,text:""}}return {shape:n,section:"className",rowIndex:-1,text:n.className}}let h=n.attributes.length>0?n.attributes.length*V+L*2:L*2,l=-r+o,u=l+h;if(n.attributes.length>0&&a>=l&&a<=u){let g=Math.floor((a-l-L)/V);if(g>=0&&g<n.attributes.length){let m=n.attributes[g];return {shape:n,section:"attribute",rowIndex:g,text:`${m.visibility} ${m.name}: ${m.type}`}}return {shape:n,section:"attribute",rowIndex:-1,text:""}}let c=u,p=r;if(n.methods.length>0&&a>=c&&a<=p){let g=Math.floor((a-c-L)/V);if(g>=0&&g<n.methods.length){let m=n.methods[g];return {shape:n,section:"method",rowIndex:g,text:`${m.visibility} ${m.name}(${m.params}): ${m.returnType}`}}return {shape:n,section:"method",rowIndex:-1,text:""}}return {shape:n,section:"className",rowIndex:-1,text:n.className}}return null}setActiveTool(e){this.tools.has(e)&&(this.activeTool=e,this.eraserPoint=null,this.notifyListeners());}getActiveTool(){return this.activeTool}getShapes(){return [...this.shapes]}getData(){return {shapes:this.getShapes(),camera:{x:this.camera.x,y:this.camera.y,zoom:this.camera.zoom}}}setShapes(e){return Array.isArray(e)?(this.shapes=e.map(t=>({...t,style:{...t.style}})),this.selectedIds=[],this.undoStack=[],this.redoStack=[],this.notifyListeners(),this.render(),true):false}setTheme(e){de(e),this.scheduleRender();}setLanguage(e){ue(e);}getSelectedIds(){return [...this.selectedIds]}getCamera(){return this.camera}isPointerDown(){return this.pointerIsDown}zoomIn(){this.camera.zoomAt({x:window.innerWidth/2,y:window.innerHeight/2},1.2),this.scheduleRender(),this.notifyListeners();}zoomOut(){this.camera.zoomAt({x:window.innerWidth/2,y:window.innerHeight/2},.8),this.scheduleRender(),this.notifyListeners();}resetZoom(){this.camera.reset(),this.scheduleRender(),this.notifyListeners();}panBy(e,t){this.camera.translate(e,t),this.scheduleRender(),this.notifyListeners();}setCameraPosition(e,t){this.camera.x=e,this.camera.y=t,this.scheduleRender(),this.notifyListeners();}requestRender(){this.scheduleRender(),this.notifyListeners();}setShowGrid(e){this.renderer.setShowGrid(e),this.scheduleRender();}render(){this.renderer.render(this.shapes,this.camera,new Set(this.selectedIds),this.brushRect,this.snapGuides,this.connectingTargetId,this.genPreview,this.eraserPoint,this.mindMapSelectedNode,this.mindMapHoverNode);}scheduleRender(){this.renderScheduled||(this.renderScheduled=true,requestAnimationFrame(()=>{this.renderScheduled=false,this.render();}));}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}subscribeNotifications(e){return this.notificationListeners.add(e),()=>this.notificationListeners.delete(e)}notify(e){this.notificationListeners.forEach(t=>t(e));}notifyListeners(){this.notifyScheduled||(this.notifyScheduled=true,queueMicrotask(()=>{this.notifyScheduled=false,this.mindMapEditingShapeId&&!this.selectedIds.includes(this.mindMapEditingShapeId)&&(this.mindMapEditingShapeId=null,this.mindMapSelectedNode=null),this.listeners.forEach(e=>e());}));}cloneShapes(e){return e.map(t=>{let i={...t,style:{...t.style}};return Array.isArray(t.points)&&(i.points=t.points.map(n=>({...n}))),t.startBinding&&(i.startBinding={...t.startBinding}),t.endBinding&&(i.endBinding={...t.endBinding}),t.root&&(i.root=ye(t.root)),i})}commitHistory(){if(this.isUndoing)return;let e={shapes:this.cloneShapes(this.shapes),selectedIds:[...this.selectedIds]};this.undoStack.push(e),this.undoStack.length>it&&this.undoStack.shift(),this.redoStack=[];}mark(){this.commitHistory();}undo(){if(this.undoStack.length!==0){this.isUndoing=true;try{this.redoStack.push({shapes:this.cloneShapes(this.shapes),selectedIds:[...this.selectedIds]});let e=this.undoStack.pop();this.shapes=this.cloneShapes(e.shapes),this.selectedIds=[...e.selectedIds];}finally{this.isUndoing=false;}this.notifyListeners(),this.render();}}redo(){if(this.redoStack.length!==0){this.isUndoing=true;try{this.undoStack.push({shapes:this.cloneShapes(this.shapes),selectedIds:[...this.selectedIds]});let e=this.redoStack.pop();this.shapes=this.cloneShapes(e.shapes),this.selectedIds=[...e.selectedIds];}finally{this.isUndoing=false;}this.notifyListeners(),this.render();}}canUndo(){return this.undoStack.length>0}canRedo(){return this.redoStack.length>0}saveToStorage(){if(!this.persist)return false;try{let e=JSON.stringify({version:1,shapes:this.shapes,savedAt:Date.now()});return localStorage.setItem(Ae,e),this.notifyListeners(),this.notify(z("save.success")),!0}catch(e){return console.error("\u4FDD\u5B58\u5931\u8D25:",e),this.notify(z("save.fail")),false}}loadFromStorage(){if(!this.persist)return false;try{let e=localStorage.getItem(Ae);if(!e)return !1;let t=JSON.parse(e);return t.shapes&&Array.isArray(t.shapes)?(this.shapes=t.shapes,this.selectedIds=[],this.undoStack=[],this.redoStack=[],this.notifyListeners(),this.scheduleRender(),!0):!1}catch(e){return console.error("\u52A0\u8F7D\u5931\u8D25:",e),false}}clearStorage(){localStorage.removeItem(Ae);}exportJSON(){return JSON.stringify({version:1,shapes:this.shapes,savedAt:Date.now()},null,2)}importJSON(e){try{let t=JSON.parse(e);return t.shapes&&Array.isArray(t.shapes)?(this.commitHistory(),this.shapes=t.shapes,this.selectedIds=[],this.notifyListeners(),this.render(),!0):!1}catch(t){return console.error("\u5BFC\u5165\u5931\u8D25:",t),false}}getEditingShapeId(){return this.editingShapeId}canEditShape(e){return !(e.type==="line"||e.type==="arrow"||e.type==="draw"||e.type==="uml-class"||e.type==="uml-interface"||e.type==="mind-map")}enterEditing(e){let t=this.shapes.find(i=>i.id===e);!t||!this.canEditShape(t)||(this.editingShapeId=e,this.selectedIds=[e],this.isNewTextShape=t.type==="text"&&!t.text,this.originalTextValue=t.text||"",this.notifyListeners(),this.scheduleRender(),requestAnimationFrame(()=>{this.createTextInput(t);}));}exitEditing(){if(!this.editingShapeId)return;let e=this.editingShapeId,t=this.shapes.find(n=>n.id===e),i=this.textInput?this.textInput.value:"";if(this.removeTextInput(),t)if(t.type==="text")if(this.commitHistory(),!i.trim()&&this.isNewTextShape)this.shapes=this.shapes.filter(n=>n.id!==e),this.selectedIds=this.selectedIds.filter(n=>n!==e);else {let n=t,s=n.fontSize||16,r=s*1.3,o=n.width||200,a=i.split(`
|
|
3
|
+
`),h=0;for(let c of a){let p="";for(let g of c){let m=p+g;m.length*s*.6>o&&p?(h++,p=g):p=m;}p&&h++;}let l={...n,text:i,height:Math.max(h*r,r)},u=this.shapes.indexOf(t);u!==-1&&(this.shapes[u]=l),i.trim()||(this.shapes=this.shapes.filter(c=>c.id!==e),this.selectedIds=this.selectedIds.filter(c=>c!==e));}else this.commitHistory(),this.updateShape(e,{text:i,textColor:t.textColor||v.text,fontSize:t.fontSize||16});this.editingShapeId=null,this.isNewTextShape=false,this.originalTextValue="",this.setActiveTool("select"),this.notifyListeners(),this.render();}removeTextInput(){this.textOverlay&&(this.textOverlay.remove(),this.textOverlay=null),this.textInput&&(this.textInput.remove(),this.textInput=null);}createTextInput(e){this.removeTextInput();let t=this.canvas.parentElement;if(!t)return;let i=this.canvas.getBoundingClientRect(),n=t.getBoundingClientRect(),s=i.left-n.left,r=i.top-n.top;this.textOverlay=document.createElement("div"),this.textOverlay.style.position="absolute",this.textOverlay.style.left=`${s}px`,this.textOverlay.style.top=`${r}px`,this.textOverlay.style.width=`${i.width}px`,this.textOverlay.style.height=`${i.height}px`,this.textOverlay.style.background="transparent",this.textOverlay.style.zIndex="1000",this.textOverlay.style.cursor="text",this.textOverlay.addEventListener("pointerdown",u=>{this.textInput&&u.target!==this.textInput&&(u.preventDefault(),this.exitEditing());}),t.appendChild(this.textOverlay);let o=this.getShapeScreenBounds(e),a=this.camera.getZoom(),h=(e.fontSize||16)*a,l=document.createElement("textarea");l.style.position="absolute",l.style.left=`${s+o.x}px`,l.style.top=`${r+o.y}px`,l.style.width=`${Math.max(o.width,60)}px`,l.style.height=`${Math.max(o.height,24)}px`,l.style.fontSize=`${h}px`,l.style.color=e.textColor||"#1f2937",l.style.textAlign="center",l.style.border=`2px solid ${v.editBorder}`,l.style.borderRadius="4px",l.style.background="rgba(255, 255, 255, 0.95)",l.style.resize="none",l.style.padding="4px 8px",l.style.boxSizing="border-box",l.style.lineHeight="1.4",l.style.fontFamily="sans-serif",l.style.outline="none",l.style.whiteSpace="pre-wrap",l.style.wordBreak="break-word",l.style.overflow="hidden",l.style.zIndex="1001",l.value=e.text||"",l.dataset.shapeId=e.id,l.addEventListener("pointerdown",u=>{u.stopPropagation();}),l.addEventListener("mousedown",u=>{u.stopPropagation();}),l.addEventListener("keydown",u=>{if(u.stopPropagation(),u.key==="Escape"&&(u.preventDefault(),this.textInput&&(this.textInput.value=this.originalTextValue),this.exitEditing()),u.key==="Enter"&&!u.shiftKey&&(u.preventDefault(),this.exitEditing()),u.key==="Enter"&&u.shiftKey){u.preventDefault();let c=l.selectionStart,p=l.selectionEnd;l.value=l.value.substring(0,c)+`
|
|
4
|
+
`+l.value.substring(p),l.selectionStart=l.selectionEnd=c+1;}}),t.appendChild(l),l.focus(),e.type==="text"&&!e.text&&(l.placeholder="\u8F93\u5165\u6587\u672C..."),this.textInput=l;}getShapeScreenBounds(e){let t=this.camera.getZoom(),i=this.camera.pageToScreen({x:e.x,y:e.y});switch(e.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "hexagon":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":return {x:i.x-e.width*t/2,y:i.y-e.height*t/2,width:e.width*t,height:e.height*t};case "circle":return {x:i.x-e.radius*t,y:i.y-e.radius*t,width:e.radius*2*t,height:e.radius*2*t};case "text":{let n=e,s=n.width*t,r=n.height*t;return {x:i.x-s/2,y:i.y-r/2,width:s,height:r}}default:return {x:i.x-50*t,y:i.y-20*t,width:100*t,height:40*t}}}getShapeAtScreenPoint(e){let t=this.screenToPage(e);return this.getShapeAtPoint(t)}getShapeAtPoint(e,t){for(let i=this.shapes.length-1;i>=0;i--){let n=this.shapes[i];if(!(t&&n.id===t)&&this.isPointInShape(e,n))return n}return null}getShapesInBrushRadius(e,t){let i=[];for(let n of this.shapes)this.shapeIntersectsBrush(n,e,t)&&i.push(n);return i}shapeIntersectsBrush(e,t,i){switch(e.type){case "line":case "arrow":case "draw":{let n=e.points,s=i+4;for(let r=1;r<n.length;r++)if(this.pointToSegmentDist(t,n[r-1],n[r])<=s)return true;return n.length>0&&Math.hypot(t.x-n[0].x,t.y-n[0].y)<=s}case "circle":return Math.hypot(t.x-e.x,t.y-e.y)<=e.radius+i;case "text":{let n=e;return Math.abs(t.x-e.x)<=n.width/2+i&&Math.abs(t.y-e.y)<=n.height/2+i}default:return Math.abs(t.x-e.x)<=e.width/2+i&&Math.abs(t.y-e.y)<=e.height/2+i}}pointToSegmentDist(e,t,i){let n=i.x-t.x,s=i.y-t.y,r=n*n+s*s,o=r===0?0:Math.max(0,Math.min(1,((e.x-t.x)*n+(e.y-t.y)*s)/r));return Math.hypot(e.x-(t.x+o*n),e.y-(t.y+o*s))}setEraserPoint(e){this.eraserPoint=e,this.scheduleRender();}isPointInShape(e,t){let i=e.x-t.x,n=e.y-t.y;switch(t.type){case "rectangle":case "rounded-rectangle":case "ellipse":case "diamond":case "triangle":case "parallelogram":case "trapezoid":case "pentagon":case "octagon":case "star":case "uml-class":case "uml-interface":return Math.abs(i)<=t.width/2&&Math.abs(n)<=t.height/2;case "circle":return i*i+n*n<=t.radius*t.radius;case "hexagon":{let s=t.width/2,r=t.height/2;return Math.abs(i)<=s&&Math.abs(n)<=r&&Math.abs(i)/s+Math.abs(n)/r<=1.5}case "mind-map":return Math.abs(i)<=t.width/2&&Math.abs(n)<=t.height/2;case "text":{let s=t;return Math.abs(i)<=s.width/2&&Math.abs(n)<=s.height/2}default:return false}}updateArrowBinding(e,t,i,n){let s=this.shapes.find(a=>a.id===e);if(!s||s.type!=="arrow")return;let r=s,o={};if(i){let a=this.shapes.find(c=>c.id===i);if(!a)return;let h=n?.handle||this.getClosestHandle(r,a),l=this.getBindingPosition(a,h),u=n?{...n,toShapeId:i}:{toShapeId:i,handle:h};t==="start"?(o.startBinding=u,o.points=r.points.map((c,p)=>p===0?l:c)):(o.endBinding=u,o.points=r.points.map((c,p)=>p===r.points.length-1?l:c));}else t==="start"?o.startBinding=void 0:o.endBinding=void 0;this.updateShape(e,o);}getClosestHandle(e,t){let i=e.points[0],n=e.points[e.points.length-1],s=e.endBinding?n:i,r=s.x-t.x,o=s.y-t.y;return Math.abs(r)>Math.abs(o)?r>0?"right":"left":o>0?"bottom":"top"}dispose(){this.canvas.removeEventListener("pointerdown",this.handlePointerDown),this.canvas.removeEventListener("pointermove",this.handlePointerMove),this.canvas.removeEventListener("pointerup",this.handlePointerUp),this.canvas.removeEventListener("pointerleave",this.handlePointerUp),this.canvas.removeEventListener("wheel",this.handleWheel),window.removeEventListener("keydown",this.handleKeyDown),window.removeEventListener("keyup",this.handleKeyUp),window.removeEventListener("resize",this.handleResize),this.removeTextInput(),this.tools.forEach(e=>e.dispose()),this.listeners.clear();}};export{ae as ArrowTool,ee as Camera,Le as Editor,Q as FreehandTool,re as HandTool,oe as LineTool,Te as MINDMAP_COLORS,pe as MINDMAP_FONT_SIZE,Xe as MINDMAP_MAX_WIDTH,Ye as MINDMAP_MIN_WIDTH,We as MINDMAP_NODE_HEIGHT,Y as Mat2d,ie as Renderer,se as SelectTool,R as ShapeTool,v as THEME,W as UML_FONT_SIZE,X as UML_HEADER_HEIGHT,V as UML_LINE_HEIGHT,ne as UML_MIN_WIDTH,$ as UML_PADDING_X,L as UML_PADDING_Y,j as Vec,xe as calcUmlClassSize,ye as cloneMindMapNode,Be as countMindMapNodes,F as findMindMapNode,$e as getLanguage,ke as getMindMapNodeDepth,te as getMindMapParent,Oe as getTheme,q as hexToRgba,k as layoutMindMap,ge as mindMapNodeColor,Ve as mindMapNodeSize,ue as setLanguage,de as setTheme,ze as shadeColor,Ke as subscribeLanguage,Ge as subscribeTheme,z as t};
|