json-canvas-viewer 3.0.3 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Hesprs
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Hesprs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  SOFTWARE.
package/README.md CHANGED
@@ -1,208 +1,387 @@
1
- # JSON Canvas Viewer
2
-
3
- ![TypeScript](https://badgen.net/badge/-/Strict?icon=typescript&label=TypeScript&labelColor=blue&color=555555)
4
- [![npm](https://badgen.net/npm/v/json-canvas-viewer?icon=npm&labelColor=red&color=555555)](https://www.npmjs.com/package/json-canvas-viewer)
5
- [![publish size](https://badgen.net/packagephobia/publish/json-canvas-viewer?labelColor=green&color=555555)](https://packagephobia.now.sh/result?p=json-canvas-viewer)
6
- [![GitHub commits](https://badgen.net/github/commits/hesprs/JSON-Canvas-Viewer?icon=git&labelColor=purple&color=555555)](https://github.com/hesprs/JSON-Canvas-Viewer/commits/main)
7
-
8
- ![Canvas Viewer](example/preview.png)
9
-
10
- A **TypeScript-based** viewer for **JSON Canvas** files. View and interact with your canvas files directly in the browser, or embed the viewer in front-end projects with ease. It is built without frameworks so it can be easily integrated into any framework.
11
-
12
- This project is inspired by [sofanati-nour/obsidian-canvas-web-renderer](https://github.com/sofanati-nour/obsidian-canvas-web-renderer), but is far more developed and optimized.
13
-
14
- For more about **JSON Canvas**, also known as **Obsidian Canvas**, please visit [jsoncanvas.org](https://jsoncanvas.org/).
15
-
16
- ## 📦 Installation
17
-
18
- We recommend using your favorite package manager to install the package. **Note: This package requires `marked` as dependency, your package manager will automatically install it.**
19
-
20
- ``` bash
21
- # npm
22
- npm install json-canvas-viewer
23
-
24
- # pnpm
25
- pnpm add json-canvas-viewer
26
-
27
- # yarn
28
- yarn add json-canvas-viewer
29
- ```
30
-
31
- The integrated version is a choice if your project *doesn't use Node.js*, which is built with `marked` and `json-canvas-viewer` inlined, so it can be deployed in vanilla JavaScript projects. Find the integrated version in [Release page](https://github.com/hesprs/JSON-Canvas-Viewer/releases).
32
-
33
- After installation, you can import the package as a module. It supports both ES module and Common JS, here we take ESM as example:
34
-
35
- ``` TypeScript
36
- // with Node.js
37
- import canvasViewer from 'json-canvas-viewer';
38
-
39
- // using integrated version
40
- import canvasViewer from 'path/to/canvasViewer.js';
41
- ```
42
-
43
- ## 🚀 Quick Start
44
-
45
- As a custom element (a simple way to embed, already defined in the code):
46
-
47
- ``` HTML
48
- <canvas-viewer
49
- src="example/introduction.canvas"
50
- extensions="minimap mistouchPrevention"
51
- options="minimapCollapsed"
52
- ></canvas-viewer>
53
- ```
54
-
55
- Or instantiate the viewer (more flexible, but requires more code):
56
-
57
- ``` HTML
58
- <div id="myCanvasContainer" style="width:800px; height:600px;"></div>
59
- <script>
60
- const viewer = new canvasViewer(
61
- document.getElementById('myCanvasContainer'),
62
- ['minimap', 'mistouchPrevention'],
63
- ['minimapCollapsed']
64
- );
65
- viewer.loadCanvas('example/introduction.canvas');
66
- viewer.addEventListener('interact', e => {
67
- // handle node interaction
68
- });
69
- // dispose when not needed
70
- viewer.dispose();
71
- </script>
72
- ```
73
-
74
- **Tip**: All emited events are realized by `JavaScript CustomEvent`, so the event callback is stored in `event.detail`.
75
-
76
- If you are coding in TypeScript, and intend to retrieve Custom Event callback, please use the pattern below to make the type validator believe your code is type safe:
77
-
78
- ``` TypeScript
79
- const viewer: canvasViewer = new canvasViewer(...);
80
- viewer.loadCanvas(...);
81
- viewer.addEventListener('...', (e: Event) => {
82
- if (e instanceof CustomEvent) {
83
- // use e.detail safely here
84
- console.log(e.detail);
85
- };
86
- });
87
- ```
88
-
89
- ## 🐶 Features
90
-
91
- - View JSON Canvas files (`.canvas`) in a web browser
92
- - Full markdown syntax support (auto-parsed to HTML)
93
- - Embed into front-end projects using a container element or custom element
94
- - Interactive pan and zoom functionality
95
- - Support for different node types:
96
- - Text nodes
97
- - File nodes (including Markdown files)
98
- - Link nodes (embedded web content)
99
- - Group nodes with custom colors
100
- - Edge connections between nodes with labels
101
- - Minimap for easy navigation (optional extension)
102
- - Mistouch prevention (optional extension)
103
- - Responsive design with mobile and touchpad adaption
104
- - 🔥 **Much more performant** than rendering canvas in Obsidian!
105
-
106
- ## 🔌 API Reference
107
-
108
- ### Constructor
109
-
110
- ``` TypeScript
111
- new canvasViewer(container, extensions, options);
112
- ```
113
-
114
- - `container`: HTMLElement where the viewer will be rendered
115
- - `extensions`: (optional) Array (or space-separated string in case of custom element) of extension names to enable:
116
- - `minimap` - Adds navigation minimap
117
- - `mistouchPrevention` - Frozes canvas when clicking outside. **Warning: navigation methods (like `zoomIn()` or `resetView()`) cannot take effect if the canvas is frozen**.
118
- - `options`: (optional) Array (or space-separated string in case of custom element) of config options:
119
- - `controlsHidden` - Hides the control panel
120
- - `controlsCollapsed` - Starts with controls collapsed
121
- - `proControlSchema` - Uses control keybindings in professional softwares (`mouse wheel`: scroll vertically; `mouse wheel` + `shift`: scroll horizontally; `mouse wheel` + `ctrl`: zoom), rather than mouse wheel to zoom. The canvas viewer automatically detect and adjust control schema by default, but you can explicitly configure it. This option doesn't affect mobile control.
122
- - `noShadow` - Disables shadow DOM, DOM elements will be appended to the light DOM directly. The canvas viewer will still be functionable, but the styles may be affected.
123
- - `noPreventionAtStart` (avaliable when mistouchPrevention enabled) Starts without prevention
124
- - `minimapCollapsed` - (avaliable when minimap enabled) Starts with minimap collapsed
125
-
126
- ### Methods
127
-
128
- - `loadCanvas(path)` Load a canvas file (by path), **please put all the related files (files embeded in the canvas) in the same folder as the canvas file, wherever they originally are**.
129
- - `shiftFullscreen(option)` — Toggle fullscreen mode ('toggle', 'enter', 'exit')
130
- - `resetView()` — Reset pan/zoom to fit canvas content
131
- - `zoomIn()` — Zoom in by a fixed step
132
- - `zoomOut()` — Zoom out by a fixed step
133
- - `setScale(scale)` — Set zoom level to a specific value (number, 0.05–20)
134
- - `panTo(x, y)` — Pan the view to a specific world coordinate
135
- - `dispose()` — Clean up and remove viewer from DOM
136
-
137
- ### Events
138
-
139
- Register with `viewer.addEventListener(event, callback)`.
140
-
141
- - `interact` — Fired when a node is interacted with (`callback(node id, type: 'select' | 'preview')`)
142
- - `loaded` — Fired when a canvas file is loaded (`callback(canvasData)`)
143
-
144
- ## 📂 Canvas File Structure
145
-
146
- The viewer expects JSON Canvas files in JSON format:
147
-
148
- ``` JSON
149
- {
150
- "nodes": [
151
- {
152
- "id": "unique-id",
153
- "type": "text|file|link|group",
154
- "x": 0,
155
- "y": 0,
156
- "width": 400,
157
- "height": 400,
158
- "text": "Content for text nodes",
159
- "file": "filename for file nodes",
160
- "url": "URL for link nodes",
161
- "color": "color-id for groups"
162
- }
163
- ],
164
- "edges": [
165
- {
166
- "id": "edge-id",
167
- "fromNode": "source-node-id",
168
- "toNode": "target-node-id",
169
- "fromSide": "top|bottom|left|right",
170
- "toSide": "top|bottom|left|right",
171
- "label": "Optional edge label"
172
- }
173
- ]
174
- }
175
- ```
176
-
177
- ## 💻 Development
178
-
179
- Built with `TypeScript`, `SCSS` and `HTML5 Canvas`.
180
-
181
- **Project Structure**:
182
-
183
- ``` TypeScript
184
- root
185
- ├── src/
186
- │ ├── canvasViewer.ts // Main class-based component
187
- │ ├── controls.ts // Controls panel
188
- │ ├── interactor.ts // Handles pointer events for user pan/zoom
189
- │ ├── minimap.ts // Minimap extension
190
- │ ├── mistouchPreventer.ts // MistouchPrevention extension
191
- │ ├── overlayManager.ts // Renderer for interactive nodes
192
- │ ├── previewModal.ts // Preview modal
193
- │ ├── renderer.ts // Renderer for non-interactive stuff + some shared exports
194
- │ ├── declarations.d.ts // Public types
195
- │ └── styles.scss // Styles for the viewer
196
- └── example/
197
- └── index.html // Example/test entry point
198
- ```
199
-
200
- **Development Standards**:
201
-
202
- - Strict type validation, no non-null assertion operator `!` allowed.
203
- - Meticulous resource disposal, no memory leak ever possible.
204
- - Modularized components, avoid monolithic class.
205
-
206
- ## 📝 Copyright & License
207
-
208
- Copyright ©️ 2025 Hesprs (Hēsperus) | [MIT License](https://mit-license.org/)
1
+ # JSON Canvas Viewer
2
+
3
+ ![TypeScript](https://badgen.net/badge/-/Strict?icon=typescript&label=TypeScript&labelColor=blue&color=555555)
4
+ [![npm](https://badgen.net/npm/v/json-canvas-viewer?icon=npm&labelColor=red&color=555555)](https://www.npmjs.com/package/json-canvas-viewer)
5
+ [![publish size](https://badgen.net/packagephobia/publish/json-canvas-viewer?labelColor=green&color=555555)](https://packagephobia.now.sh/result?p=json-canvas-viewer)
6
+
7
+ ![Canvas Viewer](example/preview.png)
8
+
9
+ A **TypeScript-based** viewer for **JSON Canvas** files. View and interact with your canvas files directly in the browser, or embed the viewer in front-end projects with ease. It is built without frameworks so it can be easily integrated into any framework.
10
+
11
+ This project is inspired by [sofanati-nour/obsidian-canvas-web-renderer](https://github.com/sofanati-nour/obsidian-canvas-web-renderer), but is far more developed and optimized.
12
+
13
+ For more about **JSON Canvas**, also known as **Obsidian Canvas**, please visit [jsoncanvas.org](https://jsoncanvas.org/).
14
+
15
+ ## 📦 Installation
16
+
17
+ We recommend using your favorite package manager to install the package. **Note: This package requires `marked` as dependency, your package manager will automatically install it.**
18
+
19
+ ```bash
20
+ # npm
21
+ npm install json-canvas-viewer
22
+
23
+ # pnpm
24
+ pnpm add json-canvas-viewer
25
+
26
+ # yarn
27
+ yarn add json-canvas-viewer
28
+ ```
29
+
30
+ After installation, you can import the package as a module. It supports both ES module and CommonJS. JS, here we take ESM as an example:
31
+
32
+ ```TypeScript
33
+ import canvasViewer from 'json-canvas-viewer';
34
+ ```
35
+
36
+ ## 🚀 Quick Start
37
+
38
+ Instantiate the viewer:
39
+
40
+ ```HTML
41
+ <div id="myCanvasContainer" style="width:800px; height:600px;"></div>
42
+ <script type="module">
43
+ import canvasViewer from 'json-canvas-viewer';
44
+ const viewer = new canvasViewer(document.getElementById('myCanvasContainer'));
45
+ viewer.loadCanvas('example/introduction.canvas');
46
+ // dispose when not needed
47
+ viewer.dispose();
48
+ </script>
49
+ ```
50
+
51
+ And the viewer should be right in your container, you can instantiate the viewer multiple times to render multiple canvases simultaneously.
52
+
53
+ **Methods**:
54
+
55
+ - `loadCanvas(path)` — Load a canvas file (by path), **please put all the related files (files embedded in the canvas) in the same folder as the canvas file, wherever they originally are**.
56
+ - `dispose()` — Clean up and remove viewer from DOM.
57
+
58
+ ## 🐶 Features
59
+
60
+ - View JSON Canvas files (`.canvas`) in a web browser
61
+ - Full markdown syntax support (auto-parsed to HTML)
62
+ - Embed into websites easily
63
+ - Interactive pan and zoom functionality
64
+ - Support for different node types:
65
+ - Text nodes
66
+ - File nodes (including Markdown files)
67
+ - Link nodes (embedded web content)
68
+ - Group nodes with custom colors
69
+ - Edge connections between nodes with labels
70
+ - Minimap for easy navigation (optional extension)
71
+ - Mistouch prevention (optional extension)
72
+ - Responsive design with mobile and touchpad adaptation
73
+ - Out-of-the-box extensibility and tree-shaking
74
+ - TypeScript native support
75
+ - 🔥 **Much more performant** than rendering canvases in Obsidian!
76
+
77
+ ## 🧩 Extensibility
78
+
79
+ ### Registry
80
+
81
+ The viewer implements the `registry`, which is a powerful orchestrator to streamline the development and extension of the viewer. The registry is the core of the viewer.
82
+
83
+ ```TypeScript
84
+ new canvasViewer(container, registry);
85
+
86
+ interface registry {
87
+ options: Record<string, Record<string, any>>;
88
+ extensions: Array<Class<runtimeData, registry>>;
89
+ hooks: Record<string, Array<Function>>;
90
+ api: Record<string, Record<string, Function>>;
91
+ register: (userRegistry: userRegistry) => void;
92
+ }
93
+ interface Class<T> { new (...args: any[]): T }
94
+ interface Function { (...args: any[]): any }
95
+ ```
96
+
97
+ The second parameter of the constructor is an object which is then merged with the default registry. You can also manually register using the `register` method.
98
+
99
+ **Default Options and Values**:
100
+
101
+ ```TypeScript
102
+ {
103
+ main: {
104
+ noShadow: false,
105
+ },
106
+ interactor: {
107
+ preventDefault: true,
108
+ proControlSchema: false,
109
+ zoomFactor: 0.002,
110
+ lockControlSchema: false,
111
+ },
112
+ }
113
+ ```
114
+
115
+ - `noShadow` Disables shadow DOM, DOM elements will be appended to the light DOM directly. The canvas viewer will still be functional, but the styles may be affected.
116
+ - `preventDefault` Prevents default behavior of mouse events, the viewer may not work properly if set to false.
117
+ - `proControlSchema` Uses control keybindings in professional software (`mouse wheel`: scroll vertically; `mouse wheel + shift`: scroll horizontally; `mouse wheel + ctrl`: zoom), rather than zooming with the mouse wheel. The canvas viewer automatically detects and adjusts the control schema by default, but you can explicitly configure it. This option doesn't affect mobile control.
118
+ - `zoomFactor` The zoom factor, how fast the canvas zooms in or out.
119
+ - `lockControlSchema` Locks the control schema.
120
+
121
+ **Default Hooks**:
122
+
123
+ ```TypeScript
124
+ {
125
+ onDispose: [],
126
+ onRender: [],
127
+ onResize: [(width: number, height: number) => {}],
128
+ onClick: [(id: string | null) => {}],
129
+ onZoom: [],
130
+ onToggleFullscreen: [],
131
+ onInteractionStart: [],
132
+ onInteractionEnd: [],
133
+ }
134
+ ```
135
+
136
+ - `onDispose` — Called when the viewer is disposed.
137
+ - `onRender` — Called when the viewer is rendered every frame.
138
+ - `onResize` — Called when the viewer container is resized.
139
+ - `width` — The width of the resized viewer container.
140
+ - `height` — The height of the resized viewer container.
141
+ - `onClick` — Called when the canvas is clicked.
142
+ - `id` — The id of the node that is clicked, or `null` if no node is clicked.
143
+ - `onZoom` — Called when the zoom level changes.
144
+ - `onToggleFullscreen` Called when the fullscreen mode is toggled.
145
+ - `onInteractionStart` — Called when the pointer enters a selected node.
146
+ - `onInteractionEnd` Called when the pointer leaves a selected node.
147
+
148
+ **Default API**:
149
+
150
+ ```TypeScript
151
+ {
152
+ main: {
153
+ loadCanvas: (path: string) => Promise<void>,
154
+ refresh: () => void, // Manually trigger a render
155
+ pan: (x: number, y: number) => void,
156
+ zoom: (factor: number, origin: Coordinates) => void,
157
+ zoomToScale: (newScale: number, origin: Coordinates) => void,
158
+ panToCoords: (x: number, y: number) => void,
159
+ shiftFullscreen: (option: 'toggle' | 'enter' | 'exit' = 'toggle') => void,
160
+ resetView: () => void, // Reset the scale and offset to default that the whole canvas is visible
161
+ },
162
+ dataManager: {
163
+ middleViewer: () => {
164
+ x: number; // half of the container width
165
+ y: number; // half of the container height
166
+ width: number; // container width
167
+ height: number; // container height
168
+ },
169
+ findNodeAtMousePosition: (mousePosition: Coordinates) => JSONCanvasNode | null,
170
+ },
171
+ interactionHandler: {
172
+ stop: () => void, // Stop receiving interaction
173
+ start: () => void, // Start receiving interaction
174
+ },
175
+ }
176
+ ```
177
+
178
+ ### Extensions
179
+
180
+ The viewer is built with extensibility in mind, and it is easy to extend the viewer with custom extensions.
181
+
182
+ #### Official Extensions
183
+
184
+ **minimap**: Renders the minimap with an overview of the canvas.
185
+ - used with:
186
+ ```TypeScript
187
+ import minimap from 'json-canvas-viewer/minimap';
188
+ new canvasViewer(container, { extensions: [minimap] });
189
+ ```
190
+ - new options and API:
191
+ ```TypeScript
192
+ {
193
+ options: {
194
+ minimap: {
195
+ collapsed: false,
196
+ },
197
+ },
198
+ api: {
199
+ minimap: {
200
+ toggleCollapse: () => void,
201
+ },
202
+ }
203
+ }
204
+ ```
205
+
206
+ **mistouchPreventer**: Prevents mistouch by freezing the canvas when clicking outside the viewer.
207
+ - used with:
208
+ ```TypeScript
209
+ import mistouchPreventer from 'json-canvas-viewer/mistouchPreventer';
210
+ new canvasViewer(container, { extensions: [mistouchPreventer] });
211
+ ```
212
+ - new options and API:
213
+ ```TypeScript
214
+ {
215
+ options: {
216
+ mistouchPreventer: {
217
+ preventAtStart: true,
218
+ },
219
+ },
220
+ api: {
221
+ mistouchPreventer: {
222
+ startPrevention: () => void,
223
+ endPrevention: () => void,
224
+ },
225
+ }
226
+ }
227
+ ```
228
+
229
+ **controls**: Shows a control bar with zoom, pan, scale slider, and fullscreen buttons.
230
+ - used with:
231
+ ```TypeScript
232
+ import controls from 'json-canvas-viewer/controls';
233
+ new canvasViewer(container, { extensions: [controls] });
234
+ ```
235
+ - new options and API:
236
+ ```TypeScript
237
+ {
238
+ options: {
239
+ controls: {
240
+ collapsed: false,
241
+ },
242
+ },
243
+ api: {
244
+ controls: {
245
+ toggleCollapse: () => void,
246
+ },
247
+ }
248
+ }
249
+ ```
250
+
251
+ **debugPanel**: Shows a debug panel with scale and offset.
252
+ - used with:
253
+ ```TypeScript
254
+ import debugPanel from 'json-canvas-viewer/debugPanel';
255
+ new canvasViewer(container, { extensions: [debugPanel] });
256
+ ```
257
+ - new API:
258
+ ```TypeScript
259
+ {
260
+ api: {
261
+ debugPanel: {
262
+ update: () => void,
263
+ },
264
+ }
265
+ }
266
+ ```
267
+
268
+ #### Develop an Extension
269
+
270
+ An extension, in essence, is a class that follows a fixed pattern. You can do almost anything with the viewer by using an extension. Actually, the viewer runs with only four core extensions: `renderer`, `interactionHandler`, `overlayManager` and `dataManager`. Here is the fixed pattern:
271
+ - receive `runtimeData` and `registry` as parameters in the constructor.
272
+ - calls `registry.register` first in the constructor to define default options, register hooks and provide API.
273
+
274
+ Here comes a minimal sample extension of a debug panel (JavaScript for simplicity):
275
+
276
+ ```JavaScript
277
+ import { round } from '../utilities';
278
+
279
+ export default class debugPanel {
280
+ constructor(data, registry) {
281
+ registry.register({
282
+ hooks: {
283
+ onRender: [this.update],
284
+ onDispose: [this.dispose],
285
+ },
286
+ api: {
287
+ debugPanel: {
288
+ update: this.update,
289
+ },
290
+ },
291
+ });
292
+ this.debugPanel = document.createElement('div');
293
+ this.debugPanel.className = 'debug-panel';
294
+ this.data = data;
295
+ data.container.appendChild(this.debugPanel);
296
+ }
297
+
298
+ private update = () => {
299
+ this.debugPanel.innerHTML = `
300
+ <p>Scale: ${round(this.data.scale, 3)}</p>
301
+ <p>Offset: ${round(this.data.offsetX, 1)}, ${round(this.data.offsetY, 1)}</p>
302
+ `;
303
+ };
304
+
305
+ private dispose = () => {
306
+ this.debugPanel.remove();
307
+ this.debugPanel = null;
308
+ };
309
+ }
310
+ ```
311
+
312
+ ## 📂 Canvas File Structure
313
+
314
+ The viewer expects JSON Canvas files in JSON format (a combination of official [JSON Canvas spec](https://jsoncanvas.org/spec/1.0/) and [Developer-Mike/obsidian-advanced-canvas spec](https://github.com/Developer-Mike/obsidian-advanced-canvas)):
315
+
316
+ ```TypeScript
317
+ interface JSONCanvas {
318
+ nodes: Array<JSONCanvasNode>;
319
+ edges: Array<JSONCanvasEdge>;
320
+ metadata: {
321
+ version: string;
322
+ frontmatter: Record<string, string>;
323
+ };
324
+ }
325
+
326
+ interface JSONCanvasNode {
327
+ id: string;
328
+ type: 'group' | 'file' | 'text' | 'link';
329
+ x: number;
330
+ y: number;
331
+ width: number;
332
+ height: number;
333
+ label?: string;
334
+ background?: string;
335
+ backgroundStyle?: 'cover' | 'ratio' | 'repeat';
336
+ styleAttributes?: Record<string, string>;
337
+ color?: string;
338
+ text?: string;
339
+ file?: string;
340
+ subpath?: string;
341
+ url?: string;
342
+ }
343
+
344
+ interface JSONCanvasEdge {
345
+ id: string;
346
+ fromNode: string;
347
+ toNode: string;
348
+ fromSide: 'right' | 'left' | 'top' | 'bottom';
349
+ toSide: 'right' | 'left' | 'top' | 'bottom';
350
+ toEnd?: 'arrow' | 'none';
351
+ label?: string;
352
+ styleAttributes?: Record<string, string>;
353
+ color?: string;
354
+ }
355
+ ```
356
+
357
+ ## 💻 Development
358
+
359
+ Built with `TypeScript`, `SCSS` and `HTML5 Canvas`.
360
+
361
+ **Project Structure**:
362
+
363
+ ```
364
+ root
365
+ ├── src/
366
+ │ ├── extensions/
367
+ │ │ ├── controls.ts // Control panel
368
+ │ │ ├── minimap.ts // Minimap extension
369
+ │ │ ├── mistouchPreventer.ts // MistouchPrevention extension
370
+ │ │ └── debugPanel.ts // Debug panel
371
+ │ ├── canvasViewer.ts // Main entry point
372
+ │ ├── interactor.ts // Handles pointer events for user pan/zoom
373
+ │ ├── dataManager.ts // Manages canvas data
374
+ │ ├── interactionHandler.ts // Handles interaction events (wrapper of interactor)
375
+ │ ├── overlayManager.ts // Renderer for interactive nodes
376
+ │ ├── renderer.ts // Renderer for non-interactive stuff
377
+ │ ├── declarations.d.ts // Public types
378
+ │ ├── utilities.ts // Utility functions
379
+ │ └── styles.scss // Styles for the viewer
380
+ └── example/
381
+ ├── index.html // Example/test entry point
382
+ └── Example Canvas/ // Example/test canvas file
383
+ ```
384
+
385
+ ## 📝 Copyright & License
386
+
387
+ Copyright ©️ 2025 Hesprs (Hēsperus) | [MIT License](https://mit-license.org/)