json-canvas-viewer 4.2.0 → 4.2.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/dist/chimp.js CHANGED
@@ -281,7 +281,7 @@ pre .JSON-Canvas-Viewer .JCV-markdown-content code {
281
281
  background: rgba(255, 255, 255, 0.12);
282
282
  font-weight: bold;
283
283
  }
284
- `;const b=Error(`[JSONCanvasViewer] Resource hasn't been set up or has been disposed.`);function x(e,t){let n=document.createElement(`style`);n.innerHTML=t,e.appendChild(n)}function S(e,t,n,r,i,a){e.beginPath(),e.moveTo(t+a,n),e.lineTo(t+r-a,n),e.quadraticCurveTo(t+r,n,t+r,n+a),e.lineTo(t+r,n+i-a),e.quadraticCurveTo(t+r,n+i,t+r-a,n+i),e.lineTo(t+a,n+i),e.quadraticCurveTo(t,n+i,t,n+i-a),e.lineTo(t,n+a),e.quadraticCurveTo(t,n,t+a,n),e.closePath()}function C(e,t){let n=e.x+e.width/2,r=e.y+e.height/2;switch(t){case`top`:return{x:n,y:e.y};case`bottom`:return{x:n,y:e.y+e.height};case`left`:return{x:e.x,y:r};case`right`:return{x:e.x+e.width,y:r};default:return{x:n,y:r}}}function w(e,t,n){let r=window.devicePixelRatio??1,i=e.getContext(`2d`);if(!i)throw Error(`[JSONCanvasViewer] This error is unexpected, probably caused uncontrollable runtime errors. Please contact the developer and show how to reproduce.`);e.width=Math.round(t*r),e.height=Math.round(n*r),i.setTransform(1,0,0,1,0,0),i.scale(r,r)}function T(e,t){let n=10**t;return Math.round(e*n)/n}function E(e=!1,t=!1){let n=t?async(...t)=>{if(e){let e=[...n.subs].reverse();for(let n of e)await n(...t)}else for(let e of n.subs)await e(...t)}:(...t)=>{if(e){let e=[...n.subs].reverse();for(let n of e)n(...t)}else for(let e of n.subs)e(...t)};return n.subs=new Set,n.subscribe=e=>{n.subs.add(e)},n.unsubscribe=e=>{n.subs.delete(e)},n}var D=class extends v{onToggleFullscreen=E();data={canvasBaseDir:`./`,canvasData:{edges:[],nodes:[]},container:document.createElement(`div`),edgeMap:{},nodeBounds:{centerX:0,centerY:0,height:0,maxX:0,maxY:0,minX:0,minY:0,width:0},nodeMap:{},offsetX:0,offsetY:0,scale:1};constructor(...e){super(...e);let t=this.options.container;for(;t.firstElementChild;)t.firstElementChild.remove();t.innerHTML=``;let n=this.options.shadowed?t.attachShadow({mode:`open`}):t;x(n,y+this.options.extraCSS),this.data.container.classList.add(`JSON-Canvas-Viewer`),n.appendChild(this.data.container),this.augment({onToggleFullscreen:this.onToggleFullscreen,resetView:this.resetView,toggleFullscreen:this.toggleFullscreen}),this.onStart(this.start),this.onRestart(this.start),this.onDispose(this.dispose)}start=()=>{let e={edges:[],nodes:[],...this.options.canvas};Object.assign(this.data,{canvasBaseDir:this.processBaseDir(this.options.attachmentDir),canvasData:e,edgeMap:{},nodeBounds:this.calculateNodeBounds(e),nodeMap:{},offsetX:0,offsetY:0,scale:1}),this.data.canvasData.nodes.forEach(e=>{let t={box:this.getNodeBox(e),ref:e};if(this.data.nodeMap[e.id]=t,e.type===`file`){let n=e.file.split(`/`).pop()??``;if(t.fileName=n,!e.file.startsWith(`http://`)&&!e.file.startsWith(`https://`)){let t=this.options.attachments?.[n];t?e.file=t:this.options.noAttachmentRelocation||(e.file=this.data.canvasBaseDir+n)}}}),this.data.canvasData.edges.forEach(e=>{this.data.edgeMap[e.id]={box:this.getEdgeBox(e),ref:e}}),this.resetView()};processBaseDir=e=>e?e?.slice(-1)===`/`?e:`${e}/`:`./`;getNodeBox=e=>({bottom:e.y+e.height,left:e.x,right:e.width+e.x,top:e.type===`file`||e.type===`group`?e.y-40:e.y});getEdgeBox=e=>{let t=this.data.nodeMap,n=t[e.fromNode].ref,r=t[e.toNode].ref,i=C(n,e.fromSide),a=C(r,e.toSide),o={bottom:Math.max(i.y,a.y),left:Math.min(i.x,a.x),right:Math.max(i.x,a.x),top:Math.min(i.y,a.y)},s=o.right-o.left,c=o.bottom-o.top,l=Math.min(s,c),u=Math.log2(Math.max(s,c)/(l===0?1:l))*10;return{bottom:o.bottom+u,left:o.left-u,right:o.right+u,top:o.top-u}};calculateNodeBounds(e){let t=1/0,n=1/0,r=-1/0,i=-1/0;e.nodes.forEach(e=>{t=Math.min(t,e.x),n=Math.min(n,e.y),r=Math.max(r,e.x+e.width),i=Math.max(i,e.y+e.height)});let a=r-t,o=i-n;return{centerX:t+a/2,centerY:n+o/2,height:o,maxX:r,maxY:i,minX:t,minY:n,width:a}}toggleFullscreen=async e=>{!document.fullscreenElement&&(!e||e===`enter`)?(await this.data.container.requestFullscreen(),this.onToggleFullscreen(`enter`)):document.fullscreenElement&&(!e||e===`exit`)&&(await document.exitFullscreen(),this.onToggleFullscreen(`exit`))};resetView=()=>{let e=this.data.nodeBounds,t=this.data.container;if(!e||!t)return;let n=e.width+200,r=e.height+200,i=t.clientWidth,a=t.clientHeight,o=i/n,s=a/r,c=Math.round(Math.min(o,s)*1e3)/1e3,l=e.centerX,u=e.centerY,d={offsetX:i/2-l*c,offsetY:a/2-u*c,scale:c};this.data.offsetX=d.offsetX,this.data.offsetY=d.offsetY,this.data.scale=d.scale};middleViewer=()=>{let e=this.data.container;return{height:e.clientHeight,width:e.clientWidth,x:e.clientWidth/2,y:e.clientHeight/2}};dispose=()=>{this.data.container.remove()}},O=class extends v{theme=`light`;onChangeTheme=E();definedColors={dark:{0:{hue:0,lightness:40,saturation:0},1:{hue:358,lightness:65,saturation:100},2:{hue:23,lightness:63,saturation:86},3:{hue:39,lightness:70,saturation:91},4:{hue:153,lightness:45,saturation:80},5:{hue:217,lightness:62,saturation:100},6:{hue:259,lightness:75,saturation:100}},light:{0:{hue:0,lightness:72,saturation:0},1:{hue:358,lightness:55,saturation:81},2:{hue:19,lightness:58,saturation:87},3:{hue:41,lightness:52,saturation:79},4:{hue:150,lightness:37,saturation:100},5:{hue:221,lightness:59,saturation:100},6:{hue:257,lightness:62,saturation:81}}};namedColors={dark:{background:`rgb(30, 30, 30)`,"background-secondary":`rgb(37, 37, 40)`,border:`hsla(0, 0%, 30%, 0.7)`,dots:`hsla(0, 0%, 40%, 0.3)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.2)`,text:`rgb(242, 242, 242)`},light:{background:`rgb(250, 250, 250)`,"background-secondary":`rgb(255, 255, 255)`,border:`hsla(0, 0%, 82%, 0.7)`,dots:`hsla(0, 0%, 72%, 0.4)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.1)`,text:`rgb(30, 30, 30)`}};colorCache={dark:{},light:{}};constructor(...e){super(...e);let t=this.options.colors;t&&[`light`,`dark`].forEach(e=>{if(!(e in t))return;let n=t[e];n&&Object.entries(n).forEach(([t,n])=>{if(!n)return;let r=this.namedColors[e],i=this.definedColors[e];if(t in r)r[t]=n;else if(t in i){let e=this.parseColor(n);if(!e){console.warn(`[JSON Canvas Viewer] Color ${n} unsupported.`);return}i[t]=e}})}),this.changeTheme(this.options.theme??`light`),this.augment({changeTheme:this.changeTheme,onChangeTheme:this.onChangeTheme})}hslProcessor=e=>{let{hue:t,saturation:n,lightness:r}=e,a=this.theme===`dark`?{active:e,background:{...e,alpha:.1},border:{...e,alpha:.7},card:{hue:t,lightness:r/3,saturation:n/3},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`}:{active:e,background:{...e,alpha:.1},border:{...e,alpha:.7},card:t===0?{hue:t,lightness:100,saturation:n}:{hue:t,lightness:90,saturation:n*.4},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`};return{active:i(a.active),background:i(a.background),border:i(a.border),card:i(a.card),text:a.text}};parseColor=i=>{if(i.startsWith(`rgb`))return r(n(i));if(i.startsWith(`#`))return r(e(i));if(i.startsWith(`hsl`))return t(i)};getColor=(t=`0`)=>{let n=this.theme,i;if(this.colorCache[n][t])return this.colorCache[n][t];i=t in this.definedColors[n]?this.hslProcessor(this.definedColors[n][t]):this.hslProcessor(r(e(t)));let a={...i,"border-width":t===`0`?`1px`:`2px`};return this.colorCache[n][t]=a,a};getNamedColor=e=>this.namedColors[this.theme][e];changeTheme=e=>{this.theme=e??this.theme===`dark`?`light`:`dark`;let t=this.container.get(D).data.container;Object.entries(this.namedColors[this.theme]).forEach(([e,n])=>{t.style.setProperty(`--${e}`,n)}),this.onChangeTheme(this.theme)}},k=class extends v{animationId;resizeAnimationId;DM;SM;resizeObserver;perFrame={lastOffsets:{x:0,y:0},lastScale:1};lastResizeCenter={x:void 0,y:void 0};onResize=E();onRefresh=E();constructor(...e){super(...e),this.DM=this.container.get(D),this.SM=this.container.get(O),this.resizeObserver=new ResizeObserver(this.onResizeCallback),this.SM.onChangeTheme.subscribe(this.refresh),this.augment({onRefresh:this.onRefresh,onResize:this.onResize,refresh:this.refresh}),this.onStart(this.start),this.onRestart(this.refresh),this.onDispose(this.dispose)}start=()=>{this.resizeObserver.observe(this.DM.data.container),this.animationId=requestAnimationFrame(this.draw)};draw=()=>{(this.perFrame.lastScale!==this.DM.data.scale||this.perFrame.lastOffsets.x!==this.DM.data.offsetX||this.perFrame.lastOffsets.y!==this.DM.data.offsetY)&&this.refresh(),this.animationId=requestAnimationFrame(this.draw)};refresh=()=>{this.perFrame={lastOffsets:{x:this.DM.data.offsetX,y:this.DM.data.offsetY},lastScale:this.DM.data.scale},this.onRefresh()};onResizeCallback=()=>{this.resizeAnimationId=requestAnimationFrame(()=>{let e=this.DM.middleViewer();this.lastResizeCenter.x&&this.lastResizeCenter.y&&(this.DM.data.offsetX=this.DM.data.offsetX+e.x-this.lastResizeCenter.x,this.DM.data.offsetY=this.DM.data.offsetY+e.y-this.lastResizeCenter.y),this.lastResizeCenter.x=e.x,this.lastResizeCenter.y=e.y,this.onResize(e.width,e.height),this.refresh()})};dispose=()=>{this.animationId&&cancelAnimationFrame(this.animationId),this.resizeAnimationId&&cancelAnimationFrame(this.resizeAnimationId),this.resizeObserver.disconnect()}};const A={audio:/\.(mp3|wav|ogg|opus|aac|m4a|flac)$/i,image:/\.(png|jpg|jpeg|gif|svg|webp|avif|bmp|ico|heic|heif)$/i,markdown:/\.(md|mdx|markdown|txt)$/i,video:/\.(mp4|webm|ogv|mov|m3u8|mpd)$/i},j=[`markdown`,`image`,`audio`,`video`];var M=class extends v{_overlaysLayer=document.createElement(`div`);overlays={};selectedId;aborted=!1;eventListeners={};DM;SM;parse;componentDict={audio:({container:e,content:t})=>{let n=document.createElement(`audio`);n.className=`JCV-audio`,n.src=t,n.controls=!0,e.appendChild(n)},image:({container:e,content:t})=>{let n=document.createElement(`img`);n.className=`JCV-img`,n.src=t,n.loading=`lazy`,e.appendChild(n)},link:({container:e,content:t})=>{let n=document.createElement(`iframe`);n.src=t,n.sandbox=`allow-scripts allow-same-origin`,n.className=`JCV-link-iframe`,n.loading=`lazy`,e.appendChild(n)},markdown:async({container:e,content:t})=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.textContent=`Loading...`,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n);let r;try{let e=await(await fetch(t)).text(),n=/^---\n([\s\S]*?)\n---\n([\s\S]*)$/.exec(e);r=await this.parse(n?n[2]:e)}catch(e){console.error(`[JSON Canvas Viewer] Failed to load markdown:`,e),r=`Failed to load content.`}n.innerHTML=r},text:({container:e,content:t})=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.innerHTML=t,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n)},video:({container:e,content:t})=>{let n=document.createElement(`video`);n.className=`JCV-video`,n.src=t,n.controls=!0,e.appendChild(n)}};get overlaysLayer(){if(!this._overlaysLayer)throw b;return this._overlaysLayer}onInteractionStart=E();onInteractionEnd=E();onNodeActive=E();onNodeLosesActive=E();constructor(...e){super(...e),this.parse=this.options.parser??(e=>e),this.DM=this.container.get(D),this.SM=this.container.get(O),this.container.get(k).onRefresh.subscribe(this.updateOverlays),this.SM.onChangeTheme.subscribe(this.themeChanged),this._overlaysLayer=document.createElement(`div`),this._overlaysLayer.className=`JCV-overlays`,this._overlaysLayer.id=`overlays`,this.DM.data.container.appendChild(this.overlaysLayer);let t=this.options.nodeComponents;t&&Object.assign(this.componentDict,t),this.augment({onNodeActive:this.onNodeActive,onNodeLosesActive:this.onNodeLosesActive}),this.onStart(this.start),this.onRestart(this.restart),this.onDispose(this.dispose)}start=()=>{this.container.get(N).onClick.subscribe(this.select),this.renderOverlays()};restart=()=>{this.clearOverlays(),this.renderOverlays()};renderOverlays=()=>{let e=async e=>{switch(e.type){case`text`:this.createOverlay(e,await this.parse(e.text),`text`);break;case`file`:for(let t of j)if(e.file.match(A[t])){this.createOverlay(e,e.file,t);break}break;case`link`:this.createOverlay(e,e.url,`link`);break}};Object.values(this.DM.data.nodeMap).forEach(async t=>{await e(t.ref)})};themeChanged=()=>{Object.values(this.overlays).forEach(e=>{let t=this.DM.data.nodeMap[e.id].ref,n=this.SM.getColor(t.color);this.setOverlayColor(e,n)})};select=e=>{let t=this.selectedId,n=t?this.overlays[t]:void 0,r=e?this.overlays[e]:void 0;if(n&&t){n.classList.remove(`JCV-active`);let e=this.DM.data.nodeMap[t];this.onNodeLosesActive(e.ref),e.onLoseActive?.()}if(r&&e){r.classList.add(`JCV-active`),this.onInteractionStart();let t=this.DM.data.nodeMap[e];this.onNodeActive(t.ref),t.onActive?.()}else this.onInteractionEnd();this.selectedId=e};updateOverlays=()=>{let e=this.DM.data;this.overlaysLayer.style.transform=`translate(${e.offsetX}px, ${e.offsetY}px) scale(${e.scale})`};createOverlay=(...e)=>{if(this.aborted)return;let t=e[0],n=this.overlays[t.id];if(!n){if(n=this.constructOverlay(...e),this.aborted)return;this.overlaysLayer.appendChild(n),this.overlays[t.id]=n,n.style.left=`${t.x}px`,n.style.top=`${t.y}px`,n.style.width=`${t.width}px`,n.style.height=`${t.height}px`}};constructOverlay=(...e)=>{let t=e[0],n=document.createElement(`div`);n.classList.add(`JCV-overlay-container`),n.id=t.id,this.setOverlayColor(n,this.SM.getColor(t.color));let r=document.createElement(`div`);r.classList.add(`JCV-content`),n.appendChild(r);let i=document.createElement(`div`);i.className=`JCV-click-layer`,n.appendChild(i);let a=document.createElement(`div`);a.className=`JCV-overlay-border`,n.appendChild(a);let o=this.DM.data.nodeMap[t.id];o.onActive=E(),o.onLoseActive=E(),o.onBeforeUnmount=E(),this.componentDict[e[2]]({container:r,content:e[1],node:e[0],onActive:o.onActive,onBeforeUnmount:o.onBeforeUnmount,onLoseActive:o.onLoseActive});let s=()=>{t.id===this.selectedId&&this.onInteractionStart()},c=()=>{t.id===this.selectedId&&this.onInteractionEnd()};return n.addEventListener(`pointerenter`,s),n.addEventListener(`pointerleave`,c),n.addEventListener(`touchstart`,s),n.addEventListener(`touchend`,c),this.eventListeners[t.id]=[s,c],n};setOverlayColor=(e,t)=>{Object.entries(t).forEach(([t,n])=>{e.style.setProperty(`--overlay-${t}`,n)})};clearOverlays=()=>{Object.entries(this.overlays).forEach(([e,t])=>{if(this.DM.data.nodeMap[e].onBeforeUnmount?.(),this.eventListeners[e]){let n=this.eventListeners[e][0],r=this.eventListeners[e][1];if(!n||!r)throw b;t.removeEventListener(`pointerenter`,n),t.removeEventListener(`pointerleave`,r),t.removeEventListener(`touchstart`,n),t.removeEventListener(`touchend`,r),this.eventListeners[e][0]=void 0,this.eventListeners[e][1]=void 0}t.remove(),delete this.overlays[e]})};dispose=()=>{this.aborted=!0,this.clearOverlays(),this.overlaysLayer.remove(),this._overlaysLayer=void 0}},N=class extends v{pointeract;DM;onClick=E();constructor(...e){super(...e),this.DM=this.container.get(D);let t=Object.assign(this.options.pointeract??{},{coordinateOutput:`relative`,element:this.DM.data.container,lubricator:{drag:f,pan:p,zoom:m}});this.pointeract=new l(t,[a,o,d,u,c,s]);let n=this.container.get(M);n.onInteractionStart.subscribe(this.stopInteract),n.onInteractionEnd.subscribe(this.startInteract),this.augment({pan:this.pan,panToCoords:this.panToCoords,zoom:this.zoom,zoomToScale:this.zoomToScale}),this.onStart(this.start),this.onDispose(this.dispose)}start=()=>{this.pointeract.on(`pan`,this.onPan).on(`drag`,this.onPan).on(`zoom`,this.onZoom).on(`trueClick`,this.onTrueClick).start()};startInteract=()=>{this.pointeract.start()};stopInteract=()=>{this.pointeract.stop()};onPan=e=>{this.truePan({x:e.deltaX,y:e.deltaY})};onZoom=e=>{this.trueZoom(e.factor,e)};trueZoom=(e,t)=>{let n=Math.max(Math.min(this.DM.data.scale*e,20),.05);if(n===this.DM.data.scale)return;let r=n/this.DM.data.scale,i=this.C2C(t);this.DM.data.offsetX=t.x-i.x*r,this.DM.data.offsetY=t.y-i.y*r,this.DM.data.scale=n};truePan=({x:e,y:t})=>{this.DM.data.offsetX+=e,this.DM.data.offsetY+=t};zoom=(e,t)=>{this.pointeract.dispatch(`zoom`,{factor:e,...t})};pan=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e,deltaY:t})};zoomToScale=(e,t)=>{let n=e/this.DM.data.scale;this.pointeract.dispatch(`zoom`,{factor:n,...t})};panToCoords=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e-this.DM.data.offsetX,deltaY:t-this.DM.data.offsetY})};C2C=({x:e,y:t})=>({x:e-this.DM.data.offsetX,y:t-this.DM.data.offsetY});onTrueClick=e=>{let t=e.target;if(this.isUIControl(t))return;let n=this.findNodeId(t);this.onClick(n)};isUIControl=e=>e?e.closest(`.controls`)||e.closest(`button`)||e.closest(`input`):!1;findNodeId=e=>{if(!e)return;let t=e;for(;(!t.id||t.id===``)&&t.parentElement;)t=t.parentElement;if(!(t.id===`overlays`||!t.id||t.id===``))return t.id};dispose=()=>this.pointeract.dispose()},P=`.JSON-Canvas-Viewer > .JCV-controls {
284
+ `;const b=Error(`[JSONCanvasViewer] Resource hasn't been set up or has been disposed.`);function x(e,t){let n=document.createElement(`style`);n.innerHTML=t,e.appendChild(n)}function S(e,t,n,r,i,a){e.beginPath(),e.moveTo(t+a,n),e.lineTo(t+r-a,n),e.quadraticCurveTo(t+r,n,t+r,n+a),e.lineTo(t+r,n+i-a),e.quadraticCurveTo(t+r,n+i,t+r-a,n+i),e.lineTo(t+a,n+i),e.quadraticCurveTo(t,n+i,t,n+i-a),e.lineTo(t,n+a),e.quadraticCurveTo(t,n,t+a,n),e.closePath()}function C(e,t){let n=e.x+e.width/2,r=e.y+e.height/2;switch(t){case`top`:return{x:n,y:e.y};case`bottom`:return{x:n,y:e.y+e.height};case`left`:return{x:e.x,y:r};case`right`:return{x:e.x+e.width,y:r};default:return{x:n,y:r}}}function w(e,t,n){let r=window.devicePixelRatio??1,i=e.getContext(`2d`);if(!i)throw Error(`[JSONCanvasViewer] This error is unexpected, probably caused uncontrollable runtime errors. Please contact the developer and show how to reproduce.`);e.width=Math.round(t*r),e.height=Math.round(n*r),i.setTransform(1,0,0,1,0,0),i.scale(r,r)}function T(e,t){let n=10**t;return Math.round(e*n)/n}function E(e=!1,t=!1){let n=t?async(...t)=>{if(e){let e=[...n.subs].reverse();for(let n of e)await n(...t)}else for(let e of n.subs)await e(...t)}:(...t)=>{if(e){let e=[...n.subs].reverse();for(let n of e)n(...t)}else for(let e of n.subs)e(...t)};return n.subs=new Set,n.subscribe=e=>{n.subs.add(e)},n.unsubscribe=e=>{n.subs.delete(e)},n}var D=class extends v{onToggleFullscreen=E();data={canvasBaseDir:`./`,canvasData:{edges:[],nodes:[]},container:document.createElement(`div`),edgeMap:{},nodeBounds:{centerX:0,centerY:0,height:0,maxX:0,maxY:0,minX:0,minY:0,width:0},nodeMap:{},offsetX:0,offsetY:0,scale:1};constructor(...e){super(...e);let t=this.options.container;for(;t.firstElementChild;)t.firstElementChild.remove();t.innerHTML=``;let n=this.options.shadowed?t.attachShadow({mode:`open`}):t;x(n,y+this.options.extraCSS),this.data.container.classList.add(`JSON-Canvas-Viewer`),n.appendChild(this.data.container),this.augment({onToggleFullscreen:this.onToggleFullscreen,resetView:this.resetView,toggleFullscreen:this.toggleFullscreen}),this.onStart(this.start),this.onRestart(this.start),this.onDispose(this.dispose)}start=()=>{let e={edges:[],nodes:[],...this.options.canvas};Object.assign(this.data,{canvasBaseDir:this.processBaseDir(this.options.attachmentDir),canvasData:e,edgeMap:{},nodeBounds:this.calculateNodeBounds(e),nodeMap:{},offsetX:0,offsetY:0,scale:1}),this.data.canvasData.nodes.forEach(e=>{let t={box:this.getNodeBox(e),ref:e};if(this.data.nodeMap[e.id]=t,e.type===`file`){let n=e.file.split(`/`).pop()??``;if(t.fileName=n,!e.file.startsWith(`http://`)&&!e.file.startsWith(`https://`)){let t=this.options.attachments?.[n];t?e.file=t:this.options.noAttachmentRelocation||(e.file=this.data.canvasBaseDir+n)}}}),this.data.canvasData.edges.forEach(e=>{this.data.edgeMap[e.id]={box:this.getEdgeBox(e),ref:e}}),this.resetView()};processBaseDir=e=>e?e?.slice(-1)===`/`?e:`${e}/`:`./`;getNodeBox=e=>({bottom:e.y+e.height,left:e.x,right:e.width+e.x,top:e.type===`file`||e.type===`group`?e.y-40:e.y});getEdgeBox=e=>{let t=this.data.nodeMap,n=t[e.fromNode].ref,r=t[e.toNode].ref,i=C(n,e.fromSide),a=C(r,e.toSide),o={bottom:Math.max(i.y,a.y),left:Math.min(i.x,a.x),right:Math.max(i.x,a.x),top:Math.min(i.y,a.y)},s=o.right-o.left,c=o.bottom-o.top,l=Math.min(s,c),u=Math.log2(Math.max(s,c)/(l===0?1:l))*10;return{bottom:o.bottom+u,left:o.left-u,right:o.right+u,top:o.top-u}};calculateNodeBounds(e){let t=1/0,n=1/0,r=-1/0,i=-1/0;e.nodes.forEach(e=>{t=Math.min(t,e.x),n=Math.min(n,e.y),r=Math.max(r,e.x+e.width),i=Math.max(i,e.y+e.height)});let a=r-t,o=i-n;return{centerX:t+a/2,centerY:n+o/2,height:o,maxX:r,maxY:i,minX:t,minY:n,width:a}}toggleFullscreen=async e=>{!document.fullscreenElement&&(!e||e===`enter`)?(await this.data.container.requestFullscreen(),this.onToggleFullscreen(`enter`)):document.fullscreenElement&&(!e||e===`exit`)&&(await document.exitFullscreen(),this.onToggleFullscreen(`exit`))};resetView=()=>{let e=this.data.nodeBounds,t=this.data.container;if(!e||!t)return;let n=e.width+200,r=e.height+200,i=t.clientWidth,a=t.clientHeight,o=i/n,s=a/r,c=Math.round(Math.min(o,s)*1e3)/1e3,l=e.centerX,u=e.centerY,d={offsetX:i/2-l*c,offsetY:a/2-u*c,scale:c};this.data.offsetX=d.offsetX,this.data.offsetY=d.offsetY,this.data.scale=d.scale};middleViewer=()=>{let e=this.data.container;return{height:e.clientHeight,width:e.clientWidth,x:e.clientWidth/2,y:e.clientHeight/2}};dispose=()=>{this.data.container.remove()}},O=class extends v{theme=`light`;onChangeTheme=E();definedColors={dark:{0:{hue:0,lightness:40,saturation:0},1:{hue:358,lightness:65,saturation:100},2:{hue:23,lightness:63,saturation:86},3:{hue:39,lightness:70,saturation:91},4:{hue:153,lightness:45,saturation:80},5:{hue:217,lightness:62,saturation:100},6:{hue:259,lightness:75,saturation:100}},light:{0:{hue:0,lightness:72,saturation:0},1:{hue:358,lightness:55,saturation:81},2:{hue:19,lightness:58,saturation:87},3:{hue:41,lightness:52,saturation:79},4:{hue:150,lightness:37,saturation:100},5:{hue:221,lightness:59,saturation:100},6:{hue:257,lightness:62,saturation:81}}};namedColors={dark:{background:`rgb(30, 30, 30)`,"background-secondary":`rgb(37, 37, 40)`,border:`hsla(0, 0%, 30%, 0.7)`,dots:`hsla(0, 0%, 40%, 0.3)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.2)`,text:`rgb(242, 242, 242)`},light:{background:`rgb(250, 250, 250)`,"background-secondary":`rgb(255, 255, 255)`,border:`hsla(0, 0%, 82%, 0.7)`,dots:`hsla(0, 0%, 72%, 0.4)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.1)`,text:`rgb(30, 30, 30)`}};colorCache={dark:{},light:{}};constructor(...e){super(...e);let t=this.options.colors;t&&[`light`,`dark`].forEach(e=>{if(!(e in t))return;let n=t[e];n&&Object.entries(n).forEach(([t,n])=>{if(!n)return;let r=this.namedColors[e],i=this.definedColors[e];if(t in r)r[t]=n;else if(t in i){let e=this.parseColor(n);if(!e){console.warn(`[JSON Canvas Viewer] Color ${n} unsupported.`);return}i[t]=e}})}),this.changeTheme(this.options.theme??`light`),this.augment({changeTheme:this.changeTheme,onChangeTheme:this.onChangeTheme})}hslProcessor=e=>{let{hue:t,saturation:n,lightness:r}=e,a=this.theme===`dark`?{active:e,background:{...e,alpha:.1},border:{...e,alpha:.7},card:{hue:t,lightness:r/3,saturation:n/3},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`}:{active:e,background:{...e,alpha:.1},border:{...e,alpha:.7},card:t===0?{hue:t,lightness:100,saturation:n}:{hue:t,lightness:90,saturation:n*.4},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`};return{active:i(a.active),background:i(a.background),border:i(a.border),card:i(a.card),text:a.text}};parseColor=i=>{if(i.startsWith(`rgb`))return r(n(i));if(i.startsWith(`#`))return r(e(i));if(i.startsWith(`hsl`))return t(i)};getColor=(t=`0`)=>{let n=this.theme,i;if(this.colorCache[n][t])return this.colorCache[n][t];i=t in this.definedColors[n]?this.hslProcessor(this.definedColors[n][t]):this.hslProcessor(r(e(t)));let a={...i,"border-width":t===`0`?`1px`:`2px`};return this.colorCache[n][t]=a,a};getNamedColor=e=>this.namedColors[this.theme][e];changeTheme=e=>{this.theme=e??(this.theme===`dark`?`light`:`dark`);let t=this.container.get(D).data.container;Object.entries(this.namedColors[this.theme]).forEach(([e,n])=>{t.style.setProperty(`--${e}`,n)}),this.onChangeTheme(this.theme)}},k=class extends v{animationId;resizeAnimationId;DM;SM;resizeObserver;perFrame={lastOffsets:{x:0,y:0},lastScale:1};lastResizeCenter={};onResize=E();onRefresh=E();constructor(...e){super(...e),this.DM=this.container.get(D),this.SM=this.container.get(O),this.resizeObserver=new ResizeObserver(this.onResizeCallback),this.SM.onChangeTheme.subscribe(this.refresh),this.augment({onRefresh:this.onRefresh,onResize:this.onResize,refresh:this.refresh}),this.onStart(this.start),this.onRestart(this.refresh),this.onDispose(this.dispose)}start=()=>{this.resizeObserver.observe(this.DM.data.container),this.animationId=requestAnimationFrame(this.draw)};draw=()=>{(this.perFrame.lastScale!==this.DM.data.scale||this.perFrame.lastOffsets.x!==this.DM.data.offsetX||this.perFrame.lastOffsets.y!==this.DM.data.offsetY)&&this.refresh(),this.animationId=requestAnimationFrame(this.draw)};refresh=()=>{this.perFrame={lastOffsets:{x:this.DM.data.offsetX,y:this.DM.data.offsetY},lastScale:this.DM.data.scale},this.onRefresh()};onResizeCallback=()=>{this.resizeAnimationId=requestAnimationFrame(()=>{let e=this.DM.middleViewer();this.lastResizeCenter.x&&this.lastResizeCenter.y&&(this.DM.data.offsetX=this.DM.data.offsetX+e.x-this.lastResizeCenter.x,this.DM.data.offsetY=this.DM.data.offsetY+e.y-this.lastResizeCenter.y),this.lastResizeCenter.x=e.x,this.lastResizeCenter.y=e.y,this.onResize(e.width,e.height),this.refresh()})};dispose=()=>{this.animationId&&cancelAnimationFrame(this.animationId),this.resizeAnimationId&&cancelAnimationFrame(this.resizeAnimationId),this.resizeObserver.disconnect()}};const A={audio:/\.(mp3|wav|ogg|opus|aac|m4a|flac)$/i,image:/\.(png|jpg|jpeg|gif|svg|webp|avif|bmp|ico|heic|heif)$/i,markdown:/\.(md|mdx|markdown|txt)$/i,video:/\.(mp4|webm|ogv|mov|m3u8|mpd)$/i},j=[`markdown`,`image`,`audio`,`video`];var M=class extends v{_overlaysLayer=document.createElement(`div`);overlays={};selectedId;aborted=!1;eventListeners={};DM;SM;parse;componentDict={audio:({container:e,content:t})=>{let n=document.createElement(`audio`);n.className=`JCV-audio`,n.src=t,n.controls=!0,e.appendChild(n)},image:({container:e,content:t})=>{let n=document.createElement(`img`);n.className=`JCV-img`,n.src=t,n.loading=`lazy`,e.appendChild(n)},link:({container:e,content:t})=>{let n=document.createElement(`iframe`);n.src=t,n.sandbox=`allow-scripts allow-same-origin`,n.className=`JCV-link-iframe`,n.loading=`lazy`,e.appendChild(n)},markdown:async({container:e,content:t})=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.textContent=`Loading...`,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n);let r;try{let e=await(await fetch(t)).text(),n=/^---\n([\s\S]*?)\n---\n([\s\S]*)$/.exec(e);r=await this.parse(n?n[2]:e)}catch(e){console.error(`[JSON Canvas Viewer] Failed to load markdown:`,e),r=`Failed to load content.`}n.innerHTML=r},text:({container:e,content:t})=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.innerHTML=t,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n)},video:({container:e,content:t})=>{let n=document.createElement(`video`);n.className=`JCV-video`,n.src=t,n.controls=!0,e.appendChild(n)}};get overlaysLayer(){if(!this._overlaysLayer)throw b;return this._overlaysLayer}onInteractionStart=E();onInteractionEnd=E();onNodeActive=E();onNodeLosesActive=E();constructor(...e){super(...e),this.parse=this.options.parser??(e=>e),this.DM=this.container.get(D),this.SM=this.container.get(O),this.container.get(k).onRefresh.subscribe(this.updateOverlays),this.SM.onChangeTheme.subscribe(this.themeChanged),this._overlaysLayer=document.createElement(`div`),this._overlaysLayer.className=`JCV-overlays`,this._overlaysLayer.id=`overlays`,this.DM.data.container.appendChild(this.overlaysLayer);let t=this.options.nodeComponents;t&&Object.assign(this.componentDict,t),this.augment({onNodeActive:this.onNodeActive,onNodeLosesActive:this.onNodeLosesActive}),this.onStart(this.start),this.onRestart(this.restart),this.onDispose(this.dispose)}start=()=>{this.container.get(N).onClick.subscribe(this.select),this.renderOverlays()};restart=()=>{this.clearOverlays(),this.renderOverlays()};renderOverlays=()=>{let e=async e=>{switch(e.type){case`text`:this.createOverlay(e,await this.parse(e.text),`text`);break;case`file`:for(let t of j)if(e.file.match(A[t])){this.createOverlay(e,e.file,t);break}break;case`link`:this.createOverlay(e,e.url,`link`);break}};Object.values(this.DM.data.nodeMap).forEach(async t=>{await e(t.ref)})};themeChanged=()=>{Object.values(this.overlays).forEach(e=>{let t=this.DM.data.nodeMap[e.id].ref,n=this.SM.getColor(t.color);this.setOverlayColor(e,n)})};select=e=>{let t=this.selectedId,n=t?this.overlays[t]:void 0,r=e?this.overlays[e]:void 0;if(n&&t){n.classList.remove(`JCV-active`);let e=this.DM.data.nodeMap[t];this.onNodeLosesActive(e.ref),e.onLoseActive?.()}if(r&&e){r.classList.add(`JCV-active`),this.onInteractionStart();let t=this.DM.data.nodeMap[e];this.onNodeActive(t.ref),t.onActive?.()}else this.onInteractionEnd();this.selectedId=e};updateOverlays=()=>{let e=this.DM.data;this.overlaysLayer.style.transform=`translate(${e.offsetX}px, ${e.offsetY}px) scale(${e.scale})`};createOverlay=(...e)=>{if(this.aborted)return;let t=e[0],n=this.overlays[t.id];if(!n){if(n=this.constructOverlay(...e),this.aborted)return;this.overlaysLayer.appendChild(n),this.overlays[t.id]=n,n.style.left=`${t.x}px`,n.style.top=`${t.y}px`,n.style.width=`${t.width}px`,n.style.height=`${t.height}px`}};constructOverlay=(...e)=>{let t=e[0],n=document.createElement(`div`);n.classList.add(`JCV-overlay-container`),n.id=t.id,this.setOverlayColor(n,this.SM.getColor(t.color));let r=document.createElement(`div`);r.classList.add(`JCV-content`),n.appendChild(r);let i=document.createElement(`div`);i.className=`JCV-click-layer`,n.appendChild(i);let a=document.createElement(`div`);a.className=`JCV-overlay-border`,n.appendChild(a);let o=this.DM.data.nodeMap[t.id];o.onActive=E(),o.onLoseActive=E(),o.onBeforeUnmount=E(),this.componentDict[e[2]]({container:r,content:e[1],node:e[0],onActive:o.onActive,onBeforeUnmount:o.onBeforeUnmount,onLoseActive:o.onLoseActive});let s=()=>{t.id===this.selectedId&&this.onInteractionStart()},c=()=>{t.id===this.selectedId&&this.onInteractionEnd()};return n.addEventListener(`pointerenter`,s),n.addEventListener(`pointerleave`,c),n.addEventListener(`touchstart`,s),n.addEventListener(`touchend`,c),this.eventListeners[t.id]=[s,c],n};setOverlayColor=(e,t)=>{Object.entries(t).forEach(([t,n])=>{e.style.setProperty(`--overlay-${t}`,n)})};clearOverlays=()=>{Object.entries(this.overlays).forEach(([e,t])=>{if(this.DM.data.nodeMap[e].onBeforeUnmount?.(),this.eventListeners[e]){let n=this.eventListeners[e][0],r=this.eventListeners[e][1];if(!n||!r)throw b;t.removeEventListener(`pointerenter`,n),t.removeEventListener(`pointerleave`,r),t.removeEventListener(`touchstart`,n),t.removeEventListener(`touchend`,r),this.eventListeners[e][0]=void 0,this.eventListeners[e][1]=void 0}t.remove(),delete this.overlays[e]})};dispose=()=>{this.aborted=!0,this.clearOverlays(),this.overlaysLayer.remove(),this._overlaysLayer=void 0}},N=class extends v{pointeract;DM;onClick=E();constructor(...e){super(...e),this.DM=this.container.get(D);let t=Object.assign(this.options.pointeract??{},{coordinateOutput:`relative`,element:this.DM.data.container,lubricator:{drag:f,pan:p,zoom:m}});this.pointeract=new l(t,[a,o,d,u,c,s]);let n=this.container.get(M);n.onInteractionStart.subscribe(this.stopInteract),n.onInteractionEnd.subscribe(this.startInteract),this.augment({pan:this.pan,panToCoords:this.panToCoords,zoom:this.zoom,zoomToScale:this.zoomToScale}),this.onStart(this.start),this.onDispose(this.dispose)}start=()=>{this.pointeract.on(`pan`,this.onPan).on(`drag`,this.onPan).on(`zoom`,this.onZoom).on(`trueClick`,this.onTrueClick).start()};startInteract=()=>{this.pointeract.start()};stopInteract=()=>{this.pointeract.stop()};onPan=e=>{this.truePan({x:e.deltaX,y:e.deltaY})};onZoom=e=>{this.trueZoom(e.factor,e)};trueZoom=(e,t)=>{let n=Math.max(Math.min(this.DM.data.scale*e,20),.05);if(n===this.DM.data.scale)return;let r=n/this.DM.data.scale,i=this.C2C(t);this.DM.data.offsetX=t.x-i.x*r,this.DM.data.offsetY=t.y-i.y*r,this.DM.data.scale=n};truePan=({x:e,y:t})=>{this.DM.data.offsetX+=e,this.DM.data.offsetY+=t};zoom=(e,t)=>{this.pointeract.dispatch(`zoom`,{factor:e,...t})};pan=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e,deltaY:t})};zoomToScale=(e,t)=>{let n=e/this.DM.data.scale;this.pointeract.dispatch(`zoom`,{factor:n,...t})};panToCoords=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e-this.DM.data.offsetX,deltaY:t-this.DM.data.offsetY})};C2C=({x:e,y:t})=>({x:e-this.DM.data.offsetX,y:t-this.DM.data.offsetY});onTrueClick=e=>{let t=e.target?e.target:void 0;if(this.isUIControl(t))return;let n=this.findNodeId(t);this.onClick(n)};isUIControl=e=>e?e.closest(`.controls`)||e.closest(`button`)||e.closest(`input`):!1;findNodeId=e=>{if(!e)return;let t=e;for(;(!t.id||t.id===``)&&t.parentElement;)t=t.parentElement;if(!(t.id===`overlays`||!t.id||t.id===``))return t.id};dispose=()=>this.pointeract.dispose()},P=`.JSON-Canvas-Viewer > .JCV-controls {
285
285
  position: absolute;
286
286
  top: 10px;
287
287
  right: 10px;
@@ -392,5 +392,5 @@ pre .JSON-Canvas-Viewer .JCV-markdown-content code {
392
392
  line-height: calc(17px + 0.3vw);
393
393
  text-align: center;
394
394
  }
395
- `,H=class extends v{_preventionContainer;preventMt=!1;DM;preventMistouch={initialX:0,initialY:0,lastX:0,lastY:0,record:!1};get preventionContainer(){if(!this._preventionContainer)throw b;return this._preventionContainer}constructor(...e){super(...e);let t=document.createElement(`div`);t.className=`JCV-prevention-banner JCV-border-shadow-bg`,t.textContent=this.options.mistouchPreventerBannerText??`Click on to unlock.`,this.DM=this.container.get(D),this._preventionContainer=document.createElement(`div`),this._preventionContainer.className=`JCV-prevention-container JCV-hidden JCV-full JCV-flex-center`,x(this._preventionContainer,V),this._preventionContainer.appendChild(t),this.DM.data.container.appendChild(this._preventionContainer),this.options.preventMistouchAtStart&&this.startPrevention(),window.addEventListener(`pointerdown`,this.onPointerDown),window.addEventListener(`pointermove`,this.onPointerMove),window.addEventListener(`pointerup`,this.onPointerUp),this.augment({endMistouchPrevention:this.endPrevention,startMistouchPrevention:this.startPrevention}),this.onDispose(this.dispose)}onPointerDown=e=>{let t=this.DM.data.container.getBoundingClientRect();e.clientX<t.left||e.clientX>t.right||e.clientY<t.top||e.clientY>t.bottom?this.preventMt||this.startPrevention():this.preventMt&&(this.preventMistouch.initialX=e.clientX,this.preventMistouch.initialY=e.clientY,this.preventMistouch.lastX=e.clientX,this.preventMistouch.lastY=e.clientY,this.preventMistouch.record=!0)};onPointerMove=e=>{this.preventMistouch.record&&(this.preventMistouch.lastX=e.clientX,this.preventMistouch.lastY=e.clientY)};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())};startPrevention=()=>{this.preventionContainer.classList.remove(`JCV-hidden`),this.DM.data.container.classList.add(`JCV-numb`),this.preventMt=!0};endPrevention=()=>{this.preventMt=!1,this.preventionContainer.classList.add(`JCV-hidden`),setTimeout(()=>this.DM.data.container.classList.remove(`JCV-numb`),50)};dispose=()=>{window.removeEventListener(`pointerdown`,this.onPointerDown),window.removeEventListener(`pointermove`,this.onPointerMove),window.removeEventListener(`pointerup`,this.onPointerUp),this.preventionContainer.remove(),this._preventionContainer=void 0}};const U=[D,O,k,M,N,class extends v{_canvas;ctx;DM;SM;zoomInOptimize={lastCallTime:0,lastDrawnScale:0,lastDrawnViewport:{bottom:0,left:0,right:0,top:0},timeout:void 0};get canvas(){if(!this._canvas)throw b;return this._canvas}constructor(...e){super(...e);let t=this.container.get(k);this.SM=this.container.get(O),t.onRefresh.subscribe(this.redraw),t.onResize.subscribe(this.optimizeDPR),this.DM=this.container.get(D),this._canvas=document.createElement(`canvas`),this._canvas.className=`JCV-main-canvas`,this.ctx=this._canvas.getContext(`2d`),this.DM.data.container.appendChild(this._canvas),this.onDispose(this.dispose)}optimizeDPR=()=>{let e=this.DM.data.container;w(this.canvas,e.offsetWidth,e.offsetHeight)};redraw=()=>{let e=this.DM.data.offsetX,t=this.DM.data.offsetY,n=this.DM.data.scale,r=this.getCurrentViewport(e,t,n);if(!this.options.zoomInOptimization){this.trueRedraw(e,t,n,r);return}this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=void 0);let i=Date.now();if(this.isInside(r,this.zoomInOptimize.lastDrawnViewport)&&n!==this.zoomInOptimize.lastDrawnScale&&i-this.zoomInOptimize.lastCallTime<500){this.zoomInOptimize.timeout=window.setTimeout(()=>{this.trueRedraw(e,t,n,r),this.zoomInOptimize.lastCallTime=i,this.zoomInOptimize.timeout=void 0},60),this.fakeRedraw(r,n);return}this.zoomInOptimize.lastCallTime=i,this.trueRedraw(e,t,n,r)};trueRedraw(e,t,n,r){this.zoomInOptimize.lastDrawnViewport=r,this.zoomInOptimize.lastDrawnScale=n,this.canvas.style.transform=``,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.save(),this.drawGridDots(n,e,t),this.ctx.translate(e,t),this.ctx.scale(n,n),Object.values(this.DM.data.nodeMap).forEach(e=>{if(this.isOutside(e.box,r))return;let t=e.ref;t.type===`file`?this.drawFile(e):t.type===`group`&&this.drawGroup(t,n)}),Object.values(this.DM.data.edgeMap).forEach(e=>{this.isOutside(e.box,r)||this.drawEdge(e)}),this.ctx.restore()}fakeRedraw(e,t){let n=t/this.zoomInOptimize.lastDrawnScale,r=(this.zoomInOptimize.lastDrawnViewport.left-e.left)*t,i=(this.zoomInOptimize.lastDrawnViewport.top-e.top)*t;this.canvas.style.transform=`translate(${r}px, ${i}px) scale(${n})`}isInside=(e,t)=>e.left>t.left&&e.top>t.top&&e.right<t.right&&e.bottom<t.bottom;isOutside=(e,t)=>e.right<t.left||e.bottom<t.top||e.left>t.right||e.top>t.bottom;getCurrentViewport=(e,t,n)=>{let r=-e/n,i=-t/n,a=this.DM.data.container,o=r+a.clientWidth/n;return{bottom:i+a.clientHeight/n,left:r,right:o,top:i}};drawLabelBar=(e,t,n,r,i,a)=>{let o=30*a,s=6*a,c=8*a,l=16*a,u=6*a;this.ctx.save(),this.ctx.translate(e,t),this.ctx.scale(1/a,1/a),this.ctx.font=`${l}px 'Inter', sans-serif`;let d=this.ctx.measureText(n).width+2*u;this.ctx.translate(0,-o-c),this.ctx.fillStyle=r,this.ctx.beginPath(),this.ctx.moveTo(s,0),this.ctx.lineTo(d-s,0),this.ctx.quadraticCurveTo(d,0,d,s),this.ctx.lineTo(d,o-s),this.ctx.quadraticCurveTo(d,o,d-s,o),this.ctx.lineTo(s,o),this.ctx.quadraticCurveTo(0,o,0,o-s),this.ctx.lineTo(0,s),this.ctx.quadraticCurveTo(0,0,s,0),this.ctx.closePath(),this.ctx.fill(),this.ctx.fillStyle=i,this.ctx.fillText(n,u,o*.65),this.ctx.restore()};drawNodeBackground=e=>{let t=this.SM.getColor(e.color);this.ctx.globalAlpha=1,this.ctx.fillStyle=t.background,S(this.ctx,e.x+1,e.y+1,e.width-2,e.height-2,12),this.ctx.fill(),this.ctx.strokeStyle=t.border,this.ctx.lineWidth=2,S(this.ctx,e.x,e.y,e.width,e.height,12),this.ctx.stroke()};drawGroup=(e,t)=>{if(this.drawNodeBackground(e),e.label){let n=this.SM.getColor(e.color);this.drawLabelBar(e.x,e.y,e.label,n.active,n.text,t)}};drawFile=e=>{this.ctx.fillStyle=this.SM.getColor().text;let t=e.ref;this.ctx.font=`16px sans-serif`,this.ctx.fillText(e.fileName??``,t.x+5,t.y-10)};drawEdge=e=>{let t=e.ref,n=this.DM.data.nodeMap[t.fromNode].ref,r=this.DM.data.nodeMap[t.toNode].ref,{x:i,y:a}=C(n,t.fromSide),{x:o,y:s}=C(r,t.toSide),c=this.SM.getColor(t.color),l,u,d,f;e.controlPoints?[l,u,d,f]=e.controlPoints:([l,u,d,f]=this.getControlPoints(i,a,o,s,t.fromSide,t.toSide),e.controlPoints=[l,u,d,f]),this.drawCurvedPath(i,a,o,s,l,u,d,f,c.active),this.drawArrowhead(o,s,d,f,c.active),t.label&&this.drawEdgeLabel(i,a,o,s,l,u,d,f,t.label,c.active,c.text)};drawEdgeLabel=(e,t,n,r,i,a,o,s,c,l,u)=>{let d=.5,f=(1-d)**3*e+3*(1-d)**2*d*i+3*(1-d)*d*d*o+d**3*n,p=(1-d)**3*t+3*(1-d)**2*d*a+3*(1-d)*d*d*s+d**3*r;this.ctx.font=`18px sans-serif`;let m=c.split(`
395
+ `,H=class extends v{_preventionContainer;preventMt=!1;DM;preventMistouch={initialX:0,initialY:0,lastX:0,lastY:0,record:!1};get preventionContainer(){if(!this._preventionContainer)throw b;return this._preventionContainer}constructor(...e){super(...e);let t=document.createElement(`div`);t.className=`JCV-prevention-banner JCV-border-shadow-bg`,t.textContent=this.options.mistouchPreventerBannerText??`Click on to unlock.`,this.DM=this.container.get(D),this._preventionContainer=document.createElement(`div`),this._preventionContainer.className=`JCV-prevention-container JCV-hidden JCV-full JCV-flex-center`,x(this._preventionContainer,V),this._preventionContainer.appendChild(t),this.DM.data.container.appendChild(this._preventionContainer),this.options.preventMistouchAtStart&&this.startPrevention(),window.addEventListener(`pointerdown`,this.onPointerDown),window.addEventListener(`pointermove`,this.onPointerMove),window.addEventListener(`pointerup`,this.onPointerUp),this.augment({endMistouchPrevention:this.endPrevention,startMistouchPrevention:this.startPrevention}),this.onDispose(this.dispose)}onPointerDown=e=>{let t=this.DM.data.container.getBoundingClientRect();e.clientX<t.left||e.clientX>t.right||e.clientY<t.top||e.clientY>t.bottom?this.preventMt||this.startPrevention():this.preventMt&&(this.preventMistouch.initialX=e.clientX,this.preventMistouch.initialY=e.clientY,this.preventMistouch.lastX=e.clientX,this.preventMistouch.lastY=e.clientY,this.preventMistouch.record=!0)};onPointerMove=e=>{this.preventMistouch.record&&(this.preventMistouch.lastX=e.clientX,this.preventMistouch.lastY=e.clientY)};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())};startPrevention=()=>{this.preventionContainer.classList.remove(`JCV-hidden`),this.DM.data.container.classList.add(`JCV-numb`),this.preventMt=!0};endPrevention=()=>{this.preventMt=!1,this.preventionContainer.classList.add(`JCV-hidden`),setTimeout(()=>this.DM.data.container.classList.remove(`JCV-numb`),50)};dispose=()=>{window.removeEventListener(`pointerdown`,this.onPointerDown),window.removeEventListener(`pointermove`,this.onPointerMove),window.removeEventListener(`pointerup`,this.onPointerUp),this.preventionContainer.remove(),this._preventionContainer=void 0}};const U=[D,O,k,M,N,class extends v{_canvas;ctx;DM;SM;zoomInOptimize={lastCallTime:0,lastDrawnScale:0,lastDrawnViewport:{bottom:0,left:0,right:0,top:0}};get canvas(){if(!this._canvas)throw b;return this._canvas}constructor(...e){super(...e);let t=this.container.get(k);this.SM=this.container.get(O),t.onRefresh.subscribe(this.redraw),t.onResize.subscribe(this.optimizeDPR),this.DM=this.container.get(D),this._canvas=document.createElement(`canvas`),this._canvas.className=`JCV-main-canvas`,this.ctx=this._canvas.getContext(`2d`),this.DM.data.container.appendChild(this._canvas),this.onDispose(this.dispose)}optimizeDPR=()=>{let e=this.DM.data.container;w(this.canvas,e.offsetWidth,e.offsetHeight)};redraw=()=>{let e=this.DM.data.offsetX,t=this.DM.data.offsetY,n=this.DM.data.scale,r=this.getCurrentViewport(e,t,n);if(!this.options.zoomInOptimization){this.trueRedraw(e,t,n,r);return}this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=void 0);let i=Date.now();if(this.isInside(r,this.zoomInOptimize.lastDrawnViewport)&&n!==this.zoomInOptimize.lastDrawnScale&&i-this.zoomInOptimize.lastCallTime<500){this.zoomInOptimize.timeout=window.setTimeout(()=>{this.trueRedraw(e,t,n,r),this.zoomInOptimize.lastCallTime=i,this.zoomInOptimize.timeout=void 0},60),this.fakeRedraw(r,n);return}this.zoomInOptimize.lastCallTime=i,this.trueRedraw(e,t,n,r)};trueRedraw(e,t,n,r){this.zoomInOptimize.lastDrawnViewport=r,this.zoomInOptimize.lastDrawnScale=n,this.canvas.style.transform=``,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.save(),this.drawGridDots(n,e,t),this.ctx.translate(e,t),this.ctx.scale(n,n),Object.values(this.DM.data.nodeMap).forEach(e=>{if(this.isOutside(e.box,r))return;let t=e.ref;t.type===`file`?this.drawFile(e):t.type===`group`&&this.drawGroup(t,n)}),Object.values(this.DM.data.edgeMap).forEach(e=>{this.isOutside(e.box,r)||this.drawEdge(e)}),this.ctx.restore()}fakeRedraw(e,t){let n=t/this.zoomInOptimize.lastDrawnScale,r=(this.zoomInOptimize.lastDrawnViewport.left-e.left)*t,i=(this.zoomInOptimize.lastDrawnViewport.top-e.top)*t;this.canvas.style.transform=`translate(${r}px, ${i}px) scale(${n})`}isInside=(e,t)=>e.left>t.left&&e.top>t.top&&e.right<t.right&&e.bottom<t.bottom;isOutside=(e,t)=>e.right<t.left||e.bottom<t.top||e.left>t.right||e.top>t.bottom;getCurrentViewport=(e,t,n)=>{let r=-e/n,i=-t/n,a=this.DM.data.container,o=r+a.clientWidth/n;return{bottom:i+a.clientHeight/n,left:r,right:o,top:i}};drawLabelBar=(e,t,n,r,i,a)=>{let o=30*a,s=6*a,c=8*a,l=16*a,u=6*a;this.ctx.save(),this.ctx.translate(e,t),this.ctx.scale(1/a,1/a),this.ctx.font=`${l}px 'Inter', sans-serif`;let d=this.ctx.measureText(n).width+2*u;this.ctx.translate(0,-o-c),this.ctx.fillStyle=r,this.ctx.beginPath(),this.ctx.moveTo(s,0),this.ctx.lineTo(d-s,0),this.ctx.quadraticCurveTo(d,0,d,s),this.ctx.lineTo(d,o-s),this.ctx.quadraticCurveTo(d,o,d-s,o),this.ctx.lineTo(s,o),this.ctx.quadraticCurveTo(0,o,0,o-s),this.ctx.lineTo(0,s),this.ctx.quadraticCurveTo(0,0,s,0),this.ctx.closePath(),this.ctx.fill(),this.ctx.fillStyle=i,this.ctx.fillText(n,u,o*.65),this.ctx.restore()};drawNodeBackground=e=>{let t=this.SM.getColor(e.color);this.ctx.globalAlpha=1,this.ctx.fillStyle=t.background,S(this.ctx,e.x+1,e.y+1,e.width-2,e.height-2,12),this.ctx.fill(),this.ctx.strokeStyle=t.border,this.ctx.lineWidth=2,S(this.ctx,e.x,e.y,e.width,e.height,12),this.ctx.stroke()};drawGroup=(e,t)=>{if(this.drawNodeBackground(e),e.label){let n=this.SM.getColor(e.color);this.drawLabelBar(e.x,e.y,e.label,n.active,n.text,t)}};drawFile=e=>{this.ctx.fillStyle=this.SM.getColor().text;let t=e.ref;this.ctx.font=`16px sans-serif`,this.ctx.fillText(e.fileName??``,t.x+5,t.y-10)};drawEdge=e=>{let t=e.ref,n=this.DM.data.nodeMap[t.fromNode].ref,r=this.DM.data.nodeMap[t.toNode].ref,{x:i,y:a}=C(n,t.fromSide),{x:o,y:s}=C(r,t.toSide),c=this.SM.getColor(t.color),l,u,d,f;e.controlPoints?[l,u,d,f]=e.controlPoints:([l,u,d,f]=this.getControlPoints(i,a,o,s,t.fromSide,t.toSide),e.controlPoints=[l,u,d,f]),this.drawCurvedPath(i,a,o,s,l,u,d,f,c.active),this.drawArrowhead(o,s,d,f,c.active),t.label&&this.drawEdgeLabel(i,a,o,s,l,u,d,f,t.label,c.active,c.text)};drawEdgeLabel=(e,t,n,r,i,a,o,s,c,l,u)=>{let d=.5,f=(1-d)**3*e+3*(1-d)**2*d*i+3*(1-d)*d*d*o+d**3*n,p=(1-d)**3*t+3*(1-d)**2*d*a+3*(1-d)*d*d*s+d**3*r;this.ctx.font=`18px sans-serif`;let m=c.split(`
396
396
  `),h=0;for(let e of m){let t=this.ctx.measureText(e).width;t>h&&(h=t)}let g=h+16,_=m.length*17+6;this.ctx.fillStyle=l,this.ctx.beginPath(),S(this.ctx,f-g/2,p-_/2-2,g,_,4),this.ctx.fill(),this.ctx.fillStyle=u,this.ctx.textAlign=`center`,this.ctx.textBaseline=`middle`;for(let e=0;e<m.length;e++){let t=(e-(m.length-1)/2)*17;this.ctx.fillText(m[e],f,p-2+t)}this.ctx.textAlign=`left`,this.ctx.textBaseline=`alphabetic`};getControlPoints=(e,t,n,r,i,a)=>{let o=n-e,s=r-t,c=((e,t,n)=>Math.max(t,Math.min(n,e)))((Math.min(Math.abs(o),Math.abs(s))+.3*Math.max(Math.abs(o),Math.abs(s)))*.5,60,300),l=e,u=t,d=n,f=r;switch(i){case`top`:u=t-c;break;case`bottom`:u=t+c;break;case`left`:l=e-c;break;case`right`:l=e+c;break}switch(a){case`top`:f=r-c;break;case`bottom`:f=r+c;break;case`left`:d=n-c;break;case`right`:d=n+c;break}return[l,u,d,f]};drawGridDots=(e,t,n)=>{let r=10*2**-Math.floor(Math.log2(e))*e,i=this.canvas.width,a=this.canvas.height,o=t%r,s=n%r;this.ctx.fillStyle=this.SM.getNamedColor(`dots`);for(let e=o;e<=i;e+=r)for(let t=s;t<=a;t+=r)this.ctx.beginPath(),this.ctx.arc(e,t,1,0,2*Math.PI),this.ctx.fill()};drawCurvedPath=(e,t,n,r,i,a,o,s,c)=>{this.ctx.beginPath(),this.ctx.moveTo(e,t),this.ctx.bezierCurveTo(i,a,o,s,n,r),this.ctx.strokeStyle=c,this.ctx.lineWidth=2,this.ctx.stroke()};drawArrowhead=(e,t,n,r,i)=>{let a=e-n,o=t-r,s=Math.sqrt(a*a+o*o);if(s===0)return;let c=a/s,l=o/s,u=e-c*12-l*4,d=t-l*12+c*4,f=e-c*12+l*4,p=t-l*12-c*4;this.ctx.beginPath(),this.ctx.fillStyle=i,this.ctx.moveTo(e,t),this.ctx.lineTo(u,d),this.ctx.lineTo(f,p),this.ctx.closePath(),this.ctx.fill()};dispose=()=>{this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=void 0),this.canvas.remove(),this._canvas=void 0}}];var W=class{allModules;IO;started=!1;disposed=!1;options;container;onDispose=E(!0);onStart=E();onRestart=E();constructor(e,t){this.container=new h,this.options=e;let n=e=>{this.container.bind({provide:e,useFactory:()=>new e(this.container,this.options,this.onStart,this.onDispose,this.onRestart,this.augment)})};this.allModules=[...U,...t??[]],this.allModules.forEach(n),this.allModules.forEach(e=>{this.container.get(e)});let r=this.options.loading??`normal`;r===`normal`?this.load():r===`lazy`&&(this.IO=new IntersectionObserver(this.onVisibilityCheck,{rootMargin:`50px`,threshold:0}),this.IO.observe(this.options.container))}onVisibilityCheck=e=>{e.forEach(e=>{if(e.isIntersecting){this.load(),this.IO?.disconnect(),this.IO=void 0;return}})};augment=e=>{let t=Object.getOwnPropertyDescriptors(e);Object.defineProperties(this,t)};load=e=>{this.disposed||(e&&Object.assign(this.options,e),this.started?this.onRestart():(this.onStart(),this.started=!0))};dispose=()=>{if(!this.started||this.disposed)return;this.IO?.disconnect(),this.IO=void 0;let e=this.options.container;for(;e.firstChild;)e.firstChild.remove();this.onDispose(),this.container.unbindAll(),this.disposed=!0}};async function G(e){return g.sanitize(await _(e))}async function K(e){return await fetch(e).then(e=>e.json())}export{I as Controls,R as DebugPanel,W as JSONCanvasViewer,B as Minimap,H as MistouchPreventer,K as fetchCanvas,G as parser};
@@ -1 +1 @@
1
- {"version":3,"file":"BaseModule.js","names":[],"sources":["../../src/kernel/BaseModule.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { General, GeneralObject, ModuleInput as MI, Orchestratable } from '$/types';\nimport type { Hook } from '$/utilities';\nimport type { Container } from '@needle-di/core';\n\nexport type GeneralModuleCtor = typeof BaseModule<General, General>;\nexport type GeneralModule = BaseModule<General, General>;\n\nexport type ModuleInputCtor = Array<GeneralModuleCtor>;\nexport type ModuleInput = MI<GeneralModuleCtor>;\nexport type Options<M extends ModuleInput> = Orchestratable<M, 'options'>;\nexport type Augmentation<M extends ModuleInput> = Orchestratable<M, '_Augmentation'>;\n\nexport type BaseArgs = ConstructorParameters<GeneralModuleCtor>;\n\nexport class BaseModule<O extends BaseOptions = BaseOptions, A extends GeneralObject = {}> {\n\t// https://github.com/timocov/dts-bundle-generator/issues/360\n\tdeclare private static readonly _BaseModuleBrand: unique symbol; // Nominal marker\n\tdeclare _Augmentation: A;\n\tonStart: Hook['subscribe'];\n\tonRestart: Hook['subscribe'];\n\tonDispose: Hook['subscribe'];\n\t// oxlint-disable-next-line max-params\n\tconstructor(\n\t\tprotected container: Container,\n\t\toptions: GeneralObject,\n\t\tonStart: Hook,\n\t\tonDispose: Hook,\n\t\tonRestart: Hook,\n\t\tprotected augment: (aug: A) => void,\n\t) {\n\t\tthis.options = options as O;\n\t\tthis.onStart = onStart.subscribe;\n\t\tthis.onDispose = onDispose.subscribe;\n\t\tthis.onRestart = onRestart.subscribe;\n\t}\n\toptions: O;\n}\n"],"mappings":"AAeA,IAAa,EAAb,KAA2F,CAI1F,QACA,UACA,UAEA,YACC,EACA,EACA,EACA,EACA,EACA,EACC,CANS,KAAA,UAAA,EAKA,KAAA,QAAA,EAEV,KAAK,QAAU,EACf,KAAK,QAAU,EAAQ,UACvB,KAAK,UAAY,EAAU,UAC3B,KAAK,UAAY,EAAU,UAE5B"}
1
+ {"version":3,"file":"BaseModule.js","names":[],"sources":["../../src/kernel/BaseModule.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { General, GeneralObject, ModuleInput as MI, Orchestratable } from '$/types';\nimport type { Hook } from '$/utilities';\nimport type { Container } from '@needle-di/core';\n\nexport type GeneralModuleCtor = typeof BaseModule<General, General>;\nexport type GeneralModule = BaseModule<General, General>;\n\nexport type ModuleInputCtor = Array<GeneralModuleCtor>;\nexport type ModuleInput = MI<GeneralModuleCtor>;\nexport type Options<M extends ModuleInput> = Orchestratable<M, 'options'>;\nexport type Augmentation<M extends ModuleInput> = Orchestratable<M, '_Augmentation'>;\n\nexport type BaseArgs = ConstructorParameters<GeneralModuleCtor>;\n\nexport class BaseModule<O extends BaseOptions = BaseOptions, A extends GeneralObject = {}> {\n\tdeclare private static readonly _BaseModuleBrand: unique symbol; // Nominal marker\n\tdeclare _Augmentation: A;\n\tonStart: Hook['subscribe'];\n\tonRestart: Hook['subscribe'];\n\tonDispose: Hook['subscribe'];\n\n\tconstructor(\n\t\tprotected container: Container,\n\t\toptions: GeneralObject,\n\t\tonStart: Hook,\n\t\tonDispose: Hook,\n\t\tonRestart: Hook,\n\t\tprotected augment: (aug: A) => void,\n\t) {\n\t\tthis.options = options as O;\n\t\tthis.onStart = onStart.subscribe;\n\t\tthis.onDispose = onDispose.subscribe;\n\t\tthis.onRestart = onRestart.subscribe;\n\t}\n\toptions: O;\n}\n"],"mappings":"AAeA,IAAa,EAAb,KAA2F,CAG1F,QACA,UACA,UAEA,YACC,EACA,EACA,EACA,EACA,EACA,EACC,CANS,KAAA,UAAA,EAKA,KAAA,QAAA,EAEV,KAAK,QAAU,EACf,KAAK,QAAU,EAAQ,UACvB,KAAK,UAAY,EAAU,UAC3B,KAAK,UAAY,EAAU,UAE5B"}
@@ -9,8 +9,8 @@ type Augmentation = {
9
9
  onResize: Controller['onResize'];
10
10
  };
11
11
  declare class Controller extends BaseModule<BaseOptions, Augmentation> {
12
- private animationId;
13
- private resizeAnimationId;
12
+ private animationId?;
13
+ private resizeAnimationId?;
14
14
  private readonly DM;
15
15
  private readonly SM;
16
16
  private readonly resizeObserver;
@@ -1,2 +1,2 @@
1
- import{BaseModule as e}from"./BaseModule.js";import{makeHook as t}from"./utilities.js";import n from"./DataManager.js";import r from"./StyleManager.js";var i=class extends e{animationId;resizeAnimationId;DM;SM;resizeObserver;perFrame={lastOffsets:{x:0,y:0},lastScale:1};lastResizeCenter={x:void 0,y:void 0};onResize=t();onRefresh=t();constructor(...e){super(...e),this.DM=this.container.get(n),this.SM=this.container.get(r),this.resizeObserver=new ResizeObserver(this.onResizeCallback),this.SM.onChangeTheme.subscribe(this.refresh),this.augment({onRefresh:this.onRefresh,onResize:this.onResize,refresh:this.refresh}),this.onStart(this.start),this.onRestart(this.refresh),this.onDispose(this.dispose)}start=()=>{this.resizeObserver.observe(this.DM.data.container),this.animationId=requestAnimationFrame(this.draw)};draw=()=>{(this.perFrame.lastScale!==this.DM.data.scale||this.perFrame.lastOffsets.x!==this.DM.data.offsetX||this.perFrame.lastOffsets.y!==this.DM.data.offsetY)&&this.refresh(),this.animationId=requestAnimationFrame(this.draw)};refresh=()=>{this.perFrame={lastOffsets:{x:this.DM.data.offsetX,y:this.DM.data.offsetY},lastScale:this.DM.data.scale},this.onRefresh()};onResizeCallback=()=>{this.resizeAnimationId=requestAnimationFrame(()=>{let e=this.DM.middleViewer();this.lastResizeCenter.x&&this.lastResizeCenter.y&&(this.DM.data.offsetX=this.DM.data.offsetX+e.x-this.lastResizeCenter.x,this.DM.data.offsetY=this.DM.data.offsetY+e.y-this.lastResizeCenter.y),this.lastResizeCenter.x=e.x,this.lastResizeCenter.y=e.y,this.onResize(e.width,e.height),this.refresh()})};dispose=()=>{this.animationId&&cancelAnimationFrame(this.animationId),this.resizeAnimationId&&cancelAnimationFrame(this.resizeAnimationId),this.resizeObserver.disconnect()}};export{i as default};
1
+ import{BaseModule as e}from"./BaseModule.js";import{makeHook as t}from"./utilities.js";import n from"./DataManager.js";import r from"./StyleManager.js";var i=class extends e{animationId;resizeAnimationId;DM;SM;resizeObserver;perFrame={lastOffsets:{x:0,y:0},lastScale:1};lastResizeCenter={};onResize=t();onRefresh=t();constructor(...e){super(...e),this.DM=this.container.get(n),this.SM=this.container.get(r),this.resizeObserver=new ResizeObserver(this.onResizeCallback),this.SM.onChangeTheme.subscribe(this.refresh),this.augment({onRefresh:this.onRefresh,onResize:this.onResize,refresh:this.refresh}),this.onStart(this.start),this.onRestart(this.refresh),this.onDispose(this.dispose)}start=()=>{this.resizeObserver.observe(this.DM.data.container),this.animationId=requestAnimationFrame(this.draw)};draw=()=>{(this.perFrame.lastScale!==this.DM.data.scale||this.perFrame.lastOffsets.x!==this.DM.data.offsetX||this.perFrame.lastOffsets.y!==this.DM.data.offsetY)&&this.refresh(),this.animationId=requestAnimationFrame(this.draw)};refresh=()=>{this.perFrame={lastOffsets:{x:this.DM.data.offsetX,y:this.DM.data.offsetY},lastScale:this.DM.data.scale},this.onRefresh()};onResizeCallback=()=>{this.resizeAnimationId=requestAnimationFrame(()=>{let e=this.DM.middleViewer();this.lastResizeCenter.x&&this.lastResizeCenter.y&&(this.DM.data.offsetX=this.DM.data.offsetX+e.x-this.lastResizeCenter.x,this.DM.data.offsetY=this.DM.data.offsetY+e.y-this.lastResizeCenter.y),this.lastResizeCenter.x=e.x,this.lastResizeCenter.y=e.y,this.onResize(e.width,e.height),this.refresh()})};dispose=()=>{this.animationId&&cancelAnimationFrame(this.animationId),this.resizeAnimationId&&cancelAnimationFrame(this.resizeAnimationId),this.resizeObserver.disconnect()}};export{i as default};
2
2
  //# sourceMappingURL=Controller.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Controller.js","names":[],"sources":["../../src/kernel/Controller.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport { BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport StyleManager from '$/StyleManager';\nimport { makeHook } from '$/utilities';\n\ntype Augmentation = {\n\trefresh: Controller['refresh'];\n\tonRefresh: Controller['onRefresh'];\n\tonResize: Controller['onResize'];\n};\n\nexport default class Controller extends BaseModule<BaseOptions, Augmentation> {\n\tprivate animationId: undefined | number;\n\tprivate resizeAnimationId: undefined | number;\n\tprivate readonly DM: DataManager;\n\tprivate readonly SM: StyleManager;\n\tprivate readonly resizeObserver: ResizeObserver;\n\tprivate perFrame: {\n\t\tlastScale: number;\n\t\tlastOffsets: { x: number; y: number };\n\t} = {\n\t\tlastOffsets: { x: 0, y: 0 },\n\t\tlastScale: 1,\n\t};\n\tprivate readonly lastResizeCenter: {\n\t\tx: undefined | number;\n\t\ty: undefined | number;\n\t} = {\n\t\tx: undefined,\n\t\ty: undefined,\n\t};\n\n\tonResize = makeHook<[number, number]>();\n\tonRefresh = makeHook();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tthis.resizeObserver = new ResizeObserver(this.onResizeCallback);\n\t\tthis.SM.onChangeTheme.subscribe(this.refresh);\n\t\tthis.augment({\n\t\t\tonRefresh: this.onRefresh,\n\t\t\tonResize: this.onResize,\n\t\t\trefresh: this.refresh,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.refresh);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tthis.resizeObserver.observe(this.DM.data.container);\n\t\tthis.animationId = requestAnimationFrame(this.draw);\n\t};\n\n\tprivate readonly draw = () => {\n\t\tif (\n\t\t\tthis.perFrame.lastScale !== this.DM.data.scale ||\n\t\t\tthis.perFrame.lastOffsets.x !== this.DM.data.offsetX ||\n\t\t\tthis.perFrame.lastOffsets.y !== this.DM.data.offsetY\n\t\t)\n\t\t\tthis.refresh();\n\t\tthis.animationId = requestAnimationFrame(this.draw);\n\t};\n\n\trefresh = () => {\n\t\tthis.perFrame = {\n\t\t\tlastOffsets: { x: this.DM.data.offsetX, y: this.DM.data.offsetY },\n\t\t\tlastScale: this.DM.data.scale,\n\t\t};\n\t\tthis.onRefresh();\n\t};\n\n\tprivate readonly onResizeCallback = () => {\n\t\tthis.resizeAnimationId = requestAnimationFrame(() => {\n\t\t\tconst center = this.DM.middleViewer();\n\t\t\tif (this.lastResizeCenter.x && this.lastResizeCenter.y) {\n\t\t\t\tthis.DM.data.offsetX = this.DM.data.offsetX + center.x - this.lastResizeCenter.x;\n\t\t\t\tthis.DM.data.offsetY = this.DM.data.offsetY + center.y - this.lastResizeCenter.y;\n\t\t\t}\n\t\t\tthis.lastResizeCenter.x = center.x;\n\t\t\tthis.lastResizeCenter.y = center.y;\n\t\t\tthis.onResize(center.width, center.height);\n\t\t\tthis.refresh();\n\t\t});\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tif (this.animationId) cancelAnimationFrame(this.animationId);\n\t\tif (this.resizeAnimationId) cancelAnimationFrame(this.resizeAnimationId);\n\t\tthis.resizeObserver.disconnect();\n\t};\n}\n"],"mappings":"wJAaA,IAAqB,EAArB,cAAwC,CAAsC,CAC7E,YACA,kBACA,GACA,GACA,eACA,SAGI,CACH,YAAa,CAAE,EAAG,EAAG,EAAG,EAAG,CAC3B,UAAW,EACX,CACD,iBAGI,CACH,EAAG,IAAA,GACH,EAAG,IAAA,GACH,CAED,SAAW,GAA4B,CACvC,UAAY,GAAU,CAEtB,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,KAAK,GAAK,KAAK,UAAU,IAAI,EAAa,CAC1C,KAAK,eAAiB,IAAI,eAAe,KAAK,iBAAiB,CAC/D,KAAK,GAAG,cAAc,UAAU,KAAK,QAAQ,CAC7C,KAAK,QAAQ,CACZ,UAAW,KAAK,UAChB,SAAU,KAAK,SACf,QAAS,KAAK,QACd,CAAC,CACF,KAAK,QAAQ,KAAK,MAAM,CACxB,KAAK,UAAU,KAAK,QAAQ,CAC5B,KAAK,UAAU,KAAK,QAAQ,CAG7B,UAA+B,CAC9B,KAAK,eAAe,QAAQ,KAAK,GAAG,KAAK,UAAU,CACnD,KAAK,YAAc,sBAAsB,KAAK,KAAK,EAGpD,SAA8B,EAE5B,KAAK,SAAS,YAAc,KAAK,GAAG,KAAK,OACzC,KAAK,SAAS,YAAY,IAAM,KAAK,GAAG,KAAK,SAC7C,KAAK,SAAS,YAAY,IAAM,KAAK,GAAG,KAAK,UAE7C,KAAK,SAAS,CACf,KAAK,YAAc,sBAAsB,KAAK,KAAK,EAGpD,YAAgB,CACf,KAAK,SAAW,CACf,YAAa,CAAE,EAAG,KAAK,GAAG,KAAK,QAAS,EAAG,KAAK,GAAG,KAAK,QAAS,CACjE,UAAW,KAAK,GAAG,KAAK,MACxB,CACD,KAAK,WAAW,EAGjB,qBAA0C,CACzC,KAAK,kBAAoB,0BAA4B,CACpD,IAAM,EAAS,KAAK,GAAG,cAAc,CACjC,KAAK,iBAAiB,GAAK,KAAK,iBAAiB,IACpD,KAAK,GAAG,KAAK,QAAU,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,KAAK,iBAAiB,EAC/E,KAAK,GAAG,KAAK,QAAU,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,KAAK,iBAAiB,GAEhF,KAAK,iBAAiB,EAAI,EAAO,EACjC,KAAK,iBAAiB,EAAI,EAAO,EACjC,KAAK,SAAS,EAAO,MAAO,EAAO,OAAO,CAC1C,KAAK,SAAS,EACb,EAGH,YAAiC,CAC5B,KAAK,aAAa,qBAAqB,KAAK,YAAY,CACxD,KAAK,mBAAmB,qBAAqB,KAAK,kBAAkB,CACxE,KAAK,eAAe,YAAY"}
1
+ {"version":3,"file":"Controller.js","names":[],"sources":["../../src/kernel/Controller.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport { BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport StyleManager from '$/StyleManager';\nimport { makeHook } from '$/utilities';\n\ntype Augmentation = {\n\trefresh: Controller['refresh'];\n\tonRefresh: Controller['onRefresh'];\n\tonResize: Controller['onResize'];\n};\n\nexport default class Controller extends BaseModule<BaseOptions, Augmentation> {\n\tprivate animationId?: number;\n\tprivate resizeAnimationId?: number;\n\tprivate readonly DM: DataManager;\n\tprivate readonly SM: StyleManager;\n\tprivate readonly resizeObserver: ResizeObserver;\n\tprivate perFrame: {\n\t\tlastScale: number;\n\t\tlastOffsets: { x: number; y: number };\n\t} = {\n\t\tlastOffsets: { x: 0, y: 0 },\n\t\tlastScale: 1,\n\t};\n\tprivate readonly lastResizeCenter: {\n\t\tx?: number;\n\t\ty?: number;\n\t} = {};\n\n\tonResize = makeHook<[number, number]>();\n\tonRefresh = makeHook();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tthis.resizeObserver = new ResizeObserver(this.onResizeCallback);\n\t\tthis.SM.onChangeTheme.subscribe(this.refresh);\n\t\tthis.augment({\n\t\t\tonRefresh: this.onRefresh,\n\t\t\tonResize: this.onResize,\n\t\t\trefresh: this.refresh,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.refresh);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tthis.resizeObserver.observe(this.DM.data.container);\n\t\tthis.animationId = requestAnimationFrame(this.draw);\n\t};\n\n\tprivate readonly draw = () => {\n\t\tif (\n\t\t\tthis.perFrame.lastScale !== this.DM.data.scale ||\n\t\t\tthis.perFrame.lastOffsets.x !== this.DM.data.offsetX ||\n\t\t\tthis.perFrame.lastOffsets.y !== this.DM.data.offsetY\n\t\t)\n\t\t\tthis.refresh();\n\t\tthis.animationId = requestAnimationFrame(this.draw);\n\t};\n\n\trefresh = () => {\n\t\tthis.perFrame = {\n\t\t\tlastOffsets: { x: this.DM.data.offsetX, y: this.DM.data.offsetY },\n\t\t\tlastScale: this.DM.data.scale,\n\t\t};\n\t\tthis.onRefresh();\n\t};\n\n\tprivate readonly onResizeCallback = () => {\n\t\tthis.resizeAnimationId = requestAnimationFrame(() => {\n\t\t\tconst center = this.DM.middleViewer();\n\t\t\tif (this.lastResizeCenter.x && this.lastResizeCenter.y) {\n\t\t\t\tthis.DM.data.offsetX = this.DM.data.offsetX + center.x - this.lastResizeCenter.x;\n\t\t\t\tthis.DM.data.offsetY = this.DM.data.offsetY + center.y - this.lastResizeCenter.y;\n\t\t\t}\n\t\t\tthis.lastResizeCenter.x = center.x;\n\t\t\tthis.lastResizeCenter.y = center.y;\n\t\t\tthis.onResize(center.width, center.height);\n\t\t\tthis.refresh();\n\t\t});\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tif (this.animationId) cancelAnimationFrame(this.animationId);\n\t\tif (this.resizeAnimationId) cancelAnimationFrame(this.resizeAnimationId);\n\t\tthis.resizeObserver.disconnect();\n\t};\n}\n"],"mappings":"wJAaA,IAAqB,EAArB,cAAwC,CAAsC,CAC7E,YACA,kBACA,GACA,GACA,eACA,SAGI,CACH,YAAa,CAAE,EAAG,EAAG,EAAG,EAAG,CAC3B,UAAW,EACX,CACD,iBAGI,EAAE,CAEN,SAAW,GAA4B,CACvC,UAAY,GAAU,CAEtB,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,KAAK,GAAK,KAAK,UAAU,IAAI,EAAa,CAC1C,KAAK,eAAiB,IAAI,eAAe,KAAK,iBAAiB,CAC/D,KAAK,GAAG,cAAc,UAAU,KAAK,QAAQ,CAC7C,KAAK,QAAQ,CACZ,UAAW,KAAK,UAChB,SAAU,KAAK,SACf,QAAS,KAAK,QACd,CAAC,CACF,KAAK,QAAQ,KAAK,MAAM,CACxB,KAAK,UAAU,KAAK,QAAQ,CAC5B,KAAK,UAAU,KAAK,QAAQ,CAG7B,UAA+B,CAC9B,KAAK,eAAe,QAAQ,KAAK,GAAG,KAAK,UAAU,CACnD,KAAK,YAAc,sBAAsB,KAAK,KAAK,EAGpD,SAA8B,EAE5B,KAAK,SAAS,YAAc,KAAK,GAAG,KAAK,OACzC,KAAK,SAAS,YAAY,IAAM,KAAK,GAAG,KAAK,SAC7C,KAAK,SAAS,YAAY,IAAM,KAAK,GAAG,KAAK,UAE7C,KAAK,SAAS,CACf,KAAK,YAAc,sBAAsB,KAAK,KAAK,EAGpD,YAAgB,CACf,KAAK,SAAW,CACf,YAAa,CAAE,EAAG,KAAK,GAAG,KAAK,QAAS,EAAG,KAAK,GAAG,KAAK,QAAS,CACjE,UAAW,KAAK,GAAG,KAAK,MACxB,CACD,KAAK,WAAW,EAGjB,qBAA0C,CACzC,KAAK,kBAAoB,0BAA4B,CACpD,IAAM,EAAS,KAAK,GAAG,cAAc,CACjC,KAAK,iBAAiB,GAAK,KAAK,iBAAiB,IACpD,KAAK,GAAG,KAAK,QAAU,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,KAAK,iBAAiB,EAC/E,KAAK,GAAG,KAAK,QAAU,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,KAAK,iBAAiB,GAEhF,KAAK,iBAAiB,EAAI,EAAO,EACjC,KAAK,iBAAiB,EAAI,EAAO,EACjC,KAAK,SAAS,EAAO,MAAO,EAAO,OAAO,CAC1C,KAAK,SAAS,EACb,EAGH,YAAiC,CAC5B,KAAK,aAAa,qBAAqB,KAAK,YAAY,CACxD,KAAK,mBAAmB,qBAAqB,KAAK,kBAAkB,CACxE,KAAK,eAAe,YAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"DataManager.js","names":["style"],"sources":["../../src/kernel/DataManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { Box, NodeBounds } from '$/types';\nimport type { Hook } from '$/utilities';\nimport type { JSONCanvas, JSONCanvasEdge, JSONCanvasNode } from '@repo/shared';\nimport { BaseModule } from '$/BaseModule';\nimport style from '$/styles.scss?inline';\nimport { applyStyles, getAnchorCoord, makeHook } from '$/utilities';\n\nconst INITIAL_VIEWPORT_PADDING = 100;\nconst NODE_LABEL_MARGIN = 40;\nconst EDGE_BOX_HEURISTICS_BASE_MARGIN = 10;\n\ntype Options = {\n\tshadowed?: boolean;\n\tcanvas?: JSONCanvas;\n\tattachmentDir?: string;\n\textraCSS?: string;\n\tattachments?: Record<string, string>;\n\tnoAttachmentRelocation?: boolean;\n} & BaseOptions;\n\ntype Augmentation = {\n\tresetView: DataManager['resetView'];\n\ttoggleFullscreen: DataManager['toggleFullscreen'];\n\tonToggleFullscreen: DataManager['onToggleFullscreen'];\n};\n\nexport type NodeItem = {\n\tref: JSONCanvasNode;\n\tbox: Box;\n\tfileName?: string;\n\tonBeforeUnmount?: Hook;\n\tonActive?: Hook;\n\tonLoseActive?: Hook;\n};\n\nexport type EdgeItem = {\n\tref: JSONCanvasEdge;\n\tbox: Box;\n\tcontrolPoints?: Array<number>;\n};\n\ntype NodeMap = Record<string, NodeItem>;\ntype EdgeMap = Record<string, EdgeItem>;\n\nexport default class DataManager extends BaseModule<Options, Augmentation> {\n\tonToggleFullscreen = makeHook<['enter' | 'exit']>();\n\n\tdata: {\n\t\tcanvasData: Required<JSONCanvas>;\n\t\tnodeMap: NodeMap;\n\t\tedgeMap: EdgeMap;\n\t\tcanvasBaseDir: string;\n\t\tnodeBounds: NodeBounds;\n\t\toffsetX: number;\n\t\toffsetY: number;\n\t\tscale: number;\n\t\tcontainer: HTMLDivElement;\n\t} = {\n\t\tcanvasBaseDir: './',\n\t\tcanvasData: {\n\t\t\tedges: [],\n\t\t\tnodes: [],\n\t\t},\n\t\tcontainer: document.createElement('div'),\n\t\tedgeMap: {},\n\t\tnodeBounds: {\n\t\t\tcenterX: 0,\n\t\t\tcenterY: 0,\n\t\t\theight: 0,\n\t\t\tmaxX: 0,\n\t\t\tmaxY: 0,\n\t\t\tminX: 0,\n\t\t\tminY: 0,\n\t\t\twidth: 0,\n\t\t},\n\t\tnodeMap: {},\n\t\toffsetX: 0,\n\t\toffsetY: 0,\n\t\tscale: 1,\n\t};\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tconst viewerContainer = this.options.container;\n\t\twhile (viewerContainer.firstElementChild) viewerContainer.firstElementChild.remove();\n\t\tviewerContainer.innerHTML = '';\n\n\t\tconst realContainer = this.options.shadowed\n\t\t\t? viewerContainer.attachShadow({ mode: 'open' })\n\t\t\t: viewerContainer;\n\n\t\tapplyStyles(realContainer, style + this.options.extraCSS);\n\n\t\tthis.data.container.classList.add('JSON-Canvas-Viewer');\n\t\trealContainer.appendChild(this.data.container);\n\n\t\tthis.augment({\n\t\t\tonToggleFullscreen: this.onToggleFullscreen,\n\t\t\tresetView: this.resetView,\n\t\t\ttoggleFullscreen: this.toggleFullscreen,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tconst canvasData = {\n\t\t\tedges: [],\n\t\t\tnodes: [],\n\t\t\t...this.options.canvas,\n\t\t};\n\n\t\tObject.assign(this.data, {\n\t\t\tcanvasBaseDir: this.processBaseDir(this.options.attachmentDir),\n\t\t\tcanvasData,\n\t\t\tedgeMap: {},\n\t\t\tnodeBounds: this.calculateNodeBounds(canvasData),\n\t\t\tnodeMap: {},\n\t\t\toffsetX: 0,\n\t\t\toffsetY: 0,\n\t\t\tscale: 1,\n\t\t});\n\n\t\tthis.data.canvasData.nodes.forEach((node) => {\n\t\t\tconst item: NodeItem = {\n\t\t\t\tbox: this.getNodeBox(node),\n\t\t\t\tref: node,\n\t\t\t};\n\t\t\tthis.data.nodeMap[node.id] = item;\n\n\t\t\t// Re-process attachments\n\t\t\tif (node.type === 'file') {\n\t\t\t\tconst path = node.file.split('/');\n\t\t\t\tconst fileName = path.pop() ?? '';\n\t\t\t\titem.fileName = fileName;\n\t\t\t\tif (!node.file.startsWith('http://') && !node.file.startsWith('https://')) {\n\t\t\t\t\tconst userDefinedAttachment = this.options.attachments?.[fileName];\n\t\t\t\t\tif (userDefinedAttachment) node.file = userDefinedAttachment;\n\t\t\t\t\telse if (!this.options.noAttachmentRelocation)\n\t\t\t\t\t\tnode.file = this.data.canvasBaseDir + fileName;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.data.canvasData.edges.forEach((edge) => {\n\t\t\tthis.data.edgeMap[edge.id] = {\n\t\t\t\tbox: this.getEdgeBox(edge),\n\t\t\t\tref: edge,\n\t\t\t};\n\t\t});\n\t\tthis.resetView();\n\t};\n\n\tprivate readonly processBaseDir = (baseDir: string | undefined) => {\n\t\tif (!baseDir) return './';\n\t\tconst lastChar = baseDir?.slice(-1);\n\t\tif (lastChar === '/') return baseDir;\n\t\treturn `${baseDir}/`;\n\t};\n\n\tprivate readonly getNodeBox = (node: JSONCanvasNode) => ({\n\t\tbottom: node.y + node.height,\n\t\tleft: node.x,\n\t\tright: node.width + node.x,\n\t\ttop: node.type === 'file' || node.type === 'group' ? node.y - NODE_LABEL_MARGIN : node.y,\n\t});\n\n\tprivate readonly getEdgeBox = (edge: JSONCanvasEdge) => {\n\t\tconst nodes = this.data.nodeMap;\n\t\tconst from = nodes[edge.fromNode].ref;\n\t\tconst to = nodes[edge.toNode].ref;\n\t\tconst fromAnchor = getAnchorCoord(from, edge.fromSide);\n\t\tconst toAnchor = getAnchorCoord(to, edge.toSide);\n\t\tconst strictBox = {\n\t\t\tbottom: Math.max(fromAnchor.y, toAnchor.y),\n\t\t\tleft: Math.min(fromAnchor.x, toAnchor.x),\n\t\t\tright: Math.max(fromAnchor.x, toAnchor.x),\n\t\t\ttop: Math.min(fromAnchor.y, toAnchor.y),\n\t\t};\n\t\t// Edge size heuristics\n\t\tconst width = strictBox.right - strictBox.left;\n\t\tconst height = strictBox.bottom - strictBox.top;\n\t\tconst _min = Math.min(width, height);\n\t\tconst min = _min === 0 ? 1 : _min;\n\t\tconst max = Math.max(width, height);\n\t\tconst edgeFactor = Math.log2(max / min);\n\t\tconst margin = edgeFactor * EDGE_BOX_HEURISTICS_BASE_MARGIN;\n\t\treturn {\n\t\t\tbottom: strictBox.bottom + margin,\n\t\t\tleft: strictBox.left - margin,\n\t\t\tright: strictBox.right + margin,\n\t\t\ttop: strictBox.top - margin,\n\t\t};\n\t};\n\n\tprivate calculateNodeBounds(canvasData: Required<JSONCanvas>) {\n\t\tlet minX = Infinity,\n\t\t\tminY = Infinity,\n\t\t\tmaxX = -Infinity,\n\t\t\tmaxY = -Infinity;\n\t\tcanvasData.nodes.forEach((node) => {\n\t\t\tminX = Math.min(minX, node.x);\n\t\t\tminY = Math.min(minY, node.y);\n\t\t\tmaxX = Math.max(maxX, node.x + node.width);\n\t\t\tmaxY = Math.max(maxY, node.y + node.height);\n\t\t});\n\t\tconst width = maxX - minX;\n\t\tconst height = maxY - minY;\n\t\tconst centerX = minX + width / 2;\n\t\tconst centerY = minY + height / 2;\n\t\treturn { centerX, centerY, height, maxX, maxY, minX, minY, width };\n\t}\n\ttoggleFullscreen = async (option?: 'enter' | 'exit') => {\n\t\tif (!document.fullscreenElement && (!option || option === 'enter')) {\n\t\t\tawait this.data.container.requestFullscreen();\n\t\t\tthis.onToggleFullscreen('enter');\n\t\t} else if (document.fullscreenElement && (!option || option === 'exit')) {\n\t\t\tawait document.exitFullscreen();\n\t\t\tthis.onToggleFullscreen('exit');\n\t\t}\n\t};\n\tresetView = () => {\n\t\tconst bounds = this.data.nodeBounds;\n\t\tconst container = this.data.container;\n\t\tif (!bounds || !container) return;\n\t\tconst contentWidth = bounds.width + INITIAL_VIEWPORT_PADDING * 2;\n\t\tconst contentHeight = bounds.height + INITIAL_VIEWPORT_PADDING * 2;\n\t\t// Use logical dimensions for scaling calculations\n\t\tconst viewWidth = container.clientWidth;\n\t\tconst viewHeight = container.clientHeight;\n\t\tconst scaleX = viewWidth / contentWidth;\n\t\tconst scaleY = viewHeight / contentHeight;\n\t\tconst newScale = Math.round(Math.min(scaleX, scaleY) * 1000) / 1000;\n\t\tconst contentCenterX = bounds.centerX;\n\t\tconst contentCenterY = bounds.centerY;\n\t\tconst initialView = {\n\t\t\toffsetX: viewWidth / 2 - contentCenterX * newScale,\n\t\t\toffsetY: viewHeight / 2 - contentCenterY * newScale,\n\t\t\tscale: newScale,\n\t\t};\n\t\tthis.data.offsetX = initialView.offsetX;\n\t\tthis.data.offsetY = initialView.offsetY;\n\t\tthis.data.scale = initialView.scale;\n\t};\n\n\tmiddleViewer = () => {\n\t\tconst container = this.data.container;\n\t\treturn {\n\t\t\theight: container.clientHeight,\n\t\t\twidth: container.clientWidth,\n\t\t\tx: container.clientWidth / 2,\n\t\t\ty: container.clientHeight / 2,\n\t\t};\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tthis.data.container.remove();\n\t};\n}\n"],"mappings":"uJA8CA,IAAqB,EAArB,cAAyC,CAAkC,CAC1E,mBAAqB,GAA8B,CAEnD,KAUI,CACH,cAAe,KACf,WAAY,CACX,MAAO,EAAE,CACT,MAAO,EAAE,CACT,CACD,UAAW,SAAS,cAAc,MAAM,CACxC,QAAS,EAAE,CACX,WAAY,CACX,QAAS,EACT,QAAS,EACT,OAAQ,EACR,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,MAAO,EACP,CACD,QAAS,EAAE,CACX,QAAS,EACT,QAAS,EACT,MAAO,EACP,CAED,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,IAAM,EAAkB,KAAK,QAAQ,UACrC,KAAO,EAAgB,mBAAmB,EAAgB,kBAAkB,QAAQ,CACpF,EAAgB,UAAY,GAE5B,IAAM,EAAgB,KAAK,QAAQ,SAChC,EAAgB,aAAa,CAAE,KAAM,OAAQ,CAAC,CAC9C,EAEH,EAAY,EAAeA,EAAQ,KAAK,QAAQ,SAAS,CAEzD,KAAK,KAAK,UAAU,UAAU,IAAI,qBAAqB,CACvD,EAAc,YAAY,KAAK,KAAK,UAAU,CAE9C,KAAK,QAAQ,CACZ,mBAAoB,KAAK,mBACzB,UAAW,KAAK,UAChB,iBAAkB,KAAK,iBACvB,CAAC,CACF,KAAK,QAAQ,KAAK,MAAM,CACxB,KAAK,UAAU,KAAK,MAAM,CAC1B,KAAK,UAAU,KAAK,QAAQ,CAG7B,UAA+B,CAC9B,IAAM,EAAa,CAClB,MAAO,EAAE,CACT,MAAO,EAAE,CACT,GAAG,KAAK,QAAQ,OAChB,CAED,OAAO,OAAO,KAAK,KAAM,CACxB,cAAe,KAAK,eAAe,KAAK,QAAQ,cAAc,CAC9D,aACA,QAAS,EAAE,CACX,WAAY,KAAK,oBAAoB,EAAW,CAChD,QAAS,EAAE,CACX,QAAS,EACT,QAAS,EACT,MAAO,EACP,CAAC,CAEF,KAAK,KAAK,WAAW,MAAM,QAAS,GAAS,CAC5C,IAAM,EAAiB,CACtB,IAAK,KAAK,WAAW,EAAK,CAC1B,IAAK,EACL,CAID,GAHA,KAAK,KAAK,QAAQ,EAAK,IAAM,EAGzB,EAAK,OAAS,OAAQ,CAEzB,IAAM,EADO,EAAK,KAAK,MAAM,IACR,CAAC,KAAK,EAAI,GAE/B,GADA,EAAK,SAAW,EACZ,CAAC,EAAK,KAAK,WAAW,UAAU,EAAI,CAAC,EAAK,KAAK,WAAW,WAAW,CAAE,CAC1E,IAAM,EAAwB,KAAK,QAAQ,cAAc,GACrD,EAAuB,EAAK,KAAO,EAC7B,KAAK,QAAQ,yBACtB,EAAK,KAAO,KAAK,KAAK,cAAgB,MAGxC,CACF,KAAK,KAAK,WAAW,MAAM,QAAS,GAAS,CAC5C,KAAK,KAAK,QAAQ,EAAK,IAAM,CAC5B,IAAK,KAAK,WAAW,EAAK,CAC1B,IAAK,EACL,EACA,CACF,KAAK,WAAW,EAGjB,eAAmC,GAC7B,EACY,GAAS,MAAM,GAAG,GAClB,IAAY,EACtB,GAAG,EAAQ,GAHG,KAMtB,WAA+B,IAA0B,CACxD,OAAQ,EAAK,EAAI,EAAK,OACtB,KAAM,EAAK,EACX,MAAO,EAAK,MAAQ,EAAK,EACzB,IAAK,EAAK,OAAS,QAAU,EAAK,OAAS,QAAU,EAAK,EAAI,GAAoB,EAAK,EACvF,EAED,WAA+B,GAAyB,CACvD,IAAM,EAAQ,KAAK,KAAK,QAClB,EAAO,EAAM,EAAK,UAAU,IAC5B,EAAK,EAAM,EAAK,QAAQ,IACxB,EAAa,EAAe,EAAM,EAAK,SAAS,CAChD,EAAW,EAAe,EAAI,EAAK,OAAO,CAC1C,EAAY,CACjB,OAAQ,KAAK,IAAI,EAAW,EAAG,EAAS,EAAE,CAC1C,KAAM,KAAK,IAAI,EAAW,EAAG,EAAS,EAAE,CACxC,MAAO,KAAK,IAAI,EAAW,EAAG,EAAS,EAAE,CACzC,IAAK,KAAK,IAAI,EAAW,EAAG,EAAS,EAAE,CACvC,CAEK,EAAQ,EAAU,MAAQ,EAAU,KACpC,EAAS,EAAU,OAAS,EAAU,IACtC,EAAO,KAAK,IAAI,EAAO,EAAO,CAI9B,EADa,KAAK,KADZ,KAAK,IAAI,EAAO,EACI,EAFpB,IAAS,EAAI,EAAI,GAGJ,CAAG,GAC5B,MAAO,CACN,OAAQ,EAAU,OAAS,EAC3B,KAAM,EAAU,KAAO,EACvB,MAAO,EAAU,MAAQ,EACzB,IAAK,EAAU,IAAM,EACrB,EAGF,oBAA4B,EAAkC,CAC7D,IAAI,EAAO,IACV,EAAO,IACP,EAAO,KACP,EAAO,KACR,EAAW,MAAM,QAAS,GAAS,CAClC,EAAO,KAAK,IAAI,EAAM,EAAK,EAAE,CAC7B,EAAO,KAAK,IAAI,EAAM,EAAK,EAAE,CAC7B,EAAO,KAAK,IAAI,EAAM,EAAK,EAAI,EAAK,MAAM,CAC1C,EAAO,KAAK,IAAI,EAAM,EAAK,EAAI,EAAK,OAAO,EAC1C,CACF,IAAM,EAAQ,EAAO,EACf,EAAS,EAAO,EAGtB,MAAO,CAAE,QAFO,EAAO,EAAQ,EAEb,QADF,EAAO,EAAS,EACL,SAAQ,OAAM,OAAM,OAAM,OAAM,QAAO,CAEnE,iBAAmB,KAAO,IAA8B,CACnD,CAAC,SAAS,oBAAsB,CAAC,GAAU,IAAW,UACzD,MAAM,KAAK,KAAK,UAAU,mBAAmB,CAC7C,KAAK,mBAAmB,QAAQ,EACtB,SAAS,oBAAsB,CAAC,GAAU,IAAW,UAC/D,MAAM,SAAS,gBAAgB,CAC/B,KAAK,mBAAmB,OAAO,GAGjC,cAAkB,CACjB,IAAM,EAAS,KAAK,KAAK,WACnB,EAAY,KAAK,KAAK,UAC5B,GAAI,CAAC,GAAU,CAAC,EAAW,OAC3B,IAAM,EAAe,EAAO,MAAQ,IAC9B,EAAgB,EAAO,OAAS,IAEhC,EAAY,EAAU,YACtB,EAAa,EAAU,aACvB,EAAS,EAAY,EACrB,EAAS,EAAa,EACtB,EAAW,KAAK,MAAM,KAAK,IAAI,EAAQ,EAAO,CAAG,IAAK,CAAG,IACzD,EAAiB,EAAO,QACxB,EAAiB,EAAO,QACxB,EAAc,CACnB,QAAS,EAAY,EAAI,EAAiB,EAC1C,QAAS,EAAa,EAAI,EAAiB,EAC3C,MAAO,EACP,CACD,KAAK,KAAK,QAAU,EAAY,QAChC,KAAK,KAAK,QAAU,EAAY,QAChC,KAAK,KAAK,MAAQ,EAAY,OAG/B,iBAAqB,CACpB,IAAM,EAAY,KAAK,KAAK,UAC5B,MAAO,CACN,OAAQ,EAAU,aAClB,MAAO,EAAU,YACjB,EAAG,EAAU,YAAc,EAC3B,EAAG,EAAU,aAAe,EAC5B,EAGF,YAAiC,CAChC,KAAK,KAAK,UAAU,QAAQ"}
1
+ {"version":3,"file":"DataManager.js","names":["style"],"sources":["../../src/kernel/DataManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { Box, NodeBounds } from '$/types';\nimport type { Hook } from '$/utilities';\nimport type { JSONCanvas, JSONCanvasEdge, JSONCanvasNode } from '@repo/shared';\nimport { BaseModule } from '$/BaseModule';\nimport style from '$/styles.scss?inline';\nimport { applyStyles, getAnchorCoord, makeHook } from '$/utilities';\n\nconst INITIAL_VIEWPORT_PADDING = 100;\nconst NODE_LABEL_MARGIN = 40;\nconst EDGE_BOX_HEURISTICS_BASE_MARGIN = 10;\n\ntype Options = {\n\tshadowed?: boolean;\n\tcanvas?: JSONCanvas;\n\tattachmentDir?: string;\n\textraCSS?: string;\n\tattachments?: Record<string, string>;\n\tnoAttachmentRelocation?: boolean;\n} & BaseOptions;\n\ntype Augmentation = {\n\tresetView: DataManager['resetView'];\n\ttoggleFullscreen: DataManager['toggleFullscreen'];\n\tonToggleFullscreen: DataManager['onToggleFullscreen'];\n};\n\nexport type NodeItem = {\n\tref: JSONCanvasNode;\n\tbox: Box;\n\tfileName?: string;\n\tonBeforeUnmount?: Hook;\n\tonActive?: Hook;\n\tonLoseActive?: Hook;\n};\n\nexport type EdgeItem = {\n\tref: JSONCanvasEdge;\n\tbox: Box;\n\tcontrolPoints?: Array<number>;\n};\n\ntype NodeMap = Record<string, NodeItem>;\ntype EdgeMap = Record<string, EdgeItem>;\n\nexport default class DataManager extends BaseModule<Options, Augmentation> {\n\tonToggleFullscreen = makeHook<['enter' | 'exit']>();\n\n\tdata: {\n\t\tcanvasData: Required<JSONCanvas>;\n\t\tnodeMap: NodeMap;\n\t\tedgeMap: EdgeMap;\n\t\tcanvasBaseDir: string;\n\t\tnodeBounds: NodeBounds;\n\t\toffsetX: number;\n\t\toffsetY: number;\n\t\tscale: number;\n\t\tcontainer: HTMLDivElement;\n\t} = {\n\t\tcanvasBaseDir: './',\n\t\tcanvasData: {\n\t\t\tedges: [],\n\t\t\tnodes: [],\n\t\t},\n\t\tcontainer: document.createElement('div'),\n\t\tedgeMap: {},\n\t\tnodeBounds: {\n\t\t\tcenterX: 0,\n\t\t\tcenterY: 0,\n\t\t\theight: 0,\n\t\t\tmaxX: 0,\n\t\t\tmaxY: 0,\n\t\t\tminX: 0,\n\t\t\tminY: 0,\n\t\t\twidth: 0,\n\t\t},\n\t\tnodeMap: {},\n\t\toffsetX: 0,\n\t\toffsetY: 0,\n\t\tscale: 1,\n\t};\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tconst viewerContainer = this.options.container;\n\t\twhile (viewerContainer.firstElementChild) viewerContainer.firstElementChild.remove();\n\t\tviewerContainer.innerHTML = '';\n\n\t\tconst realContainer = this.options.shadowed\n\t\t\t? viewerContainer.attachShadow({ mode: 'open' })\n\t\t\t: viewerContainer;\n\n\t\tapplyStyles(realContainer, style + this.options.extraCSS);\n\n\t\tthis.data.container.classList.add('JSON-Canvas-Viewer');\n\t\trealContainer.appendChild(this.data.container);\n\n\t\tthis.augment({\n\t\t\tonToggleFullscreen: this.onToggleFullscreen,\n\t\t\tresetView: this.resetView,\n\t\t\ttoggleFullscreen: this.toggleFullscreen,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tconst canvasData = {\n\t\t\tedges: [],\n\t\t\tnodes: [],\n\t\t\t...this.options.canvas,\n\t\t};\n\n\t\tObject.assign(this.data, {\n\t\t\tcanvasBaseDir: this.processBaseDir(this.options.attachmentDir),\n\t\t\tcanvasData,\n\t\t\tedgeMap: {},\n\t\t\tnodeBounds: this.calculateNodeBounds(canvasData),\n\t\t\tnodeMap: {},\n\t\t\toffsetX: 0,\n\t\t\toffsetY: 0,\n\t\t\tscale: 1,\n\t\t});\n\n\t\tthis.data.canvasData.nodes.forEach((node) => {\n\t\t\tconst item: NodeItem = {\n\t\t\t\tbox: this.getNodeBox(node),\n\t\t\t\tref: node,\n\t\t\t};\n\t\t\tthis.data.nodeMap[node.id] = item;\n\n\t\t\t// Re-process attachments\n\t\t\tif (node.type === 'file') {\n\t\t\t\tconst path = node.file.split('/');\n\t\t\t\tconst fileName = path.pop() ?? '';\n\t\t\t\titem.fileName = fileName;\n\t\t\t\tif (!node.file.startsWith('http://') && !node.file.startsWith('https://')) {\n\t\t\t\t\tconst userDefinedAttachment = this.options.attachments?.[fileName];\n\t\t\t\t\tif (userDefinedAttachment) node.file = userDefinedAttachment;\n\t\t\t\t\telse if (!this.options.noAttachmentRelocation)\n\t\t\t\t\t\tnode.file = this.data.canvasBaseDir + fileName;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.data.canvasData.edges.forEach((edge) => {\n\t\t\tthis.data.edgeMap[edge.id] = {\n\t\t\t\tbox: this.getEdgeBox(edge),\n\t\t\t\tref: edge,\n\t\t\t};\n\t\t});\n\t\tthis.resetView();\n\t};\n\n\tprivate readonly processBaseDir = (baseDir?: string) => {\n\t\tif (!baseDir) return './';\n\t\tconst lastChar = baseDir?.slice(-1);\n\t\tif (lastChar === '/') return baseDir;\n\t\treturn `${baseDir}/`;\n\t};\n\n\tprivate readonly getNodeBox = (node: JSONCanvasNode) => ({\n\t\tbottom: node.y + node.height,\n\t\tleft: node.x,\n\t\tright: node.width + node.x,\n\t\ttop: node.type === 'file' || node.type === 'group' ? node.y - NODE_LABEL_MARGIN : node.y,\n\t});\n\n\tprivate readonly getEdgeBox = (edge: JSONCanvasEdge) => {\n\t\tconst nodes = this.data.nodeMap;\n\t\tconst from = nodes[edge.fromNode].ref;\n\t\tconst to = nodes[edge.toNode].ref;\n\t\tconst fromAnchor = getAnchorCoord(from, edge.fromSide);\n\t\tconst toAnchor = getAnchorCoord(to, edge.toSide);\n\t\tconst strictBox = {\n\t\t\tbottom: Math.max(fromAnchor.y, toAnchor.y),\n\t\t\tleft: Math.min(fromAnchor.x, toAnchor.x),\n\t\t\tright: Math.max(fromAnchor.x, toAnchor.x),\n\t\t\ttop: Math.min(fromAnchor.y, toAnchor.y),\n\t\t};\n\t\t// Edge size heuristics\n\t\tconst width = strictBox.right - strictBox.left;\n\t\tconst height = strictBox.bottom - strictBox.top;\n\t\tconst _min = Math.min(width, height);\n\t\tconst min = _min === 0 ? 1 : _min;\n\t\tconst max = Math.max(width, height);\n\t\tconst edgeFactor = Math.log2(max / min);\n\t\tconst margin = edgeFactor * EDGE_BOX_HEURISTICS_BASE_MARGIN;\n\t\treturn {\n\t\t\tbottom: strictBox.bottom + margin,\n\t\t\tleft: strictBox.left - margin,\n\t\t\tright: strictBox.right + margin,\n\t\t\ttop: strictBox.top - margin,\n\t\t};\n\t};\n\n\tprivate calculateNodeBounds(canvasData: Required<JSONCanvas>) {\n\t\tlet minX = Infinity,\n\t\t\tminY = Infinity,\n\t\t\tmaxX = -Infinity,\n\t\t\tmaxY = -Infinity;\n\t\tcanvasData.nodes.forEach((node) => {\n\t\t\tminX = Math.min(minX, node.x);\n\t\t\tminY = Math.min(minY, node.y);\n\t\t\tmaxX = Math.max(maxX, node.x + node.width);\n\t\t\tmaxY = Math.max(maxY, node.y + node.height);\n\t\t});\n\t\tconst width = maxX - minX;\n\t\tconst height = maxY - minY;\n\t\tconst centerX = minX + width / 2;\n\t\tconst centerY = minY + height / 2;\n\t\treturn { centerX, centerY, height, maxX, maxY, minX, minY, width };\n\t}\n\ttoggleFullscreen = async (option?: 'enter' | 'exit') => {\n\t\tif (!document.fullscreenElement && (!option || option === 'enter')) {\n\t\t\tawait this.data.container.requestFullscreen();\n\t\t\tthis.onToggleFullscreen('enter');\n\t\t} else if (document.fullscreenElement && (!option || option === 'exit')) {\n\t\t\tawait document.exitFullscreen();\n\t\t\tthis.onToggleFullscreen('exit');\n\t\t}\n\t};\n\tresetView = () => {\n\t\tconst bounds = this.data.nodeBounds;\n\t\tconst container = this.data.container;\n\t\tif (!bounds || !container) return;\n\t\tconst contentWidth = bounds.width + INITIAL_VIEWPORT_PADDING * 2;\n\t\tconst contentHeight = bounds.height + INITIAL_VIEWPORT_PADDING * 2;\n\t\t// Use logical dimensions for scaling calculations\n\t\tconst viewWidth = container.clientWidth;\n\t\tconst viewHeight = container.clientHeight;\n\t\tconst scaleX = viewWidth / contentWidth;\n\t\tconst scaleY = viewHeight / contentHeight;\n\t\tconst newScale = Math.round(Math.min(scaleX, scaleY) * 1000) / 1000;\n\t\tconst contentCenterX = bounds.centerX;\n\t\tconst contentCenterY = bounds.centerY;\n\t\tconst initialView = {\n\t\t\toffsetX: viewWidth / 2 - contentCenterX * newScale,\n\t\t\toffsetY: viewHeight / 2 - contentCenterY * newScale,\n\t\t\tscale: newScale,\n\t\t};\n\t\tthis.data.offsetX = initialView.offsetX;\n\t\tthis.data.offsetY = initialView.offsetY;\n\t\tthis.data.scale = initialView.scale;\n\t};\n\n\tmiddleViewer = () => {\n\t\tconst container = this.data.container;\n\t\treturn {\n\t\t\theight: container.clientHeight,\n\t\t\twidth: container.clientWidth,\n\t\t\tx: container.clientWidth / 2,\n\t\t\ty: container.clientHeight / 2,\n\t\t};\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tthis.data.container.remove();\n\t};\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{BaseModule as e}from"./BaseModule.js";import{makeHook as t}from"./utilities.js";import n from"./DataManager.js";import r from"./OverlayManager.js";import{Click as i,Drag as a,Lubricator as o,MultitouchPanZoom as s,Pointeract as c,PreventDefault as l,WheelPanZoom as u,lubricatorDragPreset as d,lubricatorPanPreset as f,lubricatorZoomPreset as p}from"pointeract";var m=class extends e{pointeract;DM;onClick=t();constructor(...e){super(...e),this.DM=this.container.get(n);let t=Object.assign(this.options.pointeract??{},{coordinateOutput:`relative`,element:this.DM.data.container,lubricator:{drag:d,pan:f,zoom:p}});this.pointeract=new c(t,[i,a,u,l,s,o]);let m=this.container.get(r);m.onInteractionStart.subscribe(this.stopInteract),m.onInteractionEnd.subscribe(this.startInteract),this.augment({pan:this.pan,panToCoords:this.panToCoords,zoom:this.zoom,zoomToScale:this.zoomToScale}),this.onStart(this.start),this.onDispose(this.dispose)}start=()=>{this.pointeract.on(`pan`,this.onPan).on(`drag`,this.onPan).on(`zoom`,this.onZoom).on(`trueClick`,this.onTrueClick).start()};startInteract=()=>{this.pointeract.start()};stopInteract=()=>{this.pointeract.stop()};onPan=e=>{this.truePan({x:e.deltaX,y:e.deltaY})};onZoom=e=>{this.trueZoom(e.factor,e)};trueZoom=(e,t)=>{let n=Math.max(Math.min(this.DM.data.scale*e,20),.05);if(n===this.DM.data.scale)return;let r=n/this.DM.data.scale,i=this.C2C(t);this.DM.data.offsetX=t.x-i.x*r,this.DM.data.offsetY=t.y-i.y*r,this.DM.data.scale=n};truePan=({x:e,y:t})=>{this.DM.data.offsetX+=e,this.DM.data.offsetY+=t};zoom=(e,t)=>{this.pointeract.dispatch(`zoom`,{factor:e,...t})};pan=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e,deltaY:t})};zoomToScale=(e,t)=>{let n=e/this.DM.data.scale;this.pointeract.dispatch(`zoom`,{factor:n,...t})};panToCoords=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e-this.DM.data.offsetX,deltaY:t-this.DM.data.offsetY})};C2C=({x:e,y:t})=>({x:e-this.DM.data.offsetX,y:t-this.DM.data.offsetY});onTrueClick=e=>{let t=e.target;if(this.isUIControl(t))return;let n=this.findNodeId(t);this.onClick(n)};isUIControl=e=>e?e.closest(`.controls`)||e.closest(`button`)||e.closest(`input`):!1;findNodeId=e=>{if(!e)return;let t=e;for(;(!t.id||t.id===``)&&t.parentElement;)t=t.parentElement;if(!(t.id===`overlays`||!t.id||t.id===``))return t.id};dispose=()=>this.pointeract.dispose()};export{m as default};
1
+ import{BaseModule as e}from"./BaseModule.js";import{makeHook as t}from"./utilities.js";import n from"./DataManager.js";import r from"./OverlayManager.js";import{Click as i,Drag as a,Lubricator as o,MultitouchPanZoom as s,Pointeract as c,PreventDefault as l,WheelPanZoom as u,lubricatorDragPreset as d,lubricatorPanPreset as f,lubricatorZoomPreset as p}from"pointeract";var m=class extends e{pointeract;DM;onClick=t();constructor(...e){super(...e),this.DM=this.container.get(n);let t=Object.assign(this.options.pointeract??{},{coordinateOutput:`relative`,element:this.DM.data.container,lubricator:{drag:d,pan:f,zoom:p}});this.pointeract=new c(t,[i,a,u,l,s,o]);let m=this.container.get(r);m.onInteractionStart.subscribe(this.stopInteract),m.onInteractionEnd.subscribe(this.startInteract),this.augment({pan:this.pan,panToCoords:this.panToCoords,zoom:this.zoom,zoomToScale:this.zoomToScale}),this.onStart(this.start),this.onDispose(this.dispose)}start=()=>{this.pointeract.on(`pan`,this.onPan).on(`drag`,this.onPan).on(`zoom`,this.onZoom).on(`trueClick`,this.onTrueClick).start()};startInteract=()=>{this.pointeract.start()};stopInteract=()=>{this.pointeract.stop()};onPan=e=>{this.truePan({x:e.deltaX,y:e.deltaY})};onZoom=e=>{this.trueZoom(e.factor,e)};trueZoom=(e,t)=>{let n=Math.max(Math.min(this.DM.data.scale*e,20),.05);if(n===this.DM.data.scale)return;let r=n/this.DM.data.scale,i=this.C2C(t);this.DM.data.offsetX=t.x-i.x*r,this.DM.data.offsetY=t.y-i.y*r,this.DM.data.scale=n};truePan=({x:e,y:t})=>{this.DM.data.offsetX+=e,this.DM.data.offsetY+=t};zoom=(e,t)=>{this.pointeract.dispatch(`zoom`,{factor:e,...t})};pan=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e,deltaY:t})};zoomToScale=(e,t)=>{let n=e/this.DM.data.scale;this.pointeract.dispatch(`zoom`,{factor:n,...t})};panToCoords=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e-this.DM.data.offsetX,deltaY:t-this.DM.data.offsetY})};C2C=({x:e,y:t})=>({x:e-this.DM.data.offsetX,y:t-this.DM.data.offsetY});onTrueClick=e=>{let t=e.target?e.target:void 0;if(this.isUIControl(t))return;let n=this.findNodeId(t);this.onClick(n)};isUIControl=e=>e?e.closest(`.controls`)||e.closest(`button`)||e.closest(`input`):!1;findNodeId=e=>{if(!e)return;let t=e;for(;(!t.id||t.id===``)&&t.parentElement;)t=t.parentElement;if(!(t.id===`overlays`||!t.id||t.id===``))return t.id};dispose=()=>this.pointeract.dispose()};export{m as default};
2
2
  //# sourceMappingURL=InteractionHandler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InteractionHandler.js","names":[],"sources":["../../src/kernel/InteractionHandler.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { Coordinates } from '$/types';\nimport type { Options as PointeractOptions, Events, PointeractInterface } from 'pointeract';\nimport { BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport OverlayManager from '$/OverlayManager';\nimport { makeHook } from '$/utilities';\nimport {\n\tClick,\n\tDrag,\n\tMultitouchPanZoom,\n\tPointeract,\n\tPreventDefault,\n\tWheelPanZoom,\n\tLubricator,\n\tlubricatorPanPreset as pan,\n\tlubricatorZoomPreset as zoom,\n\tlubricatorDragPreset as drag,\n} from 'pointeract';\n\ntype LoadedModules = [Click, Drag, WheelPanZoom, PreventDefault, MultitouchPanZoom, Lubricator];\n\ntype LoadedEvents = Events<LoadedModules>;\n\ntype Options = {\n\tpointeract?: PointeractOptions<LoadedModules>;\n} & BaseOptions;\n\ntype Augmentation = {\n\tpan: InteractionHandler['pan'];\n\tpanToCoords: InteractionHandler['panToCoords'];\n\tzoom: InteractionHandler['zoom'];\n\tzoomToScale: InteractionHandler['zoomToScale'];\n};\n\nexport default class InteractionHandler extends BaseModule<Options, Augmentation> {\n\tpointeract: PointeractInterface<LoadedModules>;\n\tprivate readonly DM: DataManager;\n\tonClick = makeHook<[string | undefined]>();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tconst options = Object.assign(this.options.pointeract ?? {}, {\n\t\t\tcoordinateOutput: 'relative',\n\t\t\telement: this.DM.data.container,\n\t\t\tlubricator: { drag, pan, zoom },\n\t\t} satisfies PointeractOptions<LoadedModules>);\n\t\tthis.pointeract = new Pointeract(options, [\n\t\t\tClick,\n\t\t\tDrag,\n\t\t\tWheelPanZoom,\n\t\t\tPreventDefault,\n\t\t\tMultitouchPanZoom,\n\t\t\tLubricator,\n\t\t]);\n\t\tconst OM = this.container.get(OverlayManager);\n\t\tOM.onInteractionStart.subscribe(this.stopInteract);\n\t\tOM.onInteractionEnd.subscribe(this.startInteract);\n\n\t\tthis.augment({\n\t\t\tpan: this.pan,\n\t\t\tpanToCoords: this.panToCoords,\n\t\t\tzoom: this.zoom,\n\t\t\tzoomToScale: this.zoomToScale,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tthis.pointeract\n\t\t\t.on('pan', this.onPan)\n\t\t\t.on('drag', this.onPan)\n\t\t\t.on('zoom', this.onZoom)\n\t\t\t.on('trueClick', this.onTrueClick)\n\t\t\t.start();\n\t};\n\n\tprivate readonly startInteract = () => {\n\t\tthis.pointeract.start();\n\t};\n\tprivate readonly stopInteract = () => {\n\t\tthis.pointeract.stop();\n\t};\n\n\tprivate readonly onPan = (event: LoadedEvents['pan']) => {\n\t\tthis.truePan({\n\t\t\tx: event.deltaX,\n\t\t\ty: event.deltaY,\n\t\t});\n\t};\n\tprivate readonly onZoom = (event: LoadedEvents['zoom']) => {\n\t\tthis.trueZoom(event.factor, event);\n\t};\n\n\ttrueZoom = (_factor: number, origin: Coordinates) => {\n\t\tconst newScale = Math.max(Math.min(this.DM.data.scale * _factor, 20), 0.05);\n\t\tconst scale = this.DM.data.scale;\n\t\tif (newScale === scale) return;\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tconst canvasCoords = this.C2C(origin);\n\t\tthis.DM.data.offsetX = origin.x - canvasCoords.x * factor;\n\t\tthis.DM.data.offsetY = origin.y - canvasCoords.y * factor;\n\t\tthis.DM.data.scale = newScale;\n\t};\n\ttruePan = ({ x, y }: Coordinates) => {\n\t\tthis.DM.data.offsetX += x;\n\t\tthis.DM.data.offsetY += y;\n\t};\n\n\tzoom = (_factor: number, origin: Coordinates) => {\n\t\tthis.pointeract.dispatch('zoom', { factor: _factor, ...origin });\n\t};\n\tpan = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', { deltaX: x, deltaY: y });\n\t};\n\tzoomToScale = (newScale: number, origin: Coordinates) => {\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tthis.pointeract.dispatch('zoom', { factor, ...origin });\n\t};\n\tpanToCoords = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', {\n\t\t\tdeltaX: x - this.DM.data.offsetX,\n\t\t\tdeltaY: y - this.DM.data.offsetY,\n\t\t});\n\t};\n\n\t// Container Coords to Canvas Coords relative to the top-left corner of the scaled canvas\n\tprivate readonly C2C = ({ x: containerX, y: containerY }: Coordinates) => ({\n\t\tx: containerX - this.DM.data.offsetX,\n\t\ty: containerY - this.DM.data.offsetY,\n\t});\n\n\tprivate readonly onTrueClick = (e: LoadedEvents['trueClick']) => {\n\t\tconst element = e.target as HTMLElement | undefined;\n\t\tif (this.isUIControl(element)) return;\n\t\tconst node = this.findNodeId(element);\n\t\tthis.onClick(node);\n\t};\n\n\tprivate readonly isUIControl = (target?: HTMLElement) => {\n\t\tif (!target) return false;\n\t\treturn target.closest('.controls') || target.closest('button') || target.closest('input');\n\t};\n\n\tprivate readonly findNodeId = (element?: HTMLElement) => {\n\t\tif (!element) return;\n\t\tlet ele = element;\n\t\twhile (!ele.id || ele.id === '') {\n\t\t\tif (!ele.parentElement) break;\n\t\t\tele = ele.parentElement;\n\t\t}\n\t\tif (ele.id === 'overlays' || !ele.id || ele.id === '') return;\n\t\treturn ele.id;\n\t};\n\n\tprivate readonly dispose = () => this.pointeract.dispose();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"InteractionHandler.js","names":[],"sources":["../../src/kernel/InteractionHandler.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { Coordinates } from '$/types';\nimport type { Options as PointeractOptions, Events, PointeractInterface } from 'pointeract';\nimport { BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport OverlayManager from '$/OverlayManager';\nimport { makeHook } from '$/utilities';\nimport {\n\tClick,\n\tDrag,\n\tMultitouchPanZoom,\n\tPointeract,\n\tPreventDefault,\n\tWheelPanZoom,\n\tLubricator,\n\tlubricatorPanPreset as pan,\n\tlubricatorZoomPreset as zoom,\n\tlubricatorDragPreset as drag,\n} from 'pointeract';\n\ntype LoadedModules = [Click, Drag, WheelPanZoom, PreventDefault, MultitouchPanZoom, Lubricator];\n\ntype LoadedEvents = Events<LoadedModules>;\n\ntype Options = {\n\tpointeract?: PointeractOptions<LoadedModules>;\n} & BaseOptions;\n\ntype Augmentation = {\n\tpan: InteractionHandler['pan'];\n\tpanToCoords: InteractionHandler['panToCoords'];\n\tzoom: InteractionHandler['zoom'];\n\tzoomToScale: InteractionHandler['zoomToScale'];\n};\n\nexport default class InteractionHandler extends BaseModule<Options, Augmentation> {\n\tpointeract: PointeractInterface<LoadedModules>;\n\tprivate readonly DM: DataManager;\n\tonClick = makeHook<[string | undefined]>();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tconst options = Object.assign(this.options.pointeract ?? {}, {\n\t\t\tcoordinateOutput: 'relative',\n\t\t\telement: this.DM.data.container,\n\t\t\tlubricator: { drag, pan, zoom },\n\t\t} satisfies PointeractOptions<LoadedModules>);\n\t\tthis.pointeract = new Pointeract(options, [\n\t\t\tClick,\n\t\t\tDrag,\n\t\t\tWheelPanZoom,\n\t\t\tPreventDefault,\n\t\t\tMultitouchPanZoom,\n\t\t\tLubricator,\n\t\t]);\n\t\tconst OM = this.container.get(OverlayManager);\n\t\tOM.onInteractionStart.subscribe(this.stopInteract);\n\t\tOM.onInteractionEnd.subscribe(this.startInteract);\n\n\t\tthis.augment({\n\t\t\tpan: this.pan,\n\t\t\tpanToCoords: this.panToCoords,\n\t\t\tzoom: this.zoom,\n\t\t\tzoomToScale: this.zoomToScale,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tthis.pointeract\n\t\t\t.on('pan', this.onPan)\n\t\t\t.on('drag', this.onPan)\n\t\t\t.on('zoom', this.onZoom)\n\t\t\t.on('trueClick', this.onTrueClick)\n\t\t\t.start();\n\t};\n\n\tprivate readonly startInteract = () => {\n\t\tthis.pointeract.start();\n\t};\n\tprivate readonly stopInteract = () => {\n\t\tthis.pointeract.stop();\n\t};\n\n\tprivate readonly onPan = (event: LoadedEvents['pan']) => {\n\t\tthis.truePan({\n\t\t\tx: event.deltaX,\n\t\t\ty: event.deltaY,\n\t\t});\n\t};\n\tprivate readonly onZoom = (event: LoadedEvents['zoom']) => {\n\t\tthis.trueZoom(event.factor, event);\n\t};\n\n\ttrueZoom = (_factor: number, origin: Coordinates) => {\n\t\tconst newScale = Math.max(Math.min(this.DM.data.scale * _factor, 20), 0.05);\n\t\tconst scale = this.DM.data.scale;\n\t\tif (newScale === scale) return;\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tconst canvasCoords = this.C2C(origin);\n\t\tthis.DM.data.offsetX = origin.x - canvasCoords.x * factor;\n\t\tthis.DM.data.offsetY = origin.y - canvasCoords.y * factor;\n\t\tthis.DM.data.scale = newScale;\n\t};\n\ttruePan = ({ x, y }: Coordinates) => {\n\t\tthis.DM.data.offsetX += x;\n\t\tthis.DM.data.offsetY += y;\n\t};\n\n\tzoom = (_factor: number, origin: Coordinates) => {\n\t\tthis.pointeract.dispatch('zoom', { factor: _factor, ...origin });\n\t};\n\tpan = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', { deltaX: x, deltaY: y });\n\t};\n\tzoomToScale = (newScale: number, origin: Coordinates) => {\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tthis.pointeract.dispatch('zoom', { factor, ...origin });\n\t};\n\tpanToCoords = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', {\n\t\t\tdeltaX: x - this.DM.data.offsetX,\n\t\t\tdeltaY: y - this.DM.data.offsetY,\n\t\t});\n\t};\n\n\t// Container Coords to Canvas Coords relative to the top-left corner of the scaled canvas\n\tprivate readonly C2C = ({ x: containerX, y: containerY }: Coordinates) => ({\n\t\tx: containerX - this.DM.data.offsetX,\n\t\ty: containerY - this.DM.data.offsetY,\n\t});\n\n\tprivate readonly onTrueClick = (e: LoadedEvents['trueClick']) => {\n\t\tconst element = e.target ? (e.target as HTMLElement) : undefined;\n\t\tif (this.isUIControl(element)) return;\n\t\tconst node = this.findNodeId(element);\n\t\tthis.onClick(node);\n\t};\n\n\tprivate readonly isUIControl = (target?: HTMLElement) => {\n\t\tif (!target) return false;\n\t\treturn target.closest('.controls') || target.closest('button') || target.closest('input');\n\t};\n\n\tprivate readonly findNodeId = (element?: HTMLElement) => {\n\t\tif (!element) return;\n\t\tlet ele = element;\n\t\twhile (!ele.id || ele.id === '') {\n\t\t\tif (!ele.parentElement) break;\n\t\t\tele = ele.parentElement;\n\t\t}\n\t\tif (ele.id === 'overlays' || !ele.id || ele.id === '') return;\n\t\treturn ele.id;\n\t};\n\n\tprivate readonly dispose = () => this.pointeract.dispose();\n}\n"],"mappings":"iXAoCA,IAAqB,EAArB,cAAgD,CAAkC,CACjF,WACA,GACA,QAAU,GAAgC,CAE1C,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,IAAM,EAAU,OAAO,OAAO,KAAK,QAAQ,YAAc,EAAE,CAAE,CAC5D,iBAAkB,WAClB,QAAS,KAAK,GAAG,KAAK,UACtB,WAAY,CAAE,KAAA,EAAM,IAAA,EAAK,KAAA,EAAM,CAC/B,CAA4C,CAC7C,KAAK,WAAa,IAAI,EAAW,EAAS,CACzC,EACA,EACA,EACA,EACA,EACA,EACA,CAAC,CACF,IAAM,EAAK,KAAK,UAAU,IAAI,EAAe,CAC7C,EAAG,mBAAmB,UAAU,KAAK,aAAa,CAClD,EAAG,iBAAiB,UAAU,KAAK,cAAc,CAEjD,KAAK,QAAQ,CACZ,IAAK,KAAK,IACV,YAAa,KAAK,YAClB,KAAM,KAAK,KACX,YAAa,KAAK,YAClB,CAAC,CACF,KAAK,QAAQ,KAAK,MAAM,CACxB,KAAK,UAAU,KAAK,QAAQ,CAG7B,UAA+B,CAC9B,KAAK,WACH,GAAG,MAAO,KAAK,MAAM,CACrB,GAAG,OAAQ,KAAK,MAAM,CACtB,GAAG,OAAQ,KAAK,OAAO,CACvB,GAAG,YAAa,KAAK,YAAY,CACjC,OAAO,EAGV,kBAAuC,CACtC,KAAK,WAAW,OAAO,EAExB,iBAAsC,CACrC,KAAK,WAAW,MAAM,EAGvB,MAA0B,GAA+B,CACxD,KAAK,QAAQ,CACZ,EAAG,EAAM,OACT,EAAG,EAAM,OACT,CAAC,EAEH,OAA2B,GAAgC,CAC1D,KAAK,SAAS,EAAM,OAAQ,EAAM,EAGnC,UAAY,EAAiB,IAAwB,CACpD,IAAM,EAAW,KAAK,IAAI,KAAK,IAAI,KAAK,GAAG,KAAK,MAAQ,EAAS,GAAG,CAAE,IAAK,CAE3E,GAAI,IADU,KAAK,GAAG,KAAK,MACH,OACxB,IAAM,EAAS,EAAW,KAAK,GAAG,KAAK,MACjC,EAAe,KAAK,IAAI,EAAO,CACrC,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,EAAa,EAAI,EACnD,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,EAAa,EAAI,EACnD,KAAK,GAAG,KAAK,MAAQ,GAEtB,SAAW,CAAE,IAAG,OAAqB,CACpC,KAAK,GAAG,KAAK,SAAW,EACxB,KAAK,GAAG,KAAK,SAAW,GAGzB,MAAQ,EAAiB,IAAwB,CAChD,KAAK,WAAW,SAAS,OAAQ,CAAE,OAAQ,EAAS,GAAG,EAAQ,CAAC,EAEjE,KAAO,CAAE,IAAG,OAAqB,CAChC,KAAK,WAAW,SAAS,MAAO,CAAE,OAAQ,EAAG,OAAQ,EAAG,CAAC,EAE1D,aAAe,EAAkB,IAAwB,CACxD,IAAM,EAAS,EAAW,KAAK,GAAG,KAAK,MACvC,KAAK,WAAW,SAAS,OAAQ,CAAE,SAAQ,GAAG,EAAQ,CAAC,EAExD,aAAe,CAAE,IAAG,OAAqB,CACxC,KAAK,WAAW,SAAS,MAAO,CAC/B,OAAQ,EAAI,KAAK,GAAG,KAAK,QACzB,OAAQ,EAAI,KAAK,GAAG,KAAK,QACzB,CAAC,EAIH,KAAwB,CAAE,EAAG,EAAY,EAAG,MAA+B,CAC1E,EAAG,EAAa,KAAK,GAAG,KAAK,QAC7B,EAAG,EAAa,KAAK,GAAG,KAAK,QAC7B,EAED,YAAgC,GAAiC,CAChE,IAAM,EAAU,EAAE,OAAU,EAAE,OAAyB,IAAA,GACvD,GAAI,KAAK,YAAY,EAAQ,CAAE,OAC/B,IAAM,EAAO,KAAK,WAAW,EAAQ,CACrC,KAAK,QAAQ,EAAK,EAGnB,YAAgC,GAC1B,EACE,EAAO,QAAQ,YAAY,EAAI,EAAO,QAAQ,SAAS,EAAI,EAAO,QAAQ,QAAQ,CADrE,GAIrB,WAA+B,GAA0B,CACxD,GAAI,CAAC,EAAS,OACd,IAAI,EAAM,EACV,MAAO,CAAC,EAAI,IAAM,EAAI,KAAO,KACvB,EAAI,eACT,EAAM,EAAI,cAEP,OAAI,KAAO,YAAc,CAAC,EAAI,IAAM,EAAI,KAAO,IACnD,OAAO,EAAI,IAGZ,YAAiC,KAAK,WAAW,SAAS"}
@@ -30,9 +30,9 @@ type ComponentNodeMap = {
30
30
  };
31
31
  type ComponentDict = { [K in keyof ComponentNodeMap]: NodeComponentHook<ComponentNodeMap[K]> };
32
32
  declare class OverlayManager extends BaseModule<Options, Augmentation> {
33
- private _overlaysLayer;
33
+ private _overlaysLayer?;
34
34
  private overlays;
35
- private selectedId;
35
+ private selectedId?;
36
36
  private aborted;
37
37
  private eventListeners;
38
38
  private readonly DM;
@@ -1 +1 @@
1
- {"version":3,"file":"OverlayManager.js","names":[],"sources":["../../src/kernel/OverlayManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { WithBorderWidth as Color } from '$/StyleManager';\nimport type { Hook } from '$/utilities';\nimport type {\n\tJSONCanvasFileNode,\n\tJSONCanvasLinkNode,\n\tJSONCanvasNode,\n\tJSONCanvasTextNode,\n\tParser,\n} from '@repo/shared';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport InteractionHandler from '$/InteractionHandler';\nimport StyleManager from '$/StyleManager';\nimport { destroyError, makeHook } from '$/utilities';\n\ntype Options = {\n\tparser?: Parser;\n\tnodeComponents?: Partial<ComponentDict>;\n} & BaseOptions;\n\ntype Augmentation = {\n\tonNodeActive: OverlayManager['onNodeActive'];\n\tonNodeLosesActive: OverlayManager['onNodeLosesActive'];\n};\n\nconst fileRegex = {\n\taudio: /\\.(mp3|wav|ogg|opus|aac|m4a|flac)$/i,\n\timage: /\\.(png|jpg|jpeg|gif|svg|webp|avif|bmp|ico|heic|heif)$/i,\n\tmarkdown: /\\.(md|mdx|markdown|txt)$/i,\n\tvideo: /\\.(mp4|webm|ogv|mov|m3u8|mpd)$/i,\n};\n\ntype NodeComponentHook<N extends JSONCanvasNode> = (options: {\n\tcontainer: HTMLDivElement;\n\tcontent: string;\n\tnode: N;\n\tonBeforeUnmount: Hook;\n\tonActive: Hook;\n\tonLoseActive: Hook;\n}) => void | Promise<void>;\n\ntype CreateOverlayArgs =\n\t| [ComponentNodeMap['text'], string, 'text']\n\t| [ComponentNodeMap['markdown'], string, 'markdown']\n\t| [ComponentNodeMap['image'], string, 'image']\n\t| [ComponentNodeMap['audio'], string, 'audio']\n\t| [ComponentNodeMap['video'], string, 'video']\n\t| [ComponentNodeMap['link'], string, 'link'];\n\ntype ComponentNodeMap = {\n\ttext: JSONCanvasTextNode;\n\tmarkdown: JSONCanvasFileNode;\n\timage: JSONCanvasFileNode;\n\taudio: JSONCanvasFileNode;\n\tvideo: JSONCanvasFileNode;\n\tlink: JSONCanvasLinkNode;\n};\n\ntype ComponentDict = {\n\t[K in keyof ComponentNodeMap]: NodeComponentHook<ComponentNodeMap[K]>;\n};\n\nconst supportedTypes = ['markdown', 'image', 'audio', 'video'] as const;\n\nexport default class OverlayManager extends BaseModule<Options, Augmentation> {\n\tprivate _overlaysLayer: HTMLDivElement | undefined = document.createElement('div');\n\tprivate overlays: Record<string, HTMLDivElement> = {}; // { id: node } the overlays in viewport\n\tprivate selectedId: string | undefined;\n\tprivate aborted = false;\n\tprivate eventListeners: Record<string, Array<EventListener | undefined>> = {};\n\tprivate readonly DM: DataManager;\n\tprivate readonly SM: StyleManager;\n\tprivate readonly parse: Parser;\n\tprivate readonly componentDict: ComponentDict = {\n\t\taudio: ({ container, content }) => {\n\t\t\tconst audio = document.createElement('audio');\n\t\t\taudio.className = 'JCV-audio';\n\t\t\taudio.src = content;\n\t\t\taudio.controls = true;\n\t\t\tcontainer.appendChild(audio);\n\t\t},\n\t\timage: ({ container, content }) => {\n\t\t\tconst img = document.createElement('img');\n\t\t\timg.className = 'JCV-img';\n\t\t\timg.src = content;\n\t\t\timg.loading = 'lazy';\n\t\t\tcontainer.appendChild(img);\n\t\t},\n\t\tlink: ({ container, content }) => {\n\t\t\tconst iframe = document.createElement('iframe');\n\t\t\tiframe.src = content;\n\t\t\tiframe.sandbox = 'allow-scripts allow-same-origin';\n\t\t\tiframe.className = 'JCV-link-iframe';\n\t\t\tiframe.loading = 'lazy';\n\t\t\tcontainer.appendChild(iframe);\n\t\t},\n\t\tmarkdown: async ({ container, content }) => {\n\t\t\tcontainer.classList.add('JCV-markdown-content');\n\t\t\tconst parsedContentWrapper = document.createElement('div');\n\t\t\tparsedContentWrapper.textContent = 'Loading...';\n\t\t\tparsedContentWrapper.classList.add('JCV-parsed-content-wrapper');\n\t\t\tcontainer.appendChild(parsedContentWrapper);\n\t\t\tlet parsedContent: string;\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(content);\n\t\t\t\tconst result = await response.text();\n\t\t\t\tconst frontmatterMatch = /^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/.exec(result);\n\t\t\t\tparsedContent = await this.parse(frontmatterMatch ? frontmatterMatch[2] : result);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[JSON Canvas Viewer] Failed to load markdown:', error);\n\t\t\t\tparsedContent = 'Failed to load content.';\n\t\t\t}\n\t\t\tparsedContentWrapper.innerHTML = parsedContent;\n\t\t},\n\t\ttext: ({ container, content }) => {\n\t\t\tcontainer.classList.add('JCV-markdown-content');\n\t\t\tconst parsedContentWrapper = document.createElement('div');\n\t\t\tparsedContentWrapper.innerHTML = content;\n\t\t\tparsedContentWrapper.classList.add('JCV-parsed-content-wrapper');\n\t\t\tcontainer.appendChild(parsedContentWrapper);\n\t\t},\n\t\tvideo: ({ container, content }) => {\n\t\t\tconst video = document.createElement('video');\n\t\t\tvideo.className = 'JCV-video';\n\t\t\tvideo.src = content;\n\t\t\tvideo.controls = true;\n\t\t\tcontainer.appendChild(video);\n\t\t},\n\t};\n\n\tprivate get overlaysLayer() {\n\t\tif (!this._overlaysLayer) throw destroyError;\n\t\treturn this._overlaysLayer;\n\t}\n\n\tonInteractionStart = makeHook();\n\tonInteractionEnd = makeHook();\n\tonNodeActive = makeHook<[JSONCanvasNode]>();\n\tonNodeLosesActive = makeHook<[JSONCanvasNode]>();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.parse = this.options.parser ?? ((markdown: string) => markdown);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tconst controller = this.container.get(Controller);\n\t\tcontroller.onRefresh.subscribe(this.updateOverlays);\n\t\tthis.SM.onChangeTheme.subscribe(this.themeChanged);\n\n\t\tthis._overlaysLayer = document.createElement('div');\n\t\tthis._overlaysLayer.className = 'JCV-overlays';\n\t\tthis._overlaysLayer.id = 'overlays';\n\t\tthis.DM.data.container.appendChild(this.overlaysLayer);\n\n\t\tconst components = this.options.nodeComponents;\n\t\tif (components) Object.assign(this.componentDict, components);\n\n\t\tthis.augment({\n\t\t\tonNodeActive: this.onNodeActive,\n\t\t\tonNodeLosesActive: this.onNodeLosesActive,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.restart);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tthis.container.get(InteractionHandler).onClick.subscribe(this.select);\n\t\tthis.renderOverlays();\n\t};\n\n\tprivate readonly restart = () => {\n\t\tthis.clearOverlays();\n\t\tthis.renderOverlays();\n\t};\n\n\tprivate readonly renderOverlays = () => {\n\t\tconst overlayMatcher = async (node: JSONCanvasNode) => {\n\t\t\tswitch (node.type) {\n\t\t\t\tcase 'text': {\n\t\t\t\t\tthis.createOverlay(node, await this.parse(node.text), 'text');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'file': {\n\t\t\t\t\tfor (const type of supportedTypes) {\n\t\t\t\t\t\tif (!node.file.match(fileRegex[type])) continue;\n\t\t\t\t\t\tthis.createOverlay(node, node.file, type);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'link': {\n\t\t\t\t\tthis.createOverlay(node, node.url, 'link');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tObject.values(this.DM.data.nodeMap).forEach(async (node) => {\n\t\t\tawait overlayMatcher(node.ref);\n\t\t});\n\t};\n\n\tprivate readonly themeChanged = () => {\n\t\tObject.values(this.overlays).forEach((overlay) => {\n\t\t\tconst node = this.DM.data.nodeMap[overlay.id].ref;\n\t\t\tconst color = this.SM.getColor(node.color);\n\t\t\tthis.setOverlayColor(overlay, color);\n\t\t});\n\t};\n\n\tprivate readonly select = (id?: string) => {\n\t\tconst previousId = this.selectedId;\n\t\tconst previous = !previousId ? undefined : this.overlays[previousId];\n\t\tconst current = !id ? undefined : this.overlays[id];\n\t\tif (previous && previousId) {\n\t\t\tprevious.classList.remove('JCV-active');\n\t\t\tconst nodeItem = this.DM.data.nodeMap[previousId];\n\t\t\tthis.onNodeLosesActive(nodeItem.ref);\n\t\t\tnodeItem.onLoseActive?.();\n\t\t}\n\t\tif (current && id) {\n\t\t\tcurrent.classList.add('JCV-active');\n\t\t\tthis.onInteractionStart();\n\t\t\tconst nodeItem = this.DM.data.nodeMap[id];\n\t\t\tthis.onNodeActive(nodeItem.ref);\n\t\t\tnodeItem.onActive?.();\n\t\t} else this.onInteractionEnd();\n\t\tthis.selectedId = id;\n\t};\n\n\tprivate readonly updateOverlays = () => {\n\t\tconst data = this.DM.data;\n\t\tthis.overlaysLayer.style.transform = `translate(${data.offsetX}px, ${data.offsetY}px) scale(${data.scale})`;\n\t};\n\n\tprivate readonly createOverlay = (...args: CreateOverlayArgs) => {\n\t\tif (this.aborted) return;\n\t\tconst node = args[0];\n\t\tlet element = this.overlays[node.id];\n\t\tif (!element) {\n\t\t\telement = this.constructOverlay(...args);\n\t\t\tif (this.aborted) return;\n\t\t\tthis.overlaysLayer.appendChild(element);\n\t\t\tthis.overlays[node.id] = element;\n\t\t\telement.style.left = `${node.x}px`;\n\t\t\telement.style.top = `${node.y}px`;\n\t\t\telement.style.width = `${node.width}px`;\n\t\t\telement.style.height = `${node.height}px`;\n\t\t}\n\t};\n\n\tprivate readonly constructOverlay = (...args: CreateOverlayArgs) => {\n\t\tconst node = args[0];\n\t\tconst overlay = document.createElement('div');\n\t\toverlay.classList.add('JCV-overlay-container');\n\t\toverlay.id = node.id;\n\t\tthis.setOverlayColor(overlay, this.SM.getColor(node.color));\n\t\tconst contentWrapper = document.createElement('div');\n\t\tcontentWrapper.classList.add('JCV-content');\n\t\toverlay.appendChild(contentWrapper);\n\t\tconst clickLayer = document.createElement('div');\n\t\tclickLayer.className = 'JCV-click-layer';\n\t\toverlay.appendChild(clickLayer);\n\t\tconst overlayBorder = document.createElement('div');\n\t\toverlayBorder.className = 'JCV-overlay-border';\n\t\toverlay.appendChild(overlayBorder);\n\t\tconst nodeItem = this.DM.data.nodeMap[node.id];\n\n\t\tnodeItem.onActive = makeHook();\n\t\tnodeItem.onLoseActive = makeHook();\n\t\tnodeItem.onBeforeUnmount = makeHook();\n\n\t\tvoid this.componentDict[args[2]]({\n\t\t\tcontainer: contentWrapper,\n\t\t\tcontent: args[1],\n\t\t\tnode: args[0] as never,\n\t\t\tonActive: nodeItem.onActive,\n\t\t\tonBeforeUnmount: nodeItem.onBeforeUnmount,\n\t\t\tonLoseActive: nodeItem.onLoseActive,\n\t\t});\n\t\tconst onStart = () => {\n\t\t\tif (node.id === this.selectedId) this.onInteractionStart();\n\t\t};\n\t\tconst onEnd = () => {\n\t\t\tif (node.id === this.selectedId) this.onInteractionEnd();\n\t\t};\n\t\toverlay.addEventListener('pointerenter', onStart);\n\t\toverlay.addEventListener('pointerleave', onEnd);\n\t\toverlay.addEventListener('touchstart', onStart);\n\t\toverlay.addEventListener('touchend', onEnd);\n\t\tthis.eventListeners[node.id] = [onStart, onEnd];\n\t\treturn overlay;\n\t};\n\n\tprivate readonly setOverlayColor = (overlay: HTMLDivElement, color: Color) => {\n\t\tObject.entries(color).forEach(([key, value]) => {\n\t\t\toverlay.style.setProperty(`--overlay-${key}`, value);\n\t\t});\n\t};\n\n\tprivate readonly clearOverlays = () => {\n\t\tObject.entries(this.overlays).forEach(([id, overlay]) => {\n\t\t\tthis.DM.data.nodeMap[id].onBeforeUnmount?.();\n\t\t\tif (this.eventListeners[id]) {\n\t\t\t\tconst onStart = this.eventListeners[id][0];\n\t\t\t\tconst onEnd = this.eventListeners[id][1];\n\t\t\t\tif (!onStart || !onEnd) throw destroyError;\n\t\t\t\toverlay.removeEventListener('pointerenter', onStart);\n\t\t\t\toverlay.removeEventListener('pointerleave', onEnd);\n\t\t\t\toverlay.removeEventListener('touchstart', onStart);\n\t\t\t\toverlay.removeEventListener('touchend', onEnd);\n\t\t\t\tthis.eventListeners[id][0] = undefined;\n\t\t\t\tthis.eventListeners[id][1] = undefined;\n\t\t\t}\n\t\t\toverlay.remove();\n\t\t\tdelete this.overlays[id];\n\t\t});\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tthis.aborted = true;\n\t\tthis.clearOverlays();\n\t\tthis.overlaysLayer.remove();\n\t\tthis._overlaysLayer = undefined;\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"OverlayManager.js","names":[],"sources":["../../src/kernel/OverlayManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { WithBorderWidth as Color } from '$/StyleManager';\nimport type { Hook } from '$/utilities';\nimport type {\n\tJSONCanvasFileNode,\n\tJSONCanvasLinkNode,\n\tJSONCanvasNode,\n\tJSONCanvasTextNode,\n\tParser,\n} from '@repo/shared';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport InteractionHandler from '$/InteractionHandler';\nimport StyleManager from '$/StyleManager';\nimport { destroyError, makeHook } from '$/utilities';\n\ntype Options = {\n\tparser?: Parser;\n\tnodeComponents?: Partial<ComponentDict>;\n} & BaseOptions;\n\ntype Augmentation = {\n\tonNodeActive: OverlayManager['onNodeActive'];\n\tonNodeLosesActive: OverlayManager['onNodeLosesActive'];\n};\n\nconst fileRegex = {\n\taudio: /\\.(mp3|wav|ogg|opus|aac|m4a|flac)$/i,\n\timage: /\\.(png|jpg|jpeg|gif|svg|webp|avif|bmp|ico|heic|heif)$/i,\n\tmarkdown: /\\.(md|mdx|markdown|txt)$/i,\n\tvideo: /\\.(mp4|webm|ogv|mov|m3u8|mpd)$/i,\n};\n\ntype NodeComponentHook<N extends JSONCanvasNode> = (options: {\n\tcontainer: HTMLDivElement;\n\tcontent: string;\n\tnode: N;\n\tonBeforeUnmount: Hook;\n\tonActive: Hook;\n\tonLoseActive: Hook;\n}) => void | Promise<void>;\n\ntype CreateOverlayArgs =\n\t| [ComponentNodeMap['text'], string, 'text']\n\t| [ComponentNodeMap['markdown'], string, 'markdown']\n\t| [ComponentNodeMap['image'], string, 'image']\n\t| [ComponentNodeMap['audio'], string, 'audio']\n\t| [ComponentNodeMap['video'], string, 'video']\n\t| [ComponentNodeMap['link'], string, 'link'];\n\ntype ComponentNodeMap = {\n\ttext: JSONCanvasTextNode;\n\tmarkdown: JSONCanvasFileNode;\n\timage: JSONCanvasFileNode;\n\taudio: JSONCanvasFileNode;\n\tvideo: JSONCanvasFileNode;\n\tlink: JSONCanvasLinkNode;\n};\n\ntype ComponentDict = {\n\t[K in keyof ComponentNodeMap]: NodeComponentHook<ComponentNodeMap[K]>;\n};\n\nconst supportedTypes = ['markdown', 'image', 'audio', 'video'] as const;\n\nexport default class OverlayManager extends BaseModule<Options, Augmentation> {\n\tprivate _overlaysLayer?: HTMLDivElement = document.createElement('div');\n\tprivate overlays: Record<string, HTMLDivElement> = {}; // { id: node } the overlays in viewport\n\tprivate selectedId?: string;\n\tprivate aborted = false;\n\tprivate eventListeners: Record<string, Array<EventListener | undefined>> = {};\n\tprivate readonly DM: DataManager;\n\tprivate readonly SM: StyleManager;\n\tprivate readonly parse: Parser;\n\tprivate readonly componentDict: ComponentDict = {\n\t\taudio: ({ container, content }) => {\n\t\t\tconst audio = document.createElement('audio');\n\t\t\taudio.className = 'JCV-audio';\n\t\t\taudio.src = content;\n\t\t\taudio.controls = true;\n\t\t\tcontainer.appendChild(audio);\n\t\t},\n\t\timage: ({ container, content }) => {\n\t\t\tconst img = document.createElement('img');\n\t\t\timg.className = 'JCV-img';\n\t\t\timg.src = content;\n\t\t\timg.loading = 'lazy';\n\t\t\tcontainer.appendChild(img);\n\t\t},\n\t\tlink: ({ container, content }) => {\n\t\t\tconst iframe = document.createElement('iframe');\n\t\t\tiframe.src = content;\n\t\t\tiframe.sandbox = 'allow-scripts allow-same-origin';\n\t\t\tiframe.className = 'JCV-link-iframe';\n\t\t\tiframe.loading = 'lazy';\n\t\t\tcontainer.appendChild(iframe);\n\t\t},\n\t\tmarkdown: async ({ container, content }) => {\n\t\t\tcontainer.classList.add('JCV-markdown-content');\n\t\t\tconst parsedContentWrapper = document.createElement('div');\n\t\t\tparsedContentWrapper.textContent = 'Loading...';\n\t\t\tparsedContentWrapper.classList.add('JCV-parsed-content-wrapper');\n\t\t\tcontainer.appendChild(parsedContentWrapper);\n\t\t\tlet parsedContent: string;\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(content);\n\t\t\t\tconst result = await response.text();\n\t\t\t\tconst frontmatterMatch = /^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/.exec(result);\n\t\t\t\tparsedContent = await this.parse(frontmatterMatch ? frontmatterMatch[2] : result);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[JSON Canvas Viewer] Failed to load markdown:', error);\n\t\t\t\tparsedContent = 'Failed to load content.';\n\t\t\t}\n\t\t\tparsedContentWrapper.innerHTML = parsedContent;\n\t\t},\n\t\ttext: ({ container, content }) => {\n\t\t\tcontainer.classList.add('JCV-markdown-content');\n\t\t\tconst parsedContentWrapper = document.createElement('div');\n\t\t\tparsedContentWrapper.innerHTML = content;\n\t\t\tparsedContentWrapper.classList.add('JCV-parsed-content-wrapper');\n\t\t\tcontainer.appendChild(parsedContentWrapper);\n\t\t},\n\t\tvideo: ({ container, content }) => {\n\t\t\tconst video = document.createElement('video');\n\t\t\tvideo.className = 'JCV-video';\n\t\t\tvideo.src = content;\n\t\t\tvideo.controls = true;\n\t\t\tcontainer.appendChild(video);\n\t\t},\n\t};\n\n\tprivate get overlaysLayer() {\n\t\tif (!this._overlaysLayer) throw destroyError;\n\t\treturn this._overlaysLayer;\n\t}\n\n\tonInteractionStart = makeHook();\n\tonInteractionEnd = makeHook();\n\tonNodeActive = makeHook<[JSONCanvasNode]>();\n\tonNodeLosesActive = makeHook<[JSONCanvasNode]>();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.parse = this.options.parser ?? ((markdown: string) => markdown);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tconst controller = this.container.get(Controller);\n\t\tcontroller.onRefresh.subscribe(this.updateOverlays);\n\t\tthis.SM.onChangeTheme.subscribe(this.themeChanged);\n\n\t\tthis._overlaysLayer = document.createElement('div');\n\t\tthis._overlaysLayer.className = 'JCV-overlays';\n\t\tthis._overlaysLayer.id = 'overlays';\n\t\tthis.DM.data.container.appendChild(this.overlaysLayer);\n\n\t\tconst components = this.options.nodeComponents;\n\t\tif (components) Object.assign(this.componentDict, components);\n\n\t\tthis.augment({\n\t\t\tonNodeActive: this.onNodeActive,\n\t\t\tonNodeLosesActive: this.onNodeLosesActive,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.restart);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tthis.container.get(InteractionHandler).onClick.subscribe(this.select);\n\t\tthis.renderOverlays();\n\t};\n\n\tprivate readonly restart = () => {\n\t\tthis.clearOverlays();\n\t\tthis.renderOverlays();\n\t};\n\n\tprivate readonly renderOverlays = () => {\n\t\tconst overlayMatcher = async (node: JSONCanvasNode) => {\n\t\t\tswitch (node.type) {\n\t\t\t\tcase 'text': {\n\t\t\t\t\tthis.createOverlay(node, await this.parse(node.text), 'text');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'file': {\n\t\t\t\t\tfor (const type of supportedTypes) {\n\t\t\t\t\t\tif (!node.file.match(fileRegex[type])) continue;\n\t\t\t\t\t\tthis.createOverlay(node, node.file, type);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'link': {\n\t\t\t\t\tthis.createOverlay(node, node.url, 'link');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tObject.values(this.DM.data.nodeMap).forEach(async (node) => {\n\t\t\tawait overlayMatcher(node.ref);\n\t\t});\n\t};\n\n\tprivate readonly themeChanged = () => {\n\t\tObject.values(this.overlays).forEach((overlay) => {\n\t\t\tconst node = this.DM.data.nodeMap[overlay.id].ref;\n\t\t\tconst color = this.SM.getColor(node.color);\n\t\t\tthis.setOverlayColor(overlay, color);\n\t\t});\n\t};\n\n\tprivate readonly select = (id?: string) => {\n\t\tconst previousId = this.selectedId;\n\t\tconst previous = previousId ? this.overlays[previousId] : undefined;\n\t\tconst current = id ? this.overlays[id] : undefined;\n\t\tif (previous && previousId) {\n\t\t\tprevious.classList.remove('JCV-active');\n\t\t\tconst nodeItem = this.DM.data.nodeMap[previousId];\n\t\t\tthis.onNodeLosesActive(nodeItem.ref);\n\t\t\tnodeItem.onLoseActive?.();\n\t\t}\n\t\tif (current && id) {\n\t\t\tcurrent.classList.add('JCV-active');\n\t\t\tthis.onInteractionStart();\n\t\t\tconst nodeItem = this.DM.data.nodeMap[id];\n\t\t\tthis.onNodeActive(nodeItem.ref);\n\t\t\tnodeItem.onActive?.();\n\t\t} else this.onInteractionEnd();\n\t\tthis.selectedId = id;\n\t};\n\n\tprivate readonly updateOverlays = () => {\n\t\tconst data = this.DM.data;\n\t\tthis.overlaysLayer.style.transform = `translate(${data.offsetX}px, ${data.offsetY}px) scale(${data.scale})`;\n\t};\n\n\tprivate readonly createOverlay = (...args: CreateOverlayArgs) => {\n\t\tif (this.aborted) return;\n\t\tconst node = args[0];\n\t\tlet element = this.overlays[node.id];\n\t\tif (!element) {\n\t\t\telement = this.constructOverlay(...args);\n\t\t\tif (this.aborted) return;\n\t\t\tthis.overlaysLayer.appendChild(element);\n\t\t\tthis.overlays[node.id] = element;\n\t\t\telement.style.left = `${node.x}px`;\n\t\t\telement.style.top = `${node.y}px`;\n\t\t\telement.style.width = `${node.width}px`;\n\t\t\telement.style.height = `${node.height}px`;\n\t\t}\n\t};\n\n\tprivate readonly constructOverlay = (...args: CreateOverlayArgs) => {\n\t\tconst node = args[0];\n\t\tconst overlay = document.createElement('div');\n\t\toverlay.classList.add('JCV-overlay-container');\n\t\toverlay.id = node.id;\n\t\tthis.setOverlayColor(overlay, this.SM.getColor(node.color));\n\t\tconst contentWrapper = document.createElement('div');\n\t\tcontentWrapper.classList.add('JCV-content');\n\t\toverlay.appendChild(contentWrapper);\n\t\tconst clickLayer = document.createElement('div');\n\t\tclickLayer.className = 'JCV-click-layer';\n\t\toverlay.appendChild(clickLayer);\n\t\tconst overlayBorder = document.createElement('div');\n\t\toverlayBorder.className = 'JCV-overlay-border';\n\t\toverlay.appendChild(overlayBorder);\n\t\tconst nodeItem = this.DM.data.nodeMap[node.id];\n\n\t\tnodeItem.onActive = makeHook();\n\t\tnodeItem.onLoseActive = makeHook();\n\t\tnodeItem.onBeforeUnmount = makeHook();\n\n\t\tvoid this.componentDict[args[2]]({\n\t\t\tcontainer: contentWrapper,\n\t\t\tcontent: args[1],\n\t\t\tnode: args[0] as never,\n\t\t\tonActive: nodeItem.onActive,\n\t\t\tonBeforeUnmount: nodeItem.onBeforeUnmount,\n\t\t\tonLoseActive: nodeItem.onLoseActive,\n\t\t});\n\t\tconst onStart = () => {\n\t\t\tif (node.id === this.selectedId) this.onInteractionStart();\n\t\t};\n\t\tconst onEnd = () => {\n\t\t\tif (node.id === this.selectedId) this.onInteractionEnd();\n\t\t};\n\t\toverlay.addEventListener('pointerenter', onStart);\n\t\toverlay.addEventListener('pointerleave', onEnd);\n\t\toverlay.addEventListener('touchstart', onStart);\n\t\toverlay.addEventListener('touchend', onEnd);\n\t\tthis.eventListeners[node.id] = [onStart, onEnd];\n\t\treturn overlay;\n\t};\n\n\tprivate readonly setOverlayColor = (overlay: HTMLDivElement, color: Color) => {\n\t\tObject.entries(color).forEach(([key, value]) => {\n\t\t\toverlay.style.setProperty(`--overlay-${key}`, value);\n\t\t});\n\t};\n\n\tprivate readonly clearOverlays = () => {\n\t\tObject.entries(this.overlays).forEach(([id, overlay]) => {\n\t\t\tthis.DM.data.nodeMap[id].onBeforeUnmount?.();\n\t\t\tif (this.eventListeners[id]) {\n\t\t\t\tconst onStart = this.eventListeners[id][0];\n\t\t\t\tconst onEnd = this.eventListeners[id][1];\n\t\t\t\tif (!onStart || !onEnd) throw destroyError;\n\t\t\t\toverlay.removeEventListener('pointerenter', onStart);\n\t\t\t\toverlay.removeEventListener('pointerleave', onEnd);\n\t\t\t\toverlay.removeEventListener('touchstart', onStart);\n\t\t\t\toverlay.removeEventListener('touchend', onEnd);\n\t\t\t\tthis.eventListeners[id][0] = undefined;\n\t\t\t\tthis.eventListeners[id][1] = undefined;\n\t\t\t}\n\t\t\toverlay.remove();\n\t\t\tdelete this.overlays[id];\n\t\t});\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tthis.aborted = true;\n\t\tthis.clearOverlays();\n\t\tthis.overlaysLayer.remove();\n\t\tthis._overlaysLayer = undefined;\n\t};\n}\n"],"mappings":"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"}
@@ -6,7 +6,7 @@ type Options = {
6
6
  zoomInOptimization?: boolean;
7
7
  } & BaseOptions;
8
8
  declare class Renderer extends BaseModule<Options> {
9
- private _canvas;
9
+ private _canvas?;
10
10
  private readonly ctx;
11
11
  private readonly DM;
12
12
  private readonly SM;
@@ -1,3 +1,3 @@
1
- import{BaseModule as e}from"./BaseModule.js";import{destroyError as t,drawRoundRect as n,getAnchorCoord as r,resizeCanvasForDPR as i}from"./utilities.js";import a from"./DataManager.js";import o from"./StyleManager.js";import s from"./Controller.js";var c=class extends e{_canvas;ctx;DM;SM;zoomInOptimize={lastCallTime:0,lastDrawnScale:0,lastDrawnViewport:{bottom:0,left:0,right:0,top:0},timeout:void 0};get canvas(){if(!this._canvas)throw t;return this._canvas}constructor(...e){super(...e);let t=this.container.get(s);this.SM=this.container.get(o),t.onRefresh.subscribe(this.redraw),t.onResize.subscribe(this.optimizeDPR),this.DM=this.container.get(a),this._canvas=document.createElement(`canvas`),this._canvas.className=`JCV-main-canvas`,this.ctx=this._canvas.getContext(`2d`),this.DM.data.container.appendChild(this._canvas),this.onDispose(this.dispose)}optimizeDPR=()=>{let e=this.DM.data.container;i(this.canvas,e.offsetWidth,e.offsetHeight)};redraw=()=>{let e=this.DM.data.offsetX,t=this.DM.data.offsetY,n=this.DM.data.scale,r=this.getCurrentViewport(e,t,n);if(!this.options.zoomInOptimization){this.trueRedraw(e,t,n,r);return}this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=void 0);let i=Date.now();if(this.isInside(r,this.zoomInOptimize.lastDrawnViewport)&&n!==this.zoomInOptimize.lastDrawnScale&&i-this.zoomInOptimize.lastCallTime<500){this.zoomInOptimize.timeout=window.setTimeout(()=>{this.trueRedraw(e,t,n,r),this.zoomInOptimize.lastCallTime=i,this.zoomInOptimize.timeout=void 0},60),this.fakeRedraw(r,n);return}this.zoomInOptimize.lastCallTime=i,this.trueRedraw(e,t,n,r)};trueRedraw(e,t,n,r){this.zoomInOptimize.lastDrawnViewport=r,this.zoomInOptimize.lastDrawnScale=n,this.canvas.style.transform=``,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.save(),this.drawGridDots(n,e,t),this.ctx.translate(e,t),this.ctx.scale(n,n),Object.values(this.DM.data.nodeMap).forEach(e=>{if(this.isOutside(e.box,r))return;let t=e.ref;t.type===`file`?this.drawFile(e):t.type===`group`&&this.drawGroup(t,n)}),Object.values(this.DM.data.edgeMap).forEach(e=>{this.isOutside(e.box,r)||this.drawEdge(e)}),this.ctx.restore()}fakeRedraw(e,t){let n=t/this.zoomInOptimize.lastDrawnScale,r=(this.zoomInOptimize.lastDrawnViewport.left-e.left)*t,i=(this.zoomInOptimize.lastDrawnViewport.top-e.top)*t;this.canvas.style.transform=`translate(${r}px, ${i}px) scale(${n})`}isInside=(e,t)=>e.left>t.left&&e.top>t.top&&e.right<t.right&&e.bottom<t.bottom;isOutside=(e,t)=>e.right<t.left||e.bottom<t.top||e.left>t.right||e.top>t.bottom;getCurrentViewport=(e,t,n)=>{let r=-e/n,i=-t/n,a=this.DM.data.container,o=r+a.clientWidth/n;return{bottom:i+a.clientHeight/n,left:r,right:o,top:i}};drawLabelBar=(e,t,n,r,i,a)=>{let o=30*a,s=6*a,c=8*a,l=16*a,u=6*a;this.ctx.save(),this.ctx.translate(e,t),this.ctx.scale(1/a,1/a),this.ctx.font=`${l}px 'Inter', sans-serif`;let d=this.ctx.measureText(n).width+2*u;this.ctx.translate(0,-o-c),this.ctx.fillStyle=r,this.ctx.beginPath(),this.ctx.moveTo(s,0),this.ctx.lineTo(d-s,0),this.ctx.quadraticCurveTo(d,0,d,s),this.ctx.lineTo(d,o-s),this.ctx.quadraticCurveTo(d,o,d-s,o),this.ctx.lineTo(s,o),this.ctx.quadraticCurveTo(0,o,0,o-s),this.ctx.lineTo(0,s),this.ctx.quadraticCurveTo(0,0,s,0),this.ctx.closePath(),this.ctx.fill(),this.ctx.fillStyle=i,this.ctx.fillText(n,u,o*.65),this.ctx.restore()};drawNodeBackground=e=>{let t=this.SM.getColor(e.color);this.ctx.globalAlpha=1,this.ctx.fillStyle=t.background,n(this.ctx,e.x+1,e.y+1,e.width-2,e.height-2,12),this.ctx.fill(),this.ctx.strokeStyle=t.border,this.ctx.lineWidth=2,n(this.ctx,e.x,e.y,e.width,e.height,12),this.ctx.stroke()};drawGroup=(e,t)=>{if(this.drawNodeBackground(e),e.label){let n=this.SM.getColor(e.color);this.drawLabelBar(e.x,e.y,e.label,n.active,n.text,t)}};drawFile=e=>{this.ctx.fillStyle=this.SM.getColor().text;let t=e.ref;this.ctx.font=`16px sans-serif`,this.ctx.fillText(e.fileName??``,t.x+5,t.y-10)};drawEdge=e=>{let t=e.ref,n=this.DM.data.nodeMap[t.fromNode].ref,i=this.DM.data.nodeMap[t.toNode].ref,{x:a,y:o}=r(n,t.fromSide),{x:s,y:c}=r(i,t.toSide),l=this.SM.getColor(t.color),u,d,f,p;e.controlPoints?[u,d,f,p]=e.controlPoints:([u,d,f,p]=this.getControlPoints(a,o,s,c,t.fromSide,t.toSide),e.controlPoints=[u,d,f,p]),this.drawCurvedPath(a,o,s,c,u,d,f,p,l.active),this.drawArrowhead(s,c,f,p,l.active),t.label&&this.drawEdgeLabel(a,o,s,c,u,d,f,p,t.label,l.active,l.text)};drawEdgeLabel=(e,t,r,i,a,o,s,c,l,u,d)=>{let f=.5,p=(1-f)**3*e+3*(1-f)**2*f*a+3*(1-f)*f*f*s+f**3*r,m=(1-f)**3*t+3*(1-f)**2*f*o+3*(1-f)*f*f*c+f**3*i;this.ctx.font=`18px sans-serif`;let h=l.split(`
1
+ import{BaseModule as e}from"./BaseModule.js";import{destroyError as t,drawRoundRect as n,getAnchorCoord as r,resizeCanvasForDPR as i}from"./utilities.js";import a from"./DataManager.js";import o from"./StyleManager.js";import s from"./Controller.js";var c=class extends e{_canvas;ctx;DM;SM;zoomInOptimize={lastCallTime:0,lastDrawnScale:0,lastDrawnViewport:{bottom:0,left:0,right:0,top:0}};get canvas(){if(!this._canvas)throw t;return this._canvas}constructor(...e){super(...e);let t=this.container.get(s);this.SM=this.container.get(o),t.onRefresh.subscribe(this.redraw),t.onResize.subscribe(this.optimizeDPR),this.DM=this.container.get(a),this._canvas=document.createElement(`canvas`),this._canvas.className=`JCV-main-canvas`,this.ctx=this._canvas.getContext(`2d`),this.DM.data.container.appendChild(this._canvas),this.onDispose(this.dispose)}optimizeDPR=()=>{let e=this.DM.data.container;i(this.canvas,e.offsetWidth,e.offsetHeight)};redraw=()=>{let e=this.DM.data.offsetX,t=this.DM.data.offsetY,n=this.DM.data.scale,r=this.getCurrentViewport(e,t,n);if(!this.options.zoomInOptimization){this.trueRedraw(e,t,n,r);return}this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=void 0);let i=Date.now();if(this.isInside(r,this.zoomInOptimize.lastDrawnViewport)&&n!==this.zoomInOptimize.lastDrawnScale&&i-this.zoomInOptimize.lastCallTime<500){this.zoomInOptimize.timeout=window.setTimeout(()=>{this.trueRedraw(e,t,n,r),this.zoomInOptimize.lastCallTime=i,this.zoomInOptimize.timeout=void 0},60),this.fakeRedraw(r,n);return}this.zoomInOptimize.lastCallTime=i,this.trueRedraw(e,t,n,r)};trueRedraw(e,t,n,r){this.zoomInOptimize.lastDrawnViewport=r,this.zoomInOptimize.lastDrawnScale=n,this.canvas.style.transform=``,this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.save(),this.drawGridDots(n,e,t),this.ctx.translate(e,t),this.ctx.scale(n,n),Object.values(this.DM.data.nodeMap).forEach(e=>{if(this.isOutside(e.box,r))return;let t=e.ref;t.type===`file`?this.drawFile(e):t.type===`group`&&this.drawGroup(t,n)}),Object.values(this.DM.data.edgeMap).forEach(e=>{this.isOutside(e.box,r)||this.drawEdge(e)}),this.ctx.restore()}fakeRedraw(e,t){let n=t/this.zoomInOptimize.lastDrawnScale,r=(this.zoomInOptimize.lastDrawnViewport.left-e.left)*t,i=(this.zoomInOptimize.lastDrawnViewport.top-e.top)*t;this.canvas.style.transform=`translate(${r}px, ${i}px) scale(${n})`}isInside=(e,t)=>e.left>t.left&&e.top>t.top&&e.right<t.right&&e.bottom<t.bottom;isOutside=(e,t)=>e.right<t.left||e.bottom<t.top||e.left>t.right||e.top>t.bottom;getCurrentViewport=(e,t,n)=>{let r=-e/n,i=-t/n,a=this.DM.data.container,o=r+a.clientWidth/n;return{bottom:i+a.clientHeight/n,left:r,right:o,top:i}};drawLabelBar=(e,t,n,r,i,a)=>{let o=30*a,s=6*a,c=8*a,l=16*a,u=6*a;this.ctx.save(),this.ctx.translate(e,t),this.ctx.scale(1/a,1/a),this.ctx.font=`${l}px 'Inter', sans-serif`;let d=this.ctx.measureText(n).width+2*u;this.ctx.translate(0,-o-c),this.ctx.fillStyle=r,this.ctx.beginPath(),this.ctx.moveTo(s,0),this.ctx.lineTo(d-s,0),this.ctx.quadraticCurveTo(d,0,d,s),this.ctx.lineTo(d,o-s),this.ctx.quadraticCurveTo(d,o,d-s,o),this.ctx.lineTo(s,o),this.ctx.quadraticCurveTo(0,o,0,o-s),this.ctx.lineTo(0,s),this.ctx.quadraticCurveTo(0,0,s,0),this.ctx.closePath(),this.ctx.fill(),this.ctx.fillStyle=i,this.ctx.fillText(n,u,o*.65),this.ctx.restore()};drawNodeBackground=e=>{let t=this.SM.getColor(e.color);this.ctx.globalAlpha=1,this.ctx.fillStyle=t.background,n(this.ctx,e.x+1,e.y+1,e.width-2,e.height-2,12),this.ctx.fill(),this.ctx.strokeStyle=t.border,this.ctx.lineWidth=2,n(this.ctx,e.x,e.y,e.width,e.height,12),this.ctx.stroke()};drawGroup=(e,t)=>{if(this.drawNodeBackground(e),e.label){let n=this.SM.getColor(e.color);this.drawLabelBar(e.x,e.y,e.label,n.active,n.text,t)}};drawFile=e=>{this.ctx.fillStyle=this.SM.getColor().text;let t=e.ref;this.ctx.font=`16px sans-serif`,this.ctx.fillText(e.fileName??``,t.x+5,t.y-10)};drawEdge=e=>{let t=e.ref,n=this.DM.data.nodeMap[t.fromNode].ref,i=this.DM.data.nodeMap[t.toNode].ref,{x:a,y:o}=r(n,t.fromSide),{x:s,y:c}=r(i,t.toSide),l=this.SM.getColor(t.color),u,d,f,p;e.controlPoints?[u,d,f,p]=e.controlPoints:([u,d,f,p]=this.getControlPoints(a,o,s,c,t.fromSide,t.toSide),e.controlPoints=[u,d,f,p]),this.drawCurvedPath(a,o,s,c,u,d,f,p,l.active),this.drawArrowhead(s,c,f,p,l.active),t.label&&this.drawEdgeLabel(a,o,s,c,u,d,f,p,t.label,l.active,l.text)};drawEdgeLabel=(e,t,r,i,a,o,s,c,l,u,d)=>{let f=.5,p=(1-f)**3*e+3*(1-f)**2*f*a+3*(1-f)*f*f*s+f**3*r,m=(1-f)**3*t+3*(1-f)**2*f*o+3*(1-f)*f*f*c+f**3*i;this.ctx.font=`18px sans-serif`;let h=l.split(`
2
2
  `),g=0;for(let e of h){let t=this.ctx.measureText(e).width;t>g&&(g=t)}let _=g+16,v=h.length*17+6;this.ctx.fillStyle=u,this.ctx.beginPath(),n(this.ctx,p-_/2,m-v/2-2,_,v,4),this.ctx.fill(),this.ctx.fillStyle=d,this.ctx.textAlign=`center`,this.ctx.textBaseline=`middle`;for(let e=0;e<h.length;e++){let t=(e-(h.length-1)/2)*17;this.ctx.fillText(h[e],p,m-2+t)}this.ctx.textAlign=`left`,this.ctx.textBaseline=`alphabetic`};getControlPoints=(e,t,n,r,i,a)=>{let o=n-e,s=r-t,c=((e,t,n)=>Math.max(t,Math.min(n,e)))((Math.min(Math.abs(o),Math.abs(s))+.3*Math.max(Math.abs(o),Math.abs(s)))*.5,60,300),l=e,u=t,d=n,f=r;switch(i){case`top`:u=t-c;break;case`bottom`:u=t+c;break;case`left`:l=e-c;break;case`right`:l=e+c;break}switch(a){case`top`:f=r-c;break;case`bottom`:f=r+c;break;case`left`:d=n-c;break;case`right`:d=n+c;break}return[l,u,d,f]};drawGridDots=(e,t,n)=>{let r=10*2**-Math.floor(Math.log2(e))*e,i=this.canvas.width,a=this.canvas.height,o=t%r,s=n%r;this.ctx.fillStyle=this.SM.getNamedColor(`dots`);for(let e=o;e<=i;e+=r)for(let t=s;t<=a;t+=r)this.ctx.beginPath(),this.ctx.arc(e,t,1,0,2*Math.PI),this.ctx.fill()};drawCurvedPath=(e,t,n,r,i,a,o,s,c)=>{this.ctx.beginPath(),this.ctx.moveTo(e,t),this.ctx.bezierCurveTo(i,a,o,s,n,r),this.ctx.strokeStyle=c,this.ctx.lineWidth=2,this.ctx.stroke()};drawArrowhead=(e,t,n,r,i)=>{let a=e-n,o=t-r,s=Math.sqrt(a*a+o*o);if(s===0)return;let c=a/s,l=o/s,u=e-c*12-l*4,d=t-l*12+c*4,f=e-c*12+l*4,p=t-l*12-c*4;this.ctx.beginPath(),this.ctx.fillStyle=i,this.ctx.moveTo(e,t),this.ctx.lineTo(u,d),this.ctx.lineTo(f,p),this.ctx.closePath(),this.ctx.fill()};dispose=()=>{this.zoomInOptimize.timeout&&(clearTimeout(this.zoomInOptimize.timeout),this.zoomInOptimize.timeout=void 0),this.canvas.remove(),this._canvas=void 0}};export{c as default};
3
3
  //# sourceMappingURL=Renderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Renderer.js","names":[],"sources":["../../src/kernel/Renderer.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { EdgeItem, NodeItem } from '$/DataManager';\nimport type { Box } from '$/types';\nimport type { JSONCanvasGroupNode, JSONCanvasNode } from '@repo/shared';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport StyleManager from '$/StyleManager';\nimport { destroyError, drawRoundRect, getAnchorCoord, resizeCanvasForDPR } from '$/utilities';\n\nconst ARROW_LENGTH = 12;\nconst ARROW_WIDTH = 4;\nconst NODE_RADIUS = 12;\nconst CSS_ZOOM_REDRAW_INTERVAL = 500;\nconst NODE_BORDER_WIDTH = 2;\nconst DOT_RADIUS = 1; // Dot radius in CSS pixels\nconst DOT_BASE_GAP = 10; // Base gap between dots in CSS pixels\n\nconst NODE_BORDER_HALF_WIDTH = NODE_BORDER_WIDTH / 2;\n\ntype Options = {\n\tzoomInOptimization?: boolean;\n} & BaseOptions;\n\nexport default class Renderer extends BaseModule<Options> {\n\tprivate _canvas: HTMLCanvasElement | undefined;\n\tprivate readonly ctx: CanvasRenderingContext2D;\n\tprivate readonly DM: DataManager;\n\tprivate readonly SM: StyleManager;\n\tprivate readonly zoomInOptimize: {\n\t\tlastDrawnScale: number;\n\t\tlastDrawnViewport: Box;\n\t\ttimeout: number | undefined;\n\t\tlastCallTime: number;\n\t} = {\n\t\tlastCallTime: 0,\n\t\tlastDrawnScale: 0,\n\t\tlastDrawnViewport: {\n\t\t\tbottom: 0,\n\t\t\tleft: 0,\n\t\t\tright: 0,\n\t\t\ttop: 0,\n\t\t},\n\t\ttimeout: undefined,\n\t};\n\n\tprivate get canvas() {\n\t\tif (!this._canvas) throw destroyError;\n\t\treturn this._canvas;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tconst controller = this.container.get(Controller);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tcontroller.onRefresh.subscribe(this.redraw);\n\t\tcontroller.onResize.subscribe(this.optimizeDPR);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis._canvas = document.createElement('canvas');\n\t\tthis._canvas.className = 'JCV-main-canvas';\n\t\tthis.ctx = this._canvas.getContext('2d') as CanvasRenderingContext2D;\n\t\tthis.DM.data.container.appendChild(this._canvas);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly optimizeDPR = () => {\n\t\tconst container = this.DM.data.container;\n\t\tresizeCanvasForDPR(this.canvas, container.offsetWidth, container.offsetHeight);\n\t};\n\n\tprivate readonly redraw = () => {\n\t\tconst offsetX = this.DM.data.offsetX;\n\t\tconst offsetY = this.DM.data.offsetY;\n\t\tconst scale = this.DM.data.scale;\n\t\tconst currentViewport = this.getCurrentViewport(offsetX, offsetY, scale);\n\t\tif (!this.options.zoomInOptimization) {\n\t\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t\t\treturn;\n\t\t}\n\t\tif (this.zoomInOptimize.timeout) {\n\t\t\tclearTimeout(this.zoomInOptimize.timeout);\n\t\t\tthis.zoomInOptimize.timeout = undefined;\n\t\t}\n\t\tconst now = Date.now();\n\t\tif (\n\t\t\tthis.isInside(currentViewport, this.zoomInOptimize.lastDrawnViewport) &&\n\t\t\tscale !== this.zoomInOptimize.lastDrawnScale\n\t\t) {\n\t\t\tconst timeSinceLast = now - this.zoomInOptimize.lastCallTime;\n\t\t\tif (timeSinceLast < CSS_ZOOM_REDRAW_INTERVAL) {\n\t\t\t\tthis.zoomInOptimize.timeout = window.setTimeout(() => {\n\t\t\t\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t\t\t\t\tthis.zoomInOptimize.lastCallTime = now;\n\t\t\t\t\tthis.zoomInOptimize.timeout = undefined;\n\t\t\t\t}, 60);\n\t\t\t\tthis.fakeRedraw(currentViewport, scale);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tthis.zoomInOptimize.lastCallTime = now;\n\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t};\n\n\tprivate trueRedraw(offsetX: number, offsetY: number, scale: number, currentViewport: Box) {\n\t\tthis.zoomInOptimize.lastDrawnViewport = currentViewport;\n\t\tthis.zoomInOptimize.lastDrawnScale = scale;\n\t\tthis.canvas.style.transform = '';\n\t\tthis.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n\t\tthis.ctx.save();\n\t\tthis.drawGridDots(scale, offsetX, offsetY);\n\t\tthis.ctx.translate(offsetX, offsetY);\n\t\tthis.ctx.scale(scale, scale);\n\t\tObject.values(this.DM.data.nodeMap).forEach((item) => {\n\t\t\tif (this.isOutside(item.box, currentViewport)) return;\n\t\t\tconst node = item.ref;\n\t\t\tif (node.type === 'file') this.drawFile(item);\n\t\t\telse if (node.type === 'group') this.drawGroup(node, scale);\n\t\t});\n\t\tObject.values(this.DM.data.edgeMap).forEach((item) => {\n\t\t\tif (this.isOutside(item.box, currentViewport)) return;\n\t\t\tthis.drawEdge(item);\n\t\t});\n\t\tthis.ctx.restore();\n\t}\n\n\tprivate fakeRedraw(currentViewport: Box, scale: number) {\n\t\tconst cssScale = scale / this.zoomInOptimize.lastDrawnScale;\n\t\tconst currentOffsetX =\n\t\t\t(this.zoomInOptimize.lastDrawnViewport.left - currentViewport.left) * scale;\n\t\tconst currentOffsetY =\n\t\t\t(this.zoomInOptimize.lastDrawnViewport.top - currentViewport.top) * scale;\n\t\tthis.canvas.style.transform = `translate(${currentOffsetX}px, ${currentOffsetY}px) scale(${cssScale})`;\n\t}\n\n\tprivate readonly isInside = (inner: Box, outer: Box) =>\n\t\tinner.left > outer.left &&\n\t\tinner.top > outer.top &&\n\t\tinner.right < outer.right &&\n\t\tinner.bottom < outer.bottom;\n\n\tprivate readonly isOutside = (inner: Box, outer: Box) =>\n\t\tinner.right < outer.left ||\n\t\tinner.bottom < outer.top ||\n\t\tinner.left > outer.right ||\n\t\tinner.top > outer.bottom;\n\n\tprivate readonly getCurrentViewport = (offsetX: number, offsetY: number, scale: number) => {\n\t\tconst left = -offsetX / scale;\n\t\tconst top = -offsetY / scale;\n\t\tconst container = this.DM.data.container;\n\t\tconst right = left + container.clientWidth / scale;\n\t\tconst bottom = top + container.clientHeight / scale;\n\t\treturn { bottom, left, right, top };\n\t};\n\n\tprivate readonly drawLabelBar = (\n\t\tx: number,\n\t\ty: number,\n\t\tlabel: string,\n\t\tcolor: string,\n\t\ttextColor: string,\n\t\tscale: number,\n\t) => {\n\t\tconst barHeight = 30 * scale;\n\t\tconst radius = 6 * scale;\n\t\tconst yOffset = 8 * scale;\n\t\tconst fontSize = 16 * scale;\n\t\tconst xPadding = 6 * scale;\n\t\tthis.ctx.save();\n\t\tthis.ctx.translate(x, y);\n\t\tthis.ctx.scale(1 / scale, 1 / scale);\n\t\tthis.ctx.font = `${fontSize}px 'Inter', sans-serif`;\n\t\tconst barWidth = this.ctx.measureText(label).width + 2 * xPadding;\n\t\tthis.ctx.translate(0, -barHeight - yOffset);\n\t\tthis.ctx.fillStyle = color;\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.moveTo(radius, 0);\n\t\tthis.ctx.lineTo(barWidth - radius, 0);\n\t\tthis.ctx.quadraticCurveTo(barWidth, 0, barWidth, radius);\n\t\tthis.ctx.lineTo(barWidth, barHeight - radius);\n\t\tthis.ctx.quadraticCurveTo(barWidth, barHeight, barWidth - radius, barHeight);\n\t\tthis.ctx.lineTo(radius, barHeight);\n\t\tthis.ctx.quadraticCurveTo(0, barHeight, 0, barHeight - radius);\n\t\tthis.ctx.lineTo(0, radius);\n\t\tthis.ctx.quadraticCurveTo(0, 0, radius, 0);\n\t\tthis.ctx.closePath();\n\t\tthis.ctx.fill();\n\t\tthis.ctx.fillStyle = textColor;\n\t\tthis.ctx.fillText(label, xPadding, barHeight * 0.65);\n\t\tthis.ctx.restore();\n\t};\n\n\tprivate readonly drawNodeBackground = (node: JSONCanvasNode) => {\n\t\tconst colors = this.SM.getColor(node.color);\n\t\tconst radius = NODE_RADIUS;\n\t\tthis.ctx.globalAlpha = 1;\n\t\tthis.ctx.fillStyle = colors.background;\n\t\tdrawRoundRect(\n\t\t\tthis.ctx,\n\t\t\tnode.x + NODE_BORDER_HALF_WIDTH,\n\t\t\tnode.y + NODE_BORDER_HALF_WIDTH,\n\t\t\tnode.width - NODE_BORDER_WIDTH,\n\t\t\tnode.height - NODE_BORDER_WIDTH,\n\t\t\tradius,\n\t\t);\n\t\tthis.ctx.fill();\n\t\tthis.ctx.strokeStyle = colors.border;\n\t\tthis.ctx.lineWidth = NODE_BORDER_WIDTH;\n\t\tdrawRoundRect(this.ctx, node.x, node.y, node.width, node.height, radius);\n\t\tthis.ctx.stroke();\n\t};\n\n\tprivate readonly drawGroup = (node: JSONCanvasGroupNode, scale: number) => {\n\t\tthis.drawNodeBackground(node);\n\t\tif (node.label) {\n\t\t\tconst color = this.SM.getColor(node.color);\n\t\t\tthis.drawLabelBar(node.x, node.y, node.label, color.active, color.text, scale);\n\t\t}\n\t};\n\n\tprivate readonly drawFile = (item: NodeItem) => {\n\t\tthis.ctx.fillStyle = this.SM.getColor().text;\n\t\tconst node = item.ref;\n\t\tthis.ctx.font = '16px sans-serif';\n\t\tthis.ctx.fillText(item.fileName ?? '', node.x + 5, node.y - 10);\n\t};\n\n\tprivate readonly drawEdge = (item: EdgeItem) => {\n\t\tconst edge = item.ref;\n\t\tconst fromNode = this.DM.data.nodeMap[edge.fromNode].ref;\n\t\tconst toNode = this.DM.data.nodeMap[edge.toNode].ref;\n\t\tconst { x: startX, y: startY } = getAnchorCoord(fromNode, edge.fromSide);\n\t\tconst { x: endX, y: endY } = getAnchorCoord(toNode, edge.toSide);\n\t\tconst color = this.SM.getColor(edge.color);\n\t\tlet startControlX, startControlY, endControlX, endControlY: number;\n\t\tif (!item.controlPoints) {\n\t\t\t[startControlX, startControlY, endControlX, endControlY] = this.getControlPoints(\n\t\t\t\tstartX,\n\t\t\t\tstartY,\n\t\t\t\tendX,\n\t\t\t\tendY,\n\t\t\t\tedge.fromSide,\n\t\t\t\tedge.toSide,\n\t\t\t);\n\t\t\titem.controlPoints = [startControlX, startControlY, endControlX, endControlY];\n\t\t} else [startControlX, startControlY, endControlX, endControlY] = item.controlPoints;\n\t\tthis.drawCurvedPath(\n\t\t\tstartX,\n\t\t\tstartY,\n\t\t\tendX,\n\t\t\tendY,\n\t\t\tstartControlX,\n\t\t\tstartControlY,\n\t\t\tendControlX,\n\t\t\tendControlY,\n\t\t\tcolor.active,\n\t\t);\n\t\tthis.drawArrowhead(endX, endY, endControlX, endControlY, color.active);\n\t\tif (edge.label)\n\t\t\tthis.drawEdgeLabel(\n\t\t\t\tstartX,\n\t\t\t\tstartY,\n\t\t\t\tendX,\n\t\t\t\tendY,\n\t\t\t\tstartControlX,\n\t\t\t\tstartControlY,\n\t\t\t\tendControlX,\n\t\t\t\tendControlY,\n\t\t\t\tedge.label,\n\t\t\t\tcolor.active,\n\t\t\t\tcolor.text,\n\t\t\t);\n\t};\n\n\tprivate readonly drawEdgeLabel = (\n\t\tstartX: number,\n\t\tstartY: number,\n\t\tendX: number,\n\t\tendY: number,\n\t\tstartControlX: number,\n\t\tstartControlY: number,\n\t\tendControlX: number,\n\t\tendControlY: number,\n\t\tlabel: string,\n\t\tcolor: string,\n\t\ttextColor: string,\n\t) => {\n\t\tconst t = 0.5;\n\t\tconst x =\n\t\t\t(1 - t) ** 3 * startX +\n\t\t\t3 * (1 - t) ** 2 * t * startControlX +\n\t\t\t3 * (1 - t) * t * t * endControlX +\n\t\t\tt ** 3 * endX;\n\t\tconst y =\n\t\t\t(1 - t) ** 3 * startY +\n\t\t\t3 * (1 - t) ** 2 * t * startControlY +\n\t\t\t3 * (1 - t) * t * t * endControlY +\n\t\t\tt ** 3 * endY;\n\t\tthis.ctx.font = '18px sans-serif';\n\t\tconst lines = label.split('\\n');\n\t\tconst lineHeight = 17;\n\t\tlet maxWidth = 0;\n\t\tfor (const line of lines) {\n\t\t\tconst w = this.ctx.measureText(line).width;\n\t\t\tif (w > maxWidth) maxWidth = w;\n\t\t}\n\t\tconst paddingX = 8;\n\t\tconst paddingY = 3;\n\t\tconst labelWidth = maxWidth + paddingX * 2;\n\t\tconst labelHeight = lines.length * lineHeight + paddingY * 2; // Dynamic height\n\t\tthis.ctx.fillStyle = color;\n\t\tthis.ctx.beginPath();\n\t\tdrawRoundRect(\n\t\t\tthis.ctx,\n\t\t\tx - labelWidth / 2,\n\t\t\ty - labelHeight / 2 - 2,\n\t\t\tlabelWidth,\n\t\t\tlabelHeight,\n\t\t\t4,\n\t\t);\n\t\tthis.ctx.fill();\n\t\tthis.ctx.fillStyle = textColor;\n\t\tthis.ctx.textAlign = 'center';\n\t\tthis.ctx.textBaseline = 'middle';\n\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\tconst offsetY = (i - (lines.length - 1) / 2) * lineHeight;\n\t\t\tthis.ctx.fillText(lines[i], x, y - 2 + offsetY);\n\t\t}\n\t\tthis.ctx.textAlign = 'left';\n\t\tthis.ctx.textBaseline = 'alphabetic';\n\t};\n\n\tprivate readonly getControlPoints = (\n\t\tstartX: number,\n\t\tstartY: number,\n\t\tendX: number,\n\t\tendY: number,\n\t\tfromSide: string,\n\t\ttoSide: string,\n\t) => {\n\t\tconst distanceX = endX - startX;\n\t\tconst distanceY = endY - startY;\n\t\tconst realDistance =\n\t\t\tMath.min(Math.abs(distanceX), Math.abs(distanceY)) +\n\t\t\t0.3 * Math.max(Math.abs(distanceX), Math.abs(distanceY));\n\t\tconst clamp = (val: number, min: number, max: number) => Math.max(min, Math.min(max, val));\n\t\tconst PADDING = clamp(realDistance * 0.5, 60, 300);\n\t\tlet startControlX = startX;\n\t\tlet startControlY = startY;\n\t\tlet endControlX = endX;\n\t\tlet endControlY = endY;\n\t\tswitch (fromSide) {\n\t\t\tcase 'top': {\n\t\t\t\tstartControlY = startY - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'bottom': {\n\t\t\t\tstartControlY = startY + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\tstartControlX = startX - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'right': {\n\t\t\t\tstartControlX = startX + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tswitch (toSide) {\n\t\t\tcase 'top': {\n\t\t\t\tendControlY = endY - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'bottom': {\n\t\t\t\tendControlY = endY + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\tendControlX = endX - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'right': {\n\t\t\t\tendControlX = endX + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn [startControlX, startControlY, endControlX, endControlY];\n\t};\n\n\tprivate readonly drawGridDots = (scale: number, offsetX: number, offsetY: number) => {\n\t\tconst scaleLevel = -Math.floor(Math.log2(scale));\n\t\tconst actualGap = DOT_BASE_GAP * 2 ** scaleLevel * scale;\n\t\tconst width = this.canvas.width;\n\t\tconst height = this.canvas.height;\n\t\tconst startX = offsetX % actualGap;\n\t\tconst startY = offsetY % actualGap;\n\t\tthis.ctx.fillStyle = this.SM.getNamedColor('dots');\n\t\tfor (let x = startX; x <= width; x += actualGap)\n\t\t\tfor (let y = startY; y <= height; y += actualGap) {\n\t\t\t\tthis.ctx.beginPath();\n\t\t\t\tthis.ctx.arc(x, y, DOT_RADIUS, 0, 2 * Math.PI);\n\t\t\t\tthis.ctx.fill();\n\t\t\t}\n\t};\n\n\tprivate readonly drawCurvedPath = (\n\t\tstartX: number,\n\t\tstartY: number,\n\t\tendX: number,\n\t\tendY: number,\n\t\tc1x: number,\n\t\tc1y: number,\n\t\tc2x: number,\n\t\tc2y: number,\n\t\tcolor: string,\n\t) => {\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.moveTo(startX, startY);\n\t\tthis.ctx.bezierCurveTo(c1x, c1y, c2x, c2y, endX, endY);\n\t\tthis.ctx.strokeStyle = color;\n\t\tthis.ctx.lineWidth = 2;\n\t\tthis.ctx.stroke();\n\t};\n\n\tprivate readonly drawArrowhead = (\n\t\ttipX: number,\n\t\ttipY: number,\n\t\tfromX: number,\n\t\tfromY: number,\n\t\tcolor: string,\n\t) => {\n\t\tconst dx = tipX - fromX;\n\t\tconst dy = tipY - fromY;\n\t\tconst length = Math.sqrt(dx * dx + dy * dy);\n\t\tif (length === 0) return;\n\t\tconst unitX = dx / length;\n\t\tconst unitY = dy / length;\n\t\tconst leftX = tipX - unitX * ARROW_LENGTH - unitY * ARROW_WIDTH;\n\t\tconst leftY = tipY - unitY * ARROW_LENGTH + unitX * ARROW_WIDTH;\n\t\tconst rightX = tipX - unitX * ARROW_LENGTH + unitY * ARROW_WIDTH;\n\t\tconst rightY = tipY - unitY * ARROW_LENGTH - unitX * ARROW_WIDTH;\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.fillStyle = color;\n\t\tthis.ctx.moveTo(tipX, tipY);\n\t\tthis.ctx.lineTo(leftX, leftY);\n\t\tthis.ctx.lineTo(rightX, rightY);\n\t\tthis.ctx.closePath();\n\t\tthis.ctx.fill();\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tif (this.zoomInOptimize.timeout) {\n\t\t\tclearTimeout(this.zoomInOptimize.timeout);\n\t\t\tthis.zoomInOptimize.timeout = undefined;\n\t\t}\n\t\tthis.canvas.remove();\n\t\tthis._canvas = undefined;\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Renderer.js","names":[],"sources":["../../src/kernel/Renderer.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { EdgeItem, NodeItem } from '$/DataManager';\nimport type { Box } from '$/types';\nimport type { JSONCanvasGroupNode, JSONCanvasNode } from '@repo/shared';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport StyleManager from '$/StyleManager';\nimport { destroyError, drawRoundRect, getAnchorCoord, resizeCanvasForDPR } from '$/utilities';\n\nconst ARROW_LENGTH = 12;\nconst ARROW_WIDTH = 4;\nconst NODE_RADIUS = 12;\nconst CSS_ZOOM_REDRAW_INTERVAL = 500;\nconst NODE_BORDER_WIDTH = 2;\nconst DOT_RADIUS = 1; // Dot radius in CSS pixels\nconst DOT_BASE_GAP = 10; // Base gap between dots in CSS pixels\n\nconst NODE_BORDER_HALF_WIDTH = NODE_BORDER_WIDTH / 2;\n\ntype Options = {\n\tzoomInOptimization?: boolean;\n} & BaseOptions;\n\nexport default class Renderer extends BaseModule<Options> {\n\tprivate _canvas?: HTMLCanvasElement;\n\tprivate readonly ctx: CanvasRenderingContext2D;\n\tprivate readonly DM: DataManager;\n\tprivate readonly SM: StyleManager;\n\tprivate readonly zoomInOptimize: {\n\t\tlastDrawnScale: number;\n\t\tlastDrawnViewport: Box;\n\t\ttimeout?: number;\n\t\tlastCallTime: number;\n\t} = {\n\t\tlastCallTime: 0,\n\t\tlastDrawnScale: 0,\n\t\tlastDrawnViewport: {\n\t\t\tbottom: 0,\n\t\t\tleft: 0,\n\t\t\tright: 0,\n\t\t\ttop: 0,\n\t\t},\n\t};\n\n\tprivate get canvas() {\n\t\tif (!this._canvas) throw destroyError;\n\t\treturn this._canvas;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tconst controller = this.container.get(Controller);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tcontroller.onRefresh.subscribe(this.redraw);\n\t\tcontroller.onResize.subscribe(this.optimizeDPR);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis._canvas = document.createElement('canvas');\n\t\tthis._canvas.className = 'JCV-main-canvas';\n\t\tthis.ctx = this._canvas.getContext('2d') as CanvasRenderingContext2D;\n\t\tthis.DM.data.container.appendChild(this._canvas);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly optimizeDPR = () => {\n\t\tconst container = this.DM.data.container;\n\t\tresizeCanvasForDPR(this.canvas, container.offsetWidth, container.offsetHeight);\n\t};\n\n\tprivate readonly redraw = () => {\n\t\tconst offsetX = this.DM.data.offsetX;\n\t\tconst offsetY = this.DM.data.offsetY;\n\t\tconst scale = this.DM.data.scale;\n\t\tconst currentViewport = this.getCurrentViewport(offsetX, offsetY, scale);\n\t\tif (!this.options.zoomInOptimization) {\n\t\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t\t\treturn;\n\t\t}\n\t\tif (this.zoomInOptimize.timeout) {\n\t\t\tclearTimeout(this.zoomInOptimize.timeout);\n\t\t\tthis.zoomInOptimize.timeout = undefined;\n\t\t}\n\t\tconst now = Date.now();\n\t\tif (\n\t\t\tthis.isInside(currentViewport, this.zoomInOptimize.lastDrawnViewport) &&\n\t\t\tscale !== this.zoomInOptimize.lastDrawnScale\n\t\t) {\n\t\t\tconst timeSinceLast = now - this.zoomInOptimize.lastCallTime;\n\t\t\tif (timeSinceLast < CSS_ZOOM_REDRAW_INTERVAL) {\n\t\t\t\tthis.zoomInOptimize.timeout = window.setTimeout(() => {\n\t\t\t\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t\t\t\t\tthis.zoomInOptimize.lastCallTime = now;\n\t\t\t\t\tthis.zoomInOptimize.timeout = undefined;\n\t\t\t\t}, 60);\n\t\t\t\tthis.fakeRedraw(currentViewport, scale);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tthis.zoomInOptimize.lastCallTime = now;\n\t\tthis.trueRedraw(offsetX, offsetY, scale, currentViewport);\n\t};\n\n\tprivate trueRedraw(offsetX: number, offsetY: number, scale: number, currentViewport: Box) {\n\t\tthis.zoomInOptimize.lastDrawnViewport = currentViewport;\n\t\tthis.zoomInOptimize.lastDrawnScale = scale;\n\t\tthis.canvas.style.transform = '';\n\t\tthis.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n\t\tthis.ctx.save();\n\t\tthis.drawGridDots(scale, offsetX, offsetY);\n\t\tthis.ctx.translate(offsetX, offsetY);\n\t\tthis.ctx.scale(scale, scale);\n\t\tObject.values(this.DM.data.nodeMap).forEach((item) => {\n\t\t\tif (this.isOutside(item.box, currentViewport)) return;\n\t\t\tconst node = item.ref;\n\t\t\tif (node.type === 'file') this.drawFile(item);\n\t\t\telse if (node.type === 'group') this.drawGroup(node, scale);\n\t\t});\n\t\tObject.values(this.DM.data.edgeMap).forEach((item) => {\n\t\t\tif (this.isOutside(item.box, currentViewport)) return;\n\t\t\tthis.drawEdge(item);\n\t\t});\n\t\tthis.ctx.restore();\n\t}\n\n\tprivate fakeRedraw(currentViewport: Box, scale: number) {\n\t\tconst cssScale = scale / this.zoomInOptimize.lastDrawnScale;\n\t\tconst currentOffsetX =\n\t\t\t(this.zoomInOptimize.lastDrawnViewport.left - currentViewport.left) * scale;\n\t\tconst currentOffsetY =\n\t\t\t(this.zoomInOptimize.lastDrawnViewport.top - currentViewport.top) * scale;\n\t\tthis.canvas.style.transform = `translate(${currentOffsetX}px, ${currentOffsetY}px) scale(${cssScale})`;\n\t}\n\n\tprivate readonly isInside = (inner: Box, outer: Box) =>\n\t\tinner.left > outer.left &&\n\t\tinner.top > outer.top &&\n\t\tinner.right < outer.right &&\n\t\tinner.bottom < outer.bottom;\n\n\tprivate readonly isOutside = (inner: Box, outer: Box) =>\n\t\tinner.right < outer.left ||\n\t\tinner.bottom < outer.top ||\n\t\tinner.left > outer.right ||\n\t\tinner.top > outer.bottom;\n\n\tprivate readonly getCurrentViewport = (offsetX: number, offsetY: number, scale: number) => {\n\t\tconst left = -offsetX / scale;\n\t\tconst top = -offsetY / scale;\n\t\tconst container = this.DM.data.container;\n\t\tconst right = left + container.clientWidth / scale;\n\t\tconst bottom = top + container.clientHeight / scale;\n\t\treturn { bottom, left, right, top };\n\t};\n\n\tprivate readonly drawLabelBar = (\n\t\tx: number,\n\t\ty: number,\n\t\tlabel: string,\n\t\tcolor: string,\n\t\ttextColor: string,\n\t\tscale: number,\n\t) => {\n\t\tconst barHeight = 30 * scale;\n\t\tconst radius = 6 * scale;\n\t\tconst yOffset = 8 * scale;\n\t\tconst fontSize = 16 * scale;\n\t\tconst xPadding = 6 * scale;\n\t\tthis.ctx.save();\n\t\tthis.ctx.translate(x, y);\n\t\tthis.ctx.scale(1 / scale, 1 / scale);\n\t\tthis.ctx.font = `${fontSize}px 'Inter', sans-serif`;\n\t\tconst barWidth = this.ctx.measureText(label).width + 2 * xPadding;\n\t\tthis.ctx.translate(0, -barHeight - yOffset);\n\t\tthis.ctx.fillStyle = color;\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.moveTo(radius, 0);\n\t\tthis.ctx.lineTo(barWidth - radius, 0);\n\t\tthis.ctx.quadraticCurveTo(barWidth, 0, barWidth, radius);\n\t\tthis.ctx.lineTo(barWidth, barHeight - radius);\n\t\tthis.ctx.quadraticCurveTo(barWidth, barHeight, barWidth - radius, barHeight);\n\t\tthis.ctx.lineTo(radius, barHeight);\n\t\tthis.ctx.quadraticCurveTo(0, barHeight, 0, barHeight - radius);\n\t\tthis.ctx.lineTo(0, radius);\n\t\tthis.ctx.quadraticCurveTo(0, 0, radius, 0);\n\t\tthis.ctx.closePath();\n\t\tthis.ctx.fill();\n\t\tthis.ctx.fillStyle = textColor;\n\t\tthis.ctx.fillText(label, xPadding, barHeight * 0.65);\n\t\tthis.ctx.restore();\n\t};\n\n\tprivate readonly drawNodeBackground = (node: JSONCanvasNode) => {\n\t\tconst colors = this.SM.getColor(node.color);\n\t\tconst radius = NODE_RADIUS;\n\t\tthis.ctx.globalAlpha = 1;\n\t\tthis.ctx.fillStyle = colors.background;\n\t\tdrawRoundRect(\n\t\t\tthis.ctx,\n\t\t\tnode.x + NODE_BORDER_HALF_WIDTH,\n\t\t\tnode.y + NODE_BORDER_HALF_WIDTH,\n\t\t\tnode.width - NODE_BORDER_WIDTH,\n\t\t\tnode.height - NODE_BORDER_WIDTH,\n\t\t\tradius,\n\t\t);\n\t\tthis.ctx.fill();\n\t\tthis.ctx.strokeStyle = colors.border;\n\t\tthis.ctx.lineWidth = NODE_BORDER_WIDTH;\n\t\tdrawRoundRect(this.ctx, node.x, node.y, node.width, node.height, radius);\n\t\tthis.ctx.stroke();\n\t};\n\n\tprivate readonly drawGroup = (node: JSONCanvasGroupNode, scale: number) => {\n\t\tthis.drawNodeBackground(node);\n\t\tif (node.label) {\n\t\t\tconst color = this.SM.getColor(node.color);\n\t\t\tthis.drawLabelBar(node.x, node.y, node.label, color.active, color.text, scale);\n\t\t}\n\t};\n\n\tprivate readonly drawFile = (item: NodeItem) => {\n\t\tthis.ctx.fillStyle = this.SM.getColor().text;\n\t\tconst node = item.ref;\n\t\tthis.ctx.font = '16px sans-serif';\n\t\tthis.ctx.fillText(item.fileName ?? '', node.x + 5, node.y - 10);\n\t};\n\n\tprivate readonly drawEdge = (item: EdgeItem) => {\n\t\tconst edge = item.ref;\n\t\tconst fromNode = this.DM.data.nodeMap[edge.fromNode].ref;\n\t\tconst toNode = this.DM.data.nodeMap[edge.toNode].ref;\n\t\tconst { x: startX, y: startY } = getAnchorCoord(fromNode, edge.fromSide);\n\t\tconst { x: endX, y: endY } = getAnchorCoord(toNode, edge.toSide);\n\t\tconst color = this.SM.getColor(edge.color);\n\t\tlet startControlX, startControlY, endControlX, endControlY: number;\n\t\tif (!item.controlPoints) {\n\t\t\t[startControlX, startControlY, endControlX, endControlY] = this.getControlPoints(\n\t\t\t\tstartX,\n\t\t\t\tstartY,\n\t\t\t\tendX,\n\t\t\t\tendY,\n\t\t\t\tedge.fromSide,\n\t\t\t\tedge.toSide,\n\t\t\t);\n\t\t\titem.controlPoints = [startControlX, startControlY, endControlX, endControlY];\n\t\t} else [startControlX, startControlY, endControlX, endControlY] = item.controlPoints;\n\t\tthis.drawCurvedPath(\n\t\t\tstartX,\n\t\t\tstartY,\n\t\t\tendX,\n\t\t\tendY,\n\t\t\tstartControlX,\n\t\t\tstartControlY,\n\t\t\tendControlX,\n\t\t\tendControlY,\n\t\t\tcolor.active,\n\t\t);\n\t\tthis.drawArrowhead(endX, endY, endControlX, endControlY, color.active);\n\t\tif (edge.label)\n\t\t\tthis.drawEdgeLabel(\n\t\t\t\tstartX,\n\t\t\t\tstartY,\n\t\t\t\tendX,\n\t\t\t\tendY,\n\t\t\t\tstartControlX,\n\t\t\t\tstartControlY,\n\t\t\t\tendControlX,\n\t\t\t\tendControlY,\n\t\t\t\tedge.label,\n\t\t\t\tcolor.active,\n\t\t\t\tcolor.text,\n\t\t\t);\n\t};\n\n\tprivate readonly drawEdgeLabel = (\n\t\tstartX: number,\n\t\tstartY: number,\n\t\tendX: number,\n\t\tendY: number,\n\t\tstartControlX: number,\n\t\tstartControlY: number,\n\t\tendControlX: number,\n\t\tendControlY: number,\n\t\tlabel: string,\n\t\tcolor: string,\n\t\ttextColor: string,\n\t) => {\n\t\tconst t = 0.5;\n\t\tconst x =\n\t\t\t(1 - t) ** 3 * startX +\n\t\t\t3 * (1 - t) ** 2 * t * startControlX +\n\t\t\t3 * (1 - t) * t * t * endControlX +\n\t\t\tt ** 3 * endX;\n\t\tconst y =\n\t\t\t(1 - t) ** 3 * startY +\n\t\t\t3 * (1 - t) ** 2 * t * startControlY +\n\t\t\t3 * (1 - t) * t * t * endControlY +\n\t\t\tt ** 3 * endY;\n\t\tthis.ctx.font = '18px sans-serif';\n\t\tconst lines = label.split('\\n');\n\t\tconst lineHeight = 17;\n\t\tlet maxWidth = 0;\n\t\tfor (const line of lines) {\n\t\t\tconst w = this.ctx.measureText(line).width;\n\t\t\tif (w > maxWidth) maxWidth = w;\n\t\t}\n\t\tconst paddingX = 8;\n\t\tconst paddingY = 3;\n\t\tconst labelWidth = maxWidth + paddingX * 2;\n\t\tconst labelHeight = lines.length * lineHeight + paddingY * 2; // Dynamic height\n\t\tthis.ctx.fillStyle = color;\n\t\tthis.ctx.beginPath();\n\t\tdrawRoundRect(\n\t\t\tthis.ctx,\n\t\t\tx - labelWidth / 2,\n\t\t\ty - labelHeight / 2 - 2,\n\t\t\tlabelWidth,\n\t\t\tlabelHeight,\n\t\t\t4,\n\t\t);\n\t\tthis.ctx.fill();\n\t\tthis.ctx.fillStyle = textColor;\n\t\tthis.ctx.textAlign = 'center';\n\t\tthis.ctx.textBaseline = 'middle';\n\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\tconst offsetY = (i - (lines.length - 1) / 2) * lineHeight;\n\t\t\tthis.ctx.fillText(lines[i], x, y - 2 + offsetY);\n\t\t}\n\t\tthis.ctx.textAlign = 'left';\n\t\tthis.ctx.textBaseline = 'alphabetic';\n\t};\n\n\tprivate readonly getControlPoints = (\n\t\tstartX: number,\n\t\tstartY: number,\n\t\tendX: number,\n\t\tendY: number,\n\t\tfromSide: string,\n\t\ttoSide: string,\n\t) => {\n\t\tconst distanceX = endX - startX;\n\t\tconst distanceY = endY - startY;\n\t\tconst realDistance =\n\t\t\tMath.min(Math.abs(distanceX), Math.abs(distanceY)) +\n\t\t\t0.3 * Math.max(Math.abs(distanceX), Math.abs(distanceY));\n\t\tconst clamp = (val: number, min: number, max: number) => Math.max(min, Math.min(max, val));\n\t\tconst PADDING = clamp(realDistance * 0.5, 60, 300);\n\t\tlet startControlX = startX;\n\t\tlet startControlY = startY;\n\t\tlet endControlX = endX;\n\t\tlet endControlY = endY;\n\t\tswitch (fromSide) {\n\t\t\tcase 'top': {\n\t\t\t\tstartControlY = startY - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'bottom': {\n\t\t\t\tstartControlY = startY + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\tstartControlX = startX - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'right': {\n\t\t\t\tstartControlX = startX + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tswitch (toSide) {\n\t\t\tcase 'top': {\n\t\t\t\tendControlY = endY - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'bottom': {\n\t\t\t\tendControlY = endY + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\tendControlX = endX - PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'right': {\n\t\t\t\tendControlX = endX + PADDING;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn [startControlX, startControlY, endControlX, endControlY];\n\t};\n\n\tprivate readonly drawGridDots = (scale: number, offsetX: number, offsetY: number) => {\n\t\tconst scaleLevel = -Math.floor(Math.log2(scale));\n\t\tconst actualGap = DOT_BASE_GAP * 2 ** scaleLevel * scale;\n\t\tconst width = this.canvas.width;\n\t\tconst height = this.canvas.height;\n\t\tconst startX = offsetX % actualGap;\n\t\tconst startY = offsetY % actualGap;\n\t\tthis.ctx.fillStyle = this.SM.getNamedColor('dots');\n\t\tfor (let x = startX; x <= width; x += actualGap)\n\t\t\tfor (let y = startY; y <= height; y += actualGap) {\n\t\t\t\tthis.ctx.beginPath();\n\t\t\t\tthis.ctx.arc(x, y, DOT_RADIUS, 0, 2 * Math.PI);\n\t\t\t\tthis.ctx.fill();\n\t\t\t}\n\t};\n\n\tprivate readonly drawCurvedPath = (\n\t\tstartX: number,\n\t\tstartY: number,\n\t\tendX: number,\n\t\tendY: number,\n\t\tc1x: number,\n\t\tc1y: number,\n\t\tc2x: number,\n\t\tc2y: number,\n\t\tcolor: string,\n\t) => {\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.moveTo(startX, startY);\n\t\tthis.ctx.bezierCurveTo(c1x, c1y, c2x, c2y, endX, endY);\n\t\tthis.ctx.strokeStyle = color;\n\t\tthis.ctx.lineWidth = 2;\n\t\tthis.ctx.stroke();\n\t};\n\n\tprivate readonly drawArrowhead = (\n\t\ttipX: number,\n\t\ttipY: number,\n\t\tfromX: number,\n\t\tfromY: number,\n\t\tcolor: string,\n\t) => {\n\t\tconst dx = tipX - fromX;\n\t\tconst dy = tipY - fromY;\n\t\tconst length = Math.sqrt(dx * dx + dy * dy);\n\t\tif (length === 0) return;\n\t\tconst unitX = dx / length;\n\t\tconst unitY = dy / length;\n\t\tconst leftX = tipX - unitX * ARROW_LENGTH - unitY * ARROW_WIDTH;\n\t\tconst leftY = tipY - unitY * ARROW_LENGTH + unitX * ARROW_WIDTH;\n\t\tconst rightX = tipX - unitX * ARROW_LENGTH + unitY * ARROW_WIDTH;\n\t\tconst rightY = tipY - unitY * ARROW_LENGTH - unitX * ARROW_WIDTH;\n\t\tthis.ctx.beginPath();\n\t\tthis.ctx.fillStyle = color;\n\t\tthis.ctx.moveTo(tipX, tipY);\n\t\tthis.ctx.lineTo(leftX, leftY);\n\t\tthis.ctx.lineTo(rightX, rightY);\n\t\tthis.ctx.closePath();\n\t\tthis.ctx.fill();\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tif (this.zoomInOptimize.timeout) {\n\t\t\tclearTimeout(this.zoomInOptimize.timeout);\n\t\t\tthis.zoomInOptimize.timeout = undefined;\n\t\t}\n\t\tthis.canvas.remove();\n\t\tthis._canvas = undefined;\n\t};\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{BaseModule as e}from"./BaseModule.js";import{makeHook as t}from"./utilities.js";import n from"./DataManager.js";import{parseHex as r,parseHsl as i,parseRgb as a,rgbToHsl as o,toHslString as s}from"@ahmedsemih/color-fns";var c=class extends e{theme=`light`;onChangeTheme=t();definedColors={dark:{0:{hue:0,lightness:40,saturation:0},1:{hue:358,lightness:65,saturation:100},2:{hue:23,lightness:63,saturation:86},3:{hue:39,lightness:70,saturation:91},4:{hue:153,lightness:45,saturation:80},5:{hue:217,lightness:62,saturation:100},6:{hue:259,lightness:75,saturation:100}},light:{0:{hue:0,lightness:72,saturation:0},1:{hue:358,lightness:55,saturation:81},2:{hue:19,lightness:58,saturation:87},3:{hue:41,lightness:52,saturation:79},4:{hue:150,lightness:37,saturation:100},5:{hue:221,lightness:59,saturation:100},6:{hue:257,lightness:62,saturation:81}}};namedColors={dark:{background:`rgb(30, 30, 30)`,"background-secondary":`rgb(37, 37, 40)`,border:`hsla(0, 0%, 30%, 0.7)`,dots:`hsla(0, 0%, 40%, 0.3)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.2)`,text:`rgb(242, 242, 242)`},light:{background:`rgb(250, 250, 250)`,"background-secondary":`rgb(255, 255, 255)`,border:`hsla(0, 0%, 82%, 0.7)`,dots:`hsla(0, 0%, 72%, 0.4)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.1)`,text:`rgb(30, 30, 30)`}};colorCache={dark:{},light:{}};constructor(...e){super(...e);let t=this.options.colors;t&&[`light`,`dark`].forEach(e=>{if(!(e in t))return;let n=t[e];n&&Object.entries(n).forEach(([t,n])=>{if(!n)return;let r=this.namedColors[e],i=this.definedColors[e];if(t in r)r[t]=n;else if(t in i){let e=this.parseColor(n);if(!e){console.warn(`[JSON Canvas Viewer] Color ${n} unsupported.`);return}i[t]=e}})}),this.changeTheme(this.options.theme??`light`),this.augment({changeTheme:this.changeTheme,onChangeTheme:this.onChangeTheme})}hslProcessor=e=>{let{hue:t,saturation:n,lightness:r}=e,i=this.theme===`dark`?{active:e,background:{...e,alpha:.1},border:{...e,alpha:.7},card:{hue:t,lightness:r/3,saturation:n/3},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`}:{active:e,background:{...e,alpha:.1},border:{...e,alpha:.7},card:t===0?{hue:t,lightness:100,saturation:n}:{hue:t,lightness:90,saturation:n*.4},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`};return{active:s(i.active),background:s(i.background),border:s(i.border),card:s(i.card),text:i.text}};parseColor=e=>{if(e.startsWith(`rgb`))return o(a(e));if(e.startsWith(`#`))return o(r(e));if(e.startsWith(`hsl`))return i(e)};getColor=(e=`0`)=>{let t=this.theme,n;if(this.colorCache[t][e])return this.colorCache[t][e];n=e in this.definedColors[t]?this.hslProcessor(this.definedColors[t][e]):this.hslProcessor(o(r(e)));let i={...n,"border-width":e===`0`?`1px`:`2px`};return this.colorCache[t][e]=i,i};getNamedColor=e=>this.namedColors[this.theme][e];changeTheme=e=>{this.theme=e??this.theme===`dark`?`light`:`dark`;let t=this.container.get(n).data.container;Object.entries(this.namedColors[this.theme]).forEach(([e,n])=>{t.style.setProperty(`--${e}`,n)}),this.onChangeTheme(this.theme)}};export{c as default};
1
+ import{BaseModule as e}from"./BaseModule.js";import{makeHook as t}from"./utilities.js";import n from"./DataManager.js";import{parseHex as r,parseHsl as i,parseRgb as a,rgbToHsl as o,toHslString as s}from"@ahmedsemih/color-fns";var c=class extends e{theme=`light`;onChangeTheme=t();definedColors={dark:{0:{hue:0,lightness:40,saturation:0},1:{hue:358,lightness:65,saturation:100},2:{hue:23,lightness:63,saturation:86},3:{hue:39,lightness:70,saturation:91},4:{hue:153,lightness:45,saturation:80},5:{hue:217,lightness:62,saturation:100},6:{hue:259,lightness:75,saturation:100}},light:{0:{hue:0,lightness:72,saturation:0},1:{hue:358,lightness:55,saturation:81},2:{hue:19,lightness:58,saturation:87},3:{hue:41,lightness:52,saturation:79},4:{hue:150,lightness:37,saturation:100},5:{hue:221,lightness:59,saturation:100},6:{hue:257,lightness:62,saturation:81}}};namedColors={dark:{background:`rgb(30, 30, 30)`,"background-secondary":`rgb(37, 37, 40)`,border:`hsla(0, 0%, 30%, 0.7)`,dots:`hsla(0, 0%, 40%, 0.3)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.2)`,text:`rgb(242, 242, 242)`},light:{background:`rgb(250, 250, 250)`,"background-secondary":`rgb(255, 255, 255)`,border:`hsla(0, 0%, 82%, 0.7)`,dots:`hsla(0, 0%, 72%, 0.4)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.1)`,text:`rgb(30, 30, 30)`}};colorCache={dark:{},light:{}};constructor(...e){super(...e);let t=this.options.colors;t&&[`light`,`dark`].forEach(e=>{if(!(e in t))return;let n=t[e];n&&Object.entries(n).forEach(([t,n])=>{if(!n)return;let r=this.namedColors[e],i=this.definedColors[e];if(t in r)r[t]=n;else if(t in i){let e=this.parseColor(n);if(!e){console.warn(`[JSON Canvas Viewer] Color ${n} unsupported.`);return}i[t]=e}})}),this.changeTheme(this.options.theme??`light`),this.augment({changeTheme:this.changeTheme,onChangeTheme:this.onChangeTheme})}hslProcessor=e=>{let{hue:t,saturation:n,lightness:r}=e,i=this.theme===`dark`?{active:e,background:{...e,alpha:.1},border:{...e,alpha:.7},card:{hue:t,lightness:r/3,saturation:n/3},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`}:{active:e,background:{...e,alpha:.1},border:{...e,alpha:.7},card:t===0?{hue:t,lightness:100,saturation:n}:{hue:t,lightness:90,saturation:n*.4},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`};return{active:s(i.active),background:s(i.background),border:s(i.border),card:s(i.card),text:i.text}};parseColor=e=>{if(e.startsWith(`rgb`))return o(a(e));if(e.startsWith(`#`))return o(r(e));if(e.startsWith(`hsl`))return i(e)};getColor=(e=`0`)=>{let t=this.theme,n;if(this.colorCache[t][e])return this.colorCache[t][e];n=e in this.definedColors[t]?this.hslProcessor(this.definedColors[t][e]):this.hslProcessor(o(r(e)));let i={...n,"border-width":e===`0`?`1px`:`2px`};return this.colorCache[t][e]=i,i};getNamedColor=e=>this.namedColors[this.theme][e];changeTheme=e=>{this.theme=e??(this.theme===`dark`?`light`:`dark`);let t=this.container.get(n).data.container;Object.entries(this.namedColors[this.theme]).forEach(([e,n])=>{t.style.setProperty(`--${e}`,n)}),this.onChangeTheme(this.theme)}};export{c as default};
2
2
  //# sourceMappingURL=StyleManager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StyleManager.js","names":[],"sources":["../../src/kernel/StyleManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { HslColor } from '@ahmedsemih/color-fns';\nimport { BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport { makeHook } from '$/utilities';\nimport { parseHex, toHslString, rgbToHsl, parseHsl, parseRgb } from '@ahmedsemih/color-fns';\n\ntype Color = {\n\tborder: string;\n\tbackground: string;\n\tactive: string;\n\ttext: string;\n\tcard: string;\n};\n\nexport type WithBorderWidth = {\n\t'border-width': string;\n} & Color;\n\ntype ColorOptions = {\n\t[K in keyof (StyleManager['definedColors']['light'] &\n\t\tStyleManager['namedColors']['light'])]?: string;\n};\n\ntype Options = {\n\ttheme?: 'dark' | 'light';\n\tcolors?: {\n\t\tlight?: ColorOptions;\n\t\tdark?: ColorOptions;\n\t};\n} & BaseOptions;\n\ntype Augmentation = {\n\tchangeTheme: StyleManager['changeTheme'];\n\tonChangeTheme: StyleManager['onChangeTheme'];\n};\n\nexport default class StyleManager extends BaseModule<Options, Augmentation> {\n\ttheme: 'dark' | 'light' = 'light';\n\tonChangeTheme = makeHook<['light' | 'dark']>();\n\tdefinedColors = {\n\t\tdark: {\n\t\t\t'0': { hue: 0, lightness: 40, saturation: 0 },\n\t\t\t'1': { hue: 358, lightness: 65, saturation: 100 },\n\t\t\t'2': { hue: 23, lightness: 63, saturation: 86 },\n\t\t\t'3': { hue: 39, lightness: 70, saturation: 91 },\n\t\t\t'4': { hue: 153, lightness: 45, saturation: 80 },\n\t\t\t'5': { hue: 217, lightness: 62, saturation: 100 },\n\t\t\t'6': { hue: 259, lightness: 75, saturation: 100 },\n\t\t},\n\t\tlight: {\n\t\t\t'0': { hue: 0, lightness: 72, saturation: 0 },\n\t\t\t'1': { hue: 358, lightness: 55, saturation: 81 },\n\t\t\t'2': { hue: 19, lightness: 58, saturation: 87 },\n\t\t\t'3': { hue: 41, lightness: 52, saturation: 79 },\n\t\t\t'4': { hue: 150, lightness: 37, saturation: 100 },\n\t\t\t'5': { hue: 221, lightness: 59, saturation: 100 },\n\t\t\t'6': { hue: 257, lightness: 62, saturation: 81 },\n\t\t},\n\t};\n\n\tnamedColors = {\n\t\tdark: {\n\t\t\tbackground: 'rgb(30, 30, 30)',\n\t\t\t'background-secondary': 'rgb(37, 37, 40)',\n\t\t\tborder: 'hsla(0, 0%, 30%, 0.7)',\n\t\t\tdots: 'hsla(0, 0%, 40%, 0.3)',\n\t\t\tshadow: '0px 0px 8px rgb(0, 0, 0, 0.2)',\n\t\t\ttext: 'rgb(242, 242, 242)',\n\t\t},\n\t\tlight: {\n\t\t\tbackground: 'rgb(250, 250, 250)',\n\t\t\t'background-secondary': 'rgb(255, 255, 255)',\n\t\t\tborder: 'hsla(0, 0%, 82%, 0.7)',\n\t\t\tdots: 'hsla(0, 0%, 72%, 0.4)',\n\t\t\tshadow: '0px 0px 8px rgb(0, 0, 0, 0.1)',\n\t\t\ttext: 'rgb(30, 30, 30)',\n\t\t},\n\t};\n\n\tprivate readonly colorCache: {\n\t\tdark: Record<string, WithBorderWidth>;\n\t\tlight: Record<string, WithBorderWidth>;\n\t} = {\n\t\tdark: {},\n\t\tlight: {},\n\t};\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\n\t\t// User-defined color merging\n\t\tconst colors = this.options.colors;\n\t\tif (colors) {\n\t\t\tconst themes = ['light', 'dark'] as const;\n\t\t\tthemes.forEach((theme) => {\n\t\t\t\tif (!(theme in colors)) return;\n\t\t\t\tconst colorObject = colors[theme];\n\t\t\t\tif (!colorObject) return;\n\t\t\t\tObject.entries(colorObject).forEach(([key, value]) => {\n\t\t\t\t\tif (!value) return;\n\t\t\t\t\tconst namedColorsDict = this.namedColors[theme];\n\t\t\t\t\tconst definedColorsDict = this.definedColors[theme];\n\t\t\t\t\tif (key in namedColorsDict)\n\t\t\t\t\t\tnamedColorsDict[key as keyof typeof namedColorsDict] = value;\n\t\t\t\t\telse if (key in definedColorsDict) {\n\t\t\t\t\t\tconst color = this.parseColor(value);\n\t\t\t\t\t\tif (!color) {\n\t\t\t\t\t\t\tconsole.warn(`[JSON Canvas Viewer] Color ${value} unsupported.`);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefinedColorsDict[key as keyof typeof definedColorsDict] = color;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tthis.changeTheme(this.options.theme ?? 'light');\n\t\tthis.augment({\n\t\t\tchangeTheme: this.changeTheme,\n\t\t\tonChangeTheme: this.onChangeTheme,\n\t\t});\n\t}\n\n\tprivate readonly hslProcessor = (color: HslColor) => {\n\t\tconst { hue, saturation, lightness } = color;\n\t\tconst result =\n\t\t\tthis.theme === 'dark'\n\t\t\t\t? {\n\t\t\t\t\t\tactive: color,\n\t\t\t\t\t\tbackground: { ...color, alpha: 0.1 },\n\t\t\t\t\t\tborder: { ...color, alpha: 0.7 },\n\t\t\t\t\t\tcard: { hue, lightness: lightness / 3, saturation: saturation / 3 },\n\t\t\t\t\t\ttext: color.lightness >= 70 ? 'rgb(30, 30, 30)' : 'rgb(242, 242, 242)',\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tactive: color,\n\t\t\t\t\t\tbackground: { ...color, alpha: 0.1 },\n\t\t\t\t\t\tborder: { ...color, alpha: 0.7 },\n\t\t\t\t\t\tcard:\n\t\t\t\t\t\t\thue === 0\n\t\t\t\t\t\t\t\t? { hue, lightness: 100, saturation }\n\t\t\t\t\t\t\t\t: { hue, lightness: 90, saturation: saturation * 0.4 },\n\t\t\t\t\t\ttext: color.lightness >= 70 ? 'rgb(30, 30, 30)' : 'rgb(242, 242, 242)',\n\t\t\t\t\t};\n\t\treturn {\n\t\t\tactive: toHslString(result.active),\n\t\t\tbackground: toHslString(result.background),\n\t\t\tborder: toHslString(result.border),\n\t\t\tcard: toHslString(result.card),\n\t\t\ttext: result.text,\n\t\t};\n\t};\n\n\tprivate readonly parseColor = (color: string) => {\n\t\tif (color.startsWith('rgb')) return rgbToHsl(parseRgb(color));\n\t\tif (color.startsWith('#')) return rgbToHsl(parseHex(color));\n\t\tif (color.startsWith('hsl')) return parseHsl(color);\n\t};\n\n\tgetColor = (colorIndex = '0') => {\n\t\tconst theme = this.theme;\n\t\tlet color: Color;\n\t\tif (this.colorCache[theme][colorIndex]) return this.colorCache[theme][colorIndex];\n\t\telse if (colorIndex in this.definedColors[theme])\n\t\t\tcolor = this.hslProcessor(\n\t\t\t\tthis.definedColors[theme][colorIndex as keyof typeof this.definedColors.dark],\n\t\t\t);\n\t\telse color = this.hslProcessor(rgbToHsl(parseHex(colorIndex)));\n\t\tconst withBorderWidth: WithBorderWidth = {\n\t\t\t...color,\n\t\t\t'border-width': colorIndex === '0' ? '1px' : '2px',\n\t\t};\n\t\tthis.colorCache[theme][colorIndex] = withBorderWidth;\n\t\treturn withBorderWidth;\n\t};\n\n\tgetNamedColor = (name: keyof typeof this.namedColors.light) =>\n\t\tthis.namedColors[this.theme][name];\n\n\tchangeTheme = (theme?: 'dark' | 'light') => {\n\t\tthis.theme = (theme ?? this.theme === 'dark') ? 'light' : 'dark';\n\t\tconst container = this.container.get(DataManager).data.container;\n\t\tObject.entries(this.namedColors[this.theme]).forEach(([key, value]) => {\n\t\t\tcontainer.style.setProperty(`--${key}`, value);\n\t\t});\n\t\tthis.onChangeTheme(this.theme);\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"StyleManager.js","names":[],"sources":["../../src/kernel/StyleManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { HslColor } from '@ahmedsemih/color-fns';\nimport { BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport { makeHook } from '$/utilities';\nimport { parseHex, toHslString, rgbToHsl, parseHsl, parseRgb } from '@ahmedsemih/color-fns';\n\ntype Color = {\n\tborder: string;\n\tbackground: string;\n\tactive: string;\n\ttext: string;\n\tcard: string;\n};\n\nexport type WithBorderWidth = {\n\t'border-width': string;\n} & Color;\n\ntype ColorOptions = {\n\t[K in keyof (StyleManager['definedColors']['light'] &\n\t\tStyleManager['namedColors']['light'])]?: string;\n};\n\ntype Options = {\n\ttheme?: 'dark' | 'light';\n\tcolors?: {\n\t\tlight?: ColorOptions;\n\t\tdark?: ColorOptions;\n\t};\n} & BaseOptions;\n\ntype Augmentation = {\n\tchangeTheme: StyleManager['changeTheme'];\n\tonChangeTheme: StyleManager['onChangeTheme'];\n};\n\nexport default class StyleManager extends BaseModule<Options, Augmentation> {\n\ttheme: 'dark' | 'light' = 'light';\n\tonChangeTheme = makeHook<['light' | 'dark']>();\n\tdefinedColors = {\n\t\tdark: {\n\t\t\t'0': { hue: 0, lightness: 40, saturation: 0 },\n\t\t\t'1': { hue: 358, lightness: 65, saturation: 100 },\n\t\t\t'2': { hue: 23, lightness: 63, saturation: 86 },\n\t\t\t'3': { hue: 39, lightness: 70, saturation: 91 },\n\t\t\t'4': { hue: 153, lightness: 45, saturation: 80 },\n\t\t\t'5': { hue: 217, lightness: 62, saturation: 100 },\n\t\t\t'6': { hue: 259, lightness: 75, saturation: 100 },\n\t\t},\n\t\tlight: {\n\t\t\t'0': { hue: 0, lightness: 72, saturation: 0 },\n\t\t\t'1': { hue: 358, lightness: 55, saturation: 81 },\n\t\t\t'2': { hue: 19, lightness: 58, saturation: 87 },\n\t\t\t'3': { hue: 41, lightness: 52, saturation: 79 },\n\t\t\t'4': { hue: 150, lightness: 37, saturation: 100 },\n\t\t\t'5': { hue: 221, lightness: 59, saturation: 100 },\n\t\t\t'6': { hue: 257, lightness: 62, saturation: 81 },\n\t\t},\n\t};\n\n\tnamedColors = {\n\t\tdark: {\n\t\t\tbackground: 'rgb(30, 30, 30)',\n\t\t\t'background-secondary': 'rgb(37, 37, 40)',\n\t\t\tborder: 'hsla(0, 0%, 30%, 0.7)',\n\t\t\tdots: 'hsla(0, 0%, 40%, 0.3)',\n\t\t\tshadow: '0px 0px 8px rgb(0, 0, 0, 0.2)',\n\t\t\ttext: 'rgb(242, 242, 242)',\n\t\t},\n\t\tlight: {\n\t\t\tbackground: 'rgb(250, 250, 250)',\n\t\t\t'background-secondary': 'rgb(255, 255, 255)',\n\t\t\tborder: 'hsla(0, 0%, 82%, 0.7)',\n\t\t\tdots: 'hsla(0, 0%, 72%, 0.4)',\n\t\t\tshadow: '0px 0px 8px rgb(0, 0, 0, 0.1)',\n\t\t\ttext: 'rgb(30, 30, 30)',\n\t\t},\n\t};\n\n\tprivate readonly colorCache: {\n\t\tdark: Record<string, WithBorderWidth>;\n\t\tlight: Record<string, WithBorderWidth>;\n\t} = {\n\t\tdark: {},\n\t\tlight: {},\n\t};\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\n\t\t// User-defined color merging\n\t\tconst colors = this.options.colors;\n\t\tif (colors) {\n\t\t\tconst themes = ['light', 'dark'] as const;\n\t\t\tthemes.forEach((theme) => {\n\t\t\t\tif (!(theme in colors)) return;\n\t\t\t\tconst colorObject = colors[theme];\n\t\t\t\tif (!colorObject) return;\n\t\t\t\tObject.entries(colorObject).forEach(([key, value]) => {\n\t\t\t\t\tif (!value) return;\n\t\t\t\t\tconst namedColorsDict = this.namedColors[theme];\n\t\t\t\t\tconst definedColorsDict = this.definedColors[theme];\n\t\t\t\t\tif (key in namedColorsDict)\n\t\t\t\t\t\tnamedColorsDict[key as keyof typeof namedColorsDict] = value;\n\t\t\t\t\telse if (key in definedColorsDict) {\n\t\t\t\t\t\tconst color = this.parseColor(value);\n\t\t\t\t\t\tif (!color) {\n\t\t\t\t\t\t\tconsole.warn(`[JSON Canvas Viewer] Color ${value} unsupported.`);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefinedColorsDict[key as keyof typeof definedColorsDict] = color;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tthis.changeTheme(this.options.theme ?? 'light');\n\t\tthis.augment({\n\t\t\tchangeTheme: this.changeTheme,\n\t\t\tonChangeTheme: this.onChangeTheme,\n\t\t});\n\t}\n\n\tprivate readonly hslProcessor = (color: HslColor) => {\n\t\tconst { hue, saturation, lightness } = color;\n\t\tconst result =\n\t\t\tthis.theme === 'dark'\n\t\t\t\t? {\n\t\t\t\t\t\tactive: color,\n\t\t\t\t\t\tbackground: { ...color, alpha: 0.1 },\n\t\t\t\t\t\tborder: { ...color, alpha: 0.7 },\n\t\t\t\t\t\tcard: { hue, lightness: lightness / 3, saturation: saturation / 3 },\n\t\t\t\t\t\ttext: color.lightness >= 70 ? 'rgb(30, 30, 30)' : 'rgb(242, 242, 242)',\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tactive: color,\n\t\t\t\t\t\tbackground: { ...color, alpha: 0.1 },\n\t\t\t\t\t\tborder: { ...color, alpha: 0.7 },\n\t\t\t\t\t\tcard:\n\t\t\t\t\t\t\thue === 0\n\t\t\t\t\t\t\t\t? { hue, lightness: 100, saturation }\n\t\t\t\t\t\t\t\t: { hue, lightness: 90, saturation: saturation * 0.4 },\n\t\t\t\t\t\ttext: color.lightness >= 70 ? 'rgb(30, 30, 30)' : 'rgb(242, 242, 242)',\n\t\t\t\t\t};\n\t\treturn {\n\t\t\tactive: toHslString(result.active),\n\t\t\tbackground: toHslString(result.background),\n\t\t\tborder: toHslString(result.border),\n\t\t\tcard: toHslString(result.card),\n\t\t\ttext: result.text,\n\t\t};\n\t};\n\n\tprivate readonly parseColor = (color: string) => {\n\t\tif (color.startsWith('rgb')) return rgbToHsl(parseRgb(color));\n\t\tif (color.startsWith('#')) return rgbToHsl(parseHex(color));\n\t\tif (color.startsWith('hsl')) return parseHsl(color);\n\t};\n\n\tgetColor = (colorIndex = '0') => {\n\t\tconst theme = this.theme;\n\t\tlet color: Color;\n\t\tif (this.colorCache[theme][colorIndex]) return this.colorCache[theme][colorIndex];\n\t\telse if (colorIndex in this.definedColors[theme])\n\t\t\tcolor = this.hslProcessor(\n\t\t\t\tthis.definedColors[theme][colorIndex as keyof typeof this.definedColors.dark],\n\t\t\t);\n\t\telse color = this.hslProcessor(rgbToHsl(parseHex(colorIndex)));\n\t\tconst withBorderWidth: WithBorderWidth = {\n\t\t\t...color,\n\t\t\t'border-width': colorIndex === '0' ? '1px' : '2px',\n\t\t};\n\t\tthis.colorCache[theme][colorIndex] = withBorderWidth;\n\t\treturn withBorderWidth;\n\t};\n\n\tgetNamedColor = (name: keyof typeof this.namedColors.light) =>\n\t\tthis.namedColors[this.theme][name];\n\n\tchangeTheme = (theme?: 'dark' | 'light') => {\n\t\tthis.theme = theme ?? (this.theme === 'dark' ? 'light' : 'dark');\n\t\tconst container = this.container.get(DataManager).data.container;\n\t\tObject.entries(this.namedColors[this.theme]).forEach(([key, value]) => {\n\t\t\tcontainer.style.setProperty(`--${key}`, value);\n\t\t});\n\t\tthis.onChangeTheme(this.theme);\n\t};\n}\n"],"mappings":"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"}
@@ -20,7 +20,7 @@ type AllOptions<M extends ModuleInput = []> = Options<M> & Options<InternalModul
20
20
  type AllAugmentation<M extends ModuleInput = []> = Augmentation<M> & Augmentation<InternalModules>;
21
21
  declare class JSONCanvasViewer<M extends ModuleInputCtor> {
22
22
  private readonly allModules;
23
- private IO;
23
+ private IO?;
24
24
  private started;
25
25
  private disposed;
26
26
  options: AllOptions<M>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/kernel/index.ts"],"sourcesContent":["import type {\n\tModuleInputCtor,\n\tModuleInput,\n\tOptions,\n\tAugmentation,\n\tGeneralModuleCtor,\n} from '$/BaseModule';\nimport type { GeneralObject } from '$/types';\nimport type { JSONCanvas } from '@repo/shared';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport InteractionHandler from '$/InteractionHandler';\nimport OverlayManager from '$/OverlayManager';\nimport Renderer from '$/Renderer';\nimport StyleManager from '$/StyleManager';\nimport { makeHook } from '$/utilities';\nimport { Container } from '@needle-di/core';\n\nexport type BaseOptions = {\n\tcontainer: HTMLElement;\n\tloading?: 'normal' | 'lazy' | 'none';\n};\n\nconst internalModules = [\n\tDataManager,\n\tStyleManager,\n\tController,\n\tOverlayManager,\n\tInteractionHandler,\n\tRenderer,\n];\n\ntype InternalModules = typeof internalModules;\n\nexport type AllOptions<M extends ModuleInput = []> = Options<M> & Options<InternalModules>;\ntype AllAugmentation<M extends ModuleInput = []> = Augmentation<M> & Augmentation<InternalModules>;\n\nclass JSONCanvasViewer<M extends ModuleInputCtor> {\n\tprivate readonly allModules: ModuleInputCtor;\n\tprivate IO: IntersectionObserver | undefined;\n\tprivate started = false;\n\tprivate disposed = false;\n\toptions: AllOptions<M>;\n\tcontainer: Container;\n\tonDispose = makeHook(true);\n\tonStart = makeHook();\n\tonRestart = makeHook();\n\n\tconstructor(options: AllOptions<M>, modules?: M) {\n\t\tthis.container = new Container();\n\t\tthis.options = options;\n\t\tconst bind = (Class: GeneralModuleCtor) => {\n\t\t\tthis.container.bind({\n\t\t\t\tprovide: Class,\n\t\t\t\tuseFactory: () =>\n\t\t\t\t\tnew Class(\n\t\t\t\t\t\tthis.container,\n\t\t\t\t\t\tthis.options,\n\t\t\t\t\t\tthis.onStart,\n\t\t\t\t\t\tthis.onDispose,\n\t\t\t\t\t\tthis.onRestart,\n\t\t\t\t\t\tthis.augment,\n\t\t\t\t\t),\n\t\t\t});\n\t\t};\n\t\tthis.allModules = [...internalModules, ...(modules ?? [])];\n\t\tthis.allModules.forEach(bind);\n\t\tthis.allModules.forEach((Module) => {\n\t\t\tthis.container.get(Module);\n\t\t});\n\n\t\tconst loading = this.options.loading ?? 'normal';\n\t\tif (loading === 'normal') this.load();\n\t\telse if (loading === 'lazy') {\n\t\t\tthis.IO = new IntersectionObserver(this.onVisibilityCheck, {\n\t\t\t\trootMargin: '50px',\n\t\t\t\tthreshold: 0,\n\t\t\t});\n\t\t\tthis.IO.observe(this.options.container);\n\t\t}\n\t}\n\n\tprivate readonly onVisibilityCheck = (entries: Array<IntersectionObserverEntry>) => {\n\t\tentries.forEach((entry) => {\n\t\t\tif (entry.isIntersecting) {\n\t\t\t\tthis.load();\n\t\t\t\tthis.IO?.disconnect();\n\t\t\t\tthis.IO = undefined;\n\t\t\t\treturn;\n\t\t\t}\n\t\t});\n\t};\n\n\tprivate readonly augment = (aug: GeneralObject) => {\n\t\tconst descriptors = Object.getOwnPropertyDescriptors(aug);\n\t\tObject.defineProperties(this, descriptors);\n\t};\n\n\tload = (options?: {\n\t\tcanvas?: JSONCanvas;\n\t\tattachmentDir?: string;\n\t\tattachments?: Record<string, string>;\n\t}) => {\n\t\tif (this.disposed) return;\n\t\tif (options) Object.assign(this.options, options);\n\t\tif (this.started) this.onRestart();\n\t\telse {\n\t\t\tthis.onStart();\n\t\t\tthis.started = true;\n\t\t}\n\t};\n\n\tdispose = () => {\n\t\tif (!this.started || this.disposed) return;\n\t\tthis.IO?.disconnect();\n\t\tthis.IO = undefined;\n\t\tconst container = this.options.container;\n\t\twhile (container.firstChild) container.firstChild.remove();\n\t\tthis.onDispose();\n\t\tthis.container.unbindAll();\n\t\tthis.disposed = true;\n\t};\n}\n\ntype JSONCanvasViewerType = new <M extends ModuleInputCtor = []>(\n\t...args: ConstructorParameters<typeof JSONCanvasViewer<M>>\n) => JSONCanvasViewer<M> & AllAugmentation<M>;\n\nexport type JSONCanvasViewerInterface<M extends ModuleInput = []> = JSONCanvasViewer<never> &\n\tAllAugmentation<M>;\n\nexport default JSONCanvasViewer as JSONCanvasViewerType;\n"],"mappings":"6RAuBA,MAAM,EAAkB,CACvB,EACA,EACA,EACA,EACA,EACA,EACA,CAOD,IAAM,EAAN,KAAkD,CACjD,WACA,GACA,QAAkB,GAClB,SAAmB,GACnB,QACA,UACA,UAAY,EAAS,GAAK,CAC1B,QAAU,GAAU,CACpB,UAAY,GAAU,CAEtB,YAAY,EAAwB,EAAa,CAChD,KAAK,UAAY,IAAI,EACrB,KAAK,QAAU,EACf,IAAM,EAAQ,GAA6B,CAC1C,KAAK,UAAU,KAAK,CACnB,QAAS,EACT,eACC,IAAI,EACH,KAAK,UACL,KAAK,QACL,KAAK,QACL,KAAK,UACL,KAAK,UACL,KAAK,QACL,CACF,CAAC,EAEH,KAAK,WAAa,CAAC,GAAG,EAAiB,GAAI,GAAW,EAAE,CAAE,CAC1D,KAAK,WAAW,QAAQ,EAAK,CAC7B,KAAK,WAAW,QAAS,GAAW,CACnC,KAAK,UAAU,IAAI,EAAO,EACzB,CAEF,IAAM,EAAU,KAAK,QAAQ,SAAW,SACpC,IAAY,SAAU,KAAK,MAAM,CAC5B,IAAY,SACpB,KAAK,GAAK,IAAI,qBAAqB,KAAK,kBAAmB,CAC1D,WAAY,OACZ,UAAW,EACX,CAAC,CACF,KAAK,GAAG,QAAQ,KAAK,QAAQ,UAAU,EAIzC,kBAAsC,GAA8C,CACnF,EAAQ,QAAS,GAAU,CAC1B,GAAI,EAAM,eAAgB,CACzB,KAAK,MAAM,CACX,KAAK,IAAI,YAAY,CACrB,KAAK,GAAK,IAAA,GACV,SAEA,EAGH,QAA4B,GAAuB,CAClD,IAAM,EAAc,OAAO,0BAA0B,EAAI,CACzD,OAAO,iBAAiB,KAAM,EAAY,EAG3C,KAAQ,GAIF,CACD,KAAK,WACL,GAAS,OAAO,OAAO,KAAK,QAAS,EAAQ,CAC7C,KAAK,QAAS,KAAK,WAAW,EAEjC,KAAK,SAAS,CACd,KAAK,QAAU,MAIjB,YAAgB,CACf,GAAI,CAAC,KAAK,SAAW,KAAK,SAAU,OACpC,KAAK,IAAI,YAAY,CACrB,KAAK,GAAK,IAAA,GACV,IAAM,EAAY,KAAK,QAAQ,UAC/B,KAAO,EAAU,YAAY,EAAU,WAAW,QAAQ,CAC1D,KAAK,WAAW,CAChB,KAAK,UAAU,WAAW,CAC1B,KAAK,SAAW"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/kernel/index.ts"],"sourcesContent":["import type {\n\tModuleInputCtor,\n\tModuleInput,\n\tOptions,\n\tAugmentation,\n\tGeneralModuleCtor,\n} from '$/BaseModule';\nimport type { GeneralObject } from '$/types';\nimport type { JSONCanvas } from '@repo/shared';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport InteractionHandler from '$/InteractionHandler';\nimport OverlayManager from '$/OverlayManager';\nimport Renderer from '$/Renderer';\nimport StyleManager from '$/StyleManager';\nimport { makeHook } from '$/utilities';\nimport { Container } from '@needle-di/core';\n\nexport type BaseOptions = {\n\tcontainer: HTMLElement;\n\tloading?: 'normal' | 'lazy' | 'none';\n};\n\nconst internalModules = [\n\tDataManager,\n\tStyleManager,\n\tController,\n\tOverlayManager,\n\tInteractionHandler,\n\tRenderer,\n];\n\ntype InternalModules = typeof internalModules;\n\nexport type AllOptions<M extends ModuleInput = []> = Options<M> & Options<InternalModules>;\ntype AllAugmentation<M extends ModuleInput = []> = Augmentation<M> & Augmentation<InternalModules>;\n\nclass JSONCanvasViewer<M extends ModuleInputCtor> {\n\tprivate readonly allModules: ModuleInputCtor;\n\tprivate IO?: IntersectionObserver;\n\tprivate started = false;\n\tprivate disposed = false;\n\toptions: AllOptions<M>;\n\tcontainer: Container;\n\tonDispose = makeHook(true);\n\tonStart = makeHook();\n\tonRestart = makeHook();\n\n\tconstructor(options: AllOptions<M>, modules?: M) {\n\t\tthis.container = new Container();\n\t\tthis.options = options;\n\t\tconst bind = (Class: GeneralModuleCtor) => {\n\t\t\tthis.container.bind({\n\t\t\t\tprovide: Class,\n\t\t\t\tuseFactory: () =>\n\t\t\t\t\tnew Class(\n\t\t\t\t\t\tthis.container,\n\t\t\t\t\t\tthis.options,\n\t\t\t\t\t\tthis.onStart,\n\t\t\t\t\t\tthis.onDispose,\n\t\t\t\t\t\tthis.onRestart,\n\t\t\t\t\t\tthis.augment,\n\t\t\t\t\t),\n\t\t\t});\n\t\t};\n\t\tthis.allModules = [...internalModules, ...(modules ?? [])];\n\t\tthis.allModules.forEach(bind);\n\t\tthis.allModules.forEach((Module) => {\n\t\t\tthis.container.get(Module);\n\t\t});\n\n\t\tconst loading = this.options.loading ?? 'normal';\n\t\tif (loading === 'normal') this.load();\n\t\telse if (loading === 'lazy') {\n\t\t\tthis.IO = new IntersectionObserver(this.onVisibilityCheck, {\n\t\t\t\trootMargin: '50px',\n\t\t\t\tthreshold: 0,\n\t\t\t});\n\t\t\tthis.IO.observe(this.options.container);\n\t\t}\n\t}\n\n\tprivate readonly onVisibilityCheck = (entries: Array<IntersectionObserverEntry>) => {\n\t\tentries.forEach((entry) => {\n\t\t\tif (entry.isIntersecting) {\n\t\t\t\tthis.load();\n\t\t\t\tthis.IO?.disconnect();\n\t\t\t\tthis.IO = undefined;\n\t\t\t\treturn;\n\t\t\t}\n\t\t});\n\t};\n\n\tprivate readonly augment = (aug: GeneralObject) => {\n\t\tconst descriptors = Object.getOwnPropertyDescriptors(aug);\n\t\tObject.defineProperties(this, descriptors);\n\t};\n\n\tload = (options?: {\n\t\tcanvas?: JSONCanvas;\n\t\tattachmentDir?: string;\n\t\tattachments?: Record<string, string>;\n\t}) => {\n\t\tif (this.disposed) return;\n\t\tif (options) Object.assign(this.options, options);\n\t\tif (this.started) this.onRestart();\n\t\telse {\n\t\t\tthis.onStart();\n\t\t\tthis.started = true;\n\t\t}\n\t};\n\n\tdispose = () => {\n\t\tif (!this.started || this.disposed) return;\n\t\tthis.IO?.disconnect();\n\t\tthis.IO = undefined;\n\t\tconst container = this.options.container;\n\t\twhile (container.firstChild) container.firstChild.remove();\n\t\tthis.onDispose();\n\t\tthis.container.unbindAll();\n\t\tthis.disposed = true;\n\t};\n}\n\ntype JSONCanvasViewerType = new <M extends ModuleInputCtor = []>(\n\t...args: ConstructorParameters<typeof JSONCanvasViewer<M>>\n) => JSONCanvasViewer<M> & AllAugmentation<M>;\n\nexport type JSONCanvasViewerInterface<M extends ModuleInput = []> = JSONCanvasViewer<never> &\n\tAllAugmentation<M>;\n\nexport default JSONCanvasViewer as JSONCanvasViewerType;\n"],"mappings":"6RAuBA,MAAM,EAAkB,CACvB,EACA,EACA,EACA,EACA,EACA,EACA,CAOD,IAAM,EAAN,KAAkD,CACjD,WACA,GACA,QAAkB,GAClB,SAAmB,GACnB,QACA,UACA,UAAY,EAAS,GAAK,CAC1B,QAAU,GAAU,CACpB,UAAY,GAAU,CAEtB,YAAY,EAAwB,EAAa,CAChD,KAAK,UAAY,IAAI,EACrB,KAAK,QAAU,EACf,IAAM,EAAQ,GAA6B,CAC1C,KAAK,UAAU,KAAK,CACnB,QAAS,EACT,eACC,IAAI,EACH,KAAK,UACL,KAAK,QACL,KAAK,QACL,KAAK,UACL,KAAK,UACL,KAAK,QACL,CACF,CAAC,EAEH,KAAK,WAAa,CAAC,GAAG,EAAiB,GAAI,GAAW,EAAE,CAAE,CAC1D,KAAK,WAAW,QAAQ,EAAK,CAC7B,KAAK,WAAW,QAAS,GAAW,CACnC,KAAK,UAAU,IAAI,EAAO,EACzB,CAEF,IAAM,EAAU,KAAK,QAAQ,SAAW,SACpC,IAAY,SAAU,KAAK,MAAM,CAC5B,IAAY,SACpB,KAAK,GAAK,IAAI,qBAAqB,KAAK,kBAAmB,CAC1D,WAAY,OACZ,UAAW,EACX,CAAC,CACF,KAAK,GAAG,QAAQ,KAAK,QAAQ,UAAU,EAIzC,kBAAsC,GAA8C,CACnF,EAAQ,QAAS,GAAU,CAC1B,GAAI,EAAM,eAAgB,CACzB,KAAK,MAAM,CACX,KAAK,IAAI,YAAY,CACrB,KAAK,GAAK,IAAA,GACV,SAEA,EAGH,QAA4B,GAAuB,CAClD,IAAM,EAAc,OAAO,0BAA0B,EAAI,CACzD,OAAO,iBAAiB,KAAM,EAAY,EAG3C,KAAQ,GAIF,CACD,KAAK,WACL,GAAS,OAAO,OAAO,KAAK,QAAS,EAAQ,CAC7C,KAAK,QAAS,KAAK,WAAW,EAEjC,KAAK,SAAS,CACd,KAAK,QAAU,MAIjB,YAAgB,CACf,GAAI,CAAC,KAAK,SAAW,KAAK,SAAU,OACpC,KAAK,IAAI,YAAY,CACrB,KAAK,GAAK,IAAA,GACV,IAAM,EAAY,KAAK,QAAQ,UAC/B,KAAO,EAAU,YAAY,EAAU,WAAW,QAAQ,CAC1D,KAAK,WAAW,CAChB,KAAK,UAAU,WAAW,CAC1B,KAAK,SAAW"}
@@ -9,13 +9,13 @@ type Augmentation = {
9
9
  toggleControlsCollapse: Controls['toggleCollapse'];
10
10
  };
11
11
  declare class Controls extends BaseModule<Options, Augmentation> {
12
- private _controlsPanel;
13
- private _toggleCollapseBtn;
14
- private _toggleFullscreenBtn;
15
- private _zoomOutBtn;
16
- private _zoomSlider;
17
- private _zoomInBtn;
18
- private _resetViewBtn;
12
+ private _controlsPanel?;
13
+ private _toggleCollapseBtn?;
14
+ private _toggleFullscreenBtn?;
15
+ private _zoomOutBtn?;
16
+ private _zoomSlider?;
17
+ private _zoomInBtn?;
18
+ private _resetViewBtn?;
19
19
  private readonly DM;
20
20
  private readonly IH;
21
21
  private collapsed;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["style"],"sources":["../../../src/modules/Controls/index.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport InteractionHandler from '$/InteractionHandler';\nimport { applyStyles, destroyError } from '$/utilities';\nimport style from './styles.scss?inline';\n\ntype Options = {\n\tcontrolsCollapsed?: boolean;\n} & BaseOptions;\n\ntype Augmentation = {\n\ttoggleControlsCollapse: Controls['toggleCollapse'];\n};\n\nconst resetIcon =\n\t'<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>';\nconst enterFullscreenIcon =\n\t'<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>';\nconst exitFullscreenIcon =\n\t'<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>';\nconst zoomInIcon =\n\t'<svg viewBox=\"-1.2 -1.2 26.4 26.4\"><path d=\"M6 12h12m-6-6v12\" stroke-width=\"2\" stroke-linecap=\"round\" /></svg>';\nconst zoomOutIcon =\n\t'<svg viewBox=\"-1.2 -1.2 26.4 26.4\"><path d=\"M6 12h12\" stroke-width=\"2\" stroke-linecap=\"round\" /></svg>';\nconst toggleCollapseIcon =\n\t'<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>';\n\nexport default class Controls extends BaseModule<Options, Augmentation> {\n\tprivate _controlsPanel: HTMLDivElement | undefined;\n\tprivate _toggleCollapseBtn: HTMLButtonElement | undefined;\n\tprivate _toggleFullscreenBtn: HTMLButtonElement | undefined;\n\tprivate _zoomOutBtn: HTMLButtonElement | undefined;\n\tprivate _zoomSlider: HTMLInputElement | undefined;\n\tprivate _zoomInBtn: HTMLButtonElement | undefined;\n\tprivate _resetViewBtn: HTMLButtonElement | undefined;\n\tprivate readonly DM: DataManager;\n\tprivate readonly IH: InteractionHandler;\n\tprivate collapsed: boolean;\n\n\tprivate get controlsPanel() {\n\t\tif (!this._controlsPanel) throw destroyError;\n\t\treturn this._controlsPanel;\n\t}\n\tprivate get toggleCollapseBtn() {\n\t\tif (!this._toggleCollapseBtn) throw destroyError;\n\t\treturn this._toggleCollapseBtn;\n\t}\n\tprivate get toggleFullscreenBtn() {\n\t\tif (!this._toggleFullscreenBtn) throw destroyError;\n\t\treturn this._toggleFullscreenBtn;\n\t}\n\tprivate get zoomOutBtn() {\n\t\tif (!this._zoomOutBtn) throw destroyError;\n\t\treturn this._zoomOutBtn;\n\t}\n\tprivate get zoomSlider() {\n\t\tif (!this._zoomSlider) throw destroyError;\n\t\treturn this._zoomSlider;\n\t}\n\tprivate get zoomInBtn() {\n\t\tif (!this._zoomInBtn) throw destroyError;\n\t\treturn this._zoomInBtn;\n\t}\n\tprivate get resetViewBtn() {\n\t\tif (!this._resetViewBtn) throw destroyError;\n\t\treturn this._resetViewBtn;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.collapsed = this.options.controlsCollapsed ?? false;\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.IH = this.container.get(InteractionHandler);\n\t\tthis.DM.onToggleFullscreen.subscribe(this.updateFullscreenBtn);\n\t\tthis.container.get(Controller).onRefresh.subscribe(this.updateSlider);\n\n\t\tthis._controlsPanel = document.createElement('div');\n\t\tthis._controlsPanel.className = 'JCV-controls';\n\t\tthis._controlsPanel.classList.toggle('JCV-collapsed', this.collapsed);\n\n\t\tapplyStyles(this._controlsPanel, style);\n\n\t\tthis._toggleCollapseBtn = document.createElement('button');\n\t\tthis._toggleCollapseBtn.className = 'JCV-button JCV-collapse-button JCV-border-shadow-bg';\n\t\tthis._toggleCollapseBtn.innerHTML = toggleCollapseIcon;\n\t\tthis._controlsPanel.appendChild(this._toggleCollapseBtn);\n\n\t\tconst controlsContent = document.createElement('div');\n\t\tcontrolsContent.className = 'JCV-controls-content';\n\n\t\tthis._toggleFullscreenBtn = document.createElement('button');\n\t\tthis._toggleFullscreenBtn.className = 'JCV-button';\n\t\tthis._toggleFullscreenBtn.innerHTML = enterFullscreenIcon;\n\t\tcontrolsContent.appendChild(this._toggleFullscreenBtn);\n\n\t\tthis._zoomOutBtn = document.createElement('button');\n\t\tthis.zoomOutBtn.className = 'JCV-button';\n\t\tthis._zoomOutBtn.innerHTML = zoomOutIcon;\n\t\tcontrolsContent.appendChild(this._zoomOutBtn);\n\n\t\tthis._zoomSlider = document.createElement('input');\n\t\tthis._zoomSlider.type = 'range';\n\t\tthis._zoomSlider.className = 'JCV-zoom-slider';\n\t\tthis._zoomSlider.min = '-30';\n\t\tthis._zoomSlider.max = '30';\n\t\tthis._zoomSlider.value = '0';\n\t\tcontrolsContent.appendChild(this._zoomSlider);\n\n\t\tthis._zoomInBtn = document.createElement('button');\n\t\tthis._zoomInBtn.className = 'JCV-button';\n\t\tthis._zoomInBtn.innerHTML = zoomInIcon;\n\t\tcontrolsContent.appendChild(this._zoomInBtn);\n\n\t\tthis._resetViewBtn = document.createElement('button');\n\t\tthis._resetViewBtn.className = 'JCV-button';\n\t\tthis._resetViewBtn.innerHTML = resetIcon;\n\t\tcontrolsContent.appendChild(this._resetViewBtn);\n\n\t\tthis._controlsPanel.appendChild(controlsContent);\n\n\t\tthis.DM.data.container.appendChild(this._controlsPanel);\n\n\t\tthis._toggleCollapseBtn.addEventListener('click', this.toggleCollapse);\n\t\tthis._zoomInBtn.addEventListener('click', this.zoomIn);\n\t\tthis._zoomOutBtn.addEventListener('click', this.zoomOut);\n\t\tthis._zoomSlider.addEventListener('input', this.slide);\n\t\tthis._resetViewBtn.addEventListener('click', this.DM.resetView);\n\t\tthis._toggleFullscreenBtn.addEventListener('click', this.toggleFullscreen);\n\n\t\tthis.augment({ toggleControlsCollapse: this.toggleCollapse });\n\t\tthis.onDispose(this.dispose);\n\t}\n\ttoggleCollapse = () => {\n\t\tthis.collapsed = !this.collapsed;\n\t\tthis.controlsPanel.classList.toggle('JCV-collapsed', this.collapsed);\n\t\tif (!this.collapsed) this.updateSlider();\n\t};\n\tprivate readonly zoomIn = () => this.IH.zoom(1.3, this.DM.middleViewer());\n\tprivate readonly zoomOut = () => this.IH.zoom(1 / 1.3, this.DM.middleViewer());\n\tprivate readonly slide = () =>\n\t\tthis.IH.trueZoom(\n\t\t\t1.1 ** Number(this.zoomSlider.value) / this.DM.data.scale,\n\t\t\tthis.DM.middleViewer(),\n\t\t);\n\n\tprivate readonly updateFullscreenBtn = (enter: 'enter' | 'exit') => {\n\t\tthis.toggleFullscreenBtn.innerHTML =\n\t\t\tenter === 'enter' ? exitFullscreenIcon : enterFullscreenIcon;\n\t};\n\tprivate readonly toggleFullscreen = () => this.DM.toggleFullscreen();\n\n\tprivate readonly updateSlider = () => {\n\t\tif (this.collapsed) return;\n\t\tthis.zoomSlider.value = String(this.scaleToSlider(this.DM.data.scale));\n\t};\n\tprivate readonly scaleToSlider = (scale: number) => Math.log(scale) / Math.log(1.1);\n\n\tprivate readonly dispose = () => {\n\t\tthis.toggleCollapseBtn.removeEventListener('click', this.toggleCollapse);\n\t\tthis.zoomInBtn.removeEventListener('click', this.zoomIn);\n\t\tthis.zoomOutBtn.removeEventListener('click', this.zoomOut);\n\t\tthis.zoomSlider.removeEventListener('input', this.slide);\n\t\tthis.resetViewBtn.removeEventListener('click', this.DM.resetView);\n\t\tthis.toggleFullscreenBtn.removeEventListener('click', this.toggleFullscreen);\n\t\tthis.controlsPanel.remove();\n\t\tthis._controlsPanel = undefined;\n\t\tthis._toggleCollapseBtn = undefined;\n\t\tthis._zoomInBtn = undefined;\n\t\tthis._zoomOutBtn = undefined;\n\t\tthis._zoomSlider = undefined;\n\t\tthis._resetViewBtn = undefined;\n\t\tthis._toggleFullscreenBtn = undefined;\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["style"],"sources":["../../../src/modules/Controls/index.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport InteractionHandler from '$/InteractionHandler';\nimport { applyStyles, destroyError } from '$/utilities';\nimport style from './styles.scss?inline';\n\ntype Options = {\n\tcontrolsCollapsed?: boolean;\n} & BaseOptions;\n\ntype Augmentation = {\n\ttoggleControlsCollapse: Controls['toggleCollapse'];\n};\n\nconst resetIcon =\n\t'<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>';\nconst enterFullscreenIcon =\n\t'<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>';\nconst exitFullscreenIcon =\n\t'<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>';\nconst zoomInIcon =\n\t'<svg viewBox=\"-1.2 -1.2 26.4 26.4\"><path d=\"M6 12h12m-6-6v12\" stroke-width=\"2\" stroke-linecap=\"round\" /></svg>';\nconst zoomOutIcon =\n\t'<svg viewBox=\"-1.2 -1.2 26.4 26.4\"><path d=\"M6 12h12\" stroke-width=\"2\" stroke-linecap=\"round\" /></svg>';\nconst toggleCollapseIcon =\n\t'<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>';\n\nexport default class Controls extends BaseModule<Options, Augmentation> {\n\tprivate _controlsPanel?: HTMLDivElement;\n\tprivate _toggleCollapseBtn?: HTMLButtonElement;\n\tprivate _toggleFullscreenBtn?: HTMLButtonElement;\n\tprivate _zoomOutBtn?: HTMLButtonElement;\n\tprivate _zoomSlider?: HTMLInputElement;\n\tprivate _zoomInBtn?: HTMLButtonElement;\n\tprivate _resetViewBtn?: HTMLButtonElement;\n\tprivate readonly DM: DataManager;\n\tprivate readonly IH: InteractionHandler;\n\tprivate collapsed: boolean;\n\n\tprivate get controlsPanel() {\n\t\tif (!this._controlsPanel) throw destroyError;\n\t\treturn this._controlsPanel;\n\t}\n\tprivate get toggleCollapseBtn() {\n\t\tif (!this._toggleCollapseBtn) throw destroyError;\n\t\treturn this._toggleCollapseBtn;\n\t}\n\tprivate get toggleFullscreenBtn() {\n\t\tif (!this._toggleFullscreenBtn) throw destroyError;\n\t\treturn this._toggleFullscreenBtn;\n\t}\n\tprivate get zoomOutBtn() {\n\t\tif (!this._zoomOutBtn) throw destroyError;\n\t\treturn this._zoomOutBtn;\n\t}\n\tprivate get zoomSlider() {\n\t\tif (!this._zoomSlider) throw destroyError;\n\t\treturn this._zoomSlider;\n\t}\n\tprivate get zoomInBtn() {\n\t\tif (!this._zoomInBtn) throw destroyError;\n\t\treturn this._zoomInBtn;\n\t}\n\tprivate get resetViewBtn() {\n\t\tif (!this._resetViewBtn) throw destroyError;\n\t\treturn this._resetViewBtn;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.collapsed = this.options.controlsCollapsed ?? false;\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.IH = this.container.get(InteractionHandler);\n\t\tthis.DM.onToggleFullscreen.subscribe(this.updateFullscreenBtn);\n\t\tthis.container.get(Controller).onRefresh.subscribe(this.updateSlider);\n\n\t\tthis._controlsPanel = document.createElement('div');\n\t\tthis._controlsPanel.className = 'JCV-controls';\n\t\tthis._controlsPanel.classList.toggle('JCV-collapsed', this.collapsed);\n\n\t\tapplyStyles(this._controlsPanel, style);\n\n\t\tthis._toggleCollapseBtn = document.createElement('button');\n\t\tthis._toggleCollapseBtn.className = 'JCV-button JCV-collapse-button JCV-border-shadow-bg';\n\t\tthis._toggleCollapseBtn.innerHTML = toggleCollapseIcon;\n\t\tthis._controlsPanel.appendChild(this._toggleCollapseBtn);\n\n\t\tconst controlsContent = document.createElement('div');\n\t\tcontrolsContent.className = 'JCV-controls-content';\n\n\t\tthis._toggleFullscreenBtn = document.createElement('button');\n\t\tthis._toggleFullscreenBtn.className = 'JCV-button';\n\t\tthis._toggleFullscreenBtn.innerHTML = enterFullscreenIcon;\n\t\tcontrolsContent.appendChild(this._toggleFullscreenBtn);\n\n\t\tthis._zoomOutBtn = document.createElement('button');\n\t\tthis.zoomOutBtn.className = 'JCV-button';\n\t\tthis._zoomOutBtn.innerHTML = zoomOutIcon;\n\t\tcontrolsContent.appendChild(this._zoomOutBtn);\n\n\t\tthis._zoomSlider = document.createElement('input');\n\t\tthis._zoomSlider.type = 'range';\n\t\tthis._zoomSlider.className = 'JCV-zoom-slider';\n\t\tthis._zoomSlider.min = '-30';\n\t\tthis._zoomSlider.max = '30';\n\t\tthis._zoomSlider.value = '0';\n\t\tcontrolsContent.appendChild(this._zoomSlider);\n\n\t\tthis._zoomInBtn = document.createElement('button');\n\t\tthis._zoomInBtn.className = 'JCV-button';\n\t\tthis._zoomInBtn.innerHTML = zoomInIcon;\n\t\tcontrolsContent.appendChild(this._zoomInBtn);\n\n\t\tthis._resetViewBtn = document.createElement('button');\n\t\tthis._resetViewBtn.className = 'JCV-button';\n\t\tthis._resetViewBtn.innerHTML = resetIcon;\n\t\tcontrolsContent.appendChild(this._resetViewBtn);\n\n\t\tthis._controlsPanel.appendChild(controlsContent);\n\n\t\tthis.DM.data.container.appendChild(this._controlsPanel);\n\n\t\tthis._toggleCollapseBtn.addEventListener('click', this.toggleCollapse);\n\t\tthis._zoomInBtn.addEventListener('click', this.zoomIn);\n\t\tthis._zoomOutBtn.addEventListener('click', this.zoomOut);\n\t\tthis._zoomSlider.addEventListener('input', this.slide);\n\t\tthis._resetViewBtn.addEventListener('click', this.DM.resetView);\n\t\tthis._toggleFullscreenBtn.addEventListener('click', this.toggleFullscreen);\n\n\t\tthis.augment({ toggleControlsCollapse: this.toggleCollapse });\n\t\tthis.onDispose(this.dispose);\n\t}\n\ttoggleCollapse = () => {\n\t\tthis.collapsed = !this.collapsed;\n\t\tthis.controlsPanel.classList.toggle('JCV-collapsed', this.collapsed);\n\t\tif (!this.collapsed) this.updateSlider();\n\t};\n\tprivate readonly zoomIn = () => this.IH.zoom(1.3, this.DM.middleViewer());\n\tprivate readonly zoomOut = () => this.IH.zoom(1 / 1.3, this.DM.middleViewer());\n\tprivate readonly slide = () =>\n\t\tthis.IH.trueZoom(\n\t\t\t1.1 ** Number(this.zoomSlider.value) / this.DM.data.scale,\n\t\t\tthis.DM.middleViewer(),\n\t\t);\n\n\tprivate readonly updateFullscreenBtn = (enter: 'enter' | 'exit') => {\n\t\tthis.toggleFullscreenBtn.innerHTML =\n\t\t\tenter === 'enter' ? exitFullscreenIcon : enterFullscreenIcon;\n\t};\n\tprivate readonly toggleFullscreen = () => this.DM.toggleFullscreen();\n\n\tprivate readonly updateSlider = () => {\n\t\tif (this.collapsed) return;\n\t\tthis.zoomSlider.value = String(this.scaleToSlider(this.DM.data.scale));\n\t};\n\tprivate readonly scaleToSlider = (scale: number) => Math.log(scale) / Math.log(1.1);\n\n\tprivate readonly dispose = () => {\n\t\tthis.toggleCollapseBtn.removeEventListener('click', this.toggleCollapse);\n\t\tthis.zoomInBtn.removeEventListener('click', this.zoomIn);\n\t\tthis.zoomOutBtn.removeEventListener('click', this.zoomOut);\n\t\tthis.zoomSlider.removeEventListener('input', this.slide);\n\t\tthis.resetViewBtn.removeEventListener('click', this.DM.resetView);\n\t\tthis.toggleFullscreenBtn.removeEventListener('click', this.toggleFullscreen);\n\t\tthis.controlsPanel.remove();\n\t\tthis._controlsPanel = undefined;\n\t\tthis._toggleCollapseBtn = undefined;\n\t\tthis._zoomInBtn = undefined;\n\t\tthis._zoomOutBtn = undefined;\n\t\tthis._zoomSlider = undefined;\n\t\tthis._resetViewBtn = undefined;\n\t\tthis._toggleFullscreenBtn = undefined;\n\t};\n}\n"],"mappings":"oSAiBA,MAEM,EACL,+ZAUD,IAAqB,EAArB,cAAsC,CAAkC,CACvE,eACA,mBACA,qBACA,YACA,YACA,WACA,cACA,GACA,GACA,UAEA,IAAY,eAAgB,CAC3B,GAAI,CAAC,KAAK,eAAgB,MAAM,EAChC,OAAO,KAAK,eAEb,IAAY,mBAAoB,CAC/B,GAAI,CAAC,KAAK,mBAAoB,MAAM,EACpC,OAAO,KAAK,mBAEb,IAAY,qBAAsB,CACjC,GAAI,CAAC,KAAK,qBAAsB,MAAM,EACtC,OAAO,KAAK,qBAEb,IAAY,YAAa,CACxB,GAAI,CAAC,KAAK,YAAa,MAAM,EAC7B,OAAO,KAAK,YAEb,IAAY,YAAa,CACxB,GAAI,CAAC,KAAK,YAAa,MAAM,EAC7B,OAAO,KAAK,YAEb,IAAY,WAAY,CACvB,GAAI,CAAC,KAAK,WAAY,MAAM,EAC5B,OAAO,KAAK,WAEb,IAAY,cAAe,CAC1B,GAAI,CAAC,KAAK,cAAe,MAAM,EAC/B,OAAO,KAAK,cAGb,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,KAAK,UAAY,KAAK,QAAQ,mBAAqB,GACnD,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,KAAK,GAAK,KAAK,UAAU,IAAI,EAAmB,CAChD,KAAK,GAAG,mBAAmB,UAAU,KAAK,oBAAoB,CAC9D,KAAK,UAAU,IAAI,EAAW,CAAC,UAAU,UAAU,KAAK,aAAa,CAErE,KAAK,eAAiB,SAAS,cAAc,MAAM,CACnD,KAAK,eAAe,UAAY,eAChC,KAAK,eAAe,UAAU,OAAO,gBAAiB,KAAK,UAAU,CAErE,EAAY,KAAK,eAAgBA,EAAM,CAEvC,KAAK,mBAAqB,SAAS,cAAc,SAAS,CAC1D,KAAK,mBAAmB,UAAY,sDACpC,KAAK,mBAAmB,UAAY,mMACpC,KAAK,eAAe,YAAY,KAAK,mBAAmB,CAExD,IAAM,EAAkB,SAAS,cAAc,MAAM,CACrD,EAAgB,UAAY,uBAE5B,KAAK,qBAAuB,SAAS,cAAc,SAAS,CAC5D,KAAK,qBAAqB,UAAY,aACtC,KAAK,qBAAqB,UAAY,EACtC,EAAgB,YAAY,KAAK,qBAAqB,CAEtD,KAAK,YAAc,SAAS,cAAc,SAAS,CACnD,KAAK,WAAW,UAAY,aAC5B,KAAK,YAAY,UAAY,yGAC7B,EAAgB,YAAY,KAAK,YAAY,CAE7C,KAAK,YAAc,SAAS,cAAc,QAAQ,CAClD,KAAK,YAAY,KAAO,QACxB,KAAK,YAAY,UAAY,kBAC7B,KAAK,YAAY,IAAM,MACvB,KAAK,YAAY,IAAM,KACvB,KAAK,YAAY,MAAQ,IACzB,EAAgB,YAAY,KAAK,YAAY,CAE7C,KAAK,WAAa,SAAS,cAAc,SAAS,CAClD,KAAK,WAAW,UAAY,aAC5B,KAAK,WAAW,UAAY,iHAC5B,EAAgB,YAAY,KAAK,WAAW,CAE5C,KAAK,cAAgB,SAAS,cAAc,SAAS,CACrD,KAAK,cAAc,UAAY,aAC/B,KAAK,cAAc,UAAY,6cAC/B,EAAgB,YAAY,KAAK,cAAc,CAE/C,KAAK,eAAe,YAAY,EAAgB,CAEhD,KAAK,GAAG,KAAK,UAAU,YAAY,KAAK,eAAe,CAEvD,KAAK,mBAAmB,iBAAiB,QAAS,KAAK,eAAe,CACtE,KAAK,WAAW,iBAAiB,QAAS,KAAK,OAAO,CACtD,KAAK,YAAY,iBAAiB,QAAS,KAAK,QAAQ,CACxD,KAAK,YAAY,iBAAiB,QAAS,KAAK,MAAM,CACtD,KAAK,cAAc,iBAAiB,QAAS,KAAK,GAAG,UAAU,CAC/D,KAAK,qBAAqB,iBAAiB,QAAS,KAAK,iBAAiB,CAE1E,KAAK,QAAQ,CAAE,uBAAwB,KAAK,eAAgB,CAAC,CAC7D,KAAK,UAAU,KAAK,QAAQ,CAE7B,mBAAuB,CACtB,KAAK,UAAY,CAAC,KAAK,UACvB,KAAK,cAAc,UAAU,OAAO,gBAAiB,KAAK,UAAU,CAC/D,KAAK,WAAW,KAAK,cAAc,EAEzC,WAAgC,KAAK,GAAG,KAAK,IAAK,KAAK,GAAG,cAAc,CAAC,CACzE,YAAiC,KAAK,GAAG,KAAK,EAAI,IAAK,KAAK,GAAG,cAAc,CAAC,CAC9E,UACC,KAAK,GAAG,SACP,KAAO,OAAO,KAAK,WAAW,MAAM,CAAG,KAAK,GAAG,KAAK,MACpD,KAAK,GAAG,cAAc,CACtB,CAEF,oBAAwC,GAA4B,CACnE,KAAK,oBAAoB,UACxB,IAAU,QAAU,mXAAqB,GAE3C,qBAA0C,KAAK,GAAG,kBAAkB,CAEpE,iBAAsC,CACjC,KAAK,YACT,KAAK,WAAW,MAAQ,OAAO,KAAK,cAAc,KAAK,GAAG,KAAK,MAAM,CAAC,GAEvE,cAAkC,GAAkB,KAAK,IAAI,EAAM,CAAG,KAAK,IAAI,IAAI,CAEnF,YAAiC,CAChC,KAAK,kBAAkB,oBAAoB,QAAS,KAAK,eAAe,CACxE,KAAK,UAAU,oBAAoB,QAAS,KAAK,OAAO,CACxD,KAAK,WAAW,oBAAoB,QAAS,KAAK,QAAQ,CAC1D,KAAK,WAAW,oBAAoB,QAAS,KAAK,MAAM,CACxD,KAAK,aAAa,oBAAoB,QAAS,KAAK,GAAG,UAAU,CACjE,KAAK,oBAAoB,oBAAoB,QAAS,KAAK,iBAAiB,CAC5E,KAAK,cAAc,QAAQ,CAC3B,KAAK,eAAiB,IAAA,GACtB,KAAK,mBAAqB,IAAA,GAC1B,KAAK,WAAa,IAAA,GAClB,KAAK,YAAc,IAAA,GACnB,KAAK,YAAc,IAAA,GACnB,KAAK,cAAgB,IAAA,GACrB,KAAK,qBAAuB,IAAA"}
@@ -2,7 +2,7 @@ import { BaseArgs, BaseModule } from "../../kernel/BaseModule.js";
2
2
 
3
3
  //#region src/modules/DebugPanel/index.d.ts
4
4
  declare class DebugPanel extends BaseModule {
5
- private _debugPanel;
5
+ private _debugPanel?;
6
6
  private readonly DM;
7
7
  private get debugPanel();
8
8
  constructor(...args: BaseArgs);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["style"],"sources":["../../../src/modules/DebugPanel/index.ts"],"sourcesContent":["import type { BaseArgs } from '$/BaseModule';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport { applyStyles, destroyError, round } from '$/utilities';\nimport style from './styles.scss?inline';\n\nexport default class DebugPanel extends BaseModule {\n\tprivate _debugPanel: HTMLDivElement | undefined;\n\tprivate readonly DM: DataManager;\n\n\tprivate get debugPanel() {\n\t\tif (!this._debugPanel) throw destroyError;\n\t\treturn this._debugPanel;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.container.get(Controller).onRefresh.subscribe(this.update);\n\t\tthis._debugPanel = document.createElement('div');\n\t\tthis._debugPanel.className = 'JCV-debug-panel JCV-border-shadow-bg';\n\t\tconst HTMLContainer = this.DM.data.container;\n\t\tapplyStyles(HTMLContainer, style);\n\t\tHTMLContainer.appendChild(this._debugPanel);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly update = () => {\n\t\tconst data = this.DM.data;\n\t\tthis.debugPanel.innerHTML = `<p>Scale: ${round(data.scale, 3)}</p><p>Offset: ${round(data.offsetX, 1)}, ${round(data.offsetY, 1)}</p>`;\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tthis.debugPanel.remove();\n\t\tthis._debugPanel = undefined;\n\t};\n}\n"],"mappings":"6PAOA,IAAqB,EAArB,cAAwC,CAAW,CAClD,YACA,GAEA,IAAY,YAAa,CACxB,GAAI,CAAC,KAAK,YAAa,MAAM,EAC7B,OAAO,KAAK,YAGb,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,KAAK,UAAU,IAAI,EAAW,CAAC,UAAU,UAAU,KAAK,OAAO,CAC/D,KAAK,YAAc,SAAS,cAAc,MAAM,CAChD,KAAK,YAAY,UAAY,uCAC7B,IAAM,EAAgB,KAAK,GAAG,KAAK,UACnC,EAAY,EAAeA,EAAM,CACjC,EAAc,YAAY,KAAK,YAAY,CAC3C,KAAK,UAAU,KAAK,QAAQ,CAG7B,WAAgC,CAC/B,IAAM,EAAO,KAAK,GAAG,KACrB,KAAK,WAAW,UAAY,aAAa,EAAM,EAAK,MAAO,EAAE,CAAC,iBAAiB,EAAM,EAAK,QAAS,EAAE,CAAC,IAAI,EAAM,EAAK,QAAS,EAAE,CAAC,OAGlI,YAAiC,CAChC,KAAK,WAAW,QAAQ,CACxB,KAAK,YAAc,IAAA"}
1
+ {"version":3,"file":"index.js","names":["style"],"sources":["../../../src/modules/DebugPanel/index.ts"],"sourcesContent":["import type { BaseArgs } from '$/BaseModule';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport { applyStyles, destroyError, round } from '$/utilities';\nimport style from './styles.scss?inline';\n\nexport default class DebugPanel extends BaseModule {\n\tprivate _debugPanel?: HTMLDivElement;\n\tprivate readonly DM: DataManager;\n\n\tprivate get debugPanel() {\n\t\tif (!this._debugPanel) throw destroyError;\n\t\treturn this._debugPanel;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.container.get(Controller).onRefresh.subscribe(this.update);\n\t\tthis._debugPanel = document.createElement('div');\n\t\tthis._debugPanel.className = 'JCV-debug-panel JCV-border-shadow-bg';\n\t\tconst HTMLContainer = this.DM.data.container;\n\t\tapplyStyles(HTMLContainer, style);\n\t\tHTMLContainer.appendChild(this._debugPanel);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly update = () => {\n\t\tconst data = this.DM.data;\n\t\tthis.debugPanel.innerHTML = `<p>Scale: ${round(data.scale, 3)}</p><p>Offset: ${round(data.offsetX, 1)}, ${round(data.offsetY, 1)}</p>`;\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tthis.debugPanel.remove();\n\t\tthis._debugPanel = undefined;\n\t};\n}\n"],"mappings":"6PAOA,IAAqB,EAArB,cAAwC,CAAW,CAClD,YACA,GAEA,IAAY,YAAa,CACxB,GAAI,CAAC,KAAK,YAAa,MAAM,EAC7B,OAAO,KAAK,YAGb,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,KAAK,UAAU,IAAI,EAAW,CAAC,UAAU,UAAU,KAAK,OAAO,CAC/D,KAAK,YAAc,SAAS,cAAc,MAAM,CAChD,KAAK,YAAY,UAAY,uCAC7B,IAAM,EAAgB,KAAK,GAAG,KAAK,UACnC,EAAY,EAAeA,EAAM,CACjC,EAAc,YAAY,KAAK,YAAY,CAC3C,KAAK,UAAU,KAAK,QAAQ,CAG7B,WAAgC,CAC/B,IAAM,EAAO,KAAK,GAAG,KACrB,KAAK,WAAW,UAAY,aAAa,EAAM,EAAK,MAAO,EAAE,CAAC,iBAAiB,EAAM,EAAK,QAAS,EAAE,CAAC,IAAI,EAAM,EAAK,QAAS,EAAE,CAAC,OAGlI,YAAiC,CAChC,KAAK,WAAW,QAAQ,CACxB,KAAK,YAAc,IAAA"}
@@ -9,11 +9,11 @@ type Augmentation = {
9
9
  toggleMinimapCollapse: Minimap['toggleCollapse'];
10
10
  };
11
11
  declare class Minimap extends BaseModule<Options, Augmentation> {
12
- private readonly _minimapCtx;
13
- private _viewportRectangle;
14
- private _minimap;
15
- private _minimapContainer;
16
- private _toggleMinimapBtn;
12
+ private readonly _minimapCtx?;
13
+ private _viewportRectangle?;
14
+ private _minimap?;
15
+ private _minimapContainer?;
16
+ private _toggleMinimapBtn?;
17
17
  private readonly minimapCache;
18
18
  private readonly DM;
19
19
  private readonly SM;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["style"],"sources":["../../../src/modules/Minimap/index.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { JSONCanvasEdge, JSONCanvasNode } from '@repo/shared';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport StyleManager from '$/StyleManager';\nimport {\n\tapplyStyles,\n\tdestroyError,\n\tdrawRoundRect,\n\tgetAnchorCoord,\n\tresizeCanvasForDPR,\n} from '$/utilities';\nimport style from './styles.scss?inline';\n\ntype Options = {\n\tminimapCollapsed?: boolean;\n} & BaseOptions;\n\ntype Augmentation = {\n\ttoggleMinimapCollapse: Minimap['toggleCollapse'];\n};\n\nconst toggleCollapseIcon =\n\t'<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>';\n\nexport default class Minimap extends BaseModule<Options, Augmentation> {\n\tprivate readonly _minimapCtx: CanvasRenderingContext2D | undefined;\n\tprivate _viewportRectangle: HTMLDivElement | undefined;\n\tprivate _minimap: HTMLDivElement | undefined;\n\tprivate _minimapContainer: HTMLDivElement | undefined;\n\tprivate _toggleMinimapBtn: HTMLButtonElement | undefined;\n\tprivate readonly minimapCache: { scale: number; centerX: number; centerY: number } = {\n\t\tcenterX: 0,\n\t\tcenterY: 0,\n\t\tscale: 1,\n\t};\n\tprivate readonly DM: DataManager;\n\tprivate readonly SM: StyleManager;\n\tprivate collapsed: boolean;\n\n\tprivate get minimap() {\n\t\tif (!this._minimap) throw destroyError;\n\t\treturn this._minimap;\n\t}\n\tprivate get minimapCtx() {\n\t\tif (!this._minimapCtx) throw destroyError;\n\t\treturn this._minimapCtx;\n\t}\n\tprivate get viewportRectangle() {\n\t\tif (!this._viewportRectangle) throw destroyError;\n\t\treturn this._viewportRectangle;\n\t}\n\tprivate get minimapContainer() {\n\t\tif (!this._minimapContainer) throw destroyError;\n\t\treturn this._minimapContainer;\n\t}\n\tprivate get toggleMinimapBtn() {\n\t\tif (!this._toggleMinimapBtn) throw destroyError;\n\t\treturn this._toggleMinimapBtn;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.collapsed = this.options.minimapCollapsed ?? false;\n\t\tthis.container.get(Controller).onRefresh.subscribe(this.updateViewportRectangle);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.SM = this.container.get(StyleManager);\n\n\t\tthis._minimapContainer = document.createElement('div');\n\t\tthis._minimapContainer.className = 'JCV-minimap-container';\n\n\t\tapplyStyles(this._minimapContainer, style);\n\n\t\tthis._toggleMinimapBtn = document.createElement('button');\n\t\tthis._toggleMinimapBtn.className =\n\t\t\t'JCV-button JCV-toggle-minimap JCV-collapse-button JCV-border-shadow-bg';\n\t\tthis._toggleMinimapBtn.innerHTML = toggleCollapseIcon;\n\t\tthis._minimapContainer.appendChild(this._toggleMinimapBtn);\n\n\t\tthis._minimap = document.createElement('div');\n\t\tthis._minimap.className = 'JCV-minimap JCV-border-shadow-bg';\n\t\tconst minimapCanvas = document.createElement('canvas');\n\t\tminimapCanvas.className = 'JCV-minimap-canvas';\n\t\tminimapCanvas.width = 200;\n\t\tminimapCanvas.height = 150;\n\n\t\tthis._minimap.appendChild(minimapCanvas);\n\t\tthis._minimapCtx = minimapCanvas.getContext('2d') as CanvasRenderingContext2D;\n\t\tthis._viewportRectangle = document.createElement('div');\n\t\tthis._viewportRectangle.className = 'JCV-viewport-rectangle';\n\t\tthis._minimap.appendChild(this._viewportRectangle);\n\t\tthis._minimapContainer.appendChild(this._minimap);\n\n\t\tthis.DM.data.container.appendChild(this._minimapContainer);\n\n\t\tthis._minimapContainer.classList.toggle('JCV-collapsed', this.collapsed);\n\n\t\tthis._toggleMinimapBtn.addEventListener('click', this.toggleCollapse);\n\t\tresizeCanvasForDPR(minimapCanvas, minimapCanvas.width, minimapCanvas.height);\n\n\t\tthis.augment({ toggleMinimapCollapse: this.toggleCollapse });\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\ttoggleCollapse = () => {\n\t\tthis.collapsed = !this.collapsed;\n\t\tthis.minimapContainer.classList.toggle('JCV-collapsed', this.collapsed);\n\t\tif (!this.collapsed) this.updateViewportRectangle();\n\t};\n\n\tprivate readonly start = () => {\n\t\tconst bounds = this.DM.data.nodeBounds;\n\t\tif (!bounds) return;\n\t\tconst displayWidth = this.minimap.clientWidth;\n\t\tconst displayHeight = this.minimap.clientHeight;\n\t\tconst scaleX = displayWidth / bounds.width;\n\t\tconst scaleY = displayHeight / bounds.height;\n\t\tthis.minimapCache.scale = Math.min(scaleX, scaleY) * 0.9;\n\t\tthis.minimapCache.centerX = displayWidth / 2;\n\t\tthis.minimapCache.centerY = displayHeight / 2;\n\t\tthis.minimapCtx.clearRect(0, 0, displayWidth, displayHeight);\n\t\tthis.minimapCtx.save();\n\t\tthis.minimapCtx.translate(this.minimapCache.centerX, this.minimapCache.centerY);\n\t\tthis.minimapCtx.scale(this.minimapCache.scale, this.minimapCache.scale);\n\t\tthis.minimapCtx.translate(-bounds.centerX, -bounds.centerY);\n\t\tconst canvasData = this.DM.data.canvasData;\n\t\tfor (const edge of canvasData.edges) this.drawMinimapEdge(edge);\n\t\tfor (const node of canvasData.nodes) this.drawMinimapNode(node);\n\t\tthis.minimapCtx.restore();\n\t};\n\n\tprivate readonly drawMinimapNode = (node: JSONCanvasNode) => {\n\t\tconst colors = this.SM.getColor(node.color);\n\t\tconst radius = 25;\n\t\tthis.minimapCtx.fillStyle = colors.border;\n\t\tdrawRoundRect(this.minimapCtx, node.x, node.y, node.width, node.height, radius);\n\t\tthis.minimapCtx.fill();\n\t};\n\n\tprivate readonly drawMinimapEdge = (edge: JSONCanvasEdge) => {\n\t\tconst canvasMap = this.DM.data.nodeMap;\n\t\tconst fromNode = canvasMap[edge.fromNode].ref;\n\t\tconst toNode = canvasMap[edge.toNode].ref;\n\t\tif (!fromNode || !toNode) return;\n\t\tconst { x: startX, y: startY } = getAnchorCoord(fromNode, edge.fromSide);\n\t\tconst { x: endX, y: endY } = getAnchorCoord(toNode, edge.toSide);\n\t\tthis.minimapCtx.beginPath();\n\t\tthis.minimapCtx.moveTo(startX, startY);\n\t\tthis.minimapCtx.lineTo(endX, endY);\n\t\tthis.minimapCtx.strokeStyle = this.SM.getColor(edge.color).active;\n\t\tthis.minimapCtx.lineWidth = 10;\n\t\tthis.minimapCtx.stroke();\n\t};\n\n\tprivate readonly updateViewportRectangle = () => {\n\t\tif (this.collapsed) return;\n\t\tconst bounds = this.DM.data.nodeBounds;\n\t\tconst container = this.DM.data.container;\n\t\tconst scale = this.DM.data.scale;\n\t\tif (!bounds) return;\n\t\tconst viewWidth = container.clientWidth / scale;\n\t\tconst viewHeight = container.clientHeight / scale;\n\t\tconst viewportCenterX = -this.DM.data.offsetX / scale + container.clientWidth / (2 * scale);\n\t\tconst viewportCenterY =\n\t\t\t-this.DM.data.offsetY / scale + container.clientHeight / (2 * scale);\n\t\tconst viewRectX =\n\t\t\tthis.minimapCache.centerX +\n\t\t\t(viewportCenterX - viewWidth / 2 - bounds.centerX) * this.minimapCache.scale;\n\t\tconst viewRectY =\n\t\t\tthis.minimapCache.centerY +\n\t\t\t(viewportCenterY - viewHeight / 2 - bounds.centerY) * this.minimapCache.scale;\n\t\tconst viewRectWidth = viewWidth * this.minimapCache.scale;\n\t\tconst viewRectHeight = viewHeight * this.minimapCache.scale;\n\t\tthis.viewportRectangle.style.left = `${viewRectX}px`;\n\t\tthis.viewportRectangle.style.top = `${viewRectY}px`;\n\t\tthis.viewportRectangle.style.width = `${viewRectWidth}px`;\n\t\tthis.viewportRectangle.style.height = `${viewRectHeight}px`;\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tthis.toggleMinimapBtn.removeEventListener('click', this.toggleCollapse);\n\t\tthis.minimapCtx.clearRect(0, 0, this.minimap.clientWidth, this.minimap.clientHeight);\n\t\tthis.minimapContainer.remove();\n\t\tthis._minimapContainer = undefined;\n\t\tthis._toggleMinimapBtn = undefined;\n\t\tthis._viewportRectangle = undefined;\n\t\tthis._minimap = undefined;\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["style"],"sources":["../../../src/modules/Minimap/index.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { JSONCanvasEdge, JSONCanvasNode } from '@repo/shared';\nimport { BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport StyleManager from '$/StyleManager';\nimport {\n\tapplyStyles,\n\tdestroyError,\n\tdrawRoundRect,\n\tgetAnchorCoord,\n\tresizeCanvasForDPR,\n} from '$/utilities';\nimport style from './styles.scss?inline';\n\ntype Options = {\n\tminimapCollapsed?: boolean;\n} & BaseOptions;\n\ntype Augmentation = {\n\ttoggleMinimapCollapse: Minimap['toggleCollapse'];\n};\n\nconst toggleCollapseIcon =\n\t'<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>';\n\nexport default class Minimap extends BaseModule<Options, Augmentation> {\n\tprivate readonly _minimapCtx?: CanvasRenderingContext2D;\n\tprivate _viewportRectangle?: HTMLDivElement;\n\tprivate _minimap?: HTMLDivElement;\n\tprivate _minimapContainer?: HTMLDivElement;\n\tprivate _toggleMinimapBtn?: HTMLButtonElement;\n\tprivate readonly minimapCache: { scale: number; centerX: number; centerY: number } = {\n\t\tcenterX: 0,\n\t\tcenterY: 0,\n\t\tscale: 1,\n\t};\n\tprivate readonly DM: DataManager;\n\tprivate readonly SM: StyleManager;\n\tprivate collapsed: boolean;\n\n\tprivate get minimap() {\n\t\tif (!this._minimap) throw destroyError;\n\t\treturn this._minimap;\n\t}\n\tprivate get minimapCtx() {\n\t\tif (!this._minimapCtx) throw destroyError;\n\t\treturn this._minimapCtx;\n\t}\n\tprivate get viewportRectangle() {\n\t\tif (!this._viewportRectangle) throw destroyError;\n\t\treturn this._viewportRectangle;\n\t}\n\tprivate get minimapContainer() {\n\t\tif (!this._minimapContainer) throw destroyError;\n\t\treturn this._minimapContainer;\n\t}\n\tprivate get toggleMinimapBtn() {\n\t\tif (!this._toggleMinimapBtn) throw destroyError;\n\t\treturn this._toggleMinimapBtn;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.collapsed = this.options.minimapCollapsed ?? false;\n\t\tthis.container.get(Controller).onRefresh.subscribe(this.updateViewportRectangle);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.SM = this.container.get(StyleManager);\n\n\t\tthis._minimapContainer = document.createElement('div');\n\t\tthis._minimapContainer.className = 'JCV-minimap-container';\n\n\t\tapplyStyles(this._minimapContainer, style);\n\n\t\tthis._toggleMinimapBtn = document.createElement('button');\n\t\tthis._toggleMinimapBtn.className =\n\t\t\t'JCV-button JCV-toggle-minimap JCV-collapse-button JCV-border-shadow-bg';\n\t\tthis._toggleMinimapBtn.innerHTML = toggleCollapseIcon;\n\t\tthis._minimapContainer.appendChild(this._toggleMinimapBtn);\n\n\t\tthis._minimap = document.createElement('div');\n\t\tthis._minimap.className = 'JCV-minimap JCV-border-shadow-bg';\n\t\tconst minimapCanvas = document.createElement('canvas');\n\t\tminimapCanvas.className = 'JCV-minimap-canvas';\n\t\tminimapCanvas.width = 200;\n\t\tminimapCanvas.height = 150;\n\n\t\tthis._minimap.appendChild(minimapCanvas);\n\t\tthis._minimapCtx = minimapCanvas.getContext('2d') as CanvasRenderingContext2D;\n\t\tthis._viewportRectangle = document.createElement('div');\n\t\tthis._viewportRectangle.className = 'JCV-viewport-rectangle';\n\t\tthis._minimap.appendChild(this._viewportRectangle);\n\t\tthis._minimapContainer.appendChild(this._minimap);\n\n\t\tthis.DM.data.container.appendChild(this._minimapContainer);\n\n\t\tthis._minimapContainer.classList.toggle('JCV-collapsed', this.collapsed);\n\n\t\tthis._toggleMinimapBtn.addEventListener('click', this.toggleCollapse);\n\t\tresizeCanvasForDPR(minimapCanvas, minimapCanvas.width, minimapCanvas.height);\n\n\t\tthis.augment({ toggleMinimapCollapse: this.toggleCollapse });\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\ttoggleCollapse = () => {\n\t\tthis.collapsed = !this.collapsed;\n\t\tthis.minimapContainer.classList.toggle('JCV-collapsed', this.collapsed);\n\t\tif (!this.collapsed) this.updateViewportRectangle();\n\t};\n\n\tprivate readonly start = () => {\n\t\tconst bounds = this.DM.data.nodeBounds;\n\t\tif (!bounds) return;\n\t\tconst displayWidth = this.minimap.clientWidth;\n\t\tconst displayHeight = this.minimap.clientHeight;\n\t\tconst scaleX = displayWidth / bounds.width;\n\t\tconst scaleY = displayHeight / bounds.height;\n\t\tthis.minimapCache.scale = Math.min(scaleX, scaleY) * 0.9;\n\t\tthis.minimapCache.centerX = displayWidth / 2;\n\t\tthis.minimapCache.centerY = displayHeight / 2;\n\t\tthis.minimapCtx.clearRect(0, 0, displayWidth, displayHeight);\n\t\tthis.minimapCtx.save();\n\t\tthis.minimapCtx.translate(this.minimapCache.centerX, this.minimapCache.centerY);\n\t\tthis.minimapCtx.scale(this.minimapCache.scale, this.minimapCache.scale);\n\t\tthis.minimapCtx.translate(-bounds.centerX, -bounds.centerY);\n\t\tconst canvasData = this.DM.data.canvasData;\n\t\tfor (const edge of canvasData.edges) this.drawMinimapEdge(edge);\n\t\tfor (const node of canvasData.nodes) this.drawMinimapNode(node);\n\t\tthis.minimapCtx.restore();\n\t};\n\n\tprivate readonly drawMinimapNode = (node: JSONCanvasNode) => {\n\t\tconst colors = this.SM.getColor(node.color);\n\t\tconst radius = 25;\n\t\tthis.minimapCtx.fillStyle = colors.border;\n\t\tdrawRoundRect(this.minimapCtx, node.x, node.y, node.width, node.height, radius);\n\t\tthis.minimapCtx.fill();\n\t};\n\n\tprivate readonly drawMinimapEdge = (edge: JSONCanvasEdge) => {\n\t\tconst canvasMap = this.DM.data.nodeMap;\n\t\tconst fromNode = canvasMap[edge.fromNode].ref;\n\t\tconst toNode = canvasMap[edge.toNode].ref;\n\t\tif (!fromNode || !toNode) return;\n\t\tconst { x: startX, y: startY } = getAnchorCoord(fromNode, edge.fromSide);\n\t\tconst { x: endX, y: endY } = getAnchorCoord(toNode, edge.toSide);\n\t\tthis.minimapCtx.beginPath();\n\t\tthis.minimapCtx.moveTo(startX, startY);\n\t\tthis.minimapCtx.lineTo(endX, endY);\n\t\tthis.minimapCtx.strokeStyle = this.SM.getColor(edge.color).active;\n\t\tthis.minimapCtx.lineWidth = 10;\n\t\tthis.minimapCtx.stroke();\n\t};\n\n\tprivate readonly updateViewportRectangle = () => {\n\t\tif (this.collapsed) return;\n\t\tconst bounds = this.DM.data.nodeBounds;\n\t\tconst container = this.DM.data.container;\n\t\tconst scale = this.DM.data.scale;\n\t\tif (!bounds) return;\n\t\tconst viewWidth = container.clientWidth / scale;\n\t\tconst viewHeight = container.clientHeight / scale;\n\t\tconst viewportCenterX = -this.DM.data.offsetX / scale + container.clientWidth / (2 * scale);\n\t\tconst viewportCenterY =\n\t\t\t-this.DM.data.offsetY / scale + container.clientHeight / (2 * scale);\n\t\tconst viewRectX =\n\t\t\tthis.minimapCache.centerX +\n\t\t\t(viewportCenterX - viewWidth / 2 - bounds.centerX) * this.minimapCache.scale;\n\t\tconst viewRectY =\n\t\t\tthis.minimapCache.centerY +\n\t\t\t(viewportCenterY - viewHeight / 2 - bounds.centerY) * this.minimapCache.scale;\n\t\tconst viewRectWidth = viewWidth * this.minimapCache.scale;\n\t\tconst viewRectHeight = viewHeight * this.minimapCache.scale;\n\t\tthis.viewportRectangle.style.left = `${viewRectX}px`;\n\t\tthis.viewportRectangle.style.top = `${viewRectY}px`;\n\t\tthis.viewportRectangle.style.width = `${viewRectWidth}px`;\n\t\tthis.viewportRectangle.style.height = `${viewRectHeight}px`;\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tthis.toggleMinimapBtn.removeEventListener('click', this.toggleCollapse);\n\t\tthis.minimapCtx.clearRect(0, 0, this.minimap.clientWidth, this.minimap.clientHeight);\n\t\tthis.minimapContainer.remove();\n\t\tthis._minimapContainer = undefined;\n\t\tthis._toggleMinimapBtn = undefined;\n\t\tthis._viewportRectangle = undefined;\n\t\tthis._minimap = undefined;\n\t};\n}\n"],"mappings":"6VA2BA,IAAqB,EAArB,cAAqC,CAAkC,CACtE,YACA,mBACA,SACA,kBACA,kBACA,aAAqF,CACpF,QAAS,EACT,QAAS,EACT,MAAO,EACP,CACD,GACA,GACA,UAEA,IAAY,SAAU,CACrB,GAAI,CAAC,KAAK,SAAU,MAAM,EAC1B,OAAO,KAAK,SAEb,IAAY,YAAa,CACxB,GAAI,CAAC,KAAK,YAAa,MAAM,EAC7B,OAAO,KAAK,YAEb,IAAY,mBAAoB,CAC/B,GAAI,CAAC,KAAK,mBAAoB,MAAM,EACpC,OAAO,KAAK,mBAEb,IAAY,kBAAmB,CAC9B,GAAI,CAAC,KAAK,kBAAmB,MAAM,EACnC,OAAO,KAAK,kBAEb,IAAY,kBAAmB,CAC9B,GAAI,CAAC,KAAK,kBAAmB,MAAM,EACnC,OAAO,KAAK,kBAGb,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,KAAK,UAAY,KAAK,QAAQ,kBAAoB,GAClD,KAAK,UAAU,IAAI,EAAW,CAAC,UAAU,UAAU,KAAK,wBAAwB,CAChF,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,KAAK,GAAK,KAAK,UAAU,IAAI,EAAa,CAE1C,KAAK,kBAAoB,SAAS,cAAc,MAAM,CACtD,KAAK,kBAAkB,UAAY,wBAEnC,EAAY,KAAK,kBAAmBA,EAAM,CAE1C,KAAK,kBAAoB,SAAS,cAAc,SAAS,CACzD,KAAK,kBAAkB,UACtB,yEACD,KAAK,kBAAkB,UAAY,mMACnC,KAAK,kBAAkB,YAAY,KAAK,kBAAkB,CAE1D,KAAK,SAAW,SAAS,cAAc,MAAM,CAC7C,KAAK,SAAS,UAAY,mCAC1B,IAAM,EAAgB,SAAS,cAAc,SAAS,CACtD,EAAc,UAAY,qBAC1B,EAAc,MAAQ,IACtB,EAAc,OAAS,IAEvB,KAAK,SAAS,YAAY,EAAc,CACxC,KAAK,YAAc,EAAc,WAAW,KAAK,CACjD,KAAK,mBAAqB,SAAS,cAAc,MAAM,CACvD,KAAK,mBAAmB,UAAY,yBACpC,KAAK,SAAS,YAAY,KAAK,mBAAmB,CAClD,KAAK,kBAAkB,YAAY,KAAK,SAAS,CAEjD,KAAK,GAAG,KAAK,UAAU,YAAY,KAAK,kBAAkB,CAE1D,KAAK,kBAAkB,UAAU,OAAO,gBAAiB,KAAK,UAAU,CAExE,KAAK,kBAAkB,iBAAiB,QAAS,KAAK,eAAe,CACrE,EAAmB,EAAe,EAAc,MAAO,EAAc,OAAO,CAE5E,KAAK,QAAQ,CAAE,sBAAuB,KAAK,eAAgB,CAAC,CAC5D,KAAK,QAAQ,KAAK,MAAM,CACxB,KAAK,UAAU,KAAK,MAAM,CAC1B,KAAK,UAAU,KAAK,QAAQ,CAG7B,mBAAuB,CACtB,KAAK,UAAY,CAAC,KAAK,UACvB,KAAK,iBAAiB,UAAU,OAAO,gBAAiB,KAAK,UAAU,CAClE,KAAK,WAAW,KAAK,yBAAyB,EAGpD,UAA+B,CAC9B,IAAM,EAAS,KAAK,GAAG,KAAK,WAC5B,GAAI,CAAC,EAAQ,OACb,IAAM,EAAe,KAAK,QAAQ,YAC5B,EAAgB,KAAK,QAAQ,aAC7B,EAAS,EAAe,EAAO,MAC/B,EAAS,EAAgB,EAAO,OACtC,KAAK,aAAa,MAAQ,KAAK,IAAI,EAAQ,EAAO,CAAG,GACrD,KAAK,aAAa,QAAU,EAAe,EAC3C,KAAK,aAAa,QAAU,EAAgB,EAC5C,KAAK,WAAW,UAAU,EAAG,EAAG,EAAc,EAAc,CAC5D,KAAK,WAAW,MAAM,CACtB,KAAK,WAAW,UAAU,KAAK,aAAa,QAAS,KAAK,aAAa,QAAQ,CAC/E,KAAK,WAAW,MAAM,KAAK,aAAa,MAAO,KAAK,aAAa,MAAM,CACvE,KAAK,WAAW,UAAU,CAAC,EAAO,QAAS,CAAC,EAAO,QAAQ,CAC3D,IAAM,EAAa,KAAK,GAAG,KAAK,WAChC,IAAK,IAAM,KAAQ,EAAW,MAAO,KAAK,gBAAgB,EAAK,CAC/D,IAAK,IAAM,KAAQ,EAAW,MAAO,KAAK,gBAAgB,EAAK,CAC/D,KAAK,WAAW,SAAS,EAG1B,gBAAoC,GAAyB,CAC5D,IAAM,EAAS,KAAK,GAAG,SAAS,EAAK,MAAM,CAE3C,KAAK,WAAW,UAAY,EAAO,OACnC,EAAc,KAAK,WAAY,EAAK,EAAG,EAAK,EAAG,EAAK,MAAO,EAAK,OAAQ,GAAO,CAC/E,KAAK,WAAW,MAAM,EAGvB,gBAAoC,GAAyB,CAC5D,IAAM,EAAY,KAAK,GAAG,KAAK,QACzB,EAAW,EAAU,EAAK,UAAU,IACpC,EAAS,EAAU,EAAK,QAAQ,IACtC,GAAI,CAAC,GAAY,CAAC,EAAQ,OAC1B,GAAM,CAAE,EAAG,EAAQ,EAAG,GAAW,EAAe,EAAU,EAAK,SAAS,CAClE,CAAE,EAAG,EAAM,EAAG,GAAS,EAAe,EAAQ,EAAK,OAAO,CAChE,KAAK,WAAW,WAAW,CAC3B,KAAK,WAAW,OAAO,EAAQ,EAAO,CACtC,KAAK,WAAW,OAAO,EAAM,EAAK,CAClC,KAAK,WAAW,YAAc,KAAK,GAAG,SAAS,EAAK,MAAM,CAAC,OAC3D,KAAK,WAAW,UAAY,GAC5B,KAAK,WAAW,QAAQ,EAGzB,4BAAiD,CAChD,GAAI,KAAK,UAAW,OACpB,IAAM,EAAS,KAAK,GAAG,KAAK,WACtB,EAAY,KAAK,GAAG,KAAK,UACzB,EAAQ,KAAK,GAAG,KAAK,MAC3B,GAAI,CAAC,EAAQ,OACb,IAAM,EAAY,EAAU,YAAc,EACpC,EAAa,EAAU,aAAe,EACtC,EAAkB,CAAC,KAAK,GAAG,KAAK,QAAU,EAAQ,EAAU,aAAe,EAAI,GAC/E,EACL,CAAC,KAAK,GAAG,KAAK,QAAU,EAAQ,EAAU,cAAgB,EAAI,GACzD,EACL,KAAK,aAAa,SACjB,EAAkB,EAAY,EAAI,EAAO,SAAW,KAAK,aAAa,MAClE,EACL,KAAK,aAAa,SACjB,EAAkB,EAAa,EAAI,EAAO,SAAW,KAAK,aAAa,MACnE,EAAgB,EAAY,KAAK,aAAa,MAC9C,EAAiB,EAAa,KAAK,aAAa,MACtD,KAAK,kBAAkB,MAAM,KAAO,GAAG,EAAU,IACjD,KAAK,kBAAkB,MAAM,IAAM,GAAG,EAAU,IAChD,KAAK,kBAAkB,MAAM,MAAQ,GAAG,EAAc,IACtD,KAAK,kBAAkB,MAAM,OAAS,GAAG,EAAe,KAGzD,YAAiC,CAChC,KAAK,iBAAiB,oBAAoB,QAAS,KAAK,eAAe,CACvE,KAAK,WAAW,UAAU,EAAG,EAAG,KAAK,QAAQ,YAAa,KAAK,QAAQ,aAAa,CACpF,KAAK,iBAAiB,QAAQ,CAC9B,KAAK,kBAAoB,IAAA,GACzB,KAAK,kBAAoB,IAAA,GACzB,KAAK,mBAAqB,IAAA,GAC1B,KAAK,SAAW,IAAA"}
@@ -11,7 +11,7 @@ type Augmentation = {
11
11
  endMistouchPrevention: MistouchPreventer['endPrevention'];
12
12
  };
13
13
  declare class MistouchPreventer extends BaseModule<Options, Augmentation> {
14
- private _preventionContainer;
14
+ private _preventionContainer?;
15
15
  private preventMt;
16
16
  private readonly DM;
17
17
  private readonly preventMistouch;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["style"],"sources":["../../../src/modules/MistouchPreventer/index.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport { BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport { applyStyles, destroyError } from '$/utilities';\nimport style from './styles.scss?inline';\n\ntype Options = {\n\tpreventMistouchAtStart?: boolean;\n\tmistouchPreventerBannerText?: string;\n} & BaseOptions;\n\ntype Augmentation = {\n\tstartMistouchPrevention: MistouchPreventer['startPrevention'];\n\tendMistouchPrevention: MistouchPreventer['endPrevention'];\n};\n\nexport default class MistouchPreventer extends BaseModule<Options, Augmentation> {\n\tprivate _preventionContainer: HTMLDivElement | undefined;\n\tprivate preventMt = false;\n\tprivate readonly DM: DataManager;\n\tprivate readonly preventMistouch: {\n\t\trecord: boolean;\n\t\tlastX: number;\n\t\tlastY: number;\n\t\tinitialX: number;\n\t\tinitialY: number;\n\t} = {\n\t\tinitialX: 0,\n\t\tinitialY: 0,\n\t\tlastX: 0,\n\t\tlastY: 0,\n\t\trecord: false,\n\t};\n\n\tprivate get preventionContainer() {\n\t\tif (!this._preventionContainer) throw destroyError;\n\t\treturn this._preventionContainer;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\n\t\tconst preventionBanner = document.createElement('div');\n\t\tpreventionBanner.className = 'JCV-prevention-banner JCV-border-shadow-bg';\n\t\tpreventionBanner.textContent =\n\t\t\tthis.options.mistouchPreventerBannerText ?? 'Click on to unlock.';\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis._preventionContainer = document.createElement('div');\n\t\tthis._preventionContainer.className =\n\t\t\t'JCV-prevention-container JCV-hidden JCV-full JCV-flex-center';\n\n\t\tapplyStyles(this._preventionContainer, style);\n\t\tthis._preventionContainer.appendChild(preventionBanner);\n\t\tthis.DM.data.container.appendChild(this._preventionContainer);\n\n\t\tif (this.options.preventMistouchAtStart) this.startPrevention();\n\n\t\twindow.addEventListener('pointerdown', this.onPointerDown);\n\t\twindow.addEventListener('pointermove', this.onPointerMove);\n\t\twindow.addEventListener('pointerup', this.onPointerUp);\n\n\t\tthis.augment({\n\t\t\tendMistouchPrevention: this.endPrevention,\n\t\t\tstartMistouchPrevention: this.startPrevention,\n\t\t});\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly onPointerDown = (e: PointerEvent) => {\n\t\tconst bounds = this.DM.data.container.getBoundingClientRect();\n\t\tif (\n\t\t\te.clientX < bounds.left ||\n\t\t\te.clientX > bounds.right ||\n\t\t\te.clientY < bounds.top ||\n\t\t\te.clientY > bounds.bottom\n\t\t) {\n\t\t\tif (!this.preventMt) this.startPrevention();\n\t\t} else if (this.preventMt) {\n\t\t\tthis.preventMistouch.initialX = e.clientX;\n\t\t\tthis.preventMistouch.initialY = e.clientY;\n\t\t\tthis.preventMistouch.lastX = e.clientX;\n\t\t\tthis.preventMistouch.lastY = e.clientY;\n\t\t\tthis.preventMistouch.record = true;\n\t\t}\n\t};\n\n\tprivate readonly onPointerMove = (e: PointerEvent) => {\n\t\tif (this.preventMistouch.record) {\n\t\t\tthis.preventMistouch.lastX = e.clientX;\n\t\t\tthis.preventMistouch.lastY = e.clientY;\n\t\t}\n\t};\n\n\tprivate readonly onPointerUp = () => {\n\t\tif (this.preventMistouch.record) {\n\t\t\tthis.preventMistouch.record = false;\n\t\t\tif (\n\t\t\t\tMath.abs(this.preventMistouch.lastX - this.preventMistouch.initialX) +\n\t\t\t\t\tMath.abs(this.preventMistouch.lastY - this.preventMistouch.initialY) <\n\t\t\t\t5\n\t\t\t)\n\t\t\t\tthis.endPrevention();\n\t\t}\n\t};\n\n\tstartPrevention = () => {\n\t\tthis.preventionContainer.classList.remove('JCV-hidden');\n\t\tthis.DM.data.container.classList.add('JCV-numb');\n\t\tthis.preventMt = true;\n\t};\n\n\tendPrevention = () => {\n\t\tthis.preventMt = false;\n\t\tthis.preventionContainer.classList.add('JCV-hidden');\n\t\tsetTimeout(() => this.DM.data.container.classList.remove('JCV-numb'), 50); // Minimum delay to prevent triggering undesired button touch\n\t};\n\n\tprivate readonly dispose = () => {\n\t\twindow.removeEventListener('pointerdown', this.onPointerDown);\n\t\twindow.removeEventListener('pointermove', this.onPointerMove);\n\t\twindow.removeEventListener('pointerup', this.onPointerUp);\n\t\tthis.preventionContainer.remove();\n\t\tthis._preventionContainer = undefined;\n\t};\n}\n"],"mappings":"wMAiBA,IAAqB,EAArB,cAA+C,CAAkC,CAChF,qBACA,UAAoB,GACpB,GACA,gBAMI,CACH,SAAU,EACV,SAAU,EACV,MAAO,EACP,MAAO,EACP,OAAQ,GACR,CAED,IAAY,qBAAsB,CACjC,GAAI,CAAC,KAAK,qBAAsB,MAAM,EACtC,OAAO,KAAK,qBAGb,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CAEd,IAAM,EAAmB,SAAS,cAAc,MAAM,CACtD,EAAiB,UAAY,6CAC7B,EAAiB,YAChB,KAAK,QAAQ,6BAA+B,sBAC7C,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,KAAK,qBAAuB,SAAS,cAAc,MAAM,CACzD,KAAK,qBAAqB,UACzB,+DAED,EAAY,KAAK,qBAAsBA,EAAM,CAC7C,KAAK,qBAAqB,YAAY,EAAiB,CACvD,KAAK,GAAG,KAAK,UAAU,YAAY,KAAK,qBAAqB,CAEzD,KAAK,QAAQ,wBAAwB,KAAK,iBAAiB,CAE/D,OAAO,iBAAiB,cAAe,KAAK,cAAc,CAC1D,OAAO,iBAAiB,cAAe,KAAK,cAAc,CAC1D,OAAO,iBAAiB,YAAa,KAAK,YAAY,CAEtD,KAAK,QAAQ,CACZ,sBAAuB,KAAK,cAC5B,wBAAyB,KAAK,gBAC9B,CAAC,CACF,KAAK,UAAU,KAAK,QAAQ,CAG7B,cAAkC,GAAoB,CACrD,IAAM,EAAS,KAAK,GAAG,KAAK,UAAU,uBAAuB,CAE5D,EAAE,QAAU,EAAO,MACnB,EAAE,QAAU,EAAO,OACnB,EAAE,QAAU,EAAO,KACnB,EAAE,QAAU,EAAO,OAEd,KAAK,WAAW,KAAK,iBAAiB,CACjC,KAAK,YACf,KAAK,gBAAgB,SAAW,EAAE,QAClC,KAAK,gBAAgB,SAAW,EAAE,QAClC,KAAK,gBAAgB,MAAQ,EAAE,QAC/B,KAAK,gBAAgB,MAAQ,EAAE,QAC/B,KAAK,gBAAgB,OAAS,KAIhC,cAAkC,GAAoB,CACjD,KAAK,gBAAgB,SACxB,KAAK,gBAAgB,MAAQ,EAAE,QAC/B,KAAK,gBAAgB,MAAQ,EAAE,UAIjC,gBAAqC,CAChC,KAAK,gBAAgB,SACxB,KAAK,gBAAgB,OAAS,GAE7B,KAAK,IAAI,KAAK,gBAAgB,MAAQ,KAAK,gBAAgB,SAAS,CACnE,KAAK,IAAI,KAAK,gBAAgB,MAAQ,KAAK,gBAAgB,SAAS,CACrE,GAEA,KAAK,eAAe,GAIvB,oBAAwB,CACvB,KAAK,oBAAoB,UAAU,OAAO,aAAa,CACvD,KAAK,GAAG,KAAK,UAAU,UAAU,IAAI,WAAW,CAChD,KAAK,UAAY,IAGlB,kBAAsB,CACrB,KAAK,UAAY,GACjB,KAAK,oBAAoB,UAAU,IAAI,aAAa,CACpD,eAAiB,KAAK,GAAG,KAAK,UAAU,UAAU,OAAO,WAAW,CAAE,GAAG,EAG1E,YAAiC,CAChC,OAAO,oBAAoB,cAAe,KAAK,cAAc,CAC7D,OAAO,oBAAoB,cAAe,KAAK,cAAc,CAC7D,OAAO,oBAAoB,YAAa,KAAK,YAAY,CACzD,KAAK,oBAAoB,QAAQ,CACjC,KAAK,qBAAuB,IAAA"}
1
+ {"version":3,"file":"index.js","names":["style"],"sources":["../../../src/modules/MistouchPreventer/index.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport { BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport { applyStyles, destroyError } from '$/utilities';\nimport style from './styles.scss?inline';\n\ntype Options = {\n\tpreventMistouchAtStart?: boolean;\n\tmistouchPreventerBannerText?: string;\n} & BaseOptions;\n\ntype Augmentation = {\n\tstartMistouchPrevention: MistouchPreventer['startPrevention'];\n\tendMistouchPrevention: MistouchPreventer['endPrevention'];\n};\n\nexport default class MistouchPreventer extends BaseModule<Options, Augmentation> {\n\tprivate _preventionContainer?: HTMLDivElement;\n\tprivate preventMt = false;\n\tprivate readonly DM: DataManager;\n\tprivate readonly preventMistouch: {\n\t\trecord: boolean;\n\t\tlastX: number;\n\t\tlastY: number;\n\t\tinitialX: number;\n\t\tinitialY: number;\n\t} = {\n\t\tinitialX: 0,\n\t\tinitialY: 0,\n\t\tlastX: 0,\n\t\tlastY: 0,\n\t\trecord: false,\n\t};\n\n\tprivate get preventionContainer() {\n\t\tif (!this._preventionContainer) throw destroyError;\n\t\treturn this._preventionContainer;\n\t}\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\n\t\tconst preventionBanner = document.createElement('div');\n\t\tpreventionBanner.className = 'JCV-prevention-banner JCV-border-shadow-bg';\n\t\tpreventionBanner.textContent =\n\t\t\tthis.options.mistouchPreventerBannerText ?? 'Click on to unlock.';\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis._preventionContainer = document.createElement('div');\n\t\tthis._preventionContainer.className =\n\t\t\t'JCV-prevention-container JCV-hidden JCV-full JCV-flex-center';\n\n\t\tapplyStyles(this._preventionContainer, style);\n\t\tthis._preventionContainer.appendChild(preventionBanner);\n\t\tthis.DM.data.container.appendChild(this._preventionContainer);\n\n\t\tif (this.options.preventMistouchAtStart) this.startPrevention();\n\n\t\twindow.addEventListener('pointerdown', this.onPointerDown);\n\t\twindow.addEventListener('pointermove', this.onPointerMove);\n\t\twindow.addEventListener('pointerup', this.onPointerUp);\n\n\t\tthis.augment({\n\t\t\tendMistouchPrevention: this.endPrevention,\n\t\t\tstartMistouchPrevention: this.startPrevention,\n\t\t});\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly onPointerDown = (e: PointerEvent) => {\n\t\tconst bounds = this.DM.data.container.getBoundingClientRect();\n\t\tif (\n\t\t\te.clientX < bounds.left ||\n\t\t\te.clientX > bounds.right ||\n\t\t\te.clientY < bounds.top ||\n\t\t\te.clientY > bounds.bottom\n\t\t) {\n\t\t\tif (!this.preventMt) this.startPrevention();\n\t\t} else if (this.preventMt) {\n\t\t\tthis.preventMistouch.initialX = e.clientX;\n\t\t\tthis.preventMistouch.initialY = e.clientY;\n\t\t\tthis.preventMistouch.lastX = e.clientX;\n\t\t\tthis.preventMistouch.lastY = e.clientY;\n\t\t\tthis.preventMistouch.record = true;\n\t\t}\n\t};\n\n\tprivate readonly onPointerMove = (e: PointerEvent) => {\n\t\tif (this.preventMistouch.record) {\n\t\t\tthis.preventMistouch.lastX = e.clientX;\n\t\t\tthis.preventMistouch.lastY = e.clientY;\n\t\t}\n\t};\n\n\tprivate readonly onPointerUp = () => {\n\t\tif (this.preventMistouch.record) {\n\t\t\tthis.preventMistouch.record = false;\n\t\t\tif (\n\t\t\t\tMath.abs(this.preventMistouch.lastX - this.preventMistouch.initialX) +\n\t\t\t\t\tMath.abs(this.preventMistouch.lastY - this.preventMistouch.initialY) <\n\t\t\t\t5\n\t\t\t)\n\t\t\t\tthis.endPrevention();\n\t\t}\n\t};\n\n\tstartPrevention = () => {\n\t\tthis.preventionContainer.classList.remove('JCV-hidden');\n\t\tthis.DM.data.container.classList.add('JCV-numb');\n\t\tthis.preventMt = true;\n\t};\n\n\tendPrevention = () => {\n\t\tthis.preventMt = false;\n\t\tthis.preventionContainer.classList.add('JCV-hidden');\n\t\tsetTimeout(() => this.DM.data.container.classList.remove('JCV-numb'), 50); // Minimum delay to prevent triggering undesired button touch\n\t};\n\n\tprivate readonly dispose = () => {\n\t\twindow.removeEventListener('pointerdown', this.onPointerDown);\n\t\twindow.removeEventListener('pointermove', this.onPointerMove);\n\t\twindow.removeEventListener('pointerup', this.onPointerUp);\n\t\tthis.preventionContainer.remove();\n\t\tthis._preventionContainer = undefined;\n\t};\n}\n"],"mappings":"wMAiBA,IAAqB,EAArB,cAA+C,CAAkC,CAChF,qBACA,UAAoB,GACpB,GACA,gBAMI,CACH,SAAU,EACV,SAAU,EACV,MAAO,EACP,MAAO,EACP,OAAQ,GACR,CAED,IAAY,qBAAsB,CACjC,GAAI,CAAC,KAAK,qBAAsB,MAAM,EACtC,OAAO,KAAK,qBAGb,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CAEd,IAAM,EAAmB,SAAS,cAAc,MAAM,CACtD,EAAiB,UAAY,6CAC7B,EAAiB,YAChB,KAAK,QAAQ,6BAA+B,sBAC7C,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,KAAK,qBAAuB,SAAS,cAAc,MAAM,CACzD,KAAK,qBAAqB,UACzB,+DAED,EAAY,KAAK,qBAAsBA,EAAM,CAC7C,KAAK,qBAAqB,YAAY,EAAiB,CACvD,KAAK,GAAG,KAAK,UAAU,YAAY,KAAK,qBAAqB,CAEzD,KAAK,QAAQ,wBAAwB,KAAK,iBAAiB,CAE/D,OAAO,iBAAiB,cAAe,KAAK,cAAc,CAC1D,OAAO,iBAAiB,cAAe,KAAK,cAAc,CAC1D,OAAO,iBAAiB,YAAa,KAAK,YAAY,CAEtD,KAAK,QAAQ,CACZ,sBAAuB,KAAK,cAC5B,wBAAyB,KAAK,gBAC9B,CAAC,CACF,KAAK,UAAU,KAAK,QAAQ,CAG7B,cAAkC,GAAoB,CACrD,IAAM,EAAS,KAAK,GAAG,KAAK,UAAU,uBAAuB,CAE5D,EAAE,QAAU,EAAO,MACnB,EAAE,QAAU,EAAO,OACnB,EAAE,QAAU,EAAO,KACnB,EAAE,QAAU,EAAO,OAEd,KAAK,WAAW,KAAK,iBAAiB,CACjC,KAAK,YACf,KAAK,gBAAgB,SAAW,EAAE,QAClC,KAAK,gBAAgB,SAAW,EAAE,QAClC,KAAK,gBAAgB,MAAQ,EAAE,QAC/B,KAAK,gBAAgB,MAAQ,EAAE,QAC/B,KAAK,gBAAgB,OAAS,KAIhC,cAAkC,GAAoB,CACjD,KAAK,gBAAgB,SACxB,KAAK,gBAAgB,MAAQ,EAAE,QAC/B,KAAK,gBAAgB,MAAQ,EAAE,UAIjC,gBAAqC,CAChC,KAAK,gBAAgB,SACxB,KAAK,gBAAgB,OAAS,GAE7B,KAAK,IAAI,KAAK,gBAAgB,MAAQ,KAAK,gBAAgB,SAAS,CACnE,KAAK,IAAI,KAAK,gBAAgB,MAAQ,KAAK,gBAAgB,SAAS,CACrE,GAEA,KAAK,eAAe,GAIvB,oBAAwB,CACvB,KAAK,oBAAoB,UAAU,OAAO,aAAa,CACvD,KAAK,GAAG,KAAK,UAAU,UAAU,IAAI,WAAW,CAChD,KAAK,UAAY,IAGlB,kBAAsB,CACrB,KAAK,UAAY,GACjB,KAAK,oBAAoB,UAAU,IAAI,aAAa,CACpD,eAAiB,KAAK,GAAG,KAAK,UAAU,UAAU,OAAO,WAAW,CAAE,GAAG,EAG1E,YAAiC,CAChC,OAAO,oBAAoB,cAAe,KAAK,cAAc,CAC7D,OAAO,oBAAoB,cAAe,KAAK,cAAc,CAC7D,OAAO,oBAAoB,YAAa,KAAK,YAAY,CACzD,KAAK,oBAAoB,QAAQ,CACjC,KAAK,qBAAuB,IAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-canvas-viewer",
3
- "version": "4.2.0",
3
+ "version": "4.2.1",
4
4
  "description": "An extensible web-based viewer for JSON Canvas, easy to embed into websites.",
5
5
  "keywords": [
6
6
  "frontend",