@preference-sl/pref-viewer 2.16.0-beta.9 → 2.16.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/README.md +129 -102
- package/index.d.ts +373 -12
- package/package.json +7 -6
- package/src/babylonjs-animation-opening.js +11 -5
- package/src/babylonjs-controller.js +484 -271
- package/src/localization/translations.js +5 -17
- package/src/material-utils.js +72 -0
- package/src/panzoom-controller.js +36 -17
- package/src/pref-viewer-2d.js +395 -21
- package/src/pref-viewer-3d.js +160 -89
- package/src/pref-viewer-menu-3d.js +185 -268
- package/src/pref-viewer-task.js +7 -2
- package/src/pref-viewer.js +618 -188
- package/src/render-math.js +127 -0
- package/src/styles.js +169 -178
|
@@ -3,18 +3,12 @@ export const translations = {
|
|
|
3
3
|
prefViewer: {
|
|
4
4
|
menu3d: {
|
|
5
5
|
title: "3D render settings",
|
|
6
|
-
subtitle: "
|
|
7
|
-
pendingLabel: "Pending changes",
|
|
6
|
+
subtitle: "Modify the visual effects.",
|
|
8
7
|
actions: {
|
|
9
|
-
apply: "Apply",
|
|
10
|
-
applying: "Applying...",
|
|
11
8
|
play: "Play",
|
|
12
9
|
pause: "Pause",
|
|
13
10
|
},
|
|
14
|
-
|
|
15
|
-
error: "Couldn't apply the changes.",
|
|
16
|
-
},
|
|
17
|
-
switches: {
|
|
11
|
+
features: {
|
|
18
12
|
antiAliasingEnabled: {
|
|
19
13
|
label: "Antialiasing",
|
|
20
14
|
helper: "Softens jagged edges and lines.",
|
|
@@ -70,18 +64,12 @@ export const translations = {
|
|
|
70
64
|
prefViewer: {
|
|
71
65
|
menu3d: {
|
|
72
66
|
title: "Ajustes de render 3D",
|
|
73
|
-
subtitle: "
|
|
74
|
-
pendingLabel: "Pendiente de aplicar",
|
|
67
|
+
subtitle: "Modifica los efectos visuales.",
|
|
75
68
|
actions: {
|
|
76
|
-
apply: "Aplicar",
|
|
77
|
-
applying: "Aplicando...",
|
|
78
69
|
play: "Reproducir",
|
|
79
70
|
pause: "Pausar",
|
|
80
71
|
},
|
|
81
|
-
|
|
82
|
-
error: "No se pudo aplicar los cambios.",
|
|
83
|
-
},
|
|
84
|
-
switches: {
|
|
72
|
+
features: {
|
|
85
73
|
antiAliasingEnabled: {
|
|
86
74
|
label: "Antialiasing",
|
|
87
75
|
helper: "Suaviza aristas y líneas.",
|
|
@@ -100,7 +88,7 @@ export const translations = {
|
|
|
100
88
|
},
|
|
101
89
|
highlightEnabled: {
|
|
102
90
|
label: "Resaltado",
|
|
103
|
-
helper: "
|
|
91
|
+
helper: "Resalta elementos animados al pasar el ratón.",
|
|
104
92
|
},
|
|
105
93
|
highlightColor: {
|
|
106
94
|
label: "Color de resaltado",
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { PBRMaterial } from "@babylonjs/core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utilities for classifying and tagging PBR materials by their transparency/transmission mode.
|
|
5
|
+
* Used by BabylonJSController at load time and by pref-viewer-3d for render-order decisions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const PREF_VIEWER_SIMPLIFIED_TRANSMISSION_METADATA_KEY = "prefViewerSimplifiedTransmission";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Tags a PBR material as having been converted from physical KHR_materials_transmission to simple
|
|
12
|
+
* alpha blending. The tag is stored in `mat.metadata` under an internal key so that downstream
|
|
13
|
+
* render-order passes can still identify these materials as transparent candidates even after
|
|
14
|
+
* their `subSurface.isRefractionEnabled` flag has been cleared.
|
|
15
|
+
*
|
|
16
|
+
* Returns the same material instance (or the original value when `mat` is falsy) so calls can be
|
|
17
|
+
* chained.
|
|
18
|
+
* @param {import("@babylonjs/core").PBRMaterial|null|undefined} mat - Material to tag.
|
|
19
|
+
* @returns {import("@babylonjs/core").PBRMaterial|null|undefined} The same `mat` value that was passed in.
|
|
20
|
+
*/
|
|
21
|
+
export function markPrefViewerSimplifiedTransmissionMaterial(mat) {
|
|
22
|
+
if (!mat) {
|
|
23
|
+
return mat;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
mat.metadata = {
|
|
27
|
+
...(mat.metadata ?? {}),
|
|
28
|
+
[PREF_VIEWER_SIMPLIFIED_TRANSMISSION_METADATA_KEY]: true,
|
|
29
|
+
};
|
|
30
|
+
return mat;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Returns true when the material uses Babylon.js physical glass rendering — i.e. either
|
|
35
|
+
* KHR_materials_transmission (refraction) or KHR_materials_translucency is active.
|
|
36
|
+
*
|
|
37
|
+
* This is intentionally narrower than `isPrefViewerTransparentRenderOrderMaterial`: it only
|
|
38
|
+
* matches full physical transmission, not plain alpha blending or simplified environment glass.
|
|
39
|
+
* @param {import("@babylonjs/core").Material|null|undefined} mat - Material to test.
|
|
40
|
+
* @returns {boolean}
|
|
41
|
+
*/
|
|
42
|
+
export function isPrefViewerPhysicalGlassMaterial(mat) {
|
|
43
|
+
return Boolean(mat?.subSurface?.isRefractionEnabled || mat?.subSurface?.isTranslucencyEnabled);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Returns true when a material should be placed in the transparent rendering group (renderingGroupId=1).
|
|
48
|
+
*
|
|
49
|
+
* A material qualifies when any of the following is true:
|
|
50
|
+
* - It is a physical glass material (KHR_materials_transmission / translucency).
|
|
51
|
+
* - It has been tagged as simplified environment transmission via `markPrefViewerSimplifiedTransmissionMaterial`.
|
|
52
|
+
* - Its effective alpha is below 1, its `transparencyMode` is alpha-blend or alpha-test-and-blend,
|
|
53
|
+
* or it self-reports as needing blending/testing through the Babylon.js material API.
|
|
54
|
+
* @param {import("@babylonjs/core").Material|null|undefined} mat - Material to test.
|
|
55
|
+
* @returns {boolean}
|
|
56
|
+
*/
|
|
57
|
+
export function isPrefViewerTransparentRenderOrderMaterial(mat) {
|
|
58
|
+
if (!mat) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const isTransmissive = isPrefViewerPhysicalGlassMaterial(mat);
|
|
62
|
+
const isSimplifiedTransmission = mat.metadata?.[PREF_VIEWER_SIMPLIFIED_TRANSMISSION_METADATA_KEY] === true;
|
|
63
|
+
const alpha = typeof mat.alpha === "number" ? mat.alpha : 1;
|
|
64
|
+
const isAlphaBlended =
|
|
65
|
+
alpha < 1 ||
|
|
66
|
+
mat.transparencyMode === PBRMaterial.PBRMATERIAL_ALPHABLEND ||
|
|
67
|
+
mat.transparencyMode === PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND ||
|
|
68
|
+
mat.needAlphaBlending?.() === true ||
|
|
69
|
+
mat.needAlphaTesting?.() === true;
|
|
70
|
+
|
|
71
|
+
return Boolean(isTransmissive || isSimplifiedTransmission || isAlphaBlended);
|
|
72
|
+
}
|
|
@@ -27,6 +27,7 @@ import Panzoom from "@panzoom/panzoom/dist/panzoom.es.js";
|
|
|
27
27
|
* - wrapper (HTMLElement): The DOM element to apply pan/zoom interactions to.
|
|
28
28
|
* - options (object): Configuration options for Panzoom (e.g., minScale, maxScale, step).
|
|
29
29
|
* - changedCallback (function): Optional callback invoked when the pan/zoom state changes.
|
|
30
|
+
* - clickCallback (function): Optional callback invoked with the original event after a gesture is classified as a click.
|
|
30
31
|
*
|
|
31
32
|
* Public Methods:
|
|
32
33
|
* - enable(): Enables the Panzoom instance and initializes it if not already enabled.
|
|
@@ -40,7 +41,7 @@ import Panzoom from "@panzoom/panzoom/dist/panzoom.es.js";
|
|
|
40
41
|
*
|
|
41
42
|
* Getters:
|
|
42
43
|
* - panzoom: Returns the current Panzoom instance or null if not initialized.
|
|
43
|
-
* - state: Returns the current pan/zoom
|
|
44
|
+
* - state: Returns the current pan/zoom transform and semantic state.
|
|
44
45
|
*
|
|
45
46
|
* Private Methods:
|
|
46
47
|
* - #bindHandlers(): Pre-binds reusable event handlers to preserve stable references.
|
|
@@ -81,6 +82,9 @@ export default class PanzoomController {
|
|
|
81
82
|
totalCounter: 0,
|
|
82
83
|
};
|
|
83
84
|
#state = {
|
|
85
|
+
x: 0,
|
|
86
|
+
y: 0,
|
|
87
|
+
scale: 1,
|
|
84
88
|
moved: false,
|
|
85
89
|
scaled: false,
|
|
86
90
|
maximized: false,
|
|
@@ -89,6 +93,7 @@ export default class PanzoomController {
|
|
|
89
93
|
#wrapper = null;
|
|
90
94
|
|
|
91
95
|
#changedCallback = null;
|
|
96
|
+
#clickCallback = null;
|
|
92
97
|
#handlers = {
|
|
93
98
|
panzoomStart: null,
|
|
94
99
|
panzoomChange: null,
|
|
@@ -100,10 +105,11 @@ export default class PanzoomController {
|
|
|
100
105
|
wheel: null,
|
|
101
106
|
};
|
|
102
107
|
|
|
103
|
-
constructor(wrapper = null, options = {}, changedCallback = null) {
|
|
108
|
+
constructor(wrapper = null, options = {}, changedCallback = null, clickCallback = null) {
|
|
104
109
|
this.#wrapper = wrapper;
|
|
105
110
|
Object.assign(this.#options, options);
|
|
106
111
|
this.#changedCallback = changedCallback;
|
|
112
|
+
this.#clickCallback = clickCallback;
|
|
107
113
|
this.#bindHandlers();
|
|
108
114
|
}
|
|
109
115
|
|
|
@@ -145,7 +151,7 @@ export default class PanzoomController {
|
|
|
145
151
|
* @returns {{x:number,y:number}|null} Point or null if coordinates not present.
|
|
146
152
|
*/
|
|
147
153
|
#getPointFromEvent(e) {
|
|
148
|
-
if (e
|
|
154
|
+
if (Number.isFinite(e?.clientX) && Number.isFinite(e?.clientY)) {
|
|
149
155
|
return {
|
|
150
156
|
x: e.clientX,
|
|
151
157
|
y: e.clientY,
|
|
@@ -155,6 +161,13 @@ export default class PanzoomController {
|
|
|
155
161
|
}
|
|
156
162
|
}
|
|
157
163
|
|
|
164
|
+
/** Reset transient pointer data after a completed or interrupted gesture. */
|
|
165
|
+
#resetPointerEvents() {
|
|
166
|
+
this.#pointerEvents.lastPointerDownPosition = null;
|
|
167
|
+
this.#pointerEvents.partialCounter = 0;
|
|
168
|
+
this.#pointerEvents.totalCounter = 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
158
171
|
/**
|
|
159
172
|
* Update internal pan/zoom state and emit a custom event with current values.
|
|
160
173
|
* If a changed callback is defined, it is invoked with the updated state object.
|
|
@@ -164,6 +177,9 @@ export default class PanzoomController {
|
|
|
164
177
|
*/
|
|
165
178
|
#checkPanzoomState(transform) {
|
|
166
179
|
this.#state = {
|
|
180
|
+
x: transform.x,
|
|
181
|
+
y: transform.y,
|
|
182
|
+
scale: transform.scale,
|
|
167
183
|
moved: transform.x !== 0 || transform.y !== 0,
|
|
168
184
|
scaled: transform.scale !== 1,
|
|
169
185
|
maximized: transform.scale === this.#options.maxScale,
|
|
@@ -252,7 +268,6 @@ export default class PanzoomController {
|
|
|
252
268
|
* @private
|
|
253
269
|
* @param {CustomEvent} e - Panzoom custom event with originalEvent property.
|
|
254
270
|
* @returns {void}
|
|
255
|
-
* @todo Implement selection/click logic.
|
|
256
271
|
*/
|
|
257
272
|
#onPanzoomEnd(e) {
|
|
258
273
|
this.#pointerEvents.partialCounter--;
|
|
@@ -260,21 +275,21 @@ export default class PanzoomController {
|
|
|
260
275
|
if (this.#pointerEvents.partialCounter > 0) {
|
|
261
276
|
return;
|
|
262
277
|
} else if (this.#pointerEvents.totalCounter > 1) {
|
|
263
|
-
this.#
|
|
264
|
-
this.#pointerEvents.totalCounter = 0;
|
|
278
|
+
this.#resetPointerEvents();
|
|
265
279
|
return;
|
|
266
280
|
}
|
|
267
281
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
282
|
+
const originalEvent = e?.detail?.originalEvent;
|
|
283
|
+
if (!originalEvent) {
|
|
284
|
+
this.#resetPointerEvents();
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
272
287
|
const point = this.#getPointFromEvent(originalEvent);
|
|
273
288
|
const distance = this.#getDistanceBetweenPoints(point, this.#pointerEvents.lastPointerDownPosition);
|
|
274
289
|
|
|
275
290
|
let proceedToPick = true;
|
|
276
291
|
|
|
277
|
-
if (!point || distance > this.#interactionOptions.clickThreshold) {
|
|
292
|
+
if (!point || !this.#pointerEvents.lastPointerDownPosition || distance > this.#interactionOptions.clickThreshold) {
|
|
278
293
|
proceedToPick = false;
|
|
279
294
|
}
|
|
280
295
|
|
|
@@ -282,7 +297,7 @@ export default class PanzoomController {
|
|
|
282
297
|
proceedToPick = false;
|
|
283
298
|
}
|
|
284
299
|
|
|
285
|
-
this.#
|
|
300
|
+
this.#resetPointerEvents();
|
|
286
301
|
|
|
287
302
|
if (!proceedToPick) {
|
|
288
303
|
return;
|
|
@@ -292,7 +307,9 @@ export default class PanzoomController {
|
|
|
292
307
|
return;
|
|
293
308
|
}
|
|
294
309
|
|
|
295
|
-
|
|
310
|
+
if (typeof this.#clickCallback === "function") {
|
|
311
|
+
this.#clickCallback(originalEvent);
|
|
312
|
+
}
|
|
296
313
|
}
|
|
297
314
|
|
|
298
315
|
/**
|
|
@@ -302,7 +319,7 @@ export default class PanzoomController {
|
|
|
302
319
|
* @returns {void}
|
|
303
320
|
*/
|
|
304
321
|
#onPanzoomStart(e) {
|
|
305
|
-
const originalEvent = e
|
|
322
|
+
const originalEvent = e?.detail?.originalEvent;
|
|
306
323
|
this.#pointerEvents.partialCounter++;
|
|
307
324
|
this.#pointerEvents.totalCounter++;
|
|
308
325
|
this.#pointerEvents.lastPointerDownPosition = this.#getPointFromEvent(originalEvent);
|
|
@@ -421,13 +438,15 @@ export default class PanzoomController {
|
|
|
421
438
|
if (!this.#wrapper) {
|
|
422
439
|
return;
|
|
423
440
|
}
|
|
441
|
+
this.#disableMouseWheelZoom();
|
|
442
|
+
this.#resetPointerEvents();
|
|
424
443
|
this.#wrapper.parentElement.removeAttribute("tabindex");
|
|
425
444
|
this.#wrapper.removeEventListener("panzoomstart", this.#handlers.panzoomStart);
|
|
426
445
|
this.#wrapper.removeEventListener("panzoomchange", this.#handlers.panzoomChange);
|
|
427
446
|
this.#wrapper.removeEventListener("panzoomend", this.#handlers.panzoomEnd);
|
|
428
447
|
this.#wrapper.parentElement.removeEventListener("keyup", this.#handlers.keyUp);
|
|
429
|
-
this.#wrapper.parentElement.removeEventListener("focus", this.#handlers.focus);
|
|
430
|
-
this.#wrapper.parentElement.removeEventListener("blur", this.#handlers.blur);
|
|
448
|
+
this.#wrapper.parentElement.removeEventListener("focus", this.#handlers.focus, true);
|
|
449
|
+
this.#wrapper.parentElement.removeEventListener("blur", this.#handlers.blur, true);
|
|
431
450
|
this.#wrapper.parentElement.removeEventListener("contextmenu", this.#handlers.contextMenu);
|
|
432
451
|
}
|
|
433
452
|
|
|
@@ -523,7 +542,7 @@ export default class PanzoomController {
|
|
|
523
542
|
/**
|
|
524
543
|
* Returns the current pan/zoom state.
|
|
525
544
|
* @public
|
|
526
|
-
* @returns {object} The state object: { moved, scaled, maximized, minimized }.
|
|
545
|
+
* @returns {object} The state object: { x, y, scale, moved, scaled, maximized, minimized }.
|
|
527
546
|
*/
|
|
528
547
|
get state() {
|
|
529
548
|
return this.#state;
|