json-canvas-viewer 4.0.0 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chimp.js +395 -1
- package/dist/index.d.ts +29 -608
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/kernel/BaseModule.d.ts +28 -0
- package/dist/kernel/BaseModule.js +2 -0
- package/dist/kernel/BaseModule.js.map +1 -0
- package/dist/kernel/Controller.d.ts +30 -0
- package/dist/kernel/Controller.js +2 -0
- package/dist/kernel/Controller.js.map +1 -0
- package/dist/kernel/DataManager.d.ts +67 -0
- package/dist/kernel/DataManager.js +2 -0
- package/dist/kernel/DataManager.js.map +1 -0
- package/dist/kernel/InteractionHandler.d.ts +51 -0
- package/dist/kernel/InteractionHandler.js +2 -0
- package/dist/kernel/InteractionHandler.js.map +1 -0
- package/dist/kernel/OverlayManager.d.ts +55 -0
- package/dist/kernel/OverlayManager.js +2 -0
- package/dist/kernel/OverlayManager.js.map +1 -0
- package/dist/kernel/Renderer.d.ts +36 -0
- package/dist/kernel/Renderer.js +2 -0
- package/dist/kernel/Renderer.js.map +1 -0
- package/dist/kernel/StyleManager.d.ts +135 -0
- package/dist/kernel/StyleManager.js +2 -0
- package/dist/kernel/StyleManager.js.map +1 -0
- package/dist/kernel/index.d.ts +46 -0
- package/dist/kernel/index.js +2 -0
- package/dist/kernel/index.js.map +1 -0
- 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 +39 -0
- package/dist/kernel/utilities.js +2 -0
- package/dist/kernel/utilities.js.map +1 -0
- package/dist/modules/Controls/index.d.ts +42 -0
- package/dist/modules/Controls/index.js +2 -0
- package/dist/modules/Controls/index.js.map +1 -0
- 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 -0
- package/dist/modules/DebugPanel/index.js.map +1 -0
- 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 -0
- package/dist/modules/Minimap/index.js.map +1 -0
- 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 -0
- package/dist/modules/MistouchPreventer/index.js.map +1 -0
- 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/fetchCanvas.d.ts +7 -0
- package/dist/utilities/fetchCanvas.js +2 -0
- package/dist/utilities/fetchCanvas.js.map +1 -0
- package/dist/utilities/parser.d.ts +5 -0
- package/dist/utilities/parser.js +2 -0
- package/dist/utilities/parser.js.map +1 -0
- package/dist/utilities/renderToString.d.ts +12 -0
- package/dist/utilities/renderToString.js +2 -0
- package/dist/utilities/renderToString.js.map +1 -0
- package/package.json +12 -10
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Box, NodeBounds } from "./types.js";
|
|
2
|
+
import { JSONCanvas, JSONCanvasEdge, JSONCanvasNode } from "../shared/index.js";
|
|
3
|
+
import { Hook } from "./utilities.js";
|
|
4
|
+
import { BaseArgs, BaseModule } from "./BaseModule.js";
|
|
5
|
+
import { BaseOptions } from "./index.js";
|
|
6
|
+
|
|
7
|
+
//#region src/kernel/DataManager.d.ts
|
|
8
|
+
interface Options extends BaseOptions {
|
|
9
|
+
shadowed?: boolean;
|
|
10
|
+
canvas?: JSONCanvas;
|
|
11
|
+
attachmentDir?: string;
|
|
12
|
+
extraCSS?: string;
|
|
13
|
+
attachments?: Record<string, string>;
|
|
14
|
+
noAttachmentRelocation?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface Augmentation {
|
|
17
|
+
resetView: DataManager['resetView'];
|
|
18
|
+
toggleFullscreen: DataManager['toggleFullscreen'];
|
|
19
|
+
onToggleFullscreen: DataManager['onToggleFullscreen'];
|
|
20
|
+
}
|
|
21
|
+
interface NodeItem {
|
|
22
|
+
ref: JSONCanvasNode;
|
|
23
|
+
box: Box;
|
|
24
|
+
fileName?: string;
|
|
25
|
+
onBeforeUnmount?: Hook;
|
|
26
|
+
onActive?: Hook;
|
|
27
|
+
onLoseActive?: Hook;
|
|
28
|
+
}
|
|
29
|
+
interface EdgeItem {
|
|
30
|
+
ref: JSONCanvasEdge;
|
|
31
|
+
box: Box;
|
|
32
|
+
controlPoints?: Array<number>;
|
|
33
|
+
}
|
|
34
|
+
type NodeMap = Record<string, NodeItem>;
|
|
35
|
+
type EdgeMap = Record<string, EdgeItem>;
|
|
36
|
+
declare class DataManager extends BaseModule<Options, Augmentation> {
|
|
37
|
+
onToggleFullscreen: Hook<["enter" | "exit"], false>;
|
|
38
|
+
data: {
|
|
39
|
+
canvasData: Required<JSONCanvas>;
|
|
40
|
+
nodeMap: NodeMap;
|
|
41
|
+
edgeMap: EdgeMap;
|
|
42
|
+
canvasBaseDir: string;
|
|
43
|
+
nodeBounds: NodeBounds;
|
|
44
|
+
offsetX: number;
|
|
45
|
+
offsetY: number;
|
|
46
|
+
scale: number;
|
|
47
|
+
container: HTMLDivElement;
|
|
48
|
+
};
|
|
49
|
+
constructor(...args: BaseArgs);
|
|
50
|
+
private start;
|
|
51
|
+
private processBaseDir;
|
|
52
|
+
private getNodeBox;
|
|
53
|
+
private getEdgeBox;
|
|
54
|
+
private calculateNodeBounds;
|
|
55
|
+
toggleFullscreen: (option?: "enter" | "exit") => Promise<void>;
|
|
56
|
+
resetView: () => void;
|
|
57
|
+
middleViewer: () => {
|
|
58
|
+
x: number;
|
|
59
|
+
y: number;
|
|
60
|
+
width: number;
|
|
61
|
+
height: number;
|
|
62
|
+
};
|
|
63
|
+
private dispose;
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { DataManager };
|
|
67
|
+
//# sourceMappingURL=DataManager.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{BaseModule as e}from"./BaseModule.js";import t from"./styles.js";import n from"./utilities.js";var r=class extends e{onToggleFullscreen=n.makeHook();data={canvasData:{nodes:[],edges:[]},nodeMap:{},edgeMap:{},canvasBaseDir:`./`,nodeBounds:{maxX:0,maxY:0,minX:0,minY:0,width:0,height:0,centerX:0,centerY:0},offsetX:0,offsetY:0,scale:1,container:document.createElement(`div`)};constructor(...e){super(...e);let r=this.options.container;for(;r.firstElementChild;)r.firstElementChild.remove();r.innerHTML=``;let i=this.options.shadowed?r.attachShadow({mode:`open`}):r;n.applyStyles(i,t+this.options.extraCSS),this.data.container.classList.add(`JSON-Canvas-Viewer`),i.appendChild(this.data.container),this.augment({resetView:this.resetView,toggleFullscreen:this.toggleFullscreen,onToggleFullscreen:this.onToggleFullscreen}),this.onStart(this.start),this.onRestart(this.start),this.onDispose(this.dispose)}start=()=>{let e=Object.assign({nodes:[],edges:[]},this.options.canvas);Object.assign(this.data,{canvasData:e,nodeMap:{},edgeMap:{},canvasBaseDir:this.processBaseDir(this.options.attachmentDir),nodeBounds:this.calculateNodeBounds(e),offsetX:0,offsetY:0,scale:1}),this.data.canvasData.nodes.forEach(e=>{let t={ref:e,box:this.getNodeBox(e)};if(this.data.nodeMap[e.id]=t,e.type===`file`){let n=e.file.split(`/`).pop()??``;if(t.fileName=n,!e.file.startsWith(`http://`)&&!e.file.startsWith(`https://`)){let t=this.options.attachments?.[n];t?e.file=t:this.options.noAttachmentRelocation||(e.file=this.data.canvasBaseDir+n)}}}),this.data.canvasData.edges.forEach(e=>{this.data.edgeMap[e.id]={ref:e,box:this.getEdgeBox(e)}}),this.resetView()};processBaseDir=e=>e?e?.slice(-1)===`/`?e:`${e}/`:`./`;getNodeBox=e=>({left:e.x,top:e.type===`file`||e.type===`group`?e.y-40:e.y,right:e.width+e.x,bottom:e.y+e.height});getEdgeBox=e=>{let t=this.data.nodeMap,r=t[e.fromNode].ref,i=t[e.toNode].ref,a=n.getAnchorCoord(r,e.fromSide),o=n.getAnchorCoord(i,e.toSide),s={left:Math.min(a.x,o.x),top:Math.min(a.y,o.y),right:Math.max(a.x,o.x),bottom:Math.max(a.y,o.y)},c=s.right-s.left,l=s.bottom-s.top,u=Math.min(c,l),d=Math.log2(Math.max(c,l)/(u===0?1:u))*10;return{left:s.left-d,top:s.top-d,right:s.right+d,bottom:s.bottom+d}};calculateNodeBounds(e){let t=1/0,n=1/0,r=-1/0,i=-1/0;e.nodes.forEach(e=>{t=Math.min(t,e.x),n=Math.min(n,e.y),r=Math.max(r,e.x+e.width),i=Math.max(i,e.y+e.height)});let a=r-t,o=i-n,s=t+a/2,c=n+o/2;return{minX:t,minY:n,maxX:r,maxY:i,width:a,height:o,centerX:s,centerY:c}}toggleFullscreen=async e=>{!document.fullscreenElement&&(!e||e===`enter`)?(await this.data.container.requestFullscreen(),this.onToggleFullscreen(`enter`)):document.fullscreenElement&&(!e||e===`exit`)&&(await document.exitFullscreen(),this.onToggleFullscreen(`exit`))};resetView=()=>{let e=this.data.nodeBounds,t=this.data.container;if(!e||!t)return;let n=e.width+200,r=e.height+200,i=t.clientWidth,a=t.clientHeight,o=i/n,s=a/r,c=Math.round(Math.min(o,s)*1e3)/1e3,l=e.centerX,u=e.centerY,d={scale:c,offsetX:i/2-l*c,offsetY:a/2-u*c};this.data.offsetX=d.offsetX,this.data.offsetY=d.offsetY,this.data.scale=d.scale};middleViewer=()=>{let e=this.data.container;return{x:e.clientWidth/2,y:e.clientHeight/2,width:e.clientWidth,height:e.clientHeight}};dispose=()=>{this.data.container.remove()}};export{r as default};
|
|
2
|
+
//# sourceMappingURL=DataManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataManager.js","names":["utilities","style"],"sources":["../../src/kernel/DataManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { Box, NodeBounds } from '$/types';\nimport type { JSONCanvas, JSONCanvasEdge, JSONCanvasNode } from '@repo/shared';\nimport { type BaseArgs, BaseModule } from '$/BaseModule';\nimport style from '$/styles.scss?inline';\nimport utilities, { type Hook } from '$/utilities';\n\nconst INITIAL_VIEWPORT_PADDING = 100;\nconst NODE_LABEL_MARGIN = 40;\nconst EDGE_BOX_HEURISTICS_BASE_MARGIN = 10;\n\ninterface Options extends BaseOptions {\n\tshadowed?: boolean;\n\tcanvas?: JSONCanvas;\n\tattachmentDir?: string;\n\textraCSS?: string;\n\tattachments?: Record<string, string>;\n\tnoAttachmentRelocation?: boolean;\n}\n\ninterface Augmentation {\n\tresetView: DataManager['resetView'];\n\ttoggleFullscreen: DataManager['toggleFullscreen'];\n\tonToggleFullscreen: DataManager['onToggleFullscreen'];\n}\n\nexport interface NodeItem {\n\tref: JSONCanvasNode;\n\tbox: Box;\n\tfileName?: string;\n\tonBeforeUnmount?: Hook;\n\tonActive?: Hook;\n\tonLoseActive?: Hook;\n}\n\nexport interface EdgeItem {\n\tref: JSONCanvasEdge;\n\tbox: Box;\n\tcontrolPoints?: Array<number>;\n}\n\ntype NodeMap = Record<string, NodeItem>;\ntype EdgeMap = Record<string, EdgeItem>;\n\nexport default class DataManager extends BaseModule<Options, Augmentation> {\n\tonToggleFullscreen = utilities.makeHook<['enter' | 'exit']>();\n\n\tdata: {\n\t\tcanvasData: Required<JSONCanvas>;\n\t\tnodeMap: NodeMap;\n\t\tedgeMap: EdgeMap;\n\t\tcanvasBaseDir: string;\n\t\tnodeBounds: NodeBounds;\n\t\toffsetX: number;\n\t\toffsetY: number;\n\t\tscale: number;\n\t\tcontainer: HTMLDivElement;\n\t} = {\n\t\tcanvasData: {\n\t\t\tnodes: [],\n\t\t\tedges: [],\n\t\t},\n\t\tnodeMap: {},\n\t\tedgeMap: {},\n\t\tcanvasBaseDir: './',\n\t\tnodeBounds: {\n\t\t\tmaxX: 0,\n\t\t\tmaxY: 0,\n\t\t\tminX: 0,\n\t\t\tminY: 0,\n\t\t\twidth: 0,\n\t\t\theight: 0,\n\t\t\tcenterX: 0,\n\t\t\tcenterY: 0,\n\t\t},\n\t\toffsetX: 0,\n\t\toffsetY: 0,\n\t\tscale: 1,\n\t\tcontainer: document.createElement('div'),\n\t};\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tconst viewerContainer = this.options.container;\n\t\twhile (viewerContainer.firstElementChild) viewerContainer.firstElementChild.remove();\n\t\tviewerContainer.innerHTML = '';\n\n\t\tconst realContainer = this.options.shadowed\n\t\t\t? viewerContainer.attachShadow({ mode: 'open' })\n\t\t\t: viewerContainer;\n\n\t\tutilities.applyStyles(realContainer, style + this.options.extraCSS);\n\n\t\tthis.data.container.classList.add('JSON-Canvas-Viewer');\n\t\trealContainer.appendChild(this.data.container);\n\n\t\tthis.augment({\n\t\t\tresetView: this.resetView,\n\t\t\ttoggleFullscreen: this.toggleFullscreen,\n\t\t\tonToggleFullscreen: this.onToggleFullscreen,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate start = () => {\n\t\tconst canvasData = Object.assign(\n\t\t\t{\n\t\t\t\tnodes: [],\n\t\t\t\tedges: [],\n\t\t\t},\n\t\t\tthis.options.canvas,\n\t\t);\n\n\t\tObject.assign(this.data, {\n\t\t\tcanvasData: canvasData,\n\t\t\tnodeMap: {},\n\t\t\tedgeMap: {},\n\t\t\tcanvasBaseDir: this.processBaseDir(this.options.attachmentDir),\n\t\t\tnodeBounds: this.calculateNodeBounds(canvasData),\n\t\t\toffsetX: 0,\n\t\t\toffsetY: 0,\n\t\t\tscale: 1,\n\t\t});\n\n\t\tthis.data.canvasData.nodes.forEach((node) => {\n\t\t\tconst item: NodeItem = {\n\t\t\t\tref: node,\n\t\t\t\tbox: this.getNodeBox(node),\n\t\t\t};\n\t\t\tthis.data.nodeMap[node.id] = item;\n\n\t\t\t// re-process attachments\n\t\t\tif (node.type === 'file') {\n\t\t\t\tconst path = node.file.split('/');\n\t\t\t\tconst fileName = path.pop() ?? '';\n\t\t\t\titem.fileName = fileName;\n\t\t\t\tif (!node.file.startsWith('http://') && !node.file.startsWith('https://')) {\n\t\t\t\t\tconst userDefinedAttachment = this.options.attachments?.[fileName];\n\t\t\t\t\tif (userDefinedAttachment) node.file = userDefinedAttachment;\n\t\t\t\t\telse if (!this.options.noAttachmentRelocation)\n\t\t\t\t\t\tnode.file = this.data.canvasBaseDir + fileName;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.data.canvasData.edges.forEach((edge) => {\n\t\t\tthis.data.edgeMap[edge.id] = {\n\t\t\t\tref: edge,\n\t\t\t\tbox: this.getEdgeBox(edge),\n\t\t\t};\n\t\t});\n\t\tthis.resetView();\n\t};\n\n\tprivate processBaseDir = (baseDir: string | undefined) => {\n\t\tif (!baseDir) return './';\n\t\tconst lastChar = baseDir?.slice(-1);\n\t\tif (lastChar === '/') return baseDir;\n\t\treturn `${baseDir}/`;\n\t};\n\n\tprivate getNodeBox = (node: JSONCanvasNode) => {\n\t\treturn {\n\t\t\tleft: node.x,\n\t\t\ttop:\n\t\t\t\tnode.type === 'file' || node.type === 'group' ? node.y - NODE_LABEL_MARGIN : node.y,\n\t\t\tright: node.width + node.x,\n\t\t\tbottom: node.y + node.height,\n\t\t};\n\t};\n\n\tprivate getEdgeBox = (edge: JSONCanvasEdge) => {\n\t\tconst nodes = this.data.nodeMap;\n\t\tconst from = nodes[edge.fromNode].ref;\n\t\tconst to = nodes[edge.toNode].ref;\n\t\tconst fromAnchor = utilities.getAnchorCoord(from, edge.fromSide);\n\t\tconst toAnchor = utilities.getAnchorCoord(to, edge.toSide);\n\t\tconst strictBox = {\n\t\t\tleft: Math.min(fromAnchor.x, toAnchor.x),\n\t\t\ttop: Math.min(fromAnchor.y, toAnchor.y),\n\t\t\tright: Math.max(fromAnchor.x, toAnchor.x),\n\t\t\tbottom: Math.max(fromAnchor.y, toAnchor.y),\n\t\t};\n\t\t// edge size heuristics\n\t\tconst width = strictBox.right - strictBox.left;\n\t\tconst height = strictBox.bottom - strictBox.top;\n\t\tconst _min = Math.min(width, height);\n\t\tconst min = _min === 0 ? 1 : _min;\n\t\tconst max = Math.max(width, height);\n\t\tconst edgeFactor = Math.log2(max / min);\n\t\tconst margin = edgeFactor * EDGE_BOX_HEURISTICS_BASE_MARGIN;\n\t\treturn {\n\t\t\tleft: strictBox.left - margin,\n\t\t\ttop: strictBox.top - margin,\n\t\t\tright: strictBox.right + margin,\n\t\t\tbottom: strictBox.bottom + margin,\n\t\t};\n\t};\n\n\tprivate calculateNodeBounds(canvasData: Required<JSONCanvas>) {\n\t\tlet minX = Infinity,\n\t\t\tminY = Infinity,\n\t\t\tmaxX = -Infinity,\n\t\t\tmaxY = -Infinity;\n\t\tcanvasData.nodes.forEach((node) => {\n\t\t\tminX = Math.min(minX, node.x);\n\t\t\tminY = Math.min(minY, node.y);\n\t\t\tmaxX = Math.max(maxX, node.x + node.width);\n\t\t\tmaxY = Math.max(maxY, node.y + node.height);\n\t\t});\n\t\tconst width = maxX - minX;\n\t\tconst height = maxY - minY;\n\t\tconst centerX = minX + width / 2;\n\t\tconst centerY = minY + height / 2;\n\t\treturn { minX, minY, maxX, maxY, width, height, centerX, centerY };\n\t}\n\ttoggleFullscreen = async (option?: 'enter' | 'exit') => {\n\t\tif (!document.fullscreenElement && (!option || option === 'enter')) {\n\t\t\tawait this.data.container.requestFullscreen();\n\t\t\tthis.onToggleFullscreen('enter');\n\t\t} else if (document.fullscreenElement && (!option || option === 'exit')) {\n\t\t\tawait document.exitFullscreen();\n\t\t\tthis.onToggleFullscreen('exit');\n\t\t}\n\t};\n\tresetView = () => {\n\t\tconst bounds = this.data.nodeBounds;\n\t\tconst container = this.data.container;\n\t\tif (!bounds || !container) return;\n\t\tconst contentWidth = bounds.width + INITIAL_VIEWPORT_PADDING * 2;\n\t\tconst contentHeight = bounds.height + INITIAL_VIEWPORT_PADDING * 2;\n\t\t// Use logical dimensions for scaling calculations\n\t\tconst viewWidth = container.clientWidth;\n\t\tconst viewHeight = container.clientHeight;\n\t\tconst scaleX = viewWidth / contentWidth;\n\t\tconst scaleY = viewHeight / contentHeight;\n\t\tconst newScale = Math.round(Math.min(scaleX, scaleY) * 1000) / 1000;\n\t\tconst contentCenterX = bounds.centerX;\n\t\tconst contentCenterY = bounds.centerY;\n\t\tconst initialView = {\n\t\t\tscale: newScale,\n\t\t\toffsetX: viewWidth / 2 - contentCenterX * newScale,\n\t\t\toffsetY: viewHeight / 2 - contentCenterY * newScale,\n\t\t};\n\t\tthis.data.offsetX = initialView.offsetX;\n\t\tthis.data.offsetY = initialView.offsetY;\n\t\tthis.data.scale = initialView.scale;\n\t};\n\n\tmiddleViewer = () => {\n\t\tconst container = this.data.container;\n\t\treturn {\n\t\t\tx: container.clientWidth / 2,\n\t\t\ty: container.clientHeight / 2,\n\t\t\twidth: container.clientWidth,\n\t\t\theight: container.clientHeight,\n\t\t};\n\t};\n\n\tprivate dispose = () => {\n\t\tthis.data.container.remove();\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Coordinates } from "./types.js";
|
|
2
|
+
import { Hook } from "./utilities.js";
|
|
3
|
+
import { BaseArgs, BaseModule } from "./BaseModule.js";
|
|
4
|
+
import { BaseOptions } from "./index.js";
|
|
5
|
+
import { Click, Drag, Lubricator, MultitouchPanZoom, Options, PointeractInterface, PreventDefault, WheelPanZoom } from "pointeract";
|
|
6
|
+
|
|
7
|
+
//#region src/kernel/InteractionHandler.d.ts
|
|
8
|
+
type LoadedModules = [Click, Drag, WheelPanZoom, PreventDefault, MultitouchPanZoom, Lubricator];
|
|
9
|
+
interface Options$1 extends BaseOptions {
|
|
10
|
+
pointeract?: Options<LoadedModules>;
|
|
11
|
+
}
|
|
12
|
+
interface Augmentation {
|
|
13
|
+
pan: InteractionHandler['pan'];
|
|
14
|
+
panToCoords: InteractionHandler['panToCoords'];
|
|
15
|
+
zoom: InteractionHandler['zoom'];
|
|
16
|
+
zoomToScale: InteractionHandler['zoomToScale'];
|
|
17
|
+
}
|
|
18
|
+
declare class InteractionHandler extends BaseModule<Options$1, Augmentation> {
|
|
19
|
+
pointeract: PointeractInterface<LoadedModules>;
|
|
20
|
+
private DM;
|
|
21
|
+
onClick: Hook<[string | null], false>;
|
|
22
|
+
constructor(...args: BaseArgs);
|
|
23
|
+
private start;
|
|
24
|
+
private startInteract;
|
|
25
|
+
private stopInteract;
|
|
26
|
+
private onPan;
|
|
27
|
+
private onZoom;
|
|
28
|
+
trueZoom: (_factor: number, origin: Coordinates) => void;
|
|
29
|
+
truePan: ({
|
|
30
|
+
x,
|
|
31
|
+
y
|
|
32
|
+
}: Coordinates) => void;
|
|
33
|
+
zoom: (_factor: number, origin: Coordinates) => void;
|
|
34
|
+
pan: ({
|
|
35
|
+
x,
|
|
36
|
+
y
|
|
37
|
+
}: Coordinates) => void;
|
|
38
|
+
zoomToScale: (newScale: number, origin: Coordinates) => void;
|
|
39
|
+
panToCoords: ({
|
|
40
|
+
x,
|
|
41
|
+
y
|
|
42
|
+
}: Coordinates) => void;
|
|
43
|
+
private C2C;
|
|
44
|
+
private onTrueClick;
|
|
45
|
+
private isUIControl;
|
|
46
|
+
private findNodeId;
|
|
47
|
+
private dispose;
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { InteractionHandler };
|
|
51
|
+
//# sourceMappingURL=InteractionHandler.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{BaseModule as e}from"./BaseModule.js";import t from"./utilities.js";import n from"./DataManager.js";import r from"./OverlayManager.js";import{Click as i,Drag as a,Lubricator as o,MultitouchPanZoom as s,Pointeract as c,PreventDefault as l,WheelPanZoom as u,lubricatorDragPreset as d,lubricatorPanPreset as f,lubricatorZoomPreset as p}from"pointeract";var m=class extends e{pointeract;DM;onClick=t.makeHook();constructor(...e){super(...e),this.DM=this.container.get(n);let t=Object.assign(this.options.pointeract??{},{coordinateOutput:`relative`,element:this.DM.data.container,lubricator:{pan:f,zoom:p,drag:d}});this.pointeract=new c(t,[i,a,u,l,s,o]);let m=this.container.get(r);m.onInteractionStart.subscribe(this.stopInteract),m.onInteractionEnd.subscribe(this.startInteract),this.augment({pan:this.pan,panToCoords:this.panToCoords,zoom:this.zoom,zoomToScale:this.zoomToScale}),this.onStart(this.start),this.onDispose(this.dispose)}start=()=>{this.pointeract.on(`pan`,this.onPan).on(`drag`,this.onPan).on(`zoom`,this.onZoom).on(`trueClick`,this.onTrueClick).start()};startInteract=()=>{this.pointeract.start()};stopInteract=()=>{this.pointeract.stop()};onPan=e=>{this.truePan({x:e.deltaX,y:e.deltaY})};onZoom=e=>{this.trueZoom(e.factor,e)};trueZoom=(e,t)=>{let n=Math.max(Math.min(this.DM.data.scale*e,20),.05);if(n===this.DM.data.scale)return;let r=n/this.DM.data.scale,i=this.C2C(t);this.DM.data.offsetX=t.x-i.x*r,this.DM.data.offsetY=t.y-i.y*r,this.DM.data.scale=n};truePan=({x:e,y:t})=>{this.DM.data.offsetX=this.DM.data.offsetX+e,this.DM.data.offsetY=this.DM.data.offsetY+t};zoom=(e,t)=>{this.pointeract.dispatch(`zoom`,{factor:e,...t})};pan=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e,deltaY:t})};zoomToScale=(e,t)=>{let n=e/this.DM.data.scale;this.pointeract.dispatch(`zoom`,{factor:n,...t})};panToCoords=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e-this.DM.data.offsetX,deltaY:t-this.DM.data.offsetY})};C2C=({x:e,y:t})=>({x:e-this.DM.data.offsetX,y:t-this.DM.data.offsetY});onTrueClick=e=>{let t=e.target;if(this.isUIControl(t))return;let n=this.findNodeId(t);this.onClick(n)};isUIControl=e=>e?e.closest(`.controls`)||e.closest(`button`)||e.closest(`input`):!1;findNodeId=e=>{if(!e)return null;let t=e;for(;(!t.id||t.id===``)&&t.parentElement;)t=t.parentElement;return t.id===`overlays`||!t.id||t.id===``?null:t.id};dispose=()=>this.pointeract.dispose()};export{m as default};
|
|
2
|
+
//# sourceMappingURL=InteractionHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InteractionHandler.js","names":["utilities"],"sources":["../../src/kernel/InteractionHandler.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { Coordinates } from '$/types';\nimport { type BaseArgs, BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport OverlayManager from '$/OverlayManager';\nimport utilities from '$/utilities';\nimport {\n\tClick,\n\tDrag,\n\tMultitouchPanZoom,\n\tPointeract,\n\ttype Options as PointeractOptions,\n\tPreventDefault,\n\ttype Events,\n\tWheelPanZoom,\n\tLubricator,\n\tlubricatorPanPreset as pan,\n\tlubricatorZoomPreset as zoom,\n\tlubricatorDragPreset as drag,\n\ttype PointeractInterface,\n} from 'pointeract';\n\ntype LoadedModules = [Click, Drag, WheelPanZoom, PreventDefault, MultitouchPanZoom, Lubricator];\n\ntype LoadedEvents = Events<LoadedModules>;\n\ninterface Options extends BaseOptions {\n\tpointeract?: PointeractOptions<LoadedModules>;\n}\n\ninterface Augmentation {\n\tpan: InteractionHandler['pan'];\n\tpanToCoords: InteractionHandler['panToCoords'];\n\tzoom: InteractionHandler['zoom'];\n\tzoomToScale: InteractionHandler['zoomToScale'];\n}\n\nexport default class InteractionHandler extends BaseModule<Options, Augmentation> {\n\tpointeract: PointeractInterface<LoadedModules>;\n\tprivate DM: DataManager;\n\tonClick = utilities.makeHook<[string | null]>();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tconst options = Object.assign(this.options.pointeract ?? {}, {\n\t\t\tcoordinateOutput: 'relative',\n\t\t\telement: this.DM.data.container,\n\t\t\tlubricator: { pan, zoom, drag },\n\t\t} satisfies PointeractOptions<LoadedModules>);\n\t\tthis.pointeract = new Pointeract(options, [\n\t\t\tClick,\n\t\t\tDrag,\n\t\t\tWheelPanZoom,\n\t\t\tPreventDefault,\n\t\t\tMultitouchPanZoom,\n\t\t\tLubricator,\n\t\t]);\n\t\tconst OM = this.container.get(OverlayManager);\n\t\tOM.onInteractionStart.subscribe(this.stopInteract);\n\t\tOM.onInteractionEnd.subscribe(this.startInteract);\n\n\t\tthis.augment({\n\t\t\tpan: this.pan,\n\t\t\tpanToCoords: this.panToCoords,\n\t\t\tzoom: this.zoom,\n\t\t\tzoomToScale: this.zoomToScale,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate start = () => {\n\t\tthis.pointeract\n\t\t\t.on('pan', this.onPan)\n\t\t\t.on('drag', this.onPan)\n\t\t\t.on('zoom', this.onZoom)\n\t\t\t.on('trueClick', this.onTrueClick)\n\t\t\t.start();\n\t};\n\n\tprivate startInteract = () => {\n\t\tthis.pointeract.start();\n\t};\n\tprivate stopInteract = () => {\n\t\tthis.pointeract.stop();\n\t};\n\n\tprivate onPan = (event: LoadedEvents['pan']) => {\n\t\tthis.truePan({\n\t\t\tx: event.deltaX,\n\t\t\ty: event.deltaY,\n\t\t});\n\t};\n\tprivate onZoom = (event: LoadedEvents['zoom']) => {\n\t\tthis.trueZoom(event.factor, event);\n\t};\n\n\ttrueZoom = (_factor: number, origin: Coordinates) => {\n\t\tconst newScale = Math.max(Math.min(this.DM.data.scale * _factor, 20), 0.05);\n\t\tconst scale = this.DM.data.scale;\n\t\tif (newScale === scale) return;\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tconst canvasCoords = this.C2C(origin);\n\t\tthis.DM.data.offsetX = origin.x - canvasCoords.x * factor;\n\t\tthis.DM.data.offsetY = origin.y - canvasCoords.y * factor;\n\t\tthis.DM.data.scale = newScale;\n\t};\n\ttruePan = ({ x, y }: Coordinates) => {\n\t\tthis.DM.data.offsetX = this.DM.data.offsetX + x;\n\t\tthis.DM.data.offsetY = this.DM.data.offsetY + y;\n\t};\n\n\tzoom = (_factor: number, origin: Coordinates) => {\n\t\tthis.pointeract.dispatch('zoom', { factor: _factor, ...origin });\n\t};\n\tpan = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', { deltaX: x, deltaY: y });\n\t};\n\tzoomToScale = (newScale: number, origin: Coordinates) => {\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tthis.pointeract.dispatch('zoom', { factor, ...origin });\n\t};\n\tpanToCoords = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', {\n\t\t\tdeltaX: x - this.DM.data.offsetX,\n\t\t\tdeltaY: y - this.DM.data.offsetY,\n\t\t});\n\t};\n\n\t// Container Coords to Canvas Coords relative to the top-left corner of the scaled canvas\n\tprivate C2C = ({ x: containerX, y: containerY }: Coordinates) => ({\n\t\tx: containerX - this.DM.data.offsetX,\n\t\ty: containerY - this.DM.data.offsetY,\n\t});\n\n\tprivate onTrueClick = (e: LoadedEvents['trueClick']) => {\n\t\tconst element = e.target as HTMLElement | null;\n\t\tif (this.isUIControl(element)) return;\n\t\tconst node = this.findNodeId(element);\n\t\tthis.onClick(node);\n\t};\n\n\tprivate isUIControl = (target: HTMLElement | null) => {\n\t\tif (!target) return false;\n\t\treturn target.closest('.controls') || target.closest('button') || target.closest('input');\n\t};\n\n\tprivate findNodeId = (element: HTMLElement | null) => {\n\t\tif (!element) return null;\n\t\tlet ele = element;\n\t\twhile (!ele.id || ele.id === '') {\n\t\t\tif (!ele.parentElement) break;\n\t\t\tele = ele.parentElement;\n\t\t}\n\t\tif (ele.id === 'overlays' || !ele.id || ele.id === '') return null;\n\t\treturn ele.id;\n\t};\n\n\tprivate dispose = () => this.pointeract.dispose();\n}\n"],"mappings":"qWAqCA,IAAqB,EAArB,cAAgD,CAAkC,CACjF,WACA,GACA,QAAUA,EAAU,UAA2B,CAE/C,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,IAAM,EAAU,OAAO,OAAO,KAAK,QAAQ,YAAc,EAAE,CAAE,CAC5D,iBAAkB,WAClB,QAAS,KAAK,GAAG,KAAK,UACtB,WAAY,CAAE,IAAA,EAAK,KAAA,EAAM,KAAA,EAAM,CAC/B,CAA4C,CAC7C,KAAK,WAAa,IAAI,EAAW,EAAS,CACzC,EACA,EACA,EACA,EACA,EACA,EACA,CAAC,CACF,IAAM,EAAK,KAAK,UAAU,IAAI,EAAe,CAC7C,EAAG,mBAAmB,UAAU,KAAK,aAAa,CAClD,EAAG,iBAAiB,UAAU,KAAK,cAAc,CAEjD,KAAK,QAAQ,CACZ,IAAK,KAAK,IACV,YAAa,KAAK,YAClB,KAAM,KAAK,KACX,YAAa,KAAK,YAClB,CAAC,CACF,KAAK,QAAQ,KAAK,MAAM,CACxB,KAAK,UAAU,KAAK,QAAQ,CAG7B,UAAsB,CACrB,KAAK,WACH,GAAG,MAAO,KAAK,MAAM,CACrB,GAAG,OAAQ,KAAK,MAAM,CACtB,GAAG,OAAQ,KAAK,OAAO,CACvB,GAAG,YAAa,KAAK,YAAY,CACjC,OAAO,EAGV,kBAA8B,CAC7B,KAAK,WAAW,OAAO,EAExB,iBAA6B,CAC5B,KAAK,WAAW,MAAM,EAGvB,MAAiB,GAA+B,CAC/C,KAAK,QAAQ,CACZ,EAAG,EAAM,OACT,EAAG,EAAM,OACT,CAAC,EAEH,OAAkB,GAAgC,CACjD,KAAK,SAAS,EAAM,OAAQ,EAAM,EAGnC,UAAY,EAAiB,IAAwB,CACpD,IAAM,EAAW,KAAK,IAAI,KAAK,IAAI,KAAK,GAAG,KAAK,MAAQ,EAAS,GAAG,CAAE,IAAK,CAE3E,GAAI,IADU,KAAK,GAAG,KAAK,MACH,OACxB,IAAM,EAAS,EAAW,KAAK,GAAG,KAAK,MACjC,EAAe,KAAK,IAAI,EAAO,CACrC,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,EAAa,EAAI,EACnD,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,EAAa,EAAI,EACnD,KAAK,GAAG,KAAK,MAAQ,GAEtB,SAAW,CAAE,IAAG,OAAqB,CACpC,KAAK,GAAG,KAAK,QAAU,KAAK,GAAG,KAAK,QAAU,EAC9C,KAAK,GAAG,KAAK,QAAU,KAAK,GAAG,KAAK,QAAU,GAG/C,MAAQ,EAAiB,IAAwB,CAChD,KAAK,WAAW,SAAS,OAAQ,CAAE,OAAQ,EAAS,GAAG,EAAQ,CAAC,EAEjE,KAAO,CAAE,IAAG,OAAqB,CAChC,KAAK,WAAW,SAAS,MAAO,CAAE,OAAQ,EAAG,OAAQ,EAAG,CAAC,EAE1D,aAAe,EAAkB,IAAwB,CACxD,IAAM,EAAS,EAAW,KAAK,GAAG,KAAK,MACvC,KAAK,WAAW,SAAS,OAAQ,CAAE,SAAQ,GAAG,EAAQ,CAAC,EAExD,aAAe,CAAE,IAAG,OAAqB,CACxC,KAAK,WAAW,SAAS,MAAO,CAC/B,OAAQ,EAAI,KAAK,GAAG,KAAK,QACzB,OAAQ,EAAI,KAAK,GAAG,KAAK,QACzB,CAAC,EAIH,KAAe,CAAE,EAAG,EAAY,EAAG,MAA+B,CACjE,EAAG,EAAa,KAAK,GAAG,KAAK,QAC7B,EAAG,EAAa,KAAK,GAAG,KAAK,QAC7B,EAED,YAAuB,GAAiC,CACvD,IAAM,EAAU,EAAE,OAClB,GAAI,KAAK,YAAY,EAAQ,CAAE,OAC/B,IAAM,EAAO,KAAK,WAAW,EAAQ,CACrC,KAAK,QAAQ,EAAK,EAGnB,YAAuB,GACjB,EACE,EAAO,QAAQ,YAAY,EAAI,EAAO,QAAQ,SAAS,EAAI,EAAO,QAAQ,QAAQ,CADrE,GAIrB,WAAsB,GAAgC,CACrD,GAAI,CAAC,EAAS,OAAO,KACrB,IAAI,EAAM,EACV,MAAO,CAAC,EAAI,IAAM,EAAI,KAAO,KACvB,EAAI,eACT,EAAM,EAAI,cAGX,OADI,EAAI,KAAO,YAAc,CAAC,EAAI,IAAM,EAAI,KAAO,GAAW,KACvD,EAAI,IAGZ,YAAwB,KAAK,WAAW,SAAS"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { JSONCanvasFileNode, JSONCanvasLinkNode, JSONCanvasNode, JSONCanvasTextNode, Parser } from "../shared/index.js";
|
|
2
|
+
import { Hook } from "./utilities.js";
|
|
3
|
+
import { BaseArgs, BaseModule } from "./BaseModule.js";
|
|
4
|
+
import { BaseOptions } from "./index.js";
|
|
5
|
+
|
|
6
|
+
//#region src/kernel/OverlayManager.d.ts
|
|
7
|
+
interface Options extends BaseOptions {
|
|
8
|
+
parser?: Parser;
|
|
9
|
+
nodeComponents?: Partial<ComponentDict>;
|
|
10
|
+
}
|
|
11
|
+
interface Augmentation {
|
|
12
|
+
onNodeActive: OverlayManager['onNodeActive'];
|
|
13
|
+
onNodeLosesActive: OverlayManager['onNodeLosesActive'];
|
|
14
|
+
}
|
|
15
|
+
type NodeComponentHook<N extends JSONCanvasNode> = (container: HTMLDivElement, content: string, node: N, onBeforeUnmount: Hook, onActive: Hook, onLoseActive: Hook) => void | Promise<void>;
|
|
16
|
+
type ComponentNodeMap = {
|
|
17
|
+
text: JSONCanvasTextNode;
|
|
18
|
+
markdown: JSONCanvasFileNode;
|
|
19
|
+
image: JSONCanvasFileNode;
|
|
20
|
+
audio: JSONCanvasFileNode;
|
|
21
|
+
video: JSONCanvasFileNode;
|
|
22
|
+
link: JSONCanvasLinkNode;
|
|
23
|
+
};
|
|
24
|
+
type ComponentDict = { [K in keyof ComponentNodeMap]: NodeComponentHook<ComponentNodeMap[K]> };
|
|
25
|
+
declare class OverlayManager extends BaseModule<Options, Augmentation> {
|
|
26
|
+
private _overlaysLayer;
|
|
27
|
+
private overlays;
|
|
28
|
+
private selectedId;
|
|
29
|
+
private aborted;
|
|
30
|
+
private eventListeners;
|
|
31
|
+
private DM;
|
|
32
|
+
private SM;
|
|
33
|
+
private parse;
|
|
34
|
+
private componentDict;
|
|
35
|
+
private get overlaysLayer();
|
|
36
|
+
onInteractionStart: Hook<[], false>;
|
|
37
|
+
onInteractionEnd: Hook<[], false>;
|
|
38
|
+
onNodeActive: Hook<[JSONCanvasNode], false>;
|
|
39
|
+
onNodeLosesActive: Hook<[JSONCanvasNode], false>;
|
|
40
|
+
constructor(...args: BaseArgs);
|
|
41
|
+
private start;
|
|
42
|
+
private restart;
|
|
43
|
+
private renderOverlays;
|
|
44
|
+
private themeChanged;
|
|
45
|
+
private select;
|
|
46
|
+
private updateOverlays;
|
|
47
|
+
private createOverlay;
|
|
48
|
+
private constructOverlay;
|
|
49
|
+
private setOverlayColor;
|
|
50
|
+
private clearOverlays;
|
|
51
|
+
private dispose;
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { OverlayManager };
|
|
55
|
+
//# sourceMappingURL=OverlayManager.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{BaseModule as e}from"./BaseModule.js";import t,{destroyError as n}from"./utilities.js";import r from"./DataManager.js";import i from"./StyleManager.js";import a from"./Controller.js";import o from"./InteractionHandler.js";const s={markdown:/\.(md|mdx|markdown|txt)$/i,image:/\.(png|jpg|jpeg|gif|svg|webp|avif|bmp|ico|heic|heif)$/i,audio:/\.(mp3|wav|ogg|opus|aac|m4a|flac)$/i,video:/\.(mp4|webm|ogv|mov|m3u8|mpd)$/i},c=[`markdown`,`image`,`audio`,`video`];var l=class extends e{_overlaysLayer=document.createElement(`div`);overlays={};selectedId=null;aborted=!1;eventListeners={};DM;SM;parse;componentDict={text:(e,t)=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.innerHTML=t,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n)},markdown:async(e,t)=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.textContent=`Loading...`,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n);let r;try{let e=await(await fetch(t)).text(),n=e.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);r=n?await this.parse(n[2]):await this.parse(e)}catch(e){console.error(`[JSON Canvas Viewer] Failed to load markdown:`,e),r=`Failed to load content.`}n.innerHTML=r},link:(e,t)=>{let n=document.createElement(`iframe`);n.src=t,n.sandbox=`allow-scripts allow-same-origin`,n.className=`JCV-link-iframe`,n.loading=`lazy`,e.appendChild(n)},audio:(e,t)=>{let n=document.createElement(`audio`);n.className=`JCV-audio`,n.src=t,n.controls=!0,e.appendChild(n)},image:(e,t)=>{let n=document.createElement(`img`);n.className=`JCV-img`,n.src=t,n.loading=`lazy`,e.appendChild(n)},video:(e,t)=>{let n=document.createElement(`video`);n.className=`JCV-video`,n.src=t,n.controls=!0,e.appendChild(n)}};get overlaysLayer(){if(!this._overlaysLayer)throw n;return this._overlaysLayer}onInteractionStart=t.makeHook();onInteractionEnd=t.makeHook();onNodeActive=t.makeHook();onNodeLosesActive=t.makeHook();constructor(...e){super(...e),this.parse=this.options.parser||(e=>e),this.DM=this.container.get(r),this.SM=this.container.get(i),this.container.get(a).onRefresh.subscribe(this.updateOverlays),this.SM.onChangeTheme.subscribe(this.themeChanged),this._overlaysLayer=document.createElement(`div`),this._overlaysLayer.className=`JCV-overlays`,this._overlaysLayer.id=`overlays`,this.DM.data.container.appendChild(this.overlaysLayer);let t=this.options.nodeComponents;t&&Object.assign(this.componentDict,t),this.augment({onNodeActive:this.onNodeActive,onNodeLosesActive:this.onNodeLosesActive}),this.onStart(this.start),this.onRestart(this.restart),this.onDispose(this.dispose)}start=()=>{this.container.get(o).onClick.subscribe(this.select),this.renderOverlays()};restart=()=>{this.clearOverlays(),this.renderOverlays()};renderOverlays=()=>{let e=async e=>{switch(e.type){case`text`:this.createOverlay(e,await this.parse(e.text),`text`);break;case`file`:for(let t of c)if(e.file.match(s[t])){this.createOverlay(e,e.file,t);break}break;case`link`:this.createOverlay(e,e.url,`link`);break}};Object.values(this.DM.data.nodeMap).forEach(async t=>{await e(t.ref)})};themeChanged=()=>{Object.values(this.overlays).forEach(e=>{let t=this.DM.data.nodeMap[e.id].ref,n=this.SM.getColor(t.color);this.setOverlayColor(e,n)})};select=e=>{let t=this.selectedId,n=t?this.overlays[t]:null,r=e?this.overlays[e]:null;if(n&&t){n.classList.remove(`JCV-active`);let e=this.DM.data.nodeMap[t];this.onNodeLosesActive(e.ref),e.onLoseActive?.()}if(r&&e){r.classList.add(`JCV-active`),this.onInteractionStart();let t=this.DM.data.nodeMap[e];this.onNodeActive(t.ref),t.onActive?.()}else this.onInteractionEnd();this.selectedId=e};updateOverlays=()=>{let e=this.DM.data;this.overlaysLayer.style.transform=`translate(${e.offsetX}px, ${e.offsetY}px) scale(${e.scale})`};createOverlay=(...e)=>{if(this.aborted)return;let t=e[0],n=this.overlays[t.id];if(!n){if(n=this.constructOverlay(...e),this.aborted)return;this.overlaysLayer.appendChild(n),this.overlays[t.id]=n,n.style.left=`${t.x}px`,n.style.top=`${t.y}px`,n.style.width=`${t.width}px`,n.style.height=`${t.height}px`}};constructOverlay=(...e)=>{let n=e[0],r=document.createElement(`div`);r.classList.add(`JCV-overlay-container`),r.id=n.id,this.setOverlayColor(r,this.SM.getColor(n.color));let i=document.createElement(`div`);i.classList.add(`JCV-content`),r.appendChild(i);let a=document.createElement(`div`);a.className=`JCV-click-layer`,r.appendChild(a);let o=document.createElement(`div`);o.className=`JCV-overlay-border`,r.appendChild(o);let s=this.DM.data.nodeMap[n.id];s.onActive=t.makeHook(),s.onLoseActive=t.makeHook(),s.onBeforeUnmount=t.makeHook(),this.componentDict[e[2]](i,e[1],e[0],s.onBeforeUnmount,s.onActive,s.onLoseActive);let c=()=>{n.id===this.selectedId&&this.onInteractionStart()},l=()=>{n.id===this.selectedId&&this.onInteractionEnd()};return r.addEventListener(`pointerenter`,c),r.addEventListener(`pointerleave`,l),r.addEventListener(`touchstart`,c),r.addEventListener(`touchend`,l),this.eventListeners[n.id]=[c,l],r};setOverlayColor=(e,t)=>{Object.entries(t).forEach(([t,n])=>{e.style.setProperty(`--overlay-${t}`,n)})};clearOverlays=()=>{Object.entries(this.overlays).forEach(([e,t])=>{if(this.DM.data.nodeMap[e].onBeforeUnmount?.(),this.eventListeners[e]){let r=this.eventListeners[e][0],i=this.eventListeners[e][1];if(!r||!i)throw n;t.removeEventListener(`pointerenter`,r),t.removeEventListener(`pointerleave`,i),t.removeEventListener(`touchstart`,r),t.removeEventListener(`touchend`,i),this.eventListeners[e][0]=null,this.eventListeners[e][1]=null}t.remove(),delete this.overlays[e]})};dispose=()=>{this.aborted=!0,this.clearOverlays(),this.overlaysLayer.remove(),this._overlaysLayer=null}};export{l as default};
|
|
2
|
+
//# sourceMappingURL=OverlayManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OverlayManager.js","names":["utilities"],"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 WithBorderWidth as 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\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"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { BaseArgs, BaseModule } from "./BaseModule.js";
|
|
2
|
+
import { BaseOptions } from "./index.js";
|
|
3
|
+
|
|
4
|
+
//#region src/kernel/Renderer.d.ts
|
|
5
|
+
interface Options extends BaseOptions {
|
|
6
|
+
zoomInOptimization?: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare class Renderer extends BaseModule<Options> {
|
|
9
|
+
private _canvas;
|
|
10
|
+
private ctx;
|
|
11
|
+
private DM;
|
|
12
|
+
private SM;
|
|
13
|
+
private zoomInOptimize;
|
|
14
|
+
private get canvas();
|
|
15
|
+
constructor(...args: BaseArgs);
|
|
16
|
+
private optimizeDPR;
|
|
17
|
+
private redraw;
|
|
18
|
+
private trueRedraw;
|
|
19
|
+
private fakeRedraw;
|
|
20
|
+
private isInside;
|
|
21
|
+
private isOutside;
|
|
22
|
+
private getCurrentViewport;
|
|
23
|
+
private drawLabelBar;
|
|
24
|
+
private drawNodeBackground;
|
|
25
|
+
private drawGroup;
|
|
26
|
+
private drawFile;
|
|
27
|
+
private drawEdge;
|
|
28
|
+
private getControlPoints;
|
|
29
|
+
private drawGridDots;
|
|
30
|
+
private drawCurvedPath;
|
|
31
|
+
private drawArrowhead;
|
|
32
|
+
private dispose;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { Renderer };
|
|
36
|
+
//# sourceMappingURL=Renderer.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{BaseModule as e}from"./BaseModule.js";import t,{destroyError as n}from"./utilities.js";import r from"./DataManager.js";import i from"./StyleManager.js";import a from"./Controller.js";var o=class extends e{_canvas;ctx;DM;SM;zoomInOptimize={lastDrawnScale:0,lastDrawnViewport:{left:0,right:0,top:0,bottom:0},timeout:null,lastCallTime:0};get canvas(){if(!this._canvas)throw n;return this._canvas}constructor(...e){super(...e);let t=this.container.get(a);this.SM=this.container.get(i),t.onRefresh.subscribe(this.redraw),t.onResize.subscribe(this.optimizeDPR),this.DM=this.container.get(r),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;t.resizeCanvasForDPR(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=null);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=null},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;return{left:r,top:i,right:r+a.clientWidth/n,bottom:i+a.clientHeight/n}};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 n=this.SM.getColor(e.color);this.ctx.globalAlpha=1,this.ctx.fillStyle=n.background,t.drawRoundRect(this.ctx,e.x+1,e.y+1,e.width-2,e.height-2,12),this.ctx.fill(),this.ctx.strokeStyle=n.border,this.ctx.lineWidth=2,t.drawRoundRect(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 n=e.ref,r=this.DM.data.nodeMap[n.fromNode].ref,i=this.DM.data.nodeMap[n.toNode].ref,a=t.getAnchorCoord,{x:o,y:s}=a(r,n.fromSide),{x:c,y:l}=a(i,n.toSide),u=this.SM.getColor(n.color),[d,f,p,m]=[0,0,0,0];if(e.controlPoints?[d,f,p,m]=e.controlPoints:([d,f,p,m]=this.getControlPoints(o,s,c,l,n.fromSide,n.toSide),e.controlPoints=[d,f,p,m]),this.drawCurvedPath(o,s,c,l,d,f,p,m,u.active),this.drawArrowhead(c,l,p,m,u.active),n.label){let e=.5,r=(1-e)**3*o+3*(1-e)**2*e*d+3*(1-e)*e*e*p+e**3*c,i=(1-e)**3*s+3*(1-e)**2*e*f+3*(1-e)*e*e*m+e**3*l;this.ctx.font=`18px sans-serif`;let a=this.ctx.measureText(n.label).width+16;this.ctx.fillStyle=u.active,this.ctx.beginPath(),t.drawRoundRect(this.ctx,r-a/2,i-20/2-2,a,20,4),this.ctx.fill(),this.ctx.fillStyle=u.text,this.ctx.textAlign=`center`,this.ctx.textBaseline=`middle`,this.ctx.fillText(n.label,r,i-2),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=null),this.canvas.remove(),this._canvas=null}};export{o as default};
|
|
2
|
+
//# sourceMappingURL=Renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Renderer.js","names":["utilities"],"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: number | 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 = 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 = 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"],"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
|
+
interface Color {
|
|
7
|
+
border: string;
|
|
8
|
+
background: string;
|
|
9
|
+
active: string;
|
|
10
|
+
text: string;
|
|
11
|
+
card: string;
|
|
12
|
+
}
|
|
13
|
+
interface WithBorderWidth extends Color {
|
|
14
|
+
'border-width': string;
|
|
15
|
+
}
|
|
16
|
+
type ColorOptions = { [K in keyof (StyleManager['definedColors']['light'] & StyleManager['namedColors']['light'])]?: string };
|
|
17
|
+
interface Options extends BaseOptions {
|
|
18
|
+
theme?: 'dark' | 'light';
|
|
19
|
+
colors?: {
|
|
20
|
+
light?: ColorOptions;
|
|
21
|
+
dark?: ColorOptions;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface 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
|
+
light: {
|
|
33
|
+
'0': {
|
|
34
|
+
hue: number;
|
|
35
|
+
saturation: number;
|
|
36
|
+
lightness: number;
|
|
37
|
+
};
|
|
38
|
+
'1': {
|
|
39
|
+
hue: number;
|
|
40
|
+
saturation: number;
|
|
41
|
+
lightness: number;
|
|
42
|
+
};
|
|
43
|
+
'2': {
|
|
44
|
+
hue: number;
|
|
45
|
+
saturation: number;
|
|
46
|
+
lightness: number;
|
|
47
|
+
};
|
|
48
|
+
'3': {
|
|
49
|
+
hue: number;
|
|
50
|
+
saturation: number;
|
|
51
|
+
lightness: number;
|
|
52
|
+
};
|
|
53
|
+
'4': {
|
|
54
|
+
hue: number;
|
|
55
|
+
saturation: number;
|
|
56
|
+
lightness: number;
|
|
57
|
+
};
|
|
58
|
+
'5': {
|
|
59
|
+
hue: number;
|
|
60
|
+
saturation: number;
|
|
61
|
+
lightness: number;
|
|
62
|
+
};
|
|
63
|
+
'6': {
|
|
64
|
+
hue: number;
|
|
65
|
+
saturation: number;
|
|
66
|
+
lightness: number;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
dark: {
|
|
70
|
+
'0': {
|
|
71
|
+
hue: number;
|
|
72
|
+
saturation: number;
|
|
73
|
+
lightness: number;
|
|
74
|
+
};
|
|
75
|
+
'1': {
|
|
76
|
+
hue: number;
|
|
77
|
+
saturation: number;
|
|
78
|
+
lightness: number;
|
|
79
|
+
};
|
|
80
|
+
'2': {
|
|
81
|
+
hue: number;
|
|
82
|
+
saturation: number;
|
|
83
|
+
lightness: number;
|
|
84
|
+
};
|
|
85
|
+
'3': {
|
|
86
|
+
hue: number;
|
|
87
|
+
saturation: number;
|
|
88
|
+
lightness: number;
|
|
89
|
+
};
|
|
90
|
+
'4': {
|
|
91
|
+
hue: number;
|
|
92
|
+
saturation: number;
|
|
93
|
+
lightness: number;
|
|
94
|
+
};
|
|
95
|
+
'5': {
|
|
96
|
+
hue: number;
|
|
97
|
+
saturation: number;
|
|
98
|
+
lightness: number;
|
|
99
|
+
};
|
|
100
|
+
'6': {
|
|
101
|
+
hue: number;
|
|
102
|
+
saturation: number;
|
|
103
|
+
lightness: number;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
namedColors: {
|
|
108
|
+
light: {
|
|
109
|
+
dots: string;
|
|
110
|
+
text: string;
|
|
111
|
+
background: string;
|
|
112
|
+
'background-secondary': string;
|
|
113
|
+
shadow: string;
|
|
114
|
+
border: string;
|
|
115
|
+
};
|
|
116
|
+
dark: {
|
|
117
|
+
dots: string;
|
|
118
|
+
text: string;
|
|
119
|
+
background: string;
|
|
120
|
+
'background-secondary': string;
|
|
121
|
+
shadow: string;
|
|
122
|
+
border: string;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
private colorCache;
|
|
126
|
+
constructor(...args: BaseArgs);
|
|
127
|
+
private hslProcessor;
|
|
128
|
+
private 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
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{BaseModule as e}from"./BaseModule.js";import 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.makeHook();definedColors={light:{0:{hue:0,saturation:0,lightness:72},1:{hue:358,saturation:81,lightness:55},2:{hue:19,saturation:87,lightness:58},3:{hue:41,saturation:79,lightness:52},4:{hue:150,saturation:100,lightness:37},5:{hue:221,saturation:100,lightness:59},6:{hue:257,saturation:81,lightness:62}},dark:{0:{hue:0,saturation:0,lightness:40},1:{hue:358,saturation:100,lightness:65},2:{hue:23,saturation:86,lightness:63},3:{hue:39,saturation:91,lightness:70},4:{hue:153,saturation:80,lightness:45},5:{hue:217,saturation:100,lightness:62},6:{hue:259,saturation:100,lightness:75}}};namedColors={light:{dots:`hsla(0, 0%, 72%, 0.4)`,text:`rgb(30, 30, 30)`,background:`rgb(250, 250, 250)`,"background-secondary":`rgb(255, 255, 255)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.1)`,border:`hsla(0, 0%, 82%, 0.7)`},dark:{dots:`hsla(0, 0%, 40%, 0.3)`,text:`rgb(242, 242, 242)`,background:`rgb(30, 30, 30)`,"background-secondary":`rgb(37, 37, 40)`,shadow:`0px 0px 8px rgb(0, 0, 0, 0.2)`,border:`hsla(0, 0%, 30%, 0.7)`}};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;return i=this.theme===`dark`?{active:e,card:{hue:t,saturation:n/3,lightness:r/3},border:{...e,alpha:.7},background:{...e,alpha:.1},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`}:{active:e,card:t===0?{hue:t,saturation:n,lightness:100}:{hue:t,saturation:n*.4,lightness:90},border:{...e,alpha:.7},background:{...e,alpha:.1},text:e.lightness>=70?`rgb(30, 30, 30)`:`rgb(242, 242, 242)`},{active:s(i.active),card:s(i.card),border:s(i.border),background:s(i.background),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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StyleManager.js","names":["utilities"],"sources":["../../src/kernel/StyleManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport { BaseModule, type BaseArgs } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport utilities from '$/utilities';\nimport {\n\tparseHex,\n\ttoHslString,\n\ttype HslColor,\n\trgbToHsl,\n\tparseHsl,\n\tparseRgb,\n} from '@ahmedsemih/color-fns';\n\ninterface Color {\n\tborder: string;\n\tbackground: string;\n\tactive: string;\n\ttext: string;\n\tcard: string;\n}\n\nexport interface WithBorderWidth extends Color {\n\t'border-width': string;\n}\n\ntype ColorOptions = {\n\t[K in keyof (StyleManager['definedColors']['light'] &\n\t\tStyleManager['namedColors']['light'])]?: string;\n};\n\ninterface Options extends BaseOptions {\n\ttheme?: 'dark' | 'light';\n\tcolors?: {\n\t\tlight?: ColorOptions;\n\t\tdark?: ColorOptions;\n\t};\n}\n\ninterface 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 = utilities.makeHook<['light' | 'dark']>();\n\tdefinedColors = {\n\t\tlight: {\n\t\t\t'0': { hue: 0, saturation: 0, lightness: 72 },\n\t\t\t'1': { hue: 358, saturation: 81, lightness: 55 },\n\t\t\t'2': { hue: 19, saturation: 87, lightness: 58 },\n\t\t\t'3': { hue: 41, saturation: 79, lightness: 52 },\n\t\t\t'4': { hue: 150, saturation: 100, lightness: 37 },\n\t\t\t'5': { hue: 221, saturation: 100, lightness: 59 },\n\t\t\t'6': { hue: 257, saturation: 81, lightness: 62 },\n\t\t},\n\t\tdark: {\n\t\t\t'0': { hue: 0, saturation: 0, lightness: 40 },\n\t\t\t'1': { hue: 358, saturation: 100, lightness: 65 },\n\t\t\t'2': { hue: 23, saturation: 86, lightness: 63 },\n\t\t\t'3': { hue: 39, saturation: 91, lightness: 70 },\n\t\t\t'4': { hue: 153, saturation: 80, lightness: 45 },\n\t\t\t'5': { hue: 217, saturation: 100, lightness: 62 },\n\t\t\t'6': { hue: 259, saturation: 100, lightness: 75 },\n\t\t},\n\t};\n\n\tnamedColors = {\n\t\tlight: {\n\t\t\tdots: 'hsla(0, 0%, 72%, 0.4)',\n\t\t\ttext: 'rgb(30, 30, 30)',\n\t\t\tbackground: 'rgb(250, 250, 250)',\n\t\t\t'background-secondary': 'rgb(255, 255, 255)',\n\t\t\tshadow: '0px 0px 8px rgb(0, 0, 0, 0.1)',\n\t\t\tborder: 'hsla(0, 0%, 82%, 0.7)',\n\t\t},\n\t\tdark: {\n\t\t\tdots: 'hsla(0, 0%, 40%, 0.3)',\n\t\t\ttext: 'rgb(242, 242, 242)',\n\t\t\tbackground: 'rgb(30, 30, 30)',\n\t\t\t'background-secondary': 'rgb(37, 37, 40)',\n\t\t\tshadow: '0px 0px 8px rgb(0, 0, 0, 0.2)',\n\t\t\tborder: 'hsla(0, 0%, 30%, 0.7)',\n\t\t},\n\t};\n\n\tprivate colorCache: {\n\t\tdark: {\n\t\t\t[key: string]: WithBorderWidth;\n\t\t};\n\t\tlight: {\n\t\t\t[key: string]: WithBorderWidth;\n\t\t};\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 hslProcessor = (color: HslColor) => {\n\t\tconst { hue, saturation, lightness } = color;\n\t\tlet result;\n\t\tif (this.theme === 'dark') {\n\t\t\tresult = {\n\t\t\t\tactive: color,\n\t\t\t\tcard: { hue, saturation: saturation / 3, lightness: lightness / 3 },\n\t\t\t\tborder: { ...color, alpha: 0.7 },\n\t\t\t\tbackground: { ...color, alpha: 0.1 },\n\t\t\t\ttext: color.lightness >= 70 ? 'rgb(30, 30, 30)' : 'rgb(242, 242, 242)',\n\t\t\t};\n\t\t} else {\n\t\t\tresult = {\n\t\t\t\tactive: color,\n\t\t\t\tcard:\n\t\t\t\t\thue === 0\n\t\t\t\t\t\t? { hue, saturation, lightness: 100 }\n\t\t\t\t\t\t: { hue, saturation: saturation * 0.4, lightness: 90 },\n\t\t\t\tborder: { ...color, alpha: 0.7 },\n\t\t\t\tbackground: { ...color, alpha: 0.1 },\n\t\t\t\ttext: color.lightness >= 70 ? 'rgb(30, 30, 30)' : 'rgb(242, 242, 242)',\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tactive: toHslString(result.active),\n\t\t\tcard: toHslString(result.card),\n\t\t\tborder: toHslString(result.border),\n\t\t\tbackground: toHslString(result.background),\n\t\t\ttext: result.text,\n\t\t};\n\t};\n\n\tprivate 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: string = '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 ? 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 { Controller } from "./Controller.js";
|
|
5
|
+
import { DataManager } from "./DataManager.js";
|
|
6
|
+
import { InteractionHandler } from "./InteractionHandler.js";
|
|
7
|
+
import { OverlayManager } from "./OverlayManager.js";
|
|
8
|
+
import { Renderer } from "./Renderer.js";
|
|
9
|
+
import { StyleManager } from "./StyleManager.js";
|
|
10
|
+
import { Container } from "@needle-di/core";
|
|
11
|
+
|
|
12
|
+
//#region src/kernel/index.d.ts
|
|
13
|
+
interface 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 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 onVisibilityCheck;
|
|
33
|
+
private 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
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import 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=null;started=!1;disposed=!1;options;container;onDispose=e.makeHook(!0);onStart=e.makeHook();onRestart=e.makeHook();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,{root:null,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=null;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=null;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
|