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: {
|
induction: {
|
||||||
fillColor: '#ffffff',
|
fillColor: '#ffffff',
|
||||||
strokeColor: '#000000',
|
strokeColor: '#000000',
|
||||||
lineWidth: 0.5,
|
lineWidth: 1,
|
||||||
},
|
},
|
||||||
canvas: {
|
canvas: {
|
||||||
maxRenderScale: 4,
|
maxRenderScale: 4,
|
||||||
|
|||||||
@ -438,7 +438,7 @@ function drawPhotoeyeSymbol(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) {
|
|||||||
|
|
||||||
ctx.fillStyle = '#ffffff';
|
ctx.fillStyle = '#ffffff';
|
||||||
ctx.strokeStyle = '#000000';
|
ctx.strokeStyle = '#000000';
|
||||||
ctx.lineWidth = 0.5;
|
ctx.lineWidth = 1;
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
@ -456,7 +456,7 @@ function drawCurvedSymbol(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) {
|
|||||||
|
|
||||||
ctx.fillStyle = '#ffffff';
|
ctx.fillStyle = '#ffffff';
|
||||||
ctx.strokeStyle = '#000000';
|
ctx.strokeStyle = '#000000';
|
||||||
ctx.lineWidth = 0.5;
|
ctx.lineWidth = 1;
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
@ -479,7 +479,7 @@ function drawSymbolBody(ctx: CanvasRenderingContext2D, sym: PlacedSymbol): boole
|
|||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fillStyle = '#ffffff';
|
ctx.fillStyle = '#ffffff';
|
||||||
ctx.strokeStyle = '#000000';
|
ctx.strokeStyle = '#000000';
|
||||||
ctx.lineWidth = 0.5;
|
ctx.lineWidth = 1;
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
} else if (isExtendoType(sym.symbolId)) {
|
} else if (isExtendoType(sym.symbolId)) {
|
||||||
@ -503,13 +503,13 @@ function drawSymbolBody(ctx: CanvasRenderingContext2D, sym: PlacedSymbol): boole
|
|||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fillStyle = '#ffffff';
|
ctx.fillStyle = '#ffffff';
|
||||||
ctx.strokeStyle = '#000000';
|
ctx.strokeStyle = '#000000';
|
||||||
ctx.lineWidth = 0.5;
|
ctx.lineWidth = 1;
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
} else if (isRectConveyanceType(sym.symbolId)) {
|
} else if (isRectConveyanceType(sym.symbolId)) {
|
||||||
ctx.fillStyle = '#ffffff';
|
ctx.fillStyle = '#ffffff';
|
||||||
ctx.strokeStyle = '#000000';
|
ctx.strokeStyle = '#000000';
|
||||||
ctx.lineWidth = 0.5;
|
ctx.lineWidth = 1;
|
||||||
ctx.fillRect(sym.x, sym.y, sym.w, sym.h);
|
ctx.fillRect(sym.x, sym.y, sym.w, sym.h);
|
||||||
ctx.strokeRect(sym.x, sym.y, sym.w, sym.h);
|
ctx.strokeRect(sym.x, sym.y, sym.w, sym.h);
|
||||||
} else if (isPhotoeyeType(sym.symbolId)) {
|
} else if (isPhotoeyeType(sym.symbolId)) {
|
||||||
|
|||||||
@ -17,8 +17,8 @@ function parseConveyanceLabel(label: string): { lines: string[]; stripped: strin
|
|||||||
return { lines: [core], stripped: [core] };
|
return { lines: [core], stripped: [core] };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Emit conveyance label text — absolute coordinates, no transforms (Ignition compatible) */
|
/** Emit conveyance label text inside a <g> — no transform needed (inherits from group) */
|
||||||
function emitConveyanceLabel(lines: string[], sym: PlacedSymbol, _outerTransform: string) {
|
function emitConveyanceLabelInner(lines: string[], sym: PlacedSymbol) {
|
||||||
if (!sym.label) return;
|
if (!sym.label) return;
|
||||||
const { lines: textLines } = parseConveyanceLabel(sym.label);
|
const { lines: textLines } = parseConveyanceLabel(sym.label);
|
||||||
|
|
||||||
@ -134,8 +134,10 @@ export async function exportSVG() {
|
|||||||
const stripBottomY = sym.y + sym.h * INDUCTION_CONFIG.stripBottomFrac;
|
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 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`;
|
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}"` : ''} />`);
|
lines.push(` <g ${idAttr}${outerTransform ? ` transform="${outerTransform}"` : ''}>`);
|
||||||
emitConveyanceLabel(lines, sym as PlacedSymbol, 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)) {
|
} else if (isCurvedType(sym.symbolId)) {
|
||||||
const angle = sym.curveAngle || 90;
|
const angle = sym.curveAngle || 90;
|
||||||
const { arcCx, arcCy, outerR, innerR } = getCurveGeometry(sym.symbolId, sym.x, sym.y, sym.w, sym.h);
|
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}`,
|
`A ${innerR},${innerR} 0 ${largeArc},1 ${arcCx + innerR},${arcCy}`,
|
||||||
'Z',
|
'Z',
|
||||||
].join(' ');
|
].join(' ');
|
||||||
lines.push(` <path ${idAttr} d="${d}" fill="#ffffff" stroke="#000000" stroke-width="0.5"${outerTransform ? ` transform="${outerTransform}"` : ''} />`);
|
lines.push(` <g ${idAttr}${outerTransform ? ` transform="${outerTransform}"` : ''}>`);
|
||||||
emitConveyanceLabel(lines, sym as PlacedSymbol, 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)) {
|
} else if (isSpurType(sym.symbolId)) {
|
||||||
const w2 = sym.w2 ?? sym.w;
|
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`;
|
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}"` : ''} />`);
|
lines.push(` <g ${idAttr}${outerTransform ? ` transform="${outerTransform}"` : ''}>`);
|
||||||
emitConveyanceLabel(lines, sym as PlacedSymbol, 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)) {
|
} 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}"` : ''} />`);
|
lines.push(` <g ${idAttr}${outerTransform ? ` transform="${outerTransform}"` : ''}>`);
|
||||||
emitConveyanceLabel(lines, sym as PlacedSymbol, 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)) {
|
} else if (isExtendoType(sym.symbolId)) {
|
||||||
const bracketW = 10.6 / 31.07 * 73;
|
const bracketW = 10.6 / 31.07 * 73;
|
||||||
const x = sym.x, y = sym.y, w = sym.w, h = sym.h;
|
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],
|
[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';
|
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(` <g ${idAttr}${outerTransform ? ` transform="${outerTransform}"` : ''}>`);
|
||||||
emitConveyanceLabel(lines, sym as PlacedSymbol, 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)) {
|
} else if (isPhotoeyeType(sym.symbolId)) {
|
||||||
const { leftCap, rightCap } = PHOTOEYE_CONFIG;
|
const { leftCap, rightCap } = PHOTOEYE_CONFIG;
|
||||||
const x = sym.x, y = sym.y, w = sym.w, h = sym.h;
|
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],
|
[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';
|
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 {
|
} else {
|
||||||
// Regular SVG symbol
|
// Regular SVG symbol
|
||||||
try {
|
try {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user