diff --git a/svelte-app/src/lib/canvas/render-theme.ts b/svelte-app/src/lib/canvas/render-theme.ts
index 4451668..c56788b 100644
--- a/svelte-app/src/lib/canvas/render-theme.ts
+++ b/svelte-app/src/lib/canvas/render-theme.ts
@@ -58,7 +58,9 @@ export const THEME = {
rightBoxStrokeWidth: 1.5,
},
induction: {
- fillColor: '#000000',
+ fillColor: '#ffffff',
+ strokeColor: '#000000',
+ lineWidth: 0.5,
},
canvas: {
maxRenderScale: 4,
diff --git a/svelte-app/src/lib/canvas/renderer.ts b/svelte-app/src/lib/canvas/renderer.ts
index d5ddfdd..83c9a03 100644
--- a/svelte-app/src/lib/canvas/renderer.ts
+++ b/svelte-app/src/lib/canvas/renderer.ts
@@ -186,7 +186,6 @@ function drawEpcSymbol(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) {
ctx.fillStyle = THEME.epcBody.rightBoxFill;
ctx.strokeStyle = THEME.epcBody.rightBoxStroke;
ctx.lineWidth = THEME.epcBody.rightBoxStrokeWidth;
- ctx.rotate(-Math.PI / 2);
ctx.fillRect(-rb.w, -rb.h / 2, rb.w, rb.h);
ctx.strokeRect(-rb.w, -rb.h / 2, rb.w, rb.h);
ctx.restore();
@@ -269,7 +268,7 @@ function traceEpcOutlinePath(ctx: CanvasRenderingContext2D, sym: PlacedSymbol, p
ctx.save();
ctx.translate(plx, ply);
- ctx.rotate(rAngle - Math.PI / 2);
+ ctx.rotate(rAngle);
ctx.beginPath();
ctx.rect(-rb.w - pad, -rb.h / 2 - pad, rb.w + pad * 2, rb.h + pad * 2);
ctx.stroke();
@@ -376,26 +375,47 @@ function drawInductionSymbol(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) {
ctx.closePath();
ctx.fillStyle = THEME.induction.fillColor;
+ ctx.strokeStyle = THEME.induction.strokeColor;
+ ctx.lineWidth = THEME.induction.lineWidth;
ctx.fill();
+ ctx.stroke();
}
-/** Draw photoeye with 3-slice: fixed left cap, stretched middle beam, fixed right cap */
-function drawPhotoeye3Slice(ctx: CanvasRenderingContext2D, sym: PlacedSymbol, img: HTMLImageElement) {
- const { leftCap, rightCap, defaultWidth } = PHOTOEYE_CONFIG;
- const srcW = img.naturalWidth;
- const srcH = img.naturalHeight;
- const scale = srcW / defaultWidth;
- const srcLeftW = leftCap * scale;
- const srcRightW = rightCap * scale;
- const srcMiddleW = srcW - srcLeftW - srcRightW;
- const dstMiddleW = sym.w - leftCap - rightCap;
+/** Draw photoeye programmatically for consistent stroke at any size */
+function drawPhotoeyeSymbol(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) {
+ const { leftCap, rightCap } = PHOTOEYE_CONFIG;
+ const x = sym.x, y = sym.y, w = sym.w, h = sym.h;
- // Left cap (fixed)
- ctx.drawImage(img, 0, 0, srcLeftW, srcH, sym.x, sym.y, leftCap, sym.h);
- // Middle beam (stretched)
- ctx.drawImage(img, srcLeftW, 0, srcMiddleW, srcH, sym.x + leftCap, sym.y, dstMiddleW, sym.h);
- // Right cap (fixed)
- ctx.drawImage(img, srcW - srcRightW, 0, srcRightW, srcH, sym.x + sym.w - rightCap, sym.y, rightCap, sym.h);
+ // Y positions as fractions of height (derived from original SVG path)
+ const beamTop = y + h * 0.42;
+ const beamBottom = y + h * 0.585;
+ const arrowInnerTop = y + h * 0.248;
+ const arrowInnerBottom = y + h * 0.744;
+ const recvTop = y + h * 0.181;
+ const recvBottom = y + h * 0.826;
+ const arrowTipTop = y + h * 0.05;
+ const arrowTipBottom = y + h * 0.948;
+
+ ctx.beginPath();
+ ctx.moveTo(x + leftCap, beamTop);
+ ctx.lineTo(x + leftCap, arrowInnerTop);
+ ctx.lineTo(x, arrowTipTop);
+ ctx.lineTo(x, arrowTipBottom);
+ ctx.lineTo(x + leftCap, arrowInnerBottom);
+ ctx.lineTo(x + leftCap, beamBottom);
+ ctx.lineTo(x + w - rightCap, beamBottom);
+ ctx.lineTo(x + w - rightCap, recvBottom);
+ ctx.lineTo(x + w, recvBottom);
+ ctx.lineTo(x + w, recvTop);
+ ctx.lineTo(x + w - rightCap, recvTop);
+ ctx.lineTo(x + w - rightCap, beamTop);
+ ctx.closePath();
+
+ ctx.fillStyle = '#ffffff';
+ ctx.strokeStyle = '#000000';
+ ctx.lineWidth = 0.5;
+ ctx.fill();
+ ctx.stroke();
}
/** Draw curved conveyor/chute programmatically with fixed band width */
@@ -409,7 +429,7 @@ function drawCurvedSymbol(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) {
ctx.arc(arcCx, arcCy, innerR, -sweepRad, 0, false);
ctx.closePath();
- ctx.fillStyle = '#000000';
+ ctx.fillStyle = '#ffffff';
ctx.strokeStyle = '#000000';
ctx.lineWidth = 0.5;
ctx.fill();
@@ -432,19 +452,17 @@ function drawSymbolBody(ctx: CanvasRenderingContext2D, sym: PlacedSymbol): boole
ctx.lineTo(sym.x + sym.w, sym.y + sym.h);
ctx.lineTo(sym.x, sym.y + sym.h);
ctx.closePath();
- ctx.fillStyle = '#000000';
+ ctx.fillStyle = '#ffffff';
ctx.strokeStyle = '#000000';
ctx.lineWidth = 0.5;
ctx.fill();
ctx.stroke();
+ } else if (isPhotoeyeType(sym.symbolId)) {
+ drawPhotoeyeSymbol(ctx, sym);
} else {
const img = getSymbolImage(sym.file);
if (!img) return false;
- if (isPhotoeyeType(sym.symbolId)) {
- drawPhotoeye3Slice(ctx, sym, img);
- } else {
- ctx.drawImage(img, sym.x, sym.y, sym.w, sym.h);
- }
+ ctx.drawImage(img, sym.x, sym.y, sym.w, sym.h);
}
return true;
}
diff --git a/svelte-app/src/lib/export.ts b/svelte-app/src/lib/export.ts
index b632879..bda235e 100644
--- a/svelte-app/src/lib/export.ts
+++ b/svelte-app/src/lib/export.ts
@@ -52,7 +52,7 @@ 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(` `);
+ lines.push(` `);
} 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);
@@ -69,11 +69,11 @@ export async function exportSVG() {
`A ${innerR},${innerR} 0 ${largeArc},1 ${arcCx + innerR},${arcCy}`,
'Z',
].join(' ');
- lines.push(` `);
+ lines.push(` `);
} 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(` `);
+ lines.push(` `);
} else {
// Regular SVG symbol
try {
diff --git a/svelte-app/src/lib/symbols.ts b/svelte-app/src/lib/symbols.ts
index fc7bda6..9580494 100644
--- a/svelte-app/src/lib/symbols.ts
+++ b/svelte-app/src/lib/symbols.ts
@@ -36,8 +36,8 @@ export const SYMBOLS: SymbolDef[] = [
{ id: 'fio_sio_fioh_v', name: 'FIO/SIO/FIOH (V)', file: '/symbols/fio_sio_fioh.svg', w: 14, h: 20, defaultRotation: 90, group: 'I/O Modules' },
// --- Sensors ---
- { id: 'photoeye', name: 'Photoeye', file: '/symbols/photoeye.svg', w: 56, h: 20, group: 'Sensors' },
- { id: 'photoeye_v', name: 'Photoeye (V)', file: '/symbols/photoeye.svg', w: 56, h: 20, defaultRotation: 90, group: 'Sensors' },
+ { id: 'photoeye', name: 'Photoeye', file: '/symbols/photoeye.svg', w: 30, h: 14, group: 'Sensors' },
+ { id: 'photoeye_v', name: 'Photoeye (V)', file: '/symbols/photoeye.svg', w: 30, h: 14, defaultRotation: 90, group: 'Sensors' },
{ id: 'pressure_sensor', name: 'Pressure Sensor', file: '/symbols/pressure_sensor.svg', w: 20, h: 20, group: 'Sensors' },
{ id: 'pressure_sensor_v', name: 'Pressure Sensor (V)', file: '/symbols/pressure_sensor.svg', w: 20, h: 20, defaultRotation: 90, group: 'Sensors' },
diff --git a/svelte-app/static/symbols/chute.svg b/svelte-app/static/symbols/chute.svg
index 96117c4..a621872 100644
Binary files a/svelte-app/static/symbols/chute.svg and b/svelte-app/static/symbols/chute.svg differ
diff --git a/svelte-app/static/symbols/conveyor.svg b/svelte-app/static/symbols/conveyor.svg
index 9c8e36b..0f87887 100644
Binary files a/svelte-app/static/symbols/conveyor.svg and b/svelte-app/static/symbols/conveyor.svg differ
diff --git a/svelte-app/static/symbols/extendo.svg b/svelte-app/static/symbols/extendo.svg
index a2b79ff..f6ce139 100644
Binary files a/svelte-app/static/symbols/extendo.svg and b/svelte-app/static/symbols/extendo.svg differ
diff --git a/svelte-app/static/symbols/induction.svg b/svelte-app/static/symbols/induction.svg
index ffbb691..8660372 100644
Binary files a/svelte-app/static/symbols/induction.svg and b/svelte-app/static/symbols/induction.svg differ
diff --git a/svelte-app/static/symbols/spur.svg b/svelte-app/static/symbols/spur.svg
index 48c40b6..4818f09 100644
Binary files a/svelte-app/static/symbols/spur.svg and b/svelte-app/static/symbols/spur.svg differ
diff --git a/svelte-app/static/symbols/tipper.svg b/svelte-app/static/symbols/tipper.svg
index 416b1db..5aee896 100644
Binary files a/svelte-app/static/symbols/tipper.svg and b/svelte-app/static/symbols/tipper.svg differ