maker: anteprima immagine nel wizard Crea ricetta da DXF (Refs #102)
Anteprima dell'immagine scelta/acquisita accanto a quella del DXF, con pixel e campo in mm (scala a mano o calibrazione stazione); fallback se il formato non e' mostrabile. Test JS e di pagina, voci it/en. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,9 @@ function dxfRecipeWizard(taskId, csrf, msgs) {
|
||||
imageFile: null, // immagine caricata o acquisita
|
||||
imageName: '',
|
||||
imageSrc: '',
|
||||
imagePx: null, // #102: {w, h} in pixel, letto dall'<img> dell'anteprima
|
||||
imageBroken: false, // #102: il browser non sa mostrare il formato (il file resta valido per l'invio)
|
||||
calPxMm: null, // #102: px/mm della calibrazione della stazione
|
||||
dxfFile: null,
|
||||
dxfPreview: null, // #101: risposta di /dxf-preview {contorni, bbox, larghezza_mm, altezza_mm, entita, punti}
|
||||
dxfPreviewBusy: false,
|
||||
@@ -54,13 +57,17 @@ function dxfRecipeWizard(taskId, csrf, msgs) {
|
||||
|
||||
// Cambio stazione: rilegge lo stato di calibrazione dall'acquisitore
|
||||
async onStation() {
|
||||
this.calState = ''; this.calLabel = ''; this.calUrl = '';
|
||||
this.calState = ''; this.calLabel = ''; this.calUrl = ''; this.calPxMm = null;
|
||||
this.result = null;
|
||||
if (!this.stationId) return;
|
||||
const r = await fetchStationCalibration(this.stationId);
|
||||
this.calState = r.state || 'unreachable';
|
||||
this.calUrl = r.calibration_url || '';
|
||||
if (this.calState === 'calibrated') this.calLabel = formatCalibration(r.calibration || {});
|
||||
if (this.calState === 'calibrated') {
|
||||
this.calLabel = formatCalibration(r.calibration || {});
|
||||
const c = Number((r.calibration || {}).px_per_mm); // #102: scala per il campo in mm dell'anteprima
|
||||
this.calPxMm = Number.isFinite(c) && c > 0 ? c : null;
|
||||
}
|
||||
},
|
||||
|
||||
get calibrated() { return this.calState === 'calibrated'; },
|
||||
@@ -81,12 +88,38 @@ function dxfRecipeWizard(taskId, csrf, msgs) {
|
||||
|
||||
_setImage(file) {
|
||||
if (this.imageSrc) URL.revokeObjectURL(this.imageSrc);
|
||||
this.imageFile = file;
|
||||
this.imageName = file.name || '';
|
||||
this.imageSrc = URL.createObjectURL(file);
|
||||
// #102: con file null (immagine tolta) si azzera anche l'anteprima
|
||||
this.imageFile = file || null;
|
||||
this.imageName = (file && file.name) || '';
|
||||
this.imageSrc = file ? URL.createObjectURL(file) : '';
|
||||
this.imagePx = null;
|
||||
this.imageBroken = false;
|
||||
this.result = null;
|
||||
},
|
||||
|
||||
// #102: l'<img> dell'anteprima e' caricata: legge i pixel; se non si carica il formato non e' mostrabile
|
||||
onImagePreviewLoad(el) {
|
||||
this.imageBroken = false;
|
||||
this.imagePx = el && el.naturalWidth ? { w: el.naturalWidth, h: el.naturalHeight } : null;
|
||||
},
|
||||
onImagePreviewError() {
|
||||
this.imageBroken = !!this.imageSrc;
|
||||
this.imagePx = null;
|
||||
},
|
||||
// #102: nome usato dal template (stesso valore dell'URL gia' usato per l'overlay dei risultati)
|
||||
get imagePreviewUrl() { return this.imageSrc; },
|
||||
// #102: «W × H px · campo ≈ L × H mm»; scala = mm/px a mano se valido, altrimenti calibrazione della stazione
|
||||
get imagePreviewSummary() {
|
||||
const p = this.imagePx;
|
||||
if (!p) return '';
|
||||
const lang = document.documentElement.lang || 'it';
|
||||
const f = (v, d) => Number(v).toLocaleString(lang, { minimumFractionDigits: d, maximumFractionDigits: d });
|
||||
let text = `${f(p.w, 0)} × ${f(p.h, 0)} px`;
|
||||
const pxMm = this.manualPxMm !== null ? this.manualPxMm : (this.calibrated ? this.calPxMm : null);
|
||||
if (pxMm) text += ` · ${this.msgs.imageField || 'field'} ≈ ${f(p.w / pxMm, 2)} × ${f(p.h / pxMm, 2)} mm`;
|
||||
return text;
|
||||
},
|
||||
|
||||
onImage(ev) {
|
||||
const f = ev.target.files && ev.target.files[0];
|
||||
if (f) this._setImage(f);
|
||||
|
||||
Reference in New Issue
Block a user