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

如何修改particle.js实现点击创建粒子及链接颜色脉冲效果

改造particle.js实现点击脉冲粒子效果

先搞懂particle.js的核心结构(不用啃全量代码)

particle.js的核心是pJS实例,初始化后就能拿到这个对象,重点关注这几个关键部分:

  • pJS.particles.array:存储所有粒子的数组,每个元素是Particle对象,包含x/y坐标、color颜色、size大小等属性
  • pJS.links.array:存储粒子间连线的数组,每个元素是Link对象,记录连接的两个粒子(particleA和particleB)
  • 动画循环:靠requestAnimationFrame驱动,每帧先执行pJS.fn.particles.update()更新粒子状态,再执行pJS.fn.canvas.draw()重绘画面

具体修改步骤&代码

1. 初始化particle.js并扩展脉冲属性

先按需求完成基础初始化,再给粒子和链接添加脉冲相关的状态属性:

// 初始化particle.js,基础配置可按需调整
const pJS = particlesJS('particles-js', {
  particles: {
    number: { value: 10 },
    color: { value: '#ffffff' },
    size: { value: 5 },
    line_linked: { enable: true, distance: 150, color: '#ffffff', opacity: 0.4, width: 1 }
  },
  interactivity: {
    events: { onhover: { enable: false } } // 先关闭hover避免干扰脉冲逻辑
  },
  retina_detect: true
});

// 给现有粒子添加脉冲状态
pJS.particles.array.forEach(particle => {
  particle.isPulsing = false;
  particle.pulseProgress = 0;
  particle.pulseColor = '#ff0000';
});

// 给现有连线添加脉冲状态
pJS.links.array.forEach(link => {
  link.hasPulse = false;
  link.pulseProgress = 0;
  link.pulseColor = '#ff0000';
});

2. 添加点击创建粒子逻辑

监听页面点击事件,在点击位置生成新粒子,并触发初始脉冲:

document.addEventListener('click', (e) => {
  // 转换点击坐标为canvas内的相对坐标
  const rect = pJS.canvas.el.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;

  // 用particle.js自带的构造函数创建新粒子
  const newParticle = new pJS.fn.particles.Particle();
  newParticle.x = x;
  newParticle.y = y;
  newParticle.color = { value: '#ffffff' };
  newParticle.isPulsing = true; // 标记为正在脉冲
  newParticle.pulseProgress = 0;
  newParticle.pulseColor = '#ff0000';

  // 将新粒子加入粒子数组
  pJS.particles.array.push(newParticle);

  // 触发初始脉冲传递
  triggerPulse(newParticle);
});

3. 实现脉冲传递&状态更新逻辑

写函数处理脉冲触发和传递,并重写原动画更新函数加入脉冲进度控制:

// 触发粒子脉冲,传递给所有相连的粒子
function triggerPulse(particle) {
  // 筛选当前粒子的所有连接
  const connectedLinks = pJS.links.array.filter(link => 
    link.particleA === particle || link.particleB === particle
  );

  connectedLinks.forEach(link => {
    // 标记链接处于脉冲状态
    link.hasPulse = true;
    link.pulseProgress = 0;
    link.pulseColor = particle.pulseColor;

    // 找到链接的另一端粒子
    const targetParticle = link.particleA === particle ? link.particleB : link.particleA;

    // 延迟模拟脉冲传递时间,之后触发目标粒子的脉冲
    setTimeout(() => {
      if (!targetParticle.isPulsing) {
        targetParticle.isPulsing = true;
        targetParticle.pulseProgress = 0;
        targetParticle.pulseColor = particle.pulseColor;
        // 递归触发目标粒子的脉冲传递
        triggerPulse(targetParticle);
      }
    }, 500); // 传递延迟可按需调整
  });
}

// 重写粒子更新函数,加入脉冲进度更新
const originalUpdateParticles = pJS.fn.particles.update;
pJS.fn.particles.update = function() {
  originalUpdateParticles.call(this); // 先执行原有的粒子更新逻辑

  // 更新每个粒子的脉冲进度
  this.particles.array.forEach(particle => {
    if (particle.isPulsing) {
      particle.pulseProgress += 0.02;
      // 进度到1时结束脉冲
      if (particle.pulseProgress >= 1) {
        particle.isPulsing = false;
        particle.pulseProgress = 0;
      }
    }
  });

  // 更新每个链接的脉冲进度
  this.links.array.forEach(link => {
    if (link.hasPulse) {
      link.pulseProgress += 0.02;
      if (link.pulseProgress >= 1) {
        link.hasPulse = false;
        link.pulseProgress = 0;
      }
    }
  });
};

4. 修改渲染函数,绘制脉冲视觉效果

重写原有的粒子和连线绘制函数,根据脉冲状态动态调整颜色:

// 重写粒子绘制函数
const originalDrawParticle = pJS.fn.canvas.drawParticle;
pJS.fn.canvas.drawParticle = function(particle) {
  // 脉冲时混合原颜色和脉冲颜色,按进度过渡
  if (particle.isPulsing) {
    const originalColor = particle.color.value;
    const pulseColor = particle.pulseColor;
    const mixedColor = mixColors(originalColor, pulseColor, particle.pulseProgress);
    particle.color.value = mixedColor;
  }

  originalDrawParticle.call(this, particle);

  // 绘制完成后恢复原颜色,避免影响下一帧
  if (particle.isPulsing) {
    particle.color.value = '#ffffff'; // 替换为你的粒子默认颜色
  }
};

// 重写连线绘制函数
const originalDrawLink = pJS.fn.canvas.drawLink;
pJS.fn.canvas.drawLink = function(link) {
  if (link.hasPulse) {
    const originalColor = link.color;
    const pulseColor = link.pulseColor;
    const mixedColor = mixColors(originalColor, pulseColor, link.pulseProgress);
    link.color = mixedColor;
  }

  originalDrawLink.call(this, link);

  // 绘制完成后恢复原颜色
  if (link.hasPulse) {
    link.color = '#ffffff'; // 替换为你的连线默认颜色
  }
};

// 辅助函数:混合两种RGB颜色
function mixColors(color1, color2, progress) {
  const rgb1 = hexToRgb(color1);
  const rgb2 = hexToRgb(color2);

  // 按进度插值计算混合后的RGB值
  const r = Math.floor(rgb1.r + (rgb2.r - rgb1.r) * progress);
  const g = Math.floor(rgb1.g + (rgb2.g - rgb1.g) * progress);
  const b = Math.floor(rgb1.b + (rgb2.b - rgb1.b) * progress);

  return `rgb(${r}, ${g}, ${b})`;
}

// 辅助函数:十六进制颜色转RGB
function hexToRgb(hex) {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? {
    r: parseInt(result[1], 16),
    g: parseInt(result[2], 16),
    b: parseInt(result[3], 16)
  } : { r: 255, g: 255, b: 255 };
}

代码逻辑讲解

  1. 初始化扩展:在基础配置后给粒子和链接添加脉冲状态属性,用来跟踪脉冲的启动、进度和颜色。
  2. 点击创建粒子:利用particle.js自带的Particle构造函数生成新粒子,加入数组后直接触发脉冲传递。
  3. 脉冲传递:triggerPulse函数负责找到当前粒子的所有连接,标记链接的脉冲状态,延迟后触发目标粒子的脉冲,形成递归传递;重写的更新函数负责每帧推进脉冲进度,控制脉冲的开始和结束。
  4. 渲染调整:通过重写原绘制函数,在绘制前根据脉冲进度混合颜色,绘制后恢复原颜色,既实现脉冲视觉效果,又不影响粒子的正常状态。两个辅助函数负责颜色格式转换和混合,保证过渡自然。

自定义调整提示

  • 脉冲速度:修改pulseProgress += 0.02的步长,数值越大脉冲越快
  • 传递延迟:调整setTimeout的毫秒数,数值越大脉冲传递越慢
  • 脉冲颜色:直接修改pulseColor的十六进制值即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:30:39