@preference-sl/pref-viewer 2.16.0-beta.14 → 2.16.0-beta.19
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 +9 -5
- package/index.d.ts +373 -12
- package/package.json +2 -1
- package/src/babylonjs-controller.js +105 -5
- package/src/panzoom-controller.js +28 -15
- package/src/pref-viewer-2d.js +384 -3
- package/src/pref-viewer.js +79 -11
- package/src/styles.js +6 -0
package/src/pref-viewer.js
CHANGED
|
@@ -45,6 +45,7 @@ import { DEFAULT_LOCALE, resolveLocale, setLocale, SUPPORTED_LOCALES } from "./l
|
|
|
45
45
|
* - clearSelectedElements / clearSelectableElements / clearSelectionState: Reset selection state fully or partially.
|
|
46
46
|
* - getSelectionState: Return a snapshot of the current selection.
|
|
47
47
|
* - notifyElementClick: Forward a host-side element click into the viewer event stream.
|
|
48
|
+
* - appendSvgNode / removeAppendedSvgNodes: Manage host-provided SVG nodes through the root facade.
|
|
48
49
|
* - startTurnable / stopTurnable / toggleTurnable / getTurnableState: Control and inspect the auto-rotate state.
|
|
49
50
|
* - getAnimations / playAnimation / setAnimationProgress / setAnimationLoop: Inspect and control named glTF animations.
|
|
50
51
|
* - getDebugInfo: Return a diagnostic snapshot of the active 3D runtime.
|
|
@@ -61,7 +62,7 @@ import { DEFAULT_LOCALE, resolveLocale, setLocale, SUPPORTED_LOCALES } from "./l
|
|
|
61
62
|
* - `pref-viewer-2d-viewport-changed`: proxies pan/zoom delta from the 2D controller.
|
|
62
63
|
* - `pref-viewer-selection-state-changed`: emitted whenever the selectable or selected element sets change.
|
|
63
64
|
* - `pref-viewer-3d-turnable-changed`: emitted after the auto-rotate state starts, stops, or is toggled.
|
|
64
|
-
* - `pref-viewer-element-click`: emitted
|
|
65
|
+
* - `pref-viewer-element-click`: emitted with `{ ids: string[] }` for 2D or host-forwarded semantic clicks.
|
|
65
66
|
* - Legacy `scene-*` and `drawing-*` aliases are still emitted alongside their modern equivalents for backward compatibility.
|
|
66
67
|
*
|
|
67
68
|
* Notes:
|
|
@@ -113,6 +114,7 @@ export default class PrefViewer extends HTMLElement {
|
|
|
113
114
|
// Event handlers
|
|
114
115
|
#handlers = {
|
|
115
116
|
on2DZoomChanged: null,
|
|
117
|
+
on2DElementClick: null,
|
|
116
118
|
onMenuApply: null,
|
|
117
119
|
onViewerHoverStart: null,
|
|
118
120
|
onViewerHoverEnd: null,
|
|
@@ -264,6 +266,7 @@ export default class PrefViewer extends HTMLElement {
|
|
|
264
266
|
}
|
|
265
267
|
if (this.#component2D) {
|
|
266
268
|
this.#component2D.removeEventListener("pref-viewer-2d-viewport-changed", this.#handlers.on2DZoomChanged);
|
|
269
|
+
this.#component2D.removeEventListener("pref-viewer-2d-element-click", this.#handlers.on2DElementClick);
|
|
267
270
|
this.#component2D.remove();
|
|
268
271
|
}
|
|
269
272
|
if (this.#component3D) {
|
|
@@ -306,9 +309,11 @@ export default class PrefViewer extends HTMLElement {
|
|
|
306
309
|
*/
|
|
307
310
|
#createComponent2D() {
|
|
308
311
|
this.#handlers.on2DZoomChanged = this.#on2DZoomChanged.bind(this);
|
|
312
|
+
this.#handlers.on2DElementClick = this.#on2DElementClick.bind(this);
|
|
309
313
|
this.#component2D = document.createElement("pref-viewer-2d");
|
|
310
314
|
this.#component2D.setAttribute("visible", "false");
|
|
311
315
|
this.#component2D.addEventListener("pref-viewer-2d-viewport-changed", this.#handlers.on2DZoomChanged);
|
|
316
|
+
this.#component2D.addEventListener("pref-viewer-2d-element-click", this.#handlers.on2DElementClick);
|
|
312
317
|
this.#wrapper.appendChild(this.#component2D);
|
|
313
318
|
}
|
|
314
319
|
|
|
@@ -794,6 +799,8 @@ export default class PrefViewer extends HTMLElement {
|
|
|
794
799
|
this.removeAttribute("loading-2d");
|
|
795
800
|
this.setAttribute("loaded-2d", "");
|
|
796
801
|
|
|
802
|
+
this.#applySelectionStateTo2D();
|
|
803
|
+
|
|
797
804
|
this.#dispatchPrefViewerEvent("pref-viewer-2d-loaded", detail ?? {});
|
|
798
805
|
this.#dispatchPrefViewerEvent("drawing-loaded", detail ?? {}); // Legacy event for backward compatibility
|
|
799
806
|
this.#dispatchPrefViewerEvent("pref-viewer-loaded", { result: detail ?? null });
|
|
@@ -832,6 +839,17 @@ export default class PrefViewer extends HTMLElement {
|
|
|
832
839
|
this.#dispatchPrefViewerEvent("pref-viewer-2d-viewport-changed", detail);
|
|
833
840
|
}
|
|
834
841
|
|
|
842
|
+
/**
|
|
843
|
+
* Proxy semantic click ids from the encapsulated 2D component.
|
|
844
|
+
* @private
|
|
845
|
+
* @param {CustomEvent} event - Internal component event.
|
|
846
|
+
* @returns {void}
|
|
847
|
+
*/
|
|
848
|
+
#on2DElementClick(event) {
|
|
849
|
+
event.stopPropagation();
|
|
850
|
+
this.notifyElementClick(event.detail?.ids ?? []);
|
|
851
|
+
}
|
|
852
|
+
|
|
835
853
|
/**
|
|
836
854
|
* Handles the custom "pref-viewer-3d-render-settings-change-requested" event emitted by the menu component.
|
|
837
855
|
* Forwards the requested settings to the render-application pipeline.
|
|
@@ -1102,6 +1120,11 @@ export default class PrefViewer extends HTMLElement {
|
|
|
1102
1120
|
this.#dispatchPrefViewerEvent("pref-viewer-selection-state-changed", this.getSelectionState());
|
|
1103
1121
|
}
|
|
1104
1122
|
|
|
1123
|
+
/** Apply the current semantic snapshot to the 2D renderer when available. */
|
|
1124
|
+
#applySelectionStateTo2D() {
|
|
1125
|
+
this.#component2D?.applySelectionState?.(this.getSelectionState());
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1105
1128
|
/**
|
|
1106
1129
|
* Dispatches a `pref-viewer-3d-turnable-changed` event carrying the current turnable snapshot.
|
|
1107
1130
|
* Called after `startTurnable`, `stopTurnable`, or `toggleTurnable` mutates the internal state.
|
|
@@ -1407,13 +1430,14 @@ export default class PrefViewer extends HTMLElement {
|
|
|
1407
1430
|
|
|
1408
1431
|
/**
|
|
1409
1432
|
* Defines the elements that the host application considers selectable.
|
|
1410
|
-
*
|
|
1433
|
+
* The normalized state is rendered by the 2D component as non-destructive yellow SVG clones.
|
|
1411
1434
|
* @public
|
|
1412
1435
|
* @param {Array<string|{id?: string, Id?: string}>} elements - Element ids or objects containing id/Id.
|
|
1413
1436
|
* @returns {object} Current selection state.
|
|
1414
1437
|
*/
|
|
1415
1438
|
setSelectableElements(elements = []) {
|
|
1416
1439
|
this.#selectionState.selectableIds = this.#normalizeIdList(elements);
|
|
1440
|
+
this.#applySelectionStateTo2D();
|
|
1417
1441
|
this.#emitSelectionStateChanged();
|
|
1418
1442
|
return this.getSelectionState();
|
|
1419
1443
|
}
|
|
@@ -1428,6 +1452,7 @@ export default class PrefViewer extends HTMLElement {
|
|
|
1428
1452
|
const selectedItems = this.#normalizeSelectionItems(elements);
|
|
1429
1453
|
this.#selectionState.selectedItems = selectedItems;
|
|
1430
1454
|
this.#selectionState.selectedIds = selectedItems.map((item) => item.id);
|
|
1455
|
+
this.#applySelectionStateTo2D();
|
|
1431
1456
|
this.#emitSelectionStateChanged();
|
|
1432
1457
|
return this.getSelectionState();
|
|
1433
1458
|
}
|
|
@@ -1435,12 +1460,16 @@ export default class PrefViewer extends HTMLElement {
|
|
|
1435
1460
|
/**
|
|
1436
1461
|
* Applies a complete host selection state in one call.
|
|
1437
1462
|
* @public
|
|
1438
|
-
* @param {{selectableIds?: string
|
|
1463
|
+
* @param {{selectableIds?: Array<string|object>, selectables?: Array<string|object>, selectedItems?: Array<string|object>, selectedIds?: Array<string|object>, selected?: Array<string|object>}} state - Selection state with selectableIds/selectables and selectedItems/selectedIds/selected.
|
|
1439
1464
|
* @returns {object} Current selection state.
|
|
1440
1465
|
*/
|
|
1441
1466
|
applySelectionState(state = {}) {
|
|
1442
1467
|
this.#selectionState.selectableIds = this.#normalizeIdList(state.selectableIds ?? state.selectables ?? []);
|
|
1443
|
-
this
|
|
1468
|
+
const selectedItems = this.#normalizeSelectionItems(state.selectedItems ?? state.selectedIds ?? state.selected ?? []);
|
|
1469
|
+
this.#selectionState.selectedItems = selectedItems;
|
|
1470
|
+
this.#selectionState.selectedIds = selectedItems.map((item) => item.id);
|
|
1471
|
+
this.#applySelectionStateTo2D();
|
|
1472
|
+
this.#emitSelectionStateChanged();
|
|
1444
1473
|
return this.getSelectionState();
|
|
1445
1474
|
}
|
|
1446
1475
|
|
|
@@ -1452,6 +1481,7 @@ export default class PrefViewer extends HTMLElement {
|
|
|
1452
1481
|
clearSelectedElements() {
|
|
1453
1482
|
this.#selectionState.selectedIds = [];
|
|
1454
1483
|
this.#selectionState.selectedItems = [];
|
|
1484
|
+
this.#applySelectionStateTo2D();
|
|
1455
1485
|
this.#emitSelectionStateChanged();
|
|
1456
1486
|
return this.getSelectionState();
|
|
1457
1487
|
}
|
|
@@ -1463,6 +1493,7 @@ export default class PrefViewer extends HTMLElement {
|
|
|
1463
1493
|
*/
|
|
1464
1494
|
clearSelectableElements() {
|
|
1465
1495
|
this.#selectionState.selectableIds = [];
|
|
1496
|
+
this.#applySelectionStateTo2D();
|
|
1466
1497
|
this.#emitSelectionStateChanged();
|
|
1467
1498
|
return this.getSelectionState();
|
|
1468
1499
|
}
|
|
@@ -1478,6 +1509,7 @@ export default class PrefViewer extends HTMLElement {
|
|
|
1478
1509
|
selectedIds: [],
|
|
1479
1510
|
selectedItems: [],
|
|
1480
1511
|
};
|
|
1512
|
+
this.#applySelectionStateTo2D();
|
|
1481
1513
|
this.#emitSelectionStateChanged();
|
|
1482
1514
|
return this.getSelectionState();
|
|
1483
1515
|
}
|
|
@@ -1499,17 +1531,53 @@ export default class PrefViewer extends HTMLElement {
|
|
|
1499
1531
|
}
|
|
1500
1532
|
|
|
1501
1533
|
/**
|
|
1502
|
-
*
|
|
1503
|
-
* Internal 2D/3D hit-testing can call this once it exposes stable element ids.
|
|
1534
|
+
* Publishes host-forwarded semantic ids through the same exact event contract as 2D hit-testing.
|
|
1504
1535
|
* @public
|
|
1505
|
-
* @param {object|string} element - Element id or detail
|
|
1536
|
+
* @param {object|string|Array<object|string>} element - Element id, descriptor, collection, or `{ ids }` detail.
|
|
1506
1537
|
* @returns {void}
|
|
1507
1538
|
*/
|
|
1508
1539
|
notifyElementClick(element) {
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
element
|
|
1512
|
-
})
|
|
1540
|
+
let candidates;
|
|
1541
|
+
if (Array.isArray(element)) {
|
|
1542
|
+
candidates = element;
|
|
1543
|
+
} else if (Array.isArray(element?.ids)) {
|
|
1544
|
+
candidates = element.ids;
|
|
1545
|
+
} else {
|
|
1546
|
+
candidates = [element?.element ?? element];
|
|
1547
|
+
}
|
|
1548
|
+
const ids = candidates
|
|
1549
|
+
.map((candidate) => typeof candidate === "string" ? candidate : (candidate?.id ?? candidate?.Id))
|
|
1550
|
+
.filter((id) => typeof id === "string" && id.length > 0);
|
|
1551
|
+
if (ids.length === 0) {
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
this.dispatchEvent(new CustomEvent("pref-viewer-element-click", {
|
|
1555
|
+
bubbles: true,
|
|
1556
|
+
cancelable: true,
|
|
1557
|
+
composed: true,
|
|
1558
|
+
detail: { ids },
|
|
1559
|
+
}));
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
/**
|
|
1563
|
+
* Add a host-owned SVG node through the public root facade.
|
|
1564
|
+
* @public
|
|
1565
|
+
* @param {string} id - Owner id.
|
|
1566
|
+
* @param {string} svgId - Stable selector/id.
|
|
1567
|
+
* @param {SVGElement} svg - SVG node.
|
|
1568
|
+
* @returns {boolean} True when appended.
|
|
1569
|
+
*/
|
|
1570
|
+
appendSvgNode(id, svgId, svg) {
|
|
1571
|
+
return this.#component2D?.appendSvgNode?.(id, svgId, svg) ?? false;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
/**
|
|
1575
|
+
* Remove every SVG node previously added through appendSvgNode.
|
|
1576
|
+
* @public
|
|
1577
|
+
* @returns {void}
|
|
1578
|
+
* */
|
|
1579
|
+
removeAppendedSvgNodes() {
|
|
1580
|
+
this.#component2D?.removeAppendedSvgNodes?.();
|
|
1513
1581
|
}
|
|
1514
1582
|
|
|
1515
1583
|
/**
|
package/src/styles.js
CHANGED
|
@@ -206,6 +206,12 @@ export const PrefViewerMenu3DStyles = `
|
|
|
206
206
|
top: var(--toggle-margin);
|
|
207
207
|
right: var(--toggle-margin);
|
|
208
208
|
z-index: 1200;
|
|
209
|
+
/* The closed panel keeps its place in the flex column (opacity:0, not display:none), so
|
|
210
|
+
this host spans the panel's full 300px x 70vh even when only the toggle is showing.
|
|
211
|
+
Left clickable, that empty space is an invisible catcher over the right edge of the
|
|
212
|
+
viewer: it swallowed the XR entry button and orbiting alike. The toggle and the panel
|
|
213
|
+
each flip back to auto when they become usable, so nothing else is needed. */
|
|
214
|
+
pointer-events: none;
|
|
209
215
|
|
|
210
216
|
font-family: var(--font-family);
|
|
211
217
|
}
|