Alles verbessert
This commit is contained in:
@@ -187,6 +187,12 @@ header {
|
||||
color: #fff;
|
||||
box-shadow: 0 0 24px rgba(0,136,255,.45), inset 0 0 16px rgba(255,255,255,.1);
|
||||
}
|
||||
@keyframes mode-flash {
|
||||
0% { box-shadow: 0 0 0px rgba(0,255,145,0), background-color: var(--pri); }
|
||||
30% { box-shadow: 0 0 28px rgba(0,255,145,.9), background-color: #00ff91; }
|
||||
100% { box-shadow: 0 0 24px rgba(0,136,255,.45), background-color: var(--pri); }
|
||||
}
|
||||
.dbtn.flash { animation: mode-flash .5s ease-out forwards; }
|
||||
|
||||
#cam-panel { flex: 1; display: flex; flex-direction: column; min-height: 0; }
|
||||
.cam-port {
|
||||
@@ -205,19 +211,6 @@ header {
|
||||
background: #05070d;
|
||||
z-index: 1;
|
||||
}
|
||||
.c-scanlines {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 5;
|
||||
background: repeating-linear-gradient(
|
||||
0deg,
|
||||
transparent,
|
||||
transparent 3px,
|
||||
rgba(0,0,0,.09) 3px,
|
||||
rgba(0,0,0,.09) 4px
|
||||
);
|
||||
}
|
||||
.c-vignette {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
@@ -230,42 +223,19 @@ header {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
}
|
||||
.c-xhair::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 1px;
|
||||
background: rgba(0,255,145,.45);
|
||||
transform: translateY(-50%);
|
||||
@keyframes xh-spin { to { transform: rotate(360deg); } }
|
||||
@keyframes xh-pulse {
|
||||
0% { transform: scale(1); opacity: .7; }
|
||||
100% { transform: scale(2.8); opacity: 0; }
|
||||
}
|
||||
.c-xhair::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 1px;
|
||||
background: rgba(0,255,145,.45);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.xc {
|
||||
position: absolute;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
border-color: rgba(0,255,145,.7);
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
.xc.tl { top: 0; left: 0; border-top-width: 1.5px; border-left-width: 1.5px; }
|
||||
.xc.tr { top: 0; right: 0; border-top-width: 1.5px; border-right-width: 1.5px; }
|
||||
.xc.bl { bottom: 0; left: 0; border-bottom-width: 1.5px; border-left-width: 1.5px; }
|
||||
.xc.br { bottom: 0; right: 0; border-bottom-width: 1.5px; border-right-width: 1.5px; }
|
||||
.xh-rot { animation: xh-spin 14s linear infinite; transform-box: fill-box; transform-origin: center; }
|
||||
.xh-rot-rev { animation: xh-spin 8s linear infinite reverse; transform-box: fill-box; transform-origin: center; }
|
||||
.xh-pulse { animation: xh-pulse 2.5s ease-out infinite; transform-box: fill-box; transform-origin: center; }
|
||||
.c-rec {
|
||||
position: absolute;
|
||||
top: 13px;
|
||||
@@ -328,11 +298,20 @@ header {
|
||||
.sval.g { color: var(--ok); }
|
||||
.sval.o { color: var(--sec); }
|
||||
.sval.b { color: var(--pri); }
|
||||
.sval.alert {
|
||||
color: #D50000;
|
||||
animation: uv-blink 0.9s step-end infinite;
|
||||
}
|
||||
.sval.warntext { color: var(--sec); }
|
||||
.sval-conn { display: flex; align-items: center; gap: 5px; color: var(--ok); font-size: 10px; }
|
||||
.sbar-wrap { display: flex; align-items: center; gap: 8px; }
|
||||
.sbar { width: 52px; height: 3px; background: rgba(0,136,255,.12); border-radius: 1px; overflow: hidden; }
|
||||
.sbar-i { height: 100%; border-radius: 1px; background: var(--pri); }
|
||||
.sbar-i.w { background: var(--sec); }
|
||||
@keyframes uv-blink {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.2; }
|
||||
}
|
||||
|
||||
#joy-panel .p-hdr { padding: 14px 12px; }
|
||||
.mode-toggle { display: flex; gap: 2px; margin-left: auto; }
|
||||
@@ -563,10 +542,41 @@ header {
|
||||
STREAM: 8081
|
||||
</div>
|
||||
<div class="c-xhair">
|
||||
<div class="xc tl"></div><div class="xc tr"></div>
|
||||
<div class="xc bl"></div><div class="xc br"></div>
|
||||
<svg viewBox="-90 -90 180 180" xmlns="http://www.w3.org/2000/svg" width="180" height="180">
|
||||
<!-- äußerer rotierender Strichelring -->
|
||||
<circle class="xh-rot" cx="0" cy="0" r="82" fill="none" stroke="rgba(0,255,145,.2)" stroke-width="1" stroke-dasharray="4 10"/>
|
||||
<!-- mittlerer Ring, Gegenrichtung -->
|
||||
<circle class="xh-rot-rev" cx="0" cy="0" r="60" fill="none" stroke="rgba(0,255,145,.15)" stroke-width=".75" stroke-dasharray="2 16"/>
|
||||
<!-- innerer fester Ring -->
|
||||
<circle cx="0" cy="0" r="16" fill="none" stroke="rgba(0,255,145,.3)" stroke-width=".75"/>
|
||||
<!-- Kreuzlinien mit Lücke in der Mitte -->
|
||||
<line x1="-86" y1="0" x2="-19" y2="0" stroke="rgba(0,255,145,.6)" stroke-width="1"/>
|
||||
<line x1="19" y1="0" x2="86" y2="0" stroke="rgba(0,255,145,.6)" stroke-width="1"/>
|
||||
<line x1="0" y1="-86" x2="0" y2="-19" stroke="rgba(0,255,145,.6)" stroke-width="1"/>
|
||||
<line x1="0" y1="19" x2="0" y2="86" stroke="rgba(0,255,145,.6)" stroke-width="1"/>
|
||||
<!-- Skalenstriche bei r=60 -->
|
||||
<line x1="-60" y1="-6" x2="-60" y2="6" stroke="rgba(0,255,145,.45)" stroke-width=".75"/>
|
||||
<line x1="60" y1="-6" x2="60" y2="6" stroke="rgba(0,255,145,.45)" stroke-width=".75"/>
|
||||
<line x1="-6" y1="-60" x2="6" y2="-60" stroke="rgba(0,255,145,.45)" stroke-width=".75"/>
|
||||
<line x1="-6" y1="60" x2="6" y2="60" stroke="rgba(0,255,145,.45)" stroke-width=".75"/>
|
||||
<!-- Skalenstriche bei r=38 -->
|
||||
<line x1="-38" y1="-3.5" x2="-38" y2="3.5" stroke="rgba(0,255,145,.3)" stroke-width=".5"/>
|
||||
<line x1="38" y1="-3.5" x2="38" y2="3.5" stroke="rgba(0,255,145,.3)" stroke-width=".5"/>
|
||||
<line x1="-3.5" y1="-38" x2="3.5" y2="-38" stroke="rgba(0,255,145,.3)" stroke-width=".5"/>
|
||||
<line x1="-3.5" y1="38" x2="3.5" y2="38" stroke="rgba(0,255,145,.3)" stroke-width=".5"/>
|
||||
<!-- Eckklammern -->
|
||||
<path d="M-74,-58 L-74,-74 L-58,-74" fill="none" stroke="rgba(0,255,145,.75)" stroke-width="1.5"/>
|
||||
<path d="M58,-74 L74,-74 L74,-58" fill="none" stroke="rgba(0,255,145,.75)" stroke-width="1.5"/>
|
||||
<path d="M-74,58 L-74,74 L-58,74" fill="none" stroke="rgba(0,255,145,.75)" stroke-width="1.5"/>
|
||||
<path d="M58,74 L74,74 L74,58" fill="none" stroke="rgba(0,255,145,.75)" stroke-width="1.5"/>
|
||||
<!-- pulsierender Ring -->
|
||||
<circle class="xh-pulse" cx="0" cy="0" r="6" fill="none" stroke="rgba(0,255,145,.7)" stroke-width="1"/>
|
||||
<!-- Mittelpunkt -->
|
||||
<circle cx="0" cy="0" r="2.5" fill="rgba(0,255,145,.9)"/>
|
||||
<circle cx="0" cy="0" r="1" fill="rgba(255,255,255,.7)"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="c-scanlines"></div>
|
||||
|
||||
<div class="c-vignette"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -633,6 +643,10 @@ header {
|
||||
<span class="slbl">IP Adressen</span>
|
||||
<span class="sval b" id="stat-ips">--</span>
|
||||
</div>
|
||||
<div class="srow warn">
|
||||
<span class="slbl">Unterspannung</span>
|
||||
<span class="sval b" id="stat-undervoltage">--</span>
|
||||
</div>
|
||||
<div class="srow info">
|
||||
<span class="slbl">Uptime Pi</span>
|
||||
<span class="sval b" id="stat-uptime">--</span>
|
||||
@@ -704,6 +718,7 @@ header {
|
||||
var hostUrl = window.location.hostname;
|
||||
var ros = null;
|
||||
var joyListener = null;
|
||||
var roverCommandListener = null;
|
||||
var publishTimer = null;
|
||||
var statusTimer = null;
|
||||
var axes = [0, 0, 0, 0, 0, 0];
|
||||
@@ -771,6 +786,45 @@ function updateModeDisplay() {
|
||||
setText("stat-mode", label);
|
||||
}
|
||||
|
||||
function applyDriveMode(mode, flash) {
|
||||
var changed = mode !== driveMode;
|
||||
driveMode = mode;
|
||||
document.querySelectorAll(".dbtn[data-mode]").forEach(function (btn) {
|
||||
var isActive = btn.dataset.mode === mode;
|
||||
btn.classList.toggle("active", isActive);
|
||||
if (isActive && changed && flash) {
|
||||
btn.classList.remove("flash");
|
||||
void btn.offsetWidth;
|
||||
btn.classList.add("flash");
|
||||
}
|
||||
});
|
||||
updateModeDisplay();
|
||||
updateControlLocks();
|
||||
}
|
||||
|
||||
function mirrorJoyThumb(x, y) {
|
||||
if (dragging || inputMode !== "joystick") return;
|
||||
var data = joyMetrics();
|
||||
var dx = x * data.maxD;
|
||||
var dy = -y * data.maxD;
|
||||
var thumb = document.getElementById("jthumb");
|
||||
thumb.style.transition = "left .05s, top .05s";
|
||||
thumb.style.left = "calc(50% + " + dx + "px)";
|
||||
thumb.style.top = "calc(50% + " + dy + "px)";
|
||||
thumb.style.transform = "translate(-50%,-50%)";
|
||||
updateAxesDisplay(x, y);
|
||||
}
|
||||
|
||||
function locomotionModeToUi(modeValue) {
|
||||
if (modeValue === 2) {
|
||||
return "turn-on-point";
|
||||
}
|
||||
if (modeValue === 3) {
|
||||
return "crab";
|
||||
}
|
||||
return "ackermann";
|
||||
}
|
||||
|
||||
function updateMotorDisplay() {
|
||||
setText("stat-motors", motorsEnabled ? "Aktiv" : "Aus");
|
||||
}
|
||||
@@ -787,11 +841,35 @@ function setRosStatus(text) {
|
||||
setText("mission-state", text === "Verbunden" ? "Nominal" : text);
|
||||
}
|
||||
|
||||
function updateUndervoltageDisplay(text, state) {
|
||||
var el = document.getElementById("stat-undervoltage");
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
el.textContent = text || "--";
|
||||
el.classList.remove("b", "g", "o", "alert", "warntext");
|
||||
|
||||
if (state === "active") {
|
||||
el.classList.add("alert");
|
||||
return;
|
||||
}
|
||||
if (state === "past") {
|
||||
el.classList.add("warntext");
|
||||
return;
|
||||
}
|
||||
if (state === "clear") {
|
||||
el.classList.add("g");
|
||||
return;
|
||||
}
|
||||
el.classList.add("b");
|
||||
}
|
||||
|
||||
function updateServiceState(payload) {
|
||||
var system = payload.system || {};
|
||||
var services = payload.services || {};
|
||||
setText("stat-wifi", system.wifi || "unbekannt");
|
||||
setText("stat-ips", system.ips || "unbekannt");
|
||||
updateUndervoltageDisplay(system.undervoltage || "unbekannt", system.undervoltage_state || "unknown");
|
||||
setText("stat-uptime", system.uptime || "unbekannt");
|
||||
setText("stat-disk", system.disk_free || "unbekannt");
|
||||
setText("val-cpu", system.cpu_usage || "--");
|
||||
@@ -832,10 +910,10 @@ function publishJoy() {
|
||||
}
|
||||
|
||||
function startPublishing() {
|
||||
publishJoy();
|
||||
if (publishTimer) {
|
||||
clearInterval(publishTimer);
|
||||
return;
|
||||
}
|
||||
publishJoy();
|
||||
publishTimer = window.setInterval(publishJoy, 50);
|
||||
}
|
||||
|
||||
@@ -868,12 +946,7 @@ function pulseButton(buttonIndex) {
|
||||
}
|
||||
|
||||
function selectDriveMode(mode, buttonIndex) {
|
||||
driveMode = mode;
|
||||
document.querySelectorAll(".dbtn[data-mode]").forEach(function (btn) {
|
||||
btn.classList.toggle("active", btn.dataset.mode === mode);
|
||||
});
|
||||
updateModeDisplay();
|
||||
updateControlLocks();
|
||||
applyDriveMode(mode);
|
||||
pulseButton(buttonIndex);
|
||||
}
|
||||
|
||||
@@ -940,6 +1013,7 @@ function moveThumb(clientX, clientY) {
|
||||
var nx = dx / data.maxD;
|
||||
var ny = -dy / data.maxD;
|
||||
setAxes(nx, ny);
|
||||
publishJoy();
|
||||
startPublishing();
|
||||
}
|
||||
|
||||
@@ -1013,6 +1087,30 @@ window.addEventListener("load", function () {
|
||||
messageType: "sensor_msgs/Joy"
|
||||
});
|
||||
|
||||
roverCommandListener = new ROSLIB.Topic({
|
||||
ros: ros,
|
||||
name: "/rover_command",
|
||||
messageType: "exomy/RoverCommand"
|
||||
});
|
||||
|
||||
roverCommandListener.subscribe(function (message) {
|
||||
applyDriveMode(locomotionModeToUi(message.locomotion_mode), true);
|
||||
motorsEnabled = !!message.motors_enabled;
|
||||
updateMotorDisplay();
|
||||
});
|
||||
|
||||
var joySubscriber = new ROSLIB.Topic({
|
||||
ros: ros,
|
||||
name: "/joy",
|
||||
messageType: "sensor_msgs/Joy"
|
||||
});
|
||||
joySubscriber.subscribe(function (message) {
|
||||
if (message.header.frame_id === "webgui") return;
|
||||
var x = (message.axes[0] || 0);
|
||||
var y = -(message.axes[1] || 0);
|
||||
mirrorJoyThumb(x, y);
|
||||
});
|
||||
|
||||
document.querySelectorAll(".dbtn[data-mode]").forEach(function (button) {
|
||||
button.addEventListener("click", function () {
|
||||
selectDriveMode(button.dataset.mode, parseInt(button.dataset.button, 10));
|
||||
|
||||
Reference in New Issue
Block a user