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.
Files changed (79) hide show
  1. package/dist/chimp.js +396 -1
  2. package/dist/index.d.ts +29 -618
  3. package/dist/index.js +2 -2
  4. package/dist/index.js.map +1 -1
  5. package/dist/kernel/BaseModule.d.ts +27 -0
  6. package/dist/kernel/BaseModule.js +2 -2
  7. package/dist/kernel/BaseModule.js.map +1 -1
  8. package/dist/kernel/Controller.d.ts +30 -0
  9. package/dist/kernel/Controller.js +2 -2
  10. package/dist/kernel/Controller.js.map +1 -1
  11. package/dist/kernel/DataManager.d.ts +67 -0
  12. package/dist/kernel/DataManager.js +2 -2
  13. package/dist/kernel/DataManager.js.map +1 -1
  14. package/dist/kernel/InteractionHandler.d.ts +51 -0
  15. package/dist/kernel/InteractionHandler.js +2 -2
  16. package/dist/kernel/InteractionHandler.js.map +1 -1
  17. package/dist/kernel/OverlayManager.d.ts +62 -0
  18. package/dist/kernel/OverlayManager.js +2 -2
  19. package/dist/kernel/OverlayManager.js.map +1 -1
  20. package/dist/kernel/Renderer.d.ts +37 -0
  21. package/dist/kernel/Renderer.js +3 -2
  22. package/dist/kernel/Renderer.js.map +1 -1
  23. package/dist/kernel/StyleManager.d.ts +135 -0
  24. package/dist/kernel/StyleManager.js +2 -2
  25. package/dist/kernel/StyleManager.js.map +1 -1
  26. package/dist/kernel/index.d.ts +46 -0
  27. package/dist/kernel/index.js +2 -2
  28. package/dist/kernel/index.js.map +1 -1
  29. package/dist/kernel/styles.js +285 -0
  30. package/dist/kernel/styles.js.map +1 -0
  31. package/dist/kernel/types.d.ts +33 -0
  32. package/dist/kernel/utilities.d.ts +13 -0
  33. package/dist/kernel/utilities.js +2 -2
  34. package/dist/kernel/utilities.js.map +1 -1
  35. package/dist/modules/Controls/index.d.ts +42 -0
  36. package/dist/modules/Controls/index.js +2 -2
  37. package/dist/modules/Controls/index.js.map +1 -1
  38. package/dist/modules/Controls/styles.js +29 -0
  39. package/dist/modules/Controls/styles.js.map +1 -0
  40. package/dist/modules/DebugPanel/index.d.ts +14 -0
  41. package/dist/modules/DebugPanel/index.js +2 -2
  42. package/dist/modules/DebugPanel/index.js.map +1 -1
  43. package/dist/modules/DebugPanel/styles.js +13 -0
  44. package/dist/modules/DebugPanel/styles.js.map +1 -0
  45. package/dist/modules/Minimap/index.d.ts +36 -0
  46. package/dist/modules/Minimap/index.js +2 -2
  47. package/dist/modules/Minimap/index.js.map +1 -1
  48. package/dist/modules/Minimap/styles.js +56 -0
  49. package/dist/modules/Minimap/styles.js.map +1 -0
  50. package/dist/modules/MistouchPreventer/index.d.ts +29 -0
  51. package/dist/modules/MistouchPreventer/index.js +2 -2
  52. package/dist/modules/MistouchPreventer/index.js.map +1 -1
  53. package/dist/modules/MistouchPreventer/styles.js +21 -0
  54. package/dist/modules/MistouchPreventer/styles.js.map +1 -0
  55. package/dist/shared/index.d.ts +50 -0
  56. package/dist/utilities/fetch-canvas.d.ts +7 -0
  57. package/dist/utilities/fetch-canvas.js +2 -0
  58. package/dist/utilities/fetch-canvas.js.map +1 -0
  59. package/dist/utilities/parser.d.ts +5 -0
  60. package/dist/utilities/parser.js +2 -2
  61. package/dist/utilities/parser.js.map +1 -1
  62. package/dist/utilities/render-to-string.d.ts +12 -0
  63. package/dist/utilities/render-to-string.js +2 -0
  64. package/dist/utilities/render-to-string.js.map +1 -0
  65. package/package.json +8 -7
  66. package/dist/kernel/styles.scss.js +0 -2
  67. package/dist/kernel/styles.scss.js.map +0 -1
  68. package/dist/modules/Controls/styles.scss.js +0 -2
  69. package/dist/modules/Controls/styles.scss.js.map +0 -1
  70. package/dist/modules/DebugPanel/styles.scss.js +0 -2
  71. package/dist/modules/DebugPanel/styles.scss.js.map +0 -1
  72. package/dist/modules/Minimap/styles.scss.js +0 -2
  73. package/dist/modules/Minimap/styles.scss.js.map +0 -1
  74. package/dist/modules/MistouchPreventer/styles.scss.js +0 -2
  75. package/dist/modules/MistouchPreventer/styles.scss.js.map +0 -1
  76. package/dist/utilities/fetchCanvas.js +0 -2
  77. package/dist/utilities/fetchCanvas.js.map +0 -1
  78. package/dist/utilities/renderToString.js +0 -2
  79. package/dist/utilities/renderToString.js.map +0 -1
@@ -1,2 +1,2 @@
1
- class s{constructor(s,t,o,i,n,r){this.container=s,this.augment=r,this.options=t,this.onStart=o.subscribe,this.onDispose=i.subscribe,this.onRestart=n.subscribe}onStart;onRestart;onDispose;options}export{s as BaseModule};
2
- //# sourceMappingURL=BaseModule.js.map
1
+ var e=class{onStart;onRestart;onDispose;constructor(e,t,n,r,i,a){this.container=e,this.augment=a,this.options=t,this.onStart=n.subscribe,this.onDispose=r.subscribe,this.onRestart=i.subscribe}options};export{e as BaseModule};
2
+ //# sourceMappingURL=BaseModule.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BaseModule.js","sources":["../../src/kernel/BaseModule.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { General, GeneralObject, ModuleInput as MI, Orchestratable } from '$/types';\nimport type utilities from '$/utilities';\nimport type { Container } from '@needle-di/core';\n\ntype Hook = ReturnType<typeof utilities.makeHook>;\n\nexport type GeneralModuleCtor = typeof BaseModule<General, General>;\nexport type GeneralModule = BaseModule<General, General>;\n\nexport type ModuleInputCtor = Array<GeneralModuleCtor>;\nexport type ModuleInput = MI<GeneralModuleCtor>;\nexport type Options<M extends ModuleInput> = Orchestratable<M, 'options'>;\nexport type Augmentation<M extends ModuleInput> = Orchestratable<M, '_Augmentation'>;\n\nexport type BaseArgs = ConstructorParameters<GeneralModuleCtor>;\n\nexport class BaseModule<O extends BaseOptions = BaseOptions, A extends GeneralObject = {}> {\n\t// https://github.com/timocov/dts-bundle-generator/issues/360\n\tdeclare private static readonly _BaseModuleBrand: unique symbol; // Nominal marker\n\tdeclare _Augmentation: A;\n\tonStart: Hook['subscribe'];\n\tonRestart: Hook['subscribe'];\n\tonDispose: Hook['subscribe'];\n\tconstructor(\n\t\tprotected container: Container,\n\t\toptions: GeneralObject,\n\t\tonStart: Hook,\n\t\tonDispose: Hook,\n\t\tonRestart: Hook,\n\t\tprotected augment: (aug: A) => void,\n\t) {\n\t\tthis.options = options as O;\n\t\tthis.onStart = onStart.subscribe;\n\t\tthis.onDispose = onDispose.subscribe;\n\t\tthis.onRestart = onRestart.subscribe;\n\t}\n\toptions: O;\n}\n"],"names":["BaseModule","constructor","container","options","onStart","onDispose","onRestart","augment","this","subscribe"],"mappings":"AAiBO,MAAMA,EAOZ,WAAAC,CACWC,EACVC,EACAC,EACAC,EACAC,EACUC,GALAC,KAAAN,UAAAA,EAKAM,KAAAD,QAAAA,EAEVC,KAAKL,QAAUA,EACfK,KAAKJ,QAAUA,EAAQK,UACvBD,KAAKH,UAAYA,EAAUI,UAC3BD,KAAKF,UAAYA,EAAUG,SAC5B,CAfAL,QACAE,UACAD,UAcAF"}
1
+ {"version":3,"file":"BaseModule.js","names":[],"sources":["../../src/kernel/BaseModule.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { General, GeneralObject, ModuleInput as MI, Orchestratable } from '$/types';\nimport type { Hook } from '$/utilities';\nimport type { Container } from '@needle-di/core';\n\nexport type GeneralModuleCtor = typeof BaseModule<General, General>;\nexport type GeneralModule = BaseModule<General, General>;\n\nexport type ModuleInputCtor = Array<GeneralModuleCtor>;\nexport type ModuleInput = MI<GeneralModuleCtor>;\nexport type Options<M extends ModuleInput> = Orchestratable<M, 'options'>;\nexport type Augmentation<M extends ModuleInput> = Orchestratable<M, '_Augmentation'>;\n\nexport type BaseArgs = ConstructorParameters<GeneralModuleCtor>;\n\nexport class BaseModule<O extends BaseOptions = BaseOptions, A extends GeneralObject = {}> {\n\t// https://github.com/timocov/dts-bundle-generator/issues/360\n\tdeclare private static readonly _BaseModuleBrand: unique symbol; // Nominal marker\n\tdeclare _Augmentation: A;\n\tonStart: Hook['subscribe'];\n\tonRestart: Hook['subscribe'];\n\tonDispose: Hook['subscribe'];\n\t// oxlint-disable-next-line max-params\n\tconstructor(\n\t\tprotected container: Container,\n\t\toptions: GeneralObject,\n\t\tonStart: Hook,\n\t\tonDispose: Hook,\n\t\tonRestart: Hook,\n\t\tprotected augment: (aug: A) => void,\n\t) {\n\t\tthis.options = options as O;\n\t\tthis.onStart = onStart.subscribe;\n\t\tthis.onDispose = onDispose.subscribe;\n\t\tthis.onRestart = onRestart.subscribe;\n\t}\n\toptions: O;\n}\n"],"mappings":"AAeA,IAAa,EAAb,KAA2F,CAI1F,QACA,UACA,UAEA,YACC,EACA,EACA,EACA,EACA,EACA,EACC,CANS,KAAA,UAAA,EAKA,KAAA,QAAA,EAEV,KAAK,QAAU,EACf,KAAK,QAAU,EAAQ,UACvB,KAAK,UAAY,EAAU,UAC3B,KAAK,UAAY,EAAU,UAE5B"}
@@ -0,0 +1,30 @@
1
+ import { Hook } from "./utilities.js";
2
+ import { BaseArgs, BaseModule } from "./BaseModule.js";
3
+ import { BaseOptions } from "./index.js";
4
+
5
+ //#region src/kernel/Controller.d.ts
6
+ type Augmentation = {
7
+ refresh: Controller['refresh'];
8
+ onRefresh: Controller['onRefresh'];
9
+ onResize: Controller['onResize'];
10
+ };
11
+ declare class Controller extends BaseModule<BaseOptions, Augmentation> {
12
+ private animationId;
13
+ private resizeAnimationId;
14
+ private readonly DM;
15
+ private readonly SM;
16
+ private readonly resizeObserver;
17
+ private perFrame;
18
+ private readonly lastResizeCenter;
19
+ onResize: Hook<[number, number], false>;
20
+ onRefresh: Hook<[], false>;
21
+ constructor(...args: BaseArgs);
22
+ private readonly start;
23
+ private readonly draw;
24
+ refresh: () => void;
25
+ private readonly onResizeCallback;
26
+ private readonly dispose;
27
+ }
28
+ //#endregion
29
+ export { Controller };
30
+ //# sourceMappingURL=Controller.d.ts.map
@@ -1,2 +1,2 @@
1
- import{BaseModule as e}from"./BaseModule.js";import s from"./DataManager.js";import t from"./StyleManager.js";import i from"./utilities.js";class a extends e{animationId=null;resizeAnimationId=null;DM;SM;resizeObserver;perFrame={lastScale:1,lastOffsets:{x:0,y:0}};lastResizeCenter={x:null,y:null};onResize=i.makeHook();onRefresh=i.makeHook();constructor(...e){super(...e),this.DM=this.container.get(s),this.SM=this.container.get(t),this.resizeObserver=new ResizeObserver(this.onResizeCallback),this.SM.onChangeTheme.subscribe(this.refresh),this.augment({refresh:this.refresh,onRefresh:this.onRefresh,onResize:this.onResize}),this.onStart(this.start),this.onRestart(this.refresh),this.onDispose(this.dispose)}start=()=>{this.resizeObserver.observe(this.DM.data.container),this.animationId=requestAnimationFrame(this.draw)};draw=()=>{this.perFrame.lastScale===this.DM.data.scale&&this.perFrame.lastOffsets.x===this.DM.data.offsetX&&this.perFrame.lastOffsets.y===this.DM.data.offsetY||this.refresh(),this.animationId=requestAnimationFrame(this.draw)};refresh=()=>{this.perFrame={lastScale:this.DM.data.scale,lastOffsets:{x:this.DM.data.offsetX,y:this.DM.data.offsetY}},this.onRefresh()};onResizeCallback=()=>{this.resizeAnimationId=requestAnimationFrame(()=>{const e=this.DM.middleViewer();this.lastResizeCenter.x&&this.lastResizeCenter.y&&(this.DM.data.offsetX=this.DM.data.offsetX+e.x-this.lastResizeCenter.x,this.DM.data.offsetY=this.DM.data.offsetY+e.y-this.lastResizeCenter.y),this.lastResizeCenter.x=e.x,this.lastResizeCenter.y=e.y,this.onResize(e.width,e.height),this.refresh()})};dispose=()=>{this.animationId&&cancelAnimationFrame(this.animationId),this.resizeAnimationId&&cancelAnimationFrame(this.resizeAnimationId),this.resizeObserver.disconnect()}}export{a as default};
2
- //# sourceMappingURL=Controller.js.map
1
+ import{BaseModule as e}from"./BaseModule.js";import{makeHook as t}from"./utilities.js";import n from"./DataManager.js";import r from"./StyleManager.js";var i=class extends e{animationId;resizeAnimationId;DM;SM;resizeObserver;perFrame={lastOffsets:{x:0,y:0},lastScale:1};lastResizeCenter={x:void 0,y:void 0};onResize=t();onRefresh=t();constructor(...e){super(...e),this.DM=this.container.get(n),this.SM=this.container.get(r),this.resizeObserver=new ResizeObserver(this.onResizeCallback),this.SM.onChangeTheme.subscribe(this.refresh),this.augment({onRefresh:this.onRefresh,onResize:this.onResize,refresh:this.refresh}),this.onStart(this.start),this.onRestart(this.refresh),this.onDispose(this.dispose)}start=()=>{this.resizeObserver.observe(this.DM.data.container),this.animationId=requestAnimationFrame(this.draw)};draw=()=>{(this.perFrame.lastScale!==this.DM.data.scale||this.perFrame.lastOffsets.x!==this.DM.data.offsetX||this.perFrame.lastOffsets.y!==this.DM.data.offsetY)&&this.refresh(),this.animationId=requestAnimationFrame(this.draw)};refresh=()=>{this.perFrame={lastOffsets:{x:this.DM.data.offsetX,y:this.DM.data.offsetY},lastScale:this.DM.data.scale},this.onRefresh()};onResizeCallback=()=>{this.resizeAnimationId=requestAnimationFrame(()=>{let e=this.DM.middleViewer();this.lastResizeCenter.x&&this.lastResizeCenter.y&&(this.DM.data.offsetX=this.DM.data.offsetX+e.x-this.lastResizeCenter.x,this.DM.data.offsetY=this.DM.data.offsetY+e.y-this.lastResizeCenter.y),this.lastResizeCenter.x=e.x,this.lastResizeCenter.y=e.y,this.onResize(e.width,e.height),this.refresh()})};dispose=()=>{this.animationId&&cancelAnimationFrame(this.animationId),this.resizeAnimationId&&cancelAnimationFrame(this.resizeAnimationId),this.resizeObserver.disconnect()}};export{i as default};
2
+ //# sourceMappingURL=Controller.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Controller.js","sources":["../../src/kernel/Controller.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport { type BaseArgs, BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport StyleManager from '$/StyleManager';\nimport utilities from '$/utilities';\n\ninterface Augmentation {\n\trefresh: Controller['refresh'];\n\tonRefresh: Controller['onRefresh'];\n\tonResize: Controller['onResize'];\n}\n\nexport default class Controller extends BaseModule<BaseOptions, Augmentation> {\n\tprivate animationId: null | number = null;\n\tprivate resizeAnimationId: null | number = null;\n\tprivate DM: DataManager;\n\tprivate SM: StyleManager;\n\tprivate resizeObserver: ResizeObserver;\n\tprivate perFrame: {\n\t\tlastScale: number;\n\t\tlastOffsets: { x: number; y: number };\n\t} = {\n\t\tlastScale: 1,\n\t\tlastOffsets: { x: 0, y: 0 },\n\t};\n\tprivate lastResizeCenter: {\n\t\tx: null | number;\n\t\ty: null | number;\n\t} = {\n\t\tx: null,\n\t\ty: null,\n\t};\n\n\tonResize = utilities.makeHook<[number, number]>();\n\tonRefresh = utilities.makeHook();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tthis.resizeObserver = new ResizeObserver(this.onResizeCallback);\n\t\tthis.SM.onChangeTheme.subscribe(this.refresh);\n\t\tthis.augment({\n\t\t\trefresh: this.refresh,\n\t\t\tonRefresh: this.onRefresh,\n\t\t\tonResize: this.onResize,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.refresh);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate start = () => {\n\t\tthis.resizeObserver.observe(this.DM.data.container);\n\t\tthis.animationId = requestAnimationFrame(this.draw);\n\t};\n\n\tprivate draw = () => {\n\t\tif (\n\t\t\tthis.perFrame.lastScale !== this.DM.data.scale ||\n\t\t\tthis.perFrame.lastOffsets.x !== this.DM.data.offsetX ||\n\t\t\tthis.perFrame.lastOffsets.y !== this.DM.data.offsetY\n\t\t)\n\t\t\tthis.refresh();\n\t\tthis.animationId = requestAnimationFrame(this.draw);\n\t};\n\n\trefresh = () => {\n\t\tthis.perFrame = {\n\t\t\tlastScale: this.DM.data.scale,\n\t\t\tlastOffsets: { x: this.DM.data.offsetX, y: this.DM.data.offsetY },\n\t\t};\n\t\tthis.onRefresh();\n\t};\n\n\tprivate onResizeCallback = () => {\n\t\tthis.resizeAnimationId = requestAnimationFrame(() => {\n\t\t\tconst center = this.DM.middleViewer();\n\t\t\tif (this.lastResizeCenter.x && this.lastResizeCenter.y) {\n\t\t\t\tthis.DM.data.offsetX = this.DM.data.offsetX + center.x - this.lastResizeCenter.x;\n\t\t\t\tthis.DM.data.offsetY = this.DM.data.offsetY + center.y - this.lastResizeCenter.y;\n\t\t\t}\n\t\t\tthis.lastResizeCenter.x = center.x;\n\t\t\tthis.lastResizeCenter.y = center.y;\n\t\t\tthis.onResize(center.width, center.height);\n\t\t\tthis.refresh();\n\t\t});\n\t};\n\n\tprivate dispose = () => {\n\t\tif (this.animationId) cancelAnimationFrame(this.animationId);\n\t\tif (this.resizeAnimationId) cancelAnimationFrame(this.resizeAnimationId);\n\t\tthis.resizeObserver.disconnect();\n\t};\n}\n"],"names":["Controller","BaseModule","animationId","resizeAnimationId","DM","SM","resizeObserver","perFrame","lastScale","lastOffsets","x","y","lastResizeCenter","onResize","utilities","makeHook","onRefresh","constructor","args","super","this","container","get","DataManager","StyleManager","ResizeObserver","onResizeCallback","onChangeTheme","subscribe","refresh","augment","onStart","start","onRestart","onDispose","dispose","observe","data","requestAnimationFrame","draw","scale","offsetX","offsetY","center","middleViewer","width","height","cancelAnimationFrame","disconnect"],"mappings":"4IAYA,MAAqBA,UAAmBC,EAC/BC,YAA6B,KAC7BC,kBAAmC,KACnCC,GACAC,GACAC,eACAC,SAGJ,CACHC,UAAW,EACXC,YAAa,CAAEC,EAAG,EAAGC,EAAG,IAEjBC,iBAGJ,CACHF,EAAG,KACHC,EAAG,MAGJE,SAAWC,EAAUC,WACrBC,UAAYF,EAAUC,WAEtB,WAAAE,IAAeC,GACdC,SAASD,GACTE,KAAKhB,GAAKgB,KAAKC,UAAUC,IAAIC,GAC7BH,KAAKf,GAAKe,KAAKC,UAAUC,IAAIE,GAC7BJ,KAAKd,eAAiB,IAAImB,eAAeL,KAAKM,kBAC9CN,KAAKf,GAAGsB,cAAcC,UAAUR,KAAKS,SACrCT,KAAKU,QAAQ,CACZD,QAAST,KAAKS,QACdb,UAAWI,KAAKJ,UAChBH,SAAUO,KAAKP,WAEhBO,KAAKW,QAAQX,KAAKY,OAClBZ,KAAKa,UAAUb,KAAKS,SACpBT,KAAKc,UAAUd,KAAKe,QACrB,CAEQH,MAAQ,KACfZ,KAAKd,eAAe8B,QAAQhB,KAAKhB,GAAGiC,KAAKhB,WACzCD,KAAKlB,YAAcoC,sBAAsBlB,KAAKmB,OAGvCA,KAAO,KAEbnB,KAAKb,SAASC,YAAcY,KAAKhB,GAAGiC,KAAKG,OACzCpB,KAAKb,SAASE,YAAYC,IAAMU,KAAKhB,GAAGiC,KAAKI,SAC7CrB,KAAKb,SAASE,YAAYE,IAAMS,KAAKhB,GAAGiC,KAAKK,SAE7CtB,KAAKS,UACNT,KAAKlB,YAAcoC,sBAAsBlB,KAAKmB,OAG/CV,QAAU,KACTT,KAAKb,SAAW,CACfC,UAAWY,KAAKhB,GAAGiC,KAAKG,MACxB/B,YAAa,CAAEC,EAAGU,KAAKhB,GAAGiC,KAAKI,QAAS9B,EAAGS,KAAKhB,GAAGiC,KAAKK,UAEzDtB,KAAKJ,aAGEU,iBAAmB,KAC1BN,KAAKjB,kBAAoBmC,sBAAsB,KAC9C,MAAMK,EAASvB,KAAKhB,GAAGwC,eACnBxB,KAAKR,iBAAiBF,GAAKU,KAAKR,iBAAiBD,IACpDS,KAAKhB,GAAGiC,KAAKI,QAAUrB,KAAKhB,GAAGiC,KAAKI,QAAUE,EAAOjC,EAAIU,KAAKR,iBAAiBF,EAC/EU,KAAKhB,GAAGiC,KAAKK,QAAUtB,KAAKhB,GAAGiC,KAAKK,QAAUC,EAAOhC,EAAIS,KAAKR,iBAAiBD,GAEhFS,KAAKR,iBAAiBF,EAAIiC,EAAOjC,EACjCU,KAAKR,iBAAiBD,EAAIgC,EAAOhC,EACjCS,KAAKP,SAAS8B,EAAOE,MAAOF,EAAOG,QACnC1B,KAAKS,aAICM,QAAU,KACbf,KAAKlB,aAAa6C,qBAAqB3B,KAAKlB,aAC5CkB,KAAKjB,mBAAmB4C,qBAAqB3B,KAAKjB,mBACtDiB,KAAKd,eAAe0C"}
1
+ {"version":3,"file":"Controller.js","names":[],"sources":["../../src/kernel/Controller.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport { BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport StyleManager from '$/StyleManager';\nimport { makeHook } from '$/utilities';\n\ntype Augmentation = {\n\trefresh: Controller['refresh'];\n\tonRefresh: Controller['onRefresh'];\n\tonResize: Controller['onResize'];\n};\n\nexport default class Controller extends BaseModule<BaseOptions, Augmentation> {\n\tprivate animationId: undefined | number;\n\tprivate resizeAnimationId: undefined | number;\n\tprivate readonly DM: DataManager;\n\tprivate readonly SM: StyleManager;\n\tprivate readonly resizeObserver: ResizeObserver;\n\tprivate perFrame: {\n\t\tlastScale: number;\n\t\tlastOffsets: { x: number; y: number };\n\t} = {\n\t\tlastOffsets: { x: 0, y: 0 },\n\t\tlastScale: 1,\n\t};\n\tprivate readonly lastResizeCenter: {\n\t\tx: undefined | number;\n\t\ty: undefined | number;\n\t} = {\n\t\tx: undefined,\n\t\ty: undefined,\n\t};\n\n\tonResize = makeHook<[number, number]>();\n\tonRefresh = makeHook();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tthis.SM = this.container.get(StyleManager);\n\t\tthis.resizeObserver = new ResizeObserver(this.onResizeCallback);\n\t\tthis.SM.onChangeTheme.subscribe(this.refresh);\n\t\tthis.augment({\n\t\t\tonRefresh: this.onRefresh,\n\t\t\tonResize: this.onResize,\n\t\t\trefresh: this.refresh,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.refresh);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tthis.resizeObserver.observe(this.DM.data.container);\n\t\tthis.animationId = requestAnimationFrame(this.draw);\n\t};\n\n\tprivate readonly draw = () => {\n\t\tif (\n\t\t\tthis.perFrame.lastScale !== this.DM.data.scale ||\n\t\t\tthis.perFrame.lastOffsets.x !== this.DM.data.offsetX ||\n\t\t\tthis.perFrame.lastOffsets.y !== this.DM.data.offsetY\n\t\t)\n\t\t\tthis.refresh();\n\t\tthis.animationId = requestAnimationFrame(this.draw);\n\t};\n\n\trefresh = () => {\n\t\tthis.perFrame = {\n\t\t\tlastOffsets: { x: this.DM.data.offsetX, y: this.DM.data.offsetY },\n\t\t\tlastScale: this.DM.data.scale,\n\t\t};\n\t\tthis.onRefresh();\n\t};\n\n\tprivate readonly onResizeCallback = () => {\n\t\tthis.resizeAnimationId = requestAnimationFrame(() => {\n\t\t\tconst center = this.DM.middleViewer();\n\t\t\tif (this.lastResizeCenter.x && this.lastResizeCenter.y) {\n\t\t\t\tthis.DM.data.offsetX = this.DM.data.offsetX + center.x - this.lastResizeCenter.x;\n\t\t\t\tthis.DM.data.offsetY = this.DM.data.offsetY + center.y - this.lastResizeCenter.y;\n\t\t\t}\n\t\t\tthis.lastResizeCenter.x = center.x;\n\t\t\tthis.lastResizeCenter.y = center.y;\n\t\t\tthis.onResize(center.width, center.height);\n\t\t\tthis.refresh();\n\t\t});\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tif (this.animationId) cancelAnimationFrame(this.animationId);\n\t\tif (this.resizeAnimationId) cancelAnimationFrame(this.resizeAnimationId);\n\t\tthis.resizeObserver.disconnect();\n\t};\n}\n"],"mappings":"wJAaA,IAAqB,EAArB,cAAwC,CAAsC,CAC7E,YACA,kBACA,GACA,GACA,eACA,SAGI,CACH,YAAa,CAAE,EAAG,EAAG,EAAG,EAAG,CAC3B,UAAW,EACX,CACD,iBAGI,CACH,EAAG,IAAA,GACH,EAAG,IAAA,GACH,CAED,SAAW,GAA4B,CACvC,UAAY,GAAU,CAEtB,YAAY,GAAG,EAAgB,CAC9B,MAAM,GAAG,EAAK,CACd,KAAK,GAAK,KAAK,UAAU,IAAI,EAAY,CACzC,KAAK,GAAK,KAAK,UAAU,IAAI,EAAa,CAC1C,KAAK,eAAiB,IAAI,eAAe,KAAK,iBAAiB,CAC/D,KAAK,GAAG,cAAc,UAAU,KAAK,QAAQ,CAC7C,KAAK,QAAQ,CACZ,UAAW,KAAK,UAChB,SAAU,KAAK,SACf,QAAS,KAAK,QACd,CAAC,CACF,KAAK,QAAQ,KAAK,MAAM,CACxB,KAAK,UAAU,KAAK,QAAQ,CAC5B,KAAK,UAAU,KAAK,QAAQ,CAG7B,UAA+B,CAC9B,KAAK,eAAe,QAAQ,KAAK,GAAG,KAAK,UAAU,CACnD,KAAK,YAAc,sBAAsB,KAAK,KAAK,EAGpD,SAA8B,EAE5B,KAAK,SAAS,YAAc,KAAK,GAAG,KAAK,OACzC,KAAK,SAAS,YAAY,IAAM,KAAK,GAAG,KAAK,SAC7C,KAAK,SAAS,YAAY,IAAM,KAAK,GAAG,KAAK,UAE7C,KAAK,SAAS,CACf,KAAK,YAAc,sBAAsB,KAAK,KAAK,EAGpD,YAAgB,CACf,KAAK,SAAW,CACf,YAAa,CAAE,EAAG,KAAK,GAAG,KAAK,QAAS,EAAG,KAAK,GAAG,KAAK,QAAS,CACjE,UAAW,KAAK,GAAG,KAAK,MACxB,CACD,KAAK,WAAW,EAGjB,qBAA0C,CACzC,KAAK,kBAAoB,0BAA4B,CACpD,IAAM,EAAS,KAAK,GAAG,cAAc,CACjC,KAAK,iBAAiB,GAAK,KAAK,iBAAiB,IACpD,KAAK,GAAG,KAAK,QAAU,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,KAAK,iBAAiB,EAC/E,KAAK,GAAG,KAAK,QAAU,KAAK,GAAG,KAAK,QAAU,EAAO,EAAI,KAAK,iBAAiB,GAEhF,KAAK,iBAAiB,EAAI,EAAO,EACjC,KAAK,iBAAiB,EAAI,EAAO,EACjC,KAAK,SAAS,EAAO,MAAO,EAAO,OAAO,CAC1C,KAAK,SAAS,EACb,EAGH,YAAiC,CAC5B,KAAK,aAAa,qBAAqB,KAAK,YAAY,CACxD,KAAK,mBAAmB,qBAAqB,KAAK,kBAAkB,CACxE,KAAK,eAAe,YAAY"}
@@ -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
+ type Options = {
9
+ shadowed?: boolean;
10
+ canvas?: JSONCanvas;
11
+ attachmentDir?: string;
12
+ extraCSS?: string;
13
+ attachments?: Record<string, string>;
14
+ noAttachmentRelocation?: boolean;
15
+ } & BaseOptions;
16
+ type Augmentation = {
17
+ resetView: DataManager['resetView'];
18
+ toggleFullscreen: DataManager['toggleFullscreen'];
19
+ onToggleFullscreen: DataManager['onToggleFullscreen'];
20
+ };
21
+ type NodeItem = {
22
+ ref: JSONCanvasNode;
23
+ box: Box;
24
+ fileName?: string;
25
+ onBeforeUnmount?: Hook;
26
+ onActive?: Hook;
27
+ onLoseActive?: Hook;
28
+ };
29
+ type 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 readonly start;
51
+ private readonly processBaseDir;
52
+ private readonly getNodeBox;
53
+ private readonly getEdgeBox;
54
+ private calculateNodeBounds;
55
+ toggleFullscreen: (option?: "enter" | "exit") => Promise<void>;
56
+ resetView: () => void;
57
+ middleViewer: () => {
58
+ height: number;
59
+ width: number;
60
+ x: number;
61
+ y: number;
62
+ };
63
+ private readonly dispose;
64
+ }
65
+ //#endregion
66
+ export { DataManager };
67
+ //# sourceMappingURL=DataManager.d.ts.map
@@ -1,2 +1,2 @@
1
- import{BaseModule as t}from"./BaseModule.js";import e from"./styles.scss.js";import s from"./utilities.js";class a extends t{onToggleFullscreen=s.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(...t){super(...t);const a=this.options.container;for(;a.firstElementChild;)a.firstElementChild.remove();a.innerHTML="";const i=this.options.shadowed?a.attachShadow({mode:"open"}):a;s.applyStyles(i,e+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=()=>{const t=Object.assign({nodes:[],edges:[]},this.options.canvas);Object.assign(this.data,{canvasData:t,nodeMap:{},edgeMap:{},canvasBaseDir:this.processBaseDir(this.options.attachmentDir),nodeBounds:this.calculateNodeBounds(t),offsetX:0,offsetY:0,scale:1}),this.data.canvasData.nodes.forEach(t=>{const e={ref:t,box:this.getNodeBox(t)};if(this.data.nodeMap[t.id]=e,"file"===t.type){const s=t.file.split("/").pop()??"";if(e.fileName=s,!t.file.startsWith("http://")&&!t.file.startsWith("https://")){const e=this.options.attachments?.[s];e?t.file=e:this.options.noAttachmentRelocation||(t.file=this.data.canvasBaseDir+s)}}}),this.data.canvasData.edges.forEach(t=>{this.data.edgeMap[t.id]={ref:t,box:this.getEdgeBox(t)}}),this.resetView()};processBaseDir=t=>{if(!t)return"./";const e=t?.slice(-1);return"/"===e?t:`${t}/`};getNodeBox=t=>({left:t.x,top:"file"===t.type||"group"===t.type?t.y-40:t.y,right:t.width+t.x,bottom:t.y+t.height});getEdgeBox=t=>{const e=this.data.nodeMap,a=e[t.fromNode].ref,i=e[t.toNode].ref,o=s.getAnchorCoord(a,t.fromSide),n=s.getAnchorCoord(i,t.toSide),h=Math.min(o.x,n.x),r=Math.min(o.y,n.y),c=Math.max(o.x,n.x),d=Math.max(o.y,n.y),l=c-h,f=d-r,m=Math.min(l,f),g=0===m?1:m,p=Math.max(l,f),u=10*Math.log2(p/g);return{left:h-u,top:r-u,right:c+u,bottom:d+u}};calculateNodeBounds(t){let e=1/0,s=1/0,a=-1/0,i=-1/0;t.nodes.forEach(t=>{e=Math.min(e,t.x),s=Math.min(s,t.y),a=Math.max(a,t.x+t.width),i=Math.max(i,t.y+t.height)});const o=a-e,n=i-s;return{minX:e,minY:s,maxX:a,maxY:i,width:o,height:n,centerX:e+o/2,centerY:s+n/2}}toggleFullscreen=async t=>{document.fullscreenElement||t&&"enter"!==t?!document.fullscreenElement||t&&"exit"!==t||(await document.exitFullscreen(),this.onToggleFullscreen("exit")):(await this.data.container.requestFullscreen(),this.onToggleFullscreen("enter"))};resetView=()=>{const t=this.data.nodeBounds,e=this.data.container;if(!t||!e)return;const s=t.width+200,a=t.height+200,i=e.clientWidth,o=e.clientHeight,n=i/s,h=o/a,r=Math.round(1e3*Math.min(n,h))/1e3,c={scale:r,offsetX:i/2-t.centerX*r,offsetY:o/2-t.centerY*r};this.data.offsetX=c.offsetX,this.data.offsetY=c.offsetY,this.data.scale=c.scale};middleViewer=()=>{const t=this.data.container;return{x:t.clientWidth/2,y:t.clientHeight/2,width:t.clientWidth,height:t.clientHeight}};dispose=()=>{this.data.container.remove()}}export{a as default};
2
- //# sourceMappingURL=DataManager.js.map
1
+ import{BaseModule as e}from"./BaseModule.js";import t from"./styles.js";import{applyStyles as n,getAnchorCoord as r,makeHook as i}from"./utilities.js";var a=class extends e{onToggleFullscreen=i();data={canvasBaseDir:`./`,canvasData:{edges:[],nodes:[]},container:document.createElement(`div`),edgeMap:{},nodeBounds:{centerX:0,centerY:0,height:0,maxX:0,maxY:0,minX:0,minY:0,width:0},nodeMap:{},offsetX:0,offsetY:0,scale:1};constructor(...e){super(...e);let r=this.options.container;for(;r.firstElementChild;)r.firstElementChild.remove();r.innerHTML=``;let i=this.options.shadowed?r.attachShadow({mode:`open`}):r;n(i,t+this.options.extraCSS),this.data.container.classList.add(`JSON-Canvas-Viewer`),i.appendChild(this.data.container),this.augment({onToggleFullscreen:this.onToggleFullscreen,resetView:this.resetView,toggleFullscreen:this.toggleFullscreen}),this.onStart(this.start),this.onRestart(this.start),this.onDispose(this.dispose)}start=()=>{let e={edges:[],nodes:[],...this.options.canvas};Object.assign(this.data,{canvasBaseDir:this.processBaseDir(this.options.attachmentDir),canvasData:e,edgeMap:{},nodeBounds:this.calculateNodeBounds(e),nodeMap:{},offsetX:0,offsetY:0,scale:1}),this.data.canvasData.nodes.forEach(e=>{let t={box:this.getNodeBox(e),ref:e};if(this.data.nodeMap[e.id]=t,e.type===`file`){let n=e.file.split(`/`).pop()??``;if(t.fileName=n,!e.file.startsWith(`http://`)&&!e.file.startsWith(`https://`)){let t=this.options.attachments?.[n];t?e.file=t:this.options.noAttachmentRelocation||(e.file=this.data.canvasBaseDir+n)}}}),this.data.canvasData.edges.forEach(e=>{this.data.edgeMap[e.id]={box:this.getEdgeBox(e),ref:e}}),this.resetView()};processBaseDir=e=>e?e?.slice(-1)===`/`?e:`${e}/`:`./`;getNodeBox=e=>({bottom:e.y+e.height,left:e.x,right:e.width+e.x,top:e.type===`file`||e.type===`group`?e.y-40:e.y});getEdgeBox=e=>{let t=this.data.nodeMap,n=t[e.fromNode].ref,i=t[e.toNode].ref,a=r(n,e.fromSide),o=r(i,e.toSide),s={bottom:Math.max(a.y,o.y),left:Math.min(a.x,o.x),right:Math.max(a.x,o.x),top:Math.min(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{bottom:s.bottom+d,left:s.left-d,right:s.right+d,top:s.top-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;return{centerX:t+a/2,centerY:n+o/2,height:o,maxX:r,maxY:i,minX:t,minY:n,width:a}}toggleFullscreen=async e=>{!document.fullscreenElement&&(!e||e===`enter`)?(await this.data.container.requestFullscreen(),this.onToggleFullscreen(`enter`)):document.fullscreenElement&&(!e||e===`exit`)&&(await document.exitFullscreen(),this.onToggleFullscreen(`exit`))};resetView=()=>{let e=this.data.nodeBounds,t=this.data.container;if(!e||!t)return;let n=e.width+200,r=e.height+200,i=t.clientWidth,a=t.clientHeight,o=i/n,s=a/r,c=Math.round(Math.min(o,s)*1e3)/1e3,l=e.centerX,u=e.centerY,d={offsetX:i/2-l*c,offsetY:a/2-u*c,scale:c};this.data.offsetX=d.offsetX,this.data.offsetY=d.offsetY,this.data.scale=d.scale};middleViewer=()=>{let e=this.data.container;return{height:e.clientHeight,width:e.clientWidth,x:e.clientWidth/2,y:e.clientHeight/2}};dispose=()=>{this.data.container.remove()}};export{a as default};
2
+ //# sourceMappingURL=DataManager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataManager.js","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"],"names":["DataManager","BaseModule","onToggleFullscreen","utilities","makeHook","data","canvasData","nodes","edges","nodeMap","edgeMap","canvasBaseDir","nodeBounds","maxX","maxY","minX","minY","width","height","centerX","centerY","offsetX","offsetY","scale","container","document","createElement","constructor","args","super","viewerContainer","this","options","firstElementChild","remove","innerHTML","realContainer","shadowed","attachShadow","mode","applyStyles","style","extraCSS","classList","add","appendChild","augment","resetView","toggleFullscreen","onStart","start","onRestart","onDispose","dispose","Object","assign","canvas","processBaseDir","attachmentDir","calculateNodeBounds","forEach","node","item","ref","box","getNodeBox","id","type","fileName","file","split","pop","startsWith","userDefinedAttachment","attachments","noAttachmentRelocation","edge","getEdgeBox","baseDir","lastChar","slice","left","x","top","y","right","bottom","from","fromNode","to","toNode","fromAnchor","getAnchorCoord","fromSide","toAnchor","toSide","strictBox","Math","min","max","_min","margin","log2","Infinity","async","option","fullscreenElement","exitFullscreen","requestFullscreen","bounds","contentWidth","INITIAL_VIEWPORT_PADDING","contentHeight","viewWidth","clientWidth","viewHeight","clientHeight","scaleX","scaleY","newScale","round","initialView","middleViewer"],"mappings":"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"}
1
+ {"version":3,"file":"DataManager.js","names":["style"],"sources":["../../src/kernel/DataManager.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { Box, NodeBounds } from '$/types';\nimport type { Hook } from '$/utilities';\nimport type { JSONCanvas, JSONCanvasEdge, JSONCanvasNode } from '@repo/shared';\nimport { BaseModule } from '$/BaseModule';\nimport style from '$/styles.scss?inline';\nimport { applyStyles, getAnchorCoord, makeHook } from '$/utilities';\n\nconst INITIAL_VIEWPORT_PADDING = 100;\nconst NODE_LABEL_MARGIN = 40;\nconst EDGE_BOX_HEURISTICS_BASE_MARGIN = 10;\n\ntype Options = {\n\tshadowed?: boolean;\n\tcanvas?: JSONCanvas;\n\tattachmentDir?: string;\n\textraCSS?: string;\n\tattachments?: Record<string, string>;\n\tnoAttachmentRelocation?: boolean;\n} & BaseOptions;\n\ntype Augmentation = {\n\tresetView: DataManager['resetView'];\n\ttoggleFullscreen: DataManager['toggleFullscreen'];\n\tonToggleFullscreen: DataManager['onToggleFullscreen'];\n};\n\nexport type NodeItem = {\n\tref: JSONCanvasNode;\n\tbox: Box;\n\tfileName?: string;\n\tonBeforeUnmount?: Hook;\n\tonActive?: Hook;\n\tonLoseActive?: Hook;\n};\n\nexport type EdgeItem = {\n\tref: JSONCanvasEdge;\n\tbox: Box;\n\tcontrolPoints?: Array<number>;\n};\n\ntype NodeMap = Record<string, NodeItem>;\ntype EdgeMap = Record<string, EdgeItem>;\n\nexport default class DataManager extends BaseModule<Options, Augmentation> {\n\tonToggleFullscreen = makeHook<['enter' | 'exit']>();\n\n\tdata: {\n\t\tcanvasData: Required<JSONCanvas>;\n\t\tnodeMap: NodeMap;\n\t\tedgeMap: EdgeMap;\n\t\tcanvasBaseDir: string;\n\t\tnodeBounds: NodeBounds;\n\t\toffsetX: number;\n\t\toffsetY: number;\n\t\tscale: number;\n\t\tcontainer: HTMLDivElement;\n\t} = {\n\t\tcanvasBaseDir: './',\n\t\tcanvasData: {\n\t\t\tedges: [],\n\t\t\tnodes: [],\n\t\t},\n\t\tcontainer: document.createElement('div'),\n\t\tedgeMap: {},\n\t\tnodeBounds: {\n\t\t\tcenterX: 0,\n\t\t\tcenterY: 0,\n\t\t\theight: 0,\n\t\t\tmaxX: 0,\n\t\t\tmaxY: 0,\n\t\t\tminX: 0,\n\t\t\tminY: 0,\n\t\t\twidth: 0,\n\t\t},\n\t\tnodeMap: {},\n\t\toffsetX: 0,\n\t\toffsetY: 0,\n\t\tscale: 1,\n\t};\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tconst viewerContainer = this.options.container;\n\t\twhile (viewerContainer.firstElementChild) viewerContainer.firstElementChild.remove();\n\t\tviewerContainer.innerHTML = '';\n\n\t\tconst realContainer = this.options.shadowed\n\t\t\t? viewerContainer.attachShadow({ mode: 'open' })\n\t\t\t: viewerContainer;\n\n\t\tapplyStyles(realContainer, style + this.options.extraCSS);\n\n\t\tthis.data.container.classList.add('JSON-Canvas-Viewer');\n\t\trealContainer.appendChild(this.data.container);\n\n\t\tthis.augment({\n\t\t\tonToggleFullscreen: this.onToggleFullscreen,\n\t\t\tresetView: this.resetView,\n\t\t\ttoggleFullscreen: this.toggleFullscreen,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onRestart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tconst canvasData = {\n\t\t\tedges: [],\n\t\t\tnodes: [],\n\t\t\t...this.options.canvas,\n\t\t};\n\n\t\tObject.assign(this.data, {\n\t\t\tcanvasBaseDir: this.processBaseDir(this.options.attachmentDir),\n\t\t\tcanvasData,\n\t\t\tedgeMap: {},\n\t\t\tnodeBounds: this.calculateNodeBounds(canvasData),\n\t\t\tnodeMap: {},\n\t\t\toffsetX: 0,\n\t\t\toffsetY: 0,\n\t\t\tscale: 1,\n\t\t});\n\n\t\tthis.data.canvasData.nodes.forEach((node) => {\n\t\t\tconst item: NodeItem = {\n\t\t\t\tbox: this.getNodeBox(node),\n\t\t\t\tref: node,\n\t\t\t};\n\t\t\tthis.data.nodeMap[node.id] = item;\n\n\t\t\t// Re-process attachments\n\t\t\tif (node.type === 'file') {\n\t\t\t\tconst path = node.file.split('/');\n\t\t\t\tconst fileName = path.pop() ?? '';\n\t\t\t\titem.fileName = fileName;\n\t\t\t\tif (!node.file.startsWith('http://') && !node.file.startsWith('https://')) {\n\t\t\t\t\tconst userDefinedAttachment = this.options.attachments?.[fileName];\n\t\t\t\t\tif (userDefinedAttachment) node.file = userDefinedAttachment;\n\t\t\t\t\telse if (!this.options.noAttachmentRelocation)\n\t\t\t\t\t\tnode.file = this.data.canvasBaseDir + fileName;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis.data.canvasData.edges.forEach((edge) => {\n\t\t\tthis.data.edgeMap[edge.id] = {\n\t\t\t\tbox: this.getEdgeBox(edge),\n\t\t\t\tref: edge,\n\t\t\t};\n\t\t});\n\t\tthis.resetView();\n\t};\n\n\tprivate readonly processBaseDir = (baseDir: string | undefined) => {\n\t\tif (!baseDir) return './';\n\t\tconst lastChar = baseDir?.slice(-1);\n\t\tif (lastChar === '/') return baseDir;\n\t\treturn `${baseDir}/`;\n\t};\n\n\tprivate readonly getNodeBox = (node: JSONCanvasNode) => ({\n\t\tbottom: node.y + node.height,\n\t\tleft: node.x,\n\t\tright: node.width + node.x,\n\t\ttop: node.type === 'file' || node.type === 'group' ? node.y - NODE_LABEL_MARGIN : node.y,\n\t});\n\n\tprivate readonly getEdgeBox = (edge: JSONCanvasEdge) => {\n\t\tconst nodes = this.data.nodeMap;\n\t\tconst from = nodes[edge.fromNode].ref;\n\t\tconst to = nodes[edge.toNode].ref;\n\t\tconst fromAnchor = getAnchorCoord(from, edge.fromSide);\n\t\tconst toAnchor = getAnchorCoord(to, edge.toSide);\n\t\tconst strictBox = {\n\t\t\tbottom: Math.max(fromAnchor.y, toAnchor.y),\n\t\t\tleft: Math.min(fromAnchor.x, toAnchor.x),\n\t\t\tright: Math.max(fromAnchor.x, toAnchor.x),\n\t\t\ttop: Math.min(fromAnchor.y, toAnchor.y),\n\t\t};\n\t\t// Edge size heuristics\n\t\tconst width = strictBox.right - strictBox.left;\n\t\tconst height = strictBox.bottom - strictBox.top;\n\t\tconst _min = Math.min(width, height);\n\t\tconst min = _min === 0 ? 1 : _min;\n\t\tconst max = Math.max(width, height);\n\t\tconst edgeFactor = Math.log2(max / min);\n\t\tconst margin = edgeFactor * EDGE_BOX_HEURISTICS_BASE_MARGIN;\n\t\treturn {\n\t\t\tbottom: strictBox.bottom + margin,\n\t\t\tleft: strictBox.left - margin,\n\t\t\tright: strictBox.right + margin,\n\t\t\ttop: strictBox.top - margin,\n\t\t};\n\t};\n\n\tprivate calculateNodeBounds(canvasData: Required<JSONCanvas>) {\n\t\tlet minX = Infinity,\n\t\t\tminY = Infinity,\n\t\t\tmaxX = -Infinity,\n\t\t\tmaxY = -Infinity;\n\t\tcanvasData.nodes.forEach((node) => {\n\t\t\tminX = Math.min(minX, node.x);\n\t\t\tminY = Math.min(minY, node.y);\n\t\t\tmaxX = Math.max(maxX, node.x + node.width);\n\t\t\tmaxY = Math.max(maxY, node.y + node.height);\n\t\t});\n\t\tconst width = maxX - minX;\n\t\tconst height = maxY - minY;\n\t\tconst centerX = minX + width / 2;\n\t\tconst centerY = minY + height / 2;\n\t\treturn { centerX, centerY, height, maxX, maxY, minX, minY, width };\n\t}\n\ttoggleFullscreen = async (option?: 'enter' | 'exit') => {\n\t\tif (!document.fullscreenElement && (!option || option === 'enter')) {\n\t\t\tawait this.data.container.requestFullscreen();\n\t\t\tthis.onToggleFullscreen('enter');\n\t\t} else if (document.fullscreenElement && (!option || option === 'exit')) {\n\t\t\tawait document.exitFullscreen();\n\t\t\tthis.onToggleFullscreen('exit');\n\t\t}\n\t};\n\tresetView = () => {\n\t\tconst bounds = this.data.nodeBounds;\n\t\tconst container = this.data.container;\n\t\tif (!bounds || !container) return;\n\t\tconst contentWidth = bounds.width + INITIAL_VIEWPORT_PADDING * 2;\n\t\tconst contentHeight = bounds.height + INITIAL_VIEWPORT_PADDING * 2;\n\t\t// Use logical dimensions for scaling calculations\n\t\tconst viewWidth = container.clientWidth;\n\t\tconst viewHeight = container.clientHeight;\n\t\tconst scaleX = viewWidth / contentWidth;\n\t\tconst scaleY = viewHeight / contentHeight;\n\t\tconst newScale = Math.round(Math.min(scaleX, scaleY) * 1000) / 1000;\n\t\tconst contentCenterX = bounds.centerX;\n\t\tconst contentCenterY = bounds.centerY;\n\t\tconst initialView = {\n\t\t\toffsetX: viewWidth / 2 - contentCenterX * newScale,\n\t\t\toffsetY: viewHeight / 2 - contentCenterY * newScale,\n\t\t\tscale: newScale,\n\t\t};\n\t\tthis.data.offsetX = initialView.offsetX;\n\t\tthis.data.offsetY = initialView.offsetY;\n\t\tthis.data.scale = initialView.scale;\n\t};\n\n\tmiddleViewer = () => {\n\t\tconst container = this.data.container;\n\t\treturn {\n\t\t\theight: container.clientHeight,\n\t\t\twidth: container.clientWidth,\n\t\t\tx: container.clientWidth / 2,\n\t\t\ty: container.clientHeight / 2,\n\t\t};\n\t};\n\n\tprivate readonly dispose = () => {\n\t\tthis.data.container.remove();\n\t};\n}\n"],"mappings":"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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
+ type Options$1 = {
10
+ pointeract?: Options<LoadedModules>;
11
+ } & BaseOptions;
12
+ type 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 readonly DM;
21
+ onClick: Hook<[string | undefined], false>;
22
+ constructor(...args: BaseArgs);
23
+ private readonly start;
24
+ private readonly startInteract;
25
+ private readonly stopInteract;
26
+ private readonly onPan;
27
+ private readonly 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 readonly C2C;
44
+ private readonly onTrueClick;
45
+ private readonly isUIControl;
46
+ private readonly findNodeId;
47
+ private readonly dispose;
48
+ }
49
+ //#endregion
50
+ export { InteractionHandler };
51
+ //# sourceMappingURL=InteractionHandler.d.ts.map
@@ -1,2 +1,2 @@
1
- import{BaseModule as t}from"./BaseModule.js";import o from"./DataManager.js";import s from"./OverlayManager.js";import a from"./utilities.js";import{dragPreset as i,zoomPreset as e,panPreset as n,Pointeract as r,Click as c,Drag as h,WheelPanZoom as d,PreventDefault as p,MultitouchPanZoom as l,Lubricator as f}from"pointeract";class m extends t{pointeract;DM;onClick=a.makeHook();constructor(...t){super(...t),this.DM=this.container.get(o);const a=Object.assign(this.options.pointeract??{},{coordinateOutput:"relative",element:this.DM.data.container,lubricator:{pan:n,zoom:e,drag:i}});this.pointeract=new r(a,[c,h,d,p,l,f]);const m=this.container.get(s);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=t=>{this.truePan({x:t.deltaX,y:t.deltaY})};onZoom=t=>{this.trueZoom(t.factor,t)};trueZoom=(t,o)=>{const s=Math.max(Math.min(this.DM.data.scale*t,20),.05);if(s===this.DM.data.scale)return;const a=s/this.DM.data.scale,i=this.C2C(o);this.DM.data.offsetX=o.x-i.x*a,this.DM.data.offsetY=o.y-i.y*a,this.DM.data.scale=s};truePan=({x:t,y:o})=>{this.DM.data.offsetX=this.DM.data.offsetX+t,this.DM.data.offsetY=this.DM.data.offsetY+o};zoom=(t,o)=>{this.pointeract.dispatch("zoom",{factor:t,...o})};pan=({x:t,y:o})=>{this.pointeract.dispatch("pan",{deltaX:t,deltaY:o})};zoomToScale=(t,o)=>{const s=t/this.DM.data.scale;this.pointeract.dispatch("zoom",{factor:s,...o})};panToCoords=({x:t,y:o})=>{this.pointeract.dispatch("pan",{deltaX:t-this.DM.data.offsetX,deltaY:o-this.DM.data.offsetY})};C2C=({x:t,y:o})=>({x:t-this.DM.data.offsetX,y:o-this.DM.data.offsetY});onTrueClick=t=>{const o=t.target;if(this.isUIControl(o))return;const s=this.findNodeId(o);this.onClick(s)};isUIControl=t=>!!t&&(t.closest(".controls")||t.closest("button")||t.closest("input"));findNodeId=t=>{if(!t)return null;let o=t;for(;(!o.id||""===o.id)&&o.parentElement;)o=o.parentElement;return"overlays"!==o.id&&o.id&&""!==o.id?o.id:null};dispose=()=>this.pointeract.dispose()}export{m as default};
2
- //# sourceMappingURL=InteractionHandler.js.map
1
+ import{BaseModule as e}from"./BaseModule.js";import{makeHook as t}from"./utilities.js";import n from"./DataManager.js";import r from"./OverlayManager.js";import{Click as i,Drag as a,Lubricator as o,MultitouchPanZoom as s,Pointeract as c,PreventDefault as l,WheelPanZoom as u,lubricatorDragPreset as d,lubricatorPanPreset as f,lubricatorZoomPreset as p}from"pointeract";var m=class extends e{pointeract;DM;onClick=t();constructor(...e){super(...e),this.DM=this.container.get(n);let t=Object.assign(this.options.pointeract??{},{coordinateOutput:`relative`,element:this.DM.data.container,lubricator:{drag:d,pan:f,zoom:p}});this.pointeract=new c(t,[i,a,u,l,s,o]);let m=this.container.get(r);m.onInteractionStart.subscribe(this.stopInteract),m.onInteractionEnd.subscribe(this.startInteract),this.augment({pan:this.pan,panToCoords:this.panToCoords,zoom:this.zoom,zoomToScale:this.zoomToScale}),this.onStart(this.start),this.onDispose(this.dispose)}start=()=>{this.pointeract.on(`pan`,this.onPan).on(`drag`,this.onPan).on(`zoom`,this.onZoom).on(`trueClick`,this.onTrueClick).start()};startInteract=()=>{this.pointeract.start()};stopInteract=()=>{this.pointeract.stop()};onPan=e=>{this.truePan({x:e.deltaX,y:e.deltaY})};onZoom=e=>{this.trueZoom(e.factor,e)};trueZoom=(e,t)=>{let n=Math.max(Math.min(this.DM.data.scale*e,20),.05);if(n===this.DM.data.scale)return;let r=n/this.DM.data.scale,i=this.C2C(t);this.DM.data.offsetX=t.x-i.x*r,this.DM.data.offsetY=t.y-i.y*r,this.DM.data.scale=n};truePan=({x:e,y:t})=>{this.DM.data.offsetX+=e,this.DM.data.offsetY+=t};zoom=(e,t)=>{this.pointeract.dispatch(`zoom`,{factor:e,...t})};pan=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e,deltaY:t})};zoomToScale=(e,t)=>{let n=e/this.DM.data.scale;this.pointeract.dispatch(`zoom`,{factor:n,...t})};panToCoords=({x:e,y:t})=>{this.pointeract.dispatch(`pan`,{deltaX:e-this.DM.data.offsetX,deltaY:t-this.DM.data.offsetY})};C2C=({x:e,y:t})=>({x:e-this.DM.data.offsetX,y:t-this.DM.data.offsetY});onTrueClick=e=>{let t=e.target;if(this.isUIControl(t))return;let n=this.findNodeId(t);this.onClick(n)};isUIControl=e=>e?e.closest(`.controls`)||e.closest(`button`)||e.closest(`input`):!1;findNodeId=e=>{if(!e)return;let t=e;for(;(!t.id||t.id===``)&&t.parentElement;)t=t.parentElement;if(!(t.id===`overlays`||!t.id||t.id===``))return t.id};dispose=()=>this.pointeract.dispose()};export{m as default};
2
+ //# sourceMappingURL=InteractionHandler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InteractionHandler.js","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\tpanPreset as pan,\n\tzoomPreset as zoom,\n\tdragPreset 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"],"names":["InteractionHandler","BaseModule","pointeract","DM","onClick","utilities","makeHook","constructor","args","super","this","container","get","DataManager","options","Object","assign","coordinateOutput","element","data","lubricator","pan","zoom","drag","Pointeract","Click","Drag","WheelPanZoom","PreventDefault","MultitouchPanZoom","Lubricator","OM","OverlayManager","onInteractionStart","subscribe","stopInteract","onInteractionEnd","startInteract","augment","panToCoords","zoomToScale","onStart","start","onDispose","dispose","on","onPan","onZoom","onTrueClick","stop","event","truePan","x","deltaX","y","deltaY","trueZoom","factor","_factor","origin","newScale","Math","max","min","scale","canvasCoords","C2C","offsetX","offsetY","dispatch","containerX","containerY","e","target","isUIControl","node","findNodeId","closest","ele","id","parentElement"],"mappings":"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"}
1
+ {"version":3,"file":"InteractionHandler.js","names":[],"sources":["../../src/kernel/InteractionHandler.ts"],"sourcesContent":["import type { BaseOptions } from '$';\nimport type { BaseArgs } from '$/BaseModule';\nimport type { Coordinates } from '$/types';\nimport type { Options as PointeractOptions, Events, PointeractInterface } from 'pointeract';\nimport { BaseModule } from '$/BaseModule';\nimport DataManager from '$/DataManager';\nimport OverlayManager from '$/OverlayManager';\nimport { makeHook } from '$/utilities';\nimport {\n\tClick,\n\tDrag,\n\tMultitouchPanZoom,\n\tPointeract,\n\tPreventDefault,\n\tWheelPanZoom,\n\tLubricator,\n\tlubricatorPanPreset as pan,\n\tlubricatorZoomPreset as zoom,\n\tlubricatorDragPreset as drag,\n} from 'pointeract';\n\ntype LoadedModules = [Click, Drag, WheelPanZoom, PreventDefault, MultitouchPanZoom, Lubricator];\n\ntype LoadedEvents = Events<LoadedModules>;\n\ntype Options = {\n\tpointeract?: PointeractOptions<LoadedModules>;\n} & BaseOptions;\n\ntype Augmentation = {\n\tpan: InteractionHandler['pan'];\n\tpanToCoords: InteractionHandler['panToCoords'];\n\tzoom: InteractionHandler['zoom'];\n\tzoomToScale: InteractionHandler['zoomToScale'];\n};\n\nexport default class InteractionHandler extends BaseModule<Options, Augmentation> {\n\tpointeract: PointeractInterface<LoadedModules>;\n\tprivate readonly DM: DataManager;\n\tonClick = makeHook<[string | undefined]>();\n\n\tconstructor(...args: BaseArgs) {\n\t\tsuper(...args);\n\t\tthis.DM = this.container.get(DataManager);\n\t\tconst options = Object.assign(this.options.pointeract ?? {}, {\n\t\t\tcoordinateOutput: 'relative',\n\t\t\telement: this.DM.data.container,\n\t\t\tlubricator: { drag, pan, zoom },\n\t\t} satisfies PointeractOptions<LoadedModules>);\n\t\tthis.pointeract = new Pointeract(options, [\n\t\t\tClick,\n\t\t\tDrag,\n\t\t\tWheelPanZoom,\n\t\t\tPreventDefault,\n\t\t\tMultitouchPanZoom,\n\t\t\tLubricator,\n\t\t]);\n\t\tconst OM = this.container.get(OverlayManager);\n\t\tOM.onInteractionStart.subscribe(this.stopInteract);\n\t\tOM.onInteractionEnd.subscribe(this.startInteract);\n\n\t\tthis.augment({\n\t\t\tpan: this.pan,\n\t\t\tpanToCoords: this.panToCoords,\n\t\t\tzoom: this.zoom,\n\t\t\tzoomToScale: this.zoomToScale,\n\t\t});\n\t\tthis.onStart(this.start);\n\t\tthis.onDispose(this.dispose);\n\t}\n\n\tprivate readonly start = () => {\n\t\tthis.pointeract\n\t\t\t.on('pan', this.onPan)\n\t\t\t.on('drag', this.onPan)\n\t\t\t.on('zoom', this.onZoom)\n\t\t\t.on('trueClick', this.onTrueClick)\n\t\t\t.start();\n\t};\n\n\tprivate readonly startInteract = () => {\n\t\tthis.pointeract.start();\n\t};\n\tprivate readonly stopInteract = () => {\n\t\tthis.pointeract.stop();\n\t};\n\n\tprivate readonly onPan = (event: LoadedEvents['pan']) => {\n\t\tthis.truePan({\n\t\t\tx: event.deltaX,\n\t\t\ty: event.deltaY,\n\t\t});\n\t};\n\tprivate readonly onZoom = (event: LoadedEvents['zoom']) => {\n\t\tthis.trueZoom(event.factor, event);\n\t};\n\n\ttrueZoom = (_factor: number, origin: Coordinates) => {\n\t\tconst newScale = Math.max(Math.min(this.DM.data.scale * _factor, 20), 0.05);\n\t\tconst scale = this.DM.data.scale;\n\t\tif (newScale === scale) return;\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tconst canvasCoords = this.C2C(origin);\n\t\tthis.DM.data.offsetX = origin.x - canvasCoords.x * factor;\n\t\tthis.DM.data.offsetY = origin.y - canvasCoords.y * factor;\n\t\tthis.DM.data.scale = newScale;\n\t};\n\ttruePan = ({ x, y }: Coordinates) => {\n\t\tthis.DM.data.offsetX += x;\n\t\tthis.DM.data.offsetY += y;\n\t};\n\n\tzoom = (_factor: number, origin: Coordinates) => {\n\t\tthis.pointeract.dispatch('zoom', { factor: _factor, ...origin });\n\t};\n\tpan = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', { deltaX: x, deltaY: y });\n\t};\n\tzoomToScale = (newScale: number, origin: Coordinates) => {\n\t\tconst factor = newScale / this.DM.data.scale;\n\t\tthis.pointeract.dispatch('zoom', { factor, ...origin });\n\t};\n\tpanToCoords = ({ x, y }: Coordinates) => {\n\t\tthis.pointeract.dispatch('pan', {\n\t\t\tdeltaX: x - this.DM.data.offsetX,\n\t\t\tdeltaY: y - this.DM.data.offsetY,\n\t\t});\n\t};\n\n\t// Container Coords to Canvas Coords relative to the top-left corner of the scaled canvas\n\tprivate readonly C2C = ({ x: containerX, y: containerY }: Coordinates) => ({\n\t\tx: containerX - this.DM.data.offsetX,\n\t\ty: containerY - this.DM.data.offsetY,\n\t});\n\n\tprivate readonly onTrueClick = (e: LoadedEvents['trueClick']) => {\n\t\tconst element = e.target as HTMLElement | undefined;\n\t\tif (this.isUIControl(element)) return;\n\t\tconst node = this.findNodeId(element);\n\t\tthis.onClick(node);\n\t};\n\n\tprivate readonly isUIControl = (target?: HTMLElement) => {\n\t\tif (!target) return false;\n\t\treturn target.closest('.controls') || target.closest('button') || target.closest('input');\n\t};\n\n\tprivate readonly findNodeId = (element?: HTMLElement) => {\n\t\tif (!element) return;\n\t\tlet ele = element;\n\t\twhile (!ele.id || ele.id === '') {\n\t\t\tif (!ele.parentElement) break;\n\t\t\tele = ele.parentElement;\n\t\t}\n\t\tif (ele.id === 'overlays' || !ele.id || ele.id === '') return;\n\t\treturn ele.id;\n\t};\n\n\tprivate readonly dispose = () => this.pointeract.dispose();\n}\n"],"mappings":"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"}
@@ -0,0 +1,62 @@
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
+ type Options = {
8
+ parser?: Parser;
9
+ nodeComponents?: Partial<ComponentDict>;
10
+ } & BaseOptions;
11
+ type Augmentation = {
12
+ onNodeActive: OverlayManager['onNodeActive'];
13
+ onNodeLosesActive: OverlayManager['onNodeLosesActive'];
14
+ };
15
+ type NodeComponentHook<N extends JSONCanvasNode> = (options: {
16
+ container: HTMLDivElement;
17
+ content: string;
18
+ node: N;
19
+ onBeforeUnmount: Hook;
20
+ onActive: Hook;
21
+ onLoseActive: Hook;
22
+ }) => void | Promise<void>;
23
+ type ComponentNodeMap = {
24
+ text: JSONCanvasTextNode;
25
+ markdown: JSONCanvasFileNode;
26
+ image: JSONCanvasFileNode;
27
+ audio: JSONCanvasFileNode;
28
+ video: JSONCanvasFileNode;
29
+ link: JSONCanvasLinkNode;
30
+ };
31
+ type ComponentDict = { [K in keyof ComponentNodeMap]: NodeComponentHook<ComponentNodeMap[K]> };
32
+ declare class OverlayManager extends BaseModule<Options, Augmentation> {
33
+ private _overlaysLayer;
34
+ private overlays;
35
+ private selectedId;
36
+ private aborted;
37
+ private eventListeners;
38
+ private readonly DM;
39
+ private readonly SM;
40
+ private readonly parse;
41
+ private readonly componentDict;
42
+ private get overlaysLayer();
43
+ onInteractionStart: Hook<[], false>;
44
+ onInteractionEnd: Hook<[], false>;
45
+ onNodeActive: Hook<[JSONCanvasNode], false>;
46
+ onNodeLosesActive: Hook<[JSONCanvasNode], false>;
47
+ constructor(...args: BaseArgs);
48
+ private readonly start;
49
+ private readonly restart;
50
+ private readonly renderOverlays;
51
+ private readonly themeChanged;
52
+ private readonly select;
53
+ private readonly updateOverlays;
54
+ private readonly createOverlay;
55
+ private readonly constructOverlay;
56
+ private readonly setOverlayColor;
57
+ private readonly clearOverlays;
58
+ private readonly dispose;
59
+ }
60
+ //#endregion
61
+ export { OverlayManager };
62
+ //# sourceMappingURL=OverlayManager.d.ts.map
@@ -1,2 +1,2 @@
1
- import{BaseModule as e}from"./BaseModule.js";import t from"./Controller.js";import s from"./DataManager.js";import a from"./InteractionHandler.js";import o from"./StyleManager.js";import i,{destroyError as n}from"./utilities.js";const r={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"];class d 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");const s=document.createElement("div");s.innerHTML=t,s.classList.add("JCV-parsed-content-wrapper"),e.appendChild(s)},markdown:async(e,t)=>{e.classList.add("JCV-markdown-content");const s=document.createElement("div");let a;s.textContent="Loading...",s.classList.add("JCV-parsed-content-wrapper"),e.appendChild(s);try{const e=await fetch(t),s=await e.text(),o=s.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);a=o?await this.parse(o[2]):await this.parse(s)}catch(o){console.error("[JSON Canvas Viewer] Failed to load markdown:",o),a="Failed to load content."}s.innerHTML=a},link:(e,t)=>{const s=document.createElement("iframe");s.src=t,s.sandbox="allow-scripts allow-same-origin",s.className="JCV-link-iframe",s.loading="lazy",e.appendChild(s)},audio:(e,t)=>{const s=document.createElement("audio");s.className="JCV-audio",s.src=t,s.controls=!0,e.appendChild(s)},image:(e,t)=>{const s=document.createElement("img");s.className="JCV-img",s.src=t,s.loading="lazy",e.appendChild(s)},video:(e,t)=>{const s=document.createElement("video");s.className="JCV-video",s.src=t,s.controls=!0,e.appendChild(s)}};get overlaysLayer(){if(!this._overlaysLayer)throw n;return this._overlaysLayer}onInteractionStart=i.makeHook();onInteractionEnd=i.makeHook();onNodeActive=i.makeHook();onNodeLosesActive=i.makeHook();constructor(...e){super(...e),this.parse=this.options.parser||(e=>e),this.DM=this.container.get(s),this.SM=this.container.get(o);this.container.get(t).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);const a=this.options.nodeComponents;a&&Object.assign(this.componentDict,a),this.augment({onNodeActive:this.onNodeActive,onNodeLosesActive:this.onNodeLosesActive}),this.onStart(this.start),this.onRestart(this.restart),this.onDispose(this.dispose)}start=()=>{this.container.get(a).onClick.subscribe(this.select),this.renderOverlays()};restart=()=>{this.clearOverlays(),this.renderOverlays()};renderOverlays=()=>{const e=async e=>{switch(e.type){case"text":this.createOverlay(e,await this.parse(e.text),"text");break;case"file":for(const t of c)if(e.file.match(r[t])){this.createOverlay(e,e.file,t);break}break;case"link":this.createOverlay(e,e.url,"link")}};Object.values(this.DM.data.nodeMap).forEach(async t=>{await e(t.ref)})};themeChanged=()=>{Object.values(this.overlays).forEach(e=>{const t=this.DM.data.nodeMap[e.id].ref,s=this.SM.getColor(t.color);this.setOverlayColor(e,s)})};select=e=>{const t=this.selectedId,s=t?this.overlays[t]:null,a=e?this.overlays[e]:null;if(s&&t){s.classList.remove("JCV-active");const e=this.DM.data.nodeMap[t];this.onNodeLosesActive(e.ref),e.onLoseActive?.()}if(a&&e){a.classList.add("JCV-active"),this.onInteractionStart();const t=this.DM.data.nodeMap[e];this.onNodeActive(t.ref),t.onActive?.()}else this.onInteractionEnd();this.selectedId=e};updateOverlays=()=>{const e=this.DM.data;this.overlaysLayer.style.transform=`translate(${e.offsetX}px, ${e.offsetY}px) scale(${e.scale})`};createOverlay=(...e)=>{if(this.aborted)return;const t=e[0];let s=this.overlays[t.id];if(!s){if(s=this.constructOverlay(...e),this.aborted)return;this.overlaysLayer.appendChild(s),this.overlays[t.id]=s,s.style.left=`${t.x}px`,s.style.top=`${t.y}px`,s.style.width=`${t.width}px`,s.style.height=`${t.height}px`}};constructOverlay=(...e)=>{const t=e[0],s=document.createElement("div");s.classList.add("JCV-overlay-container"),s.id=t.id,this.setOverlayColor(s,this.SM.getColor(t.color));const a=document.createElement("div");a.classList.add("JCV-content"),s.appendChild(a);const o=document.createElement("div");o.className="JCV-click-layer",s.appendChild(o);const n=document.createElement("div");n.className="JCV-overlay-border",s.appendChild(n);const r=this.DM.data.nodeMap[t.id];r.onActive=i.makeHook(),r.onLoseActive=i.makeHook(),r.onBeforeUnmount=i.makeHook(),this.componentDict[e[2]](a,e[1],e[0],r.onBeforeUnmount,r.onActive,r.onLoseActive);const c=()=>{t.id===this.selectedId&&this.onInteractionStart()},d=()=>{t.id===this.selectedId&&this.onInteractionEnd()};return s.addEventListener("pointerenter",c),s.addEventListener("pointerleave",d),s.addEventListener("touchstart",c),s.addEventListener("touchend",d),this.eventListeners[t.id]=[c,d],s};setOverlayColor=(e,t)=>{Object.entries(t).forEach(([t,s])=>{e.style.setProperty(`--overlay-${t}`,s)})};clearOverlays=()=>{Object.entries(this.overlays).forEach(([e,t])=>{if(this.DM.data.nodeMap[e].onBeforeUnmount?.(),this.eventListeners[e]){const s=this.eventListeners[e][0],a=this.eventListeners[e][1];if(!s||!a)throw n;t.removeEventListener("pointerenter",s),t.removeEventListener("pointerleave",a),t.removeEventListener("touchstart",s),t.removeEventListener("touchend",a),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{d as default};
2
- //# sourceMappingURL=OverlayManager.js.map
1
+ import{BaseModule as e}from"./BaseModule.js";import{destroyError as t,makeHook 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={audio:/\.(mp3|wav|ogg|opus|aac|m4a|flac)$/i,image:/\.(png|jpg|jpeg|gif|svg|webp|avif|bmp|ico|heic|heif)$/i,markdown:/\.(md|mdx|markdown|txt)$/i,video:/\.(mp4|webm|ogv|mov|m3u8|mpd)$/i},c=[`markdown`,`image`,`audio`,`video`];var l=class extends e{_overlaysLayer=document.createElement(`div`);overlays={};selectedId;aborted=!1;eventListeners={};DM;SM;parse;componentDict={audio:({container:e,content:t})=>{let n=document.createElement(`audio`);n.className=`JCV-audio`,n.src=t,n.controls=!0,e.appendChild(n)},image:({container:e,content:t})=>{let n=document.createElement(`img`);n.className=`JCV-img`,n.src=t,n.loading=`lazy`,e.appendChild(n)},link:({container:e,content:t})=>{let n=document.createElement(`iframe`);n.src=t,n.sandbox=`allow-scripts allow-same-origin`,n.className=`JCV-link-iframe`,n.loading=`lazy`,e.appendChild(n)},markdown:async({container:e,content:t})=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.textContent=`Loading...`,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n);let r;try{let e=await(await fetch(t)).text(),n=/^---\n([\s\S]*?)\n---\n([\s\S]*)$/.exec(e);r=await this.parse(n?n[2]:e)}catch(e){console.error(`[JSON Canvas Viewer] Failed to load markdown:`,e),r=`Failed to load content.`}n.innerHTML=r},text:({container:e,content:t})=>{e.classList.add(`JCV-markdown-content`);let n=document.createElement(`div`);n.innerHTML=t,n.classList.add(`JCV-parsed-content-wrapper`),e.appendChild(n)},video:({container:e,content:t})=>{let n=document.createElement(`video`);n.className=`JCV-video`,n.src=t,n.controls=!0,e.appendChild(n)}};get overlaysLayer(){if(!this._overlaysLayer)throw t;return this._overlaysLayer}onInteractionStart=n();onInteractionEnd=n();onNodeActive=n();onNodeLosesActive=n();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]:void 0,r=e?this.overlays[e]:void 0;if(n&&t){n.classList.remove(`JCV-active`);let e=this.DM.data.nodeMap[t];this.onNodeLosesActive(e.ref),e.onLoseActive?.()}if(r&&e){r.classList.add(`JCV-active`),this.onInteractionStart();let t=this.DM.data.nodeMap[e];this.onNodeActive(t.ref),t.onActive?.()}else this.onInteractionEnd();this.selectedId=e};updateOverlays=()=>{let e=this.DM.data;this.overlaysLayer.style.transform=`translate(${e.offsetX}px, ${e.offsetY}px) scale(${e.scale})`};createOverlay=(...e)=>{if(this.aborted)return;let t=e[0],n=this.overlays[t.id];if(!n){if(n=this.constructOverlay(...e),this.aborted)return;this.overlaysLayer.appendChild(n),this.overlays[t.id]=n,n.style.left=`${t.x}px`,n.style.top=`${t.y}px`,n.style.width=`${t.width}px`,n.style.height=`${t.height}px`}};constructOverlay=(...e)=>{let t=e[0],r=document.createElement(`div`);r.classList.add(`JCV-overlay-container`),r.id=t.id,this.setOverlayColor(r,this.SM.getColor(t.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[t.id];s.onActive=n(),s.onLoseActive=n(),s.onBeforeUnmount=n(),this.componentDict[e[2]]({container:i,content:e[1],node:e[0],onActive:s.onActive,onBeforeUnmount:s.onBeforeUnmount,onLoseActive:s.onLoseActive});let c=()=>{t.id===this.selectedId&&this.onInteractionStart()},l=()=>{t.id===this.selectedId&&this.onInteractionEnd()};return r.addEventListener(`pointerenter`,c),r.addEventListener(`pointerleave`,l),r.addEventListener(`touchstart`,c),r.addEventListener(`touchend`,l),this.eventListeners[t.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,n])=>{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 t;n.removeEventListener(`pointerenter`,r),n.removeEventListener(`pointerleave`,i),n.removeEventListener(`touchstart`,r),n.removeEventListener(`touchend`,i),this.eventListeners[e][0]=void 0,this.eventListeners[e][1]=void 0}n.remove(),delete this.overlays[e]})};dispose=()=>{this.aborted=!0,this.clearOverlays(),this.overlaysLayer.remove(),this._overlaysLayer=void 0}};export{l as default};
2
+ //# sourceMappingURL=OverlayManager.js.map