background

I searched canvas effects by chance and found a good one. I changed it and realized it. I thought it was interesting.

The effect

Another effect

Principle and Code

    1. First create a sub-canvas, write the text you want to write, and then get the position of each pixel of the target through the method of pixel reading

const viceCanvas = document.createElement('canvas') viceCanvas.width = WIDTH; viceCanvas.height = HEIGHT; Let viceCxt = vicecanvas.getContext ('2d') const font = '93' vicecxt. font = '200px Arial'; const measure = viceCxt.measureText(font) viceCxt.fillText(font, (WIDTH - measure.width) / 2, HEIGHT / 2); return getFontInfo(viceCxt);Copy the code

GetFontInfo is a method that reads points by iterating through pixels


Function getFontInfo(CTX) {let imageData = ctx.getimageData (0, 0, WIDTH, HEIGHT).data; const particles = []; for (let x = 0; x < WIDTH; x += 4) { for (let y = 0; y < HEIGHT; y += 4) { const fontIndex = (x + y * WIDTH) * 4 + 3; if (imageData[fontIndex] > 0) { particles.push(new Particle({ x, y, })) } } } return particles; }Copy the code

Where Particle is a self-defined class that represents the trajectory of each point. His constructor has the initial point (random) and the target position (obtained and passed in by the previous reading copy) and speed.


constructor(center) { this.x = center.x; // This. Y = center. Y; // This. Item = 0; // This. Vx = 20; // This. Vy = 16; This.initx = math.random () * WIDTH; this.initx = math.random () * WIDTH; // this. InitY = math.random () * HEIGHT; // Point random y coordinates in the canvas}Copy the code

  • Create the main canvas, and then render

let WIDTH, HEIGHT, cxt, raf, points; // init window.onload = () => { WIDTH = document.body.clientWidth; HEIGHT = document.body.clientHeight; const canvas = document.getElementById('canvas'); canvas.width = WIDTH; canvas.height = HEIGHT; ctx = canvas.getContext('2d'); points = createViceCanvas(); render() } function render() { ctx.clearRect(0, 0, WIDTH, HEIGHT) points.forEach((value) => { // value.draw(); / / each point draw a random alone to the curve of the target location}) raf = window. RequestAnimationFrame (render) if (points [0]. Item > = 1) { window.cancelAnimationFrame(raf) } }Copy the code

Pay special attention to requestAnimationFrame and cancelAnimationFrame. Points are the collection of target points read from the replica. Each render takes a small step. Call Particle class draw method.

    1. Render

Two versions of Draw, version one bezier curve, which the author used.


Draw () {// Draw point ctx.beginPath(); Const {x, y} = threeBezier(const {x, y} = threeBezier) This. Item, [this. X, this. Y], [this. X, this. Y], [this. y, 2, 0, 2 * Math.PI, true); ctx.fillStyle = randomHexColor() ctx.fill(); ctx.closePath(); this.speed(); // Next tick drawing coordinates}Copy the code

Bezier curve, which is a nice curve, every time you calculate the position of the next point at time T, and then you make an arc bezier curve also encapsulates a method. It’s just a mathematical formula.


    const threeBezier = (t, p1, p2, cp1, cp2) => {
        const [startX, startY] = p1;
        const [endX, endY] = p2;
        const [cpX1, cpY1] = cp1;
        const [cpX2, cpY2] = cp2
        let x = startX * Math.pow(1 - t, 3) +
            3 * cpX1 * t * Math.pow(1 - t, 2) +
            3 * cpX2 * Math.pow(t, 2) * (1 - t) +
            endX * Math.pow(t, 3);
        let y = startY * Math.pow(1 - t, 3) +
            3 * cpY1 * Math.pow(1 - t, 2) * t +
            3 * cpY2 * (1 - t) * Math.pow(t, 2) +
            endY * Math.pow(t, 3)
        return {
            x,
            y,
        }
    }
Copy the code

And then version two, if YOU don’t understand Bezier’s formula, let me draw a straight line. All right.


Const {x, y} = lineAAA(// InitX, this. InitY], [this. X, this. Y], [this. this.y] ) ctx.moveTo(x, y) ctx.lineTo(this.x, this.y) ctx.strokeStyle = randomHexColor() ctx.stroke() const lineAAA = (t, p1, p2, cp1, cp2) => { const [startX, startY] = p1; const [endX, endY] = p2; let x = startX + (endX - startX) * t let y = startY + (endY - startY) * t return { x, y, } }Copy the code

    1. For a single particle, it has a random initial point and a clear target point, and then during each render process, it will calculate the point it should pass through. As above, you have a particle trajectory.
    1. Color random

This is easy


Function randomHexColor() {return '#' + ('00000' + (math.random () * 0x1000000 << 0).toString(16)).substr(-6); }Copy the code

The source code

The source code