Operatore, pannello visione: zoom −/+/Adatta in overlay sull'immagine #115

Closed
opened 2026-10-28 15:41:14 +00:00 by Adriano · 3 comments
Owner

Chiesto da Adriano in fiera il 28/10/2026: sull'immagine del task camera/DXF dell'operatore (templates/measure/task_execute.html, pannello visionExecute) mancano zoom +/− e Adatta, come in Acquisizione (#111) e nel wizard DXF (#113). Fatto: barra in overlay sull'immagine con −, +, Adatta e percentuale; Ctrl+rotella e trascinamento; all'apertura l'immagine resta in fit come oggi (#96), senza scorrimento del pannello.

Chiesto da Adriano in fiera il 28/10/2026: sull'immagine del task camera/DXF dell'operatore (templates/measure/task_execute.html, pannello visionExecute) mancano zoom +/− e Adatta, come in Acquisizione (#111) e nel wizard DXF (#113). Fatto: barra in overlay sull'immagine con −, +, Adatta e percentuale; Ctrl+rotella e trascinamento; all'apertura l'immagine resta in fit come oggi (#96), senza scorrimento del pannello.
Adriano added the sviluppo label 2026-10-28 15:41:14 +00:00
Author
Owner

ANALISI (Opus, passo 1)
COSA: zoom −/+/Adatta/% in overlay sull'immagine del pannello visione dell'operatore, Ctrl+rotella, trascinamento; all'apertura fit come oggi (#96). Stesso schema del wizard DXF (#113: static/js/dxf_recipe_wizard.js metodi _vpEl, _vLimits, vFit, vZoomBy, vWheel, vPan*; commit 45c9e6c 04b81ad 198c6c6), qui per una sola vista.
FILE: src/frontend/flask_app/templates/measure/task_execute.html ~579-583, riquadro x-show="shownImage" (resta relative flex-1 min-h-0 ... overflow-hidden):

  • barra overlay absolute top-2 right-2 z-10 con − (zoomBy(0.8)), + (zoomBy(1.25)), Adatta (zFit()), percentuale x-text="zPct()"; classi come la barra di #113 in templates/maker/task_editor.html ~729-785.
  • viewport x-ref="vp" class="absolute inset-0" con SOLO :style stringa (overflow:auto;touch-action:none;user-select:none;display:flex;cursor:...), @wheel="zWheel($event)", @pointerdown/move/up/cancel → zPanDown/zPanMove/zPanEnd.
  • dentro, wrapper class="relative" con :style="'margin:auto;flex:none;' + zSize()" (width:Wpx;height:Hpx = naturale × zoom; prima del load width:100%;height:100%).
  • img x-ref="img" e canvas x-ref="overlay" dentro il wrapper, absolute inset-0 w-full h-full object-contain come ora; img @load="onImgLoad()".
    FILE: src/frontend/flask_app/static/js/vision_execute.js, componente visionExecute():
  • stato z: { zoom: 1, fit: 1, w: 0, h: 0, auto: true }, _zPan: null, _zRO: null.
  • onImgLoad(): se cambiano le dimensioni naturali o z.auto è vero → aggiorna z.w/z.h e zFit(); altrimenti tiene lo zoom (in linea il frame nuovo resta ingrandito); poi drawOverlay(); _zObserve() (ResizeObserver su vp, rifà il fit solo se z.auto).
  • _zArea(): area utile = offsetWidth/offsetHeight meno i bordi da getComputedStyle (come 198c6c6: client* escludono le barre di scorrimento); senza offsetWidth (test) clientWidth/clientHeight.
  • zFit(): fit = min(cw/w, ch/h), zoom = fit, auto = true, scroll a 0.
  • zoomBy(f, cx, cy): limiti [fit*0.5, max(8, fit)]; punto (cx, cy) del viewport fermo (default centro): scrollLeft = (scrollLeft + cx) * nuovo/vecchio - cx dopo $nextTick; auto = false.
  • zWheel(ev): solo con ctrlKey (preventDefault), fattore 1.25/0.8 al cursore.
  • zCanPan(), zCursor() (grab/grabbing/default), zPanDown/Move/End con pointer capture, spostano scrollLeft/scrollTop.
  • zPct() = Math.round(zoom*100) + '%'; zSize().
    TRAPPOLE (viste in #113): Alpine 3.15.12 con :style stringa fa setAttribute('style') e cancella lo style statico → niente style= statico sugli elementi con :style; mai x-show e :style stringa sullo stesso elemento.
    TEST: nuovo src/frontend/flask_app/tests/js/test_vision_zoom.js (node + vm, stile tests/js/test_dxf_zoom.js): fit con $refs.vp finto (offsetWidth/offsetHeight + getComputedStyle finto con bordi), limiti di zoomBy, auto false/true, zSize prima e dopo il load, frame nuovo con stesse dimensioni che tiene lo zoom; wrapper tests/test_vision_zoom_js.py (skip senza node). Aggiornare tests/test_vision_panel_fit.py alla struttura nuova mantenendo l'intento #96: pannello overflow-hidden min-h-0, riquadro flex-1 min-h-0 overflow-hidden, vp con overflow:auto, img e canvas object-contain.
    NON TOCCARE: backend, wizard DXF, altre pagine, logica di acquisizione/check/record, rows.label (#114).
    RAMO: lavoro/daitarn-tmf-pannello da lavoro/daitarn-tmf-dxfcal (7a1df0b). Ordine dei commit: #115, #117, #116.
ANALISI (Opus, passo 1) COSA: zoom −/+/Adatta/% in overlay sull'immagine del pannello visione dell'operatore, Ctrl+rotella, trascinamento; all'apertura fit come oggi (#96). Stesso schema del wizard DXF (#113: `static/js/dxf_recipe_wizard.js` metodi `_vpEl`, `_vLimits`, `vFit`, `vZoomBy`, `vWheel`, `vPan*`; commit 45c9e6c 04b81ad 198c6c6), qui per una sola vista. FILE: `src/frontend/flask_app/templates/measure/task_execute.html` ~579-583, riquadro `x-show="shownImage"` (resta `relative flex-1 min-h-0 ... overflow-hidden`): - barra overlay `absolute top-2 right-2 z-10` con − (`zoomBy(0.8)`), + (`zoomBy(1.25)`), Adatta (`zFit()`), percentuale `x-text="zPct()"`; classi come la barra di #113 in `templates/maker/task_editor.html` ~729-785. - viewport `x-ref="vp"` `class="absolute inset-0"` con SOLO `:style` stringa (`overflow:auto;touch-action:none;user-select:none;display:flex;cursor:...`), `@wheel="zWheel($event)"`, `@pointerdown/move/up/cancel` → `zPanDown/zPanMove/zPanEnd`. - dentro, wrapper `class="relative"` con `:style="'margin:auto;flex:none;' + zSize()"` (`width:Wpx;height:Hpx` = naturale × zoom; prima del load `width:100%;height:100%`). - `img x-ref="img"` e `canvas x-ref="overlay"` dentro il wrapper, `absolute inset-0 w-full h-full object-contain` come ora; `img @load="onImgLoad()"`. FILE: `src/frontend/flask_app/static/js/vision_execute.js`, componente `visionExecute()`: - stato `z: { zoom: 1, fit: 1, w: 0, h: 0, auto: true }`, `_zPan: null`, `_zRO: null`. - `onImgLoad()`: se cambiano le dimensioni naturali o `z.auto` è vero → aggiorna `z.w/z.h` e `zFit()`; altrimenti tiene lo zoom (in linea il frame nuovo resta ingrandito); poi `drawOverlay()`; `_zObserve()` (ResizeObserver su `vp`, rifà il fit solo se `z.auto`). - `_zArea()`: area utile = `offsetWidth/offsetHeight` meno i bordi da `getComputedStyle` (come 198c6c6: `client*` escludono le barre di scorrimento); senza `offsetWidth` (test) `clientWidth/clientHeight`. - `zFit()`: `fit = min(cw/w, ch/h)`, `zoom = fit`, `auto = true`, scroll a 0. - `zoomBy(f, cx, cy)`: limiti `[fit*0.5, max(8, fit)]`; punto (cx, cy) del viewport fermo (default centro): `scrollLeft = (scrollLeft + cx) * nuovo/vecchio - cx` dopo `$nextTick`; `auto = false`. - `zWheel(ev)`: solo con `ctrlKey` (preventDefault), fattore 1.25/0.8 al cursore. - `zCanPan()`, `zCursor()` (`grab`/`grabbing`/`default`), `zPanDown/Move/End` con pointer capture, spostano `scrollLeft/scrollTop`. - `zPct()` = `Math.round(zoom*100) + '%'`; `zSize()`. TRAPPOLE (viste in #113): Alpine 3.15.12 con `:style` stringa fa `setAttribute('style')` e cancella lo `style` statico → niente `style=` statico sugli elementi con `:style`; mai `x-show` e `:style` stringa sullo stesso elemento. TEST: nuovo `src/frontend/flask_app/tests/js/test_vision_zoom.js` (node + vm, stile `tests/js/test_dxf_zoom.js`): fit con `$refs.vp` finto (offsetWidth/offsetHeight + `getComputedStyle` finto con bordi), limiti di `zoomBy`, `auto` false/true, `zSize` prima e dopo il load, frame nuovo con stesse dimensioni che tiene lo zoom; wrapper `tests/test_vision_zoom_js.py` (skip senza node). Aggiornare `tests/test_vision_panel_fit.py` alla struttura nuova mantenendo l'intento #96: pannello `overflow-hidden min-h-0`, riquadro `flex-1 min-h-0 overflow-hidden`, `vp` con `overflow:auto`, img e canvas `object-contain`. NON TOCCARE: backend, wizard DXF, altre pagine, logica di acquisizione/check/record, `rows.label` (#114). RAMO: `lavoro/daitarn-tmf-pannello` da `lavoro/daitarn-tmf-dxfcal` (7a1df0b). Ordine dei commit: #115, #117, #116.
Adriano added the assegnata:daitarn label 2026-10-28 15:45:09 +00:00
Author
Owner

🔵 daitarn — preso in carico 2026-10-28T15:45:07Z
ramo: lavoro/daitarn · capacità: build-windows, gpu

🔵 daitarn — **preso in carico** 2026-10-28T15:45:07Z ramo: `lavoro/daitarn` · capacità: build-windows, gpu
Author
Owner

Soluzione

ESITO: fatto. Zoom −/+/Adatta/% in overlay, Ctrl+rotella, trascinamento sul riquadro immagine del pannello visione; fit all'apertura (#96), zoom tenuto fra frame in linea di uguali dimensioni. FILE: src/frontend/flask_app/static/js/vision_execute.js (z, onImgLoad, zFit, zoomBy, zWheel, zPan*), templates/measure/task_execute.html (barra, viewport x-ref=vp, wrapper naturale×zoom). TEST: tests/js/test_vision_zoom.js + tests/test_vision_zoom_js.py, test_vision_panel_fit.py aggiornato. Ramo lavoro/daitarn-tmf-dxfcal 4a11d25 (merge 4485803), pytest pannello 37 passed. Installato sul PC fiera DESKTOP-RABEHJJ con riavvio TMF il 28/10, backup C:\Tielogic\backup\pre-115.

**Soluzione** ESITO: fatto. Zoom −/+/Adatta/% in overlay, Ctrl+rotella, trascinamento sul riquadro immagine del pannello visione; fit all'apertura (#96), zoom tenuto fra frame in linea di uguali dimensioni. FILE: src/frontend/flask_app/static/js/vision_execute.js (z, onImgLoad, zFit, zoomBy, zWheel, zPan*), templates/measure/task_execute.html (barra, viewport x-ref=vp, wrapper naturale×zoom). TEST: tests/js/test_vision_zoom.js + tests/test_vision_zoom_js.py, test_vision_panel_fit.py aggiornato. Ramo lavoro/daitarn-tmf-dxfcal 4a11d25 (merge 4485803), pytest pannello 37 passed. Installato sul PC fiera DESKTOP-RABEHJJ con riavvio TMF il 28/10, backup C:\Tielogic\backup\pre-115.
Adriano removed the assegnata:daitarn label 2026-10-28 16:05:48 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Adriano/TieMeasureFlow#115