From 3506d6164d721425600e3973c5c7f6f8b7a2f5c7 Mon Sep 17 00:00:00 2001 From: igurielidze Date: Mon, 30 Mar 2026 21:24:49 +0400 Subject: [PATCH] Fix spur/mirrored symbol text: counter-mirror so text stays readable Mirrored symbols need text counter-mirrored (scale -1,1) to prevent backwards text. Restored mirror fix that was incorrectly removed. Applied to both canvas renderer and SVG export. Co-Authored-By: Claude Opus 4.6 (1M context) --- svelte-app/src/lib/canvas/renderer.ts | 4 +++- svelte-app/src/lib/export.ts | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/svelte-app/src/lib/canvas/renderer.ts b/svelte-app/src/lib/canvas/renderer.ts index a49d201..fd28957 100644 --- a/svelte-app/src/lib/canvas/renderer.ts +++ b/svelte-app/src/lib/canvas/renderer.ts @@ -573,7 +573,8 @@ function drawConveyanceLabel(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) { // - Counter-mirror if symbol is mirrored (so text doesn't read backwards) const rot = ((sym.rotation || 0) % 360 + 360) % 360; const needsFlip = rot > 90 && rot < 270; - const hasCorrection = needsFlip; + const needsMirrorFix = !!sym.mirrored; + const hasCorrection = needsFlip || needsMirrorFix; ctx.fillStyle = '#000000'; ctx.textAlign = 'center'; @@ -601,6 +602,7 @@ function drawConveyanceLabel(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) { if (hasCorrection) { ctx.save(); ctx.translate(cx, cy); + if (needsMirrorFix) ctx.scale(-1, 1); if (needsFlip) ctx.rotate(Math.PI); for (let i = 0; i < tryLines.length; i++) { const dy = -(lineCount - 1) * lineH / 2 + i * lineH; diff --git a/svelte-app/src/lib/export.ts b/svelte-app/src/lib/export.ts index bfe6cbe..1413a04 100644 --- a/svelte-app/src/lib/export.ts +++ b/svelte-app/src/lib/export.ts @@ -60,16 +60,21 @@ function emitConveyanceLabelInner(lines: string[], sym: PlacedSymbol) { } // For non-curved: check readability and flip if needed + let needsMirrorFix = false; if (!isCurvedType(sym.symbolId)) { const rot = ((sym.rotation || 0) % 360 + 360) % 360; if (rot > 90 && rot < 270) textRotDeg = 180; - // Mirror: label follows mirrored shape naturally (inside group) + needsMirrorFix = !!sym.mirrored; } const fontSize = Math.min(14, availH / textLines.length); if (fontSize < 4) return; const lineH = fontSize; - const rotAttr = textRotDeg ? ` transform="rotate(${textRotDeg.toFixed(1)},${labelCx},${labelCy})"` : ''; + // Build transform: counter-mirror then rotate for readability + let transformParts: string[] = []; + if (needsMirrorFix) transformParts.push(`translate(${labelCx},${labelCy}) scale(-1,1) translate(${-labelCx},${-labelCy})`); + if (textRotDeg) transformParts.push(`rotate(${textRotDeg.toFixed(1)},${labelCx},${labelCy})`); + const rotAttr = transformParts.length ? ` transform="${transformParts.join(' ')}"` : ''; for (let i = 0; i < textLines.length; i++) { const dy = -(textLines.length - 1) * lineH / 2 + i * lineH; const y = labelCy + dy + fontSize * 0.35;