diff --git a/svelte-app/src/lib/canvas/interactions.ts b/svelte-app/src/lib/canvas/interactions.ts index 25f5f2d..d652a3e 100644 --- a/svelte-app/src/lib/canvas/interactions.ts +++ b/svelte-app/src/lib/canvas/interactions.ts @@ -100,12 +100,30 @@ function hitTest(cx: number, cy: number): number | null { return hitTestSymbols(cx, cy, layout.symbols); } +/** Get the conveyance family for a symbol ID. + * Conveyor family: conveyor, spur, curved_conv, induction, extendo + * Chute family: chute, tipper, curved_chute */ +function getConveyanceFamily(symbolId: string): string | null { + if (symbolId.startsWith('conveyor') || symbolId.startsWith('spur') || + symbolId.startsWith('curved_conv') || symbolId.startsWith('induction') || + symbolId.startsWith('extendo')) return 'conveyor'; + if (symbolId.startsWith('chute') || symbolId.startsWith('tipper') || + symbolId.startsWith('curved_chute')) return 'chute'; + return null; +} + /** Check if a device type (symbolDef) is compatible with a placed symbol for label assignment. - * Matches by SVG file so base and _v variants are treated as the same type. */ + * Matches by conveyance family so conveyor devices can drop on spurs/curves too. */ function isTypeCompatible(symbolDef: (typeof SYMBOLS)[number], placedSymbolId: string): boolean { const placedDef = SYMBOLS.find(s => s.id === placedSymbolId); if (!placedDef) return false; - return symbolDef.file === placedDef.file; + // Same SVG file (base + _v variants) + if (symbolDef.file === placedDef.file) return true; + // Same conveyance family + const dragFamily = getConveyanceFamily(symbolDef.id); + const targetFamily = getConveyanceFamily(placedSymbolId); + if (dragFamily && dragFamily === targetFamily) return true; + return false; } function onCanvasMousedown(e: MouseEvent) {