@2112-lab/central-plant 0.3.26 → 0.3.27
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/dist/bundle/index.js +894 -117
- package/dist/cjs/src/core/centralPlant.js +1 -1
- package/dist/cjs/src/core/centralPlantInternals.js +17 -0
- package/dist/cjs/src/core/sceneViewer.js +55 -2
- package/dist/cjs/src/managers/behaviors/IoAnimationManager.js +24 -1
- package/dist/cjs/src/managers/behaviors/IoOutlineManager.js +258 -0
- package/dist/cjs/src/managers/controls/transformControlsManager.js +319 -43
- package/dist/cjs/src/managers/scene/animationManager.js +9 -2
- package/dist/cjs/src/managers/scene/componentTooltipManager.js +190 -27
- package/dist/cjs/src/managers/scene/modelManager.js +15 -1
- package/dist/cjs/src/utils/boundingBoxUtils.js +38 -40
- package/dist/esm/src/core/centralPlant.js +1 -1
- package/dist/esm/src/core/centralPlantInternals.js +17 -0
- package/dist/esm/src/core/sceneViewer.js +55 -2
- package/dist/esm/src/managers/behaviors/IoAnimationManager.js +24 -1
- package/dist/esm/src/managers/behaviors/IoOutlineManager.js +234 -0
- package/dist/esm/src/managers/controls/transformControlsManager.js +319 -43
- package/dist/esm/src/managers/scene/animationManager.js +9 -2
- package/dist/esm/src/managers/scene/componentTooltipManager.js +191 -28
- package/dist/esm/src/managers/scene/modelManager.js +16 -2
- package/dist/esm/src/utils/boundingBoxUtils.js +39 -42
- package/package.json +1 -1
|
@@ -168,6 +168,169 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
168
168
|
console.log("\uD83D\uDD04 [IODevice] Toggled ".concat(scopedAttachmentId, ".").concat(dpId, ": ").concat(currentVal, " \u2192 ").concat(newVal));
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
// ── IO device drag-to-state ─────────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Begin tracking a drag gesture on an IO device mesh.
|
|
175
|
+
* Records the initial state of each animation data point so that
|
|
176
|
+
* `updateIODeviceDrag` can compute relative offsets from it.
|
|
177
|
+
*
|
|
178
|
+
* @param {THREE.Object3D} ioDeviceObject
|
|
179
|
+
*/
|
|
180
|
+
}, {
|
|
181
|
+
key: "startIODeviceDrag",
|
|
182
|
+
value: function startIODeviceDrag(ioDeviceObject) {
|
|
183
|
+
var _this$sceneViewer3,
|
|
184
|
+
_this2 = this;
|
|
185
|
+
if (!ioDeviceObject || !this._stateAdapter) return;
|
|
186
|
+
var ud = ioDeviceObject.userData;
|
|
187
|
+
var attachmentId = ud === null || ud === void 0 ? void 0 : ud.attachmentId;
|
|
188
|
+
if (!attachmentId) return;
|
|
189
|
+
var parentUuid = null;
|
|
190
|
+
var obj = ioDeviceObject.parent;
|
|
191
|
+
while (obj) {
|
|
192
|
+
var _obj$userData2;
|
|
193
|
+
if (((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.objectType) === 'component') {
|
|
194
|
+
parentUuid = obj.uuid;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
obj = obj.parent;
|
|
198
|
+
}
|
|
199
|
+
var scopedAttachmentId = this._getScopedAttachmentKey(attachmentId, parentUuid);
|
|
200
|
+
var ioAnimMgr = (_this$sceneViewer3 = this.sceneViewer) === null || _this$sceneViewer3 === void 0 || (_this$sceneViewer3 = _this$sceneViewer3.managers) === null || _this$sceneViewer3 === void 0 ? void 0 : _this$sceneViewer3.ioAnimationManager;
|
|
201
|
+
var dataPoints = ((ioAnimMgr === null || ioAnimMgr === void 0 ? void 0 : ioAnimMgr.getAnimationDataPoints(parentUuid, attachmentId)) || []).concat((ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [])
|
|
202
|
+
// deduplicate by id
|
|
203
|
+
.filter(function (dp, i, arr) {
|
|
204
|
+
return arr.findIndex(function (d) {
|
|
205
|
+
return d.id === dp.id;
|
|
206
|
+
}) === i;
|
|
207
|
+
});
|
|
208
|
+
var dpSessions = [];
|
|
209
|
+
var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(dataPoints),
|
|
210
|
+
_step;
|
|
211
|
+
try {
|
|
212
|
+
var _loop = function _loop() {
|
|
213
|
+
var _this2$_stateAdapter$;
|
|
214
|
+
var dp = _step.value;
|
|
215
|
+
var stateType = (dp.stateType || '').toLowerCase();
|
|
216
|
+
if (stateType !== 'binary' && stateType !== 'boolean' && stateType !== 'enum') return 1; // continue
|
|
217
|
+
var curVal = (_this2$_stateAdapter$ = _this2._stateAdapter.getState(scopedAttachmentId, dp.id)) !== null && _this2$_stateAdapter$ !== void 0 ? _this2$_stateAdapter$ : dp.defaultValue;
|
|
218
|
+
if (stateType === 'binary' || stateType === 'boolean') {
|
|
219
|
+
dpSessions.push({
|
|
220
|
+
dp: dp,
|
|
221
|
+
scopedAttachmentId: scopedAttachmentId,
|
|
222
|
+
attachmentId: attachmentId,
|
|
223
|
+
parentUuid: parentUuid,
|
|
224
|
+
stateType: 'binary',
|
|
225
|
+
lastApplied: curVal
|
|
226
|
+
});
|
|
227
|
+
} else {
|
|
228
|
+
var _dp$stateConfig;
|
|
229
|
+
var opts = ((_dp$stateConfig = dp.stateConfig) === null || _dp$stateConfig === void 0 ? void 0 : _dp$stateConfig.options) || [];
|
|
230
|
+
var curIdx = opts.findIndex(function (o) {
|
|
231
|
+
return String(o) === String(curVal);
|
|
232
|
+
});
|
|
233
|
+
dpSessions.push({
|
|
234
|
+
dp: dp,
|
|
235
|
+
scopedAttachmentId: scopedAttachmentId,
|
|
236
|
+
attachmentId: attachmentId,
|
|
237
|
+
parentUuid: parentUuid,
|
|
238
|
+
stateType: 'enum',
|
|
239
|
+
opts: opts,
|
|
240
|
+
startIdx: curIdx >= 0 ? curIdx : 0,
|
|
241
|
+
lastAppliedIdx: curIdx >= 0 ? curIdx : 0
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
246
|
+
if (_loop()) continue;
|
|
247
|
+
}
|
|
248
|
+
} catch (err) {
|
|
249
|
+
_iterator.e(err);
|
|
250
|
+
} finally {
|
|
251
|
+
_iterator.f();
|
|
252
|
+
}
|
|
253
|
+
this._ioDragSession = dpSessions.length ? {
|
|
254
|
+
dpSessions: dpSessions
|
|
255
|
+
} : null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Update animated mesh state while a drag is in progress.
|
|
260
|
+
* Called continuously during pointermove.
|
|
261
|
+
*
|
|
262
|
+
* Sign convention: up/right = positive `signedDelta`.
|
|
263
|
+
* - Binary: > +20 px → true/on state, < −20 px → false/off state.
|
|
264
|
+
* - Enum: each ±30 px step advances/retreats one option in the list.
|
|
265
|
+
*
|
|
266
|
+
* @param {number} signedDelta - Cumulative signed pixel displacement since drag start
|
|
267
|
+
*/
|
|
268
|
+
}, {
|
|
269
|
+
key: "updateIODeviceDrag",
|
|
270
|
+
value: function updateIODeviceDrag(signedDelta) {
|
|
271
|
+
var session = this._ioDragSession;
|
|
272
|
+
if (!session) return;
|
|
273
|
+
var BINARY_THRESHOLD = 20;
|
|
274
|
+
var ENUM_STEP_PX = 30;
|
|
275
|
+
var _iterator2 = _rollupPluginBabelHelpers.createForOfIteratorHelper(session.dpSessions),
|
|
276
|
+
_step2;
|
|
277
|
+
try {
|
|
278
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
279
|
+
var dps = _step2.value;
|
|
280
|
+
if (dps.stateType === 'binary') {
|
|
281
|
+
var newVal = void 0;
|
|
282
|
+
if (signedDelta > BINARY_THRESHOLD) {
|
|
283
|
+
newVal = true;
|
|
284
|
+
} else if (signedDelta < -BINARY_THRESHOLD) {
|
|
285
|
+
newVal = false;
|
|
286
|
+
} else {
|
|
287
|
+
continue; // dead zone
|
|
288
|
+
}
|
|
289
|
+
if (newVal === dps.lastApplied) continue;
|
|
290
|
+
dps.lastApplied = newVal;
|
|
291
|
+
this._applyDpState(dps, newVal);
|
|
292
|
+
} else if (dps.stateType === 'enum') {
|
|
293
|
+
var steps = Math.round(signedDelta / ENUM_STEP_PX);
|
|
294
|
+
var newIdx = Math.max(0, Math.min(dps.opts.length - 1, dps.startIdx + steps));
|
|
295
|
+
if (newIdx === dps.lastAppliedIdx) continue;
|
|
296
|
+
dps.lastAppliedIdx = newIdx;
|
|
297
|
+
this._applyDpState(dps, dps.opts[newIdx]);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
} catch (err) {
|
|
301
|
+
_iterator2.e(err);
|
|
302
|
+
} finally {
|
|
303
|
+
_iterator2.f();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Clean up drag session state on pointerup.
|
|
309
|
+
*/
|
|
310
|
+
}, {
|
|
311
|
+
key: "endIODeviceDrag",
|
|
312
|
+
value: function endIODeviceDrag() {
|
|
313
|
+
this._ioDragSession = null;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Apply a new value to a data point, updating Vuex state and firing behavior/animation triggers.
|
|
318
|
+
* @private
|
|
319
|
+
*/
|
|
320
|
+
}, {
|
|
321
|
+
key: "_applyDpState",
|
|
322
|
+
value: function _applyDpState(_ref2, newVal) {
|
|
323
|
+
var _this$_stateAdapter, _this$sceneViewer4, _this$sceneViewer5;
|
|
324
|
+
var scopedAttachmentId = _ref2.scopedAttachmentId,
|
|
325
|
+
attachmentId = _ref2.attachmentId,
|
|
326
|
+
parentUuid = _ref2.parentUuid,
|
|
327
|
+
dp = _ref2.dp;
|
|
328
|
+
var dpId = dp.id;
|
|
329
|
+
(_this$_stateAdapter = this._stateAdapter) === null || _this$_stateAdapter === void 0 || _this$_stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
330
|
+
(_this$sceneViewer4 = this.sceneViewer) === null || _this$sceneViewer4 === void 0 || (_this$sceneViewer4 = _this$sceneViewer4.managers) === null || _this$sceneViewer4 === void 0 || (_this$sceneViewer4 = _this$sceneViewer4.behaviorManager) === null || _this$sceneViewer4 === void 0 || _this$sceneViewer4.triggerState(attachmentId, dpId, newVal, parentUuid);
|
|
331
|
+
(_this$sceneViewer5 = this.sceneViewer) === null || _this$sceneViewer5 === void 0 || (_this$sceneViewer5 = _this$sceneViewer5.managers) === null || _this$sceneViewer5 === void 0 || (_this$sceneViewer5 = _this$sceneViewer5.ioAnimationManager) === null || _this$sceneViewer5 === void 0 || _this$sceneViewer5.triggerState(attachmentId, dpId, newVal, parentUuid);
|
|
332
|
+
}
|
|
333
|
+
|
|
171
334
|
/**
|
|
172
335
|
* Should be called when an object is selected or deselected.
|
|
173
336
|
* @param {THREE.Object3D|null} object
|
|
@@ -281,18 +444,18 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
281
444
|
}, {
|
|
282
445
|
key: "_getIODevices",
|
|
283
446
|
value: function _getIODevices(object) {
|
|
284
|
-
var
|
|
447
|
+
var _this3 = this;
|
|
285
448
|
var devices = [];
|
|
286
449
|
var parentUuid = object.uuid; // The component's own UUID
|
|
287
450
|
object.traverse(function (child) {
|
|
288
451
|
var _child$userData;
|
|
289
452
|
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'io-device') {
|
|
290
|
-
var
|
|
453
|
+
var _this3$sceneViewer$ma, _this3$sceneViewer;
|
|
291
454
|
var attachmentId = child.userData.attachmentId || '';
|
|
292
455
|
|
|
293
456
|
// Use only data points from the animate window (animationConfig).
|
|
294
457
|
// The static ioConfig.states[] snapshot on userData is intentionally ignored.
|
|
295
|
-
var dataPoints = (
|
|
458
|
+
var dataPoints = (_this3$sceneViewer$ma = (_this3$sceneViewer = _this3.sceneViewer) === null || _this3$sceneViewer === void 0 || (_this3$sceneViewer = _this3$sceneViewer.managers) === null || _this3$sceneViewer === void 0 || (_this3$sceneViewer = _this3$sceneViewer.ioAnimationManager) === null || _this3$sceneViewer === void 0 ? void 0 : _this3$sceneViewer.getAnimationDataPoints(parentUuid, attachmentId)) !== null && _this3$sceneViewer$ma !== void 0 ? _this3$sceneViewer$ma : [];
|
|
296
459
|
|
|
297
460
|
// When data points come from animationConfig they already carry direction:'input'.
|
|
298
461
|
// Pass null so _buildDataPointRow uses the per-dp direction instead of the
|
|
@@ -302,7 +465,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
302
465
|
label: child.userData.attachmentLabel || child.name || child.userData.deviceId || 'Unknown Device',
|
|
303
466
|
deviceId: child.userData.deviceId || '',
|
|
304
467
|
attachmentId: attachmentId,
|
|
305
|
-
scopedAttachmentId:
|
|
468
|
+
scopedAttachmentId: _this3._getScopedAttachmentKey(attachmentId, parentUuid),
|
|
306
469
|
dataPoints: dataPoints,
|
|
307
470
|
direction: deviceDirection
|
|
308
471
|
});
|
|
@@ -318,7 +481,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
318
481
|
}, {
|
|
319
482
|
key: "_buildTooltip",
|
|
320
483
|
value: function _buildTooltip(object) {
|
|
321
|
-
var
|
|
484
|
+
var _this4 = this;
|
|
322
485
|
// Remove any existing tooltip first
|
|
323
486
|
this.hide();
|
|
324
487
|
// Re-assign selected object since hide() clears it
|
|
@@ -389,7 +552,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
389
552
|
// Use scopedAttachmentId to ensure state is isolated per component instance
|
|
390
553
|
if (device.scopedAttachmentId && device.dataPoints.length > 0) {
|
|
391
554
|
device.dataPoints.forEach(function (dp) {
|
|
392
|
-
var row =
|
|
555
|
+
var row = _this4._buildDataPointRow(device.scopedAttachmentId, dp, device.direction, device.attachmentId);
|
|
393
556
|
list.appendChild(row);
|
|
394
557
|
});
|
|
395
558
|
}
|
|
@@ -400,11 +563,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
400
563
|
// Hover expand/collapse
|
|
401
564
|
trigger.addEventListener('mouseenter', function () {
|
|
402
565
|
ioSection.classList.add('expanded');
|
|
403
|
-
|
|
566
|
+
_this4._ioExpanded = true;
|
|
404
567
|
});
|
|
405
568
|
ioSection.addEventListener('mouseleave', function () {
|
|
406
569
|
ioSection.classList.remove('expanded');
|
|
407
|
-
|
|
570
|
+
_this4._ioExpanded = false;
|
|
408
571
|
});
|
|
409
572
|
card.appendChild(ioSection);
|
|
410
573
|
} else {
|
|
@@ -448,11 +611,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
448
611
|
}, {
|
|
449
612
|
key: "_positionTooltip",
|
|
450
613
|
value: function _positionTooltip() {
|
|
451
|
-
var _this$
|
|
614
|
+
var _this$sceneViewer6, _this$sceneViewer7;
|
|
452
615
|
if (!this.tooltipEl || !this.selectedObject) return;
|
|
453
616
|
var container = this._getContainer();
|
|
454
|
-
var camera = (_this$
|
|
455
|
-
var renderer = (_this$
|
|
617
|
+
var camera = (_this$sceneViewer6 = this.sceneViewer) === null || _this$sceneViewer6 === void 0 ? void 0 : _this$sceneViewer6.camera;
|
|
618
|
+
var renderer = (_this$sceneViewer7 = this.sceneViewer) === null || _this$sceneViewer7 === void 0 ? void 0 : _this$sceneViewer7.renderer;
|
|
456
619
|
if (!container || !camera || !renderer) return;
|
|
457
620
|
|
|
458
621
|
// Compute bounding box to position above the component
|
|
@@ -489,8 +652,8 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
489
652
|
}, {
|
|
490
653
|
key: "_getContainer",
|
|
491
654
|
value: function _getContainer() {
|
|
492
|
-
var _this$
|
|
493
|
-
return ((_this$
|
|
655
|
+
var _this$sceneViewer8;
|
|
656
|
+
return ((_this$sceneViewer8 = this.sceneViewer) === null || _this$sceneViewer8 === void 0 || (_this$sceneViewer8 = _this$sceneViewer8.renderer) === null || _this$sceneViewer8 === void 0 || (_this$sceneViewer8 = _this$sceneViewer8.domElement) === null || _this$sceneViewer8 === void 0 ? void 0 : _this$sceneViewer8.parentElement) || null;
|
|
494
657
|
}
|
|
495
658
|
|
|
496
659
|
// -----------------------------------------------------------------------
|
|
@@ -512,10 +675,10 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
512
675
|
}, {
|
|
513
676
|
key: "_buildDataPointRow",
|
|
514
677
|
value: function _buildDataPointRow(scopedAttachmentId, dp, deviceDirection, originalAttachmentId) {
|
|
515
|
-
var
|
|
678
|
+
var _ref3,
|
|
516
679
|
_this$_stateAdapter$g,
|
|
517
|
-
_this$
|
|
518
|
-
|
|
680
|
+
_this$_stateAdapter2,
|
|
681
|
+
_this5 = this;
|
|
519
682
|
var row = document.createElement('div');
|
|
520
683
|
row.className = 'cp-tooltip__dp-row';
|
|
521
684
|
var nameEl = document.createElement('span');
|
|
@@ -527,18 +690,18 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
527
690
|
// Device-level direction takes precedence; fall back to per-dp direction
|
|
528
691
|
var resolvedDirection = deviceDirection || dp.direction || 'output';
|
|
529
692
|
var isInput = resolvedDirection === 'input' || resolvedDirection === 'bidirectional';
|
|
530
|
-
var currentVal = (
|
|
693
|
+
var currentVal = (_ref3 = (_this$_stateAdapter$g = (_this$_stateAdapter2 = this._stateAdapter) === null || _this$_stateAdapter2 === void 0 ? void 0 : _this$_stateAdapter2.getState(scopedAttachmentId, dpId)) !== null && _this$_stateAdapter$g !== void 0 ? _this$_stateAdapter$g : dp.defaultValue) !== null && _ref3 !== void 0 ? _ref3 : null;
|
|
531
694
|
if (isInput) {
|
|
532
695
|
var ctrl = this._buildInputControl(dp, currentVal, function (newVal) {
|
|
533
|
-
var
|
|
534
|
-
(
|
|
696
|
+
var _this5$_stateAdapter, _this5$selectedObject, _this5$sceneViewer, _this5$sceneViewer2;
|
|
697
|
+
(_this5$_stateAdapter = _this5._stateAdapter) === null || _this5$_stateAdapter === void 0 || _this5$_stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
535
698
|
// Also fire BehaviorManager so any wired behaviors react immediately.
|
|
536
699
|
// Pass the parent component UUID so behaviors scoped to a specific instance
|
|
537
700
|
// don't bleed across clones that share the same attachmentId.
|
|
538
701
|
// Use originalAttachmentId for behavior triggering as behaviors are keyed by original ID
|
|
539
|
-
var parentUuid = ((
|
|
540
|
-
(
|
|
541
|
-
(
|
|
702
|
+
var parentUuid = ((_this5$selectedObject = _this5.selectedObject) === null || _this5$selectedObject === void 0 ? void 0 : _this5$selectedObject.uuid) || null;
|
|
703
|
+
(_this5$sceneViewer = _this5.sceneViewer) === null || _this5$sceneViewer === void 0 || (_this5$sceneViewer = _this5$sceneViewer.managers) === null || _this5$sceneViewer === void 0 || (_this5$sceneViewer = _this5$sceneViewer.behaviorManager) === null || _this5$sceneViewer === void 0 || _this5$sceneViewer.triggerState(originalAttachmentId || scopedAttachmentId, dpId, newVal, parentUuid);
|
|
704
|
+
(_this5$sceneViewer2 = _this5.sceneViewer) === null || _this5$sceneViewer2 === void 0 || (_this5$sceneViewer2 = _this5$sceneViewer2.managers) === null || _this5$sceneViewer2 === void 0 || (_this5$sceneViewer2 = _this5$sceneViewer2.ioAnimationManager) === null || _this5$sceneViewer2 === void 0 || _this5$sceneViewer2.triggerState(originalAttachmentId || scopedAttachmentId, dpId, newVal, parentUuid);
|
|
542
705
|
});
|
|
543
706
|
row.appendChild(ctrl);
|
|
544
707
|
this._stateElements.set(key, {
|
|
@@ -547,9 +710,9 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
547
710
|
isInput: true
|
|
548
711
|
});
|
|
549
712
|
} else {
|
|
550
|
-
var _dp$
|
|
713
|
+
var _dp$stateConfig2;
|
|
551
714
|
// unit suffix (optional, shown between name and badge)
|
|
552
|
-
var unit = (_dp$
|
|
715
|
+
var unit = (_dp$stateConfig2 = dp.stateConfig) === null || _dp$stateConfig2 === void 0 ? void 0 : _dp$stateConfig2.unit;
|
|
553
716
|
if (unit) {
|
|
554
717
|
var unitEl = document.createElement('span');
|
|
555
718
|
unitEl.className = 'cp-tooltip__dp-unit';
|
|
@@ -694,7 +857,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
694
857
|
}, {
|
|
695
858
|
key: "_refreshStateDisplays",
|
|
696
859
|
value: function _refreshStateDisplays() {
|
|
697
|
-
var
|
|
860
|
+
var _this6 = this;
|
|
698
861
|
if (!this._stateAdapter || !this._stateElements.size) return;
|
|
699
862
|
this._stateElements.forEach(function (entry, key) {
|
|
700
863
|
if (entry.isInput) return; // interactive controls are user-driven; don't overwrite
|
|
@@ -703,8 +866,8 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
703
866
|
if (sepIdx === -1) return;
|
|
704
867
|
var scopedAttachmentId = key.slice(0, sepIdx);
|
|
705
868
|
var dataPointId = key.slice(sepIdx + 2);
|
|
706
|
-
var val =
|
|
707
|
-
|
|
869
|
+
var val = _this6._stateAdapter.getState(scopedAttachmentId, dataPointId);
|
|
870
|
+
_this6._applyBadgeValue(entry.el, val, entry.dp);
|
|
708
871
|
});
|
|
709
872
|
}
|
|
710
873
|
}]);
|
|
@@ -77,7 +77,7 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
77
77
|
key: "loadLibraryModel",
|
|
78
78
|
value: function () {
|
|
79
79
|
var _loadLibraryModel = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee(targetMesh, jsonEntry, componentData) {
|
|
80
|
-
var component, _jsonEntry$userData, _jsonEntry$userData2, _jsonEntry$userData3, originalProps, connectorChildren, gltfScene, libraryModel, _this$sceneViewer, ioAnimMgr, _loop, _i, _Object$entries, _jsonEntry$userData4, _t;
|
|
80
|
+
var component, _jsonEntry$userData, _jsonEntry$userData2, _jsonEntry$userData3, originalProps, connectorChildren, gltfScene, libraryModel, _this$sceneViewer, ioAnimMgr, _loop, _i, _Object$entries, warmFn, _jsonEntry$userData4, _t;
|
|
81
81
|
return _rollupPluginBabelHelpers.regenerator().w(function (_context2) {
|
|
82
82
|
while (1) switch (_context2.n) {
|
|
83
83
|
case 0:
|
|
@@ -174,6 +174,20 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
174
174
|
case 8:
|
|
175
175
|
// Replace mesh in scene
|
|
176
176
|
this._replaceMeshInScene(targetMesh, libraryModel, originalProps.parent, component);
|
|
177
|
+
|
|
178
|
+
// Pre-warm the filtered bounding-box cache for smart components so the
|
|
179
|
+
// first selection is instant. Deferred to idle time so it does not
|
|
180
|
+
// block the current frame.
|
|
181
|
+
if (componentData.isSmart) {
|
|
182
|
+
warmFn = function warmFn() {
|
|
183
|
+
return boundingBoxUtils.computeFilteredBoundingBoxCached(libraryModel, ['io-device', 'connector']);
|
|
184
|
+
};
|
|
185
|
+
if (typeof requestIdleCallback !== 'undefined') {
|
|
186
|
+
requestIdleCallback(warmFn);
|
|
187
|
+
} else {
|
|
188
|
+
setTimeout(warmFn, 0);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
177
191
|
console.log("\uD83C\uDF89 ".concat((_jsonEntry$userData3 = jsonEntry.userData) === null || _jsonEntry$userData3 === void 0 ? void 0 : _jsonEntry$userData3.libraryId, " GLB model successfully rendered in scene"));
|
|
178
192
|
return _context2.a(2, libraryModel);
|
|
179
193
|
case 9:
|
|
@@ -233,6 +233,34 @@ function computeIODeviceBoundingBoxes(componentObject) {
|
|
|
233
233
|
* const helpers = createSelectionBoxHelpers(pumpModel, 0x00ff00)
|
|
234
234
|
* helpers.forEach(h => scene.add(h))
|
|
235
235
|
*/
|
|
236
|
+
/**
|
|
237
|
+
* Returns a filtered bounding box for `object`, using a cache stored on
|
|
238
|
+
* `object.userData._filteredBBoxCache`. The cache key is the serialised
|
|
239
|
+
* world-matrix elements string; if the object has moved the cache is
|
|
240
|
+
* automatically invalidated and recomputed.
|
|
241
|
+
*
|
|
242
|
+
* This avoids the expensive full-traverse on every selection event for
|
|
243
|
+
* large smart components with many child meshes.
|
|
244
|
+
*
|
|
245
|
+
* @param {THREE.Object3D} object
|
|
246
|
+
* @param {string[]} excludeTypes
|
|
247
|
+
* @returns {THREE.Box3}
|
|
248
|
+
*/
|
|
249
|
+
function computeFilteredBoundingBoxCached(object, excludeTypes) {
|
|
250
|
+
object.updateMatrixWorld(true);
|
|
251
|
+
var matrixKey = object.matrixWorld.elements.join(',');
|
|
252
|
+
var cache = object.userData._filteredBBoxCache;
|
|
253
|
+
if (cache && cache.matrixKey === matrixKey) {
|
|
254
|
+
return new THREE__namespace.Box3(_rollupPluginBabelHelpers.construct(THREE__namespace.Vector3, _rollupPluginBabelHelpers.toConsumableArray(cache.min)), _rollupPluginBabelHelpers.construct(THREE__namespace.Vector3, _rollupPluginBabelHelpers.toConsumableArray(cache.max)));
|
|
255
|
+
}
|
|
256
|
+
var box = computeFilteredBoundingBox(object, excludeTypes);
|
|
257
|
+
object.userData._filteredBBoxCache = {
|
|
258
|
+
matrixKey: matrixKey,
|
|
259
|
+
min: box.min.toArray(),
|
|
260
|
+
max: box.max.toArray()
|
|
261
|
+
};
|
|
262
|
+
return box;
|
|
263
|
+
}
|
|
236
264
|
function createSelectionBoxHelpers(object) {
|
|
237
265
|
var _object$children;
|
|
238
266
|
var color = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0x00ff00;
|
|
@@ -246,7 +274,7 @@ function createSelectionBoxHelpers(object) {
|
|
|
246
274
|
});
|
|
247
275
|
if (hasIODevices) {
|
|
248
276
|
// 1. Create filtered helper for the component body
|
|
249
|
-
var filteredBox =
|
|
277
|
+
var filteredBox = computeFilteredBoundingBoxCached(object, excludeTypes);
|
|
250
278
|
var componentHelper = _createBoxHelperFromBox3(filteredBox, color);
|
|
251
279
|
componentHelper.isHelper = true;
|
|
252
280
|
componentHelper.userData = {
|
|
@@ -256,33 +284,6 @@ function createSelectionBoxHelpers(object) {
|
|
|
256
284
|
excludeTypes: excludeTypes
|
|
257
285
|
};
|
|
258
286
|
helpers.push(componentHelper);
|
|
259
|
-
|
|
260
|
-
// 2. Create individual helpers for each io-device
|
|
261
|
-
var _iterator2 = _rollupPluginBabelHelpers.createForOfIteratorHelper(object.children),
|
|
262
|
-
_step2;
|
|
263
|
-
try {
|
|
264
|
-
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
265
|
-
var _child$userData3;
|
|
266
|
-
var child = _step2.value;
|
|
267
|
-
if (((_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.objectType) !== 'io-device') continue;
|
|
268
|
-
var deviceBox = new THREE__namespace.Box3().setFromObject(child);
|
|
269
|
-
if (deviceBox.isEmpty()) continue;
|
|
270
|
-
var deviceHelper = _createBoxHelperFromBox3(deviceBox, color);
|
|
271
|
-
deviceHelper.isHelper = true;
|
|
272
|
-
deviceHelper.userData = {
|
|
273
|
-
isBoundingBox: true,
|
|
274
|
-
sourceObjectUuid: child.uuid,
|
|
275
|
-
isFiltered: false,
|
|
276
|
-
isIODevice: true,
|
|
277
|
-
parentComponentUuid: object.uuid
|
|
278
|
-
};
|
|
279
|
-
helpers.push(deviceHelper);
|
|
280
|
-
}
|
|
281
|
-
} catch (err) {
|
|
282
|
-
_iterator2.e(err);
|
|
283
|
-
} finally {
|
|
284
|
-
_iterator2.f();
|
|
285
|
-
}
|
|
286
287
|
} else {
|
|
287
288
|
// Standard BoxHelper for non-smart objects
|
|
288
289
|
var boxHelper = new THREE__namespace.BoxHelper(object, color);
|
|
@@ -306,11 +307,11 @@ function createSelectionBoxHelpers(object) {
|
|
|
306
307
|
* @param {THREE.Scene} scene - The scene (for finding objects by uuid)
|
|
307
308
|
*/
|
|
308
309
|
function updateSelectionBoxHelpers(helpers, selectedObjects, scene) {
|
|
309
|
-
var
|
|
310
|
-
|
|
310
|
+
var _iterator2 = _rollupPluginBabelHelpers.createForOfIteratorHelper(helpers),
|
|
311
|
+
_step2;
|
|
311
312
|
try {
|
|
312
313
|
var _loop = function _loop() {
|
|
313
|
-
var helper =
|
|
314
|
+
var helper = _step2.value;
|
|
314
315
|
var _helper$userData = helper.userData,
|
|
315
316
|
sourceObjectUuid = _helper$userData.sourceObjectUuid,
|
|
316
317
|
isFiltered = _helper$userData.isFiltered,
|
|
@@ -333,29 +334,26 @@ function updateSelectionBoxHelpers(helpers, selectedObjects, scene) {
|
|
|
333
334
|
if (!sourceObject) return 1; // continue
|
|
334
335
|
sourceObject.updateMatrixWorld(true);
|
|
335
336
|
if (isFiltered && excludeTypes) {
|
|
336
|
-
// Recompute filtered bbox
|
|
337
|
-
var box =
|
|
337
|
+
// Recompute filtered bbox (uses cache when the object hasn't moved)
|
|
338
|
+
var box = computeFilteredBoundingBoxCached(sourceObject, excludeTypes);
|
|
338
339
|
_updateBoxHelperPositions(helper, box);
|
|
339
|
-
} else if (isIODevice) {
|
|
340
|
-
// Recompute io-device bbox
|
|
341
|
-
var _box = new THREE__namespace.Box3().setFromObject(sourceObject);
|
|
342
|
-
_updateBoxHelperPositions(helper, _box);
|
|
343
340
|
} else if (helper.update) {
|
|
344
341
|
// Standard BoxHelper — use built-in update
|
|
345
342
|
helper.update();
|
|
346
343
|
}
|
|
347
344
|
};
|
|
348
|
-
for (
|
|
345
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
349
346
|
if (_loop()) continue;
|
|
350
347
|
}
|
|
351
348
|
} catch (err) {
|
|
352
|
-
|
|
349
|
+
_iterator2.e(err);
|
|
353
350
|
} finally {
|
|
354
|
-
|
|
351
|
+
_iterator2.f();
|
|
355
352
|
}
|
|
356
353
|
}
|
|
357
354
|
|
|
358
355
|
exports.computeFilteredBoundingBox = computeFilteredBoundingBox;
|
|
356
|
+
exports.computeFilteredBoundingBoxCached = computeFilteredBoundingBoxCached;
|
|
359
357
|
exports.computeIODeviceBoundingBoxes = computeIODeviceBoundingBoxes;
|
|
360
358
|
exports.createSelectionBoxHelpers = createSelectionBoxHelpers;
|
|
361
359
|
exports.updateSelectionBoxHelpers = updateSelectionBoxHelpers;
|
|
@@ -31,7 +31,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31
31
|
* Initialize the CentralPlant manager
|
|
32
32
|
*
|
|
33
33
|
* @constructor
|
|
34
|
-
* @version 0.3.
|
|
34
|
+
* @version 0.3.27
|
|
35
35
|
* @updated 2025-10-22
|
|
36
36
|
*
|
|
37
37
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -24,8 +24,10 @@ import { SceneTooltipsManager } from '../managers/scene/sceneTooltipsManager.js'
|
|
|
24
24
|
import { ComponentTooltipManager } from '../managers/scene/componentTooltipManager.js';
|
|
25
25
|
import { Viewport2DManager } from '../managers/scene/viewport2DManager.js';
|
|
26
26
|
import { IoAnimationManager } from '../managers/behaviors/IoAnimationManager.js';
|
|
27
|
+
import { IoOutlineManager } from '../managers/behaviors/IoOutlineManager.js';
|
|
27
28
|
import { generateUuidFromName, getHardcodedUuid, findObjectByHardcodedUuid, generateUniqueComponentId } from '../utils/nameUtils.js';
|
|
28
29
|
import { attachIODevicesToComponent } from '../utils/ioDeviceUtils.js';
|
|
30
|
+
import { computeFilteredBoundingBoxCached } from '../utils/boundingBoxUtils.js';
|
|
29
31
|
import modelPreloader from '../rendering/modelPreloader.js';
|
|
30
32
|
|
|
31
33
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -150,6 +152,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
150
152
|
this.centralPlant.managers.componentDragManager = new ComponentDragManager(this.centralPlant.sceneViewer);
|
|
151
153
|
this.centralPlant.managers.viewport2DManager = new Viewport2DManager(this.centralPlant.sceneViewer);
|
|
152
154
|
this.centralPlant.managers.ioAnimationManager = new IoAnimationManager(this.centralPlant.sceneViewer);
|
|
155
|
+
this.centralPlant.managers.ioOutlineManager = new IoOutlineManager(this.centralPlant.sceneViewer);
|
|
153
156
|
|
|
154
157
|
// All managers are now stored in the managers collection and will be attached via attachToComponent()
|
|
155
158
|
}
|
|
@@ -1166,6 +1169,20 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
1166
1169
|
componentManager.registerComponent(componentModel);
|
|
1167
1170
|
}
|
|
1168
1171
|
|
|
1172
|
+
// Pre-warm the filtered bounding-box cache for smart components so the
|
|
1173
|
+
// first selection is instant. Deferred to idle time so it does not
|
|
1174
|
+
// block the current frame.
|
|
1175
|
+
if (componentData.isSmart) {
|
|
1176
|
+
var warmFn = function warmFn() {
|
|
1177
|
+
return computeFilteredBoundingBoxCached(componentModel, ['io-device', 'connector']);
|
|
1178
|
+
};
|
|
1179
|
+
if (typeof requestIdleCallback !== 'undefined') {
|
|
1180
|
+
requestIdleCallback(warmFn);
|
|
1181
|
+
} else {
|
|
1182
|
+
setTimeout(warmFn, 0);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1169
1186
|
// EMIT COMPONENT ADDED EVENT
|
|
1170
1187
|
// This allows UI components (like SceneHierarchy) to update reactively
|
|
1171
1188
|
if (this.centralPlant.sceneViewer.emit) {
|
|
@@ -98,7 +98,7 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
98
98
|
this.centralPlant.attachToComponent();
|
|
99
99
|
|
|
100
100
|
// Sync our managers tracking object after attachment
|
|
101
|
-
managerKeys = ['threeJSResourceManager', 'performanceMonitorManager', 'settingsManager', 'sceneExportManager', 'componentManager', 'sceneInitializationManager', 'environmentManager', 'keyboardControlsManager', 'pathfindingManager', 'pathFlowManager', 'behaviorManager', 'ioAnimationManager', 'sceneOperationsManager', 'animationManager', 'cameraControlsManager', 'componentDragManager', 'tooltipsManager', 'componentTooltipManager']; // Populate our managers tracking object
|
|
101
|
+
managerKeys = ['threeJSResourceManager', 'performanceMonitorManager', 'settingsManager', 'sceneExportManager', 'componentManager', 'sceneInitializationManager', 'environmentManager', 'keyboardControlsManager', 'pathfindingManager', 'pathFlowManager', 'behaviorManager', 'ioAnimationManager', 'ioOutlineManager', 'sceneOperationsManager', 'animationManager', 'cameraControlsManager', 'componentDragManager', 'tooltipsManager', 'componentTooltipManager']; // Populate our managers tracking object
|
|
102
102
|
managerKeys.forEach(function (key) {
|
|
103
103
|
if (_this2[key]) {
|
|
104
104
|
_this2.managers[key] = _this2[key];
|
|
@@ -286,7 +286,21 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
// Update camera aspect ratio
|
|
289
|
-
this.camera.
|
|
289
|
+
if (this.camera.isPerspectiveCamera) {
|
|
290
|
+
this.camera.aspect = width / height;
|
|
291
|
+
} else if (this.camera.isOrthographicCamera) {
|
|
292
|
+
var _this$camera$userData;
|
|
293
|
+
var aspect = width / height;
|
|
294
|
+
var extents = (_this$camera$userData = this.camera.userData) === null || _this$camera$userData === void 0 ? void 0 : _this$camera$userData._orthoHalfExtents;
|
|
295
|
+
if (extents) {
|
|
296
|
+
var frustumHalfH = Math.max(extents.halfH, extents.halfW / aspect);
|
|
297
|
+
var frustumHalfW = frustumHalfH * aspect;
|
|
298
|
+
this.camera.left = -frustumHalfW;
|
|
299
|
+
this.camera.right = frustumHalfW;
|
|
300
|
+
this.camera.top = frustumHalfH;
|
|
301
|
+
this.camera.bottom = -frustumHalfH;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
290
304
|
this.camera.updateProjectionMatrix();
|
|
291
305
|
|
|
292
306
|
// Update renderer size (updateStyle=true to sync canvas CSS)
|
|
@@ -413,6 +427,45 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
413
427
|
if (_this4.componentTooltipManager) {
|
|
414
428
|
_this4.componentTooltipManager.toggleIODeviceBinaryState(ioDeviceObject);
|
|
415
429
|
}
|
|
430
|
+
},
|
|
431
|
+
onIODeviceDrag: function onIODeviceDrag(ioDeviceObject, signedDelta, isStart) {
|
|
432
|
+
if (isStart) {
|
|
433
|
+
var _ioDeviceObject$userD, _this4$managers$ioAni, _this4$managers, _this4$managers2;
|
|
434
|
+
// Resolve parentUuid by walking up to the host component.
|
|
435
|
+
// Use userData.originalUuid (the custom componentId) because that
|
|
436
|
+
// is what IoAnimationManager uses as the map key — NOT obj.uuid.
|
|
437
|
+
var parentUuid = null;
|
|
438
|
+
var obj = ioDeviceObject.parent;
|
|
439
|
+
while (obj) {
|
|
440
|
+
var _obj$userData;
|
|
441
|
+
if (((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'component') {
|
|
442
|
+
parentUuid = obj.userData.originalUuid || obj.uuid;
|
|
443
|
+
break;
|
|
444
|
+
}
|
|
445
|
+
obj = obj.parent;
|
|
446
|
+
}
|
|
447
|
+
var attachmentId = (_ioDeviceObject$userD = ioDeviceObject.userData) === null || _ioDeviceObject$userD === void 0 ? void 0 : _ioDeviceObject$userD.attachmentId;
|
|
448
|
+
// When animated meshes are available, outline ONLY them so their
|
|
449
|
+
// silhouette is isolated and the outline ring is visible around
|
|
450
|
+
// them specifically (not swallowed by the larger device body).
|
|
451
|
+
// Fall back to the whole device group when none are registered.
|
|
452
|
+
var animatedMeshes = attachmentId && parentUuid ? (_this4$managers$ioAni = (_this4$managers = _this4.managers) === null || _this4$managers === void 0 || (_this4$managers = _this4$managers.ioAnimationManager) === null || _this4$managers === void 0 ? void 0 : _this4$managers.getAnimatedMeshes(parentUuid, attachmentId)) !== null && _this4$managers$ioAni !== void 0 ? _this4$managers$ioAni : [] : [];
|
|
453
|
+
var targets = animatedMeshes.length > 0 ? animatedMeshes : [ioDeviceObject];
|
|
454
|
+
(_this4$managers2 = _this4.managers) === null || _this4$managers2 === void 0 || (_this4$managers2 = _this4$managers2.ioOutlineManager) === null || _this4$managers2 === void 0 || _this4$managers2.setTargets(targets);
|
|
455
|
+
}
|
|
456
|
+
if (!_this4.componentTooltipManager) return;
|
|
457
|
+
if (isStart) {
|
|
458
|
+
_this4.componentTooltipManager.startIODeviceDrag(ioDeviceObject);
|
|
459
|
+
} else {
|
|
460
|
+
_this4.componentTooltipManager.updateIODeviceDrag(signedDelta);
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
onIODeviceDragEnd: function onIODeviceDragEnd(ioDeviceObject) {
|
|
464
|
+
var _this4$managers3;
|
|
465
|
+
(_this4$managers3 = _this4.managers) === null || _this4$managers3 === void 0 || (_this4$managers3 = _this4$managers3.ioOutlineManager) === null || _this4$managers3 === void 0 || _this4$managers3.setTargets([]);
|
|
466
|
+
if (_this4.componentTooltipManager) {
|
|
467
|
+
_this4.componentTooltipManager.endIODeviceDrag();
|
|
468
|
+
}
|
|
416
469
|
}
|
|
417
470
|
});
|
|
418
471
|
|