worldorbit 3.0.5 → 3.0.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "worldorbit",
3
- "version": "3.0.5",
3
+ "version": "3.0.7",
4
4
  "description": "A text-based DSL and parser pipeline for orbital worldbuilding",
5
5
  "type": "module",
6
6
  "main": "./dist/unpkg/worldorbit.esm.js",
@@ -67,6 +67,7 @@ export function createWorldOrbitEmbedMarkup(payload, options = {}) {
67
67
  }
68
68
  export function mountWorldOrbitEmbeds(root = document, options = {}) {
69
69
  const viewers = new Map();
70
+ const cleanupCallbacks = [];
70
71
  const elements = [...root.querySelectorAll(EMBED_SELECTOR)];
71
72
  for (const element of elements) {
72
73
  const payload = deserializePayloadFromElement(element);
@@ -82,14 +83,16 @@ export function mountWorldOrbitEmbeds(root = document, options = {}) {
82
83
  const viewMode = options.viewer?.viewMode ??
83
84
  payload.options?.viewMode ??
84
85
  embedModeToViewMode(mode);
86
+ const measureViewport = () => resolveEmbedViewport(element, payload.scene, options);
85
87
  if (mode === "interactive-2d" || mode === "interactive-3d") {
86
88
  try {
89
+ const viewport = measureViewport();
87
90
  const viewer = createInteractiveViewer(element, {
88
91
  ...options.viewer,
89
92
  scene: payload.scene,
90
93
  spatialScene: payload.spatialScene,
91
- width: options.width ?? payload.scene.width,
92
- height: options.height ?? payload.scene.height,
94
+ width: viewport.width,
95
+ height: viewport.height,
93
96
  padding: options.padding ?? payload.scene.padding,
94
97
  preset,
95
98
  theme,
@@ -105,6 +108,13 @@ export function mountWorldOrbitEmbeds(root = document, options = {}) {
105
108
  viewer.setAtlasState(payload.options.atlasState);
106
109
  }
107
110
  viewers.set(element, viewer);
111
+ cleanupCallbacks.push(bindEmbedResize(element, () => {
112
+ const nextViewport = measureViewport();
113
+ viewer.setRenderOptions({
114
+ width: nextViewport.width,
115
+ height: nextViewport.height,
116
+ });
117
+ }));
108
118
  options.onMount?.(viewer, element);
109
119
  }
110
120
  catch (error) {
@@ -118,17 +128,22 @@ export function mountWorldOrbitEmbeds(root = document, options = {}) {
118
128
  }
119
129
  }
120
130
  else {
121
- element.innerHTML = renderSceneToSvg(payload.scene, {
122
- width: options.width ?? payload.scene.width,
123
- height: options.height ?? payload.scene.height,
124
- padding: options.padding ?? payload.scene.padding,
125
- preset,
126
- theme,
127
- layers,
128
- filter: initialFilter,
129
- selectedObjectId: initialSelectionObjectId ?? null,
130
- subtitle,
131
- });
131
+ const renderStaticEmbed = () => {
132
+ const viewport = measureViewport();
133
+ element.innerHTML = renderSceneToSvg(payload.scene, {
134
+ width: viewport.width,
135
+ height: viewport.height,
136
+ padding: options.padding ?? payload.scene.padding,
137
+ preset,
138
+ theme,
139
+ layers,
140
+ filter: initialFilter,
141
+ selectedObjectId: initialSelectionObjectId ?? null,
142
+ subtitle,
143
+ });
144
+ };
145
+ renderStaticEmbed();
146
+ cleanupCallbacks.push(bindEmbedResize(element, renderStaticEmbed));
132
147
  options.onMount?.(null, element);
133
148
  }
134
149
  element.dataset.worldorbitMounted = "true";
@@ -136,14 +151,72 @@ export function mountWorldOrbitEmbeds(root = document, options = {}) {
136
151
  return {
137
152
  viewers: [...viewers.values()],
138
153
  destroy() {
154
+ for (const cleanup of cleanupCallbacks) {
155
+ cleanup();
156
+ }
139
157
  for (const [element, viewer] of viewers.entries()) {
140
158
  viewer.destroy();
141
159
  element.removeAttribute("data-worldorbit-mounted");
142
160
  }
161
+ for (const element of elements) {
162
+ element.removeAttribute("data-worldorbit-mounted");
163
+ }
143
164
  viewers.clear();
144
165
  },
145
166
  };
146
167
  }
168
+ function resolveEmbedViewport(element, scene, options) {
169
+ const rect = element.getBoundingClientRect();
170
+ const width = sanitizeViewportDimension(options.width) ??
171
+ sanitizeViewportDimension(element.clientWidth) ??
172
+ sanitizeViewportDimension(rect.width) ??
173
+ scene.width;
174
+ const explicitHeight = sanitizeViewportDimension(options.height) ??
175
+ sanitizeViewportDimension(element.clientHeight) ??
176
+ sanitizeViewportDimension(rect.height);
177
+ const fallbackHeight = Math.max(Math.round(width * (scene.height / Math.max(scene.width, 1))), Math.min(scene.height, 240));
178
+ return {
179
+ width,
180
+ height: explicitHeight ?? fallbackHeight,
181
+ };
182
+ }
183
+ function sanitizeViewportDimension(value) {
184
+ return typeof value === "number" && Number.isFinite(value) && value > 0
185
+ ? Math.round(value)
186
+ : null;
187
+ }
188
+ function bindEmbedResize(element, callback) {
189
+ let lastWidth = -1;
190
+ let lastHeight = -1;
191
+ const run = () => {
192
+ const rect = element.getBoundingClientRect();
193
+ const nextWidth = Math.round(Math.max(element.clientWidth || rect.width, 0));
194
+ const nextHeight = Math.round(Math.max(element.clientHeight || rect.height, 0));
195
+ if (nextWidth === lastWidth && nextHeight === lastHeight) {
196
+ return;
197
+ }
198
+ lastWidth = nextWidth;
199
+ lastHeight = nextHeight;
200
+ callback();
201
+ };
202
+ run();
203
+ if (typeof ResizeObserver !== "undefined") {
204
+ const observer = new ResizeObserver(() => {
205
+ run();
206
+ });
207
+ observer.observe(element);
208
+ return () => {
209
+ observer.disconnect();
210
+ };
211
+ }
212
+ const handleWindowResize = () => {
213
+ run();
214
+ };
215
+ window.addEventListener("resize", handleWindowResize);
216
+ return () => {
217
+ window.removeEventListener("resize", handleWindowResize);
218
+ };
219
+ }
147
220
  function deserializePayloadFromElement(element) {
148
221
  const serialized = element.dataset.worldorbitPayload;
149
222
  if (!serialized) {