@preference-sl/pref-viewer 2.10.0 → 2.11.0-beta.1
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 +6 -3
- package/src/babylonjs-controller.js +929 -0
- package/src/file-storage.js +288 -0
- package/src/gltf-resolver.js +288 -0
- package/src/index.js +492 -962
- package/src/panzoom-controller.js +494 -0
- package/src/pref-viewer-2d.js +441 -0
- package/src/pref-viewer-3d-data.js +178 -0
- package/src/pref-viewer-3d.js +457 -0
- package/src/pref-viewer-task.js +54 -0
- package/src/svg-resolver.js +281 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import SVGResolver from "./svg-resolver.js";
|
|
2
|
+
import PanzoomController from "./panzoom-controller.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* PrefViewer2D - Custom element for rendering and interacting with 2D SVG content.
|
|
6
|
+
*
|
|
7
|
+
* Summary
|
|
8
|
+
* - Renders an SVG string into an internal wrapper element and provides pan/zoom interactions using the Panzoom library.
|
|
9
|
+
* - Supports SVG input from:
|
|
10
|
+
* * data URI (storage.url) (base64 or plain string)
|
|
11
|
+
* * IndexedDB record (base64 or plain string) (storage.db, storage.table, storage.id)
|
|
12
|
+
* * remote URL (storage.url)
|
|
13
|
+
* * direct SVG strings (storage.url)
|
|
14
|
+
* - Avoids unnecessary reloads by comparing stored size and Last-Modified timestamp.
|
|
15
|
+
*
|
|
16
|
+
* Public attributes
|
|
17
|
+
* - svg: string (setting triggers load)
|
|
18
|
+
* - visible: "true" | "false" (controls visibility and event subscription)
|
|
19
|
+
*
|
|
20
|
+
* Public methods
|
|
21
|
+
* - async load(svgConfig) : Promise<boolean> — accept SVG input/config and prepare for render
|
|
22
|
+
* - show(), hide() — toggle visibility and event subscriptions
|
|
23
|
+
* - zoomIn(), zoomOut(), zoomCenter(), zoomExtentsAll() — pan/zoom controls
|
|
24
|
+
*
|
|
25
|
+
* Events
|
|
26
|
+
* - "prefviewer2d-loading": emitted before loading starts
|
|
27
|
+
* - "prefviewer2d-loaded": emitted after content and Panzoom are ready
|
|
28
|
+
* - "prefviewer2d-error": emitted on validation/fetch errors (detail.error: Error)
|
|
29
|
+
* - "prefviewer2d-zoomchanged": emitted when pan/zoom state changes (detail: { moved, scaled, maximized, minimized })
|
|
30
|
+
*
|
|
31
|
+
* Implementation notes
|
|
32
|
+
* - Keeps internal state in private fields (#svg, #panzoom, #panzoomOptions, ...).
|
|
33
|
+
* - Validates SVG content with is-svg and decodes base64 with atob.
|
|
34
|
+
* - Performs HEAD requests to obtain Content-Length and Last-Modified for remote URLs.
|
|
35
|
+
* - Focus is set on the component's parent to enable keyboard shortcuts without Panzoom focus issues.
|
|
36
|
+
*
|
|
37
|
+
* Usage examples
|
|
38
|
+
* - load plain SVG: el.load({ storage: { url: '<svg...>' } }) or el.load('<svg...>');
|
|
39
|
+
* - load from IndexedDB: el.load({ storage: { db: 'db', table: 'tbl', id: 'recId' } });
|
|
40
|
+
*
|
|
41
|
+
* Notes on extensibility
|
|
42
|
+
* - Modeled for easy addition of other input sources or interaction modes (e.g., selection callbacks).
|
|
43
|
+
*/
|
|
44
|
+
export class PrefViewer2D extends HTMLElement {
|
|
45
|
+
// State flags
|
|
46
|
+
#isInitialized = false;
|
|
47
|
+
#isLoaded = false;
|
|
48
|
+
#isVisible = false;
|
|
49
|
+
|
|
50
|
+
#options = {
|
|
51
|
+
resetOnReload: true,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Current SVG state
|
|
55
|
+
#svg = {
|
|
56
|
+
value: "",
|
|
57
|
+
size: 0,
|
|
58
|
+
timeStamp: null,
|
|
59
|
+
update: true,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
#svgResolver = null; // SVGResolver instance
|
|
63
|
+
#wrapper = null; // Panzoom element
|
|
64
|
+
#panzoomController = null; // PanzoomController instance
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Create a new instance of the 2D viewer component.
|
|
68
|
+
* The constructor only calls super(); heavy initialization happens in connectedCallback.
|
|
69
|
+
*/
|
|
70
|
+
constructor() {
|
|
71
|
+
super();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Attributes observed by the custom element.
|
|
76
|
+
* @returns {string[]} Array of attribute names that trigger attributeChangedCallback.
|
|
77
|
+
*/
|
|
78
|
+
static get observedAttributes() {
|
|
79
|
+
return ["svg", "visible"];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Handle attribute changes.
|
|
84
|
+
* @param {string} name - Attribute name.
|
|
85
|
+
* @param {string|null} _old - Previous attribute value (unused).
|
|
86
|
+
* @param {string|null} value -New attribute value.
|
|
87
|
+
* @returns {void}
|
|
88
|
+
* @description
|
|
89
|
+
* - "svg": triggers load of new SVG content.
|
|
90
|
+
* - "visible": shows or hides the component according to the attribute value ("true"/"false").
|
|
91
|
+
*/
|
|
92
|
+
attributeChangedCallback(name, _old, value) {
|
|
93
|
+
switch (name) {
|
|
94
|
+
case "svg":
|
|
95
|
+
this.load(value);
|
|
96
|
+
break;
|
|
97
|
+
case "visible":
|
|
98
|
+
if (_old === value) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (value === "true" && this.#isVisible === false) {
|
|
102
|
+
this.show();
|
|
103
|
+
} else if (value === "false" && this.#isVisible === true) {
|
|
104
|
+
this.hide();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Called when the element is inserted into the DOM.
|
|
111
|
+
* Sets up DOM nodes, initial visibility and starts loading the SVG if provided.
|
|
112
|
+
* @returns {void}
|
|
113
|
+
*/
|
|
114
|
+
connectedCallback() {
|
|
115
|
+
this.#createDOMElements();
|
|
116
|
+
this.#setInitialVisibility();
|
|
117
|
+
this.#initializePanzoom();
|
|
118
|
+
this.#isInitialized = true;
|
|
119
|
+
this.#loadSVG();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
disconnectedCallback() {
|
|
123
|
+
if (this.#panzoomController) {
|
|
124
|
+
this.#panzoomController.disable();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Create DOM structure and basic styles used by the component.
|
|
130
|
+
* @private
|
|
131
|
+
* @returns {void}
|
|
132
|
+
*/
|
|
133
|
+
#createDOMElements() {
|
|
134
|
+
this.#wrapper = document.createElement("div");
|
|
135
|
+
this.append(this.#wrapper);
|
|
136
|
+
const style = document.createElement("style");
|
|
137
|
+
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; }`;
|
|
138
|
+
this.append(style);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Set initial visibility based on inline style and the visible attribute.
|
|
143
|
+
* @private
|
|
144
|
+
* @returns {void}
|
|
145
|
+
* @description If the "visible" attribute is not present, defaults to visible.
|
|
146
|
+
*/
|
|
147
|
+
#setInitialVisibility() {
|
|
148
|
+
const visible = !this.hasAttribute("visible") || this.getAttribute("visible") === "true";
|
|
149
|
+
visible ? this.show() : this.hide();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Initializes the PanzoomController instance for the SVG wrapper element.
|
|
154
|
+
* Sets up the controller with default options and binds the state change callback.
|
|
155
|
+
* @private
|
|
156
|
+
* @returns {void}
|
|
157
|
+
*/
|
|
158
|
+
#initializePanzoom() {
|
|
159
|
+
this.#panzoomController = new PanzoomController(this.#wrapper, undefined, this.#onPanzoomChanged.bind(this));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Render the current SVG into the wrapper and (re)initialize the Panzoom instance as required.
|
|
164
|
+
* @private
|
|
165
|
+
* @returns {boolean} Returns false when no SVG should be loaded or when validation fails; otherwise performs rendering and returns true.
|
|
166
|
+
* @description
|
|
167
|
+
* Behavior:
|
|
168
|
+
* - If this.#svg.update === false the method returns false (no work needed).
|
|
169
|
+
* - SVG is not validated here because it is already handled by SVGResolver.
|
|
170
|
+
* - Calls #onLoading() before making DOM changes and #onLoaded() after Panzoom is ready.
|
|
171
|
+
* - When options.resetOnReload is true (or there is no SVG value) it destroys the existing Panzoom
|
|
172
|
+
* instance so a fresh one is created for the new content.
|
|
173
|
+
* - If the SVG content is empty the method sets loaded state and returns false (no Panzoom initialization).
|
|
174
|
+
*/
|
|
175
|
+
#loadSVG() {
|
|
176
|
+
if (!this.#svgResolver) {
|
|
177
|
+
this.#svgResolver = new SVGResolver(this.#svg);
|
|
178
|
+
}
|
|
179
|
+
if (this.#svg.update === false) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
this.#onLoading();
|
|
184
|
+
|
|
185
|
+
if (this.#options.resetOnReload || !this.#svg.value) {
|
|
186
|
+
this.#panzoomController.disable();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
this.#wrapper.innerHTML = this.#svg.value;
|
|
190
|
+
|
|
191
|
+
// If SVG is empty, do not initialize Panzoom but don't emit an error
|
|
192
|
+
if (!this.#svg.value) {
|
|
193
|
+
this.#onLoaded();
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (!this.#panzoomController.panzoom) {
|
|
198
|
+
this.#panzoomController.enable();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
this.#onLoaded();
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Handle invalid or unsupported SVG input. Emits a custom error event.
|
|
207
|
+
* @private
|
|
208
|
+
* @returns {void}
|
|
209
|
+
*/
|
|
210
|
+
#onError() {
|
|
211
|
+
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.";
|
|
212
|
+
this.dispatchEvent(
|
|
213
|
+
new CustomEvent("prefviewer2d-error", {
|
|
214
|
+
bubbles: true,
|
|
215
|
+
cancelable: false,
|
|
216
|
+
composed: true,
|
|
217
|
+
detail: { error: new Error(error) },
|
|
218
|
+
})
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Called when SVG and Panzoom are ready; sets loaded flag and subscribes to events.
|
|
224
|
+
* @private
|
|
225
|
+
* @returns {void}
|
|
226
|
+
*/
|
|
227
|
+
#onLoaded() {
|
|
228
|
+
this.dispatchEvent(
|
|
229
|
+
new CustomEvent("prefviewer2d-loaded", {
|
|
230
|
+
bubbles: true,
|
|
231
|
+
cancelable: false,
|
|
232
|
+
composed: true,
|
|
233
|
+
})
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
this.removeAttribute("loading");
|
|
237
|
+
this.setAttribute("loaded", "");
|
|
238
|
+
|
|
239
|
+
this.#isLoaded = true;
|
|
240
|
+
this.#subscribeToEvents();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Called before loading starts; clears loaded flag and unsubscribes from events.
|
|
245
|
+
* @private
|
|
246
|
+
* @returns {void}
|
|
247
|
+
*/
|
|
248
|
+
#onLoading() {
|
|
249
|
+
this.dispatchEvent(
|
|
250
|
+
new CustomEvent("prefviewer2d-loading", {
|
|
251
|
+
bubbles: true,
|
|
252
|
+
cancelable: false,
|
|
253
|
+
composed: true,
|
|
254
|
+
})
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
this.removeAttribute("loaded");
|
|
258
|
+
this.setAttribute("loading", "");
|
|
259
|
+
|
|
260
|
+
if (this.#isLoaded === true) {
|
|
261
|
+
this.#isLoaded = false;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
this.#unsubscribeToEvents();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Handles Panzoom state changes by dispatching a "prefviewer2d-zoomchanged" custom event.
|
|
269
|
+
* @private
|
|
270
|
+
* @param {object} state - The current Panzoom state object.
|
|
271
|
+
* @returns {void}
|
|
272
|
+
* @description
|
|
273
|
+
* The event detail contains the Panzoom state: { moved, scaled, maximized, minimized } to provide
|
|
274
|
+
* the UI with the enabled/disabled status of the zoomIn, zoomOut, center, and zoomExtentsAll buttons.
|
|
275
|
+
*/
|
|
276
|
+
#onPanzoomChanged(state) {
|
|
277
|
+
this.dispatchEvent(
|
|
278
|
+
new CustomEvent("prefviewer2d-zoomchanged", {
|
|
279
|
+
bubbles: true,
|
|
280
|
+
cancelable: false,
|
|
281
|
+
composed: true,
|
|
282
|
+
detail: state,
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Subscribe DOM events required by Panzoom and keyboard interactions.
|
|
289
|
+
* @private
|
|
290
|
+
* @returns {void}
|
|
291
|
+
* @description
|
|
292
|
+
* Adds listeners only when Panzoom exists and component is visible.
|
|
293
|
+
* Delegates event binding to PanzoomController instance.
|
|
294
|
+
*/
|
|
295
|
+
#subscribeToEvents() {
|
|
296
|
+
if (!this.#panzoomController || !this.#isVisible) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
this.#panzoomController.enableEvents();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Unsubscribe previously attached DOM events.
|
|
304
|
+
* @private
|
|
305
|
+
* @returns {void}
|
|
306
|
+
* @description
|
|
307
|
+
* Delegates event binding to PanzoomController instance.
|
|
308
|
+
*/
|
|
309
|
+
#unsubscribeToEvents() {
|
|
310
|
+
if (!this.#panzoomController) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
this.#panzoomController.disableEvents();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* ---------------------------
|
|
318
|
+
* Public methods
|
|
319
|
+
* ---------------------------
|
|
320
|
+
*/
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Load a new SVG resource into the viewer.
|
|
324
|
+
* @public
|
|
325
|
+
* @param {object} svgConfig - SVG configuration. An object with a `storage` property describing the source:
|
|
326
|
+
* { storage: { url: "<url>" } }
|
|
327
|
+
* or { storage: { db: "<db>", table: "<table>", id: "<id>" } }
|
|
328
|
+
* @returns {Promise<boolean|void>}
|
|
329
|
+
* - Resolves to false when the input is invalid or the SVG could not be retrieved/decoded, or when there is no update required (cached copy unchanged).
|
|
330
|
+
* - Resolves to true when the SVG was accepted and the component has started rendering.
|
|
331
|
+
*/
|
|
332
|
+
async load(svgConfig) {
|
|
333
|
+
if (!svgConfig || !(await this.#svgResolver.getSVG(svgConfig))) {
|
|
334
|
+
this.#onError();
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
this.#isInitialized && this.#loadSVG();
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Hide the component: set style, attribute and unsubscribe from events.
|
|
343
|
+
* @public
|
|
344
|
+
* @returns {void}
|
|
345
|
+
*/
|
|
346
|
+
hide() {
|
|
347
|
+
this.#isVisible = false;
|
|
348
|
+
this.setAttribute("visible", "false");
|
|
349
|
+
this.#unsubscribeToEvents();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Show the component: set style, attribute and subscribe to events.
|
|
354
|
+
* @public
|
|
355
|
+
* @returns {void}
|
|
356
|
+
*/
|
|
357
|
+
show() {
|
|
358
|
+
this.#isVisible = true;
|
|
359
|
+
this.setAttribute("visible", "true");
|
|
360
|
+
this.#subscribeToEvents();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Pans the SVG view to the center without changing the zoom level.
|
|
365
|
+
* Delegates the pan action to the PanzoomController instance.
|
|
366
|
+
* @public
|
|
367
|
+
* @returns {void}
|
|
368
|
+
*/
|
|
369
|
+
zoomCenter() {
|
|
370
|
+
if (!this.#panzoomController) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
this.#panzoomController.pan(0, 0);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Resets pan and zoom so the entire SVG drawing fits within the available space.
|
|
378
|
+
* Delegates the reset action to the PanzoomController instance.
|
|
379
|
+
* @public
|
|
380
|
+
* @returns {void}
|
|
381
|
+
*/
|
|
382
|
+
zoomExtentsAll() {
|
|
383
|
+
if (!this.#panzoomController) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
this.#panzoomController.reset();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Zoom in the SVG view one step.
|
|
391
|
+
* Delegates the zoom-in action to the PanzoomController instance.
|
|
392
|
+
* @public
|
|
393
|
+
* @returns {void}
|
|
394
|
+
*/
|
|
395
|
+
zoomIn() {
|
|
396
|
+
if (!this.#panzoomController) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
this.#panzoomController.zoomIn();
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Zoom out the SVG view one step.
|
|
404
|
+
* Delegates the zoom-out action to the PanzoomController instance.
|
|
405
|
+
* @public
|
|
406
|
+
* @returns {void}
|
|
407
|
+
*/
|
|
408
|
+
zoomOut() {
|
|
409
|
+
if (!this.#panzoomController) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
this.#panzoomController.zoomOut();
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Indicates whether the component has completed its initialization.
|
|
417
|
+
* @public
|
|
418
|
+
* @returns {boolean} True if the component is initialized; otherwise, false.
|
|
419
|
+
*/
|
|
420
|
+
get initialized() {
|
|
421
|
+
return this.#isInitialized;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Indicates whether the SVG content is loaded and ready.
|
|
426
|
+
* @public
|
|
427
|
+
* @returns {boolean} True if the SVG is loaded; otherwise, false.
|
|
428
|
+
*/
|
|
429
|
+
get loaded() {
|
|
430
|
+
return this.#isLoaded;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Indicates whether the component is currently visible.
|
|
435
|
+
* @public
|
|
436
|
+
* @returns {boolean} True if the component is visible; otherwise, false.
|
|
437
|
+
*/
|
|
438
|
+
get visible() {
|
|
439
|
+
return this.#isVisible;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContainerData - Represents the state and metadata of a asset container in the 3D viewer (e.g., model, environment, materials).
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Tracks container name, show (if must be visible), visibility (if currently visible), size, and timestamp.
|
|
6
|
+
* - Manages update state for asynchronous operations (pending, success, etc.).
|
|
7
|
+
* - Provides methods to reset, set pending, and set success states.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* - Instantiate with a name: new ContainerData("model")
|
|
11
|
+
* - Use setPending(), setSuccess(), and reset() to manage update state.
|
|
12
|
+
* - Access status via isPending, isSuccess, isVisible getters.
|
|
13
|
+
*/
|
|
14
|
+
export class ContainerData {
|
|
15
|
+
constructor(name = "") {
|
|
16
|
+
this.name = name;
|
|
17
|
+
this.show = true;
|
|
18
|
+
this.size = 0;
|
|
19
|
+
this.timeStamp = null;
|
|
20
|
+
this.visible = false;
|
|
21
|
+
// Set initial information about ongoing update
|
|
22
|
+
this.reset();
|
|
23
|
+
}
|
|
24
|
+
reset() {
|
|
25
|
+
this.update = {
|
|
26
|
+
pending: false,
|
|
27
|
+
storage: null,
|
|
28
|
+
success: false,
|
|
29
|
+
show: null,
|
|
30
|
+
size: 0,
|
|
31
|
+
timeStamp: null,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
setSuccess(success = false) {
|
|
35
|
+
if (success) {
|
|
36
|
+
this.update.success = true;
|
|
37
|
+
this.show = this.update.show !== null ? this.update.show : this.show;
|
|
38
|
+
this.size = this.update.size;
|
|
39
|
+
this.timeStamp = this.update.timeStamp;
|
|
40
|
+
} else {
|
|
41
|
+
this.update.success = false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
setPending(storage = null, show) {
|
|
45
|
+
this.reset();
|
|
46
|
+
this.update.pending = true;
|
|
47
|
+
this.update.storage = storage;
|
|
48
|
+
this.update.success = false;
|
|
49
|
+
this.update.show = show !== undefined ? show : this.update.show;
|
|
50
|
+
}
|
|
51
|
+
setPendingCacheData(size = 0, timeStamp = null) {
|
|
52
|
+
this.update.size = size;
|
|
53
|
+
this.update.timeStamp = timeStamp;
|
|
54
|
+
}
|
|
55
|
+
get isPending() {
|
|
56
|
+
return this.update.pending === true;
|
|
57
|
+
}
|
|
58
|
+
get isSuccess() {
|
|
59
|
+
return this.update.success === true;
|
|
60
|
+
}
|
|
61
|
+
get isVisible() {
|
|
62
|
+
return this.visible === true;
|
|
63
|
+
}
|
|
64
|
+
get mustBeShown() {
|
|
65
|
+
return this.show === true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* MaterialData - Represents the state and metadata of a material in the 3D viewer.
|
|
71
|
+
*
|
|
72
|
+
* Responsibilities:
|
|
73
|
+
* - Tracks material name, value, node names, and node prefixes.
|
|
74
|
+
* - Manages update state for asynchronous operations (pending, success, etc.).
|
|
75
|
+
* - Provides methods to reset, set pending, and set success states.
|
|
76
|
+
*
|
|
77
|
+
* Usage:
|
|
78
|
+
* - Instantiate with a name and optional value: new MaterialData("innerWall", value, nodeNames, nodePrefixes)
|
|
79
|
+
* - Use setPending(), setSuccess(), and reset() to manage update state.
|
|
80
|
+
* - Access status via isPending, isSuccess getters.
|
|
81
|
+
*/
|
|
82
|
+
export class MaterialData {
|
|
83
|
+
constructor(name = "", value = null, nodeNames = [], nodePrefixes = []) {
|
|
84
|
+
this.name = name;
|
|
85
|
+
this.nodeNames = nodeNames;
|
|
86
|
+
this.nodePrefixes = nodePrefixes;
|
|
87
|
+
this.value = value;
|
|
88
|
+
// Set initial information about ongoing update
|
|
89
|
+
this.reset();
|
|
90
|
+
}
|
|
91
|
+
reset() {
|
|
92
|
+
this.update = {
|
|
93
|
+
pending: false,
|
|
94
|
+
success: false,
|
|
95
|
+
value: null,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
setSuccess(success = false) {
|
|
99
|
+
if (success) {
|
|
100
|
+
this.update.success = true;
|
|
101
|
+
this.value = this.update.value;
|
|
102
|
+
} else {
|
|
103
|
+
this.update.success = false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
setPending(value = null) {
|
|
107
|
+
this.reset();
|
|
108
|
+
this.update.pending = true;
|
|
109
|
+
this.update.success = false;
|
|
110
|
+
this.update.value = value;
|
|
111
|
+
}
|
|
112
|
+
setPendingWithCurrent() {
|
|
113
|
+
this.setPending(this.value);
|
|
114
|
+
}
|
|
115
|
+
get isPending() {
|
|
116
|
+
return this.update.pending === true;
|
|
117
|
+
}
|
|
118
|
+
get isSuccess() {
|
|
119
|
+
return this.update.success === true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* CameraData - Represents the state and metadata of a camera in the 3D viewer.
|
|
125
|
+
*
|
|
126
|
+
* Responsibilities:
|
|
127
|
+
* - Tracks camera name, value, and locked status.
|
|
128
|
+
* - Manages update state for asynchronous operations (pending, success, etc.).
|
|
129
|
+
* - Provides methods to reset, set pending, and set success states.
|
|
130
|
+
*
|
|
131
|
+
* Usage:
|
|
132
|
+
* - Instantiate with a name and optional value: new CameraData("camera", value, locked)
|
|
133
|
+
* - Use setPending(), setSuccess(), and reset() to manage update state.
|
|
134
|
+
* - Access status via isPending, isSuccess getters.
|
|
135
|
+
*/
|
|
136
|
+
export class CameraData {
|
|
137
|
+
constructor(name = "", value = null, locked = true) {
|
|
138
|
+
this.name = name;
|
|
139
|
+
this.value = value;
|
|
140
|
+
this.locked = locked;
|
|
141
|
+
// Set initial information about ongoing update
|
|
142
|
+
this.reset();
|
|
143
|
+
}
|
|
144
|
+
reset() {
|
|
145
|
+
this.update = {
|
|
146
|
+
pending: false,
|
|
147
|
+
success: false,
|
|
148
|
+
value: null,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
setSuccess(success = false) {
|
|
152
|
+
if (success) {
|
|
153
|
+
this.update.success = true;
|
|
154
|
+
this.value = this.update.value;
|
|
155
|
+
} else {
|
|
156
|
+
this.update.success = false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
setPending(value = undefined, locked = true) {
|
|
160
|
+
this.reset();
|
|
161
|
+
if (value === undefined) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (value === null) {
|
|
165
|
+
locked = false;
|
|
166
|
+
}
|
|
167
|
+
this.update.pending = true;
|
|
168
|
+
this.update.success = false;
|
|
169
|
+
this.update.value = value;
|
|
170
|
+
this.update.locked = locked;
|
|
171
|
+
}
|
|
172
|
+
get isPending() {
|
|
173
|
+
return this.update.pending === true;
|
|
174
|
+
}
|
|
175
|
+
get isSuccess() {
|
|
176
|
+
return this.update.success === true;
|
|
177
|
+
}
|
|
178
|
+
}
|