iobroker.mywebui 1.42.11 → 1.42.12
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/io-package.json
CHANGED
package/package.json
CHANGED
|
@@ -230,7 +230,7 @@ export class IobrokerWebui3DScreenEditor extends BaseCustomWebComponentConstruct
|
|
|
230
230
|
// Add assets to scene (safe iteration)
|
|
231
231
|
if (Array.isArray(this.sceneData.assets)) {
|
|
232
232
|
for (const asset of this.sceneData.assets) {
|
|
233
|
-
if (asset.type === 'model' && asset.glbPath) {
|
|
233
|
+
if (asset.type === 'model' && (asset.glbPath || asset.glbData)) {
|
|
234
234
|
this.loadAsset(asset);
|
|
235
235
|
}
|
|
236
236
|
}
|
|
@@ -257,11 +257,31 @@ export class IobrokerWebui3DScreenEditor extends BaseCustomWebComponentConstruct
|
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
loadAsset(asset) {
|
|
260
|
-
|
|
260
|
+
// Support both base64 embedded data and external URL
|
|
261
|
+
let url = null;
|
|
262
|
+
let revokeAfterLoad = false;
|
|
263
|
+
|
|
264
|
+
if (asset.glbData) {
|
|
265
|
+
// base64 data URL → Blob URL for Three.js loader
|
|
266
|
+
const base64 = asset.glbData;
|
|
267
|
+
const byteString = atob(base64.split(',')[1]);
|
|
268
|
+
const mimeType = base64.split(',')[0].split(':')[1].split(';')[0];
|
|
269
|
+
const ab = new ArrayBuffer(byteString.length);
|
|
270
|
+
const ia = new Uint8Array(ab);
|
|
271
|
+
for (let i = 0; i < byteString.length; i++) ia[i] = byteString.charCodeAt(i);
|
|
272
|
+
const blob = new Blob([ab], { type: mimeType });
|
|
273
|
+
url = URL.createObjectURL(blob);
|
|
274
|
+
revokeAfterLoad = true;
|
|
275
|
+
} else if (asset.glbPath) {
|
|
276
|
+
url = asset.glbPath;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (!url) return;
|
|
261
280
|
|
|
262
281
|
this.gltfLoader.load(
|
|
263
|
-
|
|
282
|
+
url,
|
|
264
283
|
(gltf) => {
|
|
284
|
+
if (revokeAfterLoad) URL.revokeObjectURL(url);
|
|
265
285
|
const model = gltf.scene;
|
|
266
286
|
model.userData.assetId = asset.id;
|
|
267
287
|
model.userData.assetData = asset;
|
|
@@ -272,7 +292,10 @@ export class IobrokerWebui3DScreenEditor extends BaseCustomWebComponentConstruct
|
|
|
272
292
|
console.log('✅ Asset loaded:', asset.name);
|
|
273
293
|
},
|
|
274
294
|
undefined,
|
|
275
|
-
(error) =>
|
|
295
|
+
(error) => {
|
|
296
|
+
if (revokeAfterLoad) URL.revokeObjectURL(url);
|
|
297
|
+
console.error('Error loading asset:', error);
|
|
298
|
+
}
|
|
276
299
|
);
|
|
277
300
|
}
|
|
278
301
|
|
|
@@ -330,10 +353,16 @@ export class IobrokerWebui3DScreenEditor extends BaseCustomWebComponentConstruct
|
|
|
330
353
|
for (const intersection of intersects) {
|
|
331
354
|
let obj = intersection.object;
|
|
332
355
|
|
|
333
|
-
// Skip grid, axes, lights
|
|
334
|
-
if (obj.userData.isGrid || obj.userData.isAxes || obj.userData.lightId) {
|
|
356
|
+
// Skip grid, axes, lights, selection helper
|
|
357
|
+
if (obj.userData.isGrid || obj.userData.isAxes || obj.userData.lightId || obj.userData.isSelectionHelper) {
|
|
335
358
|
continue;
|
|
336
359
|
}
|
|
360
|
+
let rootCheck = obj;
|
|
361
|
+
while (rootCheck && rootCheck !== this.scene) {
|
|
362
|
+
if (rootCheck.userData.isSelectionHelper) break;
|
|
363
|
+
rootCheck = rootCheck.parent;
|
|
364
|
+
}
|
|
365
|
+
if (rootCheck && rootCheck !== this.scene && rootCheck.userData.isSelectionHelper) continue;
|
|
337
366
|
|
|
338
367
|
// Find root asset containing this mesh
|
|
339
368
|
while (obj && obj !== this.scene) {
|
|
@@ -356,41 +385,27 @@ export class IobrokerWebui3DScreenEditor extends BaseCustomWebComponentConstruct
|
|
|
356
385
|
selectObject(obj) {
|
|
357
386
|
if (this.selectedObject === obj) return;
|
|
358
387
|
|
|
359
|
-
// Deselect previous
|
|
388
|
+
// Deselect previous - remove bounding box helper
|
|
360
389
|
if (this.selectedObject) {
|
|
361
390
|
this.selectedObject.userData.selected = false;
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}
|
|
368
|
-
});
|
|
391
|
+
if (this._selectionBox) {
|
|
392
|
+
this.scene.remove(this._selectionBox);
|
|
393
|
+
this._selectionBox.geometry.dispose();
|
|
394
|
+
this._selectionBox = null;
|
|
395
|
+
}
|
|
369
396
|
}
|
|
370
397
|
|
|
371
|
-
// Select new (add subtle highlight)
|
|
372
398
|
this.selectedObject = obj;
|
|
373
399
|
obj.userData.selected = true;
|
|
374
400
|
|
|
375
|
-
//
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
}
|
|
401
|
+
// Show bounding box outline instead of material change - no yellow viewport
|
|
402
|
+
const box = new this.THREE.Box3().setFromObject(obj);
|
|
403
|
+
const boxHelper = new this.THREE.Box3Helper(box, 0x00ff00);
|
|
404
|
+
boxHelper.userData.isSelectionHelper = true;
|
|
405
|
+
this.scene.add(boxHelper);
|
|
406
|
+
this._selectionBox = boxHelper;
|
|
382
407
|
|
|
383
|
-
|
|
384
|
-
const hlMat = child.material.clone();
|
|
385
|
-
if (hlMat.emissive) {
|
|
386
|
-
hlMat.emissive.setHex(0xffff00);
|
|
387
|
-
hlMat.emissiveIntensity = 0.1; // Even more subtle
|
|
388
|
-
}
|
|
389
|
-
child.material = hlMat;
|
|
390
|
-
}
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
console.log('✅ Selected:', obj.userData.assetData.name);
|
|
408
|
+
console.log('✅ Selected:', obj.userData.assetData?.name);
|
|
394
409
|
}
|
|
395
410
|
|
|
396
411
|
updateSceneTree() {
|
|
@@ -796,38 +811,33 @@ export class IobrokerWebui3DScreenEditor extends BaseCustomWebComponentConstruct
|
|
|
796
811
|
|
|
797
812
|
const reader = new FileReader();
|
|
798
813
|
reader.onload = (e) => {
|
|
799
|
-
|
|
800
|
-
const
|
|
801
|
-
const url = URL.createObjectURL(blob);
|
|
814
|
+
// Store as base64 in JSON so it persists across refresh/restart
|
|
815
|
+
const base64 = e.target.result; // readAsDataURL gives data:...;base64,...
|
|
802
816
|
|
|
803
|
-
// Create asset object
|
|
804
817
|
const assetId = 'asset_' + Date.now().toString(36);
|
|
805
818
|
const asset = {
|
|
806
819
|
id: assetId,
|
|
807
820
|
name: file.name,
|
|
808
821
|
type: 'model',
|
|
809
|
-
|
|
822
|
+
glbData: base64, // base64 embedded - survives refresh
|
|
823
|
+
glbPath: null, // no temp blob URL
|
|
810
824
|
position: { x: 0, y: 0, z: 0 },
|
|
811
825
|
rotation: { x: 0, y: 0, z: 0 },
|
|
812
826
|
scale: { x: 1, y: 1, z: 1 },
|
|
813
827
|
visible: true
|
|
814
828
|
};
|
|
815
829
|
|
|
816
|
-
// Add to scene data
|
|
817
830
|
if (!this.sceneData.assets) {
|
|
818
831
|
this.sceneData.assets = [];
|
|
819
832
|
}
|
|
820
833
|
this.sceneData.assets.push(asset);
|
|
821
834
|
|
|
822
|
-
// Load and add to scene
|
|
823
835
|
this.loadAsset(asset);
|
|
824
|
-
|
|
825
|
-
// Update assets list
|
|
826
836
|
this.updateAssetsList();
|
|
827
837
|
|
|
828
|
-
console.log('✅ Asset added:', file.name);
|
|
838
|
+
console.log('✅ Asset added (base64):', file.name);
|
|
829
839
|
};
|
|
830
|
-
reader.
|
|
840
|
+
reader.readAsDataURL(file); // base64 data URL
|
|
831
841
|
}
|
|
832
842
|
|
|
833
843
|
switchTab(tab) {
|