Pannello visione: integrazione overlay ed etichette quota (rows, drawOverlay, overlayLabels)

Refs #116

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-28 17:00:48 +01:00
parent 88b3f202b1
commit acd94a9d33
4 changed files with 101 additions and 1 deletions
@@ -261,6 +261,10 @@ function visionExecute() {
return ((this.result && this.result.measurements) || []).map((m) => {
const st = subs.find((s) => s.id === m.subtask_id) || {};
return {
// #116: chiave stabile della quota, nome senza numero di marker e uscita ricetta, per le etichette sull'immagine
key: m.subtask_id,
name: st.description || st.measurement_type || '#' + m.subtask_id,
vision_output: st.vision_output,
// #114: il nome della quota e' description (prima: measurement_type/name, che per le quote DXF e' vuoto -> '#15')
label: (st.marker_number ? st.marker_number + '. ' : '') + (st.description || st.measurement_type || '#' + m.subtask_id),
value: m.value,
@@ -384,6 +388,30 @@ function visionExecute() {
// #117: tolleranza a 3 decimali, trattino se manca (come x-text="...?.toFixed(3) || '—'" dei calibri, ma 0 resta 0.000)
fmtTol(v) { return v == null ? '\u2014' : Number(v).toFixed(3); },
// #116: etichette «nome valore unita» agganciate alla geometria dello strumento; posizione in % delle
// dimensioni naturali dell'immagine, cosi' seguono lo zoom (#115) senza ingrandirsi
get overlayLabels() {
if (typeof VisionOverlay === 'undefined' || !this.result) return [];
const img = this.$refs && this.$refs.img;
const w = this.z.w || (img && img.naturalWidth) || 0;
const h = this.z.h || (img && img.naturalHeight) || 0;
if (!w || !h) return [];
return VisionOverlay.labels(this.rows, this.result.overlay || []).map((l) => ({
key: l.key,
text: l.text,
cls: this.labelClass(l.status),
style: 'left:' + (l.x / w * 100) + '%;top:' + (l.y / h * 100) + '%;transform:translate(8px,-50%)',
}));
},
// #116: colori dell'etichetta per esito
labelClass(s) {
if (s === 'pass') return 'bg-green-600 text-white';
if (s === 'warning') return 'bg-amber-400 text-black';
if (s === 'fail') return 'bg-red-600 text-white';
return 'bg-gray-700 text-white';
},
statusClass(s) {
// Same palette as the measurement markers of the manual flow.
if (s === 'pass') return 'bg-measure-pass/20 text-measure-pass border border-measure-pass/40';
@@ -401,8 +429,14 @@ function visionExecute() {
cv.height = img.naturalHeight;
const g = cv.getContext('2d');
g.clearRect(0, 0, cv.width, cv.height);
g.lineWidth = Math.max(2, cv.width / 400);
const lw = Math.max(2, cv.width / 400);
g.lineWidth = lw;
g.lineJoin = 'round';
// #116: tutte le forme (rect2, segment, circle, arc...) le disegna vision_overlay.js; il ciclo sotto resta come ripiego
if (typeof VisionOverlay !== 'undefined') {
VisionOverlay.draw(g, (this.result && this.result.overlay) || [], lw);
return;
}
for (const item of ((this.result && this.result.overlay) || [])) {
const rows = item.rows || [], cols = item.cols || [];
if (!rows.length || rows.length !== cols.length) continue;