json-canvas-viewer 4.1.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chimp.js +396 -1
- package/dist/index.d.ts +29 -618
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/kernel/BaseModule.d.ts +27 -0
- package/dist/kernel/BaseModule.js +2 -2
- package/dist/kernel/BaseModule.js.map +1 -1
- package/dist/kernel/Controller.d.ts +30 -0
- package/dist/kernel/Controller.js +2 -2
- package/dist/kernel/Controller.js.map +1 -1
- package/dist/kernel/DataManager.d.ts +67 -0
- package/dist/kernel/DataManager.js +2 -2
- package/dist/kernel/DataManager.js.map +1 -1
- package/dist/kernel/InteractionHandler.d.ts +51 -0
- package/dist/kernel/InteractionHandler.js +2 -2
- package/dist/kernel/InteractionHandler.js.map +1 -1
- package/dist/kernel/OverlayManager.d.ts +62 -0
- package/dist/kernel/OverlayManager.js +2 -2
- package/dist/kernel/OverlayManager.js.map +1 -1
- package/dist/kernel/Renderer.d.ts +37 -0
- package/dist/kernel/Renderer.js +3 -2
- package/dist/kernel/Renderer.js.map +1 -1
- package/dist/kernel/StyleManager.d.ts +135 -0
- package/dist/kernel/StyleManager.js +2 -2
- package/dist/kernel/StyleManager.js.map +1 -1
- package/dist/kernel/index.d.ts +46 -0
- package/dist/kernel/index.js +2 -2
- package/dist/kernel/index.js.map +1 -1
- package/dist/kernel/styles.js +285 -0
- package/dist/kernel/styles.js.map +1 -0
- package/dist/kernel/types.d.ts +33 -0
- package/dist/kernel/utilities.d.ts +13 -0
- package/dist/kernel/utilities.js +2 -2
- package/dist/kernel/utilities.js.map +1 -1
- package/dist/modules/Controls/index.d.ts +42 -0
- package/dist/modules/Controls/index.js +2 -2
- package/dist/modules/Controls/index.js.map +1 -1
- package/dist/modules/Controls/styles.js +29 -0
- package/dist/modules/Controls/styles.js.map +1 -0
- package/dist/modules/DebugPanel/index.d.ts +14 -0
- package/dist/modules/DebugPanel/index.js +2 -2
- package/dist/modules/DebugPanel/index.js.map +1 -1
- package/dist/modules/DebugPanel/styles.js +13 -0
- package/dist/modules/DebugPanel/styles.js.map +1 -0
- package/dist/modules/Minimap/index.d.ts +36 -0
- package/dist/modules/Minimap/index.js +2 -2
- package/dist/modules/Minimap/index.js.map +1 -1
- package/dist/modules/Minimap/styles.js +56 -0
- package/dist/modules/Minimap/styles.js.map +1 -0
- package/dist/modules/MistouchPreventer/index.d.ts +29 -0
- package/dist/modules/MistouchPreventer/index.js +2 -2
- package/dist/modules/MistouchPreventer/index.js.map +1 -1
- package/dist/modules/MistouchPreventer/styles.js +21 -0
- package/dist/modules/MistouchPreventer/styles.js.map +1 -0
- package/dist/shared/index.d.ts +50 -0
- package/dist/utilities/fetch-canvas.d.ts +7 -0
- package/dist/utilities/fetch-canvas.js +2 -0
- package/dist/utilities/fetch-canvas.js.map +1 -0
- package/dist/utilities/parser.d.ts +5 -0
- package/dist/utilities/parser.js +2 -2
- package/dist/utilities/parser.js.map +1 -1
- package/dist/utilities/render-to-string.d.ts +12 -0
- package/dist/utilities/render-to-string.js +2 -0
- package/dist/utilities/render-to-string.js.map +1 -0
- package/package.json +8 -7
- package/dist/kernel/styles.scss.js +0 -2
- package/dist/kernel/styles.scss.js.map +0 -1
- package/dist/modules/Controls/styles.scss.js +0 -2
- package/dist/modules/Controls/styles.scss.js.map +0 -1
- package/dist/modules/DebugPanel/styles.scss.js +0 -2
- package/dist/modules/DebugPanel/styles.scss.js.map +0 -1
- package/dist/modules/Minimap/styles.scss.js +0 -2
- package/dist/modules/Minimap/styles.scss.js.map +0 -1
- package/dist/modules/MistouchPreventer/styles.scss.js +0 -2
- package/dist/modules/MistouchPreventer/styles.scss.js.map +0 -1
- package/dist/utilities/fetchCanvas.js +0 -2
- package/dist/utilities/fetchCanvas.js.map +0 -1
- package/dist/utilities/renderToString.js +0 -2
- package/dist/utilities/renderToString.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OverlayManager.js","sources":["../../src/kernel/OverlayManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type {\n\tJSONCanvasFileNode,\n\tJSONCanvasLinkNode,\n\tJSONCanvasNode,\n\tJSONCanvasTextNode,\n\tParser,\n} from '@repo/shared';\nimport { type BaseArgs, BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager from '$/DataManager';\nimport InteractionHandler from '$/InteractionHandler';\nimport StyleManager, { type Color } from '$/StyleManager';\nimport utilities, { destroyError, type Hook } from '$/utilities';\n\ninterface Options extends BaseOptions {\n\tparser?: Parser;\n\tnodeComponents?: Partial<ComponentDict>;\n}\n\ninterface Augmentation {\n\tonNodeActive: OverlayManager['onNodeActive'];\n\tonNodeLosesActive: OverlayManager['onNodeLosesActive'];\n}\n\n// TODO: add more formats\nconst fileRegex = {\n\tmarkdown: /\\.(md|mdx|markdown|txt)$/i,\n\timage: /\\.(png|jpg|jpeg|gif|svg|webp|avif|bmp|ico|heic|heif)$/i,\n\taudio: /\\.(mp3|wav|ogg|opus|aac|m4a|flac)$/i,\n\tvideo: /\\.(mp4|webm|ogv|mov|m3u8|mpd)$/i,\n};\n\ntype NodeComponentHook<N extends JSONCanvasNode> = (\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 | null = document.createElement('div');\n\tprivate overlays: Record<string, HTMLDivElement> = {}; // { id: node } the overlays in viewport\n\tprivate selectedId: string | null = null;\n\tprivate aborted = false;\n\tprivate eventListeners: Record<string, Array<EventListener | null>> = {};\n\tprivate DM: DataManager;\n\tprivate SM: StyleManager;\n\tprivate parse: Parser;\n\tprivate componentDict: ComponentDict = {\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\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 = result.match(/^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/);\n\t\t\t\tif (frontmatterMatch) parsedContent = await this.parse(frontmatterMatch[2]);\n\t\t\t\telse parsedContent = await this.parse(result);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error('[JSON Canvas Viewer] Failed to load markdown:', err);\n\t\t\t\tparsedContent = 'Failed to load content.';\n\t\t\t}\n\t\t\tparsedContentWrapper.innerHTML = parsedContent;\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\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\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 = utilities.makeHook();\n\tonInteractionEnd = utilities.makeHook();\n\tonNodeActive = utilities.makeHook<[JSONCanvasNode]>();\n\tonNodeLosesActive = utilities.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 start = () => {\n\t\tthis.container.get(InteractionHandler).onClick.subscribe(this.select);\n\t\tthis.renderOverlays();\n\t};\n\n\tprivate restart = () => {\n\t\tthis.clearOverlays();\n\t\tthis.renderOverlays();\n\t};\n\n\tprivate 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 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 select = (id: string | null) => {\n\t\tconst previousId = this.selectedId;\n\t\tconst previous = !previousId ? null : this.overlays[previousId];\n\t\tconst current = !id ? null : 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 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 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 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 = utilities.makeHook();\n\t\tnodeItem.onLoseActive = utilities.makeHook();\n\t\tnodeItem.onBeforeUnmount = utilities.makeHook();\n\n\t\tvoid this.componentDict[args[2]](\n\t\t\tcontentWrapper,\n\t\t\targs[1],\n\t\t\targs[0] as never,\n\t\t\tnodeItem.onBeforeUnmount,\n\t\t\tnodeItem.onActive,\n\t\t\tnodeItem.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 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 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] = null;\n\t\t\t\tthis.eventListeners[id][1] = null;\n\t\t\t}\n\t\t\toverlay.remove();\n\t\t\tdelete this.overlays[id];\n\t\t});\n\t};\n\n\tprivate dispose = () => {\n\t\tthis.aborted = true;\n\t\tthis.clearOverlays();\n\t\tthis.overlaysLayer.remove();\n\t\tthis._overlaysLayer = null;\n\t};\n}\n"],"names":["fileRegex","markdown","image","audio","video","supportedTypes","OverlayManager","BaseModule","_overlaysLayer","document","createElement","overlays","selectedId","aborted","eventListeners","DM","SM","parse","componentDict","text","container","content","classList","add","parsedContentWrapper","innerHTML","appendChild","async","parsedContent","textContent","response","fetch","result","frontmatterMatch","match","this","err","console","error","link","iframe","src","sandbox","className","loading","controls","img","overlaysLayer","destroyError","onInteractionStart","utilities","makeHook","onInteractionEnd","onNodeActive","onNodeLosesActive","constructor","args","super","options","parser","get","DataManager","StyleManager","Controller","onRefresh","subscribe","updateOverlays","onChangeTheme","themeChanged","id","data","components","nodeComponents","Object","assign","augment","onStart","start","onRestart","restart","onDispose","dispose","InteractionHandler","onClick","select","renderOverlays","clearOverlays","overlayMatcher","node","type","createOverlay","file","url","values","nodeMap","forEach","ref","overlay","color","getColor","setOverlayColor","previousId","previous","current","remove","nodeItem","onLoseActive","onActive","style","transform","offsetX","offsetY","scale","element","constructOverlay","left","x","top","y","width","height","contentWrapper","clickLayer","overlayBorder","onBeforeUnmount","onEnd","addEventListener","entries","key","value","setProperty","removeEventListener"],"mappings":"qOA0BA,MAAMA,EAAY,CACjBC,SAAU,4BACVC,MAAO,yDACPC,MAAO,sCACPC,MAAO,mCAiCFC,EAAiB,CAAC,WAAY,QAAS,QAAS,SAEtD,MAAqBC,UAAuBC,EACnCC,eAAwCC,SAASC,cAAc,OAC/DC,SAA2C,CAAA,EAC3CC,WAA4B,KAC5BC,SAAU,EACVC,eAA8D,CAAA,EAC9DC,GACAC,GACAC,MACAC,cAA+B,CACtCC,KAAM,CAACC,EAAWC,KACjBD,EAAUE,UAAUC,IAAI,wBACxB,MAAMC,EAAuBf,SAASC,cAAc,OACpDc,EAAqBC,UAAYJ,EACjCG,EAAqBF,UAAUC,IAAI,8BACnCH,EAAUM,YAAYF,IAEvBvB,SAAU0B,MAAOP,EAAWC,KAC3BD,EAAUE,UAAUC,IAAI,wBACxB,MAAMC,EAAuBf,SAASC,cAAc,OAIpD,IAAIkB,EAHJJ,EAAqBK,YAAc,aACnCL,EAAqBF,UAAUC,IAAI,8BACnCH,EAAUM,YAAYF,GAEtB,IACC,MAAMM,QAAiBC,MAAMV,GACvBW,QAAeF,EAASX,OACxBc,EAAmBD,EAAOE,MAAM,qCAChBN,EAAlBK,QAAwCE,KAAKlB,MAAMgB,EAAiB,UAC7CE,KAAKlB,MAAMe,EACvC,OAASI,GACRC,QAAQC,MAAM,gDAAiDF,GAC/DR,EAAgB,yBACjB,CACAJ,EAAqBC,UAAYG,GAElCW,KAAM,CAACnB,EAAWC,KACjB,MAAMmB,EAAS/B,SAASC,cAAc,UACtC8B,EAAOC,IAAMpB,EACbmB,EAAOE,QAAU,kCACjBF,EAAOG,UAAY,kBACnBH,EAAOI,QAAU,OACjBxB,EAAUM,YAAYc,IAEvBrC,MAAO,CAACiB,EAAWC,KAClB,MAAMlB,EAAQM,SAASC,cAAc,SACrCP,EAAMwC,UAAY,YAClBxC,EAAMsC,IAAMpB,EACZlB,EAAM0C,UAAW,EACjBzB,EAAUM,YAAYvB,IAEvBD,MAAO,CAACkB,EAAWC,KAClB,MAAMyB,EAAMrC,SAASC,cAAc,OACnCoC,EAAIH,UAAY,UAChBG,EAAIL,IAAMpB,EACVyB,EAAIF,QAAU,OACdxB,EAAUM,YAAYoB,IAEvB1C,MAAO,CAACgB,EAAWC,KAClB,MAAMjB,EAAQK,SAASC,cAAc,SACrCN,EAAMuC,UAAY,YAClBvC,EAAMqC,IAAMpB,EACZjB,EAAMyC,UAAW,EACjBzB,EAAUM,YAAYtB,KAIxB,iBAAY2C,GACX,IAAKZ,KAAK3B,eAAgB,MAAMwC,EAChC,OAAOb,KAAK3B,cACb,CAEAyC,mBAAqBC,EAAUC,WAC/BC,iBAAmBF,EAAUC,WAC7BE,aAAeH,EAAUC,WACzBG,kBAAoBJ,EAAUC,WAE9B,WAAAI,IAAeC,GACdC,SAASD,GACTrB,KAAKlB,MAAQkB,KAAKuB,QAAQC,QAAA,CAAY1D,GAAqBA,GAC3DkC,KAAKpB,GAAKoB,KAAKf,UAAUwC,IAAIC,GAC7B1B,KAAKnB,GAAKmB,KAAKf,UAAUwC,IAAIE,GACV3B,KAAKf,UAAUwC,IAAIG,GAC3BC,UAAUC,UAAU9B,KAAK+B,gBACpC/B,KAAKnB,GAAGmD,cAAcF,UAAU9B,KAAKiC,cAErCjC,KAAK3B,eAAiBC,SAASC,cAAc,OAC7CyB,KAAK3B,eAAemC,UAAY,eAChCR,KAAK3B,eAAe6D,GAAK,WACzBlC,KAAKpB,GAAGuD,KAAKlD,UAAUM,YAAYS,KAAKY,eAExC,MAAMwB,EAAapC,KAAKuB,QAAQc,eAC5BD,GAAYE,OAAOC,OAAOvC,KAAKjB,cAAeqD,GAElDpC,KAAKwC,QAAQ,CACZtB,aAAclB,KAAKkB,aACnBC,kBAAmBnB,KAAKmB,oBAEzBnB,KAAKyC,QAAQzC,KAAK0C,OAClB1C,KAAK2C,UAAU3C,KAAK4C,SACpB5C,KAAK6C,UAAU7C,KAAK8C,QACrB,CAEQJ,MAAQ,KACf1C,KAAKf,UAAUwC,IAAIsB,GAAoBC,QAAQlB,UAAU9B,KAAKiD,QAC9DjD,KAAKkD,kBAGEN,QAAU,KACjB5C,KAAKmD,gBACLnD,KAAKkD,kBAGEA,eAAiB,KACxB,MAAME,EAAiB5D,MAAO6D,IAC7B,OAAQA,EAAKC,MACZ,IAAK,OACJtD,KAAKuD,cAAcF,QAAYrD,KAAKlB,MAAMuE,EAAKrE,MAAO,QACtD,MAED,IAAK,OACJ,IAAA,MAAWsE,KAAQpF,EAClB,GAAKmF,EAAKG,KAAKzD,MAAMlC,EAAUyF,IAA/B,CACAtD,KAAKuD,cAAcF,EAAMA,EAAKG,KAAMF,GACpC,KAFuC,CAIxC,MAED,IAAK,OACJtD,KAAKuD,cAAcF,EAAMA,EAAKI,IAAK,UAKtCnB,OAAOoB,OAAO1D,KAAKpB,GAAGuD,KAAKwB,SAASC,QAAQpE,MAAO6D,UAC5CD,EAAeC,EAAKQ,QAIpB5B,aAAe,KACtBK,OAAOoB,OAAO1D,KAAKxB,UAAUoF,QAASE,IACrC,MAAMT,EAAOrD,KAAKpB,GAAGuD,KAAKwB,QAAQG,EAAQ5B,IAAI2B,IACxCE,EAAQ/D,KAAKnB,GAAGmF,SAASX,EAAKU,OACpC/D,KAAKiE,gBAAgBH,EAASC,MAIxBd,OAAUf,IACjB,MAAMgC,EAAalE,KAAKvB,WAClB0F,EAAYD,EAAoBlE,KAAKxB,SAAS0F,GAArB,KACzBE,EAAWlC,EAAYlC,KAAKxB,SAAS0D,GAArB,KACtB,GAAIiC,GAAYD,EAAY,CAC3BC,EAAShF,UAAUkF,OAAO,cAC1B,MAAMC,EAAWtE,KAAKpB,GAAGuD,KAAKwB,QAAQO,GACtClE,KAAKmB,kBAAkBmD,EAAST,KAChCS,EAASC,gBACV,CACA,GAAIH,GAAWlC,EAAI,CAClBkC,EAAQjF,UAAUC,IAAI,cACtBY,KAAKc,qBACL,MAAMwD,EAAWtE,KAAKpB,GAAGuD,KAAKwB,QAAQzB,GACtClC,KAAKkB,aAAaoD,EAAST,KAC3BS,EAASE,YACV,WAAYvD,mBACZjB,KAAKvB,WAAayD,GAGXH,eAAiB,KACxB,MAAMI,EAAOnC,KAAKpB,GAAGuD,KACrBnC,KAAKY,cAAc6D,MAAMC,UAAY,aAAavC,EAAKwC,cAAcxC,EAAKyC,oBAAoBzC,EAAK0C,UAG5FtB,cAAgB,IAAIlC,KAC3B,GAAIrB,KAAKtB,QAAS,OAClB,MAAM2E,EAAOhC,EAAK,GAClB,IAAIyD,EAAU9E,KAAKxB,SAAS6E,EAAKnB,IACjC,IAAK4C,EAAS,CAEb,GADAA,EAAU9E,KAAK+E,oBAAoB1D,GAC/BrB,KAAKtB,QAAS,OAClBsB,KAAKY,cAAcrB,YAAYuF,GAC/B9E,KAAKxB,SAAS6E,EAAKnB,IAAM4C,EACzBA,EAAQL,MAAMO,KAAO,GAAG3B,EAAK4B,MAC7BH,EAAQL,MAAMS,IAAM,GAAG7B,EAAK8B,MAC5BL,EAAQL,MAAMW,MAAQ,GAAG/B,EAAK+B,UAC9BN,EAAQL,MAAMY,OAAS,GAAGhC,EAAKgC,UAChC,GAGON,iBAAmB,IAAI1D,KAC9B,MAAMgC,EAAOhC,EAAK,GACZyC,EAAUxF,SAASC,cAAc,OACvCuF,EAAQ3E,UAAUC,IAAI,yBACtB0E,EAAQ5B,GAAKmB,EAAKnB,GAClBlC,KAAKiE,gBAAgBH,EAAS9D,KAAKnB,GAAGmF,SAASX,EAAKU,QACpD,MAAMuB,EAAiBhH,SAASC,cAAc,OAC9C+G,EAAenG,UAAUC,IAAI,eAC7B0E,EAAQvE,YAAY+F,GACpB,MAAMC,EAAajH,SAASC,cAAc,OAC1CgH,EAAW/E,UAAY,kBACvBsD,EAAQvE,YAAYgG,GACpB,MAAMC,EAAgBlH,SAASC,cAAc,OAC7CiH,EAAchF,UAAY,qBAC1BsD,EAAQvE,YAAYiG,GACpB,MAAMlB,EAAWtE,KAAKpB,GAAGuD,KAAKwB,QAAQN,EAAKnB,IAE3CoC,EAASE,SAAWzD,EAAUC,WAC9BsD,EAASC,aAAexD,EAAUC,WAClCsD,EAASmB,gBAAkB1E,EAAUC,WAEhChB,KAAKjB,cAAcsC,EAAK,IAC5BiE,EACAjE,EAAK,GACLA,EAAK,GACLiD,EAASmB,gBACTnB,EAASE,SACTF,EAASC,cAEV,MAAM9B,EAAU,KACXY,EAAKnB,KAAOlC,KAAKvB,iBAAiBqC,sBAEjC4E,EAAQ,KACTrC,EAAKnB,KAAOlC,KAAKvB,iBAAiBwC,oBAOvC,OALA6C,EAAQ6B,iBAAiB,eAAgBlD,GACzCqB,EAAQ6B,iBAAiB,eAAgBD,GACzC5B,EAAQ6B,iBAAiB,aAAclD,GACvCqB,EAAQ6B,iBAAiB,WAAYD,GACrC1F,KAAKrB,eAAe0E,EAAKnB,IAAM,CAACO,EAASiD,GAClC5B,GAGAG,gBAAkB,CAACH,EAAyBC,KACnDzB,OAAOsD,QAAQ7B,GAAOH,QAAQ,EAAEiC,EAAKC,MACpChC,EAAQW,MAAMsB,YAAY,aAAaF,IAAOC,MAIxC3C,cAAgB,KACvBb,OAAOsD,QAAQ5F,KAAKxB,UAAUoF,QAAQ,EAAE1B,EAAI4B,MAE3C,GADA9D,KAAKpB,GAAGuD,KAAKwB,QAAQzB,GAAIuD,oBACrBzF,KAAKrB,eAAeuD,GAAK,CAC5B,MAAMO,EAAUzC,KAAKrB,eAAeuD,GAAI,GAClCwD,EAAQ1F,KAAKrB,eAAeuD,GAAI,GACtC,IAAKO,IAAYiD,EAAO,MAAM7E,EAC9BiD,EAAQkC,oBAAoB,eAAgBvD,GAC5CqB,EAAQkC,oBAAoB,eAAgBN,GAC5C5B,EAAQkC,oBAAoB,aAAcvD,GAC1CqB,EAAQkC,oBAAoB,WAAYN,GACxC1F,KAAKrB,eAAeuD,GAAI,GAAK,KAC7BlC,KAAKrB,eAAeuD,GAAI,GAAK,IAC9B,CACA4B,EAAQO,gBACDrE,KAAKxB,SAAS0D,MAIfY,QAAU,KACjB9C,KAAKtB,SAAU,EACfsB,KAAKmD,gBACLnD,KAAKY,cAAcyD,SACnBrE,KAAK3B,eAAiB"}
|
|
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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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { BaseArgs, BaseModule } from "./BaseModule.js";
|
|
2
|
+
import { BaseOptions } from "./index.js";
|
|
3
|
+
|
|
4
|
+
//#region src/kernel/Renderer.d.ts
|
|
5
|
+
type Options = {
|
|
6
|
+
zoomInOptimization?: boolean;
|
|
7
|
+
} & BaseOptions;
|
|
8
|
+
declare class Renderer extends BaseModule<Options> {
|
|
9
|
+
private _canvas;
|
|
10
|
+
private readonly ctx;
|
|
11
|
+
private readonly DM;
|
|
12
|
+
private readonly SM;
|
|
13
|
+
private readonly zoomInOptimize;
|
|
14
|
+
private get canvas();
|
|
15
|
+
constructor(...args: BaseArgs);
|
|
16
|
+
private readonly optimizeDPR;
|
|
17
|
+
private readonly redraw;
|
|
18
|
+
private trueRedraw;
|
|
19
|
+
private fakeRedraw;
|
|
20
|
+
private readonly isInside;
|
|
21
|
+
private readonly isOutside;
|
|
22
|
+
private readonly getCurrentViewport;
|
|
23
|
+
private readonly drawLabelBar;
|
|
24
|
+
private readonly drawNodeBackground;
|
|
25
|
+
private readonly drawGroup;
|
|
26
|
+
private readonly drawFile;
|
|
27
|
+
private readonly drawEdge;
|
|
28
|
+
private readonly drawEdgeLabel;
|
|
29
|
+
private readonly getControlPoints;
|
|
30
|
+
private readonly drawGridDots;
|
|
31
|
+
private readonly drawCurvedPath;
|
|
32
|
+
private readonly drawArrowhead;
|
|
33
|
+
private readonly dispose;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { Renderer };
|
|
37
|
+
//# sourceMappingURL=Renderer.d.ts.map
|
package/dist/kernel/Renderer.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import{BaseModule as
|
|
2
|
-
|
|
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(`
|
|
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
|
+
//# sourceMappingURL=Renderer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Renderer.js","sources":["../../src/kernel/Renderer.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { Box } from '$/types';\nimport type { JSONCanvasGroupNode, JSONCanvasNode } from '@repo/shared';\nimport { type BaseArgs, BaseModule } from '$/BaseModule';\nimport Controller from '$/Controller';\nimport DataManager, { type EdgeItem, type NodeItem } from '$/DataManager';\nimport StyleManager from '$/StyleManager';\nimport utilities, { destroyError } 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\ninterface Options extends BaseOptions {\n\tzoomInOptimization?: boolean;\n}\n\nexport default class Renderer extends BaseModule<Options> {\n\tprivate _canvas: HTMLCanvasElement | null;\n\tprivate ctx: CanvasRenderingContext2D;\n\tprivate DM: DataManager;\n\tprivate SM: StyleManager;\n\tprivate zoomInOptimize: {\n\t\tlastDrawnScale: number;\n\t\tlastDrawnViewport: Box;\n\t\ttimeout: NodeJS.Timeout | null;\n\t\tlastCallTime: number;\n\t} = {\n\t\tlastDrawnScale: 0,\n\t\tlastDrawnViewport: {\n\t\t\tleft: 0,\n\t\t\tright: 0,\n\t\t\ttop: 0,\n\t\t\tbottom: 0,\n\t\t},\n\t\ttimeout: null,\n\t\tlastCallTime: 0,\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 optimizeDPR = () => {\n\t\tconst container = this.DM.data.container;\n\t\tutilities.resizeCanvasForDPR(this.canvas, container.offsetWidth, container.offsetHeight);\n\t};\n\n\tprivate 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 = null;\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 = 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 = null;\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 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 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 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 { left, top, right, bottom };\n\t};\n\n\tprivate 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 drawNodeBackground = (node: JSONCanvasNode) => {\n\t\tconst colors = this.SM.getColor(node.color);\n\t\tconst radius = NODE_RADIUS;\n\t\tthis.ctx.globalAlpha = 1.0;\n\t\tthis.ctx.fillStyle = colors.background;\n\t\tutilities.drawRoundRect(\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\tutilities.drawRoundRect(this.ctx, node.x, node.y, node.width, node.height, radius);\n\t\tthis.ctx.stroke();\n\t};\n\n\tprivate 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 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 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 gac = utilities.getAnchorCoord;\n\t\tconst { x: startX, y: startY } = gac(fromNode, edge.fromSide);\n\t\tconst { x: endX, y: endY } = gac(toNode, edge.toSide);\n\t\tconst color = this.SM.getColor(edge.color);\n\t\tlet [startControlX, startControlY, endControlX, endControlY] = [0, 0, 0, 0];\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\tconst t = 0.5;\n\t\t\tconst x =\n\t\t\t\t(1 - t) ** 3 * startX +\n\t\t\t\t3 * (1 - t) ** 2 * t * startControlX +\n\t\t\t\t3 * (1 - t) * t * t * endControlX +\n\t\t\t\tt ** 3 * endX;\n\t\t\tconst y =\n\t\t\t\t(1 - t) ** 3 * startY +\n\t\t\t\t3 * (1 - t) ** 2 * t * startControlY +\n\t\t\t\t3 * (1 - t) * t * t * endControlY +\n\t\t\t\tt ** 3 * endY;\n\t\t\tthis.ctx.font = '18px sans-serif';\n\t\t\tconst metrics = this.ctx.measureText(edge.label);\n\t\t\tconst padding = 8;\n\t\t\tconst labelWidth = metrics.width + padding * 2;\n\t\t\tconst labelHeight = 20;\n\t\t\tthis.ctx.fillStyle = color.active;\n\t\t\tthis.ctx.beginPath();\n\t\t\tutilities.drawRoundRect(\n\t\t\t\tthis.ctx,\n\t\t\t\tx - labelWidth / 2,\n\t\t\t\ty - labelHeight / 2 - 2,\n\t\t\t\tlabelWidth,\n\t\t\t\tlabelHeight,\n\t\t\t\t4,\n\t\t\t);\n\t\t\tthis.ctx.fill();\n\t\t\tthis.ctx.fillStyle = color.text;\n\t\t\tthis.ctx.textAlign = 'center';\n\t\t\tthis.ctx.textBaseline = 'middle';\n\t\t\tthis.ctx.fillText(edge.label, x, y - 2);\n\t\t\tthis.ctx.textAlign = 'left';\n\t\t\tthis.ctx.textBaseline = 'alphabetic';\n\t\t}\n\t};\n\n\tprivate 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\tcase 'bottom':\n\t\t\t\tstartControlY = startY + PADDING;\n\t\t\t\tbreak;\n\t\t\tcase 'left':\n\t\t\t\tstartControlX = startX - PADDING;\n\t\t\t\tbreak;\n\t\t\tcase 'right':\n\t\t\t\tstartControlX = startX + PADDING;\n\t\t\t\tbreak;\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\tcase 'bottom':\n\t\t\t\tendControlY = endY + PADDING;\n\t\t\t\tbreak;\n\t\t\tcase 'left':\n\t\t\t\tendControlX = endX - PADDING;\n\t\t\t\tbreak;\n\t\t\tcase 'right':\n\t\t\t\tendControlX = endX + PADDING;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn [startControlX, startControlY, endControlX, endControlY];\n\t};\n\n\tprivate 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\t}\n\t};\n\n\tprivate 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 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 dispose = () => {\n\t\tif (this.zoomInOptimize.timeout) {\n\t\t\tclearTimeout(this.zoomInOptimize.timeout);\n\t\t\tthis.zoomInOptimize.timeout = null;\n\t\t}\n\t\tthis.canvas.remove();\n\t\tthis._canvas = null;\n\t};\n}\n"],"names":["Renderer","BaseModule","_canvas","ctx","DM","SM","zoomInOptimize","lastDrawnScale","lastDrawnViewport","left","right","top","bottom","timeout","lastCallTime","canvas","this","destroyError","constructor","args","super","controller","container","get","Controller","StyleManager","onRefresh","subscribe","redraw","onResize","optimizeDPR","DataManager","document","createElement","className","getContext","data","appendChild","onDispose","dispose","utilities","resizeCanvasForDPR","offsetWidth","offsetHeight","offsetX","offsetY","scale","currentViewport","getCurrentViewport","options","zoomInOptimization","trueRedraw","clearTimeout","now","Date","isInside","setTimeout","fakeRedraw","style","transform","clearRect","width","height","save","drawGridDots","translate","Object","values","nodeMap","forEach","item","isOutside","box","node","ref","type","drawFile","drawGroup","edgeMap","drawEdge","restore","cssScale","currentOffsetX","currentOffsetY","inner","outer","clientWidth","clientHeight","drawLabelBar","x","y","label","color","textColor","barHeight","radius","yOffset","fontSize","xPadding","font","barWidth","measureText","fillStyle","beginPath","moveTo","lineTo","quadraticCurveTo","closePath","fill","fillText","drawNodeBackground","colors","getColor","globalAlpha","background","drawRoundRect","NODE_BORDER_WIDTH","strokeStyle","border","lineWidth","stroke","active","text","fileName","edge","fromNode","toNode","gac","getAnchorCoord","startX","startY","fromSide","endX","endY","toSide","startControlX","startControlY","endControlX","endControlY","controlPoints","getControlPoints","drawCurvedPath","drawArrowhead","t","padding","labelWidth","labelHeight","textAlign","textBaseline","distanceX","distanceY","realDistance","Math","min","abs","max","PADDING","val","actualGap","floor","log2","getNamedColor","arc","PI","c1x","c1y","c2x","c2y","bezierCurveTo","tipX","tipY","fromX","fromY","dx","dy","length","sqrt","unitX","unitY","leftX","leftY","rightX","rightY","remove"],"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 | 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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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { Hook } from "./utilities.js";
|
|
2
|
+
import { BaseArgs, BaseModule } from "./BaseModule.js";
|
|
3
|
+
import { BaseOptions } from "./index.js";
|
|
4
|
+
|
|
5
|
+
//#region src/kernel/StyleManager.d.ts
|
|
6
|
+
type Color = {
|
|
7
|
+
border: string;
|
|
8
|
+
background: string;
|
|
9
|
+
active: string;
|
|
10
|
+
text: string;
|
|
11
|
+
card: string;
|
|
12
|
+
};
|
|
13
|
+
type WithBorderWidth = {
|
|
14
|
+
'border-width': string;
|
|
15
|
+
} & Color;
|
|
16
|
+
type ColorOptions = { [K in keyof (StyleManager['definedColors']['light'] & StyleManager['namedColors']['light'])]?: string };
|
|
17
|
+
type Options = {
|
|
18
|
+
theme?: 'dark' | 'light';
|
|
19
|
+
colors?: {
|
|
20
|
+
light?: ColorOptions;
|
|
21
|
+
dark?: ColorOptions;
|
|
22
|
+
};
|
|
23
|
+
} & BaseOptions;
|
|
24
|
+
type Augmentation = {
|
|
25
|
+
changeTheme: StyleManager['changeTheme'];
|
|
26
|
+
onChangeTheme: StyleManager['onChangeTheme'];
|
|
27
|
+
};
|
|
28
|
+
declare class StyleManager extends BaseModule<Options, Augmentation> {
|
|
29
|
+
theme: 'dark' | 'light';
|
|
30
|
+
onChangeTheme: Hook<["light" | "dark"], false>;
|
|
31
|
+
definedColors: {
|
|
32
|
+
dark: {
|
|
33
|
+
'0': {
|
|
34
|
+
hue: number;
|
|
35
|
+
lightness: number;
|
|
36
|
+
saturation: number;
|
|
37
|
+
};
|
|
38
|
+
'1': {
|
|
39
|
+
hue: number;
|
|
40
|
+
lightness: number;
|
|
41
|
+
saturation: number;
|
|
42
|
+
};
|
|
43
|
+
'2': {
|
|
44
|
+
hue: number;
|
|
45
|
+
lightness: number;
|
|
46
|
+
saturation: number;
|
|
47
|
+
};
|
|
48
|
+
'3': {
|
|
49
|
+
hue: number;
|
|
50
|
+
lightness: number;
|
|
51
|
+
saturation: number;
|
|
52
|
+
};
|
|
53
|
+
'4': {
|
|
54
|
+
hue: number;
|
|
55
|
+
lightness: number;
|
|
56
|
+
saturation: number;
|
|
57
|
+
};
|
|
58
|
+
'5': {
|
|
59
|
+
hue: number;
|
|
60
|
+
lightness: number;
|
|
61
|
+
saturation: number;
|
|
62
|
+
};
|
|
63
|
+
'6': {
|
|
64
|
+
hue: number;
|
|
65
|
+
lightness: number;
|
|
66
|
+
saturation: number;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
light: {
|
|
70
|
+
'0': {
|
|
71
|
+
hue: number;
|
|
72
|
+
lightness: number;
|
|
73
|
+
saturation: number;
|
|
74
|
+
};
|
|
75
|
+
'1': {
|
|
76
|
+
hue: number;
|
|
77
|
+
lightness: number;
|
|
78
|
+
saturation: number;
|
|
79
|
+
};
|
|
80
|
+
'2': {
|
|
81
|
+
hue: number;
|
|
82
|
+
lightness: number;
|
|
83
|
+
saturation: number;
|
|
84
|
+
};
|
|
85
|
+
'3': {
|
|
86
|
+
hue: number;
|
|
87
|
+
lightness: number;
|
|
88
|
+
saturation: number;
|
|
89
|
+
};
|
|
90
|
+
'4': {
|
|
91
|
+
hue: number;
|
|
92
|
+
lightness: number;
|
|
93
|
+
saturation: number;
|
|
94
|
+
};
|
|
95
|
+
'5': {
|
|
96
|
+
hue: number;
|
|
97
|
+
lightness: number;
|
|
98
|
+
saturation: number;
|
|
99
|
+
};
|
|
100
|
+
'6': {
|
|
101
|
+
hue: number;
|
|
102
|
+
lightness: number;
|
|
103
|
+
saturation: number;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
namedColors: {
|
|
108
|
+
dark: {
|
|
109
|
+
background: string;
|
|
110
|
+
'background-secondary': string;
|
|
111
|
+
border: string;
|
|
112
|
+
dots: string;
|
|
113
|
+
shadow: string;
|
|
114
|
+
text: string;
|
|
115
|
+
};
|
|
116
|
+
light: {
|
|
117
|
+
background: string;
|
|
118
|
+
'background-secondary': string;
|
|
119
|
+
border: string;
|
|
120
|
+
dots: string;
|
|
121
|
+
shadow: string;
|
|
122
|
+
text: string;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
private readonly colorCache;
|
|
126
|
+
constructor(...args: BaseArgs);
|
|
127
|
+
private readonly hslProcessor;
|
|
128
|
+
private readonly parseColor;
|
|
129
|
+
getColor: (colorIndex?: string) => WithBorderWidth;
|
|
130
|
+
getNamedColor: (name: keyof typeof this.namedColors.light) => string;
|
|
131
|
+
changeTheme: (theme?: "dark" | "light") => void;
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
134
|
+
export { StyleManager };
|
|
135
|
+
//# sourceMappingURL=StyleManager.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{BaseModule as
|
|
2
|
-
//# sourceMappingURL=StyleManager.js.map
|
|
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
|
+
//# sourceMappingURL=StyleManager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StyleManager.js","sources":["../../src/kernel/StyleManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport { BaseModule
|
|
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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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { JSONCanvas } from "../shared/index.js";
|
|
2
|
+
import { Hook } from "./utilities.js";
|
|
3
|
+
import { Augmentation, ModuleInput, ModuleInputCtor, Options } from "./BaseModule.js";
|
|
4
|
+
import { DataManager } from "./DataManager.js";
|
|
5
|
+
import { InteractionHandler } from "./InteractionHandler.js";
|
|
6
|
+
import { OverlayManager } from "./OverlayManager.js";
|
|
7
|
+
import { Renderer } from "./Renderer.js";
|
|
8
|
+
import { StyleManager } from "./StyleManager.js";
|
|
9
|
+
import { Controller } from "./Controller.js";
|
|
10
|
+
import { Container } from "@needle-di/core";
|
|
11
|
+
|
|
12
|
+
//#region src/kernel/index.d.ts
|
|
13
|
+
type BaseOptions = {
|
|
14
|
+
container: HTMLElement;
|
|
15
|
+
loading?: 'normal' | 'lazy' | 'none';
|
|
16
|
+
};
|
|
17
|
+
declare const internalModules: (typeof Controller | typeof DataManager | typeof InteractionHandler | typeof OverlayManager | typeof Renderer | typeof StyleManager)[];
|
|
18
|
+
type InternalModules = typeof internalModules;
|
|
19
|
+
type AllOptions<M extends ModuleInput = []> = Options<M> & Options<InternalModules>;
|
|
20
|
+
type AllAugmentation<M extends ModuleInput = []> = Augmentation<M> & Augmentation<InternalModules>;
|
|
21
|
+
declare class JSONCanvasViewer<M extends ModuleInputCtor> {
|
|
22
|
+
private readonly allModules;
|
|
23
|
+
private IO;
|
|
24
|
+
private started;
|
|
25
|
+
private disposed;
|
|
26
|
+
options: AllOptions<M>;
|
|
27
|
+
container: Container;
|
|
28
|
+
onDispose: Hook<[], false>;
|
|
29
|
+
onStart: Hook<[], false>;
|
|
30
|
+
onRestart: Hook<[], false>;
|
|
31
|
+
constructor(options: AllOptions<M>, modules?: M);
|
|
32
|
+
private readonly onVisibilityCheck;
|
|
33
|
+
private readonly augment;
|
|
34
|
+
load: (options?: {
|
|
35
|
+
canvas?: JSONCanvas;
|
|
36
|
+
attachmentDir?: string;
|
|
37
|
+
attachments?: Record<string, string>;
|
|
38
|
+
}) => void;
|
|
39
|
+
dispose: () => void;
|
|
40
|
+
}
|
|
41
|
+
type JSONCanvasViewerType = new <M extends ModuleInputCtor = []>(...args: ConstructorParameters<typeof JSONCanvasViewer<M>>) => JSONCanvasViewer<M> & AllAugmentation<M>;
|
|
42
|
+
type JSONCanvasViewerInterface<M extends ModuleInput = []> = JSONCanvasViewer<never> & AllAugmentation<M>;
|
|
43
|
+
declare const _default: JSONCanvasViewerType;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { AllOptions, BaseOptions, JSONCanvasViewerInterface, _default };
|
|
46
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/kernel/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import{makeHook as e}from"./utilities.js";import t from"./DataManager.js";import n from"./StyleManager.js";import r from"./Controller.js";import i from"./OverlayManager.js";import a from"./InteractionHandler.js";import o from"./Renderer.js";import{Container as s}from"@needle-di/core";const c=[t,n,r,i,a,o];var l=class{allModules;IO;started=!1;disposed=!1;options;container;onDispose=e(!0);onStart=e();onRestart=e();constructor(e,t){this.container=new s,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=[...c,...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}};export{l as default};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|