iobroker.mywebui 1.42.30 → 1.42.32
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
|
@@ -587,19 +587,51 @@ export class IobrokerHandler {
|
|
|
587
587
|
}
|
|
588
588
|
async _getObjectFromFile(name) {
|
|
589
589
|
const file = await this.connection.readFile(this.namespaceFiles, name, false);
|
|
590
|
+
let bytes;
|
|
590
591
|
if (file.mimeType == 'application/json' || file.mimeType == 'text/javascript') {
|
|
591
592
|
return JSON.parse(file.file);
|
|
593
|
+
} else if (file.mimeType == 'application/octet-stream' && file.file instanceof ArrayBuffer) {
|
|
594
|
+
bytes = new Uint8Array(file.file);
|
|
595
|
+
} else {
|
|
596
|
+
bytes = Uint8Array.from(file.file.data);
|
|
592
597
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
598
|
+
// Gzip magic bytes 1f 8b — decompress transparently
|
|
599
|
+
if (bytes[0] === 0x1f && bytes[1] === 0x8b && window.DecompressionStream) {
|
|
600
|
+
bytes = await this._gunzipBytes(bytes);
|
|
596
601
|
}
|
|
597
|
-
|
|
598
|
-
return JSON.parse(dec.decode(Uint8Array.from(file.file.data)));
|
|
602
|
+
return JSON.parse(new TextDecoder().decode(bytes));
|
|
599
603
|
}
|
|
600
604
|
async _saveObjectToFile(obj, name) {
|
|
601
|
-
const
|
|
602
|
-
|
|
605
|
+
const bytes = new TextEncoder().encode(JSON.stringify(obj));
|
|
606
|
+
// Compress files >512 KB to prevent WebSocket message overflow
|
|
607
|
+
if (bytes.length > 512 * 1024 && window.CompressionStream) {
|
|
608
|
+
const compressed = await this._gzipBytes(bytes);
|
|
609
|
+
await this.connection.writeFile64(this.namespaceFiles, name, compressed.buffer);
|
|
610
|
+
} else {
|
|
611
|
+
await this.connection.writeFile64(this.namespaceFiles, name, bytes);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
async _gzipBytes(bytes) {
|
|
615
|
+
const cs = new CompressionStream('gzip');
|
|
616
|
+
const w = cs.writable.getWriter();
|
|
617
|
+
w.write(bytes); w.close();
|
|
618
|
+
const r = cs.readable.getReader();
|
|
619
|
+
const chunks = []; let res;
|
|
620
|
+
while (!(res = await r.read()).done) chunks.push(res.value);
|
|
621
|
+
const out = new Uint8Array(chunks.reduce((s, c) => s + c.length, 0));
|
|
622
|
+
let off = 0; for (const c of chunks) { out.set(c, off); off += c.length; }
|
|
623
|
+
return out;
|
|
624
|
+
}
|
|
625
|
+
async _gunzipBytes(bytes) {
|
|
626
|
+
const ds = new DecompressionStream('gzip');
|
|
627
|
+
const w = ds.writable.getWriter();
|
|
628
|
+
w.write(bytes); w.close();
|
|
629
|
+
const r = ds.readable.getReader();
|
|
630
|
+
const chunks = []; let res;
|
|
631
|
+
while (!(res = await r.read()).done) chunks.push(res.value);
|
|
632
|
+
const out = new Uint8Array(chunks.reduce((s, c) => s + c.length, 0));
|
|
633
|
+
let off = 0; for (const c of chunks) { out.set(c, off); off += c.length; }
|
|
634
|
+
return out;
|
|
603
635
|
}
|
|
604
636
|
async _saveBinaryToFile(binary, name) {
|
|
605
637
|
await this.connection.writeFile64(this.namespaceFiles, name, await binary.arrayBuffer());
|
|
@@ -27,6 +27,7 @@ export class IobrokerWebui3DScreenViewer extends BaseCustomWebComponentConstruct
|
|
|
27
27
|
|
|
28
28
|
disconnectedCallback() {
|
|
29
29
|
this._animating = false;
|
|
30
|
+
if (this._cleanup) { this._cleanup(); this._cleanup = null; }
|
|
30
31
|
if (this._renderer) { this._renderer.dispose(); this._renderer.domElement.remove(); this._renderer = null; }
|
|
31
32
|
window.removeEventListener('resize', this._onResize);
|
|
32
33
|
}
|
|
@@ -109,15 +110,49 @@ export class IobrokerWebui3DScreenViewer extends BaseCustomWebComponentConstruct
|
|
|
109
110
|
const controls = new OrbitControls(camera, renderer.domElement);
|
|
110
111
|
controls.enableDamping = true;
|
|
111
112
|
|
|
113
|
+
// Script context helpers
|
|
114
|
+
const frameCallbacks = [];
|
|
115
|
+
const selectCallbacks = [];
|
|
116
|
+
const _subscriptions = [];
|
|
117
|
+
|
|
118
|
+
const onFrame = (fn) => frameCallbacks.push(fn);
|
|
119
|
+
const onSelect = (fn) => selectCallbacks.push(fn);
|
|
120
|
+
const log = (...args) => console.log('[3D]', ...args);
|
|
121
|
+
|
|
122
|
+
const setState = (id, val) => {
|
|
123
|
+
try { iobrokerHandler.setState(id, val); } catch (_) {}
|
|
124
|
+
};
|
|
125
|
+
const getState = async (id) => {
|
|
126
|
+
try { return await iobrokerHandler.getState(id); } catch (_) { return null; }
|
|
127
|
+
};
|
|
128
|
+
const subscribe = (id, cb) => {
|
|
129
|
+
try {
|
|
130
|
+
const unsub = iobrokerHandler.subscribeState(id, cb);
|
|
131
|
+
_subscriptions.push(unsub);
|
|
132
|
+
return unsub;
|
|
133
|
+
} catch (_) { return () => {}; }
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const assets = new Map();
|
|
137
|
+
const mixers = new Map();
|
|
138
|
+
|
|
112
139
|
// Run scene script if present
|
|
113
140
|
if (sceneData.script) {
|
|
114
141
|
try {
|
|
115
|
-
const fn = new Function(
|
|
116
|
-
|
|
142
|
+
const fn = new Function(
|
|
143
|
+
'THREE', 'scene', 'camera', 'renderer', 'controls',
|
|
144
|
+
'onFrame', 'onSelect', 'setState', 'getState', 'subscribe',
|
|
145
|
+
'assets', 'mixers', 'log',
|
|
146
|
+
sceneData.script
|
|
147
|
+
);
|
|
148
|
+
fn(THREE, scene, camera, renderer, controls,
|
|
149
|
+
onFrame, onSelect, setState, getState, subscribe,
|
|
150
|
+
assets, mixers, log);
|
|
117
151
|
} catch (e) { console.warn('3D scene script error:', e); }
|
|
118
152
|
}
|
|
119
153
|
|
|
120
154
|
this._animating = true;
|
|
155
|
+
this._cleanup = () => { _subscriptions.forEach(u => { try { u(); } catch (_) {} }); };
|
|
121
156
|
this._onResize = () => {
|
|
122
157
|
const vw = viewport.clientWidth, vh = viewport.clientHeight;
|
|
123
158
|
camera.aspect = vw / vh;
|
|
@@ -126,13 +161,17 @@ export class IobrokerWebui3DScreenViewer extends BaseCustomWebComponentConstruct
|
|
|
126
161
|
};
|
|
127
162
|
window.addEventListener('resize', this._onResize);
|
|
128
163
|
|
|
129
|
-
|
|
164
|
+
let _lastTime = 0;
|
|
165
|
+
const animate = (ts) => {
|
|
130
166
|
if (!this._animating) return;
|
|
131
167
|
requestAnimationFrame(animate);
|
|
132
|
-
|
|
168
|
+
const dt = _lastTime ? (ts - _lastTime) / 1000 : 0;
|
|
169
|
+
_lastTime = ts;
|
|
170
|
+
controls.update(dt);
|
|
171
|
+
for (const cb of frameCallbacks) { try { cb(dt, ts / 1000); } catch (_) {} }
|
|
133
172
|
renderer.render(scene, camera);
|
|
134
173
|
};
|
|
135
|
-
animate();
|
|
174
|
+
animate(0);
|
|
136
175
|
|
|
137
176
|
} catch (err) {
|
|
138
177
|
console.error('3D Viewer error:', err);
|