diff --git a/gui/app.css b/gui/app.css
index dee960a..f62cad4 100644
--- a/gui/app.css
+++ b/gui/app.css
@@ -281,8 +281,8 @@ header {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
- width: calc(180px * var(--cam-scale));
- height: calc(180px * var(--cam-scale));
+ width: calc(220px * var(--cam-scale));
+ height: calc(220px * var(--cam-scale));
z-index: 10;
pointer-events: none;
}
diff --git a/gui/index.html b/gui/index.html
index 263d811..7552c7c 100644
--- a/gui/index.html
+++ b/gui/index.html
@@ -94,50 +94,76 @@
S: 0,00 m
-
@@ -336,6 +362,7 @@ function normalizeHeadingDeg(value) {
function updateImuOverlaySvg() {
var group = document.getElementById("imu-horizon-group");
var frame = document.getElementById("imu-horizon-frame");
+ var rollPointer = document.getElementById("imu-roll-pointer");
var headingText = document.getElementById("imu-heading-text");
var rollText = document.getElementById("imu-roll-text");
var pitchText = document.getElementById("imu-pitch-text");
@@ -350,11 +377,14 @@ function updateImuOverlaySvg() {
var rollDeg = Number(imuOverlayState.rollDeg || 0);
var pitchDeg = Number(imuOverlayState.pitchDeg || 0);
var headingDeg = normalizeHeadingDeg(imuOverlayState.yawDeg);
- var pitchOffset = Math.max(-26, Math.min(26, pitchDeg * 1.1));
+ var pitchOffset = Math.max(-55, Math.min(55, pitchDeg * 2.2));
group.setAttribute("opacity", "1");
frame.setAttribute("transform", "rotate(" + (-rollDeg).toFixed(2) + ") translate(0 " + pitchOffset.toFixed(2) + ")");
- headingText.textContent = "HDG " + Math.round(headingDeg) + "°";
+ if (rollPointer) {
+ rollPointer.setAttribute("transform", "rotate(" + (-rollDeg).toFixed(2) + ")");
+ }
+ headingText.textContent = "HDG " + String(Math.round(headingDeg)).padStart(3, "0") + "°";
rollText.textContent = "R " + formatSignedNumber(rollDeg, 1) + "°";
pitchText.textContent = "P " + formatSignedNumber(pitchDeg, 1) + "°";
}
@@ -1076,44 +1106,66 @@ function drawImuHorizonOverlay(context, canvasWidth, canvasHeight, size) {
var cx = canvasWidth / 2;
var cy = canvasHeight / 2;
- var unit = size / 180;
+ var unit = size / 220;
var rollRad = Number(imuOverlayState.rollDeg || 0) * Math.PI / 180;
- var pitchOffsetPx = Math.max(-26, Math.min(26, Number(imuOverlayState.pitchDeg || 0) * 0.9 * unit));
+ var pitchOffsetPx = Math.max(-55, Math.min(55, Number(imuOverlayState.pitchDeg || 0) * 2.2)) * unit;
var headingDeg = normalizeHeadingDeg(imuOverlayState.yawDeg);
+ var rollDeg = Number(imuOverlayState.rollDeg || 0);
+ var pitchDeg = Number(imuOverlayState.pitchDeg || 0);
+ /* roll pointer triangle (only roll, no pitch) */
+ context.save();
+ context.translate(cx, cy);
+ context.rotate(-rollRad);
+ context.beginPath();
+ context.moveTo(0, -90 * unit);
+ context.lineTo(-5.5 * unit, -79 * unit);
+ context.lineTo(5.5 * unit, -79 * unit);
+ context.closePath();
+ context.fillStyle = "rgba(0,255,145,.88)";
+ context.fill();
+ context.restore();
+
+ /* horizon + pitch ladder */
context.save();
context.translate(cx, cy);
context.rotate(-rollRad);
context.translate(0, pitchOffsetPx);
- context.strokeStyle = "rgba(0,255,145,.82)";
- context.lineWidth = 1.25 * unit;
- context.beginPath();
- context.moveTo(-28 * unit, 0);
- context.lineTo(28 * unit, 0);
- context.stroke();
-
- context.strokeStyle = "rgba(0,255,145,.36)";
- context.lineWidth = 0.9 * unit;
- [-18, -9, 9, 18].forEach(function(stepDeg) {
- var y = stepDeg * 1.1 * unit;
- var span = Math.abs(stepDeg) === 18 ? 13 : 9;
+ [
+ { y: -33, span: 11, op: .28 }, { y: 33, span: 11, op: .28 },
+ { y: -22, span: 17, op: .44 }, { y: 22, span: 17, op: .44 },
+ { y: -11, span: 10, op: .3 }, { y: 11, span: 10, op: .3 }
+ ].forEach(function(pl) {
context.beginPath();
- context.moveTo(-span * unit, y);
- context.lineTo(span * unit, y);
+ context.moveTo(-pl.span * unit, pl.y * unit);
+ context.lineTo(pl.span * unit, pl.y * unit);
+ context.strokeStyle = "rgba(0,255,145," + pl.op + ")";
+ context.lineWidth = 0.9 * unit;
context.stroke();
});
+ context.strokeStyle = "rgba(0,255,145,.92)";
+ context.lineWidth = 1.5 * unit;
+ context.beginPath(); context.moveTo(-40 * unit, 0); context.lineTo(40 * unit, 0); context.stroke();
+ context.beginPath(); context.moveTo(-40 * unit, 0); context.lineTo(-32 * unit, -5 * unit); context.stroke();
+ context.beginPath(); context.moveTo(40 * unit, 0); context.lineTo(32 * unit, -5 * unit); context.stroke();
context.restore();
+ /* HDG box + text labels */
context.save();
- context.font = (8.5 * unit) + 'px "IBM Plex Mono", "Roboto Mono", monospace';
- context.fillStyle = "rgba(0,255,145,.78)";
+ var bw = 54 * unit, bh = 13 * unit;
+ context.fillStyle = "rgba(0,15,8,.58)";
+ context.fillRect(cx - bw / 2, cy - 70 * unit, bw, bh);
+ context.font = (9 * unit) + 'px "Consolas","Cascadia Mono",monospace';
+ context.fillStyle = "rgba(0,255,145,.9)";
context.textAlign = "center";
context.textBaseline = "middle";
- context.fillText("HDG " + Math.round(headingDeg) + "°", cx, cy - (48 * unit));
- context.fillText("R " + formatSignedNumber(imuOverlayState.rollDeg, 1) + "°", cx - (56 * unit), cy + (52 * unit));
- context.fillText("P " + formatSignedNumber(imuOverlayState.pitchDeg, 1) + "°", cx + (56 * unit), cy + (52 * unit));
+ context.fillText("HDG " + String(Math.round(headingDeg)).padStart(3, "0") + "°", cx, cy - 63.5 * unit);
+ context.font = (7.5 * unit) + 'px "Consolas","Cascadia Mono",monospace';
+ context.fillStyle = "rgba(0,255,145,.72)";
+ context.fillText("R " + formatSignedNumber(rollDeg, 1) + "°", cx - 73 * unit, cy + 76 * unit);
+ context.fillText("P " + formatSignedNumber(pitchDeg, 1) + "°", cx + 73 * unit, cy + 76 * unit);
context.restore();
}
@@ -1263,7 +1315,7 @@ function drawHudOverlayToCanvas(context, canvasWidth, canvasHeight) {
context.fillText(document.getElementById("cam-live-text").textContent, canvasWidth / 2 + (6 * camScale * scaleToCanvas), padding);
context.restore();
- drawCrosshairOverlayToCanvas(context, canvasWidth, canvasHeight, 180 * camScale * scaleToCanvas);
+ drawCrosshairOverlayToCanvas(context, canvasWidth, canvasHeight, 220 * camScale * scaleToCanvas);
drawVignetteAndScanlines(context, canvasWidth, canvasHeight);
}