This commit is contained in:
2026-05-29 09:20:28 +02:00
parent b4ea4799a9
commit 5e39a41f49
3 changed files with 111 additions and 50 deletions
+79 -48
View File
@@ -94,7 +94,7 @@
S: <span id="overlay-distance">0,00</span> m
</div>
<div class="c-xhair">
<svg viewBox="-110 -110 220 220" xmlns="http://www.w3.org/2000/svg" width="220" height="220">
<svg viewBox="-110 -110 220 220" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<!-- outer rotating dashed ring -->
<circle class="xh-rot" cx="0" cy="0" r="103" fill="none" stroke="rgba(0,255,145,.14)" stroke-width="1" stroke-dasharray="4 13"/>
<!-- roll arc (static) r=96, ±60° from top -->
@@ -158,8 +158,8 @@
<line x1="-42" y1="-72" x2="42" y2="-72" stroke="rgba(0,255,145,.35)" stroke-width=".5"/>
<text id="imu-heading-text" x="0" y="-62.5" fill="rgba(0,255,145,.92)" font-size="9" text-anchor="middle" letter-spacing="1">HDG 000° N</text>
<!-- roll / pitch readouts -->
<text id="imu-roll-text" x="-73" y="76" fill="rgba(0,255,145,.82)" font-size="7.5" text-anchor="middle">R +0.0°</text>
<text id="imu-pitch-text" x="73" y="76" fill="rgba(0,255,145,.82)" font-size="7.5" text-anchor="middle">P +0.0°</text>
<text id="imu-roll-text" x="-73" y="76" fill="rgba(0,255,145,.82)" font-size="10.5" text-anchor="middle">R +0.0°</text>
<text id="imu-pitch-text" x="73" y="76" fill="rgba(0,255,145,.82)" font-size="10.5" text-anchor="middle">P +0.0°</text>
</g>
<!-- center dot -->
<circle cx="0" cy="0" r="3" fill="rgba(0,255,145,.92)"/>
@@ -167,7 +167,6 @@
</svg>
</div>
<div class="c-scanlines"></div>
<div class="c-vignette"></div>
</div>
</div>
</div>
@@ -329,6 +328,26 @@ var imuOverlayState = {
lastUpdateAt: 0
};
var hudRGB = [0, 255, 145];
var xhairSvgOrigHTML = null;
function hudRgba(alpha) {
return 'rgba(' + hudRGB[0] + ',' + hudRGB[1] + ',' + hudRGB[2] + ',' + alpha + ')';
}
function applyHudColor(hex) {
var r = parseInt(hex.slice(0, 2), 16);
var g = parseInt(hex.slice(2, 4), 16);
var b = parseInt(hex.slice(4, 6), 16);
if (isNaN(r) || isNaN(g) || isNaN(b)) return;
hudRGB = [r, g, b];
try { localStorage.setItem('hudHexColor', hex); } catch (e) {}
var svgEl = document.querySelector('.c-xhair svg');
if (!svgEl) return;
if (!xhairSvgOrigHTML) xhairSvgOrigHTML = svgEl.innerHTML;
svgEl.innerHTML = xhairSvgOrigHTML.replace(/rgba\(0,255,145,/g, 'rgba(' + r + ',' + g + ',' + b + ',');
}
function setText(id, text) {
var el = document.getElementById(id);
if (el) {
@@ -357,7 +376,7 @@ function formatSignedNumber(value, digits) {
}
function headingToCompass(deg) {
var dirs = ["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"];
var dirs = ["N","NNO","NO","ONO","O","OSO","SO","SSO","S","SSW","SW","WSW","W","WNW","NW","NNW"];
return dirs[Math.round(((deg % 360) + 360) % 360 / 22.5) % 16];
}
@@ -1141,12 +1160,14 @@ function drawImuHorizonOverlay(context, canvasWidth, canvasHeight, size) {
context.save();
context.translate(cx, cy);
context.rotate(-rollRad);
context.shadowColor = "rgba(0,0,0,.85)";
context.shadowBlur = 3;
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.fillStyle = hudRgba(.88);
context.fill();
context.restore();
@@ -1155,6 +1176,8 @@ function drawImuHorizonOverlay(context, canvasWidth, canvasHeight, size) {
context.translate(cx, cy);
context.rotate(-rollRad);
context.translate(0, pitchOffsetPx);
context.shadowColor = "rgba(0,0,0,.85)";
context.shadowBlur = 2.5;
[
{ y: -33, span: 11, op: .28 }, { y: 33, span: 11, op: .28 },
@@ -1164,12 +1187,12 @@ function drawImuHorizonOverlay(context, canvasWidth, canvasHeight, size) {
context.beginPath();
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.strokeStyle = hudRgba(pl.op);
context.lineWidth = 0.9 * unit;
context.stroke();
});
context.strokeStyle = "rgba(0,255,145,.95)";
context.strokeStyle = hudRgba(.95);
context.lineWidth = 2.8 * unit;
context.beginPath(); context.moveTo(-60 * unit, 0); context.lineTo(60 * unit, 0); context.stroke();
context.beginPath(); context.moveTo(-60 * unit, 0); context.lineTo(-52 * unit, -5 * unit); context.stroke();
@@ -1181,13 +1204,15 @@ function drawImuHorizonOverlay(context, canvasWidth, canvasHeight, size) {
var bw = 84 * unit, bh = 15 * unit;
context.fillStyle = "rgba(0,15,8,.65)";
context.fillRect(cx - bw / 2, cy - 72 * unit, bw, bh);
context.shadowColor = "rgba(0,0,0,.9)";
context.shadowBlur = 3;
context.font = (9 * unit) + 'px "Consolas","Cascadia Mono",monospace';
context.fillStyle = "rgba(0,255,145,.92)";
context.fillStyle = hudRgba(.92);
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("HDG " + String(Math.round(headingDeg)).padStart(3, "0") + "° " + headingToCompass(headingDeg), cx, cy - 62.5 * unit);
context.font = (7.5 * unit) + 'px "Consolas","Cascadia Mono",monospace';
context.fillStyle = "rgba(0,255,145,.72)";
context.font = (10.5 * unit) + 'px "Consolas","Cascadia Mono",monospace';
context.fillStyle = hudRgba(.82);
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();
@@ -1198,67 +1223,76 @@ function drawCrosshairOverlayToCanvas(context, canvasWidth, canvasHeight, size)
var cy = canvasHeight / 2;
var unit = size / 180;
function circle(radius, stroke, lineWidth, dash) {
function circle(radius, alpha, lineWidth, dash) {
context.save();
context.beginPath();
context.arc(cx, cy, radius * unit, 0, Math.PI * 2);
if (dash) context.setLineDash(dash.map(function (value) { return value * unit; }));
context.strokeStyle = stroke;
context.shadowColor = "rgba(0,0,0,.85)";
context.shadowBlur = 2.5;
context.strokeStyle = hudRgba(alpha);
context.lineWidth = lineWidth * unit;
context.stroke();
context.restore();
}
function line(x1, y1, x2, y2, stroke, lineWidth) {
function line(x1, y1, x2, y2, alpha, lineWidth) {
context.save();
context.beginPath();
context.moveTo(cx + (x1 * unit), cy + (y1 * unit));
context.lineTo(cx + (x2 * unit), cy + (y2 * unit));
context.strokeStyle = stroke;
context.shadowColor = "rgba(0,0,0,.85)";
context.shadowBlur = 2.5;
context.strokeStyle = hudRgba(alpha);
context.lineWidth = lineWidth * unit;
context.stroke();
context.restore();
}
function path(points, stroke, lineWidth) {
function path(points, alpha, lineWidth) {
context.save();
context.beginPath();
context.moveTo(cx + (points[0][0] * unit), cy + (points[0][1] * unit));
for (var i = 1; i < points.length; i += 1) {
context.lineTo(cx + (points[i][0] * unit), cy + (points[i][1] * unit));
}
context.strokeStyle = stroke;
context.shadowColor = "rgba(0,0,0,.85)";
context.shadowBlur = 2.5;
context.strokeStyle = hudRgba(alpha);
context.lineWidth = lineWidth * unit;
context.stroke();
context.restore();
}
circle(82, "rgba(0,255,145,.2)", 1, [4, 10]);
circle(60, "rgba(0,255,145,.15)", 0.75, [2, 16]);
circle(16, "rgba(0,255,145,.3)", 0.75);
line(-86, 0, -19, 0, "rgba(0,255,145,.6)", 1);
line(19, 0, 86, 0, "rgba(0,255,145,.6)", 1);
line(0, -86, 0, -19, "rgba(0,255,145,.6)", 1);
line(0, 19, 0, 86, "rgba(0,255,145,.6)", 1);
line(-60, -6, -60, 6, "rgba(0,255,145,.45)", 0.75);
line(60, -6, 60, 6, "rgba(0,255,145,.45)", 0.75);
line(-6, -60, 6, -60, "rgba(0,255,145,.45)", 0.75);
line(-6, 60, 6, 60, "rgba(0,255,145,.45)", 0.75);
line(-38, -3.5, -38, 3.5, "rgba(0,255,145,.3)", 0.5);
line(38, -3.5, 38, 3.5, "rgba(0,255,145,.3)", 0.5);
line(-3.5, -38, 3.5, -38, "rgba(0,255,145,.3)", 0.5);
line(-3.5, 38, 3.5, 38, "rgba(0,255,145,.3)", 0.5);
path([[-74, -58], [-74, -74], [-58, -74]], "rgba(0,255,145,.75)", 1.5);
path([[58, -74], [74, -74], [74, -58]], "rgba(0,255,145,.75)", 1.5);
path([[-74, 58], [-74, 74], [-58, 74]], "rgba(0,255,145,.75)", 1.5);
path([[58, 74], [74, 74], [74, 58]], "rgba(0,255,145,.75)", 1.5);
circle(6, "rgba(0,255,145,.7)", 1);
circle(82, .2, 1, [4, 10]);
circle(60, .15, 0.75, [2, 16]);
circle(16, .3, 0.75);
line(-86, 0, -19, 0, .6, 1);
line(19, 0, 86, 0, .6, 1);
line(0, -86, 0, -19, .6, 1);
line(0, 19, 0, 86, .6, 1);
line(-60, -6, -60, 6, .45, 0.75);
line(60, -6, 60, 6, .45, 0.75);
line(-6, -60, 6, -60, .45, 0.75);
line(-6, 60, 6, 60, .45, 0.75);
line(-38, -3.5, -38, 3.5, .3, 0.5);
line(38, -3.5, 38, 3.5, .3, 0.5);
line(-3.5, -38, 3.5, -38, .3, 0.5);
line(-3.5, 38, 3.5, 38, .3, 0.5);
path([[-74, -58], [-74, -74], [-58, -74]], .75, 1.5);
path([[58, -74], [74, -74], [74, -58]], .75, 1.5);
path([[-74, 58], [-74, 74], [-58, 74]], .75, 1.5);
path([[58, 74], [74, 74], [74, 58]], .75, 1.5);
circle(6, .7, 1);
context.save();
context.shadowColor = "rgba(0,0,0,.85)";
context.shadowBlur = 3;
context.beginPath();
context.arc(cx, cy, 2.5 * unit, 0, Math.PI * 2);
context.fillStyle = "rgba(0,255,145,.9)";
context.fillStyle = hudRgba(.9);
context.fill();
context.shadowBlur = 0;
context.beginPath();
context.arc(cx, cy, 1 * unit, 0, Math.PI * 2);
context.fillStyle = "rgba(255,255,255,.7)";
@@ -1271,17 +1305,9 @@ function drawCrosshairOverlayToCanvas(context, canvasWidth, canvasHeight, size)
function drawVignetteAndScanlines(context, canvasWidth, canvasHeight) {
context.save();
for (var y = 0; y < canvasHeight; y += 4) {
context.fillStyle = "rgba(0,255,145,.012)";
context.fillStyle = hudRgba(.012);
context.fillRect(0, y, canvasWidth, 1);
}
var vignette = context.createRadialGradient(
canvasWidth * 0.5, canvasHeight * 0.5, canvasWidth * 0.25,
canvasWidth * 0.5, canvasHeight * 0.5, canvasWidth * 0.75
);
vignette.addColorStop(0, "rgba(0,0,0,0)");
vignette.addColorStop(1, "rgba(0,0,0,.58)");
context.fillStyle = vignette;
context.fillRect(0, 0, canvasWidth, canvasHeight);
context.restore();
}
@@ -1339,7 +1365,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, 270 * camScale * scaleToCanvas);
drawCrosshairOverlayToCanvas(context, canvasWidth, canvasHeight, 405 * camScale * scaleToCanvas);
drawVignetteAndScanlines(context, canvasWidth, canvasHeight);
}
@@ -1544,7 +1570,12 @@ function toggleStatPanel() {
setStatPanelCollapsed(!panel.classList.contains("collapsed"));
}
window.addEventListener("storage", function (e) {
if (e.key === "hudHexColor" && e.newValue) applyHudColor(e.newValue);
});
window.addEventListener("load", function () {
try { var h = localStorage.getItem("hudHexColor"); if (h) applyHudColor(h); } catch (e) {}
setText("cam-host", hostUrl);
updateModeDisplay();
updateMotorDisplay();