Wizard DXF: anteprime sotto le scelte, mm/px solo da file, prova su due colonne con zoom e Fit #104

Closed
opened 2026-10-25 15:16:36 +00:00 by Adriano · 3 comments
Owner

Richiesta Adriano 25/10/2026. Analisi nel commento.

Richiesta Adriano 25/10/2026. Analisi nel commento.
Adriano added the sviluppo label 2026-10-25 15:16:36 +00:00
Author
Owner

ESITO: richiesta
RIF: gitea:Adriano/TieMeasureFlow#104
COSA: wizard «Crea ricetta da DXF» (editor task, tipo dxf_compare): nuova disposizione. Le anteprime stanno sotto le scelte, il mm/px compare solo per un'immagine da file, il risultato della Prova va su due colonne (immagine a sinistra con zoom e Fit, dati ed errori a destra).

Richiesta di Adriano 25/10/2026: «metti anteprima immagine e anteprima dxf sotto alle scelte di immagine e dxf. Se si seleziona immagine da file viene visualizzato mm/px; anteprima della prova della ricetta deve occupare 1 colonna sx e a dx vengono visualizzati dati risultanti, eventuali errori. Inoltre immagine di prova deve avere anche i pulsanti di zoom e fit».

BASE: ramo lavoro/daitarn-tmf-102, commit 20f3323 (#102: anteprima immagine), worktree C:/Users/Adriano/lavoro/TieMeasureFlow-102.
File: src/frontend/flask_app/static/js/dxf_recipe_wizard.js e src/frontend/flask_app/templates/maker/task_editor.html, blocco «Crea ricetta da DXF» (~righe 662-760).

STATO OGGI

  • Scelte e anteprime stanno in una griglia a 2 colonne: a sinistra i bottoni camera/file, il nome e l'anteprima immagine; a destra l'input .dxf e l'anteprima SVG. Le due anteprime non sono allineate, perché i blocchi sopra hanno altezze diverse.
  • Il campo mm/px (#98) è sempre visibile, sopra le scelte.
  • Dopo «Prova»:
    • error e notice sono righe sopra;
    • l'immagine con overlay è a tutta larghezza, ed è visibile già prima della prova (duplica l'anteprima di #102);
    • sotto c'è la tabella dei 4 valori, con le chiavi grezze dxf.points_in_pct.
  • Il corpo della risposta è result = {result: {outputs, overlay, outcome, ...}, saved, recipe_dir}. Il campo outcome è l'esito della ricetta sul riferimento (vedi src/vision/costruttori.py ~riga 257).
  • Nel frontend non esiste alcun componente di zoom (grep «zoom» vuoto): va scritto.

MODIFICHE

  1. Stato imageSource: '' ('' | 'file' | 'camera'): onImage lo imposta a 'file', grab() a 'camera'; con _setImage(null) torna ''.
  2. Scala effettiva: getter useManualScale = imageSource === 'file' && manualPxMm !== null. Va usato:
    • in canRun, al posto di manualPxMm !== null;
    • in run(), per decidere se inviare px_per_mm;
    • in imagePreviewSummary;
    • nella condizione dell'avviso «Stazione non calibrata» nel template.
      Con un'immagine dalla camera vale la calibrazione della stazione. mmPx non si azzera cambiando sorgente: resta pronto se si torna al file.
  3. Template, ordine nuovo del blocco:
    a. Stazione (invariata).
    b. Griglia sm:grid-cols-2 delle SCELTE:
    • sinistra: «Immagine del pezzo», bottoni, nome file e, solo con x-show="imageSource === 'file'", il campo mm/px di #98 (spostato qui con le sue righe di aiuto e di errore, logica invariata);
    • destra: «Disegno (.dxf)», input e riga «Lettura DXF…» o errore.
      c. Griglia sm:grid-cols-2 delle ANTEPRIME, items-start, subito sotto:
    • sinistra: anteprima immagine di #102 con la riga W × H px · campo;
    • destra: SVG DXF di #101 con la sua riga.
      Le due scatole hanno la stessa altezza fissa (height: 240px, non max-height), object-fit: contain per l'img, preserveAspectRatio per l'SVG: così stanno allineate. Ogni scatola è visibile solo col suo contenuto. Il codice SVG di #101 non cambia (un solo path, x-bind:view-box.camel).
      d. Banda, soglia, controluce, bottoni Prova / Salva: invariati.
      e. RISULTATO DELLA PROVA, visibile solo dopo una Prova (x-show="tested"; tested = true alla fine di run(), riportato a false da _setImage, onDxf, onStation). Griglia lg:grid-cols-2 gap-3:
    • SINISTRA, immagine di prova con overlay e zoom:
      • barra con «−», «+», «Fit» e la percentuale corrente (es. «35 %»);
      • sotto, un contenitore x-ref="viewport" con overflow: auto, altezza min(70vh, 520px), bordo e sfondo var(--bg-primary). Dentro un wrapper position: relative largo naturalWidth * zoom px e alto naturalHeight * zoom px, che contiene l'<img x-ref="img"> (width/height 100%) e il <canvas x-ref="overlay"> assoluto inset-0. Il canvas resta nelle coordinate pixel dell'immagine come oggi (drawOverlay invariato) e lo scala il CSS.
      • stato zoom: 1; zoomBy(f) moltiplica per 1.25 o 1/1.25, limiti 0.05..8, e tiene il centro visibile aggiustando scrollLeft e scrollTop;
      • fit() = min(clientWidth / naturalWidth, clientHeight / naturalHeight) del viewport. Fit si applica da solo al load dell'immagine di prova e a ogni nuova Prova (in $nextTick).
      • Facoltativo, se semplice: Ctrl+rotella sul viewport = zoom (@wheel.prevent solo con ctrlKey); senza Ctrl la rotella scorre la pagina.
    • DESTRA, dati ed errori:
      • Esito: result.result.outcome, verde se positivo e rosso altrimenti. I valori possibili si leggono in src/vision/ o vs-task; non indovinarli: se non sono chiari mostrare il valore grezzo.
      • Tabella dei 4 valori con etichette leggibili tradotte: «Punti in banda» %, «Distanza media», «Distanza minima», «Distanza massima» in mm. Valore con fmt. La chiave grezza resta in piccolo grigio o in title.
      • Parametri usati: scala px/mm con la sua fonte (« mm/px a mano » oppure « calibrazione stazione »), banda ± mm, soglia %.
      • error (rosso) e notice (verde) si spostano qui dalla posizione di oggi.
      • Se la Prova fallisce (error, nessun result), la sezione si mostra lo stesso: a sinistra l'immagine senza overlay, a destra l'errore.
  4. Rimuovere il vecchio blocco «Anteprima con overlay» a tutta larghezza e la vecchia tabella: vengono sostituiti dal punto 3e.
  5. Testi nuovi con _() e voci in translations/{it,en}/LC_MESSAGES/messages.po, niente .mo. Testi passati al JS via msgs se servono nel JS.
  6. Ogni modifica porta un commento breve «#104».

TEST

  • src/frontend/flask_app/tests/js/test_dxf_preview.js, eseguito con node, con un caso per ciascuno di questi punti:
    • useManualScale è falso con imageSource 'camera' anche se mmPx è valido, e vero con 'file';
    • run() non invia px_per_mm con la camera (stub di fetch e FormData come nei test esistenti, se c'è il modo; altrimenti testare il getter usato da run);
    • zoomBy rispetta i limiti;
    • fit calcola il rapporto, con un viewport e un img finti con clientWidth e naturalWidth;
    • tested torna false dopo _setImage.
  • tests/test_dxf_recipe_routes.py: la pagina contiene imageSource === 'file', zoomBy, fit().
  • Suite da src/frontend/flask_app: C:/Users/Adriano/lavoro/TieMeasureFlow-dxfcal-frontend/.venv/Scripts/python.exe -m pytest tests -q -p no:cacheprovider. Base: 9 failed / 402 passed / 2 skipped (fallimenti noti). Nessun fallimento nuovo.

NON TOCCARE

  • src/backend/, src/vision/, src/vision_worker/, vendor/, templates/statistics/**.
  • Il resto di task_editor.html fuori dal blocco del wizard.
  • La logica di loadDxfPreview e dxfPreviewD (#101).
  • drawOverlay (solo il suo contenitore cambia).

PROVA (Opus): dopo il merge e il riavvio, headless Edge sul task 8 della ricetta 3.

  • Immagine da file C:/Users/Adriano/Desktop/Sider foto e DXF/Foto/sider_2_1.bmp: il campo mm/px compare; si inserisce 0,01406.
  • DXF C:/Users/Adriano/Desktop/Sider foto e DXF/DXF profilo/12.3X5.1MEVISS235JR_profilo.dxf: le due anteprime sono affiancate e allineate.
  • Prova con banda 0,3: a sinistra l'immagine con overlay e Fit applicato, a destra esito e valori.
  • «+» e «Fit» cambiano la percentuale.
  • Acquisizione da camera: il campo mm/px sparisce.
ESITO: richiesta RIF: gitea:Adriano/TieMeasureFlow#104 COSA: wizard «Crea ricetta da DXF» (editor task, tipo dxf_compare): nuova disposizione. Le anteprime stanno sotto le scelte, il mm/px compare solo per un'immagine da file, il risultato della Prova va su due colonne (immagine a sinistra con zoom e Fit, dati ed errori a destra). Richiesta di Adriano 25/10/2026: «metti anteprima immagine e anteprima dxf sotto alle scelte di immagine e dxf. Se si seleziona immagine da file viene visualizzato mm/px; anteprima della prova della ricetta deve occupare 1 colonna sx e a dx vengono visualizzati dati risultanti, eventuali errori. Inoltre immagine di prova deve avere anche i pulsanti di zoom e fit». BASE: ramo lavoro/daitarn-tmf-102, commit 20f3323 (#102: anteprima immagine), worktree C:/Users/Adriano/lavoro/TieMeasureFlow-102. File: src/frontend/flask_app/static/js/dxf_recipe_wizard.js e src/frontend/flask_app/templates/maker/task_editor.html, blocco «Crea ricetta da DXF» (~righe 662-760). STATO OGGI - Scelte e anteprime stanno in una griglia a 2 colonne: a sinistra i bottoni camera/file, il nome e l'anteprima immagine; a destra l'input .dxf e l'anteprima SVG. Le due anteprime non sono allineate, perché i blocchi sopra hanno altezze diverse. - Il campo mm/px (#98) è sempre visibile, sopra le scelte. - Dopo «Prova»: - `error` e `notice` sono righe sopra; - l'immagine con overlay è a tutta larghezza, ed è visibile già prima della prova (duplica l'anteprima di #102); - sotto c'è la tabella dei 4 valori, con le chiavi grezze `dxf.points_in_pct`. - Il corpo della risposta è `result = {result: {outputs, overlay, outcome, ...}, saved, recipe_dir}`. Il campo `outcome` è l'esito della ricetta sul riferimento (vedi `src/vision/costruttori.py` ~riga 257). - Nel frontend non esiste alcun componente di zoom (grep «zoom» vuoto): va scritto. MODIFICHE 1. Stato `imageSource: ''` ('' | 'file' | 'camera'): `onImage` lo imposta a 'file', `grab()` a 'camera'; con `_setImage(null)` torna ''. 2. Scala effettiva: getter `useManualScale` = `imageSource === 'file' && manualPxMm !== null`. Va usato: - in `canRun`, al posto di `manualPxMm !== null`; - in `run()`, per decidere se inviare `px_per_mm`; - in `imagePreviewSummary`; - nella condizione dell'avviso «Stazione non calibrata» nel template. Con un'immagine dalla camera vale la calibrazione della stazione. `mmPx` non si azzera cambiando sorgente: resta pronto se si torna al file. 3. Template, ordine nuovo del blocco: a. Stazione (invariata). b. Griglia `sm:grid-cols-2` delle SCELTE: - sinistra: «Immagine del pezzo», bottoni, nome file e, solo con `x-show="imageSource === 'file'"`, il campo mm/px di #98 (spostato qui con le sue righe di aiuto e di errore, logica invariata); - destra: «Disegno (.dxf)», input e riga «Lettura DXF…» o errore. c. Griglia `sm:grid-cols-2` delle ANTEPRIME, `items-start`, subito sotto: - sinistra: anteprima immagine di #102 con la riga W × H px · campo; - destra: SVG DXF di #101 con la sua riga. Le due scatole hanno la stessa altezza fissa (`height: 240px`, non max-height), `object-fit: contain` per l'img, `preserveAspectRatio` per l'SVG: così stanno allineate. Ogni scatola è visibile solo col suo contenuto. Il codice SVG di #101 non cambia (un solo path, `x-bind:view-box.camel`). d. Banda, soglia, controluce, bottoni Prova / Salva: invariati. e. RISULTATO DELLA PROVA, visibile solo dopo una Prova (`x-show="tested"`; `tested` = true alla fine di `run()`, riportato a false da `_setImage`, `onDxf`, `onStation`). Griglia `lg:grid-cols-2 gap-3`: - SINISTRA, immagine di prova con overlay e zoom: - barra con «−», «+», «Fit» e la percentuale corrente (es. «35 %»); - sotto, un contenitore `x-ref="viewport"` con `overflow: auto`, altezza `min(70vh, 520px)`, bordo e sfondo var(--bg-primary). Dentro un wrapper `position: relative` largo `naturalWidth * zoom` px e alto `naturalHeight * zoom` px, che contiene l'`<img x-ref="img">` (width/height 100%) e il `<canvas x-ref="overlay">` assoluto inset-0. Il canvas resta nelle coordinate pixel dell'immagine come oggi (`drawOverlay` invariato) e lo scala il CSS. - stato `zoom: 1`; `zoomBy(f)` moltiplica per 1.25 o 1/1.25, limiti 0.05..8, e tiene il centro visibile aggiustando scrollLeft e scrollTop; - `fit()` = min(clientWidth / naturalWidth, clientHeight / naturalHeight) del viewport. Fit si applica da solo al load dell'immagine di prova e a ogni nuova Prova (in `$nextTick`). - Facoltativo, se semplice: Ctrl+rotella sul viewport = zoom (`@wheel.prevent` solo con ctrlKey); senza Ctrl la rotella scorre la pagina. - DESTRA, dati ed errori: - Esito: `result.result.outcome`, verde se positivo e rosso altrimenti. I valori possibili si leggono in `src/vision/` o vs-task; non indovinarli: se non sono chiari mostrare il valore grezzo. - Tabella dei 4 valori con etichette leggibili tradotte: «Punti in banda» %, «Distanza media», «Distanza minima», «Distanza massima» in mm. Valore con `fmt`. La chiave grezza resta in piccolo grigio o in `title`. - Parametri usati: scala px/mm con la sua fonte (« mm/px a mano » oppure « calibrazione stazione »), banda ± mm, soglia %. - `error` (rosso) e `notice` (verde) si spostano qui dalla posizione di oggi. - Se la Prova fallisce (`error`, nessun `result`), la sezione si mostra lo stesso: a sinistra l'immagine senza overlay, a destra l'errore. 4. Rimuovere il vecchio blocco «Anteprima con overlay» a tutta larghezza e la vecchia tabella: vengono sostituiti dal punto 3e. 5. Testi nuovi con `_()` e voci in `translations/{it,en}/LC_MESSAGES/messages.po`, niente .mo. Testi passati al JS via `msgs` se servono nel JS. 6. Ogni modifica porta un commento breve «#104». TEST - `src/frontend/flask_app/tests/js/test_dxf_preview.js`, eseguito con node, con un caso per ciascuno di questi punti: - `useManualScale` è falso con imageSource 'camera' anche se mmPx è valido, e vero con 'file'; - `run()` non invia `px_per_mm` con la camera (stub di fetch e FormData come nei test esistenti, se c'è il modo; altrimenti testare il getter usato da run); - `zoomBy` rispetta i limiti; - `fit` calcola il rapporto, con un viewport e un img finti con clientWidth e naturalWidth; - `tested` torna false dopo `_setImage`. - `tests/test_dxf_recipe_routes.py`: la pagina contiene `imageSource === 'file'`, `zoomBy`, `fit()`. - Suite da `src/frontend/flask_app`: `C:/Users/Adriano/lavoro/TieMeasureFlow-dxfcal-frontend/.venv/Scripts/python.exe -m pytest tests -q -p no:cacheprovider`. Base: 9 failed / 402 passed / 2 skipped (fallimenti noti). Nessun fallimento nuovo. NON TOCCARE - src/backend/**, src/vision/**, src/vision_worker/**, vendor/**, templates/statistics/**. - Il resto di task_editor.html fuori dal blocco del wizard. - La logica di `loadDxfPreview` e `dxfPreviewD` (#101). - `drawOverlay` (solo il suo contenitore cambia). PROVA (Opus): dopo il merge e il riavvio, headless Edge sul task 8 della ricetta 3. - Immagine da file `C:/Users/Adriano/Desktop/Sider foto e DXF/Foto/sider_2_1.bmp`: il campo mm/px compare; si inserisce 0,01406. - DXF `C:/Users/Adriano/Desktop/Sider foto e DXF/DXF profilo/12.3X5.1MEVISS235JR_profilo.dxf`: le due anteprime sono affiancate e allineate. - Prova con banda 0,3: a sinistra l'immagine con overlay e Fit applicato, a destra esito e valori. - «+» e «Fit» cambiano la percentuale. - Acquisizione da camera: il campo mm/px sparisce.
Adriano added the assegnata:daitarn label 2026-10-25 15:16:42 +00:00
Author
Owner

🔵 daitarn — preso in carico 2026-10-25T15:16:38Z
ramo: lavoro/daitarn · capacità: build-windows, gpu

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

Soluzione

ESITO: fatto. Ramo lavoro/daitarn-tmf-dxfcal (push 08616aa). FILE: dxf_recipe_wizard.js (imageSource, useManualScale, tested, zoom/fitZoom/zoomBy/fit/onWheel, pan onPanDown/Move/End con preventDefault, vpHeight, outcome/values con etichette, scaleSummary), task_editor.html (scelte → anteprime affiancate, DXF sm:col-start-2; mm/px solo con immagine da file; risultato sm:grid-cols-2: immagine con barra −/+/Adatta in sovrimpressione e pan a sinistra, esito/valori/parametri/errori a destra), messages.po. Commit 1a19bb6, 02f1481, bdef1f1, 34e1b04, 08616aa. PROVA: headless Edge 1500 e 900 px: risultati a destra; Adatta 21 %, + ×4 52 %, drag (-120,-80) → scroll +120/+80, cursore grabbing; Adatta → altezza viewport 435 (segue immagine); camera → campo mm/px nascosto; node test ok; suite frontend 9 fallimenti noti.

**Soluzione** ESITO: fatto. Ramo lavoro/daitarn-tmf-dxfcal (push 08616aa). FILE: dxf_recipe_wizard.js (imageSource, useManualScale, tested, zoom/fitZoom/zoomBy/fit/onWheel, pan onPanDown/Move/End con preventDefault, vpHeight, outcome/values con etichette, scaleSummary), task_editor.html (scelte → anteprime affiancate, DXF sm:col-start-2; mm/px solo con immagine da file; risultato sm:grid-cols-2: immagine con barra −/+/Adatta in sovrimpressione e pan a sinistra, esito/valori/parametri/errori a destra), messages.po. Commit 1a19bb6, 02f1481, bdef1f1, 34e1b04, 08616aa. PROVA: headless Edge 1500 e 900 px: risultati a destra; Adatta 21 %, + ×4 52 %, drag (-120,-80) → scroll +120/+80, cursore grabbing; Adatta → altezza viewport 435 (segue immagine); camera → campo mm/px nascosto; node test ok; suite frontend 9 fallimenti noti.
Adriano removed the assegnata:daitarn label 2026-10-25 15:48:20 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Adriano/TieMeasureFlow#104