/* global React */
/* ===========================================================
VOLTLAB · CONVERSOR DE UNIDADES
Conversões úteis para engenharia elétrica:
Potência · Tensão · Corrente · Comprimento · Seção (AWG↔mm²)
100% no padrão visual VoltLab (reutiliza classes app.css).
=========================================================== */
const { useState, useEffect, useMemo, useRef } = React;
/* ---------- persistência segura ---------- */
const useCvPersist = (k, v) => (window.useLocalStorage ? window.useLocalStorage(k, v) : useState(v));
/* ---------- ícones (mesmo traço dos demais módulos) ---------- */
const CvIcon = ({ name, size = 16 }) => {
const p = { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round" };
const d = {
swap: <>>,
bolt: ,
wave: ,
current:<>>,
ruler: <>>,
cable: <>>,
check: ,
info: <>>,
copy: <>>,
};
return ;
};
/* ---------- dropdown idêntico ao do app (.vl-dd) ---------- */
const CvDropdown = ({ value, onChange, options }) => {
const [open, setOpen] = useState(false);
const ref = useRef(null);
useEffect(() => {
if (!open) return;
const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
document.addEventListener("mousedown", h);
return () => document.removeEventListener("mousedown", h);
}, [open]);
const cur = options.find(o => o.value === value) || options[0];
return (
{open && (
{options.map(o => (
{ onChange(o.value); setOpen(false); }}>
{o.label}
))}
)}
);
};
/* ---------- formatação de números ---------- */
function fmtNum(n) {
if (!isFinite(n)) return "—";
if (n === 0) return "0";
const abs = Math.abs(n);
let s;
if (abs >= 1e6 || abs < 1e-4) s = n.toExponential(4);
else s = n.toPrecision(7);
// limpa zeros à direita
if (s.indexOf("e") === -1 && s.indexOf(".") !== -1) s = s.replace(/\.?0+$/, "");
return s;
}
/* ===========================================================
DEFINIÇÃO DAS GRANDEZAS LINEARES (fator → unidade base SI)
=========================================================== */
const CATS = {
potencia: {
label: "Potência", icon: "bolt", base: "W", baseName: "watt",
units: [
{ u: "W", f: 1, n: "Watt" },
{ u: "kW", f: 1e3, n: "Quilowatt" },
{ u: "MW", f: 1e6, n: "Megawatt" },
{ u: "cv", f: 735.49875, n: "Cavalo-vapor (métrico)" },
{ u: "HP", f: 745.699872, n: "Horsepower (mecânico)" },
],
},
tensao: {
label: "Tensão", icon: "wave", base: "V", baseName: "volt",
units: [
{ u: "mV", f: 1e-3, n: "Milivolt" },
{ u: "V", f: 1, n: "Volt" },
{ u: "kV", f: 1e3, n: "Quilovolt" },
],
},
corrente: {
label: "Corrente", icon: "current", base: "A", baseName: "ampère",
units: [
{ u: "mA", f: 1e-3, n: "Miliampère" },
{ u: "A", f: 1, n: "Ampère" },
{ u: "kA", f: 1e3, n: "Quiloampère" },
],
},
comprimento: {
label: "Comprimento", icon: "ruler", base: "m", baseName: "metro",
units: [
{ u: "mm", f: 1e-3, n: "Milímetro" },
{ u: "cm", f: 1e-2, n: "Centímetro" },
{ u: "m", f: 1, n: "Metro" },
{ u: "km", f: 1e3, n: "Quilômetro" },
],
},
};
/* ===========================================================
TABELA AWG (gerada pela fórmula da bitola americana)
d(mm) = 0.127 · 92^((36 - n)/39) · área = π/4 · d²
=========================================================== */
const IEC_SECOES = [0.5,0.75,1,1.5,2.5,4,6,10,16,25,35,50,70,95,120,150,185,240,300,400,500];
function buildAWG() {
// n: 0000(-3) … 24 ; rotulamos os 1/0..4/0
const rows = [];
const defs = [
{ n: -3, label: "4/0 (0000)" },
{ n: -2, label: "3/0 (000)" },
{ n: -1, label: "2/0 (00)" },
{ n: 0, label: "1/0 (0)" },
];
for (let i = 1; i <= 24; i++) defs.push({ n: i, label: String(i) });
defs.forEach(({ n, label }) => {
const d_mm = 0.127 * Math.pow(92, (36 - n) / 39);
const area = Math.PI / 4 * d_mm * d_mm;
const cmil = area / 5.067e-4; // 1 cmil = 5.067e-4 mm²
rows.push({ awg: label, key: label, d_mm, area, cmil });
});
return rows;
}
const AWG_ROWS = buildAWG();
function nearestIEC(area) {
// menor seção comercial que comporta a área (próximo valor ≥)
return IEC_SECOES.find(s => s >= area - 1e-9) || IEC_SECOES[IEC_SECOES.length - 1];
}
function nearestAWG(area) {
// AWG cuja seção é a mais próxima da área informada
let best = AWG_ROWS[0], diff = Infinity;
AWG_ROWS.forEach(r => { const dd = Math.abs(r.area - area); if (dd < diff) { diff = dd; best = r; } });
return best;
}
/* ---------- átomos visuais (classes do app.css) ---------- */
const Field = ({ label, hint, children }) => (
{children}
);
const NumInput = ({ value, onChange, suffix }) => (
onChange(e.target.value)} step="any"/>
{suffix && {suffix}}
);
const Banner = ({ kind, children }) => (
{children}
);
const Metric = ({ label, value, unit }) => (
{label}
{value}{unit && {unit}}
);
/* ===========================================================
COMPONENTE PRINCIPAL
=========================================================== */
const Conversor = () => {
const [cat, setCat] = useCvPersist("vl_conv_cat", "potencia");
// estado linear
const [val, setVal] = useCvPersist("vl_conv_val", "1");
const [from, setFrom] = useCvPersist("vl_conv_from", "kW");
const [to, setTo] = useCvPersist("vl_conv_to", "cv");
// estado AWG
const [awgDir, setAwgDir] = useCvPersist("vl_conv_awgdir", "a2m"); // a2m | m2a
const [awgSel, setAwgSel] = useCvPersist("vl_conv_awg", "10");
const [mmVal, setMmVal] = useCvPersist("vl_conv_mm", "6");
const isAWG = cat === "secao";
const def = CATS[cat];
// garante que from/to pertencem à categoria atual
useEffect(() => {
if (isAWG) return;
const us = def.units.map(u => u.u);
if (!us.includes(from)) setFrom(us[0]);
if (!us.includes(to)) setTo(us[Math.min(1, us.length - 1)]);
}, [cat]); // eslint-disable-line
/* -------- cálculo linear -------- */
const linear = useMemo(() => {
if (isAWG) return null;
const v = parseFloat(val);
const fU = def.units.find(u => u.u === from) || def.units[0];
const tU = def.units.find(u => u.u === to) || def.units[0];
if (!isFinite(v)) return { invalid: true, fU, tU };
const base = v * fU.f; // em unidade SI
const out = base / tU.f; // na unidade destino
const factor = fU.f / tU.f; // multiplicador direto
const table = def.units.map(u => ({ ...u, conv: base / u.f }));
return { v, fU, tU, base, out, factor, table };
}, [cat, val, from, to, isAWG]);
/* -------- cálculo AWG -------- */
const awg = useMemo(() => {
if (!isAWG) return null;
if (awgDir === "a2m") {
const row = AWG_ROWS.find(r => r.key === awgSel) || AWG_ROWS[0];
return { mode: "a2m", row, iec: nearestIEC(row.area) };
} else {
const a = parseFloat(mmVal);
if (!isFinite(a) || a <= 0) return { mode: "m2a", invalid: true };
const row = nearestAWG(a);
return { mode: "m2a", area: a, row, iec: nearestIEC(a) };
}
}, [isAWG, awgDir, awgSel, mmVal]);
const swap = () => { const a = from; setFrom(to); setTo(a); };
/* =========================================================
RENDER
========================================================= */
return (
{/* ---------- ENTRADA ---------- */}
CONVERSÃO DE UNIDADES
Selecione a grandeza e converta
TEMPO REAL
{/* categorias */}
{Object.entries(CATS).map(([id, c]) => (
))}
{!isAWG ? (
<>
({ value: u.u, label: `${u.u} · ${u.n}` }))}/>
({ value: u.u, label: `${u.u} · ${u.n}` }))}/>
Grandeza{def.label}
Base SI{def.base}
Fator direto×{linear && !linear.invalid ? fmtNum(linear.factor) : "—"}
>
) : (
<>
{awgDir === "a2m" ? (
({ value: r.key, label: `AWG ${r.awg}` }))}/>
) : (
)}
PadrãoAWG ⇄ IEC
Referência25,4 mm/in
1 cmil5,067e-4 mm²
>
)}
{/* ---------- RESULTADO ---------- */}
{/* ---------- TABELA DE REFERÊNCIA ---------- */}
{!isAWG ? (
TABELA DE EQUIVALÊNCIA
{linear && !linear.invalid ? `${fmtNum(linear.v)} ${from}` : "Valor de entrada"} em todas as unidades de {def.label}
Base: 1 {def.base} ({def.baseName})
UNIDADE
NOME
VALOR EQUIVALENTE
FATOR P/ {def.base}
{(linear?.table || def.units.map(u => ({ ...u, conv: NaN }))).map(u => {
const sel = u.u === to;
return (
{u.u}
{u.n}
{isFinite(u.conv) ? fmtNum(u.conv) : "—"} {u.u}
×{fmtNum(u.f)}
);
})}
) : (
TABELA DE REFERÊNCIA · AWG ⇄ mm²
Bitolas americanas e seções comerciais IEC
d = 0,127 · 92^((36−n)/39)
AWG
Ø (mm)
SEÇÃO (mm²)
CIRCULAR MILS
COMERCIAL IEC
{AWG_ROWS.map(r => {
const sel = awg && !awg.invalid && awg.row.key === r.key;
return (
{r.awg}
{r.d_mm.toFixed(2)}
{fmtNum(r.area)}
{Math.round(r.cmil).toLocaleString("pt-BR")}
{fmtNum(nearestIEC(r.area))} mm²
);
})}
)}
);
};
window.VL_Conversores = Conversor;