@preference-sl/pref-viewer 2.11.0-beta.19 → 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.
- package/package.json +1 -1
- package/src/babylonjs-animation-controller.js +1 -4
- package/src/babylonjs-animation-opening-menu.js +7 -1
- package/src/babylonjs-animation-opening.js +40 -7
- package/src/babylonjs-controller.js +25 -6
- package/src/file-storage.js +11 -2
- package/src/panzoom-controller.js +90 -53
- package/src/pref-viewer-2d.js +11 -1
- package/src/pref-viewer-3d.js +3 -0
- package/src/pref-viewer-dialog.js +12 -6
- package/src/pref-viewer.js +24 -1
package/package.json
CHANGED
|
@@ -150,11 +150,8 @@ export default class BabylonJSAnimationController {
|
|
|
150
150
|
}
|
|
151
151
|
this.hideMenu();
|
|
152
152
|
this.#animatedNodes = [];
|
|
153
|
+
this.#openingAnimations.forEach((openingAnimation) => openingAnimation.dispose());
|
|
153
154
|
this.#openingAnimations = [];
|
|
154
|
-
const observer = this.#scene.onPointerObservable._observers.find((observer) => observer.callback.name.includes("#onAnimationPointerObservable"));
|
|
155
|
-
if (observer) {
|
|
156
|
-
this.#scene.onPointerObservable.remove(observer);
|
|
157
|
-
}
|
|
158
155
|
}
|
|
159
156
|
|
|
160
157
|
/**
|
|
@@ -78,6 +78,10 @@ export default class OpeningAnimationMenu {
|
|
|
78
78
|
repeatOff: `<svg id="repeat-off" width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M2,5.27L3.28,4L20,20.72L18.73,22L15.73,19H7V22L3,18L7,14V17H13.73L7,10.27V11H5V8.27L2,5.27M17,13H19V17.18L17,15.18V13M17,5V2L21,6L17,10V7H8.82L6.82,5H17Z"/></svg>`,
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
+
#handler = {
|
|
82
|
+
onSliderInput: null,
|
|
83
|
+
};
|
|
84
|
+
|
|
81
85
|
/**
|
|
82
86
|
* Constructs the OpeningAnimationMenu and initializes the menu UI.
|
|
83
87
|
* @param {string} name - The name of the animation.
|
|
@@ -154,7 +158,8 @@ export default class OpeningAnimationMenu {
|
|
|
154
158
|
this.#slider.setAttribute("step", "0.01");
|
|
155
159
|
this.#slider.setAttribute("value", this.#animationProgress.toString());
|
|
156
160
|
this.#slider.classList.add("animation-menu-slider");
|
|
157
|
-
this.#
|
|
161
|
+
this.#handler.onSliderInput = this.#onSliderInput.bind(this);
|
|
162
|
+
this.#slider.addEventListener("input", this.#handler.onSliderInput);
|
|
158
163
|
|
|
159
164
|
this.#containerMain.appendChild(this.#slider);
|
|
160
165
|
}
|
|
@@ -327,6 +332,7 @@ export default class OpeningAnimationMenu {
|
|
|
327
332
|
* @returns {void}
|
|
328
333
|
*/
|
|
329
334
|
dispose() {
|
|
335
|
+
this.#slider.removeEventListener("input", this.#handler.onSliderInput);
|
|
330
336
|
if (this.isVisible) {
|
|
331
337
|
this.#containerMain.remove();
|
|
332
338
|
}
|
|
@@ -12,6 +12,7 @@ import OpeningAnimationMenu from "./babylonjs-animation-opening-menu.js";
|
|
|
12
12
|
* - Manages the animation control menu (OpeningAnimationMenu) and its callbacks.
|
|
13
13
|
*
|
|
14
14
|
* Public Methods:
|
|
15
|
+
* - dispose(): Disposes the OpeningAnimation instance and releases all associated resources.
|
|
15
16
|
* - isAnimationForNode(node): Checks if the animation affects the given node.
|
|
16
17
|
* - playOpen(): Starts the opening animation.
|
|
17
18
|
* - playClose(): Starts the closing animation.
|
|
@@ -48,20 +49,26 @@ export default class OpeningAnimation {
|
|
|
48
49
|
closing: 4,
|
|
49
50
|
};
|
|
50
51
|
|
|
52
|
+
name = "";
|
|
51
53
|
#openAnimation = null;
|
|
52
54
|
#closeAnimation = null;
|
|
53
|
-
|
|
54
55
|
#nodes = [];
|
|
56
|
+
#menu = null;
|
|
57
|
+
|
|
55
58
|
#state = OpeningAnimation.states.closed;
|
|
56
59
|
#lastPausedFrame = 0;
|
|
57
60
|
#startFrame = 0;
|
|
58
61
|
#endFrame = 0;
|
|
59
62
|
#speedRatio = 1.0;
|
|
60
63
|
#loop = false;
|
|
61
|
-
|
|
62
|
-
#menu = null;
|
|
63
64
|
#progressThreshold = 0.025;
|
|
64
65
|
|
|
66
|
+
#handlers = {
|
|
67
|
+
onOpened: null,
|
|
68
|
+
onClosed: null,
|
|
69
|
+
updateControlsSlider: null,
|
|
70
|
+
};
|
|
71
|
+
|
|
65
72
|
/**
|
|
66
73
|
* Creates a new OpeningAnimation instance for managing open/close animations of a model part.
|
|
67
74
|
* @param {string} name - The identifier for this animation (e.g., door name).
|
|
@@ -85,8 +92,15 @@ export default class OpeningAnimation {
|
|
|
85
92
|
this.#speedRatio = this.#openAnimation.speedRatio || 1.0;
|
|
86
93
|
|
|
87
94
|
this.#getNodesFromAnimationGroups();
|
|
88
|
-
this.#
|
|
89
|
-
this.#
|
|
95
|
+
this.#bindHandlers();
|
|
96
|
+
this.#openAnimation.onAnimationGroupEndObservable.add(this.#handlers.onOpened);
|
|
97
|
+
this.#closeAnimation.onAnimationGroupEndObservable.add(this.#handlers.onClosed);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
#bindHandlers() {
|
|
101
|
+
this.#handlers.onOpened = this.#onOpened.bind(this);
|
|
102
|
+
this.#handlers.onClosed = this.#onClosed.bind(this);
|
|
103
|
+
this.#handlers.updateControlsSlider = this.#updateControlsSlider.bind(this);
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
/**
|
|
@@ -303,6 +317,25 @@ export default class OpeningAnimation {
|
|
|
303
317
|
* ---------------------------
|
|
304
318
|
*/
|
|
305
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Disposes the OpeningAnimation instance and releases all associated resources.
|
|
322
|
+
* @public
|
|
323
|
+
* @returns {void}
|
|
324
|
+
*/
|
|
325
|
+
dispose() {
|
|
326
|
+
this.hideControls();
|
|
327
|
+
if (this.#openAnimation) {
|
|
328
|
+
this.#openAnimation.onAnimationGroupEndObservable.removeCallback(this.#handlers.onOpened);
|
|
329
|
+
this.#openAnimation = null;
|
|
330
|
+
}
|
|
331
|
+
if (this.#closeAnimation) {
|
|
332
|
+
this.#closeAnimation.onAnimationGroupEndObservable.removeCallback(this.#handlers.onClosed);
|
|
333
|
+
this.#closeAnimation = null;
|
|
334
|
+
}
|
|
335
|
+
this.#nodes = [];
|
|
336
|
+
this.name = "";
|
|
337
|
+
}
|
|
338
|
+
|
|
306
339
|
/**
|
|
307
340
|
* Checks if the animation affects the given node.
|
|
308
341
|
* @param {string} node - Node identifier.
|
|
@@ -452,7 +485,7 @@ export default class OpeningAnimation {
|
|
|
452
485
|
this.#menu = new OpeningAnimationMenu(this.name, canvas, this.#state, this.#getProgress(), this.#loop, controlCallbacks);
|
|
453
486
|
|
|
454
487
|
// Attach to Babylon.js scene render loop for real-time updates
|
|
455
|
-
this.#openAnimation._scene.onBeforeRenderObservable.add(this.#updateControlsSlider
|
|
488
|
+
this.#openAnimation._scene.onBeforeRenderObservable.add(this.#handlers.updateControlsSlider);
|
|
456
489
|
}
|
|
457
490
|
|
|
458
491
|
/**
|
|
@@ -463,7 +496,7 @@ export default class OpeningAnimation {
|
|
|
463
496
|
if (!this.isControlsVisible()) {
|
|
464
497
|
return;
|
|
465
498
|
}
|
|
466
|
-
this.#openAnimation
|
|
499
|
+
this.#openAnimation?._scene?.onBeforeRenderObservable.removeCallback(this.#handlers.updateControlsSlider);
|
|
467
500
|
this.#menu.dispose();
|
|
468
501
|
this.#menu = null;
|
|
469
502
|
}
|
|
@@ -48,6 +48,7 @@ import BabylonJSAnimationController from "./babylonjs-animation-controller.js";
|
|
|
48
48
|
* - downloadUSDZ(content): Downloads the current scene, model, or environment as a USDZ file.
|
|
49
49
|
*
|
|
50
50
|
* Private Methods (using ECMAScript private fields):
|
|
51
|
+
* - #bindHandlers(): Pre-binds reusable event handlers to preserve stable references.
|
|
51
52
|
* - #configureDracoCompression(): Sets up Draco mesh compression.
|
|
52
53
|
* - #renderLoop(): Babylon.js render loop callback.
|
|
53
54
|
* - #addStylesToARButton(): Styles AR button.
|
|
@@ -112,6 +113,12 @@ export default class BabylonJSController {
|
|
|
112
113
|
#gltfResolver = null; // GLTFResolver instance
|
|
113
114
|
#babylonJSAnimationController = null; // AnimationController instance
|
|
114
115
|
|
|
116
|
+
#handlers = {
|
|
117
|
+
onKeyUp: null,
|
|
118
|
+
onPointerObservable: null,
|
|
119
|
+
renderLoop: null,
|
|
120
|
+
};
|
|
121
|
+
|
|
115
122
|
/**
|
|
116
123
|
* Constructs a new BabylonJSController instance.
|
|
117
124
|
* Initializes the canvas, asset containers, and options for the Babylon.js scene.
|
|
@@ -134,6 +141,18 @@ export default class BabylonJSController {
|
|
|
134
141
|
};
|
|
135
142
|
});
|
|
136
143
|
this.#options = options;
|
|
144
|
+
this.#bindHandlers();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Pre-binds reusable event handlers to preserve stable references.
|
|
149
|
+
* @private
|
|
150
|
+
* @returns {void}
|
|
151
|
+
*/
|
|
152
|
+
#bindHandlers() {
|
|
153
|
+
this.#handlers.onKeyUp = this.#onKeyUp.bind(this);
|
|
154
|
+
this.#handlers.onPointerObservable = this.#onPointerObservable.bind(this);
|
|
155
|
+
this.#handlers.renderLoop = this.#renderLoop.bind(this);
|
|
137
156
|
}
|
|
138
157
|
|
|
139
158
|
/**
|
|
@@ -446,10 +465,10 @@ export default class BabylonJSController {
|
|
|
446
465
|
*/
|
|
447
466
|
#enableInteraction() {
|
|
448
467
|
if (this.#canvas) {
|
|
449
|
-
this.#canvas.addEventListener("keyup", this.#onKeyUp
|
|
468
|
+
this.#canvas.addEventListener("keyup", this.#handlers.onKeyUp);
|
|
450
469
|
}
|
|
451
470
|
if (this.#scene) {
|
|
452
|
-
this.#scene.onPointerObservable.add(this.#onPointerObservable
|
|
471
|
+
this.#scene.onPointerObservable.add(this.#handlers.onPointerObservable);
|
|
453
472
|
}
|
|
454
473
|
}
|
|
455
474
|
|
|
@@ -460,10 +479,10 @@ export default class BabylonJSController {
|
|
|
460
479
|
*/
|
|
461
480
|
#disableInteraction() {
|
|
462
481
|
if (this.#canvas) {
|
|
463
|
-
this.#canvas.removeEventListener("keyup", this.#onKeyUp
|
|
482
|
+
this.#canvas.removeEventListener("keyup", this.#handlers.onKeyUp);
|
|
464
483
|
}
|
|
465
484
|
if (this.#scene !== null) {
|
|
466
|
-
this.#scene.onPointerObservable.removeCallback(this.#onPointerObservable
|
|
485
|
+
this.#scene.onPointerObservable.removeCallback(this.#handlers.onPointerObservable);
|
|
467
486
|
}
|
|
468
487
|
}
|
|
469
488
|
|
|
@@ -855,7 +874,7 @@ export default class BabylonJSController {
|
|
|
855
874
|
* @returns {void}
|
|
856
875
|
*/
|
|
857
876
|
#stopRender() {
|
|
858
|
-
this.#engine.stopRenderLoop(this.#renderLoop
|
|
877
|
+
this.#engine.stopRenderLoop(this.#handlers.renderLoop);
|
|
859
878
|
}
|
|
860
879
|
/**
|
|
861
880
|
* Starts the Babylon.js render loop for the current scene.
|
|
@@ -865,7 +884,7 @@ export default class BabylonJSController {
|
|
|
865
884
|
*/
|
|
866
885
|
async #startRender() {
|
|
867
886
|
await this.#scene.whenReadyAsync();
|
|
868
|
-
this.#engine.runRenderLoop(this.#renderLoop
|
|
887
|
+
this.#engine.runRenderLoop(this.#handlers.renderLoop);
|
|
869
888
|
}
|
|
870
889
|
|
|
871
890
|
/**
|
package/src/file-storage.js
CHANGED
|
@@ -174,7 +174,12 @@ export class FileStorage {
|
|
|
174
174
|
xhr.onload = () => {
|
|
175
175
|
if (xhr.status === 200) {
|
|
176
176
|
const blob = xhr.response;
|
|
177
|
-
const
|
|
177
|
+
const lastModified = xhr.getResponseHeader("Last-Modified");
|
|
178
|
+
let timeStamp = null;
|
|
179
|
+
if (lastModified) {
|
|
180
|
+
const parsed = new Date(lastModified);
|
|
181
|
+
timeStamp = Number.isNaN(parsed.valueOf()) ? null : parsed.toISOString();
|
|
182
|
+
}
|
|
178
183
|
file = { blob: blob, timeStamp: timeStamp };
|
|
179
184
|
resolve(file);
|
|
180
185
|
} else {
|
|
@@ -204,7 +209,11 @@ export class FileStorage {
|
|
|
204
209
|
xhr.responseType = "blob";
|
|
205
210
|
xhr.onload = () => {
|
|
206
211
|
if (xhr.status === 200) {
|
|
207
|
-
|
|
212
|
+
const lastModified = xhr.getResponseHeader("Last-Modified");
|
|
213
|
+
if (lastModified) {
|
|
214
|
+
const parsed = new Date(lastModified);
|
|
215
|
+
timeStamp = Number.isNaN(parsed.valueOf()) ? null : parsed.toISOString();
|
|
216
|
+
}
|
|
208
217
|
resolve(timeStamp);
|
|
209
218
|
} else {
|
|
210
219
|
resolve(timeStamp);
|
|
@@ -2,59 +2,67 @@
|
|
|
2
2
|
import Panzoom from "@panzoom/panzoom/dist/panzoom.es.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* PanzoomController - Encapsulates
|
|
5
|
+
* PanzoomController - Encapsulates logic for managing pan and zoom interactions on a DOM element using the Panzoom library.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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.
|
|
12
19
|
*
|
|
13
20
|
* Usage:
|
|
14
|
-
* - Instantiate
|
|
15
|
-
*
|
|
16
|
-
* -
|
|
17
|
-
* -
|
|
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();
|
|
18
26
|
*
|
|
19
27
|
* Constructor Parameters:
|
|
20
|
-
* -
|
|
21
|
-
* -
|
|
22
|
-
* -
|
|
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.
|
|
23
31
|
*
|
|
24
32
|
* Public Methods:
|
|
25
|
-
* -
|
|
26
|
-
* -
|
|
27
|
-
* -
|
|
28
|
-
* -
|
|
29
|
-
* -
|
|
30
|
-
* -
|
|
31
|
-
* -
|
|
32
|
-
* -
|
|
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.
|
|
33
41
|
*
|
|
34
42
|
* Getters:
|
|
35
|
-
* -
|
|
36
|
-
* -
|
|
43
|
+
* - panzoom: Returns the current Panzoom instance or null if not initialized.
|
|
44
|
+
* - state: Returns the current pan/zoom state (moved, scaled, maximized, minimized).
|
|
37
45
|
*
|
|
38
46
|
* Private Methods:
|
|
39
|
-
* -
|
|
40
|
-
* -
|
|
41
|
-
* -
|
|
42
|
-
* -
|
|
43
|
-
* -
|
|
44
|
-
* -
|
|
45
|
-
* -
|
|
46
|
-
* -
|
|
47
|
-
* -
|
|
48
|
-
* -
|
|
49
|
-
* -
|
|
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.
|
|
50
59
|
*
|
|
51
60
|
* Notes:
|
|
52
61
|
* - Designed to work with the Panzoom library for managing pan/zoom interactions.
|
|
53
|
-
* -
|
|
62
|
+
* - Encapsulates all pan/zoom logic in a single class for clean separation of concerns.
|
|
54
63
|
* - Can be extended or customized by overriding methods or providing additional options.
|
|
55
64
|
*/
|
|
56
65
|
export default class PanzoomController {
|
|
57
|
-
#changedCallback = null;
|
|
58
66
|
#interactionOptions = {
|
|
59
67
|
clickThreshold: 6, // Threshold to avoid false clicks on elements when panning or zooming
|
|
60
68
|
};
|
|
@@ -80,11 +88,40 @@ export default class PanzoomController {
|
|
|
80
88
|
minimized: false,
|
|
81
89
|
};
|
|
82
90
|
#wrapper = null;
|
|
83
|
-
|
|
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
|
+
|
|
84
104
|
constructor(wrapper = null, options = {}, changedCallback = null) {
|
|
85
105
|
this.#wrapper = wrapper;
|
|
86
106
|
Object.assign(this.#options, options);
|
|
87
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);
|
|
88
125
|
}
|
|
89
126
|
|
|
90
127
|
/**
|
|
@@ -295,7 +332,7 @@ export default class PanzoomController {
|
|
|
295
332
|
if (!this.#panzoom) {
|
|
296
333
|
return;
|
|
297
334
|
}
|
|
298
|
-
this.#wrapper.parentElement.removeEventListener("wheel", this.#
|
|
335
|
+
this.#wrapper.parentElement.removeEventListener("wheel", this.#handlers.wheel);
|
|
299
336
|
}
|
|
300
337
|
|
|
301
338
|
/**
|
|
@@ -310,7 +347,7 @@ export default class PanzoomController {
|
|
|
310
347
|
return;
|
|
311
348
|
}
|
|
312
349
|
this.#disableMouseWheelZoom();
|
|
313
|
-
this.#wrapper.parentElement.addEventListener("wheel", this.#
|
|
350
|
+
this.#wrapper.parentElement.addEventListener("wheel", this.#handlers.wheel);
|
|
314
351
|
}
|
|
315
352
|
|
|
316
353
|
/**
|
|
@@ -364,13 +401,13 @@ export default class PanzoomController {
|
|
|
364
401
|
|
|
365
402
|
this.disableEvents();
|
|
366
403
|
|
|
367
|
-
this.#wrapper.addEventListener("panzoomstart", this.#
|
|
368
|
-
this.#wrapper.addEventListener("panzoomchange", this.#
|
|
369
|
-
this.#wrapper.addEventListener("panzoomend", this.#
|
|
370
|
-
this.#wrapper.parentElement.addEventListener("keyup", this.#
|
|
371
|
-
this.#wrapper.parentElement.addEventListener("focus", this.#
|
|
372
|
-
this.#wrapper.parentElement.addEventListener("blur", this.#
|
|
373
|
-
this.#wrapper.parentElement.addEventListener("contextmenu", this.#
|
|
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);
|
|
374
411
|
this.#wrapper.parentElement.setAttribute("tabindex", 0);
|
|
375
412
|
this.#setFocus();
|
|
376
413
|
}
|
|
@@ -386,13 +423,13 @@ export default class PanzoomController {
|
|
|
386
423
|
return;
|
|
387
424
|
}
|
|
388
425
|
this.#wrapper.parentElement.removeAttribute("tabindex");
|
|
389
|
-
this.#wrapper.removeEventListener("panzoomstart", this.#
|
|
390
|
-
this.#wrapper.removeEventListener("panzoomchange", this.#
|
|
391
|
-
this.#wrapper.removeEventListener("panzoomend", this.#
|
|
392
|
-
this.#wrapper.parentElement.removeEventListener("keyup", this.#
|
|
393
|
-
this.#wrapper.parentElement.removeEventListener("focus", this.#
|
|
394
|
-
this.#wrapper.parentElement.removeEventListener("blur", this.#
|
|
395
|
-
this.#wrapper.parentElement.removeEventListener("contextmenu", this.#
|
|
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);
|
|
396
433
|
}
|
|
397
434
|
|
|
398
435
|
/**
|
package/src/pref-viewer-2d.js
CHANGED
|
@@ -69,6 +69,10 @@ export default class PrefViewer2D extends HTMLElement {
|
|
|
69
69
|
#wrapper = null; // Panzoom element
|
|
70
70
|
#panzoomController = null; // PanzoomController instance
|
|
71
71
|
|
|
72
|
+
#handlers = {
|
|
73
|
+
onPanzoomChanged: null,
|
|
74
|
+
};
|
|
75
|
+
|
|
72
76
|
/**
|
|
73
77
|
* Create a new instance of the 2D viewer component.
|
|
74
78
|
* The constructor only calls super(); heavy initialization happens in connectedCallback.
|
|
@@ -115,6 +119,7 @@ export default class PrefViewer2D extends HTMLElement {
|
|
|
115
119
|
/**
|
|
116
120
|
* Called when the element is inserted into the DOM.
|
|
117
121
|
* Sets up DOM nodes, initial visibility and starts loading the SVG if provided.
|
|
122
|
+
* @public
|
|
118
123
|
* @returns {void}
|
|
119
124
|
*/
|
|
120
125
|
connectedCallback() {
|
|
@@ -128,6 +133,7 @@ export default class PrefViewer2D extends HTMLElement {
|
|
|
128
133
|
/**
|
|
129
134
|
* Called when the element is removed from the DOM.
|
|
130
135
|
* Disables the PanzoomController to clean up event listeners and resources.
|
|
136
|
+
* @public
|
|
131
137
|
* @returns {void}
|
|
132
138
|
*/
|
|
133
139
|
disconnectedCallback() {
|
|
@@ -168,7 +174,8 @@ export default class PrefViewer2D extends HTMLElement {
|
|
|
168
174
|
* @returns {void}
|
|
169
175
|
*/
|
|
170
176
|
#initializePanzoom() {
|
|
171
|
-
this.#
|
|
177
|
+
this.#handlers.onPanzoomChanged = this.#onPanzoomChanged.bind(this);
|
|
178
|
+
this.#panzoomController = new PanzoomController(this.#wrapper, undefined, this.#handlers.onPanzoomChanged);
|
|
172
179
|
}
|
|
173
180
|
|
|
174
181
|
/**
|
|
@@ -351,6 +358,9 @@ export default class PrefViewer2D extends HTMLElement {
|
|
|
351
358
|
* - Resolves to { success: true, error: null } when the SVG was accepted and the component has started rendering.
|
|
352
359
|
*/
|
|
353
360
|
async load(svgConfig) {
|
|
361
|
+
if (!this.#svgResolver) {
|
|
362
|
+
this.#svgResolver = new SVGResolver(this.#svg);
|
|
363
|
+
}
|
|
354
364
|
if (!svgConfig || !(await this.#svgResolver.getSVG(svgConfig))) {
|
|
355
365
|
const errorDetail = this.#onError();
|
|
356
366
|
return { success: false, ...errorDetail };
|
package/src/pref-viewer-3d.js
CHANGED
|
@@ -130,6 +130,7 @@ export default class PrefViewer3D extends HTMLElement {
|
|
|
130
130
|
* Called when the element is added to the DOM.
|
|
131
131
|
* Creates the DOM structure, sets initial visibility, initializes component data, and sets up the BabylonJSController.
|
|
132
132
|
* Performs heavy initialization tasks required for the 3D viewer.
|
|
133
|
+
* @public
|
|
133
134
|
* @returns {void}
|
|
134
135
|
*/
|
|
135
136
|
connectedCallback() {
|
|
@@ -137,11 +138,13 @@ export default class PrefViewer3D extends HTMLElement {
|
|
|
137
138
|
this.#setInitialVisibility();
|
|
138
139
|
this.#initializeData();
|
|
139
140
|
this.#initializeBabylonJS();
|
|
141
|
+
this.#isInitialized = true;
|
|
140
142
|
}
|
|
141
143
|
|
|
142
144
|
/**
|
|
143
145
|
* Called when the element is removed from the DOM.
|
|
144
146
|
* Disables the BabylonJSController to clean up resources and event listeners associated with the 3D viewer.
|
|
147
|
+
* @public
|
|
145
148
|
* @returns {void}
|
|
146
149
|
*/
|
|
147
150
|
disconnectedCallback() {
|
|
@@ -28,6 +28,10 @@ export default class PrefViewerDialog extends HTMLElement {
|
|
|
28
28
|
#content = null;
|
|
29
29
|
#footer = null;
|
|
30
30
|
|
|
31
|
+
#handles = {
|
|
32
|
+
onBackdropClick: null,
|
|
33
|
+
};
|
|
34
|
+
|
|
31
35
|
/**
|
|
32
36
|
* Initializes the custom dialog element.
|
|
33
37
|
* Only calls super(); heavy initialization is deferred to connectedCallback.
|
|
@@ -35,13 +39,14 @@ export default class PrefViewerDialog extends HTMLElement {
|
|
|
35
39
|
constructor() {
|
|
36
40
|
super();
|
|
37
41
|
}
|
|
38
|
-
|
|
42
|
+
|
|
39
43
|
/**
|
|
40
44
|
* Called when the element is inserted into the DOM.
|
|
41
45
|
* Sets up the dialog's DOM structure and styles.
|
|
42
46
|
* @returns {void}
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
*/
|
|
48
|
+
connectedCallback() {
|
|
49
|
+
this.#handles.onBackdropClick = this.#onBackdropClick.bind(this);
|
|
45
50
|
this.#createDOMElements();
|
|
46
51
|
}
|
|
47
52
|
|
|
@@ -51,7 +56,7 @@ export default class PrefViewerDialog extends HTMLElement {
|
|
|
51
56
|
* @returns {void}
|
|
52
57
|
*/
|
|
53
58
|
disconnectedCallback() {
|
|
54
|
-
this.removeEventListener("click", this.#
|
|
59
|
+
this.removeEventListener("click", this.#handles.onBackdropClick);
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
/**
|
|
@@ -73,14 +78,14 @@ export default class PrefViewerDialog extends HTMLElement {
|
|
|
73
78
|
style.textContent = PrefViewerDialogStyles;
|
|
74
79
|
this.append(style);
|
|
75
80
|
|
|
76
|
-
this.addEventListener("click", this.#
|
|
81
|
+
this.addEventListener("click", this.#handles.onBackdropClick);
|
|
77
82
|
|
|
78
83
|
this.#header = this.#wrapper.querySelector(".dialog-header");
|
|
79
84
|
this.#content = this.#wrapper.querySelector(".dialog-content");
|
|
80
85
|
this.#footer = this.#wrapper.querySelector(".dialog-footer");
|
|
81
86
|
}
|
|
82
87
|
|
|
83
|
-
#
|
|
88
|
+
#onBackdropClick(event) {
|
|
84
89
|
if (event.target === this) {
|
|
85
90
|
this.close();
|
|
86
91
|
}
|
|
@@ -120,6 +125,7 @@ export default class PrefViewerDialog extends HTMLElement {
|
|
|
120
125
|
* @returns {void}
|
|
121
126
|
*/
|
|
122
127
|
close() {
|
|
128
|
+
this.removeEventListener("click", this.#handles.onBackdropClick);
|
|
123
129
|
this.removeAttribute("open");
|
|
124
130
|
const parent = this.getRootNode().host;
|
|
125
131
|
if (parent) {
|
package/src/pref-viewer.js
CHANGED
|
@@ -87,6 +87,10 @@ export default class PrefViewer extends HTMLElement {
|
|
|
87
87
|
#component3D = null;
|
|
88
88
|
#dialog = null;
|
|
89
89
|
|
|
90
|
+
#handlers = {
|
|
91
|
+
on2DZoomChanged: null,
|
|
92
|
+
};
|
|
93
|
+
|
|
90
94
|
/**
|
|
91
95
|
* Creates a new PrefViewer instance and attaches a shadow DOM.
|
|
92
96
|
* Initializes internal state and component references.
|
|
@@ -185,6 +189,24 @@ export default class PrefViewer extends HTMLElement {
|
|
|
185
189
|
this.#processNextTask();
|
|
186
190
|
}
|
|
187
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Called when the element is removed from the DOM.
|
|
194
|
+
* @public
|
|
195
|
+
* @returns {void}
|
|
196
|
+
*/
|
|
197
|
+
disconnectedCallback() {
|
|
198
|
+
if (this.#dialog) {
|
|
199
|
+
this.#dialog?.remove();
|
|
200
|
+
}
|
|
201
|
+
if (this.#component2D) {
|
|
202
|
+
this.#component2D.removeEventListener("drawing-zoom-changed", this.#handlers.on2DZoomChanged);
|
|
203
|
+
this.#component2D.remove();
|
|
204
|
+
}
|
|
205
|
+
if (this.#component3D) {
|
|
206
|
+
this.#component3D.remove();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
188
210
|
/**
|
|
189
211
|
* Creates and appends the 2D viewer component to the shadow DOM.
|
|
190
212
|
* Sets the "visible" attribute to true by default.
|
|
@@ -192,9 +214,10 @@ export default class PrefViewer extends HTMLElement {
|
|
|
192
214
|
* @returns {void}
|
|
193
215
|
*/
|
|
194
216
|
#createComponent2D() {
|
|
217
|
+
this.#handlers.on2DZoomChanged = this.#on2DZoomChanged.bind(this);
|
|
195
218
|
this.#component2D = document.createElement("pref-viewer-2d");
|
|
196
219
|
this.#component2D.setAttribute("visible", "false");
|
|
197
|
-
this.#component2D.addEventListener("drawing-zoom-changed", this.#on2DZoomChanged
|
|
220
|
+
this.#component2D.addEventListener("drawing-zoom-changed", this.#handlers.on2DZoomChanged);
|
|
198
221
|
this.#wrapper.appendChild(this.#component2D);
|
|
199
222
|
}
|
|
200
223
|
|