merge #101 101b: anteprima DXF disegnata con path (Refs #101)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jbf7qKuxsnAVjxthRy7dnB
This commit is contained in:
2026-10-25 16:06:54 +01:00
4 changed files with 19 additions and 7 deletions
@@ -128,6 +128,13 @@ function dxfRecipeWizard(taskId, csrf, msgs) {
return contorni.filter(c => c && c.length > 1).map(c => c.map(p => p[0] + ',' + p[1]).join(' '));
},
// #101: tutti i contorni in un solo attributo `d` ("M x y L x y ..."): x-for non funziona dentro <svg>
dxfPreviewD() {
const contorni = (this.dxfPreview && this.dxfPreview.contorni) || [];
return contorni.filter(c => c && c.length > 1)
.map(c => c.map((p, i) => (i ? 'L ' : 'M ') + p[0] + ' ' + p[1]).join(' ')).join(' ');
},
// #101: viewBox sul bbox con margine 5% (minimo 0.5 mm per lato)
dxfPreviewViewBox() {
const b = this.dxfPreview && this.dxfPreview.bbox;
@@ -718,14 +718,13 @@
<p x-show="dxfPreviewBusy" class="mt-1 text-xs text-[var(--text-muted)]">{{ _('Lettura DXF…') }}</p>
<p x-show="dxfPreviewError" class="mt-1 text-xs text-red-500" x-text="dxfPreviewError"></p>
<div x-show="dxfPreview" class="mt-2">
<svg :viewBox="dxfPreviewViewBox()" preserveAspectRatio="xMidYMid meet"
<svg x-bind:view-box.camel="dxfPreviewViewBox()" preserveAspectRatio="xMidYMid meet"
class="block w-full rounded border border-[var(--border-color)]"
style="max-height: 240px; background: var(--bg-primary);">
<template x-for="(pts, i) in dxfPreviewPaths()" :key="i">
<polyline :points="pts" fill="none" stroke="var(--color-primary, #2563eb)"
<!-- #101: un solo path (x-for/template non funziona nel namespace SVG); view-box.camel perche' il parser HTML abbassa viewBox -->
<path :d="dxfPreviewD()" fill="none" stroke="var(--color-primary, #2563eb)"
stroke-width="1.5" vector-effect="non-scaling-stroke"
stroke-linejoin="round"></polyline>
</template>
stroke-linejoin="round"></path>
</svg>
<p class="mt-1 text-xs text-[var(--text-muted)]" x-text="dxfPreviewSummary"></p>
</div>
@@ -38,6 +38,12 @@ const PREVIEW = {
check('un contorno con >1 punti diventa una polyline (quello da 1 punto no)', paths.length === 1);
check('formato points', paths[0] === '0,-5 12.3,-5 12.3,0 0,0 0,-5', paths[0]);
// #101: path unico per <path :d>
check('dxfPreviewD', w.dxfPreviewD() === 'M 0 -5 L 12.3 -5 L 12.3 0 L 0 0 L 0 -5', w.dxfPreviewD());
w.dxfPreview = null;
check('dxfPreviewD vuoto senza anteprima', w.dxfPreviewD() === '');
w.dxfPreview = PREVIEW;
const vb = w.dxfPreviewViewBox().split(' ').map(Number);
const m = Math.max(0.5, 0.05 * 12.3);
check('viewBox con margine 5%', Math.abs(vb[0] + m) < 1e-3 && Math.abs(vb[2] - (12.3 + 2 * m)) < 1e-3, vb.join(' '));
@@ -279,5 +279,5 @@ class TestPages:
assert "dxfRecipeWizard(" in html
assert "@dxf-recipe-saved" in html
assert 'x-model="mmPx"' in html # #98: campo mm/px a mano
assert "dxfPreviewPaths()" in html # #101: anteprima SVG del DXF
assert "dxfPreviewD()" in html and "view-box.camel" in html # #101: anteprima SVG del DXF
assert "Pezzo scuro su fondo chiaro" in html or "Dark part on light" in html