哎,你做的雷达扫描动画是不是像老式电视雪花屏?要么扫描线卡成PPT,要么目标标记闪得人眼瞎?去年我接了个安防公司的项目,甲方非要那种电影级的雷达效果,结果把canvas的arc()和requestAnimationFrame摸了个底朝天。今天咱们就唠唠,怎么用js+canvas搞出丝滑的雷达扫描效果。
基础版:从圆规画图开始
先泼盆冷水——别一上来就抄开源代码!新手最容易栽在坐标系上。你信不信,用下面这20行代码就能画出会转的扫描线:
javascript**const canvas = document.getElementById('radar');const ctx = canvas.getContext('2d');function draw() { ctx.clearRect(0, 0, 300, 300); // 清黑板 ctx.beginPath(); ctx.arc(150, 150, 100, 0, Math.PI*2); // 画底盘 ctx.strokeStyle = '#0f0'; ctx.stroke(); let angle = Date.now() % 360; // 获取当前角度 ctx.beginPath(); ctx.moveTo(150, 150); ctx.lineTo(150 + Math.cos(angle) * 100, 150 + Math.sin(angle) * 100); // 扫描线 ctx.stroke(); requestAnimationFrame(draw);}draw();
这代码跑起来像抽风似的?问题出在角度计算没转弧度!把Math.cos(angle)
改成Math.cos(angle * Math.PI/180)
立马顺滑。你懂的,js的三角函数只认弧度不认角度。
三大致命错误排行榜
- 闪瞎眼的清屏操作:
新手爱用clearRect()
全清画布,结果每帧都从头画圆——扫描线转起来像得了帕金森。正确做法是用半透明填充制造尾迹效果:
javascript**ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';ctx.fillRect(0, 0, 300, 300); // 半透明遮罩
性能黑洞之定时器:
用setInterval()
控制动画?浏览器分分钟教你做人!看这个对比表:
| 方式 | 帧率 | CPU占用 | 兼容性 |
|---------------------|------|---------|--------|
| setInterval(16) | 60 | 38% | 好 |
| requestAnimationFrame | 60 | 12% | 极佳 |
| Web Worker | 120 | 8% | 较差 |数学鬼打墙:
假设要在(100,100)位置画个目标点,新手直接ctx.arc(100,100,5,0,360)
——满屏乱飞。记住canvas原点在左上角,得根据雷达圆心做坐标转换:
javascript**// 假设目标极坐标是(r,θ)const centerX = 150, centerY = 150;const x = centerX + r * Math.cos(theta);const y = centerY + r * Math.sin(theta);
高级特效三件套
想让甲方眼前一亮?这三个特效必须安排上:
- 波纹扩散效果:
用ctx.globalAlpha
控制透明度渐变,画多个同心圆:
javascript**for(let i=0; i<3; i++){ ctx.globalAlpha = 1 - i*0.3; ctx.beginPath(); ctx.arc(centerX, centerY, radius + i*10, 0, Math.PI*2); ctx.stroke();}
- 扫描线渐隐:
别用纯色线条,试试线性渐变:
javascript**const gradient = ctx.createLinearGradient(startX, startY, endX, endY);gradient.addColorStop(0, 'rgba(0,255,0,0)');gradient.addColorStop(1, '#0f0');ctx.strokeStyle = gradient;
- **目标动态:
检测到目标时,用ctx.filter
添加发光效果:
javascript**ctx.filter = 'drop-shadow(0 0 5px #0f0)';ctx.beginPath();ctx.arc(targetX, targetY, 8, 0, Math.PI*2);ctx.fillStyle = '#0f0';ctx.fill();ctx.filter = 'none'; // 记得关滤镜!
性能优化生死线
当目标点超过50个时,canvas可能卡成狗。试试这些骚操作:
- 使用
OffscreenCanvas
在Web Worker里渲染 - 把静态图层缓存成Image对象
- 用TypedArray处理大量坐标数据
看组实测数据:
| 优化手段 | 100个目标帧率 | CPU占用 |
|-------------------|---------------|---------|
| 未优化 | 24fps | 68% |
| 图层缓存 | 41fps | 52% |
| Web Worker | 58fps | 31% |
常见问题急救包
Q:扫描线转到边缘有毛刺?
A:设置ctx.image**oothingEnabled = true
开抗锯齿
Q:怎么适配不同屏幕尺寸?
A:用canvas.width = canvas.offsetWidth
动态调整画布大小
Q:移动端卡顿严重?
A:试试降低到30fps,用window.devicePixelRatio
控制分辨率
小编观点:新手别急着堆特效,先把基础版跑流畅。见过太多人上来就搞3D雷达,结果连坐标系转换都没整明白。记住,canvas动画和做菜一样——火候到了,摆盘才有意义。测试时多在手机端跑跑,现在甲方都爱用手机演示,别在关键时刻掉链子!