@preference-sl/pref-viewer 2.11.0-beta.2 → 2.11.0-beta.20

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.
@@ -1,59 +1,68 @@
1
- import "@panzoom/panzoom";
1
+ // Explicitly target the ESM bundle so esbuild (platform=node) picks up the default export.
2
+ import Panzoom from "@panzoom/panzoom/dist/panzoom.es.js";
2
3
 
3
4
  /**
4
- * PanzoomController - Encapsulates the logic for managing pan and zoom interactions on a given DOM element.
5
+ * PanzoomController - Encapsulates logic for managing pan and zoom interactions on a DOM element using the Panzoom library.
5
6
  *
6
- * Responsibilities:
7
- * - Provides an interface to enable, disable, and control pan/zoom interactions.
8
- * - Manages event listeners for mouse, keyboard, and touch interactions.
9
- * - Tracks the current pan/zoom state and invokes a callback when the state changes.
10
- * - Supports zooming in/out, panning, resetting, and mouse wheel zoom.
7
+ * Summary:
8
+ * Provides a high-level API to enable, disable, and control pan/zoom interactions for SVG or other DOM content.
9
+ * Manages event listeners for mouse, keyboard, and touch interactions, and tracks the current pan/zoom state.
10
+ * Supports zooming in/out, panning, resetting, and mouse wheel zoom, with customizable options and callbacks.
11
+ *
12
+ * Key Responsibilities:
13
+ * - Initializes and manages a Panzoom instance for a wrapper element.
14
+ * - Handles enabling/disabling pan/zoom and related event listeners.
15
+ * - Tracks and exposes the current pan/zoom state.
16
+ * - Supports keyboard shortcuts, mouse wheel zoom, and context menu prevention.
17
+ * - Provides methods for panning, zooming, and resetting the view.
18
+ * - Invokes a callback when the pan/zoom state changes.
11
19
  *
12
20
  * Usage:
13
- * - Instantiate the controller with a DOM element and optional configuration:
14
- * const controller = new PanzoomController(wrapperElement, options, stateChangeCallback);
15
- * - Use public methods like `enable()`, `zoomIn()`, `pan(x, y)`, etc., to control interactions.
16
- * - Call `disable()` to remove all event listeners and destroy the Panzoom instance.
21
+ * - Instantiate: const controller = new PanzoomController(wrapperElement, options, stateChangeCallback);
22
+ * - Enable pan/zoom: controller.enable();
23
+ * - Enable events: controller.enableEvents();
24
+ * - Control view: controller.pan(x, y), controller.zoomIn(), controller.zoomOut(), controller.reset();
25
+ * - Disable pan/zoom and events: controller.disable(), controller.disableEvents();
17
26
  *
18
27
  * Constructor Parameters:
19
- * - `wrapper` (HTMLElement): The DOM element to apply pan/zoom interactions to.
20
- * - `options` (object): Configuration options for Panzoom (e.g., minScale, maxScale, step).
21
- * - `changedCallback` (function): Optional callback invoked when the pan/zoom state changes.
28
+ * - wrapper (HTMLElement): The DOM element to apply pan/zoom interactions to.
29
+ * - options (object): Configuration options for Panzoom (e.g., minScale, maxScale, step).
30
+ * - changedCallback (function): Optional callback invoked when the pan/zoom state changes.
22
31
  *
23
32
  * Public Methods:
24
- * - `enable()`: Enables the Panzoom instance and initializes it if not already enabled.
25
- * - `disable()`: Disables the Panzoom instance and removes all event listeners.
26
- * - `enableEvents()`: Attaches all required event listeners for interactions.
27
- * - `disableEvents()`: Removes all previously attached event listeners.
28
- * - `pan(x, y)`: Pans the view to the specified coordinates.
29
- * - `reset()`: Resets pan and zoom to fit the entire content within the available space.
30
- * - `zoomIn(focal?)`: Zooms in by one step, optionally centered on a focal point.
31
- * - `zoomOut(focal?)`: Zooms out by one step, optionally centered on a focal point.
33
+ * - enable(): Enables the Panzoom instance and initializes it if not already enabled.
34
+ * - disable(): Disables the Panzoom instance and removes all event listeners.
35
+ * - enableEvents(): Attaches all required event listeners for interactions.
36
+ * - disableEvents(): Removes all previously attached event listeners.
37
+ * - pan(x, y): Pans the view to the specified coordinates.
38
+ * - reset(): Resets pan and zoom to fit the entire content within the available space.
39
+ * - zoomIn(focal?): Zooms in by one step, optionally centered on a focal point.
40
+ * - zoomOut(focal?): Zooms out by one step, optionally centered on a focal point.
32
41
  *
33
42
  * Getters:
34
- * - `panzoom`: Returns the current Panzoom instance or `null` if not initialized.
35
- * - `state`: Returns the current pan/zoom state (e.g., moved, scaled, maximized, minimized).
43
+ * - panzoom: Returns the current Panzoom instance or null if not initialized.
44
+ * - state: Returns the current pan/zoom state (moved, scaled, maximized, minimized).
36
45
  *
37
46
  * Private Methods:
38
- * - `#checkPanzoomState(transform)`: Updates the internal state and invokes the state change callback.
39
- * - `#resetTransform()`: Resets the transform applied to the wrapper element.
40
- * - `#setFocus()`: Sets focus on the parent element to enable keyboard interactions.
41
- * - `#onPanzoomStart(e)`: Handles the start of a pan/zoom interaction.
42
- * - `#onPanzoomChange(e)`: Handles changes in pan/zoom state.
43
- * - `#onPanzoomEnd(e)`: Handles the end of a pan/zoom interaction.
44
- * - `#onZoomWithWheel(e)`: Handles zoom interactions via the mouse wheel.
45
- * - `#enableMouseWheelZoom()`: Enables zooming with the mouse wheel.
46
- * - `#disableMouseWheelZoom()`: Disables zooming with the mouse wheel.
47
- * - `#getDistanceBetweenPoints(point1, point2)`: Calculates the Euclidean distance between two points.
48
- * - `#getPointFromEvent(e)`: Extracts client coordinates from a mouse or touch event.
47
+ * - #bindHandlers(): Pre-binds reusable event handlers to preserve stable references.
48
+ * - #checkPanzoomState(transform): Updates the internal state and invokes the state change callback.
49
+ * - #resetTransform(): Resets the transform applied to the wrapper element.
50
+ * - #setFocus(): Sets focus on the parent element to enable keyboard interactions.
51
+ * - #onPanzoomStart(e): Handles the start of a pan/zoom interaction.
52
+ * - #onPanzoomChange(e): Handles changes in pan/zoom state.
53
+ * - #onPanzoomEnd(e): Handles the end of a pan/zoom interaction.
54
+ * - #onZoomWithWheel(e): Handles zoom interactions via the mouse wheel.
55
+ * - #enableMouseWheelZoom(): Enables zooming with the mouse wheel.
56
+ * - #disableMouseWheelZoom(): Disables zooming with the mouse wheel.
57
+ * - #getDistanceBetweenPoints(point1, point2): Calculates the Euclidean distance between two points.
58
+ * - #getPointFromEvent(e): Extracts client coordinates from a mouse or touch event.
49
59
  *
50
60
  * Notes:
51
61
  * - Designed to work with the Panzoom library for managing pan/zoom interactions.
52
- * - Provides a clean separation of concerns by encapsulating all pan/zoom logic in a single class.
62
+ * - Encapsulates all pan/zoom logic in a single class for clean separation of concerns.
53
63
  * - Can be extended or customized by overriding methods or providing additional options.
54
64
  */
55
65
  export default class PanzoomController {
56
- #changedCallback = null;
57
66
  #interactionOptions = {
58
67
  clickThreshold: 6, // Threshold to avoid false clicks on elements when panning or zooming
59
68
  };
@@ -79,11 +88,40 @@ export default class PanzoomController {
79
88
  minimized: false,
80
89
  };
81
90
  #wrapper = null;
82
-
91
+
92
+ #changedCallback = null;
93
+ #handlers = {
94
+ panzoomStart: null,
95
+ panzoomChange: null,
96
+ panzoomEnd: null,
97
+ keyUp: null,
98
+ focus: null,
99
+ blur: null,
100
+ contextMenu: null,
101
+ wheel: null,
102
+ };
103
+
83
104
  constructor(wrapper = null, options = {}, changedCallback = null) {
84
105
  this.#wrapper = wrapper;
85
106
  Object.assign(this.#options, options);
86
107
  this.#changedCallback = changedCallback;
108
+ this.#bindHandlers();
109
+ }
110
+
111
+ /**
112
+ * Pre-binds reusable event handlers to preserve stable references.
113
+ * @private
114
+ * @returns {void}
115
+ */
116
+ #bindHandlers() {
117
+ this.#handlers.panzoomStart = this.#onPanzoomStart.bind(this);
118
+ this.#handlers.panzoomChange = this.#onPanzoomChange.bind(this);
119
+ this.#handlers.panzoomEnd = this.#onPanzoomEnd.bind(this);
120
+ this.#handlers.keyUp = this.#onKeyUp.bind(this);
121
+ this.#handlers.focus = this.#enableMouseWheelZoom.bind(this);
122
+ this.#handlers.blur = this.#disableMouseWheelZoom.bind(this);
123
+ this.#handlers.contextMenu = this.#onContextMenu.bind(this);
124
+ this.#handlers.wheel = this.#onZoomWithWheel.bind(this);
87
125
  }
88
126
 
89
127
  /**
@@ -294,7 +332,7 @@ export default class PanzoomController {
294
332
  if (!this.#panzoom) {
295
333
  return;
296
334
  }
297
- this.#wrapper.parentElement.removeEventListener("wheel", this.#onZoomWithWheel.bind(this));
335
+ this.#wrapper.parentElement.removeEventListener("wheel", this.#handlers.wheel);
298
336
  }
299
337
 
300
338
  /**
@@ -309,7 +347,7 @@ export default class PanzoomController {
309
347
  return;
310
348
  }
311
349
  this.#disableMouseWheelZoom();
312
- this.#wrapper.parentElement.addEventListener("wheel", this.#onZoomWithWheel.bind(this));
350
+ this.#wrapper.parentElement.addEventListener("wheel", this.#handlers.wheel);
313
351
  }
314
352
 
315
353
  /**
@@ -363,13 +401,13 @@ export default class PanzoomController {
363
401
 
364
402
  this.disableEvents();
365
403
 
366
- this.#wrapper.addEventListener("panzoomstart", this.#onPanzoomStart.bind(this));
367
- this.#wrapper.addEventListener("panzoomchange", this.#onPanzoomChange.bind(this));
368
- this.#wrapper.addEventListener("panzoomend", this.#onPanzoomEnd.bind(this));
369
- this.#wrapper.parentElement.addEventListener("keyup", this.#onKeyUp.bind(this));
370
- this.#wrapper.parentElement.addEventListener("focus", this.#enableMouseWheelZoom.bind(this), true);
371
- this.#wrapper.parentElement.addEventListener("blur", this.#disableMouseWheelZoom.bind(this), true);
372
- this.#wrapper.parentElement.addEventListener("contextmenu", this.#onContextMenu);
404
+ this.#wrapper.addEventListener("panzoomstart", this.#handlers.panzoomStart);
405
+ this.#wrapper.addEventListener("panzoomchange", this.#handlers.panzoomChange);
406
+ this.#wrapper.addEventListener("panzoomend", this.#handlers.panzoomEnd);
407
+ this.#wrapper.parentElement.addEventListener("keyup", this.#handlers.keyUp);
408
+ this.#wrapper.parentElement.addEventListener("focus", this.#handlers.focus, true);
409
+ this.#wrapper.parentElement.addEventListener("blur", this.#handlers.blur, true);
410
+ this.#wrapper.parentElement.addEventListener("contextmenu", this.#handlers.contextMenu);
373
411
  this.#wrapper.parentElement.setAttribute("tabindex", 0);
374
412
  this.#setFocus();
375
413
  }
@@ -385,13 +423,13 @@ export default class PanzoomController {
385
423
  return;
386
424
  }
387
425
  this.#wrapper.parentElement.removeAttribute("tabindex");
388
- this.#wrapper.removeEventListener("panzoomstart", this.#onPanzoomStart.bind(this));
389
- this.#wrapper.removeEventListener("panzoomchange", this.#onPanzoomChange.bind(this));
390
- this.#wrapper.removeEventListener("panzoomend", this.#onPanzoomEnd.bind(this));
391
- this.#wrapper.parentElement.removeEventListener("keyup", this.#onKeyUp.bind(this));
392
- this.#wrapper.parentElement.removeEventListener("focus", this.#enableMouseWheelZoom.bind(this));
393
- this.#wrapper.parentElement.removeEventListener("blur", this.#disableMouseWheelZoom.bind(this));
394
- this.#wrapper.parentElement.removeEventListener("contextmenu", this.#onContextMenu);
426
+ this.#wrapper.removeEventListener("panzoomstart", this.#handlers.panzoomStart);
427
+ this.#wrapper.removeEventListener("panzoomchange", this.#handlers.panzoomChange);
428
+ this.#wrapper.removeEventListener("panzoomend", this.#handlers.panzoomEnd);
429
+ this.#wrapper.parentElement.removeEventListener("keyup", this.#handlers.keyUp);
430
+ this.#wrapper.parentElement.removeEventListener("focus", this.#handlers.focus);
431
+ this.#wrapper.parentElement.removeEventListener("blur", this.#handlers.blur);
432
+ this.#wrapper.parentElement.removeEventListener("contextmenu", this.#handlers.contextMenu);
395
433
  }
396
434
 
397
435
  /**
@@ -1,5 +1,6 @@
1
1
  import SVGResolver from "./svg-resolver.js";
2
2
  import PanzoomController from "./panzoom-controller.js";
3
+ import { PrefViewer2DStyles } from "./styles.js";
3
4
 
4
5
  /**
5
6
  * PrefViewer2D - Custom element for rendering and interacting with 2D SVG content.
@@ -46,7 +47,7 @@ import PanzoomController from "./panzoom-controller.js";
46
47
  * Notes on extensibility
47
48
  * - Modeled for easy addition of other input sources or interaction modes (e.g., selection callbacks).
48
49
  */
49
- export class PrefViewer2D extends HTMLElement {
50
+ export default class PrefViewer2D extends HTMLElement {
50
51
  // State flags
51
52
  #isInitialized = false;
52
53
  #isLoaded = false;
@@ -68,6 +69,10 @@ export class PrefViewer2D extends HTMLElement {
68
69
  #wrapper = null; // Panzoom element
69
70
  #panzoomController = null; // PanzoomController instance
70
71
 
72
+ #handlers = {
73
+ onPanzoomChanged: null,
74
+ };
75
+
71
76
  /**
72
77
  * Create a new instance of the 2D viewer component.
73
78
  * The constructor only calls super(); heavy initialization happens in connectedCallback.
@@ -114,6 +119,7 @@ export class PrefViewer2D extends HTMLElement {
114
119
  /**
115
120
  * Called when the element is inserted into the DOM.
116
121
  * Sets up DOM nodes, initial visibility and starts loading the SVG if provided.
122
+ * @public
117
123
  * @returns {void}
118
124
  */
119
125
  connectedCallback() {
@@ -127,6 +133,7 @@ export class PrefViewer2D extends HTMLElement {
127
133
  /**
128
134
  * Called when the element is removed from the DOM.
129
135
  * Disables the PanzoomController to clean up event listeners and resources.
136
+ * @public
130
137
  * @returns {void}
131
138
  */
132
139
  disconnectedCallback() {
@@ -143,8 +150,9 @@ export class PrefViewer2D extends HTMLElement {
143
150
  #createDOMElements() {
144
151
  this.#wrapper = document.createElement("div");
145
152
  this.append(this.#wrapper);
153
+
146
154
  const style = document.createElement("style");
147
- style.textContent = `pref-viewer-2d[visible="true"] { display: block; } pref-viewer-2d[visible="false"] { display: none; } pref-viewer-2d, pref-viewer-2d > div, pref-viewer-2d > div > svg { width: 100%; height: 100%; display: block; position: relative; outline: none; box-sizing: border-box; } pref-viewer-2d > div > svg { padding: 10px; }`;
155
+ style.textContent = PrefViewer2DStyles;
148
156
  this.append(style);
149
157
  }
150
158
 
@@ -166,7 +174,8 @@ export class PrefViewer2D extends HTMLElement {
166
174
  * @returns {void}
167
175
  */
168
176
  #initializePanzoom() {
169
- this.#panzoomController = new PanzoomController(this.#wrapper, undefined, this.#onPanzoomChanged.bind(this));
177
+ this.#handlers.onPanzoomChanged = this.#onPanzoomChanged.bind(this);
178
+ this.#panzoomController = new PanzoomController(this.#wrapper, undefined, this.#handlers.onPanzoomChanged);
170
179
  }
171
180
 
172
181
  /**
@@ -221,9 +230,9 @@ export class PrefViewer2D extends HTMLElement {
221
230
  const error = "PrefViewer2D: Error in SVG provided for loading. Ensure the SVG is a URL to an SVG file, a string containing a SVG, or a string containing a base64-encoded SVG.";
222
231
  const detail = { error: new Error(error) };
223
232
  const customEventOptions = {
224
- bubbles: true,
225
- cancelable: false,
226
- composed: true,
233
+ bubbles: true, // indicates whether the event bubbles up through the DOM tree or not
234
+ cancelable: true, // indicates whether the event can be canceled, and therefore prevented as if the event never happened
235
+ composed: false, // indicates whether or not the event will propagate across the shadow DOM boundary into the standard DOM
227
236
  detail: detail,
228
237
  };
229
238
  this.dispatchEvent(new CustomEvent("drawing-error", customEventOptions));
@@ -238,8 +247,8 @@ export class PrefViewer2D extends HTMLElement {
238
247
  #onLoaded() {
239
248
  const customEventOptions = {
240
249
  bubbles: true,
241
- cancelable: false,
242
- composed: true,
250
+ cancelable: true,
251
+ composed: false,
243
252
  };
244
253
  this.dispatchEvent(new CustomEvent("drawing-loaded", customEventOptions));
245
254
 
@@ -258,8 +267,8 @@ export class PrefViewer2D extends HTMLElement {
258
267
  #onLoading() {
259
268
  const customEventOptions = {
260
269
  bubbles: true,
261
- cancelable: false,
262
- composed: true,
270
+ cancelable: true,
271
+ composed: false,
263
272
  };
264
273
  this.dispatchEvent(new CustomEvent("drawing-loading", customEventOptions));
265
274
 
@@ -285,10 +294,11 @@ export class PrefViewer2D extends HTMLElement {
285
294
  #onPanzoomChanged(state) {
286
295
  const customEventOptions = {
287
296
  bubbles: true,
288
- cancelable: false,
289
- composed: true,
297
+ cancelable: true,
298
+ composed: false,
290
299
  detail: state,
291
300
  };
301
+ customEventOptions.detail.desde2d = "true";
292
302
  this.dispatchEvent(new CustomEvent("drawing-zoom-changed", customEventOptions));
293
303
  }
294
304
 
@@ -348,6 +358,9 @@ export class PrefViewer2D extends HTMLElement {
348
358
  * - Resolves to { success: true, error: null } when the SVG was accepted and the component has started rendering.
349
359
  */
350
360
  async load(svgConfig) {
361
+ if (!this.#svgResolver) {
362
+ this.#svgResolver = new SVGResolver(this.#svg);
363
+ }
351
364
  if (!svgConfig || !(await this.#svgResolver.getSVG(svgConfig))) {
352
365
  const errorDetail = this.#onError();
353
366
  return { success: false, ...errorDetail };
@@ -46,7 +46,7 @@ export class ContainerData {
46
46
  this.update.pending = true;
47
47
  this.update.storage = storage;
48
48
  this.update.success = false;
49
- this.update.show = show !== undefined ? show : this.update.show;
49
+ this.update.show = show !== undefined ? show : this.update.show !== null ? this.update.show : this.show;
50
50
  }
51
51
  setPendingCacheData(size = 0, timeStamp = null) {
52
52
  this.update.size = size;
@@ -62,7 +62,7 @@ export class ContainerData {
62
62
  return this.visible === true;
63
63
  }
64
64
  get mustBeShown() {
65
- return this.show === true;
65
+ return this.update.show !== null ? this.update.show === true : this.show === true;
66
66
  }
67
67
  }
68
68
 
@@ -152,6 +152,7 @@ export class CameraData {
152
152
  if (success) {
153
153
  this.update.success = true;
154
154
  this.value = this.update.value;
155
+ this.locked = this.update.locked;
155
156
  } else {
156
157
  this.update.success = false;
157
158
  }
@@ -1,5 +1,6 @@
1
- import { ContainerData, MaterialData, CameraData } from "./pref-viewer-3d-data.js";
1
+ import { CameraData, ContainerData, MaterialData } from "./pref-viewer-3d-data.js";
2
2
  import BabylonJSController from "./babylonjs-controller.js";
3
+ import { PrefViewer3DStyles } from "./styles.js";
3
4
 
4
5
  /**
5
6
  * PrefViewer3D - Custom Web Component for interactive 3D visualization and configuration.
@@ -31,9 +32,14 @@ import BabylonJSController from "./babylonjs-controller.js";
31
32
  * - showEnvironment(): Shows the 3D environment/scene.
32
33
  * - hideEnvironment(): Hides the 3D environment/scene.
33
34
  * - downloadModelGLB(): Downloads the current 3D model as a GLB file.
35
+ * - downloadModelGLTF(): Downloads the current 3D model as a glTF ZIP file.
34
36
  * - downloadModelUSDZ(): Downloads the current 3D model as a USDZ file.
35
37
  * - downloadModelAndSceneGLB(): Downloads both the model and scene as a GLB file.
38
+ * - downloadModelAndSceneGLTF(): Downloads both the model and scene as a glTF ZIP file.
36
39
  * - downloadModelAndSceneUSDZ(): Downloads both the model and scene as a USDZ file.
40
+ * - downloadSceneGLB(): Downloads the environment as a GLB file.
41
+ * - downloadSceneGLTF(): Downloads the environment as a glTF ZIP file.
42
+ * - downloadSceneUSDZ(): Downloads the environment as a USDZ file.
37
43
  *
38
44
  * Public Properties:
39
45
  * - isInitialized: Indicates whether the component has completed initialization.
@@ -51,7 +57,7 @@ import BabylonJSController from "./babylonjs-controller.js";
51
57
  * - Designed for extensibility and integration in product configurators and visualization tools.
52
58
  * - All resource management and rendering operations are performed asynchronously for performance.
53
59
  */
54
- export class PrefViewer3D extends HTMLElement {
60
+ export default class PrefViewer3D extends HTMLElement {
55
61
  // State flags
56
62
  #isInitialized = false;
57
63
  #isLoaded = false;
@@ -124,6 +130,7 @@ export class PrefViewer3D extends HTMLElement {
124
130
  * Called when the element is added to the DOM.
125
131
  * Creates the DOM structure, sets initial visibility, initializes component data, and sets up the BabylonJSController.
126
132
  * Performs heavy initialization tasks required for the 3D viewer.
133
+ * @public
127
134
  * @returns {void}
128
135
  */
129
136
  connectedCallback() {
@@ -131,11 +138,13 @@ export class PrefViewer3D extends HTMLElement {
131
138
  this.#setInitialVisibility();
132
139
  this.#initializeData();
133
140
  this.#initializeBabylonJS();
141
+ this.#isInitialized = true;
134
142
  }
135
143
 
136
144
  /**
137
145
  * Called when the element is removed from the DOM.
138
146
  * Disables the BabylonJSController to clean up resources and event listeners associated with the 3D viewer.
147
+ * @public
139
148
  * @returns {void}
140
149
  */
141
150
  disconnectedCallback() {
@@ -152,10 +161,12 @@ export class PrefViewer3D extends HTMLElement {
152
161
  #createDOMElements() {
153
162
  this.#wrapper = document.createElement("div");
154
163
  this.append(this.#wrapper);
164
+
155
165
  this.#canvas = document.createElement("canvas");
156
166
  this.#wrapper.appendChild(this.#canvas);
167
+
157
168
  const style = document.createElement("style");
158
- style.textContent = `pref-viewer-3d[visible="true"] { display: block; } pref-viewer-3d[visible="false"] { display: none; } pref-viewer-3d, pref-viewer-3d > div, pref-viewer-3d > div > canvas { width: 100%; height: 100%; display: block; position: relative; outline: none; box-sizing: border-box; }`;
169
+ style.textContent = PrefViewer3DStyles;
159
170
  this.append(style);
160
171
  }
161
172
 
@@ -303,9 +314,9 @@ export class PrefViewer3D extends HTMLElement {
303
314
  */
304
315
  #onLoading() {
305
316
  const customEventOptions = {
306
- bubbles: true,
307
- cancelable: false,
308
- composed: true,
317
+ bubbles: true, // indicates whether the event bubbles up through the DOM tree or not
318
+ cancelable: true, // indicates whether the event can be canceled, and therefore prevented as if the event never happened
319
+ composed: false, // indicates whether or not the event will propagate across the shadow DOM boundary into the standard DOM
309
320
  };
310
321
  this.dispatchEvent(new CustomEvent("scene-loading", customEventOptions));
311
322
 
@@ -351,8 +362,8 @@ export class PrefViewer3D extends HTMLElement {
351
362
 
352
363
  const customEventOptions = {
353
364
  bubbles: true,
354
- cancelable: false,
355
- composed: true,
365
+ cancelable: true,
366
+ composed: false,
356
367
  detail: detail,
357
368
  };
358
369
  this.dispatchEvent(new CustomEvent("scene-loaded", customEventOptions));
@@ -375,8 +386,8 @@ export class PrefViewer3D extends HTMLElement {
375
386
  #onSettingOptions() {
376
387
  const customEventOptions = {
377
388
  bubbles: true,
378
- cancelable: false,
379
- composed: true,
389
+ cancelable: true,
390
+ composed: false,
380
391
  };
381
392
  this.dispatchEvent(new CustomEvent("scene-setting-options", customEventOptions));
382
393
 
@@ -413,11 +424,11 @@ export class PrefViewer3D extends HTMLElement {
413
424
  tried: toSetDetail,
414
425
  success: settedDetail,
415
426
  };
416
-
427
+
417
428
  const customEventOptions = {
418
429
  bubbles: true,
419
- cancelable: false,
420
- composed: true,
430
+ cancelable: true,
431
+ composed: false,
421
432
  detail: detail,
422
433
  };
423
434
  this.dispatchEvent(new CustomEvent("scene-set-options", customEventOptions));
@@ -455,6 +466,7 @@ export class PrefViewer3D extends HTMLElement {
455
466
  show() {
456
467
  this.#isVisible = true;
457
468
  this.setAttribute("visible", "true");
469
+ this.#canvas.focus();
458
470
  }
459
471
 
460
472
  /**
@@ -567,7 +579,19 @@ export class PrefViewer3D extends HTMLElement {
567
579
  if (!this.#babylonJSController) {
568
580
  return;
569
581
  }
570
- this.#babylonJSController.downloadModelGLB();
582
+ this.#babylonJSController.downloadGLB(1);
583
+ }
584
+
585
+ /**
586
+ * Downloads the current 3D model as a glTF file (ZIP with gltf and all resources (textures, buffers, etc.)).
587
+ * @public
588
+ * @returns {void}
589
+ */
590
+ downloadModelGLTF() {
591
+ if (!this.#babylonJSController) {
592
+ return;
593
+ }
594
+ this.#babylonJSController.downloadGLTF(1);
571
595
  }
572
596
 
573
597
  /**
@@ -579,11 +603,35 @@ export class PrefViewer3D extends HTMLElement {
579
603
  if (!this.#babylonJSController) {
580
604
  return;
581
605
  }
582
- this.#babylonJSController.downloadModelUSDZ();
606
+ this.#babylonJSController.downloadUSDZ(1);
583
607
  }
584
608
 
585
609
  /**
586
- * Downloads both the 3D model and scene as a USDZ file.
610
+ * Downloads the current 3D complete scene (model and environment) as a GLB file.
611
+ * @public
612
+ * @returns {void}
613
+ */
614
+ downloadModelAndSceneGLB() {
615
+ if (!this.#babylonJSController) {
616
+ return;
617
+ }
618
+ this.#babylonJSController.downloadModelGLB(0);
619
+ }
620
+
621
+ /**
622
+ * Downloads the current 3D complete scene (model and environment) as a glTF file (ZIP with gltf and all resources (textures, buffers, etc.)).
623
+ * @public
624
+ * @returns {void}
625
+ */
626
+ downloadModelAndSceneGLTF() {
627
+ if (!this.#babylonJSController) {
628
+ return;
629
+ }
630
+ this.#babylonJSController.downloadGLTF(0);
631
+ }
632
+
633
+ /**
634
+ * Downloads the current 3D complete scene (model and environment) as a USDZ file.
587
635
  * @public
588
636
  * @returns {void}
589
637
  */
@@ -591,19 +639,43 @@ export class PrefViewer3D extends HTMLElement {
591
639
  if (!this.#babylonJSController) {
592
640
  return;
593
641
  }
594
- this.#babylonJSController.downloadModelAndSceneUSDZ();
642
+ this.#babylonJSController.downloadUSDZ(0);
595
643
  }
596
644
 
597
645
  /**
598
- * Downloads both the 3D model and scene as a GLB file.
646
+ * Downloads the current 3D environment as a GLB file.
599
647
  * @public
600
648
  * @returns {void}
601
649
  */
602
- downloadModelAndSceneGLB() {
650
+ downloadSceneGLB() {
651
+ if (!this.#babylonJSController) {
652
+ return;
653
+ }
654
+ this.#babylonJSController.downloadGLB(2);
655
+ }
656
+
657
+ /**
658
+ * Downloads the current 3D environment as a glTF file (ZIP with gltf and all resources (textures, buffers, etc.)).
659
+ * @public
660
+ * @returns {void}
661
+ */
662
+ downloadSceneGLTF() {
663
+ if (!this.#babylonJSController) {
664
+ return;
665
+ }
666
+ this.#babylonJSController.downloadGLTF(2);
667
+ }
668
+
669
+ /**
670
+ * Downloads the current 3D environment as a USDZ file.
671
+ * @public
672
+ * @returns {void}
673
+ */
674
+ downloadSceneUSDZ() {
603
675
  if (!this.#babylonJSController) {
604
676
  return;
605
677
  }
606
- this.#babylonJSController.downloadModelAndSceneGLB();
678
+ this.#babylonJSController.downloadUSDZ(2);
607
679
  }
608
680
 
609
681
  /**
@@ -632,4 +704,4 @@ export class PrefViewer3D extends HTMLElement {
632
704
  get isVisible() {
633
705
  return this.#isVisible;
634
706
  }
635
- }
707
+ }