Fix SVG export: group shape+text, preserve rotation, stroke-width 1px
- Wrap each conveyance shape + its label text in a <g> element so rotation/mirror transforms apply to both shape and text together - Change stroke-width from 0.5 to 1 on all conveyance and PE shapes (both canvas renderer and SVG export) - Text is now inside the group, inheriting the transform — no more floating unrotated labels Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e3a0e422e6
commit
ea367df42a
@ -60,7 +60,7 @@ export const THEME = {
|
||||
induction: {
|
||||
fillColor: '#ffffff',
|
||||
strokeColor: '#000000',
|
||||
lineWidth: 0.5,
|
||||
lineWidth: 1,
|
||||
},
|
||||
canvas: {
|
||||
maxRenderScale: 4,
|
||||
|
||||
@ -438,7 +438,7 @@ function drawPhotoeyeSymbol(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) {
|
||||
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.strokeStyle = '#000000';
|
||||
ctx.lineWidth = 0.5;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
@ -456,7 +456,7 @@ function drawCurvedSymbol(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) {
|
||||
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.strokeStyle = '#000000';
|
||||
ctx.lineWidth = 0.5;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
@ -479,7 +479,7 @@ function drawSymbolBody(ctx: CanvasRenderingContext2D, sym: PlacedSymbol): boole
|
||||
ctx.closePath();
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.strokeStyle = '#000000';
|
||||
ctx.lineWidth = 0.5;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
} else if (isExtendoType(sym.symbolId)) {
|
||||
@ -503,13 +503,13 @@ function drawSymbolBody(ctx: CanvasRenderingContext2D, sym: PlacedSymbol): boole
|
||||
ctx.closePath();
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.strokeStyle = '#000000';
|
||||
ctx.lineWidth = 0.5;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
} else if (isRectConveyanceType(sym.symbolId)) {
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.strokeStyle = '#000000';
|
||||
ctx.lineWidth = 0.5;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.fillRect(sym.x, sym.y, sym.w, sym.h);
|
||||
ctx.strokeRect(sym.x, sym.y, sym.w, sym.h);
|
||||
} else if (isPhotoeyeType(sym.symbolId)) {
|
||||
|
||||
@ -17,8 +17,8 @@ function parseConveyanceLabel(label: string): { lines: string[]; stripped: strin
|
||||
return { lines: [core], stripped: [core] };
|
||||
}
|
||||
|
||||
/** Emit conveyance label text — absolute coordinates, no transforms (Ignition compatible) */
|
||||
function emitConveyanceLabel(lines: string[], sym: PlacedSymbol, _outerTransform: string) {
|
||||
/** Emit conveyance label text inside a <g> — no transform needed (inherits from group) */
|
||||
function emitConveyanceLabelInner(lines: string[], sym: PlacedSymbol) {
|
||||
if (!sym.label) return;
|
||||
const { lines: textLines } = parseConveyanceLabel(sym.label);
|
||||
|
||||
@ -134,8 +134,10 @@ export async function exportSVG() {
|
||||
const stripBottomY = sym.y + sym.h * INDUCTION_CONFIG.stripBottomFrac;
|
||||
const pts = INDUCTION_CONFIG.arrowPoints.map(([xf, yf]) => [sym.x + xf * hw, sym.y + yf * sym.h] as const);
|
||||
const d = `M ${sym.x + sym.w},${stripTopY} L ${pts[0][0]},${stripTopY} ${pts.map(([px, py]) => `L ${px},${py}`).join(' ')} L ${pts[5][0]},${stripBottomY} L ${sym.x + sym.w},${stripBottomY} Z`;
|
||||
lines.push(` <path ${idAttr} d="${d}" fill="#ffffff" stroke="#000000" stroke-width="0.5"${outerTransform ? ` transform="${outerTransform}"` : ''} />`);
|
||||
emitConveyanceLabel(lines, sym as PlacedSymbol, outerTransform);
|
||||
lines.push(` <g ${idAttr}${outerTransform ? ` transform="${outerTransform}"` : ''}>`);
|
||||
lines.push(` <path d="${d}" fill="#ffffff" stroke="#000000" stroke-width="1" />`);
|
||||
emitConveyanceLabelInner(lines, sym as PlacedSymbol);
|
||||
lines.push(` </g>`);
|
||||
} else if (isCurvedType(sym.symbolId)) {
|
||||
const angle = sym.curveAngle || 90;
|
||||
const { arcCx, arcCy, outerR, innerR } = getCurveGeometry(sym.symbolId, sym.x, sym.y, sym.w, sym.h);
|
||||
@ -152,16 +154,22 @@ export async function exportSVG() {
|
||||
`A ${innerR},${innerR} 0 ${largeArc},1 ${arcCx + innerR},${arcCy}`,
|
||||
'Z',
|
||||
].join(' ');
|
||||
lines.push(` <path ${idAttr} d="${d}" fill="#ffffff" stroke="#000000" stroke-width="0.5"${outerTransform ? ` transform="${outerTransform}"` : ''} />`);
|
||||
emitConveyanceLabel(lines, sym as PlacedSymbol, outerTransform);
|
||||
lines.push(` <g ${idAttr}${outerTransform ? ` transform="${outerTransform}"` : ''}>`);
|
||||
lines.push(` <path d="${d}" fill="#ffffff" stroke="#000000" stroke-width="1" />`);
|
||||
emitConveyanceLabelInner(lines, sym as PlacedSymbol);
|
||||
lines.push(` </g>`);
|
||||
} else if (isSpurType(sym.symbolId)) {
|
||||
const w2 = sym.w2 ?? sym.w;
|
||||
const d = `M ${sym.x},${sym.y} L ${sym.x + w2},${sym.y} L ${sym.x + sym.w},${sym.y + sym.h} L ${sym.x},${sym.y + sym.h} Z`;
|
||||
lines.push(` <path ${idAttr} d="${d}" fill="#ffffff" stroke="#000000" stroke-width="0.5"${outerTransform ? ` transform="${outerTransform}"` : ''} />`);
|
||||
emitConveyanceLabel(lines, sym as PlacedSymbol, outerTransform);
|
||||
lines.push(` <g ${idAttr}${outerTransform ? ` transform="${outerTransform}"` : ''}>`);
|
||||
lines.push(` <path d="${d}" fill="#ffffff" stroke="#000000" stroke-width="1" />`);
|
||||
emitConveyanceLabelInner(lines, sym as PlacedSymbol);
|
||||
lines.push(` </g>`);
|
||||
} else if (isRectConveyanceType(sym.symbolId)) {
|
||||
lines.push(` <rect ${idAttr} x="${sym.x}" y="${sym.y}" width="${sym.w}" height="${sym.h}" fill="#ffffff" stroke="#000000" stroke-width="0.5"${outerTransform ? ` transform="${outerTransform}"` : ''} />`);
|
||||
emitConveyanceLabel(lines, sym as PlacedSymbol, outerTransform);
|
||||
lines.push(` <g ${idAttr}${outerTransform ? ` transform="${outerTransform}"` : ''}>`);
|
||||
lines.push(` <rect x="${sym.x}" y="${sym.y}" width="${sym.w}" height="${sym.h}" fill="#ffffff" stroke="#000000" stroke-width="1" />`);
|
||||
emitConveyanceLabelInner(lines, sym as PlacedSymbol);
|
||||
lines.push(` </g>`);
|
||||
} else if (isExtendoType(sym.symbolId)) {
|
||||
const bracketW = 10.6 / 31.07 * 73;
|
||||
const x = sym.x, y = sym.y, w = sym.w, h = sym.h;
|
||||
@ -180,8 +188,10 @@ export async function exportSVG() {
|
||||
[x + bracketW * 0.34, y + h * 0.016],
|
||||
];
|
||||
const d = `M ${pts[0][0]},${pts[0][1]} ` + pts.slice(1).map(p => `L ${p[0]},${p[1]}`).join(' ') + ' Z';
|
||||
lines.push(` <path ${idAttr} d="${d}" fill="#ffffff" stroke="#000000" stroke-width="0.5"${outerTransform ? ` transform="${outerTransform}"` : ''} />`);
|
||||
emitConveyanceLabel(lines, sym as PlacedSymbol, outerTransform);
|
||||
lines.push(` <g ${idAttr}${outerTransform ? ` transform="${outerTransform}"` : ''}>`);
|
||||
lines.push(` <path d="${d}" fill="#ffffff" stroke="#000000" stroke-width="1" />`);
|
||||
emitConveyanceLabelInner(lines, sym as PlacedSymbol);
|
||||
lines.push(` </g>`);
|
||||
} else if (isPhotoeyeType(sym.symbolId)) {
|
||||
const { leftCap, rightCap } = PHOTOEYE_CONFIG;
|
||||
const x = sym.x, y = sym.y, w = sym.w, h = sym.h;
|
||||
@ -200,7 +210,7 @@ export async function exportSVG() {
|
||||
[x + w - rightCap, y + h * 0.42],
|
||||
];
|
||||
const d = `M ${pts[0][0]},${pts[0][1]} ` + pts.slice(1).map(p => `L ${p[0]},${p[1]}`).join(' ') + ' Z';
|
||||
lines.push(` <path ${idAttr} d="${d}" fill="#ffffff" stroke="#000000" stroke-width="0.5"${outerTransform ? ` transform="${outerTransform}"` : ''} />`);
|
||||
lines.push(` <path ${idAttr} d="${d}" fill="#ffffff" stroke="#000000" stroke-width="1"${outerTransform ? ` transform="${outerTransform}"` : ''} />`);
|
||||
} else {
|
||||
// Regular SVG symbol
|
||||
try {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user