File
Blob: worker/src/client/exhibit/diagram/wire-layout.ts
| 1 | import { BRANCHES } from './diagram-model.ts'; |
| 2 | import type { Branch } from './diagram-model.ts'; |
| 3 | |
| 4 | export type Point = { x: number; y: number }; |
| 5 | export type BranchPoints = { source: Point; relayIn: Point; relayOut: Point; receiver: Point }; |
| 6 | export type Wire = { branch: Branch | 'wifi'; segment: 'source' | 'receiver'; d: string }; |
| 7 | export type WireLayout = |
| 8 | | { mode: 'desktop'; branches: Record<Branch, BranchPoints> } |
| 9 | | { mode: 'mobile'; source: Point; relay: Point; boardBottom: number }; |
| 10 | |
| 11 | /** Coordinates are relative to the diagram's inner border, independent of DOM measurement. */ |
| 12 | export function layoutWires(layout: WireLayout): Wire[] { |
| 13 | if (layout.mode === 'mobile') { |
| 14 | const { source, relay, boardBottom } = layout; |
| 15 | const gutter = source.x + 10, |
| 16 | lane = boardBottom + 18, |
| 17 | radius = 6; |
| 18 | // Route through the gap beside the PCB, then below the core labels. |
| 19 | return [ |
| 20 | { |
| 21 | branch: 'wifi', |
| 22 | segment: 'source', |
| 23 | d: `M ${source.x} ${source.y} H ${gutter - radius} Q ${gutter} ${source.y} ${gutter} ${source.y + radius} V ${lane - radius} Q ${gutter} ${lane} ${gutter + radius} ${lane} H ${relay.x - radius} Q ${relay.x} ${lane} ${relay.x} ${lane + radius} V ${relay.y}`, |
| 24 | }, |
| 25 | ]; |
| 26 | } |
| 27 | const curve = (a: Point, b: Point) => { |
| 28 | const midpoint = (a.x + b.x) / 2; |
| 29 | return `M ${a.x} ${a.y} C ${midpoint} ${a.y}, ${midpoint} ${b.y}, ${b.x} ${b.y}`; |
| 30 | }; |
| 31 | return BRANCHES.flatMap((branch): Wire[] => { |
| 32 | const points = layout.branches[branch]; |
| 33 | return [ |
| 34 | { branch, segment: 'source', d: curve(points.source, points.relayIn) }, |
| 35 | { branch, segment: 'receiver', d: curve(points.relayOut, points.receiver) }, |
| 36 | ]; |
| 37 | }); |
| 38 | } |