diff --git a/src/frontend/flask_app/static/js/image_viewer.js b/src/frontend/flask_app/static/js/image_viewer.js index d43c5ed..f6744f8 100644 --- a/src/frontend/flask_app/static/js/image_viewer.js +++ b/src/frontend/flask_app/static/js/image_viewer.js @@ -30,9 +30,9 @@ var f = Math.min(boxW / w, boxH / h); return isFinite(f) && f > 0 ? f : 0; }, - // zoom ristretto a [fit * 0.5, max(8, fit)] (come #115) + // zoom ristretto a [fit * 0.5, max(8, fit * 8)]: il massimo segue il fit, cosi' un DXF in mm (fit ~10) si ingrandisce ancora clampZoom: function (z, fit) { - var lo = fit * 0.5, hi = Math.max(8, fit); + var lo = fit * 0.5, hi = Math.max(8, fit * 8); return Math.min(hi, Math.max(lo, z)); }, // nuovo scroll che tiene fermo il punto (px, py) del viewport passando dallo zoom z0 a z1 @@ -54,8 +54,10 @@ 'tmf-viewer .tmfv-stage>svg:not(.tmfv-ov){display:block;width:100%;height:100%}', 'tmf-viewer .tmfv-ov{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;overflow:visible}', 'tmf-viewer .tmfv-labels{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}', - 'tmf-viewer .tmfv-label{position:absolute;transform:translate(8px,-50%);white-space:nowrap;font:600 12px/1.3 system-ui,sans-serif;', - 'color:#fff;background:rgba(0,0,0,.6);padding:1px 5px;border-radius:3px;pointer-events:none}', + // #122: aspetto completo dell'etichetta; le classi `cls` della pagina (es. bg-red-600 text-white) cambiano solo i colori + 'tmf-viewer .tmfv-label{position:absolute;transform:translate(8px,-50%);white-space:nowrap;font:700 12px/1.3 system-ui,sans-serif;', + 'padding:2px 6px;border-radius:4px;box-shadow:0 1px 3px rgba(0,0,0,.4);pointer-events:none}', + ':where(tmf-viewer .tmfv-label){color:#fff;background:rgba(0,0,0,.6)}', 'tmf-viewer .tmfv-bar{position:absolute;top:6px;right:6px;z-index:3;display:flex;align-items:center;gap:2px;padding:2px;', 'background:rgba(0,0,0,.55);color:#fff;border-radius:6px;font:12px/1.4 system-ui,sans-serif}', 'tmf-viewer .tmfv-bar button{appearance:none;border:0;border-radius:4px;background:transparent;color:#fff;', @@ -135,6 +137,11 @@ this._bFit.onclick = function () { self.fit(); }; this._bSave.onclick = function () { self._save(); }; img.addEventListener('load', function () { self._onLoad(); }); + // #122: errore di caricamento -> evento viewer-error (bubbling) con l'URL che non si e' caricato + img.addEventListener('error', function () { + if (!self._hasSrc()) return; // l'errore di un src appena tolto non conta + self.dispatchEvent(new CustomEvent('viewer-error', { bubbles: true, detail: { src: self.getAttribute('src') } })); + }); // Ctrl+rotella = zoom intorno al puntatore; senza Ctrl la pagina scorre come sempre vp.addEventListener('wheel', function (ev) { self._wheel(ev); }, { passive: false }); vp.addEventListener('pointerdown', function (ev) { self._panDown(ev); }); @@ -143,7 +150,12 @@ vp.addEventListener('pointercancel', function () { self._panEnd(); }); // resize del viewport: in stato «adatta» rifa Adatta; altrimenti aggiorna solo il fit if (typeof ResizeObserver !== 'undefined') { - this._ro = new ResizeObserver(function () { self._onResize(); }); + // #122: la callback cambia l'altezza del viewport (fit-height): rimando a un task dopo, senza «ResizeObserver loop» + this._ro = new ResizeObserver(function () { + if (self._raf) return; + var run = function () { self._raf = 0; self._onResize(); }; + self._raf = setTimeout(run, 0); + }); this._ro.observe(vp); } // contenuto aggiunto dopo (x-html, template): lo adotto @@ -247,6 +259,7 @@ if (this._content) this._content.style.display = this._hasSrc() ? 'none' : ''; if (!w) { this._z = 0; this._fit = 0; this._auto = true; this._apply(); return; } if (changed || this._auto || !this._z) this.fit(); else this._apply(); + if (!this._z) this._apply(true); // riquadro nascosto: Adatta rimandata, ma overlay ed etichette (in %) si disegnano gia' } // #122: area utile del viewport: offset meno i bordi (client* escludono le barre che spariranno dopo l'Adatta) diff --git a/src/frontend/flask_app/tests/js/fixtures/image_viewer_demo.html b/src/frontend/flask_app/tests/js/fixtures/image_viewer_demo.html new file mode 100644 index 0000000..89aa3be --- /dev/null +++ b/src/frontend/flask_app/tests/js/fixtures/image_viewer_demo.html @@ -0,0 +1,135 @@ + + + +
+ +