worldorbit 3.2.0 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/core/dist/scene.js +98 -16
- package/dist/browser/core/dist/spatial-scene.js +1 -0
- package/dist/browser/core/dist/types.d.ts +3 -0
- package/dist/browser/editor/dist/editor.js +55 -12
- package/dist/browser/obsidian-plugin/dist/diagnostics.d.ts +3 -0
- package/dist/browser/obsidian-plugin/dist/diagnostics.js +23 -0
- package/dist/browser/obsidian-plugin/dist/examples.d.ts +3 -0
- package/dist/browser/obsidian-plugin/dist/examples.js +77 -0
- package/dist/browser/obsidian-plugin/dist/index.d.ts +9 -0
- package/dist/browser/obsidian-plugin/dist/index.js +8 -0
- package/dist/browser/obsidian-plugin/dist/main.d.ts +2 -0
- package/dist/browser/obsidian-plugin/dist/main.js +2 -0
- package/dist/browser/obsidian-plugin/dist/navigation.d.ts +6 -0
- package/dist/browser/obsidian-plugin/dist/navigation.js +44 -0
- package/dist/browser/obsidian-plugin/dist/plugin.d.ts +8 -0
- package/dist/browser/obsidian-plugin/dist/plugin.js +508 -0
- package/dist/browser/obsidian-plugin/dist/positions.d.ts +7 -0
- package/dist/browser/obsidian-plugin/dist/positions.js +14 -0
- package/dist/browser/obsidian-plugin/dist/settings.d.ts +2 -0
- package/dist/browser/obsidian-plugin/dist/settings.js +5 -0
- package/dist/browser/obsidian-plugin/dist/theme.d.ts +2 -0
- package/dist/browser/obsidian-plugin/dist/theme.js +31 -0
- package/dist/browser/obsidian-plugin/dist/types.d.ts +42 -0
- package/dist/browser/obsidian-plugin/dist/types.js +1 -0
- package/dist/browser/obsidian-plugin/dist/viewer-host.d.ts +14 -0
- package/dist/browser/obsidian-plugin/dist/viewer-host.js +110 -0
- package/dist/browser/viewer/dist/atlas-state.js +3 -0
- package/dist/browser/viewer/dist/index.d.ts +1 -0
- package/dist/browser/viewer/dist/index.js +1 -0
- package/dist/browser/viewer/dist/interactive-2d.d.ts +21 -0
- package/dist/browser/viewer/dist/interactive-2d.js +201 -0
- package/dist/browser/viewer/dist/render.d.ts +1 -1
- package/dist/browser/viewer/dist/render.js +2 -1
- package/dist/browser/viewer/dist/types.d.ts +1 -0
- package/dist/browser/viewer/dist/viewer-state.d.ts +1 -1
- package/dist/browser/viewer/dist/viewer-state.js +1 -1
- package/dist/browser/viewer/dist/viewer.js +2 -0
- package/dist/obsidian-plugin/LICENSE +21 -0
- package/dist/obsidian-plugin/README.md +124 -0
- package/dist/obsidian-plugin/main.js +108 -0
- package/dist/obsidian-plugin/manifest.json +9 -0
- package/dist/obsidian-plugin/obsidian_scsh_1.png +0 -0
- package/dist/obsidian-plugin/obsidian_scsh_2.png +0 -0
- package/dist/obsidian-plugin/styles.css +164 -0
- package/dist/unpkg/core/dist/scene.js +98 -16
- package/dist/unpkg/core/dist/spatial-scene.js +1 -0
- package/dist/unpkg/core/dist/types.d.ts +3 -0
- package/dist/unpkg/editor/dist/editor.js +55 -12
- package/dist/unpkg/obsidian-plugin/dist/diagnostics.d.ts +3 -0
- package/dist/unpkg/obsidian-plugin/dist/diagnostics.js +23 -0
- package/dist/unpkg/obsidian-plugin/dist/examples.d.ts +3 -0
- package/dist/unpkg/obsidian-plugin/dist/examples.js +77 -0
- package/dist/unpkg/obsidian-plugin/dist/index.d.ts +9 -0
- package/dist/unpkg/obsidian-plugin/dist/index.js +8 -0
- package/dist/unpkg/obsidian-plugin/dist/main.d.ts +2 -0
- package/dist/unpkg/obsidian-plugin/dist/main.js +2 -0
- package/dist/unpkg/obsidian-plugin/dist/navigation.d.ts +6 -0
- package/dist/unpkg/obsidian-plugin/dist/navigation.js +44 -0
- package/dist/unpkg/obsidian-plugin/dist/plugin.d.ts +8 -0
- package/dist/unpkg/obsidian-plugin/dist/plugin.js +508 -0
- package/dist/unpkg/obsidian-plugin/dist/positions.d.ts +7 -0
- package/dist/unpkg/obsidian-plugin/dist/positions.js +14 -0
- package/dist/unpkg/obsidian-plugin/dist/settings.d.ts +2 -0
- package/dist/unpkg/obsidian-plugin/dist/settings.js +5 -0
- package/dist/unpkg/obsidian-plugin/dist/theme.d.ts +2 -0
- package/dist/unpkg/obsidian-plugin/dist/theme.js +31 -0
- package/dist/unpkg/obsidian-plugin/dist/types.d.ts +42 -0
- package/dist/unpkg/obsidian-plugin/dist/types.js +1 -0
- package/dist/unpkg/obsidian-plugin/dist/viewer-host.d.ts +14 -0
- package/dist/unpkg/obsidian-plugin/dist/viewer-host.js +110 -0
- package/dist/unpkg/viewer/dist/atlas-state.js +3 -0
- package/dist/unpkg/viewer/dist/index.d.ts +1 -0
- package/dist/unpkg/viewer/dist/index.js +1 -0
- package/dist/unpkg/viewer/dist/interactive-2d.d.ts +21 -0
- package/dist/unpkg/viewer/dist/interactive-2d.js +201 -0
- package/dist/unpkg/viewer/dist/render.d.ts +1 -1
- package/dist/unpkg/viewer/dist/render.js +2 -1
- package/dist/unpkg/viewer/dist/types.d.ts +1 -0
- package/dist/unpkg/viewer/dist/viewer-state.d.ts +1 -1
- package/dist/unpkg/viewer/dist/viewer-state.js +1 -1
- package/dist/unpkg/viewer/dist/viewer.js +2 -0
- package/dist/unpkg/worldorbit-core.min.js +12 -12
- package/dist/unpkg/worldorbit-editor.min.js +342 -342
- package/dist/unpkg/worldorbit-markdown.min.js +23 -23
- package/dist/unpkg/worldorbit-viewer.min.js +197 -197
- package/dist/unpkg/worldorbit.js +297 -21
- package/dist/unpkg/worldorbit.min.js +201 -201
- package/package.json +18 -1
- package/packages/core/dist/scene.js +98 -16
- package/packages/core/dist/spatial-scene.js +1 -0
- package/packages/core/dist/types.d.ts +3 -0
- package/packages/editor/dist/editor.js +55 -12
- package/packages/viewer/dist/atlas-state.js +3 -0
- package/packages/viewer/dist/index.d.ts +1 -0
- package/packages/viewer/dist/index.js +1 -0
- package/packages/viewer/dist/interactive-2d.d.ts +21 -0
- package/packages/viewer/dist/interactive-2d.js +201 -0
- package/packages/viewer/dist/render.d.ts +1 -1
- package/packages/viewer/dist/render.js +2 -1
- package/packages/viewer/dist/types.d.ts +1 -0
- package/packages/viewer/dist/viewer-state.d.ts +1 -1
- package/packages/viewer/dist/viewer-state.js +1 -1
- package/packages/viewer/dist/viewer.js +2 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function inferFenceContentStartLine(section) {
|
|
2
|
+
const lines = section.text.split(/\r?\n/);
|
|
3
|
+
const openerIndex = lines.findIndex((line) => /^\s*(```+|~~~+)\s*worldorbit(?:\s+.*)?$/i.test(line));
|
|
4
|
+
return section.lineStart + (openerIndex >= 0 ? openerIndex + 1 : 1);
|
|
5
|
+
}
|
|
6
|
+
export function resolveDiagnosticEditorPosition(contentStartLine, diagnostic) {
|
|
7
|
+
if (!diagnostic.line || diagnostic.line < 1) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
line: contentStartLine + diagnostic.line - 1,
|
|
12
|
+
ch: Math.max((diagnostic.column ?? 1) - 1, 0),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { resolveTheme } from "@worldorbit/viewer/interactive-2d";
|
|
2
|
+
export function createObsidianViewerTheme() {
|
|
3
|
+
const base = resolveTheme("atlas");
|
|
4
|
+
return {
|
|
5
|
+
...base,
|
|
6
|
+
name: "obsidian",
|
|
7
|
+
backgroundStart: "var(--background-primary, #10131a)",
|
|
8
|
+
backgroundEnd: "var(--background-secondary, #171b24)",
|
|
9
|
+
backgroundGlow: "var(--interactive-accent-hover, rgba(143, 202, 255, 0.18))",
|
|
10
|
+
panel: "var(--background-secondary-alt, rgba(10, 16, 24, 0.92))",
|
|
11
|
+
panelLine: "var(--background-modifier-border, rgba(168, 207, 242, 0.2))",
|
|
12
|
+
relation: "var(--text-accent-hover, rgba(240, 180, 100, 0.42))",
|
|
13
|
+
orbit: "var(--text-faint, rgba(163, 209, 255, 0.24))",
|
|
14
|
+
guide: "var(--background-modifier-border-hover, rgba(255, 255, 255, 0.08))",
|
|
15
|
+
leader: "var(--text-muted, rgba(225, 238, 255, 0.4))",
|
|
16
|
+
ink: "var(--text-normal, #e8f0ff)",
|
|
17
|
+
muted: "var(--text-muted, rgba(232, 240, 255, 0.7))",
|
|
18
|
+
accent: "var(--interactive-accent, #f0b464)",
|
|
19
|
+
accentStrong: "var(--text-accent-hover, #ff7f5f)",
|
|
20
|
+
selected: "var(--color-cyan, rgba(255, 214, 139, 0.92))",
|
|
21
|
+
starCore: "var(--color-yellow, #ffcc67)",
|
|
22
|
+
starStroke: "var(--text-normal, rgba(255, 245, 203, 0.85))",
|
|
23
|
+
starGlow: "var(--color-orange, #ffe8a3)",
|
|
24
|
+
objectSpecular: "var(--text-normal, #f5f8ff)",
|
|
25
|
+
selectionHalo: "var(--interactive-accent, rgba(255, 214, 139, 0.9))",
|
|
26
|
+
atmosphere: "var(--color-cyan, rgba(143, 202, 255, 0.4))",
|
|
27
|
+
cometTail: "var(--color-cyan, rgba(193, 243, 255, 0.7))",
|
|
28
|
+
fontFamily: "var(--font-interface, \"Segoe UI\", sans-serif)",
|
|
29
|
+
displayFont: "var(--font-text, var(--font-interface, \"Segoe UI\", sans-serif))",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { EditorPosition } from "obsidian";
|
|
2
|
+
import type { RenderScene, WorldOrbitDiagnostic } from "@worldorbit/core/types";
|
|
3
|
+
import type { WorldOrbitTheme, WorldOrbitViewer2D } from "@worldorbit/viewer/interactive-2d";
|
|
4
|
+
export type EmbeddedInteractionMode = "locked" | "enabled";
|
|
5
|
+
export interface WorldOrbitObsidianPluginSettings {
|
|
6
|
+
embeddedInteraction: EmbeddedInteractionMode;
|
|
7
|
+
showWarnings: boolean;
|
|
8
|
+
showFullscreenButton: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface BlockNavigationContext {
|
|
11
|
+
sourcePath: string;
|
|
12
|
+
contentStartLine: number;
|
|
13
|
+
}
|
|
14
|
+
export interface WorldOrbitEmbeddedViewOptions {
|
|
15
|
+
container: HTMLElement;
|
|
16
|
+
scene: RenderScene;
|
|
17
|
+
theme: WorldOrbitTheme;
|
|
18
|
+
interactive: boolean;
|
|
19
|
+
enablePointer: boolean;
|
|
20
|
+
enableTouch: boolean;
|
|
21
|
+
createViewer?: (container: HTMLElement, options: {
|
|
22
|
+
scene: RenderScene;
|
|
23
|
+
theme: WorldOrbitTheme;
|
|
24
|
+
pointer: boolean;
|
|
25
|
+
touch: boolean;
|
|
26
|
+
width?: number;
|
|
27
|
+
height?: number;
|
|
28
|
+
}) => WorldOrbitViewer2D;
|
|
29
|
+
renderStatic?: (scene: RenderScene, options: {
|
|
30
|
+
theme: WorldOrbitTheme;
|
|
31
|
+
width?: number;
|
|
32
|
+
height?: number;
|
|
33
|
+
}) => string;
|
|
34
|
+
}
|
|
35
|
+
export interface WorldOrbitEmbeddedViewState {
|
|
36
|
+
interactive: boolean;
|
|
37
|
+
destroyed: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface DiagnosticNavigationTarget {
|
|
40
|
+
diagnostic: WorldOrbitDiagnostic;
|
|
41
|
+
position: EditorPosition | null;
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WorldOrbitEmbeddedViewOptions, WorldOrbitEmbeddedViewState } from "./types.js";
|
|
2
|
+
export declare class WorldOrbitEmbeddedView {
|
|
3
|
+
private readonly options;
|
|
4
|
+
private viewer;
|
|
5
|
+
private state;
|
|
6
|
+
constructor(options: WorldOrbitEmbeddedViewOptions);
|
|
7
|
+
getState(): WorldOrbitEmbeddedViewState;
|
|
8
|
+
mount(): void;
|
|
9
|
+
setInteractive(interactive: boolean): void;
|
|
10
|
+
resize(): void;
|
|
11
|
+
destroy(): void;
|
|
12
|
+
private renderCurrent;
|
|
13
|
+
private destroyViewer;
|
|
14
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { createInteractiveViewer2D, renderSceneToSvg, } from "@worldorbit/viewer/interactive-2d";
|
|
2
|
+
export class WorldOrbitEmbeddedView {
|
|
3
|
+
options;
|
|
4
|
+
viewer = null;
|
|
5
|
+
state;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.options = {
|
|
8
|
+
...options,
|
|
9
|
+
createViewer: options.createViewer ?? defaultCreateViewer,
|
|
10
|
+
renderStatic: options.renderStatic ?? defaultRenderStatic,
|
|
11
|
+
};
|
|
12
|
+
this.state = {
|
|
13
|
+
interactive: options.interactive,
|
|
14
|
+
destroyed: false,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
getState() {
|
|
18
|
+
return { ...this.state };
|
|
19
|
+
}
|
|
20
|
+
mount() {
|
|
21
|
+
if (this.state.destroyed) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
this.renderCurrent();
|
|
25
|
+
}
|
|
26
|
+
setInteractive(interactive) {
|
|
27
|
+
if (this.state.destroyed || this.state.interactive === interactive) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
this.state.interactive = interactive;
|
|
31
|
+
this.renderCurrent();
|
|
32
|
+
}
|
|
33
|
+
resize() {
|
|
34
|
+
if (this.state.destroyed) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (this.viewer) {
|
|
38
|
+
const viewport = measureViewport(this.options.container, this.options.scene);
|
|
39
|
+
this.viewer.setRenderOptions(viewport);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this.renderCurrent();
|
|
43
|
+
}
|
|
44
|
+
destroy() {
|
|
45
|
+
if (this.state.destroyed) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this.state.destroyed = true;
|
|
49
|
+
this.destroyViewer();
|
|
50
|
+
clearElement(this.options.container);
|
|
51
|
+
}
|
|
52
|
+
renderCurrent() {
|
|
53
|
+
this.destroyViewer();
|
|
54
|
+
clearElement(this.options.container);
|
|
55
|
+
if (this.state.interactive) {
|
|
56
|
+
const viewport = measureViewport(this.options.container, this.options.scene);
|
|
57
|
+
this.viewer = this.options.createViewer(this.options.container, {
|
|
58
|
+
scene: this.options.scene,
|
|
59
|
+
theme: this.options.theme,
|
|
60
|
+
pointer: this.options.enablePointer,
|
|
61
|
+
touch: this.options.enableTouch,
|
|
62
|
+
...viewport,
|
|
63
|
+
});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const viewport = measureViewport(this.options.container, this.options.scene);
|
|
67
|
+
this.options.container.innerHTML = this.options.renderStatic(this.options.scene, {
|
|
68
|
+
theme: this.options.theme,
|
|
69
|
+
...viewport,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
destroyViewer() {
|
|
73
|
+
this.viewer?.destroy();
|
|
74
|
+
this.viewer = null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function defaultCreateViewer(container, options) {
|
|
78
|
+
return createInteractiveViewer2D(container, options.scene, {
|
|
79
|
+
theme: options.theme,
|
|
80
|
+
pointer: options.pointer,
|
|
81
|
+
touch: options.touch,
|
|
82
|
+
selection: true,
|
|
83
|
+
width: options.width,
|
|
84
|
+
height: options.height,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function defaultRenderStatic(scene, options) {
|
|
88
|
+
return renderSceneToSvg(scene, {
|
|
89
|
+
theme: options.theme,
|
|
90
|
+
width: options.width,
|
|
91
|
+
height: options.height,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function measureViewport(container, scene) {
|
|
95
|
+
const rect = container.getBoundingClientRect();
|
|
96
|
+
const width = sanitizeDimension(container.clientWidth || rect.width) ?? scene.width;
|
|
97
|
+
const height = sanitizeDimension(container.clientHeight || rect.height) ??
|
|
98
|
+
Math.max(Math.round(width * (scene.height / Math.max(scene.width, 1))), 280);
|
|
99
|
+
return { width, height };
|
|
100
|
+
}
|
|
101
|
+
function sanitizeDimension(value) {
|
|
102
|
+
return Number.isFinite(value) && value > 0 ? Math.round(value) : undefined;
|
|
103
|
+
}
|
|
104
|
+
function clearElement(element) {
|
|
105
|
+
if (typeof element.empty === "function") {
|
|
106
|
+
element.empty();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
element.replaceChildren();
|
|
110
|
+
}
|
|
@@ -72,6 +72,7 @@ export function createAtlasStateSnapshot(viewerState, renderOptions, filter, vie
|
|
|
72
72
|
camera: renderOptions.camera ? { ...renderOptions.camera } : null,
|
|
73
73
|
layers: renderOptions.layers ? { ...renderOptions.layers } : undefined,
|
|
74
74
|
scaleModel: renderOptions.scaleModel ? { ...renderOptions.scaleModel } : undefined,
|
|
75
|
+
bodyScaleMode: renderOptions.bodyScaleMode,
|
|
75
76
|
activeEventId: renderOptions.activeEventId ?? null,
|
|
76
77
|
viewMode: renderOptions.viewMode ?? "2d",
|
|
77
78
|
},
|
|
@@ -102,6 +103,7 @@ export function deserializeViewerAtlasState(serialized) {
|
|
|
102
103
|
scaleModel: raw.renderOptions?.scaleModel
|
|
103
104
|
? { ...raw.renderOptions.scaleModel }
|
|
104
105
|
: undefined,
|
|
106
|
+
bodyScaleMode: raw.renderOptions?.bodyScaleMode,
|
|
105
107
|
activeEventId: raw.activeEventId ?? raw.renderOptions?.activeEventId ?? null,
|
|
106
108
|
viewMode: raw.renderOptions?.viewMode ?? "2d",
|
|
107
109
|
},
|
|
@@ -126,6 +128,7 @@ export function createViewerBookmark(name, label, atlasState) {
|
|
|
126
128
|
scaleModel: atlasState.renderOptions.scaleModel
|
|
127
129
|
? { ...atlasState.renderOptions.scaleModel }
|
|
128
130
|
: undefined,
|
|
131
|
+
bodyScaleMode: atlasState.renderOptions.bodyScaleMode,
|
|
129
132
|
activeEventId: atlasState.renderOptions.activeEventId ?? null,
|
|
130
133
|
viewMode: atlasState.renderOptions.viewMode ?? "2d",
|
|
131
134
|
},
|
|
@@ -8,3 +8,4 @@ export { createEmbedPayload, createWorldOrbitEmbedMarkup, deserializeWorldOrbitE
|
|
|
8
8
|
export { defineWorldOrbitViewerElement } from "./custom-element.js";
|
|
9
9
|
export { createAtlasViewer } from "./atlas-viewer.js";
|
|
10
10
|
export { createInteractiveViewer } from "./viewer.js";
|
|
11
|
+
export { createInteractiveViewer2D } from "./interactive-2d.js";
|
|
@@ -7,3 +7,4 @@ export { createEmbedPayload, createWorldOrbitEmbedMarkup, deserializeWorldOrbitE
|
|
|
7
7
|
export { defineWorldOrbitViewerElement } from "./custom-element.js";
|
|
8
8
|
export { createAtlasViewer } from "./atlas-viewer.js";
|
|
9
9
|
export { createInteractiveViewer } from "./viewer.js";
|
|
10
|
+
export { createInteractiveViewer2D } from "./interactive-2d.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RenderScene } from "@worldorbit/core/types";
|
|
2
|
+
import type { SvgRenderOptions, ViewerState } from "./types.js";
|
|
3
|
+
export interface InteractiveViewer2DOptions extends Pick<SvgRenderOptions, "width" | "height" | "padding" | "preset" | "theme" | "layers" | "subtitle"> {
|
|
4
|
+
pointer?: boolean;
|
|
5
|
+
touch?: boolean;
|
|
6
|
+
selection?: boolean;
|
|
7
|
+
minScale?: number;
|
|
8
|
+
maxScale?: number;
|
|
9
|
+
fitPadding?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface WorldOrbitViewer2D {
|
|
12
|
+
getState(): ViewerState;
|
|
13
|
+
setState(state: Partial<ViewerState>): void;
|
|
14
|
+
setRenderOptions(options: Partial<InteractiveViewer2DOptions>): void;
|
|
15
|
+
fitToSystem(): void;
|
|
16
|
+
destroy(): void;
|
|
17
|
+
}
|
|
18
|
+
export { renderSceneToSvg } from "./render.js";
|
|
19
|
+
export { resolveTheme } from "./theme.js";
|
|
20
|
+
export type { WorldOrbitTheme } from "./types.js";
|
|
21
|
+
export declare function createInteractiveViewer2D(container: HTMLElement, scene: RenderScene, options?: InteractiveViewer2DOptions): WorldOrbitViewer2D;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { renderSceneToSvg, WORLD_LAYER_ID } from "./render.js";
|
|
2
|
+
import { DEFAULT_VIEWER_STATE, composeViewerTransform, fitViewerState, panViewerState, zoomViewerStateAt, } from "./viewer-state.js";
|
|
3
|
+
export { renderSceneToSvg } from "./render.js";
|
|
4
|
+
export { resolveTheme } from "./theme.js";
|
|
5
|
+
const DEFAULT_VIEWER_LIMITS = {
|
|
6
|
+
minScale: 0.2,
|
|
7
|
+
maxScale: 8,
|
|
8
|
+
fitPadding: 48,
|
|
9
|
+
};
|
|
10
|
+
export function createInteractiveViewer2D(container, scene, options = {}) {
|
|
11
|
+
const constraints = {
|
|
12
|
+
minScale: options.minScale ?? DEFAULT_VIEWER_LIMITS.minScale,
|
|
13
|
+
maxScale: options.maxScale ?? DEFAULT_VIEWER_LIMITS.maxScale,
|
|
14
|
+
fitPadding: options.fitPadding ?? DEFAULT_VIEWER_LIMITS.fitPadding,
|
|
15
|
+
};
|
|
16
|
+
const behavior = {
|
|
17
|
+
pointer: options.pointer ?? true,
|
|
18
|
+
touch: options.touch ?? true,
|
|
19
|
+
selection: options.selection ?? true,
|
|
20
|
+
};
|
|
21
|
+
let renderOptions = {
|
|
22
|
+
width: options.width,
|
|
23
|
+
height: options.height,
|
|
24
|
+
padding: options.padding,
|
|
25
|
+
preset: options.preset,
|
|
26
|
+
theme: options.theme,
|
|
27
|
+
layers: options.layers,
|
|
28
|
+
subtitle: options.subtitle,
|
|
29
|
+
pointer: behavior.pointer,
|
|
30
|
+
touch: behavior.touch,
|
|
31
|
+
selection: behavior.selection,
|
|
32
|
+
minScale: constraints.minScale,
|
|
33
|
+
maxScale: constraints.maxScale,
|
|
34
|
+
fitPadding: constraints.fitPadding,
|
|
35
|
+
};
|
|
36
|
+
let state = fitViewerState(scene, DEFAULT_VIEWER_STATE, constraints);
|
|
37
|
+
let svgElement = null;
|
|
38
|
+
let cameraRoot = null;
|
|
39
|
+
let destroyed = false;
|
|
40
|
+
let activePointerId = null;
|
|
41
|
+
let lastPointerClientPoint = null;
|
|
42
|
+
let dragDistance = 0;
|
|
43
|
+
const previousTabIndex = container.getAttribute("tabindex");
|
|
44
|
+
const previousTouchAction = container.style.touchAction;
|
|
45
|
+
if (previousTabIndex === null) {
|
|
46
|
+
container.tabIndex = 0;
|
|
47
|
+
}
|
|
48
|
+
container.classList.add("wo-viewer-container");
|
|
49
|
+
container.style.touchAction = behavior.touch ? "none" : previousTouchAction;
|
|
50
|
+
const handleWheel = (event) => {
|
|
51
|
+
if (!behavior.pointer || destroyed || !svgElement) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
container.focus();
|
|
56
|
+
const anchor = getScenePointFromClient(event.clientX, event.clientY);
|
|
57
|
+
const factor = clamp(Math.exp(-event.deltaY * 0.002), 0.6, 1.6);
|
|
58
|
+
updateState(zoomViewerStateAt(scene, state, factor, anchor, constraints));
|
|
59
|
+
};
|
|
60
|
+
const handlePointerDown = (event) => {
|
|
61
|
+
if (destroyed) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const isTouch = event.pointerType === "touch";
|
|
65
|
+
if ((isTouch && !behavior.touch) || (!isTouch && !behavior.pointer)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (!isTouch && event.button !== 0) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
activePointerId = event.pointerId;
|
|
72
|
+
lastPointerClientPoint = { x: event.clientX, y: event.clientY };
|
|
73
|
+
dragDistance = 0;
|
|
74
|
+
container.setPointerCapture?.(event.pointerId);
|
|
75
|
+
container.focus();
|
|
76
|
+
};
|
|
77
|
+
const handlePointerMove = (event) => {
|
|
78
|
+
if (destroyed || activePointerId !== event.pointerId || !lastPointerClientPoint) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const rect = svgElement?.getBoundingClientRect();
|
|
82
|
+
if (!rect || rect.width <= 0 || rect.height <= 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const dx = event.clientX - lastPointerClientPoint.x;
|
|
86
|
+
const dy = event.clientY - lastPointerClientPoint.y;
|
|
87
|
+
lastPointerClientPoint = { x: event.clientX, y: event.clientY };
|
|
88
|
+
dragDistance += Math.hypot(dx, dy);
|
|
89
|
+
updateState(panViewerState(state, dx * (scene.width / rect.width), dy * (scene.height / rect.height)));
|
|
90
|
+
};
|
|
91
|
+
const stopPointer = (event) => {
|
|
92
|
+
if (activePointerId !== event.pointerId) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
activePointerId = null;
|
|
96
|
+
lastPointerClientPoint = null;
|
|
97
|
+
container.releasePointerCapture?.(event.pointerId);
|
|
98
|
+
};
|
|
99
|
+
const handleClick = (event) => {
|
|
100
|
+
if (destroyed || !behavior.selection || dragDistance > 6) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const objectEl = event.target?.closest(".wo-object[data-object-id]");
|
|
104
|
+
if (!objectEl) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
updateState({
|
|
108
|
+
...state,
|
|
109
|
+
selectedObjectId: objectEl.dataset.objectId ?? null,
|
|
110
|
+
});
|
|
111
|
+
renderSvg();
|
|
112
|
+
};
|
|
113
|
+
container.addEventListener("wheel", handleWheel, { passive: false });
|
|
114
|
+
container.addEventListener("pointerdown", handlePointerDown);
|
|
115
|
+
container.addEventListener("pointermove", handlePointerMove);
|
|
116
|
+
container.addEventListener("pointerup", stopPointer);
|
|
117
|
+
container.addEventListener("pointercancel", stopPointer);
|
|
118
|
+
container.addEventListener("click", handleClick);
|
|
119
|
+
renderSvg();
|
|
120
|
+
return {
|
|
121
|
+
getState() {
|
|
122
|
+
return { ...state };
|
|
123
|
+
},
|
|
124
|
+
setState(nextState) {
|
|
125
|
+
updateState({
|
|
126
|
+
...state,
|
|
127
|
+
...nextState,
|
|
128
|
+
});
|
|
129
|
+
if ("selectedObjectId" in nextState) {
|
|
130
|
+
renderSvg();
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
setRenderOptions(nextOptions) {
|
|
134
|
+
renderOptions = {
|
|
135
|
+
...renderOptions,
|
|
136
|
+
...nextOptions,
|
|
137
|
+
};
|
|
138
|
+
renderSvg();
|
|
139
|
+
},
|
|
140
|
+
fitToSystem() {
|
|
141
|
+
updateState(fitViewerState(scene, state, constraints));
|
|
142
|
+
},
|
|
143
|
+
destroy() {
|
|
144
|
+
if (destroyed) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
destroyed = true;
|
|
148
|
+
container.removeEventListener("wheel", handleWheel);
|
|
149
|
+
container.removeEventListener("pointerdown", handlePointerDown);
|
|
150
|
+
container.removeEventListener("pointermove", handlePointerMove);
|
|
151
|
+
container.removeEventListener("pointerup", stopPointer);
|
|
152
|
+
container.removeEventListener("pointercancel", stopPointer);
|
|
153
|
+
container.removeEventListener("click", handleClick);
|
|
154
|
+
if (previousTabIndex === null) {
|
|
155
|
+
container.removeAttribute("tabindex");
|
|
156
|
+
}
|
|
157
|
+
container.style.touchAction = previousTouchAction;
|
|
158
|
+
container.replaceChildren();
|
|
159
|
+
svgElement = null;
|
|
160
|
+
cameraRoot = null;
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
function renderSvg() {
|
|
164
|
+
if (destroyed) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
container.innerHTML = renderSceneToSvg(scene, {
|
|
168
|
+
width: renderOptions.width,
|
|
169
|
+
height: renderOptions.height,
|
|
170
|
+
padding: renderOptions.padding,
|
|
171
|
+
preset: renderOptions.preset,
|
|
172
|
+
theme: renderOptions.theme,
|
|
173
|
+
layers: renderOptions.layers,
|
|
174
|
+
subtitle: renderOptions.subtitle,
|
|
175
|
+
selectedObjectId: state.selectedObjectId,
|
|
176
|
+
});
|
|
177
|
+
svgElement = container.querySelector("svg");
|
|
178
|
+
cameraRoot = container.querySelector(`[data-worldorbit-camera-root="${WORLD_LAYER_ID}"]`);
|
|
179
|
+
applyTransform();
|
|
180
|
+
}
|
|
181
|
+
function applyTransform() {
|
|
182
|
+
cameraRoot?.setAttribute("transform", composeViewerTransform(scene, state));
|
|
183
|
+
}
|
|
184
|
+
function updateState(nextState) {
|
|
185
|
+
state = nextState;
|
|
186
|
+
applyTransform();
|
|
187
|
+
}
|
|
188
|
+
function getScenePointFromClient(clientX, clientY) {
|
|
189
|
+
const rect = svgElement?.getBoundingClientRect();
|
|
190
|
+
if (!rect || rect.width <= 0 || rect.height <= 0) {
|
|
191
|
+
return { x: scene.width / 2, y: scene.height / 2 };
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
x: ((clientX - rect.left) / rect.width) * scene.width,
|
|
195
|
+
y: ((clientY - rect.top) / rect.height) * scene.height,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function clamp(value, min, max) {
|
|
200
|
+
return Math.min(Math.max(value, min), max);
|
|
201
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type RenderScene, type WorldOrbitDocument } from "@worldorbit/core";
|
|
1
|
+
import { type RenderScene, type WorldOrbitDocument } from "@worldorbit/core/types";
|
|
2
2
|
import type { SvgRenderOptions } from "./types.js";
|
|
3
3
|
export declare const WORLD_LAYER_ID = "worldorbit-camera-root";
|
|
4
4
|
export declare function renderSceneToSvg(scene: RenderScene, options?: SvgRenderOptions): string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { loadWorldOrbitSource
|
|
1
|
+
import { loadWorldOrbitSource } from "@worldorbit/core/load";
|
|
2
|
+
import { renderDocumentToScene } from "@worldorbit/core/scene";
|
|
2
3
|
import { computeVisibleObjectIds } from "./atlas-state.js";
|
|
3
4
|
import { resolveLayers, resolveTheme } from "./theme.js";
|
|
4
5
|
export const WORLD_LAYER_ID = "worldorbit-camera-root";
|
|
@@ -129,6 +129,7 @@ export interface ViewerAtlasState {
|
|
|
129
129
|
camera?: WorldOrbitViewCamera | null;
|
|
130
130
|
layers?: ViewerLayerOptions;
|
|
131
131
|
scaleModel?: Partial<RenderScaleModel>;
|
|
132
|
+
bodyScaleMode?: SceneRenderOptions["bodyScaleMode"];
|
|
132
133
|
activeEventId?: string | null;
|
|
133
134
|
viewMode?: WorldOrbitViewMode;
|
|
134
135
|
quality?: WorldOrbit3DQuality;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CoordinatePoint, type RenderBounds, type RenderScene } from "@worldorbit/core";
|
|
1
|
+
import { type CoordinatePoint, type RenderBounds, type RenderScene } from "@worldorbit/core/types";
|
|
2
2
|
import type { ViewerState } from "./types.js";
|
|
3
3
|
export interface ViewerConstraints {
|
|
4
4
|
minScale: number;
|
|
@@ -44,6 +44,7 @@ export function createInteractiveViewer(container, options) {
|
|
|
44
44
|
padding: options.padding,
|
|
45
45
|
preset: options.preset,
|
|
46
46
|
projection: options.projection,
|
|
47
|
+
bodyScaleMode: options.bodyScaleMode,
|
|
47
48
|
viewMode: options.viewMode ?? "2d",
|
|
48
49
|
quality: options.quality ?? "balanced",
|
|
49
50
|
style3d: options.style3d ?? "symbolic",
|
|
@@ -1595,6 +1596,7 @@ function hasSceneAffectingRenderOptions(options) {
|
|
|
1595
1596
|
options.projection !== undefined ||
|
|
1596
1597
|
options.camera !== undefined ||
|
|
1597
1598
|
options.scaleModel !== undefined ||
|
|
1599
|
+
options.bodyScaleMode !== undefined ||
|
|
1598
1600
|
options.activeEventId !== undefined);
|
|
1599
1601
|
}
|
|
1600
1602
|
function resolveSourceRenderOptions(loaded, renderOptions) {
|