数据可视化之路 - canvas 粒子背景效果

栏目: Html5 · 发布时间: 5年前

内容简介:之前的文章提到过 canvas 动画的难点和一般规则。canvas 采用了一种叫做本文我们做一个粒子动画效果看看:从图中可以看出,粒子运动效果依据以下规则:

之前的文章提到过 canvas 动画的难点和一般规则。canvas 采用了一种叫做 立即渲染模式 ,调用绘制方法后 canvas 会直接将图形绘制到画布上,然后就不再管它,canvas 也不会记住你绘制的任何图形。这和 dom 模型不同,我们始终可以在内存中获取到 dom 元素的引用。基于这种特点,我们在动画每一帧之前都会清除画布,重新绘制一遍。绘制步骤如下:

  1. 初始化图形的状态,如坐标、大小、速度,运动方向等
  2. 清除画布,根据图形状态调用绘制函数画图
  3. 更新图形状态,返回步骤 2

本文我们做一个粒子动画效果看看:

需求分析

从图中可以看出,粒子运动效果依据以下规则:

  1. 画布上有固定若干个粒子和线组成,一开始生成n个随机坐标的粒子
  2. 粒子朝随机方向固定速度运动,当触碰到画布边缘时回弹
  3. 鼠标移动到画布上时,会在鼠标位置生成一个粒子
  4. 当两个粒子直线距离小于一定距离时连线,否则不连线或取消连线

实现分析(不带代码)

  1. 为了记录粒子的坐标、速度、方向、连线等状态,并封装绘图方法,我们需要一个粒子类,为了绘制n个粒子,我们需要一个数组在存放粒子对象。首先将粒子类初始化,赋予随机的坐标并给定初始速度和初始方向。
  2. 往粒子数组内追加一个鼠标粒子对象,坐标为当前鼠标位置,监听鼠标滑动并更新鼠标粒子坐标。
  3. 每一帧我们会按速度和方向更新粒子对象的坐标并重绘画布,当监测粒子坐标超出画布时,给定粒子类一个相反的方向。
  4. 当检测到两个粒子距离小于一定距离时,连线。

代码解读

首先是粒子类,它接受一个渲染上下文作为参数,并封装了粒子的状态和绘图方法。

class Particle {
  ctx: CanvasRenderingContext2D;
  x: number;
  y: number;
  vx: number;
  vy: number;
  constructor(ctx: CanvasRenderingContext2D) {
    this.ctx = ctx;
    this.x = random(0, CANVAS_WIDTH);
    this.y = random(0, CANVAS_HEIGHT);
    this.vx = random(-VELOCITY, VELOCITY);
    this.vy = random(-VELOCITY, VELOCITY);
  }
  draw() {
    if (this.x > CANVAS_WIDTH || this.x < 0) {
      this.vx = -this.vx;
    }
    if (this.y > CANVAS_HEIGHT || this.y < 0) {
      this.vy = -this.vy;
    }
    this.x += this.vx;
    this.y += this.vy;
    this.ctx.beginPath();
    this.ctx.arc(this.x, this.y, PARTICLE_RADIUS, 0, Math.PI * 2);
    // this.ctx.closePath();
    this.ctx.fill();
  }
}
复制代码

其次是鼠标粒子,它接受渲染上下文和dom容器作为参数,和粒子类相同,并且监听容器的鼠标位置以更新其坐标。

class MouseParticle {
  ctx: CanvasRenderingContext2D;
  x = -1;
  y = -1;
  // 单例的
  static instance: MouseParticle;
  constructor(ctx: CanvasRenderingContext2D, container: HTMLCanvasElement) {
    this.ctx = ctx;
    if (MouseParticle.instance) return MouseParticle.instance;
    container.addEventListener("mouseenter", e => {
      this.x = e.clientX;
      this.y = e.clientY;
    });
    container.addEventListener("mousemove", e => {
      this.x = e.clientX;
      this.y = e.clientY;
    });
    container.addEventListener("mouseleave", e => {
      // 移到canvas外
      this.x = -1;
      this.y = -1;
    });
    MouseParticle.instance = this;
    return this;
  }
  draw() {
    this.ctx.beginPath();
    this.ctx.arc(this.x, this.y, PARTICLE_RADIUS, 0, Math.PI * 2);
    this.ctx.fill();
  }
}
复制代码

接着我们初始化粒子和鼠标粒子对象,并保存进粒子数组。

const particles: (Particle | MouseParticle)[] = [];
for (let index = 0; index < PARTICLE_COUNT; index++) {
  const particle = new Particle(ctx);
  particles.push(particle);
}
const mouseParticle = new MouseParticle(ctx, canvas);
复制代码

接下来是我们的主绘图函数,它会在每一帧调用,根据粒子的状态重绘画布。

function draw(ctx: CanvasRenderingContext2D) {
  requestAnimationFrame(() => draw(ctx));
  // 清除画布并重绘粒子
  ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
  particles.forEach(particle => {
    particle.draw();
  });
  // 重绘线
  ctx.save();
  particles.forEach(source => {
    particles.forEach(target => {
      const xDistance = Math.abs(source.x - target.x);
      const yDistance = Math.abs(source.y - target.y);
      const dis = Math.round(
        Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2))
      );
      if (dis < PARTICLE_DISTANCE) {
        ctx.globalAlpha = dis / PARTICLE_DISTANCE;
        ctx.beginPath();
        ctx.moveTo(source.x, source.y);
        ctx.lineTo(target.x, target.y);
        ctx.closePath();
        ctx.stroke();
      }
    });
  });
}
复制代码

在主绘图函数里我们遍历粒子数组,当两个粒子距离小于一定距离时连线。

完整的代码在这里

这样我们就完成一个粒子效果啦~~~


以上所述就是小编给大家介绍的《数据可视化之路 - canvas 粒子背景效果》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Introduction to Computation and Programming Using Python

Introduction to Computation and Programming Using Python

John V. Guttag / The MIT Press / 2013-7 / USD 25.00

This book introduces students with little or no prior programming experience to the art of computational problem solving using Python and various Python libraries, including PyLab. It provides student......一起来看看 《Introduction to Computation and Programming Using Python》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具