preface

Hi, here is CSS and WebGL magic – Alphardex.

Recently I started playing p5.js and found that it is an interesting library to create all kinds of new and interesting effects. In this article, we will implement the mouse movement effects shown below.

Let’s get started!

The preparatory work

Click on the lower right corner of the author’s P5.js template to fork a copy

Creation began

Create a point class

To begin, let’s create the simplest point class with only two parameters: the x and y coordinates

class Point {
  x: number; / / x coordinate
  y: number; / / y
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y; }}Copy the code

A line of particles

We all know that two points make a line.

But what if there are more than two points? Can you determine a line? The answer, of course, is yes, as long as the points are evenly arranged in a line, will they soon look like a straight line? In fact, this partition idea is also the basic idea of many particle effects.

Create a PointLine class that represents a line made of particles

  1. withdistThe delta function is going to find the distance between two pointsceilI take the whole, that’s the number between two points
  2. withmapThe function maps the point point to the xy coordinates of AB, yielding the coordinates of the point between two points
  3. withellipseThe function represents all the points between two points
class PointLine {
  s: p5;
  p1: Point; / / point A
  p2: Point; / / point B
  thickness: number; // The thickness of the line segment
  dotCount: number; // Total number of points
  constructor(s: p5, p1: Point, p2: Point, thickness = 1) {
    this.s = s;
    this.p1 = p1;
    this.p2 = p2;
    this.thickness = thickness;
    let dotCount = s.dist(p1.x, p1.y, p2.x, p2.y);
    this.dotCount = s.ceil(dotCount);
  }
  draw() {
    for (let i = 0; i < this.dotCount; i++) {
      let x = this.s.map(i, 0.this.dotCount, this.p1.x, this.p2.x);
      let y = this.s.map(i, 0.this.dotCount, this.p1.y, this.p2.y);
      this.s.ellipse(x, y, this.thickness, this.thickness); }}}Copy the code
const sketch = (s: p5) = > {
  const draw = () = >{... s.translate(s.width /2, s.height / 2);

    const p1 = new Point(0.0);
    const p2 = new Point(50.50);
    const line = new PointLine(s, p1, p2, 6);
    line.draw();
  };
};
Copy the code

Any polygon consisting of lines

Create a PointShape class that represents any polygon consisting of lines

  1. Create a circle that accepts the xy coordinates and radius r
  2. Try to divide this circle into polygons
  3. The parametric equation of the circle isX = a + rcos theta. Y = b + rsin theta.Using this, we can calculate the coordinates of all points of the line segment
class PointShape extends PointLine {
  x: number; / / x coordinate
  y: number; / / y
  r: number; / / radius
  edgeCount: number; / / number of length
  lines: PointLine[]; // Array of side lengths
  constructor(
    s: p5,
    x: number,
    y: number,
    r: number,
    edgeCount: number,
    thickness = 1
  ) {
    super(s, new Point(x, y), new Point(x, y), thickness);
    this.x = x;
    this.y = y;
    this.r = r;
    this.edgeCount = edgeCount;
    this.lines = [];
    for (let i = 0; i < this.edgeCount; i++) {
      const x1 =
        this.x + this.r * this.s.cos((this.s.TWO_PI * i) / this.edgeCount);
      const y1 =
        this.y + this.r * this.s.sin((this.s.TWO_PI * i) / this.edgeCount);
      const x2 =
        this.x +
        this.r * this.s.cos((this.s.TWO_PI * (i + 1)) / this.edgeCount);
      const y2 =
        this.y +
        this.r * this.s.sin((this.s.TWO_PI * (i + 1)) / this.edgeCount);
      const p1 = new Point(x1, y1);
      const p2 = new Point(x2, y2);
      const line = new PointLine(this.s, p1, p2, thickness);
      this.lines.push(line); }}draw() {
    this.lines.forEach((line) = >{ line.draw(); }); }}Copy the code
const sketch = (s: p5) = > {
  const draw = () = >{...const shape = new PointShape(s, 0.0.80.6.6);
    shape.draw();
  };
};
Copy the code

Gaussian random function

Since lines and graphs are composed of particles, we can try to make particles move. In P5. js, the commonly used random function is randomGaussian, which can add the offset generated by the function to the x and y of particles to produce the effect of random movement of particles

  1. Create a function that modifies the xy coordinates
  2. Creating a fuzzy functionblur, add the number of points and thickness to the corresponding fuzzy value, and add the offset generated by the Gaussian random function to the X and y coordinates
class PointLine {...modifyFunc: Function; // Modify the function, which is used to modify the particle's xy coordinates
  constructor(s: p5, p1: Point, p2: Point, thickness = 1){...const modifyFunc = (x: number, y: number) = > [x, y];
    this.modifyFunc = modifyFunc;
  }
  draw() {
    for (let i = 0; i < this.dotCount; i++) {
      let x = this.s.map(i, 0.this.dotCount, this.p1.x, this.p2.x);
      let y = this.s.map(i, 0.this.dotCount, this.p1.y, this.p2.y);
      [x, y] = this.modifyFunc(x, y);
      this.s.ellipse(x, y, this.thickness, this.thickness); }}blur(seed = 0, amount = 0) {
    const blurPower = 1 + this.s.sq(amount);
    this.dotCount *= blurPower;
    const blurPower2 = 1 - amount;
    this.thickness *= blurPower2;
    this.modifyFunc = (x: number, y: number) = > {
      x += seed * amount * this.s.randomGaussian(0.1);
      y += seed * amount * this.s.randomGaussian(0.1);
      return[x, y]; }; }}class PointShape extends PointLine {...blur(seed = 0, amount = 0) {
    this.lines.forEach((line) = >{ line.blur(seed, amount); }); }}Copy the code
const sketch = (s: p5) = > {
  const draw = () = >{...const shape = new PointShape(s, 0.0.80.6.6);
    shape.blur(10.0.5);
    shape.draw();
  };
};
Copy the code

Follow the mouse

  1. Create an array to hold the coordinates of the mouse and set an upper limit (12 in this case).
  2. Each time you draw, you add the current mouse coordinates, and if you exceed the limit, you delete the previously added coordinates
  3. Draws the graph based on the current mouse coordinates
const sketch = (s: p5) = > {
  let mousePositions: Point[] = [];
  const maxPos = 12; .const draw = () = >{...// s.translate(s.width / 2, s.height / 2);

    const mousePos = new Point(s.mouseX, s.mouseY);

    mousePositions.unshift(mousePos);
    if (mousePositions.length > maxPos) {
      mousePositions.pop();
    }

    mousePositions.forEach((pos, i) = > {
      const ratio = i / mousePositions.length;
      const shape = new PointShape(s, pos.x, pos.y, 80.6.6);
      shape.blur(10, ratio);
      shape.draw();
    });
  };
};
Copy the code

Showing up!

  1. applicationHSBColor mode and fill each figure with a different color
  2. applicationADDMix mode to create a dazzling effect
const sketch = (s: p5) = >{...const setup = () = >{... s.colorMode(s.HSB,1);
  };

  const draw = () = >{... mousePositions.forEach((pos, i) = > {
      s.blendMode(s.ADD);
      const ratio = i / mousePositions.length;
      s.fill(0.5 + ratio, 0.7.0.25);
      const shape = new PointShape(s, pos.x, pos.y, 80.6.6);
      shape.blur(10, ratio);
      shape.draw();
      s.blendMode(s.BLEND);
    });
  };
};
Copy the code

The project address

Blur Particle Trail