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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "mywebui",
4
- "version": "1.42.11",
4
+ "version": "1.42.12",
5
5
  "titleLang": {
6
6
  "en": "mywebui",
7
7
  "de": "mywebui",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.mywebui",
3
- "version": "1.42.11",
3
+ "version": "1.42.12",
4
4
  "description": "ioBroker mywebui - Custom edited mywebui by gokturk413 with 3D Editor",
5
5
  "type": "module",
6
6
  "main": "dist/backend/main.js",
@@ -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
- if (!asset.glbPath) return;
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
- asset.glbPath,
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) => console.error('Error loading asset:', 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 (remove highlight)
388
+ // Deselect previous - remove bounding box helper
360
389
  if (this.selectedObject) {
361
390
  this.selectedObject.userData.selected = false;
362
- // Restore original materials
363
- this.selectedObject.traverse((child) => {
364
- if (child.isMesh && child.userData.originalMaterial) {
365
- child.material = child.userData.originalMaterial;
366
- delete child.userData.originalMaterial;
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
- // Apply very subtle highlight - only emissive, preserve all other properties
376
- obj.traverse((child) => {
377
- if (child.isMesh && child.material && !Array.isArray(child.material)) {
378
- // Store original if not already stored
379
- if (!child.userData.originalMaterial) {
380
- child.userData.originalMaterial = child.material;
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
- // Clone and apply subtle glow
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
- const arrayBuffer = e.target.result;
800
- const blob = new Blob([arrayBuffer]);
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
- glbPath: url,
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.readAsArrayBuffer(file);
840
+ reader.readAsDataURL(file); // base64 data URL
831
841
  }
832
842
 
833
843
  switchTab(tab) {