149 lines
6.7 KiB
TypeScript
149 lines
6.7 KiB
TypeScript
/**
|
||
* PowerElements.ts — Custom Web Components for power-supply parts.
|
||
*
|
||
* Includes:
|
||
* wokwi-reg-7805 / -7812 / -7905 / -lm317 — linear voltage regulators
|
||
* wokwi-battery-9v / -aa / -coin-cell — discrete battery cells
|
||
* wokwi-signal-generator — benchtop AC / DC source
|
||
*
|
||
* Regulator pin layout (72 × 48 px): VIN(0, 24) GND(36, 48) VOUT(72, 24)
|
||
* LM317: VIN(0, 24) ADJ(36, 48) VOUT(72, 24)
|
||
* Battery (48 × 64 px): +(24, 0) −(24, 64)
|
||
* SigGen (80 × 64 px): SIG(80, 32) GND(80, 48)
|
||
*/
|
||
|
||
const FILL = '#eaefea';
|
||
const STROKE = '#2a2a2a';
|
||
const LEAD = '#555555';
|
||
const LABEL = '#333333';
|
||
const RED = '#b03a2e';
|
||
const BLACK = '#1a1a1a';
|
||
const STYLE = ':host{display:inline-block;line-height:0}';
|
||
|
||
// ─── Linear regulator (TO-220 style) ──────────────────────────────────────────
|
||
|
||
function regulatorSvg(label: string, middlePinLabel: string): string {
|
||
return `
|
||
<style>${STYLE}</style>
|
||
<svg width="72" height="56" xmlns="http://www.w3.org/2000/svg">
|
||
<!-- Leads -->
|
||
<line x1="0" y1="24" x2="18" y2="24" stroke="${LEAD}" stroke-width="2"/>
|
||
<line x1="36" y1="40" x2="36" y2="56" stroke="${LEAD}" stroke-width="2"/>
|
||
<line x1="54" y1="24" x2="72" y2="24" stroke="${LEAD}" stroke-width="2"/>
|
||
<!-- Body (rectangular TO-220) -->
|
||
<rect x="18" y="8" width="36" height="32" rx="3" fill="${FILL}" stroke="${STROKE}" stroke-width="1.5"/>
|
||
<!-- Heatsink tab on top -->
|
||
<rect x="22" y="2" width="28" height="6" fill="${STROKE}"/>
|
||
<!-- Pin labels -->
|
||
<text x="2" y="20" font-family="sans-serif" font-size="6" fill="${LABEL}">VIN</text>
|
||
<text x="56" y="20" font-family="sans-serif" font-size="6" fill="${LABEL}">VOUT</text>
|
||
<text x="32" y="54" font-family="sans-serif" font-size="6" fill="${LABEL}">${middlePinLabel}</text>
|
||
<!-- Part number -->
|
||
<text x="36" y="28" text-anchor="middle" font-family="sans-serif" font-size="9" fill="${LABEL}" font-weight="bold">${label}</text>
|
||
</svg>`;
|
||
}
|
||
|
||
function makeRegulatorClass(label: string, middlePinName: 'GND' | 'ADJ') {
|
||
return class extends HTMLElement {
|
||
readonly pinInfo = [
|
||
{ name: 'VIN', x: 0, y: 24, number: 1, signals: [] as string[] },
|
||
{ name: middlePinName, x: 36, y: 56, number: 2, signals: [] as string[] },
|
||
{ name: 'VOUT', x: 72, y: 24, number: 3, signals: [] as string[] },
|
||
];
|
||
constructor() {
|
||
super();
|
||
this.attachShadow({ mode: 'open' }).innerHTML = regulatorSvg(label, middlePinName);
|
||
}
|
||
};
|
||
}
|
||
|
||
const Reg7805 = makeRegulatorClass('7805', 'GND');
|
||
const Reg7812 = makeRegulatorClass('7812', 'GND');
|
||
const Reg7905 = makeRegulatorClass('7905', 'GND');
|
||
const RegLM317 = makeRegulatorClass('LM317', 'ADJ');
|
||
|
||
// ─── Battery ──────────────────────────────────────────────────────────────────
|
||
|
||
function batterySvg(label: string, color: string): string {
|
||
return `
|
||
<style>${STYLE}</style>
|
||
<svg width="48" height="72" xmlns="http://www.w3.org/2000/svg">
|
||
<!-- + terminal lead -->
|
||
<line x1="24" y1="0" x2="24" y2="8" stroke="${LEAD}" stroke-width="2"/>
|
||
<!-- Body (rounded rectangle) -->
|
||
<rect x="8" y="8" width="32" height="56" rx="3" fill="${color}" stroke="${STROKE}" stroke-width="1.5"/>
|
||
<!-- Top cap (positive) -->
|
||
<rect x="18" y="4" width="12" height="6" fill="${BLACK}" stroke="${STROKE}" stroke-width="1"/>
|
||
<!-- − terminal lead -->
|
||
<line x1="24" y1="64" x2="24" y2="72" stroke="${LEAD}" stroke-width="2"/>
|
||
<!-- + / − markers -->
|
||
<text x="24" y="22" text-anchor="middle" font-family="sans-serif" font-size="12" fill="white" font-weight="bold">+</text>
|
||
<text x="24" y="56" text-anchor="middle" font-family="sans-serif" font-size="14" fill="white" font-weight="bold">−</text>
|
||
<!-- Label -->
|
||
<text x="24" y="42" text-anchor="middle" font-family="sans-serif" font-size="8" fill="white" font-weight="bold">${label}</text>
|
||
</svg>`;
|
||
}
|
||
|
||
function makeBatteryClass(label: string, color: string) {
|
||
return class extends HTMLElement {
|
||
readonly pinInfo = [
|
||
{ name: '+', x: 24, y: 0, number: 1, signals: [] as string[] },
|
||
{ name: '−', x: 24, y: 72, number: 2, signals: [] as string[] },
|
||
];
|
||
constructor() {
|
||
super();
|
||
this.attachShadow({ mode: 'open' }).innerHTML = batterySvg(label, color);
|
||
}
|
||
};
|
||
}
|
||
|
||
const Battery9V = makeBatteryClass('9V', RED);
|
||
const BatteryAA = makeBatteryClass('AA', '#336699');
|
||
const BatteryCoin = makeBatteryClass('3V', '#666');
|
||
|
||
// ─── Signal generator (benchtop instrument) ───────────────────────────────────
|
||
|
||
class SignalGeneratorElement extends HTMLElement {
|
||
readonly pinInfo = [
|
||
{ name: 'SIG', x: 80, y: 24, number: 1, signals: [] as string[] },
|
||
{ name: 'GND', x: 80, y: 48, number: 2, signals: [] as string[] },
|
||
];
|
||
constructor() {
|
||
super();
|
||
this.attachShadow({ mode: 'open' }).innerHTML = `
|
||
<style>${STYLE}</style>
|
||
<svg width="80" height="64" xmlns="http://www.w3.org/2000/svg">
|
||
<!-- Body -->
|
||
<rect x="0" y="0" width="64" height="64" rx="4" fill="#1a1a2e" stroke="${STROKE}" stroke-width="1.5"/>
|
||
<!-- Screen -->
|
||
<rect x="6" y="6" width="52" height="28" fill="#0a3a0a"/>
|
||
<!-- Sine waveform -->
|
||
<path d="M10,20 Q16,8 22,20 T34,20 T46,20 T58,20" fill="none" stroke="#5af55a" stroke-width="1.5"/>
|
||
<!-- Knobs -->
|
||
<circle cx="14" cy="48" r="6" fill="#444" stroke="${STROKE}" stroke-width="1"/>
|
||
<circle cx="32" cy="48" r="6" fill="#444" stroke="${STROKE}" stroke-width="1"/>
|
||
<circle cx="50" cy="48" r="6" fill="#444" stroke="${STROKE}" stroke-width="1"/>
|
||
<!-- Output leads -->
|
||
<line x1="64" y1="24" x2="80" y2="24" stroke="${LEAD}" stroke-width="2"/>
|
||
<line x1="64" y1="48" x2="80" y2="48" stroke="${LEAD}" stroke-width="2"/>
|
||
<text x="66" y="20" font-family="sans-serif" font-size="6" fill="${LABEL}">SIG</text>
|
||
<text x="66" y="44" font-family="sans-serif" font-size="6" fill="${LABEL}">GND</text>
|
||
</svg>`;
|
||
}
|
||
}
|
||
|
||
function def(tag: string, cls: CustomElementConstructor) {
|
||
if (!customElements.get(tag)) customElements.define(tag, cls);
|
||
}
|
||
|
||
def('wokwi-reg-7805', Reg7805);
|
||
def('wokwi-reg-7812', Reg7812);
|
||
def('wokwi-reg-7905', Reg7905);
|
||
def('wokwi-reg-lm317', RegLM317);
|
||
def('wokwi-battery-9v', Battery9V);
|
||
def('wokwi-battery-aa', BatteryAA);
|
||
def('wokwi-battery-coin-cell', BatteryCoin);
|
||
def('wokwi-signal-generator', SignalGeneratorElement);
|
||
|
||
export {};
|