This commit is contained in:
legop3
2025-11-17 19:40:50 -05:00
parent 0c83df7933
commit 8c40c08b57
3 changed files with 51 additions and 7 deletions
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -5,7 +5,7 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>webui</title> <title>webui</title>
<script type="module" crossorigin src="/assets/index-BgmPrDPA.js"></script> <script type="module" crossorigin src="/assets/index-DwtMH0qf.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Dk59njim.css"> <link rel="stylesheet" crossorigin href="/assets/index-Dk59njim.css">
</head> </head>
<body> <body>
+46 -2
View File
@@ -1,5 +1,8 @@
import { useEffect, useRef, useState } from 'react';
import { useDriveControl } from '../context/DriveControlContext.jsx'; import { useDriveControl } from '../context/DriveControlContext.jsx';
const SLIDER_THROTTLE_MS = 150;
function formatDegrees(value) { function formatDegrees(value) {
if (typeof value !== 'number' || Number.isNaN(value)) return '—'; if (typeof value !== 'number' || Number.isNaN(value)) return '—';
return `${value > 0 ? '+' : ''}${value.toFixed(1)}°`; return `${value > 0 ? '+' : ''}${value.toFixed(1)}°`;
@@ -20,15 +23,53 @@ export default function CameraServoPanel() {
if (!enabled) return null; if (!enabled) return null;
const [pendingAngle, setPendingAngle] = useState(value);
const throttleRef = useRef(null);
const draggingRef = useRef(false);
useEffect(() => {
if (!draggingRef.current) {
setPendingAngle(value);
}
}, [value]);
useEffect(
() => () => {
if (throttleRef.current) {
clearTimeout(throttleRef.current);
}
},
[],
);
const step = const step =
typeof config?.nudgeDegrees === 'number' && config.nudgeDegrees > 0 typeof config?.nudgeDegrees === 'number' && config.nudgeDegrees > 0
? config.nudgeDegrees ? config.nudgeDegrees
: 1; : 1;
const scheduleSend = (next) => {
if (throttleRef.current) {
clearTimeout(throttleRef.current);
}
throttleRef.current = setTimeout(() => {
servo.setAngle(next);
}, SLIDER_THROTTLE_MS);
};
const handleSlider = (event) => { const handleSlider = (event) => {
const next = Number.parseFloat(event.target.value); const next = Number.parseFloat(event.target.value);
if (Number.isNaN(next)) return; if (Number.isNaN(next)) return;
servo.setAngle(next); draggingRef.current = true;
setPendingAngle(next);
scheduleSend(next);
};
const commitSlider = () => {
draggingRef.current = false;
if (throttleRef.current) {
clearTimeout(throttleRef.current);
}
servo.setAngle(pendingAngle);
}; };
const handleNudge = (direction) => { const handleNudge = (direction) => {
@@ -49,8 +90,11 @@ export default function CameraServoPanel() {
min={min} min={min}
max={max} max={max}
step={0.5} step={0.5}
value={value} value={pendingAngle}
onChange={handleSlider} onChange={handleSlider}
onMouseUp={commitSlider}
onTouchEnd={commitSlider}
onPointerUp={commitSlider}
/> />
<div className="mt-1 flex justify-between text-xs text-slate-400"> <div className="mt-1 flex justify-between text-xs text-slate-400">
<span>{formatDegrees(min)}</span> <span>{formatDegrees(min)}</span>