Programmer’s little romance — word particle effect

Time:2020-9-2

preview

Programmer's little romance -- word particle effect

Full project Preview – Preview address;

Principle of particle effect

In canvas, you can use thegetImageData()Method to obtain pixel data.

ctx.fillStyle = '#ff0000';
ctx.fillRect(0, 0, 1, 1);
const imageData = ctx.getImageData(0, 0, 1, 1);

imageDataThere are three attributes:

  • data: array containing pixel information, each pixel has four lengths, such as[255,0,0,255, ... ,255,127,0,255], representing the RGBA values of the pixel respectively.
  • widthimageDataThe width of the object.
  • heightimageDataThe height of the object.

First, in thecanvasupperWrite it downSome color words, go againanalysisPixel data (such as changing whether the pixel has transparency, etc.), and thenRecord yourselfNext to the pixelposition

The following example is rewritten text by changing the pixel data.

Programmer's little romance -- word particle effect

ctx.font = 'bold 40px Arial';
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.fillText ('Hello ', 60, 20);

document.querySelector('#button').addEventListener('click', function(){
    const imgData = ctx.getImageData(0, 0, 120, 40);
    for(let i = 0;i < imgData.data.length; i+=4){
        if(imgData.data[i + 3] == 0) continue;
        imgData.data[i] = 255;
        imgData.data[i + 1] = 0;
        imgData.data[i + 2] = 0;
        // imgData.data [i + 3] = 255; this represents the transparency of the same 255 highest 0 lowest
    }
    ctx.putImageData(imgData,120,0);
});

This code is just an example to illustrate, in fact, no one will be so brainwashed to change colors.

Get point location

To get the position of the point, first write the words on the canvas, but the words can’t be seen by others. So you can dynamically create a canvas that doesn’tappendTo any node, it will only be used for writing.

const cache = document.createElement('canvas');

Set the width and height to be the same as the displayed canvas. (don’t post this part of the code)

Create an object to get the location of the point

const ShapeBuilder = {
    //I think it is better to use the word "center" alignment
    init(width, height){
        this.width = width;
        this.height = height;
        this.ctx = cache.getContext('2d');
        this.ctx.textBaseline = 'middle';
        this.ctx.textAlign = 'center';
    },
    //You must write text before you can get the location. Here, size = 40 is the default value
    write(words, x, y, size = 40){
        //Clear the words written before.
        this.ctx.clearRect(0, 0, this.width, this.height);
        this.font = `bold ${size}px Arial`;
        this.ctx.fillText(words, x, y);
        //The location of the current text is recorded to facilitate the calculation of the pixel area
        this.x = x;
        this.y = y;
        this.size = size;
        this.length = words.length;
    },
    getPositions(){
        //Because the imgdata data is very large, the scope of data acquisition should be reduced as much as possible.
        const xStart = this.x - (this.length / 2) * this.size, 
            xEnd = this.x + (this.length / 2) * this.size,
            yStart = this.y - this.size / 2, 
            yEnd = this.y + this.size / 2, 
            
            //Getimagedata (starting point x, starting point y, width, height);
            data = this.ctx.getImageData(xStart, yStart, this.size * this.length, this.size).data;
            
        //Spacing (described below)
        const gap = 4;
        
        let positions = [], x = xStart, y = yStart;
        
        for(var i = 0;i < data.length; i += 4 * gap){
            if(data[i+3] > 0){
                positions.push({x, y});    
            }
            
            x += gap;
            
            if(x >= xEnd){
                x = xStart;
                y += gap;
                i += (gap - 1) * 4 * (xEnd - xStart);
            }
        }
        return positions;
    }
}

ShapeBuilder.init();

aboutgap: in cycleimgDataArray, too much data may causeCatonSo you can use intervals to get coordinate points. However, it may cause part of the textdefect。 It requires individuals to weigh the pros and cons and adjust themselves.

gapMust be able to bexEnd-xStartOtherwise, it will cause the result of obtaining coordinate point dislocation.

aboutcanvasinmiddleAndcenterRules for:

this.ctx.font = 'bold 40px Arial';
this.ctx.fillText Hello, 40 ';

The effect is shown in the figure below

Programmer's little romance -- word particle effect

fillTextSetCoordinate pointIt’s going to be the whole wordmidpointIn the picturemiddleAndcenterThe intersection point of. In fact, other alignment methods are also OK, depending on personal preference.

Refer to the HTML 5 canvas reference manual for more alignment rules.

Create a particle class

Particles should be randomly generated and then moved to a specific location.

Properties of microparticles:

Current position (x, y), target position: (xend, yend), size, color, and moving speed (E)

method:go()Each frame has to be moved a certain distance,render(): render out the particles (I use the shape of a heart)

class Particle {
    constructor({x, y, size = 2, color, xEnd, yEnd, e = 60} = {}){
        this.x = x;
        this.y = y;
        this.size = size;
        this.color = color ||  `hsla(${Math.random() * 360}, 90%, 65%, 1)`;
        this.xEnd = xEnd;
        this.yEnd = yEnd;
        
        //After e frame, we arrive at the target location
        this.e = e;
        //Calculate the distance traveled by each frame
        this.dx = (xEnd - x) / e;
        this.dy = (yEnd - y) / e;
    }
    go(){
        //Keep still when you get to your destination (in fact, you can do something here)
        if(--this.e <= 0) {
            this.x = this.xEnd;
            this.y = this.yEnd;
            return ;
        }
        this.x += this.dx;
        this.y += this.dy;
    }
    render(ctx){
        this.go();
        //Here's a Bezier curve with a heart-shaped shape
        ctx.beginPath();
        ctx.fillStyle = this.color;
        ctx.moveTo(this.x + 0.5 * this.size, this.y + 0.3 * this.size);
        ctx.bezierCurveTo(this.x + 0.1 * this.size, this.y, this.x, 
                        this.y + 0.6 * this.size, this.x + 0.5 * 
                        this.size, this.y + 0.9 * this.size);
        ctx.bezierCurveTo(this.x + 1 * this.size, this.y + 0.6 * 
                        this.size, this.x + 0.9 * this.size, this.y, 
                        this.x + 0.5 * this.size,
                        this.y + 0.3 * this.size);
        ctx.closePath();
        ctx.fill();
        return true;
    }
}

These are the most basic attributes and methods of particle class. If you want to make particles more beautiful or more vivid, you can add some attributes and methods by yourself.

Specific process

const canvas = {
    init(){
        //Set some properties
        this.setProperty();
        //Creating particles
        this.createParticles();
        //The cycle of canvas
        this.loop();
    },
    setProperty(){
        this.ctx = studio.getContext('2d');
        this.width = document.body.clientWidth;
        this.height = document.body.clientHeight;
        this.particles = [];
    },
    createParticles(){
        let dots;
        //ShapeBuilder.write(words, x, y, size)
        ShapeBuilder.write ('every word is', this.width  / 2,  this.height  / 3, 120);
        dots = ShapeBuilder.getPositions(6);
        ShapeBuilder.write ('Love the way you look ', this.width  / 2,  this.height  * 2 / 3, 120);
        dots = dots.concat(ShapeBuilder.getPositions(6));
        //Dots has got the coordinates of the word 
        //The target location of each particle is the coordinates of dots
        //Each particle is randomly born somewhere on the canvas
        for(let i = 0; i < dots.length; i++){
            this.particles.push(new Particle({
                xEnd:dots[i].x, 
                yEnd:dots[i].y , 
                x: Math.random() * this.width, 
                y: Math.random() * this.height, 
                size:6, 
                color:'hsla(360, 90%, 65%, 1)'
            }));
        }
    },
    loop(){
        //Clear the canvas at each frame, and then render the particles
        requestAnimationFrame(this.loop.bind(this));
        this.ctx.clearRect(0, 0, this.width, this.height);
        for(var i = 0; i < this.particles.length; i++){
            this.particles[i].render(this.ctx);
        }
    }
}

canvas.init();

Programmer's little romance -- word particle effect

If you want to add a small tail to each particle, do not clear the canvas at each frame and cover it with a transparent background color.

//Modify loop method
//this.ctx.clearRect(0, 0, this.width, this.height);
this.ctx.fillStyle = 'rgba(0,0,0,0.2)';
this.ctx.fillRect(0, 0, this.width, this.height);

In this way, the effect will be as follows
Programmer's little romance -- word particle effect

last

In this article, I didn’t pay attention to too many details, such asgapIt should be a constant that can be set, or a special annotation, and should not be arbitrarily written in the method. For this example of code, do not copy mechanically, it is important toUnderstanding principlesAnd yourselfTry it yourself

It was in the process of writing this article that I discovered the previous acquisitionpositionAn imprecise place.

Here we only talk about the most basic use of particle effect, in fact, you can make a lot of very cool effects

For example, the particles can shake after they arrive at their destination

Changes in particle shape, color, etc.

This project can also do a lot of things, we can also try to make more cool effects.

Fireworks effect can see my last article, programmer’s little romance — fireworks

Complete project

GitHub project address

If you think it’s good, please star one.

Reference items

A project on GitHub — shape shifter

I think this project is very good, but the author has disappeared for many years.

codepen.io Love in hearts

Recommended Today

Data type conversion of Java Foundation

The significance of data type conversion Data type conversion, in the actual application development, we often calculate different types of number types, so we use data conversion. On the one hand, when arithmetic operators are used to calculate numbers, the system will automatically convert them when appropriate; On the other hand, developers can also force […]