3. 导航箭头动态指示
任务目标
在 HUD 画布上根据模拟导航数据绘制转向箭头,并让箭头随转向角度平滑过渡。核心是:导航数据 → 目标角度 → 缓动插值 → 每帧重绘。
实现思路
导航数据每 1.5 秒更新一次目标角度,渲染循环用 requestAnimationFrame 以固定缓动系数把当前角度逼近目标角度,实现平滑转向动画。
完整代码
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>HUD 导航箭头</title>
<style>
body { margin:0; background:#111; display:flex; justify-content:center; align-items:center; height:100vh; }
canvas { background:#0a0a1a; border-radius:12px; }
</style></head>
<body>
<canvas id="hud" width="480" height="480"></canvas>
<script>
const canvas = document.getElementById('hud');
const ctx = canvas.getContext('2d');
const CX = canvas.width / 2, CY = canvas.height / 2;
// 模拟导航数据:角度(度, 0=正上方, 顺时针) 与剩余距离(米)
const navData = [
{ angle: 0, dist: 200 },
{ angle: 45, dist: 150 },
{ angle: 90, dist: 100 },
{ angle: -60, dist: 80 },
{ angle: 0, dist: 30 }
];
let targetAngle = navData[0].angle; // 目标角度
let currentAngle = navData[0].angle; // 当前渲染角度
let dist = navData[0].dist;
let idx = 0;
// 每 1.5 秒切换一条导航数据
setInterval(() => {
idx = (idx + 1) % navData.length;
targetAngle = navData[idx].angle;
dist = navData[idx].dist;
}, 1500);
// 角度缓动:处理 -180~180 的最短路径
function lerpAngle(cur, target, t) {
let diff = ((target - cur + 540) % 360) - 180;
return cur + diff * t;
}
function drawArrow(angleDeg) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 外圈刻度
ctx.strokeStyle = '#2a2a4a';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(CX, CY, 180, 0, Math.PI * 2);
ctx.stroke();
// 剩余距离文字
ctx.fillStyle = '#7ec8ff';
ctx.font = '20px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(dist + ' m', CX, CY + 120);
// 旋转箭头
ctx.save();
ctx.translate(CX, CY);
ctx.rotate(angleDeg * Math.PI / 180);
ctx.fillStyle = '#00e5ff';
ctx.shadowColor = '#00e5ff';
ctx.shadowBlur = 18;
ctx.beginPath();
ctx.moveTo(0, -110); // 箭头尖端
ctx.lineTo(-45, 20);
ctx.lineTo(-15, 20);
ctx.lineTo(-15, 70);
ctx.lineTo(15, 70);
ctx.lineTo(15, 20);
ctx.lineTo(45, 20);
ctx.closePath();
ctx.fill();
ctx.restore();
}
// 渲染循环:每帧向目标角度逼近 12%
function loop() {
currentAngle = lerpAngle(currentAngle, targetAngle, 0.12);
drawArrow(currentAngle);
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>
运行与验证
- 将代码保存为
hud_arrow.html,用浏览器直接打开。 - 观察画布中央的青色箭头:每 1.5 秒目标角度切换一次,箭头应平滑旋转到新方向,而非瞬间跳变。
- 箭头下方距离数字随导航数据同步更新。
- 通过条件:箭头旋转过程连续无跳变;角度从 90° 切到 -60° 时走最短路径(顺时针 150° 而非逆时针 210°)。
关键点
lerpAngle用((target - cur + 540) % 360) - 180把角度差归一化到 -180~180,避免绕远路。- 缓动系数 0.12 决定动画速度:越大越快,越小越平滑。可调此值观察效果。
- 真实 HUD 中把
navData替换为 CAN/以太网解析出的导航信号即可,渲染逻辑不变。