json-canvas-viewer 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -79,7 +79,7 @@ If you are coding in TypeScript, and intend to retrieve Custom Event callback, p
79
79
  const viewer: canvasViewer = new canvasViewer(...);
80
80
  viewer.loadCanvas(...);
81
81
  viewer.addEventListener('...', (e: Event) => {
82
- if (e instanceof CustomEvent) {
82
+ if (e instanceof CustomEvent) {
83
83
  // use e.detail safely here
84
84
  console.log(e.detail);
85
85
  };
@@ -1,2 +1,2 @@
1
- "use strict";const M=require("marked"),m=new Error("This error is unexpected, probably caused by file corruption. If you assure the error is not caused by accident, please contact the author and show how to reproduce."),l=new Error("Resource hasn't been set up or has been disposed.");class L{constructor(t){this._nodeMap=null,this._canvasData=null,this.ARROW_LENGTH=12,this.ARROW_WIDTH=7,this.FILE_NODE_RADIUS=12,this.FONT_COLOR="#fff",this.CSS_ZOOM_REDRAW_INTERVAL=500,this._canvas=document.createElement("canvas"),this._canvas.className="main-canvas",this._container=t,this._container.appendChild(this._canvas),this._ctx=this._canvas.getContext("2d"),this.zoomInOptimize={lastDrawnScale:0,lastDrawnViewport:{left:0,right:0,top:0,bottom:0},timeout:null,lastCallTime:0},y(this._canvas,t.offsetWidth,t.offsetHeight)}get nodeMap(){if(this._nodeMap===null)throw l;return this._nodeMap}get canvasData(){if(this._canvasData===null)throw l;return this._canvasData}get canvas(){if(this._canvas===null)throw l;return this._canvas}get ctx(){if(this._ctx===null)throw l;return this._ctx}get container(){if(this._container===null)throw l;return this._container}receiveData(t,e){this._nodeMap=t,this._canvasData=e}resizeCanvasForDPR(){y(this.canvas,this.container.offsetWidth,this.container.offsetHeight)}redraw(t,e,n){this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=null);const i=Date.now(),o=this.getCurrentViewport(t,e,n);if(this.isViewportInside(o,this.zoomInOptimize.lastDrawnViewport)&&n!==this.zoomInOptimize.lastDrawnScale&&i-this.zoomInOptimize.lastCallTime<this.CSS_ZOOM_REDRAW_INTERVAL){this.zoomInOptimize.timeout=setTimeout(()=>{this.trueRedraw(t,e,n,o),this.zoomInOptimize.lastCallTime=i,this.zoomInOptimize.timeout=null},60),this.fakeRedraw(o,n);return}this.zoomInOptimize.lastCallTime=i,this.trueRedraw(t,e,n,o)}dispose(){this.zoomInOptimize.timeout&&clearTimeout(this.zoomInOptimize.timeout),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.remove(),this.zoomInOptimize.timeout=null,this._ctx=null,this._canvas=null,this._container=null,this._canvasData=null,this._nodeMap=null}trueRedraw(t,e,n,i){this.zoomInOptimize.lastDrawnViewport=i,this.zoomInOptimize.lastDrawnScale=n,this.canvas.style.transform="",this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.save(),this.ctx.translate(t,e),this.ctx.scale(n,n),this.canvasData.nodes.forEach(o=>o.inViewport=this.isNodeInViewport(o,t,e,n)),this.canvasData.nodes.forEach(o=>{switch(o.type){case"group":this.drawGroup(o,n);break;case"file":this.drawFileNode(o);break}}),this.canvasData.edges.forEach(o=>this.drawEdge(o)),this.ctx.restore()}fakeRedraw(t,e){const n=e/this.zoomInOptimize.lastDrawnScale,i=(this.zoomInOptimize.lastDrawnViewport.left-t.left)*e,o=(this.zoomInOptimize.lastDrawnViewport.top-t.top)*e;this.canvas.style.transform=`translate(${i}px, ${o}px) scale(${n})`}isViewportInside(t,e){return t.left>e.left&&t.top>e.top&&t.right<e.right&&t.bottom<e.bottom}isNodeInViewport(t,e,n,i,o=200){const s=-e/i-o,r=-n/i-o,a=s+this.container.clientWidth/i+2*o,c=r+this.container.clientHeight/i+2*o;return t.x+t.width>s&&t.x<a&&t.y+t.height>r&&t.y<c}getCurrentViewport(t,e,n){const i=-t/n,o=-e/n,s=i+this.container.clientWidth/n,r=o+this.container.clientHeight/n;return{left:i,top:o,right:s,bottom:r}}drawLabelBar(t,e,n,i,o){const s=30*o,r=6*o,a=8*o,c=16*o,p=6*o;this.ctx.save(),this.ctx.translate(t,e),this.ctx.scale(1/o,1/o),this.ctx.font=`${c}px 'Inter', sans-serif`;const d=this.ctx.measureText(n).width+2*p;this.ctx.translate(0,-s-a),this.ctx.fillStyle=i,this.ctx.beginPath(),this.ctx.moveTo(r,0),this.ctx.lineTo(d-r,0),this.ctx.quadraticCurveTo(d,0,d,r),this.ctx.lineTo(d,s-r),this.ctx.quadraticCurveTo(d,s,d-r,s),this.ctx.lineTo(r,s),this.ctx.quadraticCurveTo(0,s,0,s-r),this.ctx.lineTo(0,r),this.ctx.quadraticCurveTo(0,0,r,0),this.ctx.closePath(),this.ctx.fill(),this.ctx.fillStyle=this.FONT_COLOR,this.ctx.fillText(n,p,s*.65),this.ctx.restore()}drawNodeBackground(t){const e=E(t.color),n=this.FILE_NODE_RADIUS;this.ctx.globalAlpha=1,this.ctx.fillStyle=e.background,C(this.ctx,t.x+1,t.y+1,t.width-2,t.height-2,n),this.ctx.fill(),this.ctx.strokeStyle=e.border,this.ctx.lineWidth=2,C(this.ctx,t.x,t.y,t.width,t.height,n),this.ctx.stroke()}drawGroup(t,e){this.drawNodeBackground(t),t.label&&this.drawLabelBar(t.x,t.y,t.label,E(t.color).border,e)}drawFileNode(t){if(!t.file)throw m;t.file.match(/\.md|png|jpg|jpeg|gif|svg$/i)||(this.drawNodeBackground(t),t.file.match(/\.mp3$/i)&&(this.ctx.fillStyle=this.FONT_COLOR,this.ctx.textAlign="center",this.ctx.textBaseline="middle",this.ctx.fillText("🎵 Click to Preview 🎵",t.x+t.width/2,t.y+t.height/2),this.ctx.textAlign="left")),this.ctx.fillStyle=this.FONT_COLOR,this.ctx.font="16px sans-serif",this.ctx.fillText(t.file,t.x+5,t.y-10)}drawEdge(t){const{fromNode:e,toNode:n}=this.getEdgeNodes(t);if(!e||!n)throw m;const[i,o]=_(e,t.fromSide),[s,r]=_(n,t.toSide);let[a,c,p,d]=[0,0,0,0];if(t.controlPoints?[a,c,p,d]=t.controlPoints:([a,c,p,d]=this.getControlPoints(i,o,s,r,t.fromSide,t.toSide),t.controlPoints=[a,c,p,d]),this.drawCurvedPath(i,o,s,r,a,c,p,d),this.drawArrowhead(s,r,p,d),t.label){const v=Math.pow(.5,3)*i+3*Math.pow(.5,2)*.5*a+.375*p+Math.pow(.5,3)*s,f=Math.pow(1-.5,3)*o+3*Math.pow(1-.5,2)*.5*c+3*(1-.5)*.5*.5*d+Math.pow(.5,3)*r;this.ctx.font="18px sans-serif";const x=this.ctx.measureText(t.label).width+8*2,b=20;this.ctx.fillStyle="#222",this.ctx.beginPath(),C(this.ctx,v-x/2,f-b/2-2,x,b,4),this.ctx.fill(),this.ctx.fillStyle="#ccc",this.ctx.textAlign="center",this.ctx.textBaseline="middle",this.ctx.fillText(t.label,v,f-2),this.ctx.textAlign="left",this.ctx.textBaseline="alphabetic"}}getEdgeNodes(t){return{fromNode:this.nodeMap[t.fromNode],toNode:this.nodeMap[t.toNode]}}getControlPoints(t,e,n,i,o,s){const r=n-t,a=i-e,c=Math.min(Math.abs(r),Math.abs(a))+.3*Math.max(Math.abs(r),Math.abs(a)),d=((w,x,b)=>Math.max(x,Math.min(b,w)))(c*.5,60,300);let u=t,v=e,f=n,g=i;switch(o){case"top":v=e-d;break;case"bottom":v=e+d;break;case"left":u=t-d;break;case"right":u=t+d;break}switch(s){case"top":g=i-d;break;case"bottom":g=i+d;break;case"left":f=n-d;break;case"right":f=n+d;break}return[u,v,f,g]}drawCurvedPath(t,e,n,i,o,s,r,a){this.ctx.beginPath(),this.ctx.moveTo(t,e),this.ctx.bezierCurveTo(o,s,r,a,n,i),this.ctx.strokeStyle="#ccc",this.ctx.lineWidth=2,this.ctx.stroke()}drawArrowhead(t,e,n,i){const o=t-n,s=e-i,r=Math.sqrt(o*o+s*s);if(r===0)return;const a=o/r,c=s/r,p=t-a*this.ARROW_LENGTH-c*this.ARROW_WIDTH,d=e-c*this.ARROW_LENGTH+a*this.ARROW_WIDTH,u=t-a*this.ARROW_LENGTH+c*this.ARROW_WIDTH,v=e-c*this.ARROW_LENGTH-a*this.ARROW_WIDTH;this.ctx.beginPath(),this.ctx.fillStyle="#ccc",this.ctx.moveTo(t,e),this.ctx.lineTo(p,d),this.ctx.lineTo(u,v),this.ctx.closePath(),this.ctx.fill()}}function _(h,t){const e=h.x+h.width/2,n=h.y+h.height/2;switch(t){case"top":return[e,h.y];case"bottom":return[e,h.y+h.height];case"left":return[h.x,n];case"right":return[h.x+h.width,n];default:return[e,n]}}function C(h,t,e,n,i,o){h.beginPath(),h.moveTo(t+o,e),h.lineTo(t+n-o,e),h.quadraticCurveTo(t+n,e,t+n,e+o),h.lineTo(t+n,e+i-o),h.quadraticCurveTo(t+n,e+i,t+n-o,e+i),h.lineTo(t+o,e+i),h.quadraticCurveTo(t,e+i,t,e+i-o),h.lineTo(t,e+o),h.quadraticCurveTo(t,e,t+o,e),h.closePath()}function E(h){let t=null;switch(h){case"1":t="rgba(255, 120, 129, ?)";break;case"2":t="rgba(251, 187, 131, ?)";break;case"3":t="rgba(255, 232, 139, ?)";break;case"4":t="rgba(124, 211, 124, ?)";break;case"5":t="rgba(134, 223, 226, ?)";break;case"6":t="rgba(203, 158, 255, ?)";break;default:t="rgba(140, 140, 140, ?)"}return{border:t.replace("?","0.75"),background:t.replace("?","0.1"),active:t.replace("?","1")}}function y(h,t,e){const n=window.devicePixelRatio||1,i=h.getContext("2d");if(!i)throw m;h.width=Math.round(t*n),h.height=Math.round(e*n),i.setTransform(1,0,0,1,0,0),i.scale(n,n)}class z extends EventTarget{constructor(t,e){super(),this.pointers=new Map,this.onPointerDown=i=>{if(!(this.pointers.size>=2)&&(i.isPrimary&&this.pointers.clear(),this.pointers.set(i.pointerId,{startX:i.clientX,startY:i.clientY,lastX:i.clientX,lastY:i.clientY,interrupted:!1,target:i.target}),this.pointers.size===2)){const o=this.getNthValue(0),s=this.pointers.get(i.pointerId);if(!o||!s)throw m;o.interrupted=!0,s.interrupted=!0,this.pinchZoomState.lastDistance=this.getPointerDistance(),this.pinchZoomState.lastMidpoint=this.S2C(this.getPointerMidpoint())}},this.onPointerMove=i=>{const o=this.pointers.get(i.pointerId);if(o){if(this.pointers.size===1){const s=i.clientX-o.lastX,r=i.clientY-o.lastY;this.dispatchPanEvent({x:s,y:r})}if(this.pointers.set(i.pointerId,{startX:o.startX,startY:o.startY,lastX:i.clientX,lastY:i.clientY,interrupted:o.interrupted,target:o.target}),this.pointers.size===2){const s=this.getPointerDistance(),r=this.getPointerMidpoint();if(!s||!r)throw m;let a=s/this.pinchZoomState.lastDistance;this.pinchZoomState.lastDistance=s;const c=this.S2C(r),p=c.x-this.pinchZoomState.lastMidpoint.x,d=c.y-this.pinchZoomState.lastMidpoint.y;this.pinchZoomState.lastMidpoint=c,this.dispatchPanEvent({x:p,y:d}),this.dispatchZoomEvent(a,c)}}},this.onPointerUp=i=>{const o=this.pointers.get(i.pointerId);if(o&&(this.pointers.delete(i.pointerId),this.pointers.size===0&&!o.interrupted&&Math.abs(o.startX-i.clientX)+Math.abs(o.startY-i.clientY)<5)){const s=this.S2C({x:i.clientX,y:i.clientY}),r=new CustomEvent("trueClick",{detail:{position:s,target:o.target}});this.dispatchEvent(r)}},this.onWheel=i=>{if(!this.lockControlSchema&&!this.proControlSchema&&(i.ctrlKey||Math.abs(i.deltaX)>Math.abs(i.deltaY))&&(this.proControlSchema=!0),this.preventDefault&&i.preventDefault(),this.proControlSchema&&!i.ctrlKey)this.dispatchPanEvent({x:i.deltaX,y:i.deltaY});else{const o=1-this.zoomFactor*i.deltaY,s=this.S2C({x:i.clientX,y:i.clientY});this.dispatchZoomEvent(o,s)}},this.preventDefaultFunction=i=>i.preventDefault,this._monitoringElement=t;const n=e||{};this.preventDefault=n.preventDefault||!1,this.proControlSchema=n.proControlSchema||!1,this.zoomFactor=n.zoomFactor||.002,this.lockControlSchema=n.lockControlSchema||!1,this.pointers.clear(),this.pinchZoomState={lastDistance:0,lastMidpoint:{x:0,y:0}},this.panDump={x:0,y:0},this.zoomDump={factor:1,origin:{x:0,y:0}}}get monitoringElement(){if(this._monitoringElement===null)throw l;return this._monitoringElement}getNthValue(t){if(t<0||t>=this.pointers.size)throw m;let e=0;for(const n of this.pointers.values()){if(e===t)return n;e++}}getPointerDistance(){const t=this.getNthValue(0),e=this.getNthValue(1);if(!t||!e)throw m;const n=t.lastX-e.lastX,i=t.lastY-e.lastY;return Math.sqrt(n*n+i*i)}getPointerMidpoint(){const t=this.getNthValue(0),e=this.getNthValue(1);if(!t||!e)throw m;return{x:(t.lastX+e.lastX)/2,y:(t.lastY+e.lastY)/2}}S2C({x:t,y:e}){const n=this.monitoringElement.getBoundingClientRect();return{x:t-n.left,y:e-n.top}}dispatchPanEvent(t){const e={x:this.round(t.x,1),y:this.round(t.y,1)};this.panDump.x+=e.x,this.panDump.y+=e.y;const n=new CustomEvent("pan",{detail:e});this.dispatchEvent(n)}dispatchZoomEvent(t,e){const n=this.round(t,4);this.zoomDump.factor*=n,this.zoomDump.origin=e;const i=new CustomEvent("zoom",{detail:{factor:n,origin:e}});this.dispatchEvent(i)}round(t,e){const n=10**e;return Math.round(t*n)/n}getZoomDump(){return this.zoomDump}resetZoomDump(){this.zoomDump.factor=1}getPanDump(){return this.panDump}resetPanDump(){this.panDump={x:0,y:0}}stop(){this.monitoringElement.removeEventListener("pointerdown",this.onPointerDown),window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp),this.monitoringElement.removeEventListener("wheel",this.onWheel),this.preventDefault&&(this.monitoringElement.style.touchAction="",this.monitoringElement.removeEventListener("gesturestart",this.preventDefaultFunction),this.monitoringElement.removeEventListener("gesturechange",this.preventDefaultFunction))}start(){this.monitoringElement.addEventListener("pointerdown",this.onPointerDown),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp),this.monitoringElement.addEventListener("wheel",this.onWheel,this.preventDefault?{passive:!1}:{}),this.preventDefault&&(this.monitoringElement.style.touchAction="none",this.monitoringElement.addEventListener("gesturestart",this.preventDefaultFunction,{passive:!1}),this.monitoringElement.addEventListener("gesturechange",this.preventDefaultFunction,{passive:!1}))}dispose(){this.stop(),this.pointers.clear(),this._monitoringElement=null}}class D extends EventTarget{constructor(t,e=!1){super(),this._canvasData=null,this._nodeMap=null,this._nodeBounds=null,this.toggleVisisbility=()=>{this.isMinimapVisible=!this.isMinimapVisible,this.minimapContainer.classList.toggle("collapsed"),this.dispatchEvent(new CustomEvent(this.isMinimapVisible?"minimapExpanded":"minimapCollapsed"))},this._minimapContainer=document.createElement("div"),this._minimapContainer.className="minimap-container",this._toggleMinimapBtn=document.createElement("button"),this._toggleMinimapBtn.className="toggle-minimap collapse-button",this._toggleMinimapBtn.innerHTML='<svg viewBox="-3.6 -3.6 31.2 31.2" stroke-width=".4"><path d="M15.707 4.293a1 1 0 0 1 0 1.414L9.414 12l6.293 6.293a1 1 0 0 1-1.414 1.414l-7-7a1 1 0 0 1 0-1.414l7-7a1 1 0 0 1 1.414 0Z" /></svg>',this._minimapContainer.appendChild(this._toggleMinimapBtn),this._minimap=document.createElement("div"),this._minimap.className="minimap";const n=document.createElement("canvas");n.className="minimap-canvas",n.width=200,n.height=150,this._minimap.appendChild(n),this._minimapCtx=n.getContext("2d"),this._viewportRectangle=document.createElement("div"),this._viewportRectangle.className="viewport-rectangle",this._minimap.appendChild(this._viewportRectangle),this._minimapContainer.appendChild(this._minimap),t.appendChild(this._minimapContainer),this._container=t,this.isMinimapVisible=!e,this._minimapContainer.classList.toggle("collapsed",e),this.minimapCache={scale:1,centerX:0,centerY:0},this._toggleMinimapBtn.addEventListener("click",this.toggleVisisbility),y(n,n.width,n.height)}get minimapCtx(){if(this._minimapCtx===null)throw l;return this._minimapCtx}get canvasData(){if(this._canvasData===null)throw l;return this._canvasData}get container(){if(this._container===null)throw l;return this._container}get minimap(){if(this._minimap===null)throw l;return this._minimap}get nodeBounds(){if(this._nodeBounds===null)throw l;return this._nodeBounds}get nodeMap(){if(this._nodeMap===null)throw l;return this._nodeMap}get viewportRectangle(){if(this._viewportRectangle===null)throw l;return this._viewportRectangle}get minimapContainer(){if(this._minimapContainer===null)throw l;return this._minimapContainer}get toggleMinimapBtn(){if(this._toggleMinimapBtn===null)throw l;return this._toggleMinimapBtn}receiveData(t,e,n){this._nodeBounds=t,this._canvasData=e,this._nodeMap=n,this.drawMinimap()}drawMinimap(){const t=this.nodeBounds;if(!t)return;const e=this.minimap.clientWidth,n=this.minimap.clientHeight,i=e/t.width,o=n/t.height;this.minimapCache.scale=Math.min(i,o)*.9,this.minimapCache.centerX=e/2,this.minimapCache.centerY=n/2,this.minimapCtx.clearRect(0,0,e,n),this.minimapCtx.save(),this.minimapCtx.translate(this.minimapCache.centerX,this.minimapCache.centerY),this.minimapCtx.scale(this.minimapCache.scale,this.minimapCache.scale),this.minimapCtx.translate(-t.centerX,-t.centerY);for(let s of this.canvasData.edges)this.drawMinimapEdge(s);for(let s of this.canvasData.nodes)this.drawMinimapNode(s);this.minimapCtx.restore()}drawMinimapNode(t){const e=E(t.color),n=25;this.minimapCtx.fillStyle=e.border,this.minimapCtx.globalAlpha=.3,C(this.minimapCtx,t.x,t.y,t.width,t.height,n),this.minimapCtx.fill(),this.minimapCtx.globalAlpha=1}drawMinimapEdge(t){const e=this.nodeMap[t.fromNode],n=this.nodeMap[t.toNode];if(!e||!n)return;const[i,o]=_(e,t.fromSide),[s,r]=_(n,t.toSide);this.minimapCtx.beginPath(),this.minimapCtx.moveTo(i,o),this.minimapCtx.lineTo(s,r),this.minimapCtx.strokeStyle="#555",this.minimapCtx.lineWidth=10,this.minimapCtx.stroke()}updateViewportRectangle(t,e,n){if(!this.isMinimapVisible)return;const i=this.nodeBounds;if(!i)return;const o=this.container.clientWidth/n,s=this.container.clientHeight/n,r=-t/n+this.container.clientWidth/(2*n),a=-e/n+this.container.clientHeight/(2*n),c=this.minimapCache.centerX+(r-o/2-i.centerX)*this.minimapCache.scale,p=this.minimapCache.centerY+(a-s/2-i.centerY)*this.minimapCache.scale,d=o*this.minimapCache.scale,u=s*this.minimapCache.scale;this.viewportRectangle.style.left=c+"px",this.viewportRectangle.style.top=p+"px",this.viewportRectangle.style.width=d+"px",this.viewportRectangle.style.height=u+"px"}dispose(){this.toggleMinimapBtn.removeEventListener("click",this.toggleVisisbility),this.minimapCtx.clearRect(0,0,this.minimap.clientWidth,this.minimap.clientHeight),this.minimapContainer.remove(),this._minimapContainer=null,this._minimapCtx=null,this._toggleMinimapBtn=null,this._canvasData=null,this._container=null,this._nodeMap=null,this._nodeBounds=null,this._viewportRectangle=null,this._minimap=null}}class S extends EventTarget{constructor(t,e=!1){super(),this.toggleCollapse=()=>this.controlsPanel.classList.toggle("collapsed"),this.zoomIn=()=>this.dispatchEvent(new CustomEvent("zoomIn")),this.zoomOut=()=>this.dispatchEvent(new CustomEvent("zoomOut")),this.slide=()=>this.dispatchEvent(new CustomEvent("slide",{detail:Math.pow(1.1,Number(this.zoomSlider.value))})),this.resetView=()=>this.dispatchEvent(new CustomEvent("resetView")),this.toggleFullscreen=()=>this.dispatchEvent(new CustomEvent("toggleFullscreen")),this.updateSlider=i=>this.zoomSlider.value=String(this.scaleToSlider(i)),this.scaleToSlider=i=>Math.log(i)/Math.log(1.1),this._controlsPanel=document.createElement("div"),this._controlsPanel.className="controls",this._controlsPanel.classList.toggle("collapsed",e),this._toggleCollapseBtn=document.createElement("button"),this._toggleCollapseBtn.className="collapse-button",this._toggleCollapseBtn.innerHTML='<svg viewBox="-3.6 -3.6 31.2 31.2" stroke-width=".4"><path d="M15.707 4.293a1 1 0 0 1 0 1.414L9.414 12l6.293 6.293a1 1 0 0 1-1.414 1.414l-7-7a1 1 0 0 1 0-1.414l7-7a1 1 0 0 1 1.414 0Z" /></svg>',this._controlsPanel.appendChild(this._toggleCollapseBtn);const n=document.createElement("div");n.className="controls-content",this._toggleFullscreenBtn=document.createElement("button"),this._toggleFullscreenBtn.innerHTML='<svg viewBox="-5.28 -5.28 34.56 34.56" fill="none"><path d="M4 9V5.6c0-.56 0-.84.109-1.054a1 1 0 0 1 .437-.437C4.76 4 5.04 4 5.6 4H9M4 15v3.4c0 .56 0 .84.109 1.054a1 1 0 0 0 .437.437C4.76 20 5.04 20 5.6 20H9m6-16h3.4c.56 0 .84 0 1.054.109a1 1 0 0 1 .437.437C20 4.76 20 5.04 20 5.6V9m0 6v3.4c0 .56 0 .84-.109 1.054a1 1 0 0 1-.437.437C19.24 20 18.96 20 18.4 20H15" stroke-width="2.4" stroke-linecap="round"/></svg>',n.appendChild(this._toggleFullscreenBtn),this._zoomOutBtn=document.createElement("button"),this._zoomOutBtn.innerHTML='<svg viewBox="-1.2 -1.2 26.4 26.4"><path d="M6 12h12" stroke-width="2" stroke-linecap="round" /></svg>',n.appendChild(this._zoomOutBtn),this._zoomSlider=document.createElement("input"),this._zoomSlider.type="range",this._zoomSlider.className="zoom-slider",this._zoomSlider.min="-30",this._zoomSlider.max="30",this._zoomSlider.value="0",n.appendChild(this._zoomSlider),this._zoomInBtn=document.createElement("button"),this._zoomInBtn.innerHTML='<svg viewBox="-1.2 -1.2 26.4 26.4"><path d="M6 12h12m-6-6v12" stroke-width="2" stroke-linecap="round" /></svg>',n.appendChild(this._zoomInBtn),this._resetViewBtn=document.createElement("button"),this._resetViewBtn.innerHTML='<svg viewBox="-6 -6 30 30" stroke-width=".08"><path d="m14.955 7.986.116.01a1 1 0 0 1 .85 1.13 8 8 0 0 1-13.374 4.728l-.84.84c-.63.63-1.707.184-1.707-.707V10h3.987c.89 0 1.337 1.077.707 1.707l-.731.731a6 6 0 0 0 8.347-.264 6 6 0 0 0 1.63-3.33 1 1 0 0 1 1.131-.848zM11.514.813a8 8 0 0 1 1.942 1.336l.837-.837c.63-.63 1.707-.184 1.707.707V6h-3.981c-.89 0-1.337-1.077-.707-1.707l.728-.729a6 6 0 0 0-9.98 3.591 1 1 0 1 1-1.98-.281A8 8 0 0 1 11.514.813Z" /></svg>',n.appendChild(this._resetViewBtn),this._controlsPanel.appendChild(n),t.appendChild(this._controlsPanel),this._toggleCollapseBtn.addEventListener("click",this.toggleCollapse),this._zoomInBtn.addEventListener("click",this.zoomIn),this._zoomOutBtn.addEventListener("click",this.zoomOut),this._zoomSlider.addEventListener("input",this.slide),this._resetViewBtn.addEventListener("click",this.resetView),this._toggleFullscreenBtn.addEventListener("click",this.toggleFullscreen)}get controlsPanel(){if(this._controlsPanel===null)throw l;return this._controlsPanel}get toggleCollapseBtn(){if(this._toggleCollapseBtn===null)throw l;return this._toggleCollapseBtn}get toggleFullscreenBtn(){if(this._toggleFullscreenBtn===null)throw l;return this._toggleFullscreenBtn}get zoomOutBtn(){if(this._zoomOutBtn===null)throw l;return this._zoomOutBtn}get zoomSlider(){if(this._zoomSlider===null)throw l;return this._zoomSlider}get zoomInBtn(){if(this._zoomInBtn===null)throw l;return this._zoomInBtn}get resetViewBtn(){if(this._resetViewBtn===null)throw l;return this._resetViewBtn}updateFullscreenBtn(){document.fullscreenElement===null?this.toggleFullscreenBtn.innerHTML='<svg viewBox="-40.32 -40.32 176.64 176.64"><path d="M30 60H6a6 6 0 0 0 0 12h18v18a6 6 0 0 0 12 0V66a5.997 5.997 0 0 0-6-6Zm60 0H66a5.997 5.997 0 0 0-6 6v24a6 6 0 0 0 12 0V72h18a6 6 0 0 0 0-12ZM66 36h24a6 6 0 0 0 0-12H72V6a6 6 0 0 0-12 0v24a5.997 5.997 0 0 0 6 6ZM30 0a5.997 5.997 0 0 0-6 6v18H6a6 6 0 0 0 0 12h24a5.997 5.997 0 0 0 6-6V6a5.997 5.997 0 0 0-6-6Z"/></svg>':this.toggleFullscreenBtn.innerHTML='<svg viewBox="-5.28 -5.28 34.56 34.56" fill="none"><path d="M4 9V5.6c0-.56 0-.84.109-1.054a1 1 0 0 1 .437-.437C4.76 4 5.04 4 5.6 4H9M4 15v3.4c0 .56 0 .84.109 1.054a1 1 0 0 0 .437.437C4.76 20 5.04 20 5.6 20H9m6-16h3.4c.56 0 .84 0 1.054.109a1 1 0 0 1 .437.437C20 4.76 20 5.04 20 5.6V9m0 6v3.4c0 .56 0 .84-.109 1.054a1 1 0 0 1-.437.437C19.24 20 18.96 20 18.4 20H15" stroke-width="2.4" stroke-linecap="round"/></svg>'}dispose(){this.toggleCollapseBtn.removeEventListener("click",this.toggleCollapse),this.zoomInBtn.removeEventListener("click",this.zoomIn),this.zoomOutBtn.removeEventListener("click",this.zoomOut),this.zoomSlider.removeEventListener("input",this.slide),this.resetViewBtn.removeEventListener("click",this.resetView),this.toggleFullscreenBtn.removeEventListener("click",this.toggleFullscreen),this.controlsPanel.remove(),this._controlsPanel=null,this._toggleCollapseBtn=null,this._zoomInBtn=null,this._zoomOutBtn=null,this._zoomSlider=null,this._resetViewBtn=null,this._toggleFullscreenBtn=null}}class I extends EventTarget{constructor(t){super(),this._canvasBaseDir=null,this.hidePreviewModal=()=>{this.previewModalBackdrop.classList.add("hidden"),this.previewModal.classList.add("hidden"),this.dispatchEvent(new CustomEvent("previewModalHidden"))},this._previewModalBackdrop=document.createElement("div"),this._previewModalBackdrop.className="preview-modal-backdrop hidden",t.appendChild(this._previewModalBackdrop),this._previewModal=document.createElement("div"),this._previewModal.className="preview-modal hidden",this._previewModalClose=document.createElement("button"),this._previewModalClose.className="preview-modal-close",this._previewModalClose.innerHTML='<svg viewBox="0 0 24 24"><path d="M6.758 17.243 12.001 12m5.243-5.243L12 12m0 0L6.758 6.757M12.001 12l5.243 5.243" stroke-width="2" stroke-linecap="round" /></svg>',this._previewModal.appendChild(this._previewModalClose),this._previewModalContent=document.createElement("div"),this._previewModalContent.className="preview-modal-content",this._previewModal.appendChild(this._previewModalContent),t.appendChild(this._previewModal),this._previewModalClose.addEventListener("click",this.hidePreviewModal),this._previewModalBackdrop.addEventListener("click",this.hidePreviewModal)}get previewModalBackdrop(){if(!this._previewModalBackdrop)throw l;return this._previewModalBackdrop}get previewModal(){if(!this._previewModal)throw l;return this._previewModal}get previewModalContent(){if(!this._previewModalContent)throw l;return this._previewModalContent}get canvasBaseDir(){if(!this._canvasBaseDir)throw l;return this._canvasBaseDir}get previewModalClose(){if(!this._previewModalClose)throw l;return this._previewModalClose}receiveData(t){this._canvasBaseDir=t}showPreviewModal(t){const e=this.processContent(t);if(!e)throw m;this.previewModalContent.innerHTML="",this.previewModalBackdrop.classList.remove("hidden"),this.previewModal.classList.remove("hidden"),this.previewModalContent.appendChild(e),this.dispatchEvent(new CustomEvent("previewModalShown"))}resize(t,e){this.previewModal.style.setProperty("--preview-max-width",`${t*.9}px`),this.previewModal.style.setProperty("--preview-max-height",`${e*.9}px`)}processContent(t){if(!t.file)throw m;let e;return t.file.match(/\.(png|jpg|jpeg|gif|svg)$/i)?(e=new Image,e.src=this.canvasBaseDir+t.file):t.file.match(/\.mp3$/i)&&(e=document.createElement("audio"),e.controls=!0,e.src=this.canvasBaseDir+t.file),e}dispose(){for(this.previewModalClose.removeEventListener("click",this.hidePreviewModal),this.previewModalBackdrop.removeEventListener("click",this.hidePreviewModal);this.previewModalContent.firstElementChild;)this.previewModalContent.firstElementChild.remove();this.previewModal.remove(),this.previewModalBackdrop.remove(),this._previewModal=null,this._previewModalClose=null,this._previewModalBackdrop=null,this._previewModalContent=null}}class B extends EventTarget{constructor(t){super(),this._nodeMap=null,this._canvasBaseDir=null,this.selectedId=null,this.eventListeners={},this.startInteract=()=>this.dispatchEvent(new CustomEvent("interactionStart")),this.endInteract=()=>this.dispatchEvent(new CustomEvent("interactionEnd")),this._overlaysLayer=document.createElement("div"),this._overlaysLayer.className="overlays",t.appendChild(this.overlaysLayer),this._overlays={}}get nodeMap(){if(!this._nodeMap)throw l;return this._nodeMap}get canvasBaseDir(){if(!this._canvasBaseDir)throw l;return this._canvasBaseDir}get overlays(){if(!this._overlays)throw l;return this._overlays}get overlaysLayer(){if(!this._overlaysLayer)throw l;return this._overlaysLayer}receiveData(t,e){this._canvasBaseDir=t,this._nodeMap=e}select(t){const e=this.selectedId?this.overlays[this.selectedId]:null,n=t?this.overlays[t]:null;e&&e.classList.remove("active"),n?(n.classList.add("active"),this.startInteract()):this.endInteract(),this.selectedId=t}async loadMarkdownForNode(t){if(!t.mdContent){t.mdContent="Loading...",this.updateOrCreateOverlay(t,t.mdContent,"markdown");try{if(!t.file)throw m;const n=await(await fetch(this.canvasBaseDir+t.file)).text(),i=n.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(i){const o=i[1].split(`
2
- `).reduce((s,r)=>{const[a,c]=r.split(":").map(p=>p.trim());return s[a]=c,s},{});t.mdContent=await M.marked.parse(i[2].trim()),t.mdFrontmatter=o}else t.mdContent=await M.marked.parse(n)}catch(e){console.error("Failed to load markdown:",e),t.mdContent="Failed to load content."}}this.updateOrCreateOverlay(t,t.mdContent,"markdown")}updateAllOverlays(t,e,n){this.overlaysLayer.style.transform=`translate(${t}px, ${e}px) scale(${n})`;const i=new Set,o={text:s=>{if(!s.text)throw m;s.inViewport&&(i.add(s.id),this.updateOrCreateOverlay(s,s.text,"text"))},file:s=>{if(!s.file)throw m;s.inViewport&&(i.add(s.id),s.file.match(/\.md$/i)?this.loadMarkdownForNode(s):s.file.match(/\.(png|jpg|jpeg|gif|svg)$/i)&&this.updateOrCreateOverlay(s,this.canvasBaseDir+s.file,"image"))},link:s=>{if(!s.url)throw m;i.add(s.id),this.updateOrCreateOverlay(s,s.url,"link")},group:()=>{}};Object.values(this.nodeMap).forEach(s=>o[s.type](s)),Object.keys(this.overlays).forEach(s=>{if(!i.has(s)){const r=this.overlays[s];r&&r.parentNode&&r.parentNode.removeChild(r),delete this.overlays[s]}})}async updateOrCreateOverlay(t,e,n){let i=this.overlays[t.id];if(i||(i=await this.constructOverlay(t,e,n),this.overlaysLayer.appendChild(i),this.overlays[t.id]=i,i.style.left=t.x+"px",i.style.top=t.y+"px",i.style.width=t.width+"px",i.style.height=t.height+"px"),n==="markdown"){const o=i.getElementsByClassName("parsed-content-wrapper")[0];if(!t.mdContent)throw m;o.innerHTML!==t.mdContent&&(o.innerHTML=t.mdContent),!i.classList.contains("rtl")&&t.mdFrontmatter?.direction==="rtl"&&i.classList.add("rtl")}}async constructOverlay(t,e,n){const i=document.createElement("div");i.classList.add("overlay-container"),i.id=t.id;const o=document.createElement("div");if(o.className="overlay-border",i.appendChild(o),n==="text"||n==="markdown"){i.classList.add("markdown-content");const r=document.createElement("div");r.innerHTML=await M.marked.parse(e||""),r.classList.add("parsed-content-wrapper"),i.appendChild(r)}else if(n==="link"){const r=document.createElement("iframe");r.src=e,r.sandbox="allow-scripts allow-same-origin",r.className="link-iframe",r.loading="lazy";const a=document.createElement("div");a.className="link-click-layer",i.appendChild(r),i.appendChild(a)}else if(n==="image"){const r=document.createElement("img");r.src=e,r.loading="lazy",i.appendChild(r)}const s=t.color==null?"color-0":"color-"+t.color;if(i.classList.add(s),n!=="image"){this.selectedId===t.id&&i.classList.add("active");const r=()=>{t.id===this.selectedId&&this.startInteract()},a=()=>{t.id===this.selectedId&&this.endInteract()};i.addEventListener("pointerenter",r),i.addEventListener("pointerleave",a),i.addEventListener("touchstart",r),i.addEventListener("touchend",a),this.eventListeners[t.id]=[r,a]}return i}dispose(){for(this._overlays=null;this.overlaysLayer.firstElementChild;){const t=this.overlaysLayer.firstElementChild;if(this.eventListeners[t.id]){const e=this.eventListeners[t.id][0],n=this.eventListeners[t.id][1];if(!e||!n)throw l;t.removeEventListener("pointerenter",e),t.removeEventListener("pointerleave",n),t.removeEventListener("touchstart",e),t.removeEventListener("touchend",n),this.eventListeners[t.id][0]=null,this.eventListeners[t.id][1]=null}t.remove()}this.overlaysLayer.remove(),this._overlaysLayer=null,this._nodeMap=null}}class P extends EventTarget{constructor(t,e=!0){super(),this.preventMt=!1,this.onPointerDown=i=>{const o=this.container.getBoundingClientRect();i.clientX<o.left||i.clientX>o.right||i.clientY<o.top||i.clientY>o.bottom?this.preventMt||this.startPrevention():this.preventMt&&(this.preventMistouch.initialX=i.clientX,this.preventMistouch.initialY=i.clientY,this.preventMistouch.lastX=i.clientX,this.preventMistouch.lastY=i.clientY,this.preventMistouch.record=!0)},this.onPointerMove=i=>{this.preventMistouch.record&&(this.preventMistouch.lastX=i.clientX,this.preventMistouch.lastY=i.clientY)},this.onPointerUp=()=>{this.preventMistouch.record&&(this.preventMistouch.record=!1,Math.abs(this.preventMistouch.lastX-this.preventMistouch.initialX)+Math.abs(this.preventMistouch.lastY-this.preventMistouch.initialY)<5&&this.endPrevention())},this._preventionContainer=document.createElement("div"),this._preventionContainer.className="prevention-container hidden";const n=document.createElement("div");n.className="prevention-banner",n.innerHTML="Frozen to prevent mistouch, click on to unlock.",this._preventionContainer.appendChild(n),t.appendChild(this._preventionContainer),this._container=t,this.preventMistouch={record:!1,lastX:0,lastY:0,initialX:0,initialY:0},e&&this.startPrevention(),window.addEventListener("pointerdown",this.onPointerDown),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp)}get preventionContainer(){if(this._preventionContainer===null)throw l;return this._preventionContainer}get container(){if(this._container===null)throw l;return this._container}startPrevention(){this.preventionContainer.classList.remove("hidden"),this.container.classList.add("numb"),this.preventMt=!0,this.dispatchEvent(new CustomEvent("preventionStart"))}endPrevention(){this.preventMt=!1,this.preventionContainer.classList.add("hidden"),setTimeout(()=>this.container.classList.remove("numb"),50),this.dispatchEvent(new CustomEvent("preventionEnd"))}dispose(){window.removeEventListener("pointerdown",this.onPointerDown),window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp),this.preventionContainer.remove(),this._container=null,this._preventionContainer=null}}const T=".color-1{--border-color: rgba(255, 120, 129, .75);--background-color: rgba(255, 120, 129, .1);--active-color: rgba(255, 120, 129, 1)}.color-2{--border-color: rgba(251, 187, 131, .75);--background-color: rgba(251, 187, 131, .1);--active-color: rgba(251, 187, 131, 1)}.color-3{--border-color: rgba(255, 232, 139, .75);--background-color: rgba(255, 232, 139, .1);--active-color: rgba(255, 232, 139, 1)}.color-4{--border-color: rgba(124, 211, 124, .75);--background-color: rgba(124, 211, 124, .1);--active-color: rgba(124, 211, 124, 1)}.color-5{--border-color: rgba(134, 223, 226, .75);--background-color: rgba(134, 223, 226, .1);--active-color: rgba(134, 223, 226, 1)}.color-6{--border-color: rgba(203, 158, 255, .75);--background-color: rgba(203, 158, 255, .1);--active-color: rgba(203, 158, 255, 1)}.color-0{--border-color: rgba(140, 140, 140, .75);--background-color: rgba(140, 140, 140, .1);--active-color: rgba(140, 140, 140, 1)}.full,.preview-modal,.preview-modal-backdrop,.link-click-layer,.link-iframe,.prevention-container{top:0;left:0;width:100%;height:100%;position:absolute}.flex-center,.overlay-container.markdown-content,.prevention-container{display:flex;justify-content:center;align-items:center}.overlay-border{z-index:1}.container{--themeColor: rgb(254, 247, 167);--background-color: #141414;--contentTransition: color .2s, opacity .2s, text-shadow .2s, fill .2s;--containerTransition: background .2s, opacity .2s, box-shadow .2s, border .2s, filter .2s, backdrop-filter .2s;color:#fff;fill:#fff;stroke:#fff;position:relative;width:100%;height:100%;overflow:hidden;background-color:var(--background-color)}.container.numb,.container.numb *{pointer-events:none!important}.prevention-container{overflow:visible;transition:background .2s,opacity .2s,box-shadow .2s,border .2s,filter .2s,backdrop-filter .2s}.prevention-container.hidden{pointer-events:none}.prevention-container .prevention-banner{background:#0006;border-radius:12px;padding:12px;margin:12px;-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);border:2px solid rgba(140,140,140,.75);color:#fff;font-size:calc(14px + .3vw);line-height:calc(17px + .3vw);text-align:center}.main-canvas{width:100%;height:100%;transform-origin:top left}button{cursor:pointer;font-size:18px;height:32px;border:none;transition:var(--containerTransition);text-align:center;background-color:#444;width:32px;padding:5px 0}button svg{width:100%;height:100%}.overlays{position:absolute;top:0;left:0;width:100%;height:100%;transform-origin:top left;will-change:transform}.parsed-content-wrapper{font-family:sans-serif;box-sizing:border-box;max-width:100%;max-height:100%;padding:10px 6px;pointer-events:none;overflow:hidden;scrollbar-gutter:stable both-edges;display:flex;flex-direction:column;gap:12px}@supports not (scrollbar-gutter: stable both-edges){.parsed-content-wrapper{padding:10px}}.minimap-container{position:absolute;bottom:10px;right:10px;display:flex;pointer-events:none;transition:transform .2s}.minimap-container.collapsed{transform:translate(calc(100% - 32px))}@media (max-width: 768px){.minimap-container{transform:translateY(60px) translate(80px)}.minimap-container.collapsed{transform:translateY(60px) translate(calc(100% - 32px))}}.toggle-minimap{margin:auto 10px 0 0;pointer-events:auto}.collapsed .toggle-minimap{transform:rotate(180deg)}@media (max-width: 768px){.toggle-minimap{transform:translateY(-60px)}.collapsed .toggle-minimap{transform:translateY(-60px) rotate(180deg)}}.minimap{position:relative;width:200px;height:150px;overflow:hidden;border-radius:12px;background:#202020;-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);border:2px solid rgba(140,140,140,.75);transform-origin:0 0}@media (max-width: 768px){.minimap{transform:scale(.6)}}.minimap .minimap-canvas{width:100%;height:100%}.minimap .viewport-rectangle{position:absolute;top:0;left:0;pointer-events:none;border:2px solid #fff;border-radius:6px;box-sizing:border-box;background:transparent}.collapse-button{border-radius:8px;transition:transform .2s}.collapse-button:hover{background:#444c}.controls{position:absolute;top:10px;right:10px;display:flex;align-items:center;transition:transform .2s;border-radius:8px;gap:10px}.controls.collapsed{transform:translate(calc(100% - 32px))}.controls.collapsed .collapse-button{transform:rotate(180deg)}.controls .controls-content{display:flex;gap:1px;align-items:center;border-radius:8px;overflow:hidden;background:#333c}.controls button:hover{background:#555}.zoom-slider{width:100px;margin:0 10px}.overlay-container{position:absolute;box-sizing:border-box;border-radius:12px;overflow:hidden;background-color:var(--background-color);-webkit-user-select:none;user-select:none;contain:strict;transition:var(--containerTransition)}.overlay-container:hover{box-shadow:0 2px 12px #00000080}.overlay-container .overlay-border{box-sizing:border-box;pointer-events:none;position:absolute;top:0;left:0;width:100%;height:100%;border:2px solid var(--border-color);border-radius:12px;transition:var(--containerTransition)}.overlay-container img{width:100%;height:100%;object-fit:cover;pointer-events:none}.overlay-container.active .overlay-border{border:6px solid var(--active-color)}.overlay-container.markdown-content{position:absolute;padding:0 7px}.overlay-container.markdown-content.active .parsed-content-wrapper{overflow:auto;-webkit-user-select:text;user-select:text;pointer-events:auto}.overlay-container.markdown-content.rtl{direction:rtl;text-align:right}.link-iframe{contain-intrinsic-size:100% 100%;border:none}.link-click-layer{background:transparent;pointer-events:auto}.active .link-click-layer{pointer-events:none}.preview-modal-backdrop{-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);transition:var(--containerTransition)}.preview-modal-backdrop.hidden{pointer-events:none}.preview-modal{transition:var(--containerTransition);pointer-events:none}.preview-modal-close{position:absolute;right:10px;top:10px;background:none;border:none;font-size:24px;cursor:pointer;pointer-events:none}.preview-modal:not(.hidden) .preview-modal-close{pointer-events:auto}.preview-modal-content{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:fit-content;height:fit-content;pointer-events:none}.preview-modal:not(.hidden) .preview-modal-content{pointer-events:auto}.preview-modal-content>*{max-width:var(--preview-max-width);max-height:var(--preview-max-height);border:2px solid rgba(162,162,162,.5);box-shadow:0 2px 6px #0000004d;box-sizing:border-box}.preview-modal-content>img{border-radius:12px}.preview-modal-content>audio{border-radius:27px}.hidden{opacity:0}::-webkit-scrollbar{width:4px}::-webkit-scrollbar-track{background-color:transparent}::-webkit-scrollbar-thumb{border-radius:2px;background:#ffffff40}::-webkit-scrollbar-thumb:hover{background:#1e1e1ebf}p{font-size:16px;line-height:21px}.parsed-content-wrapper img{width:100%;border-radius:8px}h1{font-size:25px}h2{font-size:23px}h3{font-size:22px}h4{font-size:20px}h5{font-size:19px}h6{font-size:17px}p,h1,h2,h3,h4,h5,h6,ol,ul{margin:0}h1,h2{font-weight:800}h3,h4{font-weight:700}h5,h6{font-weight:600}code{background:#ffffff1a;padding:2px 4px;border-radius:8px}pre code{display:block;box-sizing:border-box;width:100%}pre:has(code),table{margin:6px 0}strong{color:#fe8e7c}em{color:#5affb2}a{text-decoration:none;color:#6dadd0;font-weight:800;font-style:italic;cursor:pointer;transition:var(--contentTransition)}a:hover{color:#86d3fd}hr{height:1px;width:100%;background-color:#fff3;border:none}li{margin:5px 0}ul{padding-left:16px}ol{padding-left:15px;padding-right:7.5px}table{border-collapse:collapse;border-spacing:0;border-radius:8px;border:1px solid rgba(255,255,255,.2);overflow:hidden;width:100%}table th,table td{border:1px solid rgba(255,255,255,.2);padding:6px 10px;background:#ffffff0f;text-align:left}table th{background:#ffffff1f;font-weight:700}";class k extends EventTarget{constructor(t,e=[],n=[]){super(),this.controls=null,this.minimap=null,this.mistouchPreventer=null,this.canvasBaseDir=null,this.animationId=null,this._canvasData=null,this._nodeMap=null,this._nodeBounds=null,this.spatialGrid=null,this.draw=()=>{if(!this.perFrame.needAnimating&&!this.perFrame.pan&&!this.perFrame.resize&&!this.perFrame.zoom&&!this.perFrame.smoothZoom){this.animationId=requestAnimationFrame(this.draw);return}if(this.perFrame.needAnimating&&(this.perFrame.needAnimating=!1),this.perFrame.zoom){this.perFrame.zoom=!1;const s=this.interactor.getZoomDump();this.zoom(s.factor,s.origin),this.interactor.resetZoomDump()}this.perFrame.pan&&(this.perFrame.pan=!1,this.pan(this.interactor.getPanDump()),this.interactor.resetPanDump()),this.perFrame.smoothZoom&&this.smoothZoom(),this.perFrame.resize&&this.resize(),this.renderer.redraw(this.offsetX,this.offsetY,this.scale),this.overlayManager.updateAllOverlays(this.offsetX,this.offsetY,this.scale),this.minimap&&this.minimap.updateViewportRectangle(this.offsetX,this.offsetY,this.scale),this.animationId=requestAnimationFrame(this.draw)},this.onClick=s=>{if(s instanceof CustomEvent){if(this.isUIControl(s.detail.target))return;const r=this.findNodeAt(this.C2W(this.C2C(s.detail.position))),a=this.judgeInteract(r);switch(a){case"non-interactive":this.overlayManager.select(null);break;case"select":if(!r)throw m;this.overlayManager.select(r.id);break;case"preview":if(!r)throw m;this.previewModal.showPreviewModal(r);break}r&&a!=="non-interactive"&&this.dispatchEvent(new CustomEvent("interact",{detail:{node:r.id,type:a}}))}else throw m},this.onResize=()=>{this.perFrame.resize=!0,this.perFrame.resizeScale.width=this.container.clientWidth,this.perFrame.resizeScale.height=this.container.clientHeight},this.onPan=()=>this.perFrame.pan=!0,this.onZoom=()=>this.perFrame.zoom=!0,this.onSlide=s=>{if(s instanceof CustomEvent)this.setScale(s.detail);else throw m},this.onMinimapExpanded=()=>{this.minimap&&this.minimap.updateViewportRectangle(this.offsetX,this.offsetY,this.scale)},this.onPreventionStart=()=>{this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)},this.onPreventionEnd=()=>this.animationId=requestAnimationFrame(this.draw),this.stopInteractor=()=>this.interactor.stop(),this.startInteractor=()=>this.interactor.start(),this.onToggleFullscreen=()=>this.shiftFullscreen(),this.zoomIn=()=>this.setScale(this.scale*1.2),this.zoomOut=()=>this.setScale(this.scale/1.2),this.resetView=()=>{const s=this.nodeBounds;if(!s)return{scale:1,offsetX:this.container.clientWidth/2,offsetY:this.container.clientHeight/2};const r=s.width+this.INITIAL_VIEWPORT_PADDING*2,a=s.height+this.INITIAL_VIEWPORT_PADDING*2,c=this.container.clientWidth,p=this.container.clientHeight,d=c/r,u=p/a,v=Math.round(Math.min(d,u)*1e3)/1e3,f=s.centerX,g=s.centerY,w={scale:v,offsetX:c/2-f*v,offsetY:p/2-g*v};this.scale=w.scale,this.offsetX=w.offsetX,this.offsetY=w.offsetY,this.controls&&this.controls.updateSlider(this.scale),this.perFrame.needAnimating=!0};const i=t.attachShadow({mode:"open"}),o=document.createElement("style");o.innerHTML=T,i.appendChild(o),this._container=document.createElement("div"),this._container.classList.add("container"),this.renderer=new L(this._container),this.overlayManager=new B(this._container),this.interactor=new z(this._container,{preventDefault:!0,proControlSchema:n.includes("proControlSchema")}),this.resizeObserver=new ResizeObserver(this.onResize),e.includes("minimap")?this.minimap=new D(this._container,n.includes("minimapCollapsed")):n.includes("minimapCollapsed")&&console.warn('CanvasViewer: "minimapCollapsed" option is not supported without minimap extension.'),n.includes("controlsHidden")?n.includes("controlsCollapsed")&&console.warn('CanvasViewer: "controlsCollapsed" option is overridden by "controlsHidden" option.'):this.controls=new S(this._container,n.includes("controlsCollapsed")),this.previewModal=new I(this._container),e.includes("mistouchPrevention")&&(this.mistouchPreventer=new P(this._container,!n.includes("noPreventionAtStart"))),i.appendChild(this._container),this.extensions=e,this.options=n,this.offsetX=0,this.offsetY=0,this.scale=1,this.ZOOM_SMOOTHNESS=.25,this.INITIAL_VIEWPORT_PADDING=100,this.GRID_CELL_SIZE=800,this.perFrame={needAnimating:!1,zoom:!1,smoothZoom:!1,targetScale:1,pan:!1,resize:!1,resizeScale:{width:0,height:0,lastCentreX:null,lastCentreY:null}}}get canvasData(){if(this._canvasData===null)throw l;return this._canvasData}get nodeMap(){if(this._nodeMap===null)throw l;return this._nodeMap}get nodeBounds(){if(this._nodeBounds===null)throw l;return this._nodeBounds}get container(){if(this._container===null)throw l;return this._container}isUIControl(t){return t.closest&&(t.closest(".controls")||t.closest("button")||t.closest("input"))}findNodeAt({x:t,y:e}){let n=[];if(!this.spatialGrid)n=this.canvasData.nodes;else{const i=Math.floor(t/this.GRID_CELL_SIZE),o=Math.floor(e/this.GRID_CELL_SIZE),s=`${i},${o}`;n=this.spatialGrid[s]||[]}for(const i of n)if(!(t<i.x||t>i.x+i.width||e<i.y||e>i.y+i.height||this.judgeInteract(i)==="non-interactive"))return i}C2C({x:t,y:e}){return{x:t-this.offsetX,y:e-this.offsetY}}C2W({x:t,y:e}){return{x:t/this.scale,y:e/this.scale}}middleScreen(){return{x:this.container.clientWidth/2,y:this.container.clientHeight/2}}judgeInteract(t){switch(t?t.type:"default"){case"text":return"select";case"link":return"select";case"file":if(!t||!t.file)throw m;return t.file.match(/\.md$/i)?"select":"preview";default:return"non-interactive"}}zoomToScale(t,e){const n=Math.max(Math.min(t,20),.05);if(n===this.scale)return;const i=this.C2C(e);this.offsetX=e.x-i.x*n/this.scale,this.offsetY=e.y-i.y*n/this.scale,this.scale=n,this.controls&&this.controls.updateSlider(this.scale)}buildSpatialGrid(){if(!(!this.canvasData||this.canvasData.nodes.length<50)){this.spatialGrid={};for(let t of this.canvasData.nodes){const e=Math.floor(t.x/this.GRID_CELL_SIZE),n=Math.floor((t.x+t.width)/this.GRID_CELL_SIZE),i=Math.floor(t.y/this.GRID_CELL_SIZE),o=Math.floor((t.y+t.height)/this.GRID_CELL_SIZE);for(let s=e;s<=n;s++)for(let r=i;r<=o;r++){const a=`${s},${r}`;this.spatialGrid[a]||(this.spatialGrid[a]=[]),this.spatialGrid[a].push(t)}}}}calculateNodeBounds(){if(!this.canvasData||!this.canvasData.nodes.length)return null;let t=1/0,e=1/0,n=-1/0,i=-1/0;this.canvasData.nodes.forEach(c=>{t=Math.min(t,c.x),e=Math.min(e,c.y),n=Math.max(n,c.x+c.width),i=Math.max(i,c.y+c.height)});const o=n-t,s=i-e,r=t+o/2,a=e+s/2;return{minX:t,minY:e,maxX:n,maxY:i,width:o,height:s,centerX:r,centerY:a}}resize(){this.perFrame.resize=!1;const t=this.perFrame.resizeScale;t.lastCentreX&&t.lastCentreY&&(this.offsetX+=t.width/2-t.lastCentreX,this.offsetY+=t.height/2-t.lastCentreY),t.lastCentreX=t.width/2,t.lastCentreY=t.height/2,this.renderer.resizeCanvasForDPR(),this.previewModal.resize(t.width,t.height)}pan({x:t,y:e}){this.offsetX+=t,this.offsetY+=e}zoom(t,e){const n=this.scale*t;this.zoomToScale(n,e)}smoothZoom(){const t=this.perFrame.targetScale-this.scale;let e;Math.abs(t)<this.perFrame.targetScale*.01+.002?(e=this.perFrame.targetScale,this.perFrame.smoothZoom=!1):e=Math.round((this.scale+t*this.ZOOM_SMOOTHNESS)*1e3)/1e3,this.zoomToScale(e,this.middleScreen())}setScale(t){this.perFrame.targetScale=t,this.perFrame.smoothZoom=!0}panTo(t,e){this.offsetX=this.container.clientWidth/2-t*this.scale,this.offsetY=this.container.clientHeight/2-e*this.scale,this.perFrame.needAnimating=!0}shiftFullscreen(t="toggle"){!document.fullscreenElement&&(t==="toggle"||t==="enter")?this.container.requestFullscreen():document.fullscreenElement&&(t==="toggle"||t==="exit")&&document.exitFullscreen(),this.controls&&this.controls.updateFullscreenBtn()}async loadCanvas(t){try{if(/^https?:\/\//.test(t))this.canvasBaseDir=t.substring(0,t.lastIndexOf("/")+1);else{const e=t.lastIndexOf("/");this.canvasBaseDir=e!==-1?t.substring(0,e+1):"./"}this._canvasData=await fetch(t).then(e=>e.json()),this._nodeMap={},this.canvasData.nodes.forEach(e=>{if(e.type==="file"&&e.file&&!e.file.includes("http")){const n=e.file.split("/");e.file=n[n.length-1]}this.nodeMap[e.id]=e}),this.buildSpatialGrid(),this._nodeBounds=this.calculateNodeBounds(),this.resetView(),this.resizeObserver.observe(this.container),this.interactor.start(),this.renderer.receiveData(this.nodeMap,this.canvasData),this.overlayManager.receiveData(this.canvasBaseDir,this.nodeMap),this.previewModal.receiveData(this.canvasBaseDir),this.interactor.addEventListener("trueClick",this.onClick),this.interactor.addEventListener("pan",this.onPan),this.interactor.addEventListener("zoom",this.onZoom),this.previewModal.addEventListener("previewModalShown",this.stopInteractor),this.previewModal.addEventListener("previewModalHidden",this.startInteractor),this.overlayManager.addEventListener("interactionStart",this.stopInteractor),this.overlayManager.addEventListener("interactionEnd",this.startInteractor),this.controls&&this.controls.addEventListener("zoomIn",this.zoomIn),this.controls&&this.controls.addEventListener("zoomOut",this.zoomOut),this.controls&&this.controls.addEventListener("slide",this.onSlide),this.controls&&this.controls.addEventListener("toggleFullscreen",this.onToggleFullscreen),this.controls&&this.controls.addEventListener("resetView",this.resetView),this.minimap&&(this.minimap.receiveData(this.nodeBounds,this.canvasData,this.nodeMap),this.minimap.addEventListener("minimapExpanded",this.onMinimapExpanded)),this.mistouchPreventer&&(this.mistouchPreventer.addEventListener("preventionStart",this.onPreventionStart),this.mistouchPreventer.addEventListener("preventionEnd",this.onPreventionEnd)),(!this.extensions.includes("mistouchPrevention")||this.options.includes("noPreventionAtStart"))&&(this.animationId=requestAnimationFrame(this.draw)),this.dispatchEvent(new CustomEvent("loaded",{detail:this.canvasData}))}catch(e){console.error("Failed to load canvas data:",e)}}dispose(){this.interactor.removeEventListener("trueClick",this.onClick),this.interactor.removeEventListener("pan",this.onPan),this.interactor.removeEventListener("zoom",this.onZoom),this.previewModal.removeEventListener("previewModalShown",this.stopInteractor),this.previewModal.removeEventListener("previewModalHidden",this.startInteractor),this.overlayManager.removeEventListener("interactionStart",this.stopInteractor),this.overlayManager.removeEventListener("interactionEnd",this.startInteractor),this.controls&&this.controls.removeEventListener("zoomIn",this.zoomIn),this.controls&&this.controls.removeEventListener("zoomOut",this.zoomOut),this.controls&&this.controls.removeEventListener("slide",this.onSlide),this.controls&&this.controls.removeEventListener("toggleFullscreen",this.onToggleFullscreen),this.controls&&this.controls.removeEventListener("resetView",this.resetView),this.minimap&&this.minimap.removeEventListener("minimapExpanded",this.onMinimapExpanded),this.mistouchPreventer&&(this.mistouchPreventer.removeEventListener("preventionStart",this.onPreventionStart),this.mistouchPreventer.removeEventListener("preventionEnd",this.onPreventionEnd)),this.animationId&&cancelAnimationFrame(this.animationId),this.resizeObserver.disconnect(),this.interactor.dispose(),this.previewModal.dispose(),this.controls&&this.controls.dispose(),this.minimap&&this.minimap.dispose(),this.mistouchPreventer&&this.mistouchPreventer.dispose(),this.overlayManager.dispose(),this.renderer.dispose(),this.container.remove(),this._container=null}}class O extends HTMLElement{constructor(){super(),this.style.display="block",this.style.overflow="hidden",this.style.maxWidth="120vw",this.style.maxHeight="120vh";const t=this.getAttribute("extensions"),e=this.getAttribute("options"),n=t?t.split(" "):[],i=e?e.split(" "):[];this.viewer=new k(this,n,i)}connectedCallback(){const t=this.getAttribute("src");if(!t)throw new Error("No source canvas path provided.");this.viewer&&this.viewer.loadCanvas(t)}disconnectedCallback(){this.viewer&&this.viewer.dispose(),this.remove()}}customElements.define("canvas-viewer",O);module.exports=k;
1
+ "use strict";const M=require("marked"),m=new Error("This error is unexpected, probably caused by canvas file corruption. If you assure the error is not by accident, please contact the developer and show how to reproduce."),l=new Error("Resource hasn't been set up or has been disposed.");class k{constructor(t){this._nodeMap=null,this._canvasData=null,this.ARROW_LENGTH=12,this.ARROW_WIDTH=7,this.FILE_NODE_RADIUS=12,this.FONT_COLOR="#fff",this.CSS_ZOOM_REDRAW_INTERVAL=500,this._canvas=document.createElement("canvas"),this._canvas.className="main-canvas",this._container=t,this._container.appendChild(this._canvas),this._ctx=this._canvas.getContext("2d"),this.zoomInOptimize={lastDrawnScale:0,lastDrawnViewport:{left:0,right:0,top:0,bottom:0},timeout:null,lastCallTime:0},y(this._canvas,t.offsetWidth,t.offsetHeight)}get nodeMap(){if(this._nodeMap===null)throw l;return this._nodeMap}get canvasData(){if(this._canvasData===null)throw l;return this._canvasData}get canvas(){if(this._canvas===null)throw l;return this._canvas}get ctx(){if(this._ctx===null)throw l;return this._ctx}get container(){if(this._container===null)throw l;return this._container}receiveData(t,e){this._nodeMap=t,this._canvasData=e}resizeCanvasForDPR(){y(this.canvas,this.container.offsetWidth,this.container.offsetHeight)}redraw(t,e,n){this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=null);const i=Date.now(),o=this.getCurrentViewport(t,e,n);if(this.isViewportInside(o,this.zoomInOptimize.lastDrawnViewport)&&n!==this.zoomInOptimize.lastDrawnScale&&i-this.zoomInOptimize.lastCallTime<this.CSS_ZOOM_REDRAW_INTERVAL){this.zoomInOptimize.timeout=setTimeout(()=>{this.trueRedraw(t,e,n,o),this.zoomInOptimize.lastCallTime=i,this.zoomInOptimize.timeout=null},60),this.fakeRedraw(o,n);return}this.zoomInOptimize.lastCallTime=i,this.trueRedraw(t,e,n,o)}dispose(){this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=null),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.remove(),this._ctx=null,this._canvas=null,this._container=null,this._canvasData=null,this._nodeMap=null}trueRedraw(t,e,n,i){this.zoomInOptimize.lastDrawnViewport=i,this.zoomInOptimize.lastDrawnScale=n,this.canvas.style.transform="",this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.save(),this.ctx.translate(t,e),this.ctx.scale(n,n),this.canvasData.nodes.forEach(o=>o.inViewport=this.isNodeInViewport(o,t,e,n)),this.canvasData.nodes.forEach(o=>{switch(o.type){case"group":this.drawGroup(o,n);break;case"file":this.drawFileNode(o);break}}),this.canvasData.edges.forEach(o=>this.drawEdge(o)),this.ctx.restore()}fakeRedraw(t,e){const n=e/this.zoomInOptimize.lastDrawnScale,i=(this.zoomInOptimize.lastDrawnViewport.left-t.left)*e,o=(this.zoomInOptimize.lastDrawnViewport.top-t.top)*e;this.canvas.style.transform=`translate(${i}px, ${o}px) scale(${n})`}isViewportInside(t,e){return t.left>e.left&&t.top>e.top&&t.right<e.right&&t.bottom<e.bottom}isNodeInViewport(t,e,n,i,o=200){const s=-e/i-o,r=-n/i-o,a=s+this.container.clientWidth/i+2*o,c=r+this.container.clientHeight/i+2*o;return t.x+t.width>s&&t.x<a&&t.y+t.height>r&&t.y<c}getCurrentViewport(t,e,n){const i=-t/n,o=-e/n,s=i+this.container.clientWidth/n,r=o+this.container.clientHeight/n;return{left:i,top:o,right:s,bottom:r}}drawLabelBar(t,e,n,i,o){const s=30*o,r=6*o,a=8*o,c=16*o,p=6*o;this.ctx.save(),this.ctx.translate(t,e),this.ctx.scale(1/o,1/o),this.ctx.font=`${c}px 'Inter', sans-serif`;const d=this.ctx.measureText(n).width+2*p;this.ctx.translate(0,-s-a),this.ctx.fillStyle=i,this.ctx.beginPath(),this.ctx.moveTo(r,0),this.ctx.lineTo(d-r,0),this.ctx.quadraticCurveTo(d,0,d,r),this.ctx.lineTo(d,s-r),this.ctx.quadraticCurveTo(d,s,d-r,s),this.ctx.lineTo(r,s),this.ctx.quadraticCurveTo(0,s,0,s-r),this.ctx.lineTo(0,r),this.ctx.quadraticCurveTo(0,0,r,0),this.ctx.closePath(),this.ctx.fill(),this.ctx.fillStyle=this.FONT_COLOR,this.ctx.fillText(n,p,s*.65),this.ctx.restore()}drawNodeBackground(t){const e=E(t.color),n=this.FILE_NODE_RADIUS;this.ctx.globalAlpha=1,this.ctx.fillStyle=e.background,C(this.ctx,t.x+1,t.y+1,t.width-2,t.height-2,n),this.ctx.fill(),this.ctx.strokeStyle=e.border,this.ctx.lineWidth=2,C(this.ctx,t.x,t.y,t.width,t.height,n),this.ctx.stroke()}drawGroup(t,e){this.drawNodeBackground(t),t.label&&this.drawLabelBar(t.x,t.y,t.label,E(t.color).border,e)}drawFileNode(t){if(!t.file)throw m;t.file.match(/\.md|png|jpg|jpeg|gif|svg$/i)||(this.drawNodeBackground(t),t.file.match(/\.mp3$/i)&&(this.ctx.fillStyle=this.FONT_COLOR,this.ctx.textAlign="center",this.ctx.textBaseline="middle",this.ctx.fillText("🎵 Click to Preview 🎵",t.x+t.width/2,t.y+t.height/2),this.ctx.textAlign="left")),this.ctx.fillStyle=this.FONT_COLOR,this.ctx.font="16px sans-serif",this.ctx.fillText(t.file,t.x+5,t.y-10)}drawEdge(t){const{fromNode:e,toNode:n}=this.getEdgeNodes(t);if(!e||!n)throw m;const[i,o]=_(e,t.fromSide),[s,r]=_(n,t.toSide);let[a,c,p,d]=[0,0,0,0];if(t.controlPoints?[a,c,p,d]=t.controlPoints:([a,c,p,d]=this.getControlPoints(i,o,s,r,t.fromSide,t.toSide),t.controlPoints=[a,c,p,d]),this.drawCurvedPath(i,o,s,r,a,c,p,d),this.drawArrowhead(s,r,p,d),t.label){const v=Math.pow(.5,3)*i+3*Math.pow(.5,2)*.5*a+.375*p+Math.pow(.5,3)*s,f=Math.pow(1-.5,3)*o+3*Math.pow(1-.5,2)*.5*c+3*(1-.5)*.5*.5*d+Math.pow(.5,3)*r;this.ctx.font="18px sans-serif";const x=this.ctx.measureText(t.label).width+8*2,b=20;this.ctx.fillStyle="#222",this.ctx.beginPath(),C(this.ctx,v-x/2,f-b/2-2,x,b,4),this.ctx.fill(),this.ctx.fillStyle="#ccc",this.ctx.textAlign="center",this.ctx.textBaseline="middle",this.ctx.fillText(t.label,v,f-2),this.ctx.textAlign="left",this.ctx.textBaseline="alphabetic"}}getEdgeNodes(t){return{fromNode:this.nodeMap[t.fromNode],toNode:this.nodeMap[t.toNode]}}getControlPoints(t,e,n,i,o,s){const r=n-t,a=i-e,c=Math.min(Math.abs(r),Math.abs(a))+.3*Math.max(Math.abs(r),Math.abs(a)),d=((w,x,b)=>Math.max(x,Math.min(b,w)))(c*.5,60,300);let u=t,v=e,f=n,g=i;switch(o){case"top":v=e-d;break;case"bottom":v=e+d;break;case"left":u=t-d;break;case"right":u=t+d;break}switch(s){case"top":g=i-d;break;case"bottom":g=i+d;break;case"left":f=n-d;break;case"right":f=n+d;break}return[u,v,f,g]}drawCurvedPath(t,e,n,i,o,s,r,a){this.ctx.beginPath(),this.ctx.moveTo(t,e),this.ctx.bezierCurveTo(o,s,r,a,n,i),this.ctx.strokeStyle="#ccc",this.ctx.lineWidth=2,this.ctx.stroke()}drawArrowhead(t,e,n,i){const o=t-n,s=e-i,r=Math.sqrt(o*o+s*s);if(r===0)return;const a=o/r,c=s/r,p=t-a*this.ARROW_LENGTH-c*this.ARROW_WIDTH,d=e-c*this.ARROW_LENGTH+a*this.ARROW_WIDTH,u=t-a*this.ARROW_LENGTH+c*this.ARROW_WIDTH,v=e-c*this.ARROW_LENGTH-a*this.ARROW_WIDTH;this.ctx.beginPath(),this.ctx.fillStyle="#ccc",this.ctx.moveTo(t,e),this.ctx.lineTo(p,d),this.ctx.lineTo(u,v),this.ctx.closePath(),this.ctx.fill()}}function _(h,t){const e=h.x+h.width/2,n=h.y+h.height/2;switch(t){case"top":return[e,h.y];case"bottom":return[e,h.y+h.height];case"left":return[h.x,n];case"right":return[h.x+h.width,n];default:return[e,n]}}function C(h,t,e,n,i,o){h.beginPath(),h.moveTo(t+o,e),h.lineTo(t+n-o,e),h.quadraticCurveTo(t+n,e,t+n,e+o),h.lineTo(t+n,e+i-o),h.quadraticCurveTo(t+n,e+i,t+n-o,e+i),h.lineTo(t+o,e+i),h.quadraticCurveTo(t,e+i,t,e+i-o),h.lineTo(t,e+o),h.quadraticCurveTo(t,e,t+o,e),h.closePath()}function E(h){let t=null;switch(h){case"1":t="rgba(255, 120, 129, ?)";break;case"2":t="rgba(251, 187, 131, ?)";break;case"3":t="rgba(255, 232, 139, ?)";break;case"4":t="rgba(124, 211, 124, ?)";break;case"5":t="rgba(134, 223, 226, ?)";break;case"6":t="rgba(203, 158, 255, ?)";break;default:t="rgba(140, 140, 140, ?)"}return{border:t.replace("?","0.75"),background:t.replace("?","0.1"),active:t.replace("?","1")}}function y(h,t,e){const n=window.devicePixelRatio||1,i=h.getContext("2d");if(!i)throw m;h.width=Math.round(t*n),h.height=Math.round(e*n),i.setTransform(1,0,0,1,0,0),i.scale(n,n)}class L extends EventTarget{constructor(t,e){super(),this.pointers=new Map,this.onPointerDown=i=>{if(!(this.pointers.size>=2)&&(i.isPrimary&&this.pointers.clear(),this.pointers.set(i.pointerId,{startX:i.clientX,startY:i.clientY,lastX:i.clientX,lastY:i.clientY,interrupted:!1,target:i.target}),this.pointers.size===2)){const o=this.getNthValue(0),s=this.pointers.get(i.pointerId);if(!o||!s)throw m;o.interrupted=!0,s.interrupted=!0,this.pinchZoomState.lastDistance=this.getPointerDistance(),this.pinchZoomState.lastMidpoint=this.S2C(this.getPointerMidpoint())}},this.onPointerMove=i=>{const o=this.pointers.get(i.pointerId);if(o){if(this.pointers.size===1){const s=i.clientX-o.lastX,r=i.clientY-o.lastY;this.dispatchPanEvent({x:s,y:r})}if(this.pointers.set(i.pointerId,{startX:o.startX,startY:o.startY,lastX:i.clientX,lastY:i.clientY,interrupted:o.interrupted,target:o.target}),this.pointers.size===2){const s=this.getPointerDistance(),r=this.getPointerMidpoint();if(!s||!r)throw m;let a=s/this.pinchZoomState.lastDistance;this.pinchZoomState.lastDistance=s;const c=this.S2C(r),p=c.x-this.pinchZoomState.lastMidpoint.x,d=c.y-this.pinchZoomState.lastMidpoint.y;this.pinchZoomState.lastMidpoint=c,this.dispatchPanEvent({x:p,y:d}),this.dispatchZoomEvent(a,c)}}},this.onPointerUp=i=>{const o=this.pointers.get(i.pointerId);if(o&&(this.pointers.delete(i.pointerId),this.pointers.size===0&&!o.interrupted&&Math.abs(o.startX-i.clientX)+Math.abs(o.startY-i.clientY)<5)){const s=this.S2C({x:i.clientX,y:i.clientY}),r=new CustomEvent("trueClick",{detail:{position:s,target:o.target}});this.dispatchEvent(r)}},this.onWheel=i=>{if(!this.lockControlSchema&&!this.proControlSchema&&(i.ctrlKey||i.shiftKey||Math.abs(i.deltaX)>Math.abs(i.deltaY))&&(this.proControlSchema=!0),this.preventDefault&&i.preventDefault(),this.proControlSchema)if(i.ctrlKey){const o=i.deltaY>0?1-this.ctrlZoomFactor:1+this.ctrlZoomFactor,s=this.S2C({x:i.clientX,y:i.clientY});this.dispatchZoomEvent(o,s)}else i.shiftKey&&Math.abs(i.deltaX)<=Math.abs(i.deltaY)?this.dispatchPanEvent({x:-i.deltaY,y:-i.deltaX}):this.dispatchPanEvent({x:-i.deltaX,y:-i.deltaY});else{const o=1-this.zoomFactor*i.deltaY,s=this.S2C({x:i.clientX,y:i.clientY});this.dispatchZoomEvent(o,s)}},this.preventDefaultFunction=i=>i.preventDefault,this._monitoringElement=t;const n=e||{};this.preventDefault=n.preventDefault||!1,this.proControlSchema=n.proControlSchema||!1,this.zoomFactor=n.zoomFactor||.002,this.ctrlZoomFactor=n.zoomFactor?n.zoomFactor*50:.1,this.lockControlSchema=n.lockControlSchema||!1,this.pointers.clear(),this.pinchZoomState={lastDistance:0,lastMidpoint:{x:0,y:0}},this.panDump={x:0,y:0},this.zoomDump={factor:1,origin:{x:0,y:0}}}get monitoringElement(){if(this._monitoringElement===null)throw l;return this._monitoringElement}getNthValue(t){if(t<0||t>=this.pointers.size)throw m;let e=0;for(const n of this.pointers.values()){if(e===t)return n;e++}}getPointerDistance(){const t=this.getNthValue(0),e=this.getNthValue(1);if(!t||!e)throw m;const n=t.lastX-e.lastX,i=t.lastY-e.lastY;return Math.sqrt(n*n+i*i)}getPointerMidpoint(){const t=this.getNthValue(0),e=this.getNthValue(1);if(!t||!e)throw m;return{x:(t.lastX+e.lastX)/2,y:(t.lastY+e.lastY)/2}}S2C({x:t,y:e}){const n=this.monitoringElement.getBoundingClientRect();return{x:t-n.left,y:e-n.top}}dispatchPanEvent(t){const e={x:this.round(t.x,1),y:this.round(t.y,1)};this.panDump.x+=e.x,this.panDump.y+=e.y;const n=new CustomEvent("pan",{detail:e});this.dispatchEvent(n)}dispatchZoomEvent(t,e){const n=this.round(t,4);this.zoomDump.factor*=n,this.zoomDump.origin=e;const i=new CustomEvent("zoom",{detail:{factor:n,origin:e}});this.dispatchEvent(i)}round(t,e){const n=10**e;return Math.round(t*n)/n}getZoomDump(){return this.zoomDump}resetZoomDump(){this.zoomDump.factor=1}getPanDump(){return this.panDump}resetPanDump(){this.panDump={x:0,y:0}}stop(){this.monitoringElement.removeEventListener("pointerdown",this.onPointerDown),window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp),this.monitoringElement.removeEventListener("wheel",this.onWheel),this.preventDefault&&(this.monitoringElement.style.touchAction="",this.monitoringElement.removeEventListener("gesturestart",this.preventDefaultFunction),this.monitoringElement.removeEventListener("gesturechange",this.preventDefaultFunction))}start(){this.monitoringElement.addEventListener("pointerdown",this.onPointerDown),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp),this.monitoringElement.addEventListener("wheel",this.onWheel,this.preventDefault?{passive:!1}:{}),this.preventDefault&&(this.monitoringElement.style.touchAction="none",this.monitoringElement.addEventListener("gesturestart",this.preventDefaultFunction,{passive:!1}),this.monitoringElement.addEventListener("gesturechange",this.preventDefaultFunction,{passive:!1}))}dispose(){this.stop(),this.pointers.clear(),this._monitoringElement=null}}class S extends EventTarget{constructor(t,e=!1){super(),this._canvasData=null,this._nodeMap=null,this._nodeBounds=null,this.toggleVisisbility=()=>{this.isMinimapVisible=!this.isMinimapVisible,this.minimapContainer.classList.toggle("collapsed"),this.dispatchEvent(new CustomEvent(this.isMinimapVisible?"minimapExpanded":"minimapCollapsed"))},this._minimapContainer=document.createElement("div"),this._minimapContainer.className="minimap-container",this._toggleMinimapBtn=document.createElement("button"),this._toggleMinimapBtn.className="toggle-minimap collapse-button",this._toggleMinimapBtn.innerHTML='<svg viewBox="-3.6 -3.6 31.2 31.2" stroke-width=".4"><path d="M15.707 4.293a1 1 0 0 1 0 1.414L9.414 12l6.293 6.293a1 1 0 0 1-1.414 1.414l-7-7a1 1 0 0 1 0-1.414l7-7a1 1 0 0 1 1.414 0Z" /></svg>',this._minimapContainer.appendChild(this._toggleMinimapBtn),this._minimap=document.createElement("div"),this._minimap.className="minimap";const n=document.createElement("canvas");n.className="minimap-canvas",n.width=200,n.height=150,this._minimap.appendChild(n),this._minimapCtx=n.getContext("2d"),this._viewportRectangle=document.createElement("div"),this._viewportRectangle.className="viewport-rectangle",this._minimap.appendChild(this._viewportRectangle),this._minimapContainer.appendChild(this._minimap),t.appendChild(this._minimapContainer),this._container=t,this.isMinimapVisible=!e,this._minimapContainer.classList.toggle("collapsed",e),this.minimapCache={scale:1,centerX:0,centerY:0},this._toggleMinimapBtn.addEventListener("click",this.toggleVisisbility),y(n,n.width,n.height)}get minimapCtx(){if(this._minimapCtx===null)throw l;return this._minimapCtx}get canvasData(){if(this._canvasData===null)throw l;return this._canvasData}get container(){if(this._container===null)throw l;return this._container}get minimap(){if(this._minimap===null)throw l;return this._minimap}get nodeBounds(){if(this._nodeBounds===null)throw l;return this._nodeBounds}get nodeMap(){if(this._nodeMap===null)throw l;return this._nodeMap}get viewportRectangle(){if(this._viewportRectangle===null)throw l;return this._viewportRectangle}get minimapContainer(){if(this._minimapContainer===null)throw l;return this._minimapContainer}get toggleMinimapBtn(){if(this._toggleMinimapBtn===null)throw l;return this._toggleMinimapBtn}receiveData(t,e,n){this._nodeBounds=t,this._canvasData=e,this._nodeMap=n,this.drawMinimap()}drawMinimap(){const t=this.nodeBounds;if(!t)return;const e=this.minimap.clientWidth,n=this.minimap.clientHeight,i=e/t.width,o=n/t.height;this.minimapCache.scale=Math.min(i,o)*.9,this.minimapCache.centerX=e/2,this.minimapCache.centerY=n/2,this.minimapCtx.clearRect(0,0,e,n),this.minimapCtx.save(),this.minimapCtx.translate(this.minimapCache.centerX,this.minimapCache.centerY),this.minimapCtx.scale(this.minimapCache.scale,this.minimapCache.scale),this.minimapCtx.translate(-t.centerX,-t.centerY);for(let s of this.canvasData.edges)this.drawMinimapEdge(s);for(let s of this.canvasData.nodes)this.drawMinimapNode(s);this.minimapCtx.restore()}drawMinimapNode(t){const e=E(t.color),n=25;this.minimapCtx.fillStyle=e.border,this.minimapCtx.globalAlpha=.3,C(this.minimapCtx,t.x,t.y,t.width,t.height,n),this.minimapCtx.fill(),this.minimapCtx.globalAlpha=1}drawMinimapEdge(t){const e=this.nodeMap[t.fromNode],n=this.nodeMap[t.toNode];if(!e||!n)return;const[i,o]=_(e,t.fromSide),[s,r]=_(n,t.toSide);this.minimapCtx.beginPath(),this.minimapCtx.moveTo(i,o),this.minimapCtx.lineTo(s,r),this.minimapCtx.strokeStyle="#555",this.minimapCtx.lineWidth=10,this.minimapCtx.stroke()}updateViewportRectangle(t,e,n){if(!this.isMinimapVisible)return;const i=this.nodeBounds;if(!i)return;const o=this.container.clientWidth/n,s=this.container.clientHeight/n,r=-t/n+this.container.clientWidth/(2*n),a=-e/n+this.container.clientHeight/(2*n),c=this.minimapCache.centerX+(r-o/2-i.centerX)*this.minimapCache.scale,p=this.minimapCache.centerY+(a-s/2-i.centerY)*this.minimapCache.scale,d=o*this.minimapCache.scale,u=s*this.minimapCache.scale;this.viewportRectangle.style.left=c+"px",this.viewportRectangle.style.top=p+"px",this.viewportRectangle.style.width=d+"px",this.viewportRectangle.style.height=u+"px"}dispose(){this.toggleMinimapBtn.removeEventListener("click",this.toggleVisisbility),this.minimapCtx.clearRect(0,0,this.minimap.clientWidth,this.minimap.clientHeight),this.minimapContainer.remove(),this._minimapContainer=null,this._minimapCtx=null,this._toggleMinimapBtn=null,this._canvasData=null,this._container=null,this._nodeMap=null,this._nodeBounds=null,this._viewportRectangle=null,this._minimap=null}}class D extends EventTarget{constructor(t,e=!1){super(),this.toggleCollapse=()=>this.controlsPanel.classList.toggle("collapsed"),this.zoomIn=()=>this.dispatchEvent(new CustomEvent("zoomIn")),this.zoomOut=()=>this.dispatchEvent(new CustomEvent("zoomOut")),this.slide=()=>this.dispatchEvent(new CustomEvent("slide",{detail:Math.pow(1.1,Number(this.zoomSlider.value))})),this.resetView=()=>this.dispatchEvent(new CustomEvent("resetView")),this.toggleFullscreen=()=>this.dispatchEvent(new CustomEvent("toggleFullscreen")),this.updateSlider=i=>this.zoomSlider.value=String(this.scaleToSlider(i)),this.scaleToSlider=i=>Math.log(i)/Math.log(1.1),this._controlsPanel=document.createElement("div"),this._controlsPanel.className="controls",this._controlsPanel.classList.toggle("collapsed",e),this._toggleCollapseBtn=document.createElement("button"),this._toggleCollapseBtn.className="collapse-button",this._toggleCollapseBtn.innerHTML='<svg viewBox="-3.6 -3.6 31.2 31.2" stroke-width=".4"><path d="M15.707 4.293a1 1 0 0 1 0 1.414L9.414 12l6.293 6.293a1 1 0 0 1-1.414 1.414l-7-7a1 1 0 0 1 0-1.414l7-7a1 1 0 0 1 1.414 0Z" /></svg>',this._controlsPanel.appendChild(this._toggleCollapseBtn);const n=document.createElement("div");n.className="controls-content",this._toggleFullscreenBtn=document.createElement("button"),this._toggleFullscreenBtn.innerHTML='<svg viewBox="-5.28 -5.28 34.56 34.56" fill="none"><path d="M4 9V5.6c0-.56 0-.84.109-1.054a1 1 0 0 1 .437-.437C4.76 4 5.04 4 5.6 4H9M4 15v3.4c0 .56 0 .84.109 1.054a1 1 0 0 0 .437.437C4.76 20 5.04 20 5.6 20H9m6-16h3.4c.56 0 .84 0 1.054.109a1 1 0 0 1 .437.437C20 4.76 20 5.04 20 5.6V9m0 6v3.4c0 .56 0 .84-.109 1.054a1 1 0 0 1-.437.437C19.24 20 18.96 20 18.4 20H15" stroke-width="2.4" stroke-linecap="round"/></svg>',n.appendChild(this._toggleFullscreenBtn),this._zoomOutBtn=document.createElement("button"),this._zoomOutBtn.innerHTML='<svg viewBox="-1.2 -1.2 26.4 26.4"><path d="M6 12h12" stroke-width="2" stroke-linecap="round" /></svg>',n.appendChild(this._zoomOutBtn),this._zoomSlider=document.createElement("input"),this._zoomSlider.type="range",this._zoomSlider.className="zoom-slider",this._zoomSlider.min="-30",this._zoomSlider.max="30",this._zoomSlider.value="0",n.appendChild(this._zoomSlider),this._zoomInBtn=document.createElement("button"),this._zoomInBtn.innerHTML='<svg viewBox="-1.2 -1.2 26.4 26.4"><path d="M6 12h12m-6-6v12" stroke-width="2" stroke-linecap="round" /></svg>',n.appendChild(this._zoomInBtn),this._resetViewBtn=document.createElement("button"),this._resetViewBtn.innerHTML='<svg viewBox="-6 -6 30 30" stroke-width=".08"><path d="m14.955 7.986.116.01a1 1 0 0 1 .85 1.13 8 8 0 0 1-13.374 4.728l-.84.84c-.63.63-1.707.184-1.707-.707V10h3.987c.89 0 1.337 1.077.707 1.707l-.731.731a6 6 0 0 0 8.347-.264 6 6 0 0 0 1.63-3.33 1 1 0 0 1 1.131-.848zM11.514.813a8 8 0 0 1 1.942 1.336l.837-.837c.63-.63 1.707-.184 1.707.707V6h-3.981c-.89 0-1.337-1.077-.707-1.707l.728-.729a6 6 0 0 0-9.98 3.591 1 1 0 1 1-1.98-.281A8 8 0 0 1 11.514.813Z" /></svg>',n.appendChild(this._resetViewBtn),this._controlsPanel.appendChild(n),t.appendChild(this._controlsPanel),this._toggleCollapseBtn.addEventListener("click",this.toggleCollapse),this._zoomInBtn.addEventListener("click",this.zoomIn),this._zoomOutBtn.addEventListener("click",this.zoomOut),this._zoomSlider.addEventListener("input",this.slide),this._resetViewBtn.addEventListener("click",this.resetView),this._toggleFullscreenBtn.addEventListener("click",this.toggleFullscreen)}get controlsPanel(){if(this._controlsPanel===null)throw l;return this._controlsPanel}get toggleCollapseBtn(){if(this._toggleCollapseBtn===null)throw l;return this._toggleCollapseBtn}get toggleFullscreenBtn(){if(this._toggleFullscreenBtn===null)throw l;return this._toggleFullscreenBtn}get zoomOutBtn(){if(this._zoomOutBtn===null)throw l;return this._zoomOutBtn}get zoomSlider(){if(this._zoomSlider===null)throw l;return this._zoomSlider}get zoomInBtn(){if(this._zoomInBtn===null)throw l;return this._zoomInBtn}get resetViewBtn(){if(this._resetViewBtn===null)throw l;return this._resetViewBtn}updateFullscreenBtn(){document.fullscreenElement===null?this.toggleFullscreenBtn.innerHTML='<svg viewBox="-40.32 -40.32 176.64 176.64"><path d="M30 60H6a6 6 0 0 0 0 12h18v18a6 6 0 0 0 12 0V66a5.997 5.997 0 0 0-6-6Zm60 0H66a5.997 5.997 0 0 0-6 6v24a6 6 0 0 0 12 0V72h18a6 6 0 0 0 0-12ZM66 36h24a6 6 0 0 0 0-12H72V6a6 6 0 0 0-12 0v24a5.997 5.997 0 0 0 6 6ZM30 0a5.997 5.997 0 0 0-6 6v18H6a6 6 0 0 0 0 12h24a5.997 5.997 0 0 0 6-6V6a5.997 5.997 0 0 0-6-6Z"/></svg>':this.toggleFullscreenBtn.innerHTML='<svg viewBox="-5.28 -5.28 34.56 34.56" fill="none"><path d="M4 9V5.6c0-.56 0-.84.109-1.054a1 1 0 0 1 .437-.437C4.76 4 5.04 4 5.6 4H9M4 15v3.4c0 .56 0 .84.109 1.054a1 1 0 0 0 .437.437C4.76 20 5.04 20 5.6 20H9m6-16h3.4c.56 0 .84 0 1.054.109a1 1 0 0 1 .437.437C20 4.76 20 5.04 20 5.6V9m0 6v3.4c0 .56 0 .84-.109 1.054a1 1 0 0 1-.437.437C19.24 20 18.96 20 18.4 20H15" stroke-width="2.4" stroke-linecap="round"/></svg>'}dispose(){this.toggleCollapseBtn.removeEventListener("click",this.toggleCollapse),this.zoomInBtn.removeEventListener("click",this.zoomIn),this.zoomOutBtn.removeEventListener("click",this.zoomOut),this.zoomSlider.removeEventListener("input",this.slide),this.resetViewBtn.removeEventListener("click",this.resetView),this.toggleFullscreenBtn.removeEventListener("click",this.toggleFullscreen),this.controlsPanel.remove(),this._controlsPanel=null,this._toggleCollapseBtn=null,this._zoomInBtn=null,this._zoomOutBtn=null,this._zoomSlider=null,this._resetViewBtn=null,this._toggleFullscreenBtn=null}}class I extends EventTarget{constructor(t){super(),this._canvasBaseDir=null,this.hidePreviewModal=()=>{this.previewModalBackdrop.classList.add("hidden"),this.previewModal.classList.add("hidden"),this.dispatchEvent(new CustomEvent("previewModalHidden"))},this._previewModalBackdrop=document.createElement("div"),this._previewModalBackdrop.className="preview-modal-backdrop hidden",t.appendChild(this._previewModalBackdrop),this._previewModal=document.createElement("div"),this._previewModal.className="preview-modal hidden",this._previewModalClose=document.createElement("button"),this._previewModalClose.className="preview-modal-close",this._previewModalClose.innerHTML='<svg viewBox="0 0 24 24"><path d="M6.758 17.243 12.001 12m5.243-5.243L12 12m0 0L6.758 6.757M12.001 12l5.243 5.243" stroke-width="2" stroke-linecap="round" /></svg>',this._previewModal.appendChild(this._previewModalClose),this._previewModalContent=document.createElement("div"),this._previewModalContent.className="preview-modal-content",this._previewModal.appendChild(this._previewModalContent),t.appendChild(this._previewModal),this._previewModalClose.addEventListener("click",this.hidePreviewModal),this._previewModalBackdrop.addEventListener("click",this.hidePreviewModal)}get previewModalBackdrop(){if(!this._previewModalBackdrop)throw l;return this._previewModalBackdrop}get previewModal(){if(!this._previewModal)throw l;return this._previewModal}get previewModalContent(){if(!this._previewModalContent)throw l;return this._previewModalContent}get canvasBaseDir(){if(!this._canvasBaseDir)throw l;return this._canvasBaseDir}get previewModalClose(){if(!this._previewModalClose)throw l;return this._previewModalClose}receiveData(t){this._canvasBaseDir=t}showPreviewModal(t){const e=this.processContent(t);if(!e)throw m;this.previewModalContent.innerHTML="",this.previewModalBackdrop.classList.remove("hidden"),this.previewModal.classList.remove("hidden"),this.previewModalContent.appendChild(e),this.dispatchEvent(new CustomEvent("previewModalShown"))}resize(t,e){this.previewModal.style.setProperty("--preview-max-width",`${t*.9}px`),this.previewModal.style.setProperty("--preview-max-height",`${e*.9}px`)}processContent(t){if(!t.file)throw m;let e;return t.file.match(/\.(png|jpg|jpeg|gif|svg)$/i)?(e=new Image,e.src=this.canvasBaseDir+t.file):t.file.match(/\.mp3$/i)&&(e=document.createElement("audio"),e.controls=!0,e.src=this.canvasBaseDir+t.file),e}dispose(){for(this.previewModalClose.removeEventListener("click",this.hidePreviewModal),this.previewModalBackdrop.removeEventListener("click",this.hidePreviewModal);this.previewModalContent.firstElementChild;)this.previewModalContent.firstElementChild.remove();this.previewModal.remove(),this.previewModalBackdrop.remove(),this._previewModal=null,this._previewModalClose=null,this._previewModalBackdrop=null,this._previewModalContent=null}}class B extends EventTarget{constructor(t){super(),this._nodeMap=null,this._canvasBaseDir=null,this.selectedId=null,this.eventListeners={},this.startInteract=()=>this.dispatchEvent(new CustomEvent("interactionStart")),this.endInteract=()=>this.dispatchEvent(new CustomEvent("interactionEnd")),this._overlaysLayer=document.createElement("div"),this._overlaysLayer.className="overlays",t.appendChild(this.overlaysLayer),this._overlays={}}get nodeMap(){if(!this._nodeMap)throw l;return this._nodeMap}get canvasBaseDir(){if(!this._canvasBaseDir)throw l;return this._canvasBaseDir}get overlays(){if(!this._overlays)throw l;return this._overlays}get overlaysLayer(){if(!this._overlaysLayer)throw l;return this._overlaysLayer}receiveData(t,e){this._canvasBaseDir=t,this._nodeMap=e}select(t){const e=this.selectedId?this.overlays[this.selectedId]:null,n=t?this.overlays[t]:null;e&&e.classList.remove("active"),n?(n.classList.add("active"),this.startInteract()):this.endInteract(),this.selectedId=t}async loadMarkdownForNode(t){if(!t.mdContent){t.mdContent="Loading...",this.updateOrCreateOverlay(t,t.mdContent,"markdown");try{if(!t.file)throw m;const n=await(await fetch(this.canvasBaseDir+t.file)).text(),i=n.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(i){const o=i[1].split(`
2
+ `).reduce((s,r)=>{const[a,c]=r.split(":").map(p=>p.trim());return s[a]=c,s},{});t.mdContent=await M.marked.parse(i[2].trim()),t.mdFrontmatter=o}else t.mdContent=await M.marked.parse(n)}catch(e){console.error("Failed to load markdown:",e),t.mdContent="Failed to load content."}}this.updateOrCreateOverlay(t,t.mdContent,"markdown")}updateAllOverlays(t,e,n){this.overlaysLayer.style.transform=`translate(${t}px, ${e}px) scale(${n})`;const i=new Set,o={text:s=>{if(!s.text)throw m;s.inViewport&&(i.add(s.id),this.updateOrCreateOverlay(s,s.text,"text"))},file:s=>{if(!s.file)throw m;s.inViewport&&(i.add(s.id),s.file.match(/\.md$/i)?this.loadMarkdownForNode(s):s.file.match(/\.(png|jpg|jpeg|gif|svg)$/i)&&this.updateOrCreateOverlay(s,this.canvasBaseDir+s.file,"image"))},link:s=>{if(!s.url)throw m;i.add(s.id),this.updateOrCreateOverlay(s,s.url,"link")},group:()=>{}};Object.values(this.nodeMap).forEach(s=>o[s.type](s)),Object.keys(this.overlays).forEach(s=>{if(!i.has(s)){const r=this.overlays[s];r&&r.parentNode&&r.parentNode.removeChild(r),delete this.overlays[s]}})}async updateOrCreateOverlay(t,e,n){let i=this.overlays[t.id];if(i||(i=await this.constructOverlay(t,e,n),this.overlaysLayer.appendChild(i),this.overlays[t.id]=i,i.style.left=t.x+"px",i.style.top=t.y+"px",i.style.width=t.width+"px",i.style.height=t.height+"px"),n==="markdown"){const o=i.getElementsByClassName("parsed-content-wrapper")[0];if(!t.mdContent)throw m;o.innerHTML!==t.mdContent&&(o.innerHTML=t.mdContent),!i.classList.contains("rtl")&&t.mdFrontmatter?.direction==="rtl"&&i.classList.add("rtl")}}async constructOverlay(t,e,n){const i=document.createElement("div");i.classList.add("overlay-container"),i.id=t.id;const o=document.createElement("div");if(o.className="overlay-border",i.appendChild(o),n==="text"||n==="markdown"){i.classList.add("markdown-content");const r=document.createElement("div");r.innerHTML=await M.marked.parse(e||""),r.classList.add("parsed-content-wrapper"),i.appendChild(r)}else if(n==="link"){const r=document.createElement("iframe");r.src=e,r.sandbox="allow-scripts allow-same-origin",r.className="link-iframe",r.loading="lazy";const a=document.createElement("div");a.className="link-click-layer",i.appendChild(r),i.appendChild(a)}else if(n==="image"){const r=document.createElement("img");r.src=e,r.loading="lazy",i.appendChild(r)}const s=t.color==null?"color-0":"color-"+t.color;if(i.classList.add(s),n!=="image"){this.selectedId===t.id&&i.classList.add("active");const r=()=>{t.id===this.selectedId&&this.startInteract()},a=()=>{t.id===this.selectedId&&this.endInteract()};i.addEventListener("pointerenter",r),i.addEventListener("pointerleave",a),i.addEventListener("touchstart",r),i.addEventListener("touchend",a),this.eventListeners[t.id]=[r,a]}return i}dispose(){for(this._overlays=null;this.overlaysLayer.firstElementChild;){const t=this.overlaysLayer.firstElementChild;if(this.eventListeners[t.id]){const e=this.eventListeners[t.id][0],n=this.eventListeners[t.id][1];if(!e||!n)throw l;t.removeEventListener("pointerenter",e),t.removeEventListener("pointerleave",n),t.removeEventListener("touchstart",e),t.removeEventListener("touchend",n),this.eventListeners[t.id][0]=null,this.eventListeners[t.id][1]=null}t.remove()}this.overlaysLayer.remove(),this._overlaysLayer=null,this._nodeMap=null}}class T extends EventTarget{constructor(t,e=!0){super(),this.preventMt=!1,this.onPointerDown=i=>{const o=this.container.getBoundingClientRect();i.clientX<o.left||i.clientX>o.right||i.clientY<o.top||i.clientY>o.bottom?this.preventMt||this.startPrevention():this.preventMt&&(this.preventMistouch.initialX=i.clientX,this.preventMistouch.initialY=i.clientY,this.preventMistouch.lastX=i.clientX,this.preventMistouch.lastY=i.clientY,this.preventMistouch.record=!0)},this.onPointerMove=i=>{this.preventMistouch.record&&(this.preventMistouch.lastX=i.clientX,this.preventMistouch.lastY=i.clientY)},this.onPointerUp=()=>{this.preventMistouch.record&&(this.preventMistouch.record=!1,Math.abs(this.preventMistouch.lastX-this.preventMistouch.initialX)+Math.abs(this.preventMistouch.lastY-this.preventMistouch.initialY)<5&&this.endPrevention())},this._preventionContainer=document.createElement("div"),this._preventionContainer.className="prevention-container hidden";const n=document.createElement("div");n.className="prevention-banner",n.innerHTML="Frozen to prevent mistouch, click on to unlock.",this._preventionContainer.appendChild(n),t.appendChild(this._preventionContainer),this._container=t,this.preventMistouch={record:!1,lastX:0,lastY:0,initialX:0,initialY:0},e&&this.startPrevention(),window.addEventListener("pointerdown",this.onPointerDown),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp)}get preventionContainer(){if(this._preventionContainer===null)throw l;return this._preventionContainer}get container(){if(this._container===null)throw l;return this._container}startPrevention(){this.preventionContainer.classList.remove("hidden"),this.container.classList.add("numb"),this.preventMt=!0,this.dispatchEvent(new CustomEvent("preventionStart"))}endPrevention(){this.preventMt=!1,this.preventionContainer.classList.add("hidden"),setTimeout(()=>this.container.classList.remove("numb"),50),this.dispatchEvent(new CustomEvent("preventionEnd"))}dispose(){window.removeEventListener("pointerdown",this.onPointerDown),window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp),this.preventionContainer.remove(),this._container=null,this._preventionContainer=null}}const P=".color-1{--border-color: rgba(255, 120, 129, .75);--background-color: rgba(255, 120, 129, .1);--active-color: rgba(255, 120, 129, 1)}.color-2{--border-color: rgba(251, 187, 131, .75);--background-color: rgba(251, 187, 131, .1);--active-color: rgba(251, 187, 131, 1)}.color-3{--border-color: rgba(255, 232, 139, .75);--background-color: rgba(255, 232, 139, .1);--active-color: rgba(255, 232, 139, 1)}.color-4{--border-color: rgba(124, 211, 124, .75);--background-color: rgba(124, 211, 124, .1);--active-color: rgba(124, 211, 124, 1)}.color-5{--border-color: rgba(134, 223, 226, .75);--background-color: rgba(134, 223, 226, .1);--active-color: rgba(134, 223, 226, 1)}.color-6{--border-color: rgba(203, 158, 255, .75);--background-color: rgba(203, 158, 255, .1);--active-color: rgba(203, 158, 255, 1)}.color-0{--border-color: rgba(140, 140, 140, .75);--background-color: rgba(140, 140, 140, .1);--active-color: rgba(140, 140, 140, 1)}.full,.preview-modal,.preview-modal-backdrop,.link-click-layer,.link-iframe,.prevention-container{top:0;left:0;width:100%;height:100%;position:absolute}.flex-center,.overlay-container.markdown-content,.prevention-container{display:flex;justify-content:center;align-items:center}.overlay-border{z-index:1}.container{--themeColor: rgb(254, 247, 167);--background-color: #141414;--contentTransition: color .2s, opacity .2s, text-shadow .2s, fill .2s;--containerTransition: background .2s, opacity .2s, box-shadow .2s, border .2s, filter .2s, backdrop-filter .2s;color:#fff;fill:#fff;stroke:#fff;position:relative;width:100%;height:100%;overflow:hidden;background-color:var(--background-color)}.container.numb,.container.numb *{pointer-events:none!important}.prevention-container{overflow:visible;transition:background .2s,opacity .2s,box-shadow .2s,border .2s,filter .2s,backdrop-filter .2s}.prevention-container.hidden{pointer-events:none}.prevention-container .prevention-banner{background:#0006;border-radius:12px;padding:12px;margin:12px;-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);border:2px solid rgba(140,140,140,.75);color:#fff;font-size:calc(14px + .3vw);line-height:calc(17px + .3vw);text-align:center}.main-canvas{width:100%;height:100%;transform-origin:top left}button{cursor:pointer;font-size:18px;height:32px;border:none;transition:var(--containerTransition);text-align:center;background-color:#444;width:32px;padding:5px 0}button svg{width:100%;height:100%}.overlays{position:absolute;top:0;left:0;width:100%;height:100%;transform-origin:top left;will-change:transform}.parsed-content-wrapper{font-family:sans-serif;box-sizing:border-box;max-width:100%;max-height:100%;padding:10px 6px;pointer-events:none;overflow:hidden;scrollbar-gutter:stable both-edges;display:flex;flex-direction:column;gap:12px}@supports not (scrollbar-gutter: stable both-edges){.parsed-content-wrapper{padding:10px}}.minimap-container{position:absolute;bottom:10px;right:10px;display:flex;pointer-events:none;transition:transform .2s}.minimap-container.collapsed{transform:translate(calc(100% - 32px))}@media (max-width: 768px){.minimap-container{transform:translateY(60px) translate(80px)}.minimap-container.collapsed{transform:translateY(60px) translate(calc(100% - 32px))}}.toggle-minimap{margin:auto 10px 0 0;pointer-events:auto}.collapsed .toggle-minimap{transform:rotate(180deg)}@media (max-width: 768px){.toggle-minimap{transform:translateY(-60px)}.collapsed .toggle-minimap{transform:translateY(-60px) rotate(180deg)}}.minimap{position:relative;width:200px;height:150px;overflow:hidden;border-radius:12px;background:#202020;-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);border:2px solid rgba(140,140,140,.75);transform-origin:0 0}@media (max-width: 768px){.minimap{transform:scale(.6)}}.minimap .minimap-canvas{width:100%;height:100%}.minimap .viewport-rectangle{position:absolute;top:0;left:0;pointer-events:none;border:2px solid #fff;border-radius:6px;box-sizing:border-box;background:transparent}.collapse-button{border-radius:8px;transition:transform .2s}.collapse-button:hover{background:#444c}.controls{position:absolute;top:10px;right:10px;display:flex;align-items:center;transition:transform .2s;border-radius:8px;gap:10px}.controls.collapsed{transform:translate(calc(100% - 32px))}.controls.collapsed .collapse-button{transform:rotate(180deg)}.controls .controls-content{display:flex;gap:1px;align-items:center;border-radius:8px;overflow:hidden;background:#333c}.controls button:hover{background:#555}.zoom-slider{width:100px;margin:0 10px}.overlay-container{position:absolute;box-sizing:border-box;border-radius:12px;overflow:hidden;background-color:var(--background-color);-webkit-user-select:none;user-select:none;contain:strict;transition:var(--containerTransition)}.overlay-container:hover{box-shadow:0 2px 12px #00000080}.overlay-container .overlay-border{box-sizing:border-box;pointer-events:none;position:absolute;top:0;left:0;width:100%;height:100%;border:2px solid var(--border-color);border-radius:12px;transition:var(--containerTransition)}.overlay-container img{width:100%;height:100%;object-fit:cover;pointer-events:none}.overlay-container.active .overlay-border{border:6px solid var(--active-color)}.overlay-container.markdown-content{position:absolute;padding:0 7px}.overlay-container.markdown-content.active .parsed-content-wrapper{overflow:auto;-webkit-user-select:text;user-select:text;pointer-events:auto}.overlay-container.markdown-content.rtl{direction:rtl;text-align:right}.link-iframe{contain-intrinsic-size:100% 100%;border:none}.link-click-layer{background:transparent;pointer-events:auto}.active .link-click-layer{pointer-events:none}.preview-modal-backdrop{-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);transition:var(--containerTransition)}.preview-modal-backdrop.hidden{pointer-events:none}.preview-modal{transition:var(--containerTransition);pointer-events:none}.preview-modal-close{position:absolute;right:10px;top:10px;background:none;border:none;font-size:24px;cursor:pointer;pointer-events:none}.preview-modal:not(.hidden) .preview-modal-close{pointer-events:auto}.preview-modal-content{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:fit-content;height:fit-content;pointer-events:none}.preview-modal:not(.hidden) .preview-modal-content{pointer-events:auto}.preview-modal-content>*{max-width:var(--preview-max-width);max-height:var(--preview-max-height);border:2px solid rgba(162,162,162,.5);box-shadow:0 2px 6px #0000004d;box-sizing:border-box}.preview-modal-content>img{border-radius:12px}.preview-modal-content>audio{border-radius:27px}.hidden{opacity:0}::-webkit-scrollbar{width:4px}::-webkit-scrollbar-track{background-color:transparent}::-webkit-scrollbar-thumb{border-radius:2px;background:#ffffff40}::-webkit-scrollbar-thumb:hover{background:#1e1e1ebf}p{font-size:16px;line-height:21px}.parsed-content-wrapper img{width:100%;border-radius:8px}h1{font-size:25px}h2{font-size:23px}h3{font-size:22px}h4{font-size:20px}h5{font-size:19px}h6{font-size:17px}p,h1,h2,h3,h4,h5,h6,ol,ul{margin:0}h1,h2{font-weight:800}h3,h4{font-weight:700}h5,h6{font-weight:600}code{background:#ffffff1a;padding:2px 4px;border-radius:8px}pre code{display:block;box-sizing:border-box;width:100%}pre:has(code),table{margin:6px 0}strong{color:#fe8e7c}em{color:#5affb2}a{text-decoration:none;color:#6dadd0;font-weight:800;font-style:italic;cursor:pointer;transition:var(--contentTransition)}a:hover{color:#86d3fd}hr{height:1px;width:100%;background-color:#fff3;border:none}li{margin:5px 0}ul{padding-left:16px}ol{padding-left:15px;padding-right:7.5px}table{border-collapse:collapse;border-spacing:0;border-radius:8px;border:1px solid rgba(255,255,255,.2);overflow:hidden;width:100%}table th,table td{border:1px solid rgba(255,255,255,.2);padding:6px 10px;background:#ffffff0f;text-align:left}table th{background:#ffffff1f;font-weight:700}";class z extends EventTarget{constructor(t,e=[],n=[]){super(),this.controls=null,this.minimap=null,this.mistouchPreventer=null,this.canvasBaseDir=null,this.animationId=null,this._canvasData=null,this._nodeMap=null,this._nodeBounds=null,this.spatialGrid=null,this.ZOOM_SMOOTHNESS=.25,this.INITIAL_VIEWPORT_PADDING=100,this.GRID_CELL_SIZE=800,this.draw=()=>{if(!this.perFrame.needAnimating&&!this.perFrame.pan&&!this.perFrame.zoom&&!this.perFrame.smoothZoom){this.animationId=requestAnimationFrame(this.draw);return}if(this.perFrame.needAnimating&&(this.perFrame.needAnimating=!1),this.perFrame.zoom){this.perFrame.zoom=!1;const s=this.interactor.getZoomDump();this.zoom(s.factor,s.origin),this.interactor.resetZoomDump()}this.perFrame.pan&&(this.perFrame.pan=!1,this.pan(this.interactor.getPanDump()),this.interactor.resetPanDump()),this.perFrame.smoothZoom&&this.smoothZoom(),this.refresh(),this.animationId=requestAnimationFrame(this.draw)},this.onClick=s=>{if(s instanceof CustomEvent){if(this.isUIControl(s.detail.target))return;const r=this.findNodeAt(this.C2W(this.C2C(s.detail.position))),a=this.judgeInteract(r);switch(a){case"non-interactive":this.overlayManager.select(null);break;case"select":if(!r)throw m;this.overlayManager.select(r.id);break;case"preview":if(!r)throw m;this.previewModal.showPreviewModal(r);break}r&&a!=="non-interactive"&&this.dispatchEvent(new CustomEvent("interact",{detail:{node:r.id,type:a}}))}else throw m},this.onResize=()=>{this.resizeState.resizeTimeout&&(clearTimeout(this.resizeState.resizeTimeout),this.resizeState.resizeTimeout=null);const s=Date.now();if(s-this.resizeState.lastCallTime<100){this.resizeState.resizeTimeout=setTimeout(()=>{this.resize(),this.resizeState.lastCallTime=s,this.resizeState.resizeTimeout=null},60);return}this.resizeState.lastCallTime=s,this.resize()},this.onPan=()=>this.perFrame.pan=!0,this.onZoom=()=>this.perFrame.zoom=!0,this.onSlide=s=>{if(s instanceof CustomEvent)this.setScale(s.detail);else throw m},this.onMinimapExpanded=()=>{this.minimap&&this.minimap.updateViewportRectangle(this.offsetX,this.offsetY,this.scale)},this.onPreventionStart=()=>{this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)},this.onPreventionEnd=()=>this.animationId=requestAnimationFrame(this.draw),this.stopInteractor=()=>this.interactor.stop(),this.startInteractor=()=>this.interactor.start(),this.onToggleFullscreen=()=>this.shiftFullscreen(),this.zoomIn=()=>this.setScale(this.scale*1.2),this.zoomOut=()=>this.setScale(this.scale/1.2),this.resetView=()=>{const s=this.nodeBounds;if(!s)return{scale:1,offsetX:this.container.clientWidth/2,offsetY:this.container.clientHeight/2};const r=s.width+this.INITIAL_VIEWPORT_PADDING*2,a=s.height+this.INITIAL_VIEWPORT_PADDING*2,c=this.container.clientWidth,p=this.container.clientHeight,d=c/r,u=p/a,v=Math.round(Math.min(d,u)*1e3)/1e3,f=s.centerX,g=s.centerY,w={scale:v,offsetX:c/2-f*v,offsetY:p/2-g*v};this.scale=w.scale,this.offsetX=w.offsetX,this.offsetY=w.offsetY,this.controls&&this.controls.updateSlider(this.scale),this.perFrame.needAnimating=!0};const i=t.attachShadow({mode:"open"}),o=document.createElement("style");o.innerHTML=P,i.appendChild(o),this._container=document.createElement("div"),this._container.classList.add("container"),this.renderer=new k(this._container),this.overlayManager=new B(this._container),this.interactor=new L(this._container,{preventDefault:!0,proControlSchema:n.includes("proControlSchema")}),this.resizeObserver=new ResizeObserver(this.onResize),e.includes("minimap")?this.minimap=new S(this._container,n.includes("minimapCollapsed")):n.includes("minimapCollapsed")&&console.warn('CanvasViewer: "minimapCollapsed" option is not supported without minimap extension.'),n.includes("controlsHidden")?n.includes("controlsCollapsed")&&console.warn('CanvasViewer: "controlsCollapsed" option is overridden by "controlsHidden" option.'):this.controls=new D(this._container,n.includes("controlsCollapsed")),this.previewModal=new I(this._container),e.includes("mistouchPrevention")&&(this.mistouchPreventer=new T(this._container,!n.includes("noPreventionAtStart"))),i.appendChild(this._container),this.extensions=e,this.options=n,this.offsetX=0,this.offsetY=0,this.scale=1,this.perFrame={needAnimating:!1,zoom:!1,smoothZoom:!1,targetScale:1,pan:!1},this.resizeState={resizeTimeout:null,lastCallTime:0,center:{lastX:null,lastY:null}}}get canvasData(){if(this._canvasData===null)throw l;return this._canvasData}get nodeMap(){if(this._nodeMap===null)throw l;return this._nodeMap}get nodeBounds(){if(this._nodeBounds===null)throw l;return this._nodeBounds}get container(){if(this._container===null)throw l;return this._container}isUIControl(t){return t.closest&&(t.closest(".controls")||t.closest("button")||t.closest("input"))}findNodeAt({x:t,y:e}){let n=[];if(!this.spatialGrid)n=this.canvasData.nodes;else{const i=Math.floor(t/this.GRID_CELL_SIZE),o=Math.floor(e/this.GRID_CELL_SIZE),s=`${i},${o}`;n=this.spatialGrid[s]||[]}for(const i of n)if(!(t<i.x||t>i.x+i.width||e<i.y||e>i.y+i.height||this.judgeInteract(i)==="non-interactive"))return i}C2C({x:t,y:e}){return{x:t-this.offsetX,y:e-this.offsetY}}C2W({x:t,y:e}){return{x:t/this.scale,y:e/this.scale}}middleScreen(){return{x:this.container.clientWidth/2,y:this.container.clientHeight/2}}judgeInteract(t){switch(t?t.type:"default"){case"text":return"select";case"link":return"select";case"file":if(!t||!t.file)throw m;return t.file.match(/\.md$/i)?"select":"preview";default:return"non-interactive"}}zoomToScale(t,e){const n=Math.max(Math.min(t,20),.05);if(n===this.scale)return;const i=this.C2C(e);this.offsetX=e.x-i.x*n/this.scale,this.offsetY=e.y-i.y*n/this.scale,this.scale=n,this.controls&&this.controls.updateSlider(this.scale)}buildSpatialGrid(){if(!(!this.canvasData||this.canvasData.nodes.length<50)){this.spatialGrid={};for(let t of this.canvasData.nodes){const e=Math.floor(t.x/this.GRID_CELL_SIZE),n=Math.floor((t.x+t.width)/this.GRID_CELL_SIZE),i=Math.floor(t.y/this.GRID_CELL_SIZE),o=Math.floor((t.y+t.height)/this.GRID_CELL_SIZE);for(let s=e;s<=n;s++)for(let r=i;r<=o;r++){const a=`${s},${r}`;this.spatialGrid[a]||(this.spatialGrid[a]=[]),this.spatialGrid[a].push(t)}}}}calculateNodeBounds(){if(!this.canvasData||!this.canvasData.nodes.length)return null;let t=1/0,e=1/0,n=-1/0,i=-1/0;this.canvasData.nodes.forEach(c=>{t=Math.min(t,c.x),e=Math.min(e,c.y),n=Math.max(n,c.x+c.width),i=Math.max(i,c.y+c.height)});const o=n-t,s=i-e,r=t+o/2,a=e+s/2;return{minX:t,minY:e,maxX:n,maxY:i,width:o,height:s,centerX:r,centerY:a}}refresh(){this.renderer.redraw(this.offsetX,this.offsetY,this.scale),this.overlayManager.updateAllOverlays(this.offsetX,this.offsetY,this.scale),this.minimap&&this.minimap.updateViewportRectangle(this.offsetX,this.offsetY,this.scale)}resize(){const t=this.resizeState.center,e=this.middleScreen();t.lastX&&t.lastY&&(this.offsetX+=e.x-t.lastX,this.offsetY+=e.y-t.lastY),t.lastX=e.x,t.lastY=e.y,this.renderer.resizeCanvasForDPR(),this.previewModal.resize(e.x*2,e.y*2),this.refresh()}pan({x:t,y:e}){this.offsetX+=t,this.offsetY+=e}zoom(t,e){const n=this.scale*t;this.zoomToScale(n,e)}smoothZoom(){const t=this.perFrame.targetScale-this.scale;let e;Math.abs(t)<this.perFrame.targetScale*.01+.002?(e=this.perFrame.targetScale,this.perFrame.smoothZoom=!1):e=Math.round((this.scale+t*this.ZOOM_SMOOTHNESS)*1e3)/1e3,this.zoomToScale(e,this.middleScreen())}setScale(t){this.perFrame.targetScale=t,this.perFrame.smoothZoom=!0}panTo(t,e){this.offsetX=this.container.clientWidth/2-t*this.scale,this.offsetY=this.container.clientHeight/2-e*this.scale,this.perFrame.needAnimating=!0}shiftFullscreen(t="toggle"){!document.fullscreenElement&&(t==="toggle"||t==="enter")?this.container.requestFullscreen():document.fullscreenElement&&(t==="toggle"||t==="exit")&&document.exitFullscreen(),this.controls&&this.controls.updateFullscreenBtn()}async loadCanvas(t){try{if(/^https?:\/\//.test(t))this.canvasBaseDir=t.substring(0,t.lastIndexOf("/")+1);else{const e=t.lastIndexOf("/");this.canvasBaseDir=e!==-1?t.substring(0,e+1):"./"}this._canvasData=await fetch(t).then(e=>e.json()),this._nodeMap={},this.canvasData.nodes.forEach(e=>{if(e.type==="file"&&e.file&&!e.file.includes("http")){const n=e.file.split("/");e.file=n[n.length-1]}this.nodeMap[e.id]=e}),this.buildSpatialGrid(),this._nodeBounds=this.calculateNodeBounds(),this.resetView(),this.resizeObserver.observe(this.container),this.interactor.start(),this.renderer.receiveData(this.nodeMap,this.canvasData),this.overlayManager.receiveData(this.canvasBaseDir,this.nodeMap),this.previewModal.receiveData(this.canvasBaseDir),this.interactor.addEventListener("trueClick",this.onClick),this.interactor.addEventListener("pan",this.onPan),this.interactor.addEventListener("zoom",this.onZoom),this.previewModal.addEventListener("previewModalShown",this.stopInteractor),this.previewModal.addEventListener("previewModalHidden",this.startInteractor),this.overlayManager.addEventListener("interactionStart",this.stopInteractor),this.overlayManager.addEventListener("interactionEnd",this.startInteractor),this.controls&&this.controls.addEventListener("zoomIn",this.zoomIn),this.controls&&this.controls.addEventListener("zoomOut",this.zoomOut),this.controls&&this.controls.addEventListener("slide",this.onSlide),this.controls&&this.controls.addEventListener("toggleFullscreen",this.onToggleFullscreen),this.controls&&this.controls.addEventListener("resetView",this.resetView),this.minimap&&(this.minimap.receiveData(this.nodeBounds,this.canvasData,this.nodeMap),this.minimap.addEventListener("minimapExpanded",this.onMinimapExpanded)),this.mistouchPreventer&&(this.mistouchPreventer.addEventListener("preventionStart",this.onPreventionStart),this.mistouchPreventer.addEventListener("preventionEnd",this.onPreventionEnd)),(!this.extensions.includes("mistouchPrevention")||this.options.includes("noPreventionAtStart"))&&(this.animationId=requestAnimationFrame(this.draw)),this.dispatchEvent(new CustomEvent("loaded",{detail:this.canvasData}))}catch(e){console.error("Failed to load canvas data:",e)}}dispose(){this.resizeState.resizeTimeout&&(clearTimeout(this.resizeState.resizeTimeout),this.resizeState.resizeTimeout=null),this.interactor.removeEventListener("trueClick",this.onClick),this.interactor.removeEventListener("pan",this.onPan),this.interactor.removeEventListener("zoom",this.onZoom),this.previewModal.removeEventListener("previewModalShown",this.stopInteractor),this.previewModal.removeEventListener("previewModalHidden",this.startInteractor),this.overlayManager.removeEventListener("interactionStart",this.stopInteractor),this.overlayManager.removeEventListener("interactionEnd",this.startInteractor),this.controls&&this.controls.removeEventListener("zoomIn",this.zoomIn),this.controls&&this.controls.removeEventListener("zoomOut",this.zoomOut),this.controls&&this.controls.removeEventListener("slide",this.onSlide),this.controls&&this.controls.removeEventListener("toggleFullscreen",this.onToggleFullscreen),this.controls&&this.controls.removeEventListener("resetView",this.resetView),this.minimap&&this.minimap.removeEventListener("minimapExpanded",this.onMinimapExpanded),this.mistouchPreventer&&(this.mistouchPreventer.removeEventListener("preventionStart",this.onPreventionStart),this.mistouchPreventer.removeEventListener("preventionEnd",this.onPreventionEnd)),this.animationId&&cancelAnimationFrame(this.animationId),this.resizeObserver.disconnect(),this.interactor.dispose(),this.previewModal.dispose(),this.controls&&this.controls.dispose(),this.minimap&&this.minimap.dispose(),this.mistouchPreventer&&this.mistouchPreventer.dispose(),this.overlayManager.dispose(),this.renderer.dispose(),this.container.remove(),this._container=null}}class O extends HTMLElement{constructor(){super(),this.style.display="block",this.style.overflow="hidden",this.style.maxWidth="120vw",this.style.maxHeight="120vh";const t=this.getAttribute("extensions"),e=this.getAttribute("options"),n=t?t.split(" "):[],i=e?e.split(" "):[];this.viewer=new z(this,n,i)}connectedCallback(){const t=this.getAttribute("src");if(!t)throw new Error("No source canvas path provided.");this.viewer&&this.viewer.loadCanvas(t)}disconnectedCallback(){this.viewer&&this.viewer.dispose(),this.remove()}}customElements.define("canvas-viewer",O);module.exports=z;
@@ -21,8 +21,9 @@ export default class canvasViewer extends EventTarget {
21
21
  private spatialGrid;
22
22
  private ZOOM_SMOOTHNESS;
23
23
  private INITIAL_VIEWPORT_PADDING;
24
- private perFrame;
25
24
  private GRID_CELL_SIZE;
25
+ private perFrame;
26
+ private resizeState;
26
27
  private get canvasData();
27
28
  private get nodeMap();
28
29
  private get nodeBounds();
@@ -38,6 +39,7 @@ export default class canvasViewer extends EventTarget {
38
39
  private buildSpatialGrid;
39
40
  private calculateNodeBounds;
40
41
  private draw;
42
+ private refresh;
41
43
  private resize;
42
44
  private pan;
43
45
  private zoom;
@@ -1 +1 @@
1
- import{marked as t}from"marked";const e=new Error("This error is unexpected, probably caused by file corruption. If you assure the error is not caused by accident, please contact the author and show how to reproduce."),i=new Error("Resource hasn't been set up or has been disposed.");class n{constructor(t){this._nodeMap=null,this._canvasData=null,this.ARROW_LENGTH=12,this.ARROW_WIDTH=7,this.FILE_NODE_RADIUS=12,this.FONT_COLOR="#fff",this.CSS_ZOOM_REDRAW_INTERVAL=500,this._canvas=document.createElement("canvas"),this._canvas.className="main-canvas",this._container=t,this._container.appendChild(this._canvas),this._ctx=this._canvas.getContext("2d"),this.zoomInOptimize={lastDrawnScale:0,lastDrawnViewport:{left:0,right:0,top:0,bottom:0},timeout:null,lastCallTime:0},a(this._canvas,t.offsetWidth,t.offsetHeight)}get nodeMap(){if(null===this._nodeMap)throw i;return this._nodeMap}get canvasData(){if(null===this._canvasData)throw i;return this._canvasData}get canvas(){if(null===this._canvas)throw i;return this._canvas}get ctx(){if(null===this._ctx)throw i;return this._ctx}get container(){if(null===this._container)throw i;return this._container}receiveData(t,e){this._nodeMap=t,this._canvasData=e}resizeCanvasForDPR(){a(this.canvas,this.container.offsetWidth,this.container.offsetHeight)}redraw(t,e,i){this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=null);const n=Date.now(),s=this.getCurrentViewport(t,e,i);if(this.isViewportInside(s,this.zoomInOptimize.lastDrawnViewport)&&i!==this.zoomInOptimize.lastDrawnScale&&n-this.zoomInOptimize.lastCallTime<this.CSS_ZOOM_REDRAW_INTERVAL)return this.zoomInOptimize.timeout=setTimeout(()=>{this.trueRedraw(t,e,i,s),this.zoomInOptimize.lastCallTime=n,this.zoomInOptimize.timeout=null},60),void this.fakeRedraw(s,i);this.zoomInOptimize.lastCallTime=n,this.trueRedraw(t,e,i,s)}dispose(){this.zoomInOptimize.timeout&&clearTimeout(this.zoomInOptimize.timeout),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.remove(),this.zoomInOptimize.timeout=null,this._ctx=null,this._canvas=null,this._container=null,this._canvasData=null,this._nodeMap=null}trueRedraw(t,e,i,n){this.zoomInOptimize.lastDrawnViewport=n,this.zoomInOptimize.lastDrawnScale=i,this.canvas.style.transform="",this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.save(),this.ctx.translate(t,e),this.ctx.scale(i,i),this.canvasData.nodes.forEach(n=>n.inViewport=this.isNodeInViewport(n,t,e,i)),this.canvasData.nodes.forEach(t=>{switch(t.type){case"group":this.drawGroup(t,i);break;case"file":this.drawFileNode(t)}}),this.canvasData.edges.forEach(t=>this.drawEdge(t)),this.ctx.restore()}fakeRedraw(t,e){const i=e/this.zoomInOptimize.lastDrawnScale,n=(this.zoomInOptimize.lastDrawnViewport.left-t.left)*e,s=(this.zoomInOptimize.lastDrawnViewport.top-t.top)*e;this.canvas.style.transform=`translate(${n}px, ${s}px) scale(${i})`}isViewportInside(t,e){return t.left>e.left&&t.top>e.top&&t.right<e.right&&t.bottom<e.bottom}isNodeInViewport(t,e,i,n,s=200){const o=-e/n-s,r=-i/n-s,a=o+this.container.clientWidth/n+2*s,l=r+this.container.clientHeight/n+2*s;return t.x+t.width>o&&t.x<a&&t.y+t.height>r&&t.y<l}getCurrentViewport(t,e,i){const n=-t/i,s=-e/i;return{left:n,top:s,right:n+this.container.clientWidth/i,bottom:s+this.container.clientHeight/i}}drawLabelBar(t,e,i,n,s){const o=30*s,r=6*s,a=8*s,l=16*s,h=6*s;this.ctx.save(),this.ctx.translate(t,e),this.ctx.scale(1/s,1/s),this.ctx.font=`${l}px 'Inter', sans-serif`;const c=this.ctx.measureText(i).width+2*h;this.ctx.translate(0,-o-a),this.ctx.fillStyle=n,this.ctx.beginPath(),this.ctx.moveTo(r,0),this.ctx.lineTo(c-r,0),this.ctx.quadraticCurveTo(c,0,c,r),this.ctx.lineTo(c,o-r),this.ctx.quadraticCurveTo(c,o,c-r,o),this.ctx.lineTo(r,o),this.ctx.quadraticCurveTo(0,o,0,o-r),this.ctx.lineTo(0,r),this.ctx.quadraticCurveTo(0,0,r,0),this.ctx.closePath(),this.ctx.fill(),this.ctx.fillStyle=this.FONT_COLOR,this.ctx.fillText(i,h,.65*o),this.ctx.restore()}drawNodeBackground(t){const e=r(t.color),i=this.FILE_NODE_RADIUS;this.ctx.globalAlpha=1,this.ctx.fillStyle=e.background,o(this.ctx,t.x+1,t.y+1,t.width-2,t.height-2,i),this.ctx.fill(),this.ctx.strokeStyle=e.border,this.ctx.lineWidth=2,o(this.ctx,t.x,t.y,t.width,t.height,i),this.ctx.stroke()}drawGroup(t,e){this.drawNodeBackground(t),t.label&&this.drawLabelBar(t.x,t.y,t.label,r(t.color).border,e)}drawFileNode(t){if(!t.file)throw e;t.file.match(/\.md|png|jpg|jpeg|gif|svg$/i)||(this.drawNodeBackground(t),t.file.match(/\.mp3$/i)&&(this.ctx.fillStyle=this.FONT_COLOR,this.ctx.textAlign="center",this.ctx.textBaseline="middle",this.ctx.fillText("🎵 Click to Preview 🎵",t.x+t.width/2,t.y+t.height/2),this.ctx.textAlign="left")),this.ctx.fillStyle=this.FONT_COLOR,this.ctx.font="16px sans-serif",this.ctx.fillText(t.file,t.x+5,t.y-10)}drawEdge(t){const{fromNode:i,toNode:n}=this.getEdgeNodes(t);if(!i||!n)throw e;const[r,a]=s(i,t.fromSide),[l,h]=s(n,t.toSide);let[c,d,p,m]=[0,0,0,0];if(t.controlPoints?[c,d,p,m]=t.controlPoints:([c,d,p,m]=this.getControlPoints(r,a,l,h,t.fromSide,t.toSide),t.controlPoints=[c,d,p,m]),this.drawCurvedPath(r,a,l,h,c,d,p,m),this.drawArrowhead(l,h,p,m),t.label){const e=Math.pow(.5,3)*r+3*Math.pow(.5,2)*.5*c+.375*p+Math.pow(.5,3)*l,i=Math.pow(.5,3)*a+3*Math.pow(.5,2)*.5*d+.375*m+Math.pow(.5,3)*h;this.ctx.font="18px sans-serif";const n=this.ctx.measureText(t.label).width+16,s=20;this.ctx.fillStyle="#222",this.ctx.beginPath(),o(this.ctx,e-n/2,i-s/2-2,n,s,4),this.ctx.fill(),this.ctx.fillStyle="#ccc",this.ctx.textAlign="center",this.ctx.textBaseline="middle",this.ctx.fillText(t.label,e,i-2),this.ctx.textAlign="left",this.ctx.textBaseline="alphabetic"}}getEdgeNodes(t){return{fromNode:this.nodeMap[t.fromNode],toNode:this.nodeMap[t.toNode]}}getControlPoints(t,e,i,n,s,o){const r=i-t,a=n-e,l=Math.min(Math.abs(r),Math.abs(a))+.3*Math.max(Math.abs(r),Math.abs(a)),h=(c=.5*l,Math.max(60,Math.min(300,c)));var c;let d=t,p=e,m=i,v=n;switch(s){case"top":p=e-h;break;case"bottom":p=e+h;break;case"left":d=t-h;break;case"right":d=t+h}switch(o){case"top":v=n-h;break;case"bottom":v=n+h;break;case"left":m=i-h;break;case"right":m=i+h}return[d,p,m,v]}drawCurvedPath(t,e,i,n,s,o,r,a){this.ctx.beginPath(),this.ctx.moveTo(t,e),this.ctx.bezierCurveTo(s,o,r,a,i,n),this.ctx.strokeStyle="#ccc",this.ctx.lineWidth=2,this.ctx.stroke()}drawArrowhead(t,e,i,n){const s=t-i,o=e-n,r=Math.sqrt(s*s+o*o);if(0===r)return;const a=s/r,l=o/r,h=t-a*this.ARROW_LENGTH-l*this.ARROW_WIDTH,c=e-l*this.ARROW_LENGTH+a*this.ARROW_WIDTH,d=t-a*this.ARROW_LENGTH+l*this.ARROW_WIDTH,p=e-l*this.ARROW_LENGTH-a*this.ARROW_WIDTH;this.ctx.beginPath(),this.ctx.fillStyle="#ccc",this.ctx.moveTo(t,e),this.ctx.lineTo(h,c),this.ctx.lineTo(d,p),this.ctx.closePath(),this.ctx.fill()}}function s(t,e){const i=t.x+t.width/2,n=t.y+t.height/2;switch(e){case"top":return[i,t.y];case"bottom":return[i,t.y+t.height];case"left":return[t.x,n];case"right":return[t.x+t.width,n];default:return[i,n]}}function o(t,e,i,n,s,o){t.beginPath(),t.moveTo(e+o,i),t.lineTo(e+n-o,i),t.quadraticCurveTo(e+n,i,e+n,i+o),t.lineTo(e+n,i+s-o),t.quadraticCurveTo(e+n,i+s,e+n-o,i+s),t.lineTo(e+o,i+s),t.quadraticCurveTo(e,i+s,e,i+s-o),t.lineTo(e,i+o),t.quadraticCurveTo(e,i,e+o,i),t.closePath()}function r(t){let e=null;switch(t){case"1":e="rgba(255, 120, 129, ?)";break;case"2":e="rgba(251, 187, 131, ?)";break;case"3":e="rgba(255, 232, 139, ?)";break;case"4":e="rgba(124, 211, 124, ?)";break;case"5":e="rgba(134, 223, 226, ?)";break;case"6":e="rgba(203, 158, 255, ?)";break;default:e="rgba(140, 140, 140, ?)"}return{border:e.replace("?","0.75"),background:e.replace("?","0.1"),active:e.replace("?","1")}}function a(t,i,n){const s=window.devicePixelRatio||1,o=t.getContext("2d");if(!o)throw e;t.width=Math.round(i*s),t.height=Math.round(n*s),o.setTransform(1,0,0,1,0,0),o.scale(s,s)}class l extends EventTarget{constructor(t,i){super(),this.pointers=new Map,this.onPointerDown=t=>{if(!(this.pointers.size>=2)&&(t.isPrimary&&this.pointers.clear(),this.pointers.set(t.pointerId,{startX:t.clientX,startY:t.clientY,lastX:t.clientX,lastY:t.clientY,interrupted:!1,target:t.target}),2===this.pointers.size)){const i=this.getNthValue(0),n=this.pointers.get(t.pointerId);if(!i||!n)throw e;i.interrupted=!0,n.interrupted=!0,this.pinchZoomState.lastDistance=this.getPointerDistance(),this.pinchZoomState.lastMidpoint=this.S2C(this.getPointerMidpoint())}},this.onPointerMove=t=>{const i=this.pointers.get(t.pointerId);if(i){if(1===this.pointers.size){const e=t.clientX-i.lastX,n=t.clientY-i.lastY;this.dispatchPanEvent({x:e,y:n})}if(this.pointers.set(t.pointerId,{startX:i.startX,startY:i.startY,lastX:t.clientX,lastY:t.clientY,interrupted:i.interrupted,target:i.target}),2===this.pointers.size){const t=this.getPointerDistance(),i=this.getPointerMidpoint();if(!t||!i)throw e;let n=t/this.pinchZoomState.lastDistance;this.pinchZoomState.lastDistance=t;const s=this.S2C(i),o=s.x-this.pinchZoomState.lastMidpoint.x,r=s.y-this.pinchZoomState.lastMidpoint.y;this.pinchZoomState.lastMidpoint=s,this.dispatchPanEvent({x:o,y:r}),this.dispatchZoomEvent(n,s)}}},this.onPointerUp=t=>{const e=this.pointers.get(t.pointerId);if(e&&(this.pointers.delete(t.pointerId),0===this.pointers.size&&!e.interrupted&&Math.abs(e.startX-t.clientX)+Math.abs(e.startY-t.clientY)<5)){const i=this.S2C({x:t.clientX,y:t.clientY}),n=new CustomEvent("trueClick",{detail:{position:i,target:e.target}});this.dispatchEvent(n)}},this.onWheel=t=>{if(!this.lockControlSchema&&!this.proControlSchema&&(t.ctrlKey||Math.abs(t.deltaX)>Math.abs(t.deltaY))&&(this.proControlSchema=!0),this.preventDefault&&t.preventDefault(),this.proControlSchema&&!t.ctrlKey)this.dispatchPanEvent({x:t.deltaX,y:t.deltaY});else{const e=1-this.zoomFactor*t.deltaY,i=this.S2C({x:t.clientX,y:t.clientY});this.dispatchZoomEvent(e,i)}},this.preventDefaultFunction=t=>t.preventDefault,this._monitoringElement=t;const n=i||{};this.preventDefault=n.preventDefault||!1,this.proControlSchema=n.proControlSchema||!1,this.zoomFactor=n.zoomFactor||.002,this.lockControlSchema=n.lockControlSchema||!1,this.pointers.clear(),this.pinchZoomState={lastDistance:0,lastMidpoint:{x:0,y:0}},this.panDump={x:0,y:0},this.zoomDump={factor:1,origin:{x:0,y:0}}}get monitoringElement(){if(null===this._monitoringElement)throw i;return this._monitoringElement}getNthValue(t){if(t<0||t>=this.pointers.size)throw e;let i=0;for(const e of this.pointers.values()){if(i===t)return e;i++}}getPointerDistance(){const t=this.getNthValue(0),i=this.getNthValue(1);if(!t||!i)throw e;const n=t.lastX-i.lastX,s=t.lastY-i.lastY;return Math.sqrt(n*n+s*s)}getPointerMidpoint(){const t=this.getNthValue(0),i=this.getNthValue(1);if(!t||!i)throw e;return{x:(t.lastX+i.lastX)/2,y:(t.lastY+i.lastY)/2}}S2C({x:t,y:e}){const i=this.monitoringElement.getBoundingClientRect();return{x:t-i.left,y:e-i.top}}dispatchPanEvent(t){const e={x:this.round(t.x,1),y:this.round(t.y,1)};this.panDump.x+=e.x,this.panDump.y+=e.y;const i=new CustomEvent("pan",{detail:e});this.dispatchEvent(i)}dispatchZoomEvent(t,e){const i=this.round(t,4);this.zoomDump.factor*=i,this.zoomDump.origin=e;const n=new CustomEvent("zoom",{detail:{factor:i,origin:e}});this.dispatchEvent(n)}round(t,e){const i=10**e;return Math.round(t*i)/i}getZoomDump(){return this.zoomDump}resetZoomDump(){this.zoomDump.factor=1}getPanDump(){return this.panDump}resetPanDump(){this.panDump={x:0,y:0}}stop(){this.monitoringElement.removeEventListener("pointerdown",this.onPointerDown),window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp),this.monitoringElement.removeEventListener("wheel",this.onWheel),this.preventDefault&&(this.monitoringElement.style.touchAction="",this.monitoringElement.removeEventListener("gesturestart",this.preventDefaultFunction),this.monitoringElement.removeEventListener("gesturechange",this.preventDefaultFunction))}start(){this.monitoringElement.addEventListener("pointerdown",this.onPointerDown),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp),this.monitoringElement.addEventListener("wheel",this.onWheel,this.preventDefault?{passive:!1}:{}),this.preventDefault&&(this.monitoringElement.style.touchAction="none",this.monitoringElement.addEventListener("gesturestart",this.preventDefaultFunction,{passive:!1}),this.monitoringElement.addEventListener("gesturechange",this.preventDefaultFunction,{passive:!1}))}dispose(){this.stop(),this.pointers.clear(),this._monitoringElement=null}}class h extends EventTarget{constructor(t,e=!1){super(),this._canvasData=null,this._nodeMap=null,this._nodeBounds=null,this.toggleVisisbility=()=>{this.isMinimapVisible=!this.isMinimapVisible,this.minimapContainer.classList.toggle("collapsed"),this.dispatchEvent(new CustomEvent(this.isMinimapVisible?"minimapExpanded":"minimapCollapsed"))},this._minimapContainer=document.createElement("div"),this._minimapContainer.className="minimap-container",this._toggleMinimapBtn=document.createElement("button"),this._toggleMinimapBtn.className="toggle-minimap collapse-button",this._toggleMinimapBtn.innerHTML='<svg viewBox="-3.6 -3.6 31.2 31.2" stroke-width=".4"><path d="M15.707 4.293a1 1 0 0 1 0 1.414L9.414 12l6.293 6.293a1 1 0 0 1-1.414 1.414l-7-7a1 1 0 0 1 0-1.414l7-7a1 1 0 0 1 1.414 0Z" /></svg>',this._minimapContainer.appendChild(this._toggleMinimapBtn),this._minimap=document.createElement("div"),this._minimap.className="minimap";const i=document.createElement("canvas");i.className="minimap-canvas",i.width=200,i.height=150,this._minimap.appendChild(i),this._minimapCtx=i.getContext("2d"),this._viewportRectangle=document.createElement("div"),this._viewportRectangle.className="viewport-rectangle",this._minimap.appendChild(this._viewportRectangle),this._minimapContainer.appendChild(this._minimap),t.appendChild(this._minimapContainer),this._container=t,this.isMinimapVisible=!e,this._minimapContainer.classList.toggle("collapsed",e),this.minimapCache={scale:1,centerX:0,centerY:0},this._toggleMinimapBtn.addEventListener("click",this.toggleVisisbility),a(i,i.width,i.height)}get minimapCtx(){if(null===this._minimapCtx)throw i;return this._minimapCtx}get canvasData(){if(null===this._canvasData)throw i;return this._canvasData}get container(){if(null===this._container)throw i;return this._container}get minimap(){if(null===this._minimap)throw i;return this._minimap}get nodeBounds(){if(null===this._nodeBounds)throw i;return this._nodeBounds}get nodeMap(){if(null===this._nodeMap)throw i;return this._nodeMap}get viewportRectangle(){if(null===this._viewportRectangle)throw i;return this._viewportRectangle}get minimapContainer(){if(null===this._minimapContainer)throw i;return this._minimapContainer}get toggleMinimapBtn(){if(null===this._toggleMinimapBtn)throw i;return this._toggleMinimapBtn}receiveData(t,e,i){this._nodeBounds=t,this._canvasData=e,this._nodeMap=i,this.drawMinimap()}drawMinimap(){const t=this.nodeBounds;if(!t)return;const e=this.minimap.clientWidth,i=this.minimap.clientHeight,n=e/t.width,s=i/t.height;this.minimapCache.scale=.9*Math.min(n,s),this.minimapCache.centerX=e/2,this.minimapCache.centerY=i/2,this.minimapCtx.clearRect(0,0,e,i),this.minimapCtx.save(),this.minimapCtx.translate(this.minimapCache.centerX,this.minimapCache.centerY),this.minimapCtx.scale(this.minimapCache.scale,this.minimapCache.scale),this.minimapCtx.translate(-t.centerX,-t.centerY);for(let t of this.canvasData.edges)this.drawMinimapEdge(t);for(let t of this.canvasData.nodes)this.drawMinimapNode(t);this.minimapCtx.restore()}drawMinimapNode(t){const e=r(t.color);this.minimapCtx.fillStyle=e.border,this.minimapCtx.globalAlpha=.3,o(this.minimapCtx,t.x,t.y,t.width,t.height,25),this.minimapCtx.fill(),this.minimapCtx.globalAlpha=1}drawMinimapEdge(t){const e=this.nodeMap[t.fromNode],i=this.nodeMap[t.toNode];if(!e||!i)return;const[n,o]=s(e,t.fromSide),[r,a]=s(i,t.toSide);this.minimapCtx.beginPath(),this.minimapCtx.moveTo(n,o),this.minimapCtx.lineTo(r,a),this.minimapCtx.strokeStyle="#555",this.minimapCtx.lineWidth=10,this.minimapCtx.stroke()}updateViewportRectangle(t,e,i){if(!this.isMinimapVisible)return;const n=this.nodeBounds;if(!n)return;const s=this.container.clientWidth/i,o=this.container.clientHeight/i,r=-t/i+this.container.clientWidth/(2*i),a=-e/i+this.container.clientHeight/(2*i),l=this.minimapCache.centerX+(r-s/2-n.centerX)*this.minimapCache.scale,h=this.minimapCache.centerY+(a-o/2-n.centerY)*this.minimapCache.scale,c=s*this.minimapCache.scale,d=o*this.minimapCache.scale;this.viewportRectangle.style.left=l+"px",this.viewportRectangle.style.top=h+"px",this.viewportRectangle.style.width=c+"px",this.viewportRectangle.style.height=d+"px"}dispose(){this.toggleMinimapBtn.removeEventListener("click",this.toggleVisisbility),this.minimapCtx.clearRect(0,0,this.minimap.clientWidth,this.minimap.clientHeight),this.minimapContainer.remove(),this._minimapContainer=null,this._minimapCtx=null,this._toggleMinimapBtn=null,this._canvasData=null,this._container=null,this._nodeMap=null,this._nodeBounds=null,this._viewportRectangle=null,this._minimap=null}}class c extends EventTarget{constructor(t,e=!1){super(),this.toggleCollapse=()=>this.controlsPanel.classList.toggle("collapsed"),this.zoomIn=()=>this.dispatchEvent(new CustomEvent("zoomIn")),this.zoomOut=()=>this.dispatchEvent(new CustomEvent("zoomOut")),this.slide=()=>this.dispatchEvent(new CustomEvent("slide",{detail:Math.pow(1.1,Number(this.zoomSlider.value))})),this.resetView=()=>this.dispatchEvent(new CustomEvent("resetView")),this.toggleFullscreen=()=>this.dispatchEvent(new CustomEvent("toggleFullscreen")),this.updateSlider=t=>this.zoomSlider.value=String(this.scaleToSlider(t)),this.scaleToSlider=t=>Math.log(t)/Math.log(1.1),this._controlsPanel=document.createElement("div"),this._controlsPanel.className="controls",this._controlsPanel.classList.toggle("collapsed",e),this._toggleCollapseBtn=document.createElement("button"),this._toggleCollapseBtn.className="collapse-button",this._toggleCollapseBtn.innerHTML='<svg viewBox="-3.6 -3.6 31.2 31.2" stroke-width=".4"><path d="M15.707 4.293a1 1 0 0 1 0 1.414L9.414 12l6.293 6.293a1 1 0 0 1-1.414 1.414l-7-7a1 1 0 0 1 0-1.414l7-7a1 1 0 0 1 1.414 0Z" /></svg>',this._controlsPanel.appendChild(this._toggleCollapseBtn);const i=document.createElement("div");i.className="controls-content",this._toggleFullscreenBtn=document.createElement("button"),this._toggleFullscreenBtn.innerHTML='<svg viewBox="-5.28 -5.28 34.56 34.56" fill="none"><path d="M4 9V5.6c0-.56 0-.84.109-1.054a1 1 0 0 1 .437-.437C4.76 4 5.04 4 5.6 4H9M4 15v3.4c0 .56 0 .84.109 1.054a1 1 0 0 0 .437.437C4.76 20 5.04 20 5.6 20H9m6-16h3.4c.56 0 .84 0 1.054.109a1 1 0 0 1 .437.437C20 4.76 20 5.04 20 5.6V9m0 6v3.4c0 .56 0 .84-.109 1.054a1 1 0 0 1-.437.437C19.24 20 18.96 20 18.4 20H15" stroke-width="2.4" stroke-linecap="round"/></svg>',i.appendChild(this._toggleFullscreenBtn),this._zoomOutBtn=document.createElement("button"),this._zoomOutBtn.innerHTML='<svg viewBox="-1.2 -1.2 26.4 26.4"><path d="M6 12h12" stroke-width="2" stroke-linecap="round" /></svg>',i.appendChild(this._zoomOutBtn),this._zoomSlider=document.createElement("input"),this._zoomSlider.type="range",this._zoomSlider.className="zoom-slider",this._zoomSlider.min="-30",this._zoomSlider.max="30",this._zoomSlider.value="0",i.appendChild(this._zoomSlider),this._zoomInBtn=document.createElement("button"),this._zoomInBtn.innerHTML='<svg viewBox="-1.2 -1.2 26.4 26.4"><path d="M6 12h12m-6-6v12" stroke-width="2" stroke-linecap="round" /></svg>',i.appendChild(this._zoomInBtn),this._resetViewBtn=document.createElement("button"),this._resetViewBtn.innerHTML='<svg viewBox="-6 -6 30 30" stroke-width=".08"><path d="m14.955 7.986.116.01a1 1 0 0 1 .85 1.13 8 8 0 0 1-13.374 4.728l-.84.84c-.63.63-1.707.184-1.707-.707V10h3.987c.89 0 1.337 1.077.707 1.707l-.731.731a6 6 0 0 0 8.347-.264 6 6 0 0 0 1.63-3.33 1 1 0 0 1 1.131-.848zM11.514.813a8 8 0 0 1 1.942 1.336l.837-.837c.63-.63 1.707-.184 1.707.707V6h-3.981c-.89 0-1.337-1.077-.707-1.707l.728-.729a6 6 0 0 0-9.98 3.591 1 1 0 1 1-1.98-.281A8 8 0 0 1 11.514.813Z" /></svg>',i.appendChild(this._resetViewBtn),this._controlsPanel.appendChild(i),t.appendChild(this._controlsPanel),this._toggleCollapseBtn.addEventListener("click",this.toggleCollapse),this._zoomInBtn.addEventListener("click",this.zoomIn),this._zoomOutBtn.addEventListener("click",this.zoomOut),this._zoomSlider.addEventListener("input",this.slide),this._resetViewBtn.addEventListener("click",this.resetView),this._toggleFullscreenBtn.addEventListener("click",this.toggleFullscreen)}get controlsPanel(){if(null===this._controlsPanel)throw i;return this._controlsPanel}get toggleCollapseBtn(){if(null===this._toggleCollapseBtn)throw i;return this._toggleCollapseBtn}get toggleFullscreenBtn(){if(null===this._toggleFullscreenBtn)throw i;return this._toggleFullscreenBtn}get zoomOutBtn(){if(null===this._zoomOutBtn)throw i;return this._zoomOutBtn}get zoomSlider(){if(null===this._zoomSlider)throw i;return this._zoomSlider}get zoomInBtn(){if(null===this._zoomInBtn)throw i;return this._zoomInBtn}get resetViewBtn(){if(null===this._resetViewBtn)throw i;return this._resetViewBtn}updateFullscreenBtn(){null===document.fullscreenElement?this.toggleFullscreenBtn.innerHTML='<svg viewBox="-40.32 -40.32 176.64 176.64"><path d="M30 60H6a6 6 0 0 0 0 12h18v18a6 6 0 0 0 12 0V66a5.997 5.997 0 0 0-6-6Zm60 0H66a5.997 5.997 0 0 0-6 6v24a6 6 0 0 0 12 0V72h18a6 6 0 0 0 0-12ZM66 36h24a6 6 0 0 0 0-12H72V6a6 6 0 0 0-12 0v24a5.997 5.997 0 0 0 6 6ZM30 0a5.997 5.997 0 0 0-6 6v18H6a6 6 0 0 0 0 12h24a5.997 5.997 0 0 0 6-6V6a5.997 5.997 0 0 0-6-6Z"/></svg>':this.toggleFullscreenBtn.innerHTML='<svg viewBox="-5.28 -5.28 34.56 34.56" fill="none"><path d="M4 9V5.6c0-.56 0-.84.109-1.054a1 1 0 0 1 .437-.437C4.76 4 5.04 4 5.6 4H9M4 15v3.4c0 .56 0 .84.109 1.054a1 1 0 0 0 .437.437C4.76 20 5.04 20 5.6 20H9m6-16h3.4c.56 0 .84 0 1.054.109a1 1 0 0 1 .437.437C20 4.76 20 5.04 20 5.6V9m0 6v3.4c0 .56 0 .84-.109 1.054a1 1 0 0 1-.437.437C19.24 20 18.96 20 18.4 20H15" stroke-width="2.4" stroke-linecap="round"/></svg>'}dispose(){this.toggleCollapseBtn.removeEventListener("click",this.toggleCollapse),this.zoomInBtn.removeEventListener("click",this.zoomIn),this.zoomOutBtn.removeEventListener("click",this.zoomOut),this.zoomSlider.removeEventListener("input",this.slide),this.resetViewBtn.removeEventListener("click",this.resetView),this.toggleFullscreenBtn.removeEventListener("click",this.toggleFullscreen),this.controlsPanel.remove(),this._controlsPanel=null,this._toggleCollapseBtn=null,this._zoomInBtn=null,this._zoomOutBtn=null,this._zoomSlider=null,this._resetViewBtn=null,this._toggleFullscreenBtn=null}}class d extends EventTarget{constructor(t){super(),this._canvasBaseDir=null,this.hidePreviewModal=()=>{this.previewModalBackdrop.classList.add("hidden"),this.previewModal.classList.add("hidden"),this.dispatchEvent(new CustomEvent("previewModalHidden"))},this._previewModalBackdrop=document.createElement("div"),this._previewModalBackdrop.className="preview-modal-backdrop hidden",t.appendChild(this._previewModalBackdrop),this._previewModal=document.createElement("div"),this._previewModal.className="preview-modal hidden",this._previewModalClose=document.createElement("button"),this._previewModalClose.className="preview-modal-close",this._previewModalClose.innerHTML='<svg viewBox="0 0 24 24"><path d="M6.758 17.243 12.001 12m5.243-5.243L12 12m0 0L6.758 6.757M12.001 12l5.243 5.243" stroke-width="2" stroke-linecap="round" /></svg>',this._previewModal.appendChild(this._previewModalClose),this._previewModalContent=document.createElement("div"),this._previewModalContent.className="preview-modal-content",this._previewModal.appendChild(this._previewModalContent),t.appendChild(this._previewModal),this._previewModalClose.addEventListener("click",this.hidePreviewModal),this._previewModalBackdrop.addEventListener("click",this.hidePreviewModal)}get previewModalBackdrop(){if(!this._previewModalBackdrop)throw i;return this._previewModalBackdrop}get previewModal(){if(!this._previewModal)throw i;return this._previewModal}get previewModalContent(){if(!this._previewModalContent)throw i;return this._previewModalContent}get canvasBaseDir(){if(!this._canvasBaseDir)throw i;return this._canvasBaseDir}get previewModalClose(){if(!this._previewModalClose)throw i;return this._previewModalClose}receiveData(t){this._canvasBaseDir=t}showPreviewModal(t){const i=this.processContent(t);if(!i)throw e;this.previewModalContent.innerHTML="",this.previewModalBackdrop.classList.remove("hidden"),this.previewModal.classList.remove("hidden"),this.previewModalContent.appendChild(i),this.dispatchEvent(new CustomEvent("previewModalShown"))}resize(t,e){this.previewModal.style.setProperty("--preview-max-width",.9*t+"px"),this.previewModal.style.setProperty("--preview-max-height",.9*e+"px")}processContent(t){if(!t.file)throw e;let i;return t.file.match(/\.(png|jpg|jpeg|gif|svg)$/i)?(i=new Image,i.src=this.canvasBaseDir+t.file):t.file.match(/\.mp3$/i)&&(i=document.createElement("audio"),i.controls=!0,i.src=this.canvasBaseDir+t.file),i}dispose(){for(this.previewModalClose.removeEventListener("click",this.hidePreviewModal),this.previewModalBackdrop.removeEventListener("click",this.hidePreviewModal);this.previewModalContent.firstElementChild;)this.previewModalContent.firstElementChild.remove();this.previewModal.remove(),this.previewModalBackdrop.remove(),this._previewModal=null,this._previewModalClose=null,this._previewModalBackdrop=null,this._previewModalContent=null}}class p extends EventTarget{constructor(t){super(),this._nodeMap=null,this._canvasBaseDir=null,this.selectedId=null,this.eventListeners={},this.startInteract=()=>this.dispatchEvent(new CustomEvent("interactionStart")),this.endInteract=()=>this.dispatchEvent(new CustomEvent("interactionEnd")),this._overlaysLayer=document.createElement("div"),this._overlaysLayer.className="overlays",t.appendChild(this.overlaysLayer),this._overlays={}}get nodeMap(){if(!this._nodeMap)throw i;return this._nodeMap}get canvasBaseDir(){if(!this._canvasBaseDir)throw i;return this._canvasBaseDir}get overlays(){if(!this._overlays)throw i;return this._overlays}get overlaysLayer(){if(!this._overlaysLayer)throw i;return this._overlaysLayer}receiveData(t,e){this._canvasBaseDir=t,this._nodeMap=e}select(t){const e=this.selectedId?this.overlays[this.selectedId]:null,i=t?this.overlays[t]:null;e&&e.classList.remove("active"),i?(i.classList.add("active"),this.startInteract()):this.endInteract(),this.selectedId=t}async loadMarkdownForNode(i){if(!i.mdContent){i.mdContent="Loading...",this.updateOrCreateOverlay(i,i.mdContent,"markdown");try{if(!i.file)throw e;const n=await(await fetch(this.canvasBaseDir+i.file)).text(),s=n.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(s){const e=s[1].split("\n").reduce((t,e)=>{const[i,n]=e.split(":").map(t=>t.trim());return t[i]=n,t},{});i.mdContent=await t.parse(s[2].trim()),i.mdFrontmatter=e}else i.mdContent=await t.parse(n)}catch(t){console.error("Failed to load markdown:",t),i.mdContent="Failed to load content."}}this.updateOrCreateOverlay(i,i.mdContent,"markdown")}updateAllOverlays(t,i,n){this.overlaysLayer.style.transform=`translate(${t}px, ${i}px) scale(${n})`;const s=new Set,o={text:t=>{if(!t.text)throw e;t.inViewport&&(s.add(t.id),this.updateOrCreateOverlay(t,t.text,"text"))},file:t=>{if(!t.file)throw e;t.inViewport&&(s.add(t.id),t.file.match(/\.md$/i)?this.loadMarkdownForNode(t):t.file.match(/\.(png|jpg|jpeg|gif|svg)$/i)&&this.updateOrCreateOverlay(t,this.canvasBaseDir+t.file,"image"))},link:t=>{if(!t.url)throw e;s.add(t.id),this.updateOrCreateOverlay(t,t.url,"link")},group:()=>{}};Object.values(this.nodeMap).forEach(t=>o[t.type](t)),Object.keys(this.overlays).forEach(t=>{if(!s.has(t)){const e=this.overlays[t];e&&e.parentNode&&e.parentNode.removeChild(e),delete this.overlays[t]}})}async updateOrCreateOverlay(t,i,n){let s=this.overlays[t.id];if(s||(s=await this.constructOverlay(t,i,n),this.overlaysLayer.appendChild(s),this.overlays[t.id]=s,s.style.left=t.x+"px",s.style.top=t.y+"px",s.style.width=t.width+"px",s.style.height=t.height+"px"),"markdown"===n){const i=s.getElementsByClassName("parsed-content-wrapper")[0];if(!t.mdContent)throw e;i.innerHTML!==t.mdContent&&(i.innerHTML=t.mdContent),!s.classList.contains("rtl")&&"rtl"===t.mdFrontmatter?.direction&&s.classList.add("rtl")}}async constructOverlay(e,i,n){const s=document.createElement("div");s.classList.add("overlay-container"),s.id=e.id;const o=document.createElement("div");if(o.className="overlay-border",s.appendChild(o),"text"===n||"markdown"===n){s.classList.add("markdown-content");const e=document.createElement("div");e.innerHTML=await t.parse(i||""),e.classList.add("parsed-content-wrapper"),s.appendChild(e)}else if("link"===n){const t=document.createElement("iframe");t.src=i,t.sandbox="allow-scripts allow-same-origin",t.className="link-iframe",t.loading="lazy";const e=document.createElement("div");e.className="link-click-layer",s.appendChild(t),s.appendChild(e)}else if("image"===n){const t=document.createElement("img");t.src=i,t.loading="lazy",s.appendChild(t)}const r=null==e.color?"color-0":"color-"+e.color;if(s.classList.add(r),"image"!==n){this.selectedId===e.id&&s.classList.add("active");const t=()=>{e.id===this.selectedId&&this.startInteract()},i=()=>{e.id===this.selectedId&&this.endInteract()};s.addEventListener("pointerenter",t),s.addEventListener("pointerleave",i),s.addEventListener("touchstart",t),s.addEventListener("touchend",i),this.eventListeners[e.id]=[t,i]}return s}dispose(){for(this._overlays=null;this.overlaysLayer.firstElementChild;){const t=this.overlaysLayer.firstElementChild;if(this.eventListeners[t.id]){const e=this.eventListeners[t.id][0],n=this.eventListeners[t.id][1];if(!e||!n)throw i;t.removeEventListener("pointerenter",e),t.removeEventListener("pointerleave",n),t.removeEventListener("touchstart",e),t.removeEventListener("touchend",n),this.eventListeners[t.id][0]=null,this.eventListeners[t.id][1]=null}t.remove()}this.overlaysLayer.remove(),this._overlaysLayer=null,this._nodeMap=null}}class m extends EventTarget{constructor(t,e=!0){super(),this.preventMt=!1,this.onPointerDown=t=>{const e=this.container.getBoundingClientRect();t.clientX<e.left||t.clientX>e.right||t.clientY<e.top||t.clientY>e.bottom?this.preventMt||this.startPrevention():this.preventMt&&(this.preventMistouch.initialX=t.clientX,this.preventMistouch.initialY=t.clientY,this.preventMistouch.lastX=t.clientX,this.preventMistouch.lastY=t.clientY,this.preventMistouch.record=!0)},this.onPointerMove=t=>{this.preventMistouch.record&&(this.preventMistouch.lastX=t.clientX,this.preventMistouch.lastY=t.clientY)},this.onPointerUp=()=>{this.preventMistouch.record&&(this.preventMistouch.record=!1,Math.abs(this.preventMistouch.lastX-this.preventMistouch.initialX)+Math.abs(this.preventMistouch.lastY-this.preventMistouch.initialY)<5&&this.endPrevention())},this._preventionContainer=document.createElement("div"),this._preventionContainer.className="prevention-container hidden";const i=document.createElement("div");i.className="prevention-banner",i.innerHTML="Frozen to prevent mistouch, click on to unlock.",this._preventionContainer.appendChild(i),t.appendChild(this._preventionContainer),this._container=t,this.preventMistouch={record:!1,lastX:0,lastY:0,initialX:0,initialY:0},e&&this.startPrevention(),window.addEventListener("pointerdown",this.onPointerDown),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp)}get preventionContainer(){if(null===this._preventionContainer)throw i;return this._preventionContainer}get container(){if(null===this._container)throw i;return this._container}startPrevention(){this.preventionContainer.classList.remove("hidden"),this.container.classList.add("numb"),this.preventMt=!0,this.dispatchEvent(new CustomEvent("preventionStart"))}endPrevention(){this.preventMt=!1,this.preventionContainer.classList.add("hidden"),setTimeout(()=>this.container.classList.remove("numb"),50),this.dispatchEvent(new CustomEvent("preventionEnd"))}dispose(){window.removeEventListener("pointerdown",this.onPointerDown),window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp),this.preventionContainer.remove(),this._container=null,this._preventionContainer=null}}class v extends EventTarget{constructor(t,i=[],s=[]){super(),this.controls=null,this.minimap=null,this.mistouchPreventer=null,this.canvasBaseDir=null,this.animationId=null,this._canvasData=null,this._nodeMap=null,this._nodeBounds=null,this.spatialGrid=null,this.draw=()=>{if(this.perFrame.needAnimating||this.perFrame.pan||this.perFrame.resize||this.perFrame.zoom||this.perFrame.smoothZoom){if(this.perFrame.needAnimating&&(this.perFrame.needAnimating=!1),this.perFrame.zoom){this.perFrame.zoom=!1;const t=this.interactor.getZoomDump();this.zoom(t.factor,t.origin),this.interactor.resetZoomDump()}this.perFrame.pan&&(this.perFrame.pan=!1,this.pan(this.interactor.getPanDump()),this.interactor.resetPanDump()),this.perFrame.smoothZoom&&this.smoothZoom(),this.perFrame.resize&&this.resize(),this.renderer.redraw(this.offsetX,this.offsetY,this.scale),this.overlayManager.updateAllOverlays(this.offsetX,this.offsetY,this.scale),this.minimap&&this.minimap.updateViewportRectangle(this.offsetX,this.offsetY,this.scale),this.animationId=requestAnimationFrame(this.draw)}else this.animationId=requestAnimationFrame(this.draw)},this.onClick=t=>{if(!(t instanceof CustomEvent))throw e;{if(this.isUIControl(t.detail.target))return;const i=this.findNodeAt(this.C2W(this.C2C(t.detail.position))),n=this.judgeInteract(i);switch(n){case"non-interactive":this.overlayManager.select(null);break;case"select":if(!i)throw e;this.overlayManager.select(i.id);break;case"preview":if(!i)throw e;this.previewModal.showPreviewModal(i)}i&&"non-interactive"!==n&&this.dispatchEvent(new CustomEvent("interact",{detail:{node:i.id,type:n}}))}},this.onResize=()=>{this.perFrame.resize=!0,this.perFrame.resizeScale.width=this.container.clientWidth,this.perFrame.resizeScale.height=this.container.clientHeight},this.onPan=()=>this.perFrame.pan=!0,this.onZoom=()=>this.perFrame.zoom=!0,this.onSlide=t=>{if(!(t instanceof CustomEvent))throw e;this.setScale(t.detail)},this.onMinimapExpanded=()=>{this.minimap&&this.minimap.updateViewportRectangle(this.offsetX,this.offsetY,this.scale)},this.onPreventionStart=()=>{this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)},this.onPreventionEnd=()=>this.animationId=requestAnimationFrame(this.draw),this.stopInteractor=()=>this.interactor.stop(),this.startInteractor=()=>this.interactor.start(),this.onToggleFullscreen=()=>this.shiftFullscreen(),this.zoomIn=()=>this.setScale(1.2*this.scale),this.zoomOut=()=>this.setScale(this.scale/1.2),this.resetView=()=>{const t=this.nodeBounds;if(!t)return{scale:1,offsetX:this.container.clientWidth/2,offsetY:this.container.clientHeight/2};const e=t.width+2*this.INITIAL_VIEWPORT_PADDING,i=t.height+2*this.INITIAL_VIEWPORT_PADDING,n=this.container.clientWidth,s=this.container.clientHeight,o=n/e,r=s/i,a=Math.round(1e3*Math.min(o,r))/1e3,l={scale:a,offsetX:n/2-t.centerX*a,offsetY:s/2-t.centerY*a};this.scale=l.scale,this.offsetX=l.offsetX,this.offsetY=l.offsetY,this.controls&&this.controls.updateSlider(this.scale),this.perFrame.needAnimating=!0};const o=t.attachShadow({mode:"open"}),r=document.createElement("style");r.innerHTML=".color-1{--border-color: rgba(255, 120, 129, .75);--background-color: rgba(255, 120, 129, .1);--active-color: rgba(255, 120, 129, 1)}.color-2{--border-color: rgba(251, 187, 131, .75);--background-color: rgba(251, 187, 131, .1);--active-color: rgba(251, 187, 131, 1)}.color-3{--border-color: rgba(255, 232, 139, .75);--background-color: rgba(255, 232, 139, .1);--active-color: rgba(255, 232, 139, 1)}.color-4{--border-color: rgba(124, 211, 124, .75);--background-color: rgba(124, 211, 124, .1);--active-color: rgba(124, 211, 124, 1)}.color-5{--border-color: rgba(134, 223, 226, .75);--background-color: rgba(134, 223, 226, .1);--active-color: rgba(134, 223, 226, 1)}.color-6{--border-color: rgba(203, 158, 255, .75);--background-color: rgba(203, 158, 255, .1);--active-color: rgba(203, 158, 255, 1)}.color-0{--border-color: rgba(140, 140, 140, .75);--background-color: rgba(140, 140, 140, .1);--active-color: rgba(140, 140, 140, 1)}.full,.preview-modal,.preview-modal-backdrop,.link-click-layer,.link-iframe,.prevention-container{top:0;left:0;width:100%;height:100%;position:absolute}.flex-center,.overlay-container.markdown-content,.prevention-container{display:flex;justify-content:center;align-items:center}.overlay-border{z-index:1}.container{--themeColor: rgb(254, 247, 167);--background-color: #141414;--contentTransition: color .2s, opacity .2s, text-shadow .2s, fill .2s;--containerTransition: background .2s, opacity .2s, box-shadow .2s, border .2s, filter .2s, backdrop-filter .2s;color:#fff;fill:#fff;stroke:#fff;position:relative;width:100%;height:100%;overflow:hidden;background-color:var(--background-color)}.container.numb,.container.numb *{pointer-events:none!important}.prevention-container{overflow:visible;transition:background .2s,opacity .2s,box-shadow .2s,border .2s,filter .2s,backdrop-filter .2s}.prevention-container.hidden{pointer-events:none}.prevention-container .prevention-banner{background:#0006;border-radius:12px;padding:12px;margin:12px;-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);border:2px solid rgba(140,140,140,.75);color:#fff;font-size:calc(14px + .3vw);line-height:calc(17px + .3vw);text-align:center}.main-canvas{width:100%;height:100%;transform-origin:top left}button{cursor:pointer;font-size:18px;height:32px;border:none;transition:var(--containerTransition);text-align:center;background-color:#444;width:32px;padding:5px 0}button svg{width:100%;height:100%}.overlays{position:absolute;top:0;left:0;width:100%;height:100%;transform-origin:top left;will-change:transform}.parsed-content-wrapper{font-family:sans-serif;box-sizing:border-box;max-width:100%;max-height:100%;padding:10px 6px;pointer-events:none;overflow:hidden;scrollbar-gutter:stable both-edges;display:flex;flex-direction:column;gap:12px}@supports not (scrollbar-gutter: stable both-edges){.parsed-content-wrapper{padding:10px}}.minimap-container{position:absolute;bottom:10px;right:10px;display:flex;pointer-events:none;transition:transform .2s}.minimap-container.collapsed{transform:translate(calc(100% - 32px))}@media (max-width: 768px){.minimap-container{transform:translateY(60px) translate(80px)}.minimap-container.collapsed{transform:translateY(60px) translate(calc(100% - 32px))}}.toggle-minimap{margin:auto 10px 0 0;pointer-events:auto}.collapsed .toggle-minimap{transform:rotate(180deg)}@media (max-width: 768px){.toggle-minimap{transform:translateY(-60px)}.collapsed .toggle-minimap{transform:translateY(-60px) rotate(180deg)}}.minimap{position:relative;width:200px;height:150px;overflow:hidden;border-radius:12px;background:#202020;-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);border:2px solid rgba(140,140,140,.75);transform-origin:0 0}@media (max-width: 768px){.minimap{transform:scale(.6)}}.minimap .minimap-canvas{width:100%;height:100%}.minimap .viewport-rectangle{position:absolute;top:0;left:0;pointer-events:none;border:2px solid #fff;border-radius:6px;box-sizing:border-box;background:transparent}.collapse-button{border-radius:8px;transition:transform .2s}.collapse-button:hover{background:#444c}.controls{position:absolute;top:10px;right:10px;display:flex;align-items:center;transition:transform .2s;border-radius:8px;gap:10px}.controls.collapsed{transform:translate(calc(100% - 32px))}.controls.collapsed .collapse-button{transform:rotate(180deg)}.controls .controls-content{display:flex;gap:1px;align-items:center;border-radius:8px;overflow:hidden;background:#333c}.controls button:hover{background:#555}.zoom-slider{width:100px;margin:0 10px}.overlay-container{position:absolute;box-sizing:border-box;border-radius:12px;overflow:hidden;background-color:var(--background-color);-webkit-user-select:none;user-select:none;contain:strict;transition:var(--containerTransition)}.overlay-container:hover{box-shadow:0 2px 12px #00000080}.overlay-container .overlay-border{box-sizing:border-box;pointer-events:none;position:absolute;top:0;left:0;width:100%;height:100%;border:2px solid var(--border-color);border-radius:12px;transition:var(--containerTransition)}.overlay-container img{width:100%;height:100%;object-fit:cover;pointer-events:none}.overlay-container.active .overlay-border{border:6px solid var(--active-color)}.overlay-container.markdown-content{position:absolute;padding:0 7px}.overlay-container.markdown-content.active .parsed-content-wrapper{overflow:auto;-webkit-user-select:text;user-select:text;pointer-events:auto}.overlay-container.markdown-content.rtl{direction:rtl;text-align:right}.link-iframe{contain-intrinsic-size:100% 100%;border:none}.link-click-layer{background:transparent;pointer-events:auto}.active .link-click-layer{pointer-events:none}.preview-modal-backdrop{-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);transition:var(--containerTransition)}.preview-modal-backdrop.hidden{pointer-events:none}.preview-modal{transition:var(--containerTransition);pointer-events:none}.preview-modal-close{position:absolute;right:10px;top:10px;background:none;border:none;font-size:24px;cursor:pointer;pointer-events:none}.preview-modal:not(.hidden) .preview-modal-close{pointer-events:auto}.preview-modal-content{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:fit-content;height:fit-content;pointer-events:none}.preview-modal:not(.hidden) .preview-modal-content{pointer-events:auto}.preview-modal-content>*{max-width:var(--preview-max-width);max-height:var(--preview-max-height);border:2px solid rgba(162,162,162,.5);box-shadow:0 2px 6px #0000004d;box-sizing:border-box}.preview-modal-content>img{border-radius:12px}.preview-modal-content>audio{border-radius:27px}.hidden{opacity:0}::-webkit-scrollbar{width:4px}::-webkit-scrollbar-track{background-color:transparent}::-webkit-scrollbar-thumb{border-radius:2px;background:#ffffff40}::-webkit-scrollbar-thumb:hover{background:#1e1e1ebf}p{font-size:16px;line-height:21px}.parsed-content-wrapper img{width:100%;border-radius:8px}h1{font-size:25px}h2{font-size:23px}h3{font-size:22px}h4{font-size:20px}h5{font-size:19px}h6{font-size:17px}p,h1,h2,h3,h4,h5,h6,ol,ul{margin:0}h1,h2{font-weight:800}h3,h4{font-weight:700}h5,h6{font-weight:600}code{background:#ffffff1a;padding:2px 4px;border-radius:8px}pre code{display:block;box-sizing:border-box;width:100%}pre:has(code),table{margin:6px 0}strong{color:#fe8e7c}em{color:#5affb2}a{text-decoration:none;color:#6dadd0;font-weight:800;font-style:italic;cursor:pointer;transition:var(--contentTransition)}a:hover{color:#86d3fd}hr{height:1px;width:100%;background-color:#fff3;border:none}li{margin:5px 0}ul{padding-left:16px}ol{padding-left:15px;padding-right:7.5px}table{border-collapse:collapse;border-spacing:0;border-radius:8px;border:1px solid rgba(255,255,255,.2);overflow:hidden;width:100%}table th,table td{border:1px solid rgba(255,255,255,.2);padding:6px 10px;background:#ffffff0f;text-align:left}table th{background:#ffffff1f;font-weight:700}",o.appendChild(r),this._container=document.createElement("div"),this._container.classList.add("container"),this.renderer=new n(this._container),this.overlayManager=new p(this._container),this.interactor=new l(this._container,{preventDefault:!0,proControlSchema:s.includes("proControlSchema")}),this.resizeObserver=new ResizeObserver(this.onResize),i.includes("minimap")?this.minimap=new h(this._container,s.includes("minimapCollapsed")):s.includes("minimapCollapsed")&&console.warn('CanvasViewer: "minimapCollapsed" option is not supported without minimap extension.'),s.includes("controlsHidden")?s.includes("controlsCollapsed")&&console.warn('CanvasViewer: "controlsCollapsed" option is overridden by "controlsHidden" option.'):this.controls=new c(this._container,s.includes("controlsCollapsed")),this.previewModal=new d(this._container),i.includes("mistouchPrevention")&&(this.mistouchPreventer=new m(this._container,!s.includes("noPreventionAtStart"))),o.appendChild(this._container),this.extensions=i,this.options=s,this.offsetX=0,this.offsetY=0,this.scale=1,this.ZOOM_SMOOTHNESS=.25,this.INITIAL_VIEWPORT_PADDING=100,this.GRID_CELL_SIZE=800,this.perFrame={needAnimating:!1,zoom:!1,smoothZoom:!1,targetScale:1,pan:!1,resize:!1,resizeScale:{width:0,height:0,lastCentreX:null,lastCentreY:null}}}get canvasData(){if(null===this._canvasData)throw i;return this._canvasData}get nodeMap(){if(null===this._nodeMap)throw i;return this._nodeMap}get nodeBounds(){if(null===this._nodeBounds)throw i;return this._nodeBounds}get container(){if(null===this._container)throw i;return this._container}isUIControl(t){return t.closest&&(t.closest(".controls")||t.closest("button")||t.closest("input"))}findNodeAt({x:t,y:e}){let i=[];if(this.spatialGrid){const n=`${Math.floor(t/this.GRID_CELL_SIZE)},${Math.floor(e/this.GRID_CELL_SIZE)}`;i=this.spatialGrid[n]||[]}else i=this.canvasData.nodes;for(const n of i)if(!(t<n.x||t>n.x+n.width||e<n.y||e>n.y+n.height||"non-interactive"===this.judgeInteract(n)))return n}C2C({x:t,y:e}){return{x:t-this.offsetX,y:e-this.offsetY}}C2W({x:t,y:e}){return{x:t/this.scale,y:e/this.scale}}middleScreen(){return{x:this.container.clientWidth/2,y:this.container.clientHeight/2}}judgeInteract(t){switch(t?t.type:"default"){case"text":case"link":return"select";case"file":if(!t||!t.file)throw e;return t.file.match(/\.md$/i)?"select":"preview";default:return"non-interactive"}}zoomToScale(t,e){const i=Math.max(Math.min(t,20),.05);if(i===this.scale)return;const n=this.C2C(e);this.offsetX=e.x-n.x*i/this.scale,this.offsetY=e.y-n.y*i/this.scale,this.scale=i,this.controls&&this.controls.updateSlider(this.scale)}buildSpatialGrid(){if(this.canvasData&&!(this.canvasData.nodes.length<50)){this.spatialGrid={};for(let t of this.canvasData.nodes){const e=Math.floor(t.x/this.GRID_CELL_SIZE),i=Math.floor((t.x+t.width)/this.GRID_CELL_SIZE),n=Math.floor(t.y/this.GRID_CELL_SIZE),s=Math.floor((t.y+t.height)/this.GRID_CELL_SIZE);for(let o=e;o<=i;o++)for(let e=n;e<=s;e++){const i=`${o},${e}`;this.spatialGrid[i]||(this.spatialGrid[i]=[]),this.spatialGrid[i].push(t)}}}}calculateNodeBounds(){if(!this.canvasData||!this.canvasData.nodes.length)return null;let t=1/0,e=1/0,i=-1/0,n=-1/0;this.canvasData.nodes.forEach(s=>{t=Math.min(t,s.x),e=Math.min(e,s.y),i=Math.max(i,s.x+s.width),n=Math.max(n,s.y+s.height)});const s=i-t,o=n-e;return{minX:t,minY:e,maxX:i,maxY:n,width:s,height:o,centerX:t+s/2,centerY:e+o/2}}resize(){this.perFrame.resize=!1;const t=this.perFrame.resizeScale;t.lastCentreX&&t.lastCentreY&&(this.offsetX+=t.width/2-t.lastCentreX,this.offsetY+=t.height/2-t.lastCentreY),t.lastCentreX=t.width/2,t.lastCentreY=t.height/2,this.renderer.resizeCanvasForDPR(),this.previewModal.resize(t.width,t.height)}pan({x:t,y:e}){this.offsetX+=t,this.offsetY+=e}zoom(t,e){const i=this.scale*t;this.zoomToScale(i,e)}smoothZoom(){const t=this.perFrame.targetScale-this.scale;let e;Math.abs(t)<.01*this.perFrame.targetScale+.002?(e=this.perFrame.targetScale,this.perFrame.smoothZoom=!1):e=Math.round(1e3*(this.scale+t*this.ZOOM_SMOOTHNESS))/1e3,this.zoomToScale(e,this.middleScreen())}setScale(t){this.perFrame.targetScale=t,this.perFrame.smoothZoom=!0}panTo(t,e){this.offsetX=this.container.clientWidth/2-t*this.scale,this.offsetY=this.container.clientHeight/2-e*this.scale,this.perFrame.needAnimating=!0}shiftFullscreen(t="toggle"){document.fullscreenElement||"toggle"!==t&&"enter"!==t?document.fullscreenElement&&("toggle"===t||"exit"===t)&&document.exitFullscreen():this.container.requestFullscreen(),this.controls&&this.controls.updateFullscreenBtn()}async loadCanvas(t){try{if(/^https?:\/\//.test(t))this.canvasBaseDir=t.substring(0,t.lastIndexOf("/")+1);else{const e=t.lastIndexOf("/");this.canvasBaseDir=-1!==e?t.substring(0,e+1):"./"}this._canvasData=await fetch(t).then(t=>t.json()),this._nodeMap={},this.canvasData.nodes.forEach(t=>{if("file"===t.type&&t.file&&!t.file.includes("http")){const e=t.file.split("/");t.file=e[e.length-1]}this.nodeMap[t.id]=t}),this.buildSpatialGrid(),this._nodeBounds=this.calculateNodeBounds(),this.resetView(),this.resizeObserver.observe(this.container),this.interactor.start(),this.renderer.receiveData(this.nodeMap,this.canvasData),this.overlayManager.receiveData(this.canvasBaseDir,this.nodeMap),this.previewModal.receiveData(this.canvasBaseDir),this.interactor.addEventListener("trueClick",this.onClick),this.interactor.addEventListener("pan",this.onPan),this.interactor.addEventListener("zoom",this.onZoom),this.previewModal.addEventListener("previewModalShown",this.stopInteractor),this.previewModal.addEventListener("previewModalHidden",this.startInteractor),this.overlayManager.addEventListener("interactionStart",this.stopInteractor),this.overlayManager.addEventListener("interactionEnd",this.startInteractor),this.controls&&this.controls.addEventListener("zoomIn",this.zoomIn),this.controls&&this.controls.addEventListener("zoomOut",this.zoomOut),this.controls&&this.controls.addEventListener("slide",this.onSlide),this.controls&&this.controls.addEventListener("toggleFullscreen",this.onToggleFullscreen),this.controls&&this.controls.addEventListener("resetView",this.resetView),this.minimap&&(this.minimap.receiveData(this.nodeBounds,this.canvasData,this.nodeMap),this.minimap.addEventListener("minimapExpanded",this.onMinimapExpanded)),this.mistouchPreventer&&(this.mistouchPreventer.addEventListener("preventionStart",this.onPreventionStart),this.mistouchPreventer.addEventListener("preventionEnd",this.onPreventionEnd)),(!this.extensions.includes("mistouchPrevention")||this.options.includes("noPreventionAtStart"))&&(this.animationId=requestAnimationFrame(this.draw)),this.dispatchEvent(new CustomEvent("loaded",{detail:this.canvasData}))}catch(t){console.error("Failed to load canvas data:",t)}}dispose(){this.interactor.removeEventListener("trueClick",this.onClick),this.interactor.removeEventListener("pan",this.onPan),this.interactor.removeEventListener("zoom",this.onZoom),this.previewModal.removeEventListener("previewModalShown",this.stopInteractor),this.previewModal.removeEventListener("previewModalHidden",this.startInteractor),this.overlayManager.removeEventListener("interactionStart",this.stopInteractor),this.overlayManager.removeEventListener("interactionEnd",this.startInteractor),this.controls&&this.controls.removeEventListener("zoomIn",this.zoomIn),this.controls&&this.controls.removeEventListener("zoomOut",this.zoomOut),this.controls&&this.controls.removeEventListener("slide",this.onSlide),this.controls&&this.controls.removeEventListener("toggleFullscreen",this.onToggleFullscreen),this.controls&&this.controls.removeEventListener("resetView",this.resetView),this.minimap&&this.minimap.removeEventListener("minimapExpanded",this.onMinimapExpanded),this.mistouchPreventer&&(this.mistouchPreventer.removeEventListener("preventionStart",this.onPreventionStart),this.mistouchPreventer.removeEventListener("preventionEnd",this.onPreventionEnd)),this.animationId&&cancelAnimationFrame(this.animationId),this.resizeObserver.disconnect(),this.interactor.dispose(),this.previewModal.dispose(),this.controls&&this.controls.dispose(),this.minimap&&this.minimap.dispose(),this.mistouchPreventer&&this.mistouchPreventer.dispose(),this.overlayManager.dispose(),this.renderer.dispose(),this.container.remove(),this._container=null}}class u extends HTMLElement{constructor(){super(),this.style.display="block",this.style.overflow="hidden",this.style.maxWidth="120vw",this.style.maxHeight="120vh";const t=this.getAttribute("extensions"),e=this.getAttribute("options"),i=t?t.split(" "):[],n=e?e.split(" "):[];this.viewer=new v(this,i,n)}connectedCallback(){const t=this.getAttribute("src");if(!t)throw new Error("No source canvas path provided.");this.viewer&&this.viewer.loadCanvas(t)}disconnectedCallback(){this.viewer&&this.viewer.dispose(),this.remove()}}customElements.define("canvas-viewer",u);export{v as default};
1
+ import{marked as t}from"marked";const e=new Error("This error is unexpected, probably caused by canvas file corruption. If you assure the error is not by accident, please contact the developer and show how to reproduce."),i=new Error("Resource hasn't been set up or has been disposed.");class n{constructor(t){this._nodeMap=null,this._canvasData=null,this.ARROW_LENGTH=12,this.ARROW_WIDTH=7,this.FILE_NODE_RADIUS=12,this.FONT_COLOR="#fff",this.CSS_ZOOM_REDRAW_INTERVAL=500,this._canvas=document.createElement("canvas"),this._canvas.className="main-canvas",this._container=t,this._container.appendChild(this._canvas),this._ctx=this._canvas.getContext("2d"),this.zoomInOptimize={lastDrawnScale:0,lastDrawnViewport:{left:0,right:0,top:0,bottom:0},timeout:null,lastCallTime:0},a(this._canvas,t.offsetWidth,t.offsetHeight)}get nodeMap(){if(null===this._nodeMap)throw i;return this._nodeMap}get canvasData(){if(null===this._canvasData)throw i;return this._canvasData}get canvas(){if(null===this._canvas)throw i;return this._canvas}get ctx(){if(null===this._ctx)throw i;return this._ctx}get container(){if(null===this._container)throw i;return this._container}receiveData(t,e){this._nodeMap=t,this._canvasData=e}resizeCanvasForDPR(){a(this.canvas,this.container.offsetWidth,this.container.offsetHeight)}redraw(t,e,i){this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=null);const n=Date.now(),s=this.getCurrentViewport(t,e,i);if(this.isViewportInside(s,this.zoomInOptimize.lastDrawnViewport)&&i!==this.zoomInOptimize.lastDrawnScale&&n-this.zoomInOptimize.lastCallTime<this.CSS_ZOOM_REDRAW_INTERVAL)return this.zoomInOptimize.timeout=setTimeout(()=>{this.trueRedraw(t,e,i,s),this.zoomInOptimize.lastCallTime=n,this.zoomInOptimize.timeout=null},60),void this.fakeRedraw(s,i);this.zoomInOptimize.lastCallTime=n,this.trueRedraw(t,e,i,s)}dispose(){this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=null),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.canvas.remove(),this._ctx=null,this._canvas=null,this._container=null,this._canvasData=null,this._nodeMap=null}trueRedraw(t,e,i,n){this.zoomInOptimize.lastDrawnViewport=n,this.zoomInOptimize.lastDrawnScale=i,this.canvas.style.transform="",this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.save(),this.ctx.translate(t,e),this.ctx.scale(i,i),this.canvasData.nodes.forEach(n=>n.inViewport=this.isNodeInViewport(n,t,e,i)),this.canvasData.nodes.forEach(t=>{switch(t.type){case"group":this.drawGroup(t,i);break;case"file":this.drawFileNode(t)}}),this.canvasData.edges.forEach(t=>this.drawEdge(t)),this.ctx.restore()}fakeRedraw(t,e){const i=e/this.zoomInOptimize.lastDrawnScale,n=(this.zoomInOptimize.lastDrawnViewport.left-t.left)*e,s=(this.zoomInOptimize.lastDrawnViewport.top-t.top)*e;this.canvas.style.transform=`translate(${n}px, ${s}px) scale(${i})`}isViewportInside(t,e){return t.left>e.left&&t.top>e.top&&t.right<e.right&&t.bottom<e.bottom}isNodeInViewport(t,e,i,n,s=200){const o=-e/n-s,r=-i/n-s,a=o+this.container.clientWidth/n+2*s,l=r+this.container.clientHeight/n+2*s;return t.x+t.width>o&&t.x<a&&t.y+t.height>r&&t.y<l}getCurrentViewport(t,e,i){const n=-t/i,s=-e/i;return{left:n,top:s,right:n+this.container.clientWidth/i,bottom:s+this.container.clientHeight/i}}drawLabelBar(t,e,i,n,s){const o=30*s,r=6*s,a=8*s,l=16*s,h=6*s;this.ctx.save(),this.ctx.translate(t,e),this.ctx.scale(1/s,1/s),this.ctx.font=`${l}px 'Inter', sans-serif`;const c=this.ctx.measureText(i).width+2*h;this.ctx.translate(0,-o-a),this.ctx.fillStyle=n,this.ctx.beginPath(),this.ctx.moveTo(r,0),this.ctx.lineTo(c-r,0),this.ctx.quadraticCurveTo(c,0,c,r),this.ctx.lineTo(c,o-r),this.ctx.quadraticCurveTo(c,o,c-r,o),this.ctx.lineTo(r,o),this.ctx.quadraticCurveTo(0,o,0,o-r),this.ctx.lineTo(0,r),this.ctx.quadraticCurveTo(0,0,r,0),this.ctx.closePath(),this.ctx.fill(),this.ctx.fillStyle=this.FONT_COLOR,this.ctx.fillText(i,h,.65*o),this.ctx.restore()}drawNodeBackground(t){const e=r(t.color),i=this.FILE_NODE_RADIUS;this.ctx.globalAlpha=1,this.ctx.fillStyle=e.background,o(this.ctx,t.x+1,t.y+1,t.width-2,t.height-2,i),this.ctx.fill(),this.ctx.strokeStyle=e.border,this.ctx.lineWidth=2,o(this.ctx,t.x,t.y,t.width,t.height,i),this.ctx.stroke()}drawGroup(t,e){this.drawNodeBackground(t),t.label&&this.drawLabelBar(t.x,t.y,t.label,r(t.color).border,e)}drawFileNode(t){if(!t.file)throw e;t.file.match(/\.md|png|jpg|jpeg|gif|svg$/i)||(this.drawNodeBackground(t),t.file.match(/\.mp3$/i)&&(this.ctx.fillStyle=this.FONT_COLOR,this.ctx.textAlign="center",this.ctx.textBaseline="middle",this.ctx.fillText("🎵 Click to Preview 🎵",t.x+t.width/2,t.y+t.height/2),this.ctx.textAlign="left")),this.ctx.fillStyle=this.FONT_COLOR,this.ctx.font="16px sans-serif",this.ctx.fillText(t.file,t.x+5,t.y-10)}drawEdge(t){const{fromNode:i,toNode:n}=this.getEdgeNodes(t);if(!i||!n)throw e;const[r,a]=s(i,t.fromSide),[l,h]=s(n,t.toSide);let[c,d,p,m]=[0,0,0,0];if(t.controlPoints?[c,d,p,m]=t.controlPoints:([c,d,p,m]=this.getControlPoints(r,a,l,h,t.fromSide,t.toSide),t.controlPoints=[c,d,p,m]),this.drawCurvedPath(r,a,l,h,c,d,p,m),this.drawArrowhead(l,h,p,m),t.label){const e=Math.pow(.5,3)*r+3*Math.pow(.5,2)*.5*c+.375*p+Math.pow(.5,3)*l,i=Math.pow(.5,3)*a+3*Math.pow(.5,2)*.5*d+.375*m+Math.pow(.5,3)*h;this.ctx.font="18px sans-serif";const n=this.ctx.measureText(t.label).width+16,s=20;this.ctx.fillStyle="#222",this.ctx.beginPath(),o(this.ctx,e-n/2,i-s/2-2,n,s,4),this.ctx.fill(),this.ctx.fillStyle="#ccc",this.ctx.textAlign="center",this.ctx.textBaseline="middle",this.ctx.fillText(t.label,e,i-2),this.ctx.textAlign="left",this.ctx.textBaseline="alphabetic"}}getEdgeNodes(t){return{fromNode:this.nodeMap[t.fromNode],toNode:this.nodeMap[t.toNode]}}getControlPoints(t,e,i,n,s,o){const r=i-t,a=n-e,l=Math.min(Math.abs(r),Math.abs(a))+.3*Math.max(Math.abs(r),Math.abs(a)),h=(c=.5*l,Math.max(60,Math.min(300,c)));var c;let d=t,p=e,m=i,v=n;switch(s){case"top":p=e-h;break;case"bottom":p=e+h;break;case"left":d=t-h;break;case"right":d=t+h}switch(o){case"top":v=n-h;break;case"bottom":v=n+h;break;case"left":m=i-h;break;case"right":m=i+h}return[d,p,m,v]}drawCurvedPath(t,e,i,n,s,o,r,a){this.ctx.beginPath(),this.ctx.moveTo(t,e),this.ctx.bezierCurveTo(s,o,r,a,i,n),this.ctx.strokeStyle="#ccc",this.ctx.lineWidth=2,this.ctx.stroke()}drawArrowhead(t,e,i,n){const s=t-i,o=e-n,r=Math.sqrt(s*s+o*o);if(0===r)return;const a=s/r,l=o/r,h=t-a*this.ARROW_LENGTH-l*this.ARROW_WIDTH,c=e-l*this.ARROW_LENGTH+a*this.ARROW_WIDTH,d=t-a*this.ARROW_LENGTH+l*this.ARROW_WIDTH,p=e-l*this.ARROW_LENGTH-a*this.ARROW_WIDTH;this.ctx.beginPath(),this.ctx.fillStyle="#ccc",this.ctx.moveTo(t,e),this.ctx.lineTo(h,c),this.ctx.lineTo(d,p),this.ctx.closePath(),this.ctx.fill()}}function s(t,e){const i=t.x+t.width/2,n=t.y+t.height/2;switch(e){case"top":return[i,t.y];case"bottom":return[i,t.y+t.height];case"left":return[t.x,n];case"right":return[t.x+t.width,n];default:return[i,n]}}function o(t,e,i,n,s,o){t.beginPath(),t.moveTo(e+o,i),t.lineTo(e+n-o,i),t.quadraticCurveTo(e+n,i,e+n,i+o),t.lineTo(e+n,i+s-o),t.quadraticCurveTo(e+n,i+s,e+n-o,i+s),t.lineTo(e+o,i+s),t.quadraticCurveTo(e,i+s,e,i+s-o),t.lineTo(e,i+o),t.quadraticCurveTo(e,i,e+o,i),t.closePath()}function r(t){let e=null;switch(t){case"1":e="rgba(255, 120, 129, ?)";break;case"2":e="rgba(251, 187, 131, ?)";break;case"3":e="rgba(255, 232, 139, ?)";break;case"4":e="rgba(124, 211, 124, ?)";break;case"5":e="rgba(134, 223, 226, ?)";break;case"6":e="rgba(203, 158, 255, ?)";break;default:e="rgba(140, 140, 140, ?)"}return{border:e.replace("?","0.75"),background:e.replace("?","0.1"),active:e.replace("?","1")}}function a(t,i,n){const s=window.devicePixelRatio||1,o=t.getContext("2d");if(!o)throw e;t.width=Math.round(i*s),t.height=Math.round(n*s),o.setTransform(1,0,0,1,0,0),o.scale(s,s)}class l extends EventTarget{constructor(t,i){super(),this.pointers=new Map,this.onPointerDown=t=>{if(!(this.pointers.size>=2)&&(t.isPrimary&&this.pointers.clear(),this.pointers.set(t.pointerId,{startX:t.clientX,startY:t.clientY,lastX:t.clientX,lastY:t.clientY,interrupted:!1,target:t.target}),2===this.pointers.size)){const i=this.getNthValue(0),n=this.pointers.get(t.pointerId);if(!i||!n)throw e;i.interrupted=!0,n.interrupted=!0,this.pinchZoomState.lastDistance=this.getPointerDistance(),this.pinchZoomState.lastMidpoint=this.S2C(this.getPointerMidpoint())}},this.onPointerMove=t=>{const i=this.pointers.get(t.pointerId);if(i){if(1===this.pointers.size){const e=t.clientX-i.lastX,n=t.clientY-i.lastY;this.dispatchPanEvent({x:e,y:n})}if(this.pointers.set(t.pointerId,{startX:i.startX,startY:i.startY,lastX:t.clientX,lastY:t.clientY,interrupted:i.interrupted,target:i.target}),2===this.pointers.size){const t=this.getPointerDistance(),i=this.getPointerMidpoint();if(!t||!i)throw e;let n=t/this.pinchZoomState.lastDistance;this.pinchZoomState.lastDistance=t;const s=this.S2C(i),o=s.x-this.pinchZoomState.lastMidpoint.x,r=s.y-this.pinchZoomState.lastMidpoint.y;this.pinchZoomState.lastMidpoint=s,this.dispatchPanEvent({x:o,y:r}),this.dispatchZoomEvent(n,s)}}},this.onPointerUp=t=>{const e=this.pointers.get(t.pointerId);if(e&&(this.pointers.delete(t.pointerId),0===this.pointers.size&&!e.interrupted&&Math.abs(e.startX-t.clientX)+Math.abs(e.startY-t.clientY)<5)){const i=this.S2C({x:t.clientX,y:t.clientY}),n=new CustomEvent("trueClick",{detail:{position:i,target:e.target}});this.dispatchEvent(n)}},this.onWheel=t=>{if(!this.lockControlSchema&&!this.proControlSchema&&(t.ctrlKey||t.shiftKey||Math.abs(t.deltaX)>Math.abs(t.deltaY))&&(this.proControlSchema=!0),this.preventDefault&&t.preventDefault(),this.proControlSchema)if(t.ctrlKey){const e=t.deltaY>0?1-this.ctrlZoomFactor:1+this.ctrlZoomFactor,i=this.S2C({x:t.clientX,y:t.clientY});this.dispatchZoomEvent(e,i)}else t.shiftKey&&Math.abs(t.deltaX)<=Math.abs(t.deltaY)?this.dispatchPanEvent({x:-t.deltaY,y:-t.deltaX}):this.dispatchPanEvent({x:-t.deltaX,y:-t.deltaY});else{const e=1-this.zoomFactor*t.deltaY,i=this.S2C({x:t.clientX,y:t.clientY});this.dispatchZoomEvent(e,i)}},this.preventDefaultFunction=t=>t.preventDefault,this._monitoringElement=t;const n=i||{};this.preventDefault=n.preventDefault||!1,this.proControlSchema=n.proControlSchema||!1,this.zoomFactor=n.zoomFactor||.002,this.ctrlZoomFactor=n.zoomFactor?50*n.zoomFactor:.1,this.lockControlSchema=n.lockControlSchema||!1,this.pointers.clear(),this.pinchZoomState={lastDistance:0,lastMidpoint:{x:0,y:0}},this.panDump={x:0,y:0},this.zoomDump={factor:1,origin:{x:0,y:0}}}get monitoringElement(){if(null===this._monitoringElement)throw i;return this._monitoringElement}getNthValue(t){if(t<0||t>=this.pointers.size)throw e;let i=0;for(const e of this.pointers.values()){if(i===t)return e;i++}}getPointerDistance(){const t=this.getNthValue(0),i=this.getNthValue(1);if(!t||!i)throw e;const n=t.lastX-i.lastX,s=t.lastY-i.lastY;return Math.sqrt(n*n+s*s)}getPointerMidpoint(){const t=this.getNthValue(0),i=this.getNthValue(1);if(!t||!i)throw e;return{x:(t.lastX+i.lastX)/2,y:(t.lastY+i.lastY)/2}}S2C({x:t,y:e}){const i=this.monitoringElement.getBoundingClientRect();return{x:t-i.left,y:e-i.top}}dispatchPanEvent(t){const e={x:this.round(t.x,1),y:this.round(t.y,1)};this.panDump.x+=e.x,this.panDump.y+=e.y;const i=new CustomEvent("pan",{detail:e});this.dispatchEvent(i)}dispatchZoomEvent(t,e){const i=this.round(t,4);this.zoomDump.factor*=i,this.zoomDump.origin=e;const n=new CustomEvent("zoom",{detail:{factor:i,origin:e}});this.dispatchEvent(n)}round(t,e){const i=10**e;return Math.round(t*i)/i}getZoomDump(){return this.zoomDump}resetZoomDump(){this.zoomDump.factor=1}getPanDump(){return this.panDump}resetPanDump(){this.panDump={x:0,y:0}}stop(){this.monitoringElement.removeEventListener("pointerdown",this.onPointerDown),window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp),this.monitoringElement.removeEventListener("wheel",this.onWheel),this.preventDefault&&(this.monitoringElement.style.touchAction="",this.monitoringElement.removeEventListener("gesturestart",this.preventDefaultFunction),this.monitoringElement.removeEventListener("gesturechange",this.preventDefaultFunction))}start(){this.monitoringElement.addEventListener("pointerdown",this.onPointerDown),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp),this.monitoringElement.addEventListener("wheel",this.onWheel,this.preventDefault?{passive:!1}:{}),this.preventDefault&&(this.monitoringElement.style.touchAction="none",this.monitoringElement.addEventListener("gesturestart",this.preventDefaultFunction,{passive:!1}),this.monitoringElement.addEventListener("gesturechange",this.preventDefaultFunction,{passive:!1}))}dispose(){this.stop(),this.pointers.clear(),this._monitoringElement=null}}class h extends EventTarget{constructor(t,e=!1){super(),this._canvasData=null,this._nodeMap=null,this._nodeBounds=null,this.toggleVisisbility=()=>{this.isMinimapVisible=!this.isMinimapVisible,this.minimapContainer.classList.toggle("collapsed"),this.dispatchEvent(new CustomEvent(this.isMinimapVisible?"minimapExpanded":"minimapCollapsed"))},this._minimapContainer=document.createElement("div"),this._minimapContainer.className="minimap-container",this._toggleMinimapBtn=document.createElement("button"),this._toggleMinimapBtn.className="toggle-minimap collapse-button",this._toggleMinimapBtn.innerHTML='<svg viewBox="-3.6 -3.6 31.2 31.2" stroke-width=".4"><path d="M15.707 4.293a1 1 0 0 1 0 1.414L9.414 12l6.293 6.293a1 1 0 0 1-1.414 1.414l-7-7a1 1 0 0 1 0-1.414l7-7a1 1 0 0 1 1.414 0Z" /></svg>',this._minimapContainer.appendChild(this._toggleMinimapBtn),this._minimap=document.createElement("div"),this._minimap.className="minimap";const i=document.createElement("canvas");i.className="minimap-canvas",i.width=200,i.height=150,this._minimap.appendChild(i),this._minimapCtx=i.getContext("2d"),this._viewportRectangle=document.createElement("div"),this._viewportRectangle.className="viewport-rectangle",this._minimap.appendChild(this._viewportRectangle),this._minimapContainer.appendChild(this._minimap),t.appendChild(this._minimapContainer),this._container=t,this.isMinimapVisible=!e,this._minimapContainer.classList.toggle("collapsed",e),this.minimapCache={scale:1,centerX:0,centerY:0},this._toggleMinimapBtn.addEventListener("click",this.toggleVisisbility),a(i,i.width,i.height)}get minimapCtx(){if(null===this._minimapCtx)throw i;return this._minimapCtx}get canvasData(){if(null===this._canvasData)throw i;return this._canvasData}get container(){if(null===this._container)throw i;return this._container}get minimap(){if(null===this._minimap)throw i;return this._minimap}get nodeBounds(){if(null===this._nodeBounds)throw i;return this._nodeBounds}get nodeMap(){if(null===this._nodeMap)throw i;return this._nodeMap}get viewportRectangle(){if(null===this._viewportRectangle)throw i;return this._viewportRectangle}get minimapContainer(){if(null===this._minimapContainer)throw i;return this._minimapContainer}get toggleMinimapBtn(){if(null===this._toggleMinimapBtn)throw i;return this._toggleMinimapBtn}receiveData(t,e,i){this._nodeBounds=t,this._canvasData=e,this._nodeMap=i,this.drawMinimap()}drawMinimap(){const t=this.nodeBounds;if(!t)return;const e=this.minimap.clientWidth,i=this.minimap.clientHeight,n=e/t.width,s=i/t.height;this.minimapCache.scale=.9*Math.min(n,s),this.minimapCache.centerX=e/2,this.minimapCache.centerY=i/2,this.minimapCtx.clearRect(0,0,e,i),this.minimapCtx.save(),this.minimapCtx.translate(this.minimapCache.centerX,this.minimapCache.centerY),this.minimapCtx.scale(this.minimapCache.scale,this.minimapCache.scale),this.minimapCtx.translate(-t.centerX,-t.centerY);for(let t of this.canvasData.edges)this.drawMinimapEdge(t);for(let t of this.canvasData.nodes)this.drawMinimapNode(t);this.minimapCtx.restore()}drawMinimapNode(t){const e=r(t.color);this.minimapCtx.fillStyle=e.border,this.minimapCtx.globalAlpha=.3,o(this.minimapCtx,t.x,t.y,t.width,t.height,25),this.minimapCtx.fill(),this.minimapCtx.globalAlpha=1}drawMinimapEdge(t){const e=this.nodeMap[t.fromNode],i=this.nodeMap[t.toNode];if(!e||!i)return;const[n,o]=s(e,t.fromSide),[r,a]=s(i,t.toSide);this.minimapCtx.beginPath(),this.minimapCtx.moveTo(n,o),this.minimapCtx.lineTo(r,a),this.minimapCtx.strokeStyle="#555",this.minimapCtx.lineWidth=10,this.minimapCtx.stroke()}updateViewportRectangle(t,e,i){if(!this.isMinimapVisible)return;const n=this.nodeBounds;if(!n)return;const s=this.container.clientWidth/i,o=this.container.clientHeight/i,r=-t/i+this.container.clientWidth/(2*i),a=-e/i+this.container.clientHeight/(2*i),l=this.minimapCache.centerX+(r-s/2-n.centerX)*this.minimapCache.scale,h=this.minimapCache.centerY+(a-o/2-n.centerY)*this.minimapCache.scale,c=s*this.minimapCache.scale,d=o*this.minimapCache.scale;this.viewportRectangle.style.left=l+"px",this.viewportRectangle.style.top=h+"px",this.viewportRectangle.style.width=c+"px",this.viewportRectangle.style.height=d+"px"}dispose(){this.toggleMinimapBtn.removeEventListener("click",this.toggleVisisbility),this.minimapCtx.clearRect(0,0,this.minimap.clientWidth,this.minimap.clientHeight),this.minimapContainer.remove(),this._minimapContainer=null,this._minimapCtx=null,this._toggleMinimapBtn=null,this._canvasData=null,this._container=null,this._nodeMap=null,this._nodeBounds=null,this._viewportRectangle=null,this._minimap=null}}class c extends EventTarget{constructor(t,e=!1){super(),this.toggleCollapse=()=>this.controlsPanel.classList.toggle("collapsed"),this.zoomIn=()=>this.dispatchEvent(new CustomEvent("zoomIn")),this.zoomOut=()=>this.dispatchEvent(new CustomEvent("zoomOut")),this.slide=()=>this.dispatchEvent(new CustomEvent("slide",{detail:Math.pow(1.1,Number(this.zoomSlider.value))})),this.resetView=()=>this.dispatchEvent(new CustomEvent("resetView")),this.toggleFullscreen=()=>this.dispatchEvent(new CustomEvent("toggleFullscreen")),this.updateSlider=t=>this.zoomSlider.value=String(this.scaleToSlider(t)),this.scaleToSlider=t=>Math.log(t)/Math.log(1.1),this._controlsPanel=document.createElement("div"),this._controlsPanel.className="controls",this._controlsPanel.classList.toggle("collapsed",e),this._toggleCollapseBtn=document.createElement("button"),this._toggleCollapseBtn.className="collapse-button",this._toggleCollapseBtn.innerHTML='<svg viewBox="-3.6 -3.6 31.2 31.2" stroke-width=".4"><path d="M15.707 4.293a1 1 0 0 1 0 1.414L9.414 12l6.293 6.293a1 1 0 0 1-1.414 1.414l-7-7a1 1 0 0 1 0-1.414l7-7a1 1 0 0 1 1.414 0Z" /></svg>',this._controlsPanel.appendChild(this._toggleCollapseBtn);const i=document.createElement("div");i.className="controls-content",this._toggleFullscreenBtn=document.createElement("button"),this._toggleFullscreenBtn.innerHTML='<svg viewBox="-5.28 -5.28 34.56 34.56" fill="none"><path d="M4 9V5.6c0-.56 0-.84.109-1.054a1 1 0 0 1 .437-.437C4.76 4 5.04 4 5.6 4H9M4 15v3.4c0 .56 0 .84.109 1.054a1 1 0 0 0 .437.437C4.76 20 5.04 20 5.6 20H9m6-16h3.4c.56 0 .84 0 1.054.109a1 1 0 0 1 .437.437C20 4.76 20 5.04 20 5.6V9m0 6v3.4c0 .56 0 .84-.109 1.054a1 1 0 0 1-.437.437C19.24 20 18.96 20 18.4 20H15" stroke-width="2.4" stroke-linecap="round"/></svg>',i.appendChild(this._toggleFullscreenBtn),this._zoomOutBtn=document.createElement("button"),this._zoomOutBtn.innerHTML='<svg viewBox="-1.2 -1.2 26.4 26.4"><path d="M6 12h12" stroke-width="2" stroke-linecap="round" /></svg>',i.appendChild(this._zoomOutBtn),this._zoomSlider=document.createElement("input"),this._zoomSlider.type="range",this._zoomSlider.className="zoom-slider",this._zoomSlider.min="-30",this._zoomSlider.max="30",this._zoomSlider.value="0",i.appendChild(this._zoomSlider),this._zoomInBtn=document.createElement("button"),this._zoomInBtn.innerHTML='<svg viewBox="-1.2 -1.2 26.4 26.4"><path d="M6 12h12m-6-6v12" stroke-width="2" stroke-linecap="round" /></svg>',i.appendChild(this._zoomInBtn),this._resetViewBtn=document.createElement("button"),this._resetViewBtn.innerHTML='<svg viewBox="-6 -6 30 30" stroke-width=".08"><path d="m14.955 7.986.116.01a1 1 0 0 1 .85 1.13 8 8 0 0 1-13.374 4.728l-.84.84c-.63.63-1.707.184-1.707-.707V10h3.987c.89 0 1.337 1.077.707 1.707l-.731.731a6 6 0 0 0 8.347-.264 6 6 0 0 0 1.63-3.33 1 1 0 0 1 1.131-.848zM11.514.813a8 8 0 0 1 1.942 1.336l.837-.837c.63-.63 1.707-.184 1.707.707V6h-3.981c-.89 0-1.337-1.077-.707-1.707l.728-.729a6 6 0 0 0-9.98 3.591 1 1 0 1 1-1.98-.281A8 8 0 0 1 11.514.813Z" /></svg>',i.appendChild(this._resetViewBtn),this._controlsPanel.appendChild(i),t.appendChild(this._controlsPanel),this._toggleCollapseBtn.addEventListener("click",this.toggleCollapse),this._zoomInBtn.addEventListener("click",this.zoomIn),this._zoomOutBtn.addEventListener("click",this.zoomOut),this._zoomSlider.addEventListener("input",this.slide),this._resetViewBtn.addEventListener("click",this.resetView),this._toggleFullscreenBtn.addEventListener("click",this.toggleFullscreen)}get controlsPanel(){if(null===this._controlsPanel)throw i;return this._controlsPanel}get toggleCollapseBtn(){if(null===this._toggleCollapseBtn)throw i;return this._toggleCollapseBtn}get toggleFullscreenBtn(){if(null===this._toggleFullscreenBtn)throw i;return this._toggleFullscreenBtn}get zoomOutBtn(){if(null===this._zoomOutBtn)throw i;return this._zoomOutBtn}get zoomSlider(){if(null===this._zoomSlider)throw i;return this._zoomSlider}get zoomInBtn(){if(null===this._zoomInBtn)throw i;return this._zoomInBtn}get resetViewBtn(){if(null===this._resetViewBtn)throw i;return this._resetViewBtn}updateFullscreenBtn(){null===document.fullscreenElement?this.toggleFullscreenBtn.innerHTML='<svg viewBox="-40.32 -40.32 176.64 176.64"><path d="M30 60H6a6 6 0 0 0 0 12h18v18a6 6 0 0 0 12 0V66a5.997 5.997 0 0 0-6-6Zm60 0H66a5.997 5.997 0 0 0-6 6v24a6 6 0 0 0 12 0V72h18a6 6 0 0 0 0-12ZM66 36h24a6 6 0 0 0 0-12H72V6a6 6 0 0 0-12 0v24a5.997 5.997 0 0 0 6 6ZM30 0a5.997 5.997 0 0 0-6 6v18H6a6 6 0 0 0 0 12h24a5.997 5.997 0 0 0 6-6V6a5.997 5.997 0 0 0-6-6Z"/></svg>':this.toggleFullscreenBtn.innerHTML='<svg viewBox="-5.28 -5.28 34.56 34.56" fill="none"><path d="M4 9V5.6c0-.56 0-.84.109-1.054a1 1 0 0 1 .437-.437C4.76 4 5.04 4 5.6 4H9M4 15v3.4c0 .56 0 .84.109 1.054a1 1 0 0 0 .437.437C4.76 20 5.04 20 5.6 20H9m6-16h3.4c.56 0 .84 0 1.054.109a1 1 0 0 1 .437.437C20 4.76 20 5.04 20 5.6V9m0 6v3.4c0 .56 0 .84-.109 1.054a1 1 0 0 1-.437.437C19.24 20 18.96 20 18.4 20H15" stroke-width="2.4" stroke-linecap="round"/></svg>'}dispose(){this.toggleCollapseBtn.removeEventListener("click",this.toggleCollapse),this.zoomInBtn.removeEventListener("click",this.zoomIn),this.zoomOutBtn.removeEventListener("click",this.zoomOut),this.zoomSlider.removeEventListener("input",this.slide),this.resetViewBtn.removeEventListener("click",this.resetView),this.toggleFullscreenBtn.removeEventListener("click",this.toggleFullscreen),this.controlsPanel.remove(),this._controlsPanel=null,this._toggleCollapseBtn=null,this._zoomInBtn=null,this._zoomOutBtn=null,this._zoomSlider=null,this._resetViewBtn=null,this._toggleFullscreenBtn=null}}class d extends EventTarget{constructor(t){super(),this._canvasBaseDir=null,this.hidePreviewModal=()=>{this.previewModalBackdrop.classList.add("hidden"),this.previewModal.classList.add("hidden"),this.dispatchEvent(new CustomEvent("previewModalHidden"))},this._previewModalBackdrop=document.createElement("div"),this._previewModalBackdrop.className="preview-modal-backdrop hidden",t.appendChild(this._previewModalBackdrop),this._previewModal=document.createElement("div"),this._previewModal.className="preview-modal hidden",this._previewModalClose=document.createElement("button"),this._previewModalClose.className="preview-modal-close",this._previewModalClose.innerHTML='<svg viewBox="0 0 24 24"><path d="M6.758 17.243 12.001 12m5.243-5.243L12 12m0 0L6.758 6.757M12.001 12l5.243 5.243" stroke-width="2" stroke-linecap="round" /></svg>',this._previewModal.appendChild(this._previewModalClose),this._previewModalContent=document.createElement("div"),this._previewModalContent.className="preview-modal-content",this._previewModal.appendChild(this._previewModalContent),t.appendChild(this._previewModal),this._previewModalClose.addEventListener("click",this.hidePreviewModal),this._previewModalBackdrop.addEventListener("click",this.hidePreviewModal)}get previewModalBackdrop(){if(!this._previewModalBackdrop)throw i;return this._previewModalBackdrop}get previewModal(){if(!this._previewModal)throw i;return this._previewModal}get previewModalContent(){if(!this._previewModalContent)throw i;return this._previewModalContent}get canvasBaseDir(){if(!this._canvasBaseDir)throw i;return this._canvasBaseDir}get previewModalClose(){if(!this._previewModalClose)throw i;return this._previewModalClose}receiveData(t){this._canvasBaseDir=t}showPreviewModal(t){const i=this.processContent(t);if(!i)throw e;this.previewModalContent.innerHTML="",this.previewModalBackdrop.classList.remove("hidden"),this.previewModal.classList.remove("hidden"),this.previewModalContent.appendChild(i),this.dispatchEvent(new CustomEvent("previewModalShown"))}resize(t,e){this.previewModal.style.setProperty("--preview-max-width",.9*t+"px"),this.previewModal.style.setProperty("--preview-max-height",.9*e+"px")}processContent(t){if(!t.file)throw e;let i;return t.file.match(/\.(png|jpg|jpeg|gif|svg)$/i)?(i=new Image,i.src=this.canvasBaseDir+t.file):t.file.match(/\.mp3$/i)&&(i=document.createElement("audio"),i.controls=!0,i.src=this.canvasBaseDir+t.file),i}dispose(){for(this.previewModalClose.removeEventListener("click",this.hidePreviewModal),this.previewModalBackdrop.removeEventListener("click",this.hidePreviewModal);this.previewModalContent.firstElementChild;)this.previewModalContent.firstElementChild.remove();this.previewModal.remove(),this.previewModalBackdrop.remove(),this._previewModal=null,this._previewModalClose=null,this._previewModalBackdrop=null,this._previewModalContent=null}}class p extends EventTarget{constructor(t){super(),this._nodeMap=null,this._canvasBaseDir=null,this.selectedId=null,this.eventListeners={},this.startInteract=()=>this.dispatchEvent(new CustomEvent("interactionStart")),this.endInteract=()=>this.dispatchEvent(new CustomEvent("interactionEnd")),this._overlaysLayer=document.createElement("div"),this._overlaysLayer.className="overlays",t.appendChild(this.overlaysLayer),this._overlays={}}get nodeMap(){if(!this._nodeMap)throw i;return this._nodeMap}get canvasBaseDir(){if(!this._canvasBaseDir)throw i;return this._canvasBaseDir}get overlays(){if(!this._overlays)throw i;return this._overlays}get overlaysLayer(){if(!this._overlaysLayer)throw i;return this._overlaysLayer}receiveData(t,e){this._canvasBaseDir=t,this._nodeMap=e}select(t){const e=this.selectedId?this.overlays[this.selectedId]:null,i=t?this.overlays[t]:null;e&&e.classList.remove("active"),i?(i.classList.add("active"),this.startInteract()):this.endInteract(),this.selectedId=t}async loadMarkdownForNode(i){if(!i.mdContent){i.mdContent="Loading...",this.updateOrCreateOverlay(i,i.mdContent,"markdown");try{if(!i.file)throw e;const n=await(await fetch(this.canvasBaseDir+i.file)).text(),s=n.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(s){const e=s[1].split("\n").reduce((t,e)=>{const[i,n]=e.split(":").map(t=>t.trim());return t[i]=n,t},{});i.mdContent=await t.parse(s[2].trim()),i.mdFrontmatter=e}else i.mdContent=await t.parse(n)}catch(t){console.error("Failed to load markdown:",t),i.mdContent="Failed to load content."}}this.updateOrCreateOverlay(i,i.mdContent,"markdown")}updateAllOverlays(t,i,n){this.overlaysLayer.style.transform=`translate(${t}px, ${i}px) scale(${n})`;const s=new Set,o={text:t=>{if(!t.text)throw e;t.inViewport&&(s.add(t.id),this.updateOrCreateOverlay(t,t.text,"text"))},file:t=>{if(!t.file)throw e;t.inViewport&&(s.add(t.id),t.file.match(/\.md$/i)?this.loadMarkdownForNode(t):t.file.match(/\.(png|jpg|jpeg|gif|svg)$/i)&&this.updateOrCreateOverlay(t,this.canvasBaseDir+t.file,"image"))},link:t=>{if(!t.url)throw e;s.add(t.id),this.updateOrCreateOverlay(t,t.url,"link")},group:()=>{}};Object.values(this.nodeMap).forEach(t=>o[t.type](t)),Object.keys(this.overlays).forEach(t=>{if(!s.has(t)){const e=this.overlays[t];e&&e.parentNode&&e.parentNode.removeChild(e),delete this.overlays[t]}})}async updateOrCreateOverlay(t,i,n){let s=this.overlays[t.id];if(s||(s=await this.constructOverlay(t,i,n),this.overlaysLayer.appendChild(s),this.overlays[t.id]=s,s.style.left=t.x+"px",s.style.top=t.y+"px",s.style.width=t.width+"px",s.style.height=t.height+"px"),"markdown"===n){const i=s.getElementsByClassName("parsed-content-wrapper")[0];if(!t.mdContent)throw e;i.innerHTML!==t.mdContent&&(i.innerHTML=t.mdContent),!s.classList.contains("rtl")&&"rtl"===t.mdFrontmatter?.direction&&s.classList.add("rtl")}}async constructOverlay(e,i,n){const s=document.createElement("div");s.classList.add("overlay-container"),s.id=e.id;const o=document.createElement("div");if(o.className="overlay-border",s.appendChild(o),"text"===n||"markdown"===n){s.classList.add("markdown-content");const e=document.createElement("div");e.innerHTML=await t.parse(i||""),e.classList.add("parsed-content-wrapper"),s.appendChild(e)}else if("link"===n){const t=document.createElement("iframe");t.src=i,t.sandbox="allow-scripts allow-same-origin",t.className="link-iframe",t.loading="lazy";const e=document.createElement("div");e.className="link-click-layer",s.appendChild(t),s.appendChild(e)}else if("image"===n){const t=document.createElement("img");t.src=i,t.loading="lazy",s.appendChild(t)}const r=null==e.color?"color-0":"color-"+e.color;if(s.classList.add(r),"image"!==n){this.selectedId===e.id&&s.classList.add("active");const t=()=>{e.id===this.selectedId&&this.startInteract()},i=()=>{e.id===this.selectedId&&this.endInteract()};s.addEventListener("pointerenter",t),s.addEventListener("pointerleave",i),s.addEventListener("touchstart",t),s.addEventListener("touchend",i),this.eventListeners[e.id]=[t,i]}return s}dispose(){for(this._overlays=null;this.overlaysLayer.firstElementChild;){const t=this.overlaysLayer.firstElementChild;if(this.eventListeners[t.id]){const e=this.eventListeners[t.id][0],n=this.eventListeners[t.id][1];if(!e||!n)throw i;t.removeEventListener("pointerenter",e),t.removeEventListener("pointerleave",n),t.removeEventListener("touchstart",e),t.removeEventListener("touchend",n),this.eventListeners[t.id][0]=null,this.eventListeners[t.id][1]=null}t.remove()}this.overlaysLayer.remove(),this._overlaysLayer=null,this._nodeMap=null}}class m extends EventTarget{constructor(t,e=!0){super(),this.preventMt=!1,this.onPointerDown=t=>{const e=this.container.getBoundingClientRect();t.clientX<e.left||t.clientX>e.right||t.clientY<e.top||t.clientY>e.bottom?this.preventMt||this.startPrevention():this.preventMt&&(this.preventMistouch.initialX=t.clientX,this.preventMistouch.initialY=t.clientY,this.preventMistouch.lastX=t.clientX,this.preventMistouch.lastY=t.clientY,this.preventMistouch.record=!0)},this.onPointerMove=t=>{this.preventMistouch.record&&(this.preventMistouch.lastX=t.clientX,this.preventMistouch.lastY=t.clientY)},this.onPointerUp=()=>{this.preventMistouch.record&&(this.preventMistouch.record=!1,Math.abs(this.preventMistouch.lastX-this.preventMistouch.initialX)+Math.abs(this.preventMistouch.lastY-this.preventMistouch.initialY)<5&&this.endPrevention())},this._preventionContainer=document.createElement("div"),this._preventionContainer.className="prevention-container hidden";const i=document.createElement("div");i.className="prevention-banner",i.innerHTML="Frozen to prevent mistouch, click on to unlock.",this._preventionContainer.appendChild(i),t.appendChild(this._preventionContainer),this._container=t,this.preventMistouch={record:!1,lastX:0,lastY:0,initialX:0,initialY:0},e&&this.startPrevention(),window.addEventListener("pointerdown",this.onPointerDown),window.addEventListener("pointermove",this.onPointerMove),window.addEventListener("pointerup",this.onPointerUp)}get preventionContainer(){if(null===this._preventionContainer)throw i;return this._preventionContainer}get container(){if(null===this._container)throw i;return this._container}startPrevention(){this.preventionContainer.classList.remove("hidden"),this.container.classList.add("numb"),this.preventMt=!0,this.dispatchEvent(new CustomEvent("preventionStart"))}endPrevention(){this.preventMt=!1,this.preventionContainer.classList.add("hidden"),setTimeout(()=>this.container.classList.remove("numb"),50),this.dispatchEvent(new CustomEvent("preventionEnd"))}dispose(){window.removeEventListener("pointerdown",this.onPointerDown),window.removeEventListener("pointermove",this.onPointerMove),window.removeEventListener("pointerup",this.onPointerUp),this.preventionContainer.remove(),this._container=null,this._preventionContainer=null}}class v extends EventTarget{constructor(t,i=[],s=[]){super(),this.controls=null,this.minimap=null,this.mistouchPreventer=null,this.canvasBaseDir=null,this.animationId=null,this._canvasData=null,this._nodeMap=null,this._nodeBounds=null,this.spatialGrid=null,this.ZOOM_SMOOTHNESS=.25,this.INITIAL_VIEWPORT_PADDING=100,this.GRID_CELL_SIZE=800,this.draw=()=>{if(this.perFrame.needAnimating||this.perFrame.pan||this.perFrame.zoom||this.perFrame.smoothZoom){if(this.perFrame.needAnimating&&(this.perFrame.needAnimating=!1),this.perFrame.zoom){this.perFrame.zoom=!1;const t=this.interactor.getZoomDump();this.zoom(t.factor,t.origin),this.interactor.resetZoomDump()}this.perFrame.pan&&(this.perFrame.pan=!1,this.pan(this.interactor.getPanDump()),this.interactor.resetPanDump()),this.perFrame.smoothZoom&&this.smoothZoom(),this.refresh(),this.animationId=requestAnimationFrame(this.draw)}else this.animationId=requestAnimationFrame(this.draw)},this.onClick=t=>{if(!(t instanceof CustomEvent))throw e;{if(this.isUIControl(t.detail.target))return;const i=this.findNodeAt(this.C2W(this.C2C(t.detail.position))),n=this.judgeInteract(i);switch(n){case"non-interactive":this.overlayManager.select(null);break;case"select":if(!i)throw e;this.overlayManager.select(i.id);break;case"preview":if(!i)throw e;this.previewModal.showPreviewModal(i)}i&&"non-interactive"!==n&&this.dispatchEvent(new CustomEvent("interact",{detail:{node:i.id,type:n}}))}},this.onResize=()=>{this.resizeState.resizeTimeout&&(clearTimeout(this.resizeState.resizeTimeout),this.resizeState.resizeTimeout=null);const t=Date.now();t-this.resizeState.lastCallTime<100?this.resizeState.resizeTimeout=setTimeout(()=>{this.resize(),this.resizeState.lastCallTime=t,this.resizeState.resizeTimeout=null},60):(this.resizeState.lastCallTime=t,this.resize())},this.onPan=()=>this.perFrame.pan=!0,this.onZoom=()=>this.perFrame.zoom=!0,this.onSlide=t=>{if(!(t instanceof CustomEvent))throw e;this.setScale(t.detail)},this.onMinimapExpanded=()=>{this.minimap&&this.minimap.updateViewportRectangle(this.offsetX,this.offsetY,this.scale)},this.onPreventionStart=()=>{this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)},this.onPreventionEnd=()=>this.animationId=requestAnimationFrame(this.draw),this.stopInteractor=()=>this.interactor.stop(),this.startInteractor=()=>this.interactor.start(),this.onToggleFullscreen=()=>this.shiftFullscreen(),this.zoomIn=()=>this.setScale(1.2*this.scale),this.zoomOut=()=>this.setScale(this.scale/1.2),this.resetView=()=>{const t=this.nodeBounds;if(!t)return{scale:1,offsetX:this.container.clientWidth/2,offsetY:this.container.clientHeight/2};const e=t.width+2*this.INITIAL_VIEWPORT_PADDING,i=t.height+2*this.INITIAL_VIEWPORT_PADDING,n=this.container.clientWidth,s=this.container.clientHeight,o=n/e,r=s/i,a=Math.round(1e3*Math.min(o,r))/1e3,l={scale:a,offsetX:n/2-t.centerX*a,offsetY:s/2-t.centerY*a};this.scale=l.scale,this.offsetX=l.offsetX,this.offsetY=l.offsetY,this.controls&&this.controls.updateSlider(this.scale),this.perFrame.needAnimating=!0};const o=t.attachShadow({mode:"open"}),r=document.createElement("style");r.innerHTML=".color-1{--border-color: rgba(255, 120, 129, .75);--background-color: rgba(255, 120, 129, .1);--active-color: rgba(255, 120, 129, 1)}.color-2{--border-color: rgba(251, 187, 131, .75);--background-color: rgba(251, 187, 131, .1);--active-color: rgba(251, 187, 131, 1)}.color-3{--border-color: rgba(255, 232, 139, .75);--background-color: rgba(255, 232, 139, .1);--active-color: rgba(255, 232, 139, 1)}.color-4{--border-color: rgba(124, 211, 124, .75);--background-color: rgba(124, 211, 124, .1);--active-color: rgba(124, 211, 124, 1)}.color-5{--border-color: rgba(134, 223, 226, .75);--background-color: rgba(134, 223, 226, .1);--active-color: rgba(134, 223, 226, 1)}.color-6{--border-color: rgba(203, 158, 255, .75);--background-color: rgba(203, 158, 255, .1);--active-color: rgba(203, 158, 255, 1)}.color-0{--border-color: rgba(140, 140, 140, .75);--background-color: rgba(140, 140, 140, .1);--active-color: rgba(140, 140, 140, 1)}.full,.preview-modal,.preview-modal-backdrop,.link-click-layer,.link-iframe,.prevention-container{top:0;left:0;width:100%;height:100%;position:absolute}.flex-center,.overlay-container.markdown-content,.prevention-container{display:flex;justify-content:center;align-items:center}.overlay-border{z-index:1}.container{--themeColor: rgb(254, 247, 167);--background-color: #141414;--contentTransition: color .2s, opacity .2s, text-shadow .2s, fill .2s;--containerTransition: background .2s, opacity .2s, box-shadow .2s, border .2s, filter .2s, backdrop-filter .2s;color:#fff;fill:#fff;stroke:#fff;position:relative;width:100%;height:100%;overflow:hidden;background-color:var(--background-color)}.container.numb,.container.numb *{pointer-events:none!important}.prevention-container{overflow:visible;transition:background .2s,opacity .2s,box-shadow .2s,border .2s,filter .2s,backdrop-filter .2s}.prevention-container.hidden{pointer-events:none}.prevention-container .prevention-banner{background:#0006;border-radius:12px;padding:12px;margin:12px;-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);border:2px solid rgba(140,140,140,.75);color:#fff;font-size:calc(14px + .3vw);line-height:calc(17px + .3vw);text-align:center}.main-canvas{width:100%;height:100%;transform-origin:top left}button{cursor:pointer;font-size:18px;height:32px;border:none;transition:var(--containerTransition);text-align:center;background-color:#444;width:32px;padding:5px 0}button svg{width:100%;height:100%}.overlays{position:absolute;top:0;left:0;width:100%;height:100%;transform-origin:top left;will-change:transform}.parsed-content-wrapper{font-family:sans-serif;box-sizing:border-box;max-width:100%;max-height:100%;padding:10px 6px;pointer-events:none;overflow:hidden;scrollbar-gutter:stable both-edges;display:flex;flex-direction:column;gap:12px}@supports not (scrollbar-gutter: stable both-edges){.parsed-content-wrapper{padding:10px}}.minimap-container{position:absolute;bottom:10px;right:10px;display:flex;pointer-events:none;transition:transform .2s}.minimap-container.collapsed{transform:translate(calc(100% - 32px))}@media (max-width: 768px){.minimap-container{transform:translateY(60px) translate(80px)}.minimap-container.collapsed{transform:translateY(60px) translate(calc(100% - 32px))}}.toggle-minimap{margin:auto 10px 0 0;pointer-events:auto}.collapsed .toggle-minimap{transform:rotate(180deg)}@media (max-width: 768px){.toggle-minimap{transform:translateY(-60px)}.collapsed .toggle-minimap{transform:translateY(-60px) rotate(180deg)}}.minimap{position:relative;width:200px;height:150px;overflow:hidden;border-radius:12px;background:#202020;-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);border:2px solid rgba(140,140,140,.75);transform-origin:0 0}@media (max-width: 768px){.minimap{transform:scale(.6)}}.minimap .minimap-canvas{width:100%;height:100%}.minimap .viewport-rectangle{position:absolute;top:0;left:0;pointer-events:none;border:2px solid #fff;border-radius:6px;box-sizing:border-box;background:transparent}.collapse-button{border-radius:8px;transition:transform .2s}.collapse-button:hover{background:#444c}.controls{position:absolute;top:10px;right:10px;display:flex;align-items:center;transition:transform .2s;border-radius:8px;gap:10px}.controls.collapsed{transform:translate(calc(100% - 32px))}.controls.collapsed .collapse-button{transform:rotate(180deg)}.controls .controls-content{display:flex;gap:1px;align-items:center;border-radius:8px;overflow:hidden;background:#333c}.controls button:hover{background:#555}.zoom-slider{width:100px;margin:0 10px}.overlay-container{position:absolute;box-sizing:border-box;border-radius:12px;overflow:hidden;background-color:var(--background-color);-webkit-user-select:none;user-select:none;contain:strict;transition:var(--containerTransition)}.overlay-container:hover{box-shadow:0 2px 12px #00000080}.overlay-container .overlay-border{box-sizing:border-box;pointer-events:none;position:absolute;top:0;left:0;width:100%;height:100%;border:2px solid var(--border-color);border-radius:12px;transition:var(--containerTransition)}.overlay-container img{width:100%;height:100%;object-fit:cover;pointer-events:none}.overlay-container.active .overlay-border{border:6px solid var(--active-color)}.overlay-container.markdown-content{position:absolute;padding:0 7px}.overlay-container.markdown-content.active .parsed-content-wrapper{overflow:auto;-webkit-user-select:text;user-select:text;pointer-events:auto}.overlay-container.markdown-content.rtl{direction:rtl;text-align:right}.link-iframe{contain-intrinsic-size:100% 100%;border:none}.link-click-layer{background:transparent;pointer-events:auto}.active .link-click-layer{pointer-events:none}.preview-modal-backdrop{-webkit-backdrop-filter:blur(8px) saturate(1.5);backdrop-filter:blur(8px) saturate(1.5);transition:var(--containerTransition)}.preview-modal-backdrop.hidden{pointer-events:none}.preview-modal{transition:var(--containerTransition);pointer-events:none}.preview-modal-close{position:absolute;right:10px;top:10px;background:none;border:none;font-size:24px;cursor:pointer;pointer-events:none}.preview-modal:not(.hidden) .preview-modal-close{pointer-events:auto}.preview-modal-content{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:fit-content;height:fit-content;pointer-events:none}.preview-modal:not(.hidden) .preview-modal-content{pointer-events:auto}.preview-modal-content>*{max-width:var(--preview-max-width);max-height:var(--preview-max-height);border:2px solid rgba(162,162,162,.5);box-shadow:0 2px 6px #0000004d;box-sizing:border-box}.preview-modal-content>img{border-radius:12px}.preview-modal-content>audio{border-radius:27px}.hidden{opacity:0}::-webkit-scrollbar{width:4px}::-webkit-scrollbar-track{background-color:transparent}::-webkit-scrollbar-thumb{border-radius:2px;background:#ffffff40}::-webkit-scrollbar-thumb:hover{background:#1e1e1ebf}p{font-size:16px;line-height:21px}.parsed-content-wrapper img{width:100%;border-radius:8px}h1{font-size:25px}h2{font-size:23px}h3{font-size:22px}h4{font-size:20px}h5{font-size:19px}h6{font-size:17px}p,h1,h2,h3,h4,h5,h6,ol,ul{margin:0}h1,h2{font-weight:800}h3,h4{font-weight:700}h5,h6{font-weight:600}code{background:#ffffff1a;padding:2px 4px;border-radius:8px}pre code{display:block;box-sizing:border-box;width:100%}pre:has(code),table{margin:6px 0}strong{color:#fe8e7c}em{color:#5affb2}a{text-decoration:none;color:#6dadd0;font-weight:800;font-style:italic;cursor:pointer;transition:var(--contentTransition)}a:hover{color:#86d3fd}hr{height:1px;width:100%;background-color:#fff3;border:none}li{margin:5px 0}ul{padding-left:16px}ol{padding-left:15px;padding-right:7.5px}table{border-collapse:collapse;border-spacing:0;border-radius:8px;border:1px solid rgba(255,255,255,.2);overflow:hidden;width:100%}table th,table td{border:1px solid rgba(255,255,255,.2);padding:6px 10px;background:#ffffff0f;text-align:left}table th{background:#ffffff1f;font-weight:700}",o.appendChild(r),this._container=document.createElement("div"),this._container.classList.add("container"),this.renderer=new n(this._container),this.overlayManager=new p(this._container),this.interactor=new l(this._container,{preventDefault:!0,proControlSchema:s.includes("proControlSchema")}),this.resizeObserver=new ResizeObserver(this.onResize),i.includes("minimap")?this.minimap=new h(this._container,s.includes("minimapCollapsed")):s.includes("minimapCollapsed")&&console.warn('CanvasViewer: "minimapCollapsed" option is not supported without minimap extension.'),s.includes("controlsHidden")?s.includes("controlsCollapsed")&&console.warn('CanvasViewer: "controlsCollapsed" option is overridden by "controlsHidden" option.'):this.controls=new c(this._container,s.includes("controlsCollapsed")),this.previewModal=new d(this._container),i.includes("mistouchPrevention")&&(this.mistouchPreventer=new m(this._container,!s.includes("noPreventionAtStart"))),o.appendChild(this._container),this.extensions=i,this.options=s,this.offsetX=0,this.offsetY=0,this.scale=1,this.perFrame={needAnimating:!1,zoom:!1,smoothZoom:!1,targetScale:1,pan:!1},this.resizeState={resizeTimeout:null,lastCallTime:0,center:{lastX:null,lastY:null}}}get canvasData(){if(null===this._canvasData)throw i;return this._canvasData}get nodeMap(){if(null===this._nodeMap)throw i;return this._nodeMap}get nodeBounds(){if(null===this._nodeBounds)throw i;return this._nodeBounds}get container(){if(null===this._container)throw i;return this._container}isUIControl(t){return t.closest&&(t.closest(".controls")||t.closest("button")||t.closest("input"))}findNodeAt({x:t,y:e}){let i=[];if(this.spatialGrid){const n=`${Math.floor(t/this.GRID_CELL_SIZE)},${Math.floor(e/this.GRID_CELL_SIZE)}`;i=this.spatialGrid[n]||[]}else i=this.canvasData.nodes;for(const n of i)if(!(t<n.x||t>n.x+n.width||e<n.y||e>n.y+n.height||"non-interactive"===this.judgeInteract(n)))return n}C2C({x:t,y:e}){return{x:t-this.offsetX,y:e-this.offsetY}}C2W({x:t,y:e}){return{x:t/this.scale,y:e/this.scale}}middleScreen(){return{x:this.container.clientWidth/2,y:this.container.clientHeight/2}}judgeInteract(t){switch(t?t.type:"default"){case"text":case"link":return"select";case"file":if(!t||!t.file)throw e;return t.file.match(/\.md$/i)?"select":"preview";default:return"non-interactive"}}zoomToScale(t,e){const i=Math.max(Math.min(t,20),.05);if(i===this.scale)return;const n=this.C2C(e);this.offsetX=e.x-n.x*i/this.scale,this.offsetY=e.y-n.y*i/this.scale,this.scale=i,this.controls&&this.controls.updateSlider(this.scale)}buildSpatialGrid(){if(this.canvasData&&!(this.canvasData.nodes.length<50)){this.spatialGrid={};for(let t of this.canvasData.nodes){const e=Math.floor(t.x/this.GRID_CELL_SIZE),i=Math.floor((t.x+t.width)/this.GRID_CELL_SIZE),n=Math.floor(t.y/this.GRID_CELL_SIZE),s=Math.floor((t.y+t.height)/this.GRID_CELL_SIZE);for(let o=e;o<=i;o++)for(let e=n;e<=s;e++){const i=`${o},${e}`;this.spatialGrid[i]||(this.spatialGrid[i]=[]),this.spatialGrid[i].push(t)}}}}calculateNodeBounds(){if(!this.canvasData||!this.canvasData.nodes.length)return null;let t=1/0,e=1/0,i=-1/0,n=-1/0;this.canvasData.nodes.forEach(s=>{t=Math.min(t,s.x),e=Math.min(e,s.y),i=Math.max(i,s.x+s.width),n=Math.max(n,s.y+s.height)});const s=i-t,o=n-e;return{minX:t,minY:e,maxX:i,maxY:n,width:s,height:o,centerX:t+s/2,centerY:e+o/2}}refresh(){this.renderer.redraw(this.offsetX,this.offsetY,this.scale),this.overlayManager.updateAllOverlays(this.offsetX,this.offsetY,this.scale),this.minimap&&this.minimap.updateViewportRectangle(this.offsetX,this.offsetY,this.scale)}resize(){const t=this.resizeState.center,e=this.middleScreen();t.lastX&&t.lastY&&(this.offsetX+=e.x-t.lastX,this.offsetY+=e.y-t.lastY),t.lastX=e.x,t.lastY=e.y,this.renderer.resizeCanvasForDPR(),this.previewModal.resize(2*e.x,2*e.y),this.refresh()}pan({x:t,y:e}){this.offsetX+=t,this.offsetY+=e}zoom(t,e){const i=this.scale*t;this.zoomToScale(i,e)}smoothZoom(){const t=this.perFrame.targetScale-this.scale;let e;Math.abs(t)<.01*this.perFrame.targetScale+.002?(e=this.perFrame.targetScale,this.perFrame.smoothZoom=!1):e=Math.round(1e3*(this.scale+t*this.ZOOM_SMOOTHNESS))/1e3,this.zoomToScale(e,this.middleScreen())}setScale(t){this.perFrame.targetScale=t,this.perFrame.smoothZoom=!0}panTo(t,e){this.offsetX=this.container.clientWidth/2-t*this.scale,this.offsetY=this.container.clientHeight/2-e*this.scale,this.perFrame.needAnimating=!0}shiftFullscreen(t="toggle"){document.fullscreenElement||"toggle"!==t&&"enter"!==t?document.fullscreenElement&&("toggle"===t||"exit"===t)&&document.exitFullscreen():this.container.requestFullscreen(),this.controls&&this.controls.updateFullscreenBtn()}async loadCanvas(t){try{if(/^https?:\/\//.test(t))this.canvasBaseDir=t.substring(0,t.lastIndexOf("/")+1);else{const e=t.lastIndexOf("/");this.canvasBaseDir=-1!==e?t.substring(0,e+1):"./"}this._canvasData=await fetch(t).then(t=>t.json()),this._nodeMap={},this.canvasData.nodes.forEach(t=>{if("file"===t.type&&t.file&&!t.file.includes("http")){const e=t.file.split("/");t.file=e[e.length-1]}this.nodeMap[t.id]=t}),this.buildSpatialGrid(),this._nodeBounds=this.calculateNodeBounds(),this.resetView(),this.resizeObserver.observe(this.container),this.interactor.start(),this.renderer.receiveData(this.nodeMap,this.canvasData),this.overlayManager.receiveData(this.canvasBaseDir,this.nodeMap),this.previewModal.receiveData(this.canvasBaseDir),this.interactor.addEventListener("trueClick",this.onClick),this.interactor.addEventListener("pan",this.onPan),this.interactor.addEventListener("zoom",this.onZoom),this.previewModal.addEventListener("previewModalShown",this.stopInteractor),this.previewModal.addEventListener("previewModalHidden",this.startInteractor),this.overlayManager.addEventListener("interactionStart",this.stopInteractor),this.overlayManager.addEventListener("interactionEnd",this.startInteractor),this.controls&&this.controls.addEventListener("zoomIn",this.zoomIn),this.controls&&this.controls.addEventListener("zoomOut",this.zoomOut),this.controls&&this.controls.addEventListener("slide",this.onSlide),this.controls&&this.controls.addEventListener("toggleFullscreen",this.onToggleFullscreen),this.controls&&this.controls.addEventListener("resetView",this.resetView),this.minimap&&(this.minimap.receiveData(this.nodeBounds,this.canvasData,this.nodeMap),this.minimap.addEventListener("minimapExpanded",this.onMinimapExpanded)),this.mistouchPreventer&&(this.mistouchPreventer.addEventListener("preventionStart",this.onPreventionStart),this.mistouchPreventer.addEventListener("preventionEnd",this.onPreventionEnd)),(!this.extensions.includes("mistouchPrevention")||this.options.includes("noPreventionAtStart"))&&(this.animationId=requestAnimationFrame(this.draw)),this.dispatchEvent(new CustomEvent("loaded",{detail:this.canvasData}))}catch(t){console.error("Failed to load canvas data:",t)}}dispose(){this.resizeState.resizeTimeout&&(clearTimeout(this.resizeState.resizeTimeout),this.resizeState.resizeTimeout=null),this.interactor.removeEventListener("trueClick",this.onClick),this.interactor.removeEventListener("pan",this.onPan),this.interactor.removeEventListener("zoom",this.onZoom),this.previewModal.removeEventListener("previewModalShown",this.stopInteractor),this.previewModal.removeEventListener("previewModalHidden",this.startInteractor),this.overlayManager.removeEventListener("interactionStart",this.stopInteractor),this.overlayManager.removeEventListener("interactionEnd",this.startInteractor),this.controls&&this.controls.removeEventListener("zoomIn",this.zoomIn),this.controls&&this.controls.removeEventListener("zoomOut",this.zoomOut),this.controls&&this.controls.removeEventListener("slide",this.onSlide),this.controls&&this.controls.removeEventListener("toggleFullscreen",this.onToggleFullscreen),this.controls&&this.controls.removeEventListener("resetView",this.resetView),this.minimap&&this.minimap.removeEventListener("minimapExpanded",this.onMinimapExpanded),this.mistouchPreventer&&(this.mistouchPreventer.removeEventListener("preventionStart",this.onPreventionStart),this.mistouchPreventer.removeEventListener("preventionEnd",this.onPreventionEnd)),this.animationId&&cancelAnimationFrame(this.animationId),this.resizeObserver.disconnect(),this.interactor.dispose(),this.previewModal.dispose(),this.controls&&this.controls.dispose(),this.minimap&&this.minimap.dispose(),this.mistouchPreventer&&this.mistouchPreventer.dispose(),this.overlayManager.dispose(),this.renderer.dispose(),this.container.remove(),this._container=null}}class u extends HTMLElement{constructor(){super(),this.style.display="block",this.style.overflow="hidden",this.style.maxWidth="120vw",this.style.maxHeight="120vh";const t=this.getAttribute("extensions"),e=this.getAttribute("options"),i=t?t.split(" "):[],n=e?e.split(" "):[];this.viewer=new v(this,i,n)}connectedCallback(){const t=this.getAttribute("src");if(!t)throw new Error("No source canvas path provided.");this.viewer&&this.viewer.loadCanvas(t)}disconnectedCallback(){this.viewer&&this.viewer.dispose(),this.remove()}}customElements.define("canvas-viewer",u);export{v as default};
@@ -8,6 +8,7 @@ export default class interactor extends EventTarget {
8
8
  private zoomFactor;
9
9
  private preventDefault;
10
10
  private lockControlSchema;
11
+ private ctrlZoomFactor;
11
12
  private get monitoringElement();
12
13
  constructor(monitoringElement: HTMLElement, options?: {
13
14
  preventDefault?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-canvas-viewer",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "description": "A TypeScript-based viewer for JSON Canvas, easy to embed into websites.",
5
5
  "type": "module",
6
6
  "types": "dist/canvasViewer.d.ts",
@@ -8,8 +8,8 @@
8
8
  "module": "dist/canvasViewer.esm.js",
9
9
  "exports": {
10
10
  ".": {
11
- "import": "./dist/my-library.esm.js",
12
- "require": "./dist/my-library.cjs.js"
11
+ "import": "./dist/canvasViewer.esm.js",
12
+ "require": "./dist/canvasViewer.cjs.js"
13
13
  }
14
14
  },
15
15
  "repository": {