Files
SystemSimulationApp/frontend/src/ComponentSymbol.tsx
T

393 lines
10 KiB
TypeScript

import { AmesimPnpl01Symbol } from "./componentSymbols/boundary";
import {
AmesimF000Symbol,
AmesimForcSymbol,
AmesimLmechn1Symbol,
AmesimPnrp17Symbol,
AmesimLstp00aSymbol,
AmesimMecmas21Symbol,
} from "./componentSymbols/mechanical";
import {
AmesimHeliumMediumSymbol,
AmesimIdealAirMediumSymbol,
} from "./componentSymbols/media";
import {
AmesimPn3Node2Symbol,
AmesimP4Node2Symbol,
AmesimPnl0001Symbol,
AmesimPnl0002Symbol,
AmesimPnl0003Symbol,
AmesimPnl00rSymbol,
AmesimPnor001Symbol,
AmesimPnvo001FixedSymbol,
AmesimPnvo001SignalSymbol,
} from "./componentSymbols/pneumatic";
import { SymbolSvg } from "./componentSymbols/primitives";
import { AmesimStep0Symbol, AmesimUd00Symbol } from "./componentSymbols/signals";
import { AmesimPnch012Symbol, AmesimPnch023Symbol } from "./componentSymbols/storage";
import type {
ComponentSymbolParameters,
ComponentSymbolPortAnchors,
ComponentSymbolPresentation,
SymbolDefinition,
} from "./componentSymbols/types";
export type { ComponentSymbolPresentation } from "./componentSymbols/types";
export type ComponentSymbolSurface = "palette" | "canvas";
type ComponentSymbolProps = {
symbol: string;
surface: ComponentSymbolSurface;
className?: string;
parameters?: ComponentSymbolParameters;
};
function CylinderSymbol() {
return (
<SymbolSvg>
<path d="M3 24h7M54 24h7" stroke="currentColor" strokeWidth="2" />
<rect
fill="#dbeafe"
height="26"
rx="11"
stroke="currentColor"
strokeWidth="2"
width="44"
x="10"
y="11"
/>
<path d="M33 12v24M33 24h21" stroke="currentColor" strokeWidth="2" />
</SymbolSvg>
);
}
function TankSymbol() {
return (
<SymbolSvg>
<path d="M2 24h14M32 2v5M32 41v5" stroke="currentColor" strokeWidth="2" />
<path
d="M16 13c0-4 7.2-7 16-7s16 3 16 7v22c0 4-7.2 7-16 7s-16-3-16-7V13Z"
fill="#dcfce7"
stroke="currentColor"
strokeWidth="2"
/>
<path d="M16 13c0 4 7.2 7 16 7s16-3 16-7" stroke="currentColor" strokeWidth="2" />
</SymbolSvg>
);
}
function PipeSymbol() {
return (
<SymbolSvg>
<path d="M2 24h7M55 24h7M9 19h46M9 29h46" stroke="currentColor" strokeWidth="2" />
<path d="M9 17v14M55 17v14" stroke="currentColor" strokeWidth="2" />
</SymbolSvg>
);
}
function OrificeSymbol() {
return (
<SymbolSvg>
<path d="M2 24h18M44 24h18" stroke="currentColor" strokeWidth="2" />
<path
d="m19 9 13 15-13 15V9ZM45 9 32 24l13 15V9Z"
fill="#ffedd5"
stroke="currentColor"
strokeLinejoin="round"
strokeWidth="2"
/>
</SymbolSvg>
);
}
function TeeSymbol() {
return (
<SymbolSvg>
<path
d="M2 24h28M30 24C42 24 44 12 62 12M30 24c12 0 14 12 32 12"
stroke="currentColor"
strokeLinecap="round"
strokeWidth="7"
/>
<path
d="M2 24h28M30 24C42 24 44 12 62 12M30 24c12 0 14 12 32 12"
stroke="#f8fafc"
strokeLinecap="round"
strokeWidth="3"
/>
</SymbolSvg>
);
}
function GenericSymbol() {
return (
<SymbolSvg>
<path d="M2 24h9M53 24h9" stroke="currentColor" strokeWidth="2" />
<rect
fill="#f8fafc"
height="30"
rx="3"
stroke="currentColor"
strokeWidth="2"
width="42"
x="11"
y="9"
/>
<path d="m23 30 18-12M23 18h18v12" stroke="currentColor" strokeWidth="1.5" />
</SymbolSvg>
);
}
function SignalSymbol() {
return (
<SymbolSvg>
<path d="M2 24h8M54 24h8" stroke="currentColor" strokeWidth="2" />
<circle cx="32" cy="24" fill="#f8fafc" r="22" stroke="currentColor" strokeWidth="2" />
<path
d="M16 25c4-13 8-13 12 0s8 13 12 0 6-10 8-4"
stroke="#2563eb"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
/>
</SymbolSvg>
);
}
function JunctionSymbol() {
return (
<SymbolSvg>
<path d="M2 24h60M32 2v44" stroke="currentColor" strokeWidth="2" />
<circle cx="32" cy="24" fill="currentColor" r="5" />
</SymbolSvg>
);
}
const symbolRegistry = {
cylinder: { presentation: "framed", render: CylinderSymbol },
tank: { presentation: "framed", render: TankSymbol },
pipe: { presentation: "framed", render: PipeSymbol },
orifice: { presentation: "framed", render: OrificeSymbol },
tee: { presentation: "framed", render: TeeSymbol },
generic: { presentation: "framed", render: GenericSymbol },
signal: { presentation: "framed", render: SignalSymbol },
junction: { presentation: "framed", render: JunctionSymbol },
amesim_pnpl01: { presentation: "framed", render: AmesimPnpl01Symbol },
amesim_pnch023: { presentation: "framed", render: AmesimPnch023Symbol },
amesim_pnch012: { presentation: "framed", render: AmesimPnch012Symbol },
amesim_pnor001: { presentation: "framed", render: AmesimPnor001Symbol },
amesim_pnvo001_fixed: {
presentation: "framed",
render: AmesimPnvo001FixedSymbol,
},
amesim_pnvo001: {
presentation: "framed",
render: AmesimPnvo001SignalSymbol,
},
amesim_pnl00r: { presentation: "framed", render: AmesimPnl00rSymbol },
amesim_pnl0001: { presentation: "framed", render: AmesimPnl0001Symbol },
amesim_pnl0002: { presentation: "framed", render: AmesimPnl0002Symbol },
amesim_pnl0003: { presentation: "framed", render: AmesimPnl0003Symbol },
amesim_pn3node2: { presentation: "framed", render: AmesimPn3Node2Symbol },
amesim_p4node2: { presentation: "framed", render: AmesimP4Node2Symbol },
amesim_step0: { presentation: "framed", render: AmesimStep0Symbol },
amesim_ud00: { presentation: "framed", render: AmesimUd00Symbol },
amesim_f000: { presentation: "framed", render: AmesimF000Symbol },
amesim_forc: { presentation: "framed", render: AmesimForcSymbol },
amesim_mecmas21: { presentation: "framed", render: AmesimMecmas21Symbol },
amesim_lstp00a: { presentation: "framed", render: AmesimLstp00aSymbol },
amesim_lmechn1: { presentation: "framed", render: AmesimLmechn1Symbol },
amesim_pnrp17: { presentation: "framed", render: AmesimPnrp17Symbol },
amesim_ideal_air_medium: {
presentation: "bare",
render: AmesimIdealAirMediumSymbol,
},
amesim_helium_medium: {
presentation: "bare",
render: AmesimHeliumMediumSymbol,
},
} satisfies Record<string, SymbolDefinition>;
type RegisteredComponentSymbol = keyof typeof symbolRegistry;
const symbolPortAnchors: Partial<
Record<RegisteredComponentSymbol, ComponentSymbolPortAnchors>
> = {
cylinder: {
left: [{ x: 3, y: 24 }],
right: [{ x: 61, y: 24 }],
},
tank: { left: [{ x: 2, y: 24 }] },
pipe: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
orifice: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
tee: {
left: [{ x: 2, y: 24 }],
right: [
{ x: 62, y: 12 },
{ x: 62, y: 36 },
],
},
generic: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
signal: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
junction: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
amesim_pnpl01: { left: [{ x: 2, y: 24 }] },
amesim_pnch023: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
amesim_pnch012: {
left: [
{ x: 2, y: 16 },
{ x: 2, y: 32 },
],
right: [
{ x: 62, y: 16 },
{ x: 62, y: 32 },
],
},
amesim_pnor001: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
amesim_pnvo001_fixed: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
amesim_pnvo001: {
left: [
{ x: 26, y: 46 },
{ x: 2, y: 24 },
],
right: [{ x: 62, y: 24 }],
},
amesim_pnl00r: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
amesim_pnl0001: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
amesim_pnl0002: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
amesim_pnl0003: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
amesim_pn3node2: {
left: [{ x: 3, y: 24 }],
right: [
{ x: 61, y: 12 },
{ x: 61, y: 36 },
],
},
amesim_p4node2: {
left: [{ x: 3, y: 24 }],
right: [
{ x: 61, y: 8 },
{ x: 61, y: 24 },
{ x: 61, y: 40 },
],
},
amesim_step0: { right: [{ x: 60, y: 24 }] },
amesim_ud00: { right: [{ x: 60, y: 24 }] },
amesim_f000: { right: [{ x: 62, y: 24 }] },
amesim_forc: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
amesim_mecmas21: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
amesim_lstp00a: {
left: [{ x: 2, y: 24 }],
right: [{ x: 62, y: 24 }],
},
amesim_lmechn1: {
left: [7, 12, 17, 22, 27, 32, 37, 42].map((y) => ({ x: 5, y })),
right: [{ x: 59, y: 24 }],
},
amesim_pnrp17: {
left: [
{ x: 25.5, y: 48 },
{ x: 2, y: 4.4 },
{ x: 2, y: 24.1 },
],
right: [{ x: 62, y: 4.4 }, { x: 62, y: 24.1 }],
},
};
function isRegisteredComponentSymbol(symbol: string): symbol is RegisteredComponentSymbol {
return Object.prototype.hasOwnProperty.call(symbolRegistry, symbol);
}
export function hasComponentSymbol(symbol: string): boolean {
return isRegisteredComponentSymbol(symbol);
}
export function componentSymbolPresentation(
symbol: string,
): ComponentSymbolPresentation {
return isRegisteredComponentSymbol(symbol)
? symbolRegistry[symbol].presentation
: "framed";
}
export function componentSymbolPortAnchors(
symbol: string,
): ComponentSymbolPortAnchors | undefined {
return isRegisteredComponentSymbol(symbol)
? symbolPortAnchors[symbol]
: undefined;
}
export function ComponentSymbol({
symbol,
surface,
className,
parameters,
}: ComponentSymbolProps) {
const resolvedSymbol: RegisteredComponentSymbol = isRegisteredComponentSymbol(symbol)
? symbol
: "generic";
const definition = symbolRegistry[resolvedSymbol];
const SymbolRenderer = definition.render;
const rootClassName = [
"component-symbol",
`component-symbol-${surface}`,
`component-symbol-${resolvedSymbol}`,
className,
]
.filter(Boolean)
.join(" ");
return (
<span
aria-hidden="true"
className={rootClassName}
data-component-symbol={resolvedSymbol}
data-symbol-presentation={definition.presentation}
>
<SymbolRenderer parameters={parameters} />
</span>
);
}