a429-flight-display
Version:
React components for ARINC 429 Flight Display with primary flight instruments
453 lines (452 loc) • 20.4 kB
JavaScript
var P = Object.defineProperty;
var O = (t, i, n) => i in t ? P(t, i, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[i] = n;
var N = (t, i, n) => O(t, typeof i != "symbol" ? i + "" : i, n);
import { jsxs as a, jsx as e, Fragment as A } from "react/jsx-runtime";
class g {
constructor(i, n, c, o) {
N(this, "label");
N(this, "sdi");
N(this, "data");
N(this, "ssm");
N(this, "parity");
this.label = i, this.sdi = n, this.data = c, this.ssm = o, this.parity = this.calculateParity();
}
calculateParity() {
const i = this.label << 24 | this.sdi << 22 | this.data << 3 | this.ssm << 1;
let n = 0;
for (let c = 0; c < 31; c++)
i & 1 << c && n++;
return n % 2 === 0 ? 1 : 0;
}
}
const u = {
ALTITUDE: 131,
AIRSPEED: 134,
MACH: 135,
HEADING: 146,
VERTICAL_SPEED: 245,
PITCH: 212,
ROLL: 213,
TEMPERATURE: 137
}, p = {
NORMAL_OPERATION: 3
}, R = ({ flightData: t }) => {
const i = () => [
new g(u.ALTITUDE, 0, Math.round(t.altitude), p.NORMAL_OPERATION),
new g(u.AIRSPEED, 0, Math.round(t.airspeed), p.NORMAL_OPERATION),
new g(u.MACH, 0, Math.round(t.mach * 1e5), p.NORMAL_OPERATION),
new g(u.HEADING, 0, Math.round(t.heading), p.NORMAL_OPERATION),
new g(u.VERTICAL_SPEED, 0, Math.round(t.verticalSpeed), p.NORMAL_OPERATION),
new g(u.PITCH, 0, Math.round(t.pitch * 100), p.NORMAL_OPERATION),
new g(u.ROLL, 0, Math.round(t.roll * 100), p.NORMAL_OPERATION)
];
return /* @__PURE__ */ a("div", { className: "bg-gray-900 rounded-xl p-6 shadow-2xl", children: [
/* @__PURE__ */ a("div", { className: "flex justify-between items-center mb-4", children: [
/* @__PURE__ */ e("h2", { className: "text-xl font-bold text-white", children: "Live ARINC 429 Data Bus" }),
/* @__PURE__ */ e("div", { className: "text-green-400 font-mono text-sm", children: t.timestamp.toLocaleTimeString() })
] }),
/* @__PURE__ */ e("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4", children: i().map((n, c) => {
const o = Object.keys(u).find(
(r) => u[r] === n.label
), s = "0x" + (n.label << 24 | n.sdi << 22 | n.data << 3 | n.ssm << 1 | n.parity).toString(16).toUpperCase().padStart(8, "0");
return /* @__PURE__ */ a("div", { className: "bg-gray-800 rounded-lg p-4 border border-gray-600", children: [
/* @__PURE__ */ e("div", { className: "text-yellow-400 font-semibold text-sm mb-2", children: o }),
/* @__PURE__ */ a("div", { className: "text-white font-mono text-xs space-y-1", children: [
/* @__PURE__ */ a("div", { children: [
"Label: ",
n.label.toString(8).padStart(3, "0")
] }),
/* @__PURE__ */ a("div", { children: [
"Data: ",
n.data
] }),
/* @__PURE__ */ a("div", { children: [
"Hex: ",
s
] })
] }),
/* @__PURE__ */ e("div", { className: "text-green-400 text-xs mt-2", children: "● NORMAL" })
] }, c);
}) }),
/* @__PURE__ */ e("div", { className: "mt-6 text-center", children: /* @__PURE__ */ a("div", { className: "inline-flex items-center space-x-4 bg-gray-800 px-6 py-3 rounded-lg", children: [
/* @__PURE__ */ e("div", { className: "w-3 h-3 bg-green-400 rounded-full animate-pulse" }),
/* @__PURE__ */ e("span", { className: "text-white font-semibold", children: "ARINC 429 Bus Active" }),
/* @__PURE__ */ e("span", { className: "text-gray-400 font-mono text-sm", children: "12.5 kHz" })
] }) })
] });
}, T = ({ pitch: t, roll: i }) => {
const c = () => {
const s = [];
for (let r = -30; r <= 30; r += 5) {
if (r === 0) continue;
const l = r % 10 === 0;
s.push(
/* @__PURE__ */ e("div", { className: "absolute flex items-center justify-center w-full", children: /* @__PURE__ */ a(
"div",
{
className: "flex items-center justify-center",
style: {
transform: `translateY(${-r * 3}px)`
},
children: [
/* @__PURE__ */ e(
"div",
{
className: `bg-white ${l ? "h-0.5 w-16" : "h-0.5 w-8"}`
}
),
l && /* @__PURE__ */ a(A, { children: [
/* @__PURE__ */ e("span", { className: "text-white text-xs font-mono ml-2 select-none", children: Math.abs(r) }),
/* @__PURE__ */ e("div", { className: "bg-white h-0.5 w-16 ml-2" }),
/* @__PURE__ */ e("span", { className: "text-white text-xs font-mono ml-2 select-none", children: Math.abs(r) })
] })
]
}
) }, r)
);
}
return s;
}, o = () => {
const s = [];
return [-60, -45, -30, -20, -10, 0, 10, 20, 30, 45, 60].forEach((l) => {
const d = [0, -30, 30, -60, 60].includes(l), h = [-10, -20, 10, 20, -45, 45].includes(l);
s.push(
/* @__PURE__ */ a(
"div",
{
className: "absolute top-1 left-1/2 origin-bottom transform -translate-x-1/2",
style: {
transform: `translateX(-50%) rotate(${l}deg)`,
transformOrigin: "center 92px"
},
children: [
/* @__PURE__ */ e(
"div",
{
className: `bg-white ${d ? "w-0.5 h-4" : h ? "w-0.5 h-3" : "w-0.5 h-2"}`
}
),
(l === -30 || l === 30 || l === -60 || l === 60) && /* @__PURE__ */ e("div", { className: "text-white text-xs font-mono text-center mt-1 select-none", children: Math.abs(l) })
]
},
l
)
);
}), s;
};
return /* @__PURE__ */ a("div", { className: "relative w-48 h-48 rounded-full overflow-hidden border-4 border-gray-600 shadow-2xl bg-gray-900", children: [
/* @__PURE__ */ a(
"div",
{
className: "absolute inset-0 bg-gradient-to-b from-sky-400 via-sky-300 to-amber-500",
style: {
transform: `rotate(${i}deg) translateY(${t * 3}px)`,
transformOrigin: "center center",
width: "200%",
height: "200%",
left: "-50%",
top: "-50%"
},
children: [
/* @__PURE__ */ e(
"div",
{
className: "absolute left-0 right-0 h-1 bg-white",
style: { top: "50%", transform: "translateY(-50%)" }
}
),
/* @__PURE__ */ e(
"div",
{
className: "absolute inset-0 flex justify-center items-center",
style: { top: "50%", left: "50%", transform: "translate(-50%, -50%)" },
children: c()
}
)
]
}
),
/* @__PURE__ */ e("div", { className: "absolute inset-0", children: o() }),
/* @__PURE__ */ e(
"div",
{
className: "absolute top-1 left-1/2 w-0 h-0 border-l-3 border-r-3 border-b-6 border-transparent border-b-yellow-400 transform -translate-x-1/2 z-20",
style: {
transform: `translateX(-50%) rotate(${i}deg)`,
transformOrigin: "center 92px"
}
}
),
/* @__PURE__ */ e("div", { className: "absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-30", children: /* @__PURE__ */ a("div", { className: "relative flex items-center justify-center", children: [
/* @__PURE__ */ e("div", { className: "w-12 h-1 bg-yellow-400" }),
/* @__PURE__ */ e("div", { className: "absolute w-1 h-6 bg-yellow-400" }),
/* @__PURE__ */ e("div", { className: "absolute w-2 h-2 bg-yellow-400 rounded-full" })
] }) }),
/* @__PURE__ */ e("div", { className: "absolute top-2 left-1/2 w-0 h-0 border-l-2 border-r-2 border-b-4 border-transparent border-b-white transform -translate-x-1/2 z-10" })
] });
}, S = ({
value: t,
title: i,
unit: n,
unitTooltip: c,
generateMarks: o,
getValueColor: s = () => "text-white",
isMajorTick: r = (m) => m % 20 === 0,
formatValue: l = (m) => m.toString(),
formatCurrentValue: d = (m) => Math.round(m).toString(),
pixelsPerUnit: h = 2,
pointerSide: b = "right",
className: x = ""
}) => {
const m = o(t), f = b === "left";
return console.log(), /* @__PURE__ */ a("div", { className: `bg-gray-900 text-white rounded-lg w-32 h-64 relative overflow-hidden border-2 border-gray-600 flex flex-col ${x}`, children: [
/* @__PURE__ */ e("div", { className: "text-center text-xs font-bold text-gray-300 py-1 border-b border-gray-600", children: i }),
/* @__PURE__ */ a("div", { className: "flex-1 relative overflow-hidden", children: [
/* @__PURE__ */ e("div", { className: "absolute inset-0 flex flex-col justify-center", children: /* @__PURE__ */ e("div", { className: "relative h-48 mx-2", children: m.map((v) => {
const w = (t - v) * h, y = 96 + w;
if (Math.abs(w) > 90 || y < 0 || y > 202)
return null;
const M = r(v);
return /* @__PURE__ */ a(
"div",
{
className: "absolute flex items-center w-full",
style: {
top: `${y}px`,
transform: "translateY(-50%)",
flexDirection: f ? "row-reverse" : "row"
},
children: [
M && /* @__PURE__ */ e(
"div",
{
className: `text-xs font-mono w-8 ${f ? "text-left" : "text-right"} ${s(v)}`,
children: l(v)
}
),
/* @__PURE__ */ e(
"div",
{
className: `${f ? "mr-1" : "ml-1"} bg-white ${M ? "h-0.5 w-4" : "h-0.5 w-2"}`
}
)
]
},
v
);
}) }) }),
/* @__PURE__ */ e(
"div",
{
className: `absolute ${f ? "left-2" : "right-2"} top-1/2 w-0 h-0 ${f ? "border-t-4 border-b-4 border-r-6 border-transparent border-r-yellow-400" : "border-t-4 border-b-4 border-l-6 border-transparent border-l-yellow-400"} transform -translate-y-1/2 z-20`
}
),
/* @__PURE__ */ e(
"div",
{
className: `absolute top-1/2 ${f ? "left-8" : "right-8"} bg-black px-2 py-1 border border-white text-yellow-400 font-bold text-sm transform -translate-y-1/2 z-10 min-w-[3rem] text-center`,
children: d(t)
}
)
] }),
/* @__PURE__ */ a("div", { className: "relative group text-center text-xs text-gray-300 py-1 border-t border-gray-600", children: [
/* @__PURE__ */ e("span", { className: "cursor-help", children: n }),
c && /* @__PURE__ */ a("div", { className: "absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-2 py-1 bg-gray-800 text-white text-xs rounded shadow-lg opacity-0 group-hover:opacity-100 transition-opacity duration-200 z-50 pointer-events-none max-w-32 text-center whitespace-normal", children: [
c,
/* @__PURE__ */ e("div", { className: "absolute top-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-l-2 border-r-2 border-t-2 border-transparent border-t-gray-800" })
] })
] })
] });
}, E = ({ airspeed: t }) => /* @__PURE__ */ e(
S,
{
value: t,
title: "AIRSPEED",
unit: "KTS",
unitTooltip: "Knots (nautical mph)",
generateMarks: (o) => {
const s = [], d = Math.max(
0,
Math.floor((o - 100) / 10) * 10
), h = Math.ceil((o + 100) / 10) * 10;
for (let b = d; b <= h; b += 10)
s.push(b);
return s;
},
getValueColor: (o) => o >= 40 && o <= 100 ? "text-white" : o >= 100 && o <= 180 ? "text-green-400" : o >= 180 && o <= 220 ? "text-yellow-400" : o > 220 ? "text-red-400" : "text-gray-400",
isMajorTick: (o) => o % 20 === 0,
pixelsPerUnit: 2,
pointerSide: "right"
}
), I = ({ altitude: t }) => /* @__PURE__ */ e(
S,
{
value: t,
title: "ALTITUDE",
unit: "FT",
unitTooltip: "Feet above sea level",
generateMarks: (s) => {
const r = [], h = Math.max(
0,
Math.floor((s - 5e3) / 100) * 100
), b = Math.ceil((s + 5e3) / 100) * 100;
for (let x = h; x <= b; x += 100)
r.push(x);
return r;
},
getValueColor: (s) => s < 1e3 ? "text-red-400" : s >= 1e3 && s <= 1e4 ? "text-white" : s > 1e4 && s <= 4e4 ? "text-green-400" : s > 4e4 ? "text-yellow-400" : "text-gray-400",
isMajorTick: (s) => s % 500 === 0,
formatValue: (s) => s.toString(),
pixelsPerUnit: 0.1,
pointerSide: "left"
}
), L = ({ heading: t }) => {
const n = (() => {
const r = [];
for (let l = 0; l < 72; l++) {
const d = l * 5, h = d % 90 === 0, b = d % 30 === 0, x = d % 10 === 0;
let m = "";
d === 0 ? m = "N" : d === 90 ? m = "E" : d === 180 ? m = "S" : d === 270 ? m = "W" : b && (m = (d / 10).toString().padStart(2, "0")), r.push({
angle: d,
label: m,
isCardinal: h,
isMajor: b,
isMinor: x,
x: l * 4
});
}
return r;
})(), c = (t % 360 + 360) % 360, s = 96 - c * 4;
return /* @__PURE__ */ a("div", { className: "bg-gray-900 text-white rounded-lg w-48 h-16 relative overflow-hidden border-2 border-gray-600 shadow-lg", children: [
/* @__PURE__ */ e("div", { className: "absolute top-0 left-1/2 w-0 h-0 border-l-3 border-r-3 border-b-6 border-transparent border-b-yellow-400 transform -translate-x-1/2 z-10" }),
/* @__PURE__ */ e(
"div",
{
className: "absolute top-1 flex transition-transform duration-200 ease-out",
style: { transform: `translateX(${s}px)` },
children: n.concat(n).concat(n).map((r, l) => /* @__PURE__ */ a("div", { className: "relative flex flex-col items-center", style: { width: "4px" }, children: [
/* @__PURE__ */ e("div", { className: `bg-white ${r.isCardinal ? "w-0.5 h-4" : r.isMajor ? "w-0.5 h-3" : r.isMinor ? "w-px h-2" : "w-px h-1"}` }),
r.label && /* @__PURE__ */ e("div", { className: `mt-0.5 text-xs font-mono whitespace-nowrap ${r.isCardinal ? "text-yellow-400 font-bold" : "text-white"}`, style: { fontSize: "10px" }, children: r.label })
] }, l))
}
),
/* @__PURE__ */ a("div", { className: "absolute bottom-1 left-1/2 bg-black px-2 py-0.5 border border-gray-400 text-green-400 font-bold text-xs transform -translate-x-1/2 rounded whitespace-nowrap", children: [
"HDG ",
Math.round(c).toString().padStart(3, "0"),
"°"
] }),
/* @__PURE__ */ e("div", { className: "absolute top-0 left-0 w-4 h-full bg-gradient-to-r from-gray-900 to-transparent pointer-events-none z-20" }),
/* @__PURE__ */ e("div", { className: "absolute top-0 right-0 w-4 h-full bg-gradient-to-l from-gray-900 to-transparent pointer-events-none z-20" })
] });
}, C = ({ verticalSpeed: t }) => {
const n = (() => {
const r = [];
for (let h = -3e3; h <= 3e3; h += 200) {
const b = 50 - h / 3e3 * 40, x = h % 1e3 === 0, m = x;
r.push({
value: h,
yPercent: b,
isMajor: x,
showLabel: m,
label: m ? (h / 1e3).toString() : ""
});
}
return r;
})(), o = 50 - Math.max(-3e3, Math.min(3e3, t)) / 3e3 * 40, s = () => {
const r = Math.abs(t);
return r < 50 ? "00" : Math.floor(r / 100).toString().padStart(2, "0");
};
return /* @__PURE__ */ a("div", { className: "bg-gray-900 text-white rounded-lg w-20 h-64 relative border-2 border-gray-600 shadow-lg overflow-hidden", children: [
/* @__PURE__ */ e("div", { className: "absolute top-1 left-1/2 transform -translate-x-1/2 text-xs font-mono text-gray-300 font-semibold", children: "V/S" }),
/* @__PURE__ */ e("div", { className: "absolute right-1 top-8 bottom-8 w-16", children: n.map((r, l) => /* @__PURE__ */ a(
"div",
{
className: "absolute w-full flex items-center justify-end",
style: { top: `${r.yPercent}%` },
children: [
r.showLabel && /* @__PURE__ */ e("div", { className: "mr-1 text-xs font-mono text-white", children: r.label }),
/* @__PURE__ */ e("div", { className: `bg-white h-0.5 ${r.isMajor ? "w-4" : "w-2"} ${r.value === 0 ? "bg-yellow-400 w-6" : "bg-white"}` })
]
},
l
)) }),
/* @__PURE__ */ e(
"div",
{
className: "absolute left-2 top-1/2 w-0 h-0 border-t-2 border-b-2 border-r-4 border-transparent border-r-yellow-400 transform -translate-y-1/2 z-10"
}
),
/* @__PURE__ */ e(
"div",
{
className: "absolute left-8 w-6 h-0.5 bg-cyan-400 transform -translate-y-1/2 transition-all duration-300 z-20",
style: { top: `${o}%` }
}
),
/* @__PURE__ */ a("div", { className: "absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-black px-2 py-1 border border-gray-400 rounded z-30", children: [
/* @__PURE__ */ e("div", { className: "text-cyan-400 font-bold text-lg font-mono", children: s() }),
/* @__PURE__ */ e("div", { className: "text-gray-400 text-xs text-center", children: t >= 0 ? "▲" : "▼" })
] }),
/* @__PURE__ */ e("div", { className: "absolute bottom-1 left-1/2 transform -translate-x-1/2 text-xs text-gray-400 font-mono", children: "FPM" }),
/* @__PURE__ */ e("div", { className: "absolute top-0 left-0 w-full h-8 bg-gradient-to-b from-gray-900 to-transparent pointer-events-none z-40" }),
/* @__PURE__ */ e("div", { className: "absolute bottom-0 left-0 w-full h-8 bg-gradient-to-t from-gray-900 to-transparent pointer-events-none z-40" })
] });
};
function j({ flightData: t }) {
return /* @__PURE__ */ e(A, { children: /* @__PURE__ */ a("div", { className: "bg-black rounded-xl p-8 shadow-2xl mb-6", children: [
/* @__PURE__ */ a("div", { className: "flex justify-center items-center space-x-8", children: [
/* @__PURE__ */ e("p", { children: "AirSpeed" }),
/* @__PURE__ */ e(E, { airspeed: t.airspeed }),
/* @__PURE__ */ a("div", { className: "flex flex-col items-center space-y-4", children: [
/* @__PURE__ */ e(
T,
{
pitch: t.pitch,
roll: t.roll
}
),
/* @__PURE__ */ e(L, { heading: t.heading })
] }),
/* @__PURE__ */ e(I, { altitude: t.altitude }),
/* @__PURE__ */ e(C, { verticalSpeed: t.verticalSpeed })
] }),
/* @__PURE__ */ a("div", { className: "flex justify-center space-x-8 mt-6 text-white", children: [
/* @__PURE__ */ a("div", { className: "bg-gray-800 px-4 py-2 rounded border", children: [
/* @__PURE__ */ e("span", { className: "text-gray-400", children: "MACH:" }),
/* @__PURE__ */ e("span", { className: "text-cyan-400 ml-2 font-mono", children: t.mach.toFixed(3) })
] }),
/* @__PURE__ */ a("div", { className: "bg-gray-800 px-4 py-2 rounded border", children: [
/* @__PURE__ */ e("span", { className: "text-gray-400", children: "OAT:" }),
/* @__PURE__ */ a("span", { className: "text-blue-300 ml-2 font-mono", children: [
Math.round(t.temperature),
"°C"
] })
] }),
/* @__PURE__ */ a("div", { className: "bg-gray-800 px-4 py-2 rounded border", children: [
/* @__PURE__ */ e("span", { className: "text-gray-400", children: "GS:" }),
/* @__PURE__ */ e("span", { className: "text-green-400 ml-2 font-mono", children: "420 KT" })
] })
] })
] }) });
}
const V = ({ flightData: t }) => /* @__PURE__ */ e("div", { className: "min-h-screen bg-gray-800 p-6", children: /* @__PURE__ */ a("div", { className: "max-w-7xl mx-auto", children: [
/* @__PURE__ */ e("div", { className: "mb-6 text-center", children: /* @__PURE__ */ e("div", { className: "bg-gray-900 rounded-lg p-4 inline-block", children: /* @__PURE__ */ a("div", { className: "text-green-400 font-mono text-lg", children: [
t.timestamp.toLocaleDateString(),
" - ",
t.timestamp.toLocaleTimeString()
] }) }) }),
/* @__PURE__ */ e(j, { flightData: t }),
/* @__PURE__ */ e(R, { flightData: t })
] }) });
export {
R as ARINC429DataBus,
g as ARINC429Word,
u as ARINC429_LABELS,
V as AircraftPFD,
E as AirspeedIndicator,
I as AltitudeIndicator,
T as AttitudeIndicator,
L as HeadingIndicator,
p as SSM,
C as VerticalSpeedIndicator
};