You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化Canvas实现的高CPU占用JavaScript光标跟随动画

Canvas光标跟随拖尾动画性能优化

该动画基于Вася Воронцов的回答实现,目前存在设备资源占用过高的问题。我使用Canvas实现该动画,效果为光线跟随光标移动并留下拖尾,功能运行正常,但处理器负载非常高。

当前动画通过存储坐标数据实现圆形轨迹的半径调整和自动删除逻辑。

动画效果可通过修改以下变量控制:

  • radius(圆形半径)
  • period(圆形消失时长)
  • color(圆形颜色)
  • blur(模糊半径)
  • cursor radius(指针圆形半径)

请问如何优化该动画,降低其对设备的资源占用?


原有实现代码

HTML

<canvas id="canvas"></canvas>

CSS

body {
  height: 100%;
  width: 100%;
  position: absolute;
  cursor: none;
  margin: 0;
}

JavaScript

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = document.body.offsetWidth;
var height = document.body.offsetHeight;
var points = [], 
    cursor = [-10, -10];
var t = 0;

var radius = 100;
var period = 2100;
var color = "rgba(239, 91, 59, .5)";
var blur = 600;

canvas.style.width = canvas.width = width;
canvas.style.height = canvas.height = height;
context.fillStyle = color;
var filter = context.filter = "blur(" + 50 + "px)";
var dr = radius / period;

function draw() {
  context.clearRect(0, 0, width, height);
  let i = 0;
  let deleted = 0;
  let dt = -t + (t = window.performance.now());
  context.beginPath();
  while (i++ < points.length-1) {
    let p = points[i];
    p[2] += dt;
    let r = radius - p[2] * dr;
    context.moveTo(p[0], p[1]);
    if (p[2] <= period) {
      context.arc(p[0], p[1], r, 0, 2*Math.PI, true);
    } else deleted = i;
  }
  context.fill();
  points.splice(0, deleted);
  context.beginPath();
  context.arc(cursor[0], cursor[1], 20, 0, 2*Math.PI, true);
  context.filter = "none";
  context.fill();
  context.filter = filter;
  window.requestAnimationFrame(draw);
}

window.onmousemove = function(event) {
  let x = event.pageX;
  let y = event.pageY;
  let backwardX = 0;
  let backwardY = 0;

  backwardX += (x-backwardX) / 5
  backwardY += (y-backwardY) / 5

  points.push([x, y, 0]);
  cursor = [x, y];
}

t = window.performance.now();
window.requestAnimationFrame(draw);

优化方案

原有代码的性能损耗主要来自四个核心问题:鼠标移动时无限制插入采样点、每帧全局应用模糊滤镜、冗余Canvas API调用、频繁数组重排,对应优化措施如下:

  1. 限制采样点密度
    鼠标移动事件每秒可触发上百次,不需要每次都存储点位。可以加双重限制:两次采样间隔不小于16ms(和屏幕刷新率对齐)、两次采样坐标差不小于5px,可直接将点位数组长度压缩到原有1/10以下。
  2. 替换全局模糊实现
    全画布实时模糊是性能开销最大的部分,可改用离屏Canvas预渲染带模糊的圆形图案,每帧直接调用drawImage绘制预渲染资源,无需每帧做模糊计算。如果可以接受拖尾效果微调,还可以直接去掉全屏清空逻辑,改为每帧叠加半透明蒙层实现自然淡出,连点位生命周期计算逻辑都可以省略,性能提升最明显。
  3. 删除冗余操作
    绘制arc前不需要额外调用moveTo定位,删除该冗余调用可减少无效API开销。同时可改用环形队列存储点位,避免splice删除数组头部元素时引发的全数组重排开销。
  4. 分层渲染光标
    光标不需要和拖尾共用同一个画布,可单独用小Canvas或者DOM元素渲染光标,避免每帧反复切换filter属性,减少浏览器状态切换开销。

内容的提问来源于stack exchange,提问作者Bakhtiyar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 16:54:07