Maison > interface Web > Tutoriel H5 > Explication détaillée de l'exemple de partage de code pour la création d'une animation de grille de particules dynamique à l'aide de HTML5 Canvas

Explication détaillée de l'exemple de partage de code pour la création d'une animation de grille de particules dynamique à l'aide de HTML5 Canvas

黄舟
Libérer: 2018-05-28 17:48:39
original
3246 Les gens l'ont consulté

Cet article présente principalement l'utilisation de HTML5 Canvas pour créer des grilles de particules dynamiques animation Il est d'une grande valeur pratique et les amis dans le besoin peuvent s'y référer. il.

J'ai récemment vu une animation de grille de particules très sympa, alors j'en ai créé une moi-même. Elle fonctionne bien comme arrière-plan. Le CSDN ne peut pas télécharger d'images dépassant 2M, j'ai donc simplement coupé une image statique :

Commençons par comment obtenir cet effet :

Explication détaillée de l'exemple de partage de code pour la création d'une animation de grille de particules dynamique à l'aide de HTML5 Canvas

Tout d'abord, de Bien sûr Il est temps d'ajouter un canevas :

<canvas id="canvas"></canvas>
Copier après la connexion

Voici le style :

<style>
    #canvas{
        position: absolute;
        display: block;
        left:0;
        top:0;
        background: #0f0f0f;
        z-index: -1;
     }
</style>
Copier après la connexion

Le z-index du canevas ci-dessus : -1 peut être placé sous certains éléments comme un arrière-plan.

Afin de garantir que le canevas puisse remplir tout le navigateur, la largeur et la hauteur du canevas doivent être définies pour être les mêmes que celles du navigateur :

function getSize(){
    w = canvas.width = window.innerWidth;
    h = canvas.height = window.innerHeight;
}
Copier après la connexion

Le w et le h ci-dessus représentent respectivement la largeur et la hauteur du navigateur.

Après avoir obtenu la largeur et la hauteur du navigateur, l'étape suivante consiste à dessiner les particules à l'intérieur. Ici, nous devons définir certains paramètres de particules à l'avance :

var opt = {
    particleAmount: 50,         //粒子个数
    defaultSpeed: 1,            //粒子运动速度
    variantSpeed: 1,            //粒子运动速度的变量
    particleColor: "rgb(32,245,245)",       //粒子的颜色
    lineColor:"rgb(32,245,245)",            //网格连线的颜色
    defaultRadius: 2,           //粒子半径
    variantRadius: 2,           //粒子半径的变量
    minDistance: 200            //粒子之间连线的最小距离
};
Copier après la connexion

Les variables de vitesse ci-dessus et. les variables de rayon sont les deux. Cela permet de garantir que la taille et la vitesse des particules ne sont pas exactement les mêmes.

Ensuite on crée une classe pour initialiser les particules. Le code est relativement long, j'ai donc ajouté des commentaires :

function Partical(){
    this.x = Math.random()*w;           //粒子的x轴坐标
    this.y = Math.random()*h;           //粒子的y轴坐标
    this.speed = opt.defaultSpeed + opt.variantSpeed*Math.random();     //粒子的运动速度
    this.directionAngle = Math.floor(Math.random()*360);                //粒子运动的方向
    this.color = opt.particleColor ;                                    //粒子的颜色
    this.radius = opt.defaultRadius+Math.random()*opt.variantRadius;    //粒子的半径大小
    this.vector = {
        x:this.speed * Math.cos(this.directionAngle),       //粒子在x轴的速度
        y:this.speed * Math.sin(this.directionAngle)        //粒子在y轴的速度
    }
    this.update = function(){                   //粒子的更新函数
        this.border();                           //判断粒子是否到了边界
        this.x += this.vector.x;                //粒子下一时刻在x轴的坐标
        this.y += this.vector.y;                //粒子下一时刻在y轴的坐标
    }
    this.border = function(){               //判断粒子是都到达边界
        if(this.x >= w || this.x<= 0){      //如果到达左右边界,就让x轴的速度变为原来的负数
            this.vector.x *= -1;
        }
        if(this.y >= h || this.y <= 0){     //如果到达上下边界,就让y轴的速度变为原来的负数
            this.vector.y *= -1;
        }
        if(this.x > w){                     //下面是改变浏览器窗口大小时的操作,改变窗口大小后有的粒子会被隐藏,让他显示出来即可
            this.x = w;
        }
        if(this.y > h){
            this.y = h;
        }
        if(this.x < 0){
            this.x = 0;
        }
        if(this.y < 0){
            this.y = 0;
        }
    }
    this.draw = function(){                 //绘制粒子的函数
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius ,0 ,Math.PI * 2);
        ctx.closePath();
        ctx.fillStyle = this.color;
        ctx.fill();
    }
}
Copier après la connexion

1. et les angles sont générés de manière aléatoire, et la couleur des particules est déterminée par les options de paramètres pertinentes.

2. This.vector est utilisé pour stocker la direction de mouvement des particules : si this.vector.x vaut 1, les particules se déplacent vers la droite ; s'il vaut -1, les particules se déplacent vers la gauche. De même, si this.vector.y est négatif, la particule se déplace vers le haut, et s'il est positif, la particule se déplace vers le bas.

This.update est utilisé pour mettre à jour les coordonnées de la prochaine position de chaque particule. Tout d'abord, la détection des bords est effectuée ; si le mouvement de la particule dépasse la taille de la toile, le vecteur de direction est multiplié par -1 pour produire la direction inverse du mouvement.

3. La mise à l'échelle de la fenêtre peut amener les particules à dépasser la limite, de sorte que la fonction de détection des bords ne peut pas les capturer, donc une série d'instructions if sont nécessaires pour détecter cette situation et réinitialiser la position des particules à la frontière actuelle. de la toile.

4. La dernière étape consiste à dessiner ces points sur la toile.

La classe de particules a été écrite, dessinons-la ci-dessous :

function init(){
   getSize();
   for(let i = 0;i<opt.particleAmount; i++){
        particle.push(new Partical());
   }
   loop();
}
Copier après la connexion

La particule opt.particleAmount objet est initialisée ci-dessus, mais l'objet est initialisé mais il n'a pas été dessiné. Voici la fonction de boucle :

function loop(){
    ctx.clearRect(0,0,w,h);
    for(let i = 0;i<particle.length; i++){
        particle[i].update();
        particle[i].draw();
    }
    window.requestAnimationFrame(loop);
}
Copier après la connexion

Chaque fois que la fonction loop() est exécutée, le contenu sur le canevas sera effacé, puis les coordonnées des particules seront recalculées via la mise à jour. () de l'objet particule. Enfin, les particules sont dessinées via la fonction draw() de l'objet particule. Voici l'effet à ce moment :

Explication détaillée de l'exemple de partage de code pour la création d'une animation de grille de particules dynamique à l'aide de HTML5 Canvas

Cependant, certaines particules disparaîtront après la modification de la taille de la fenêtre du navigateur. À ce stade, vous devez ajouter un . event Surveillez si la taille du navigateur change :

window.addEventListener("resize",function(){
    winResize()
},false);
Copier après la connexion

Ensuite, vous devez écrire la fonction winResize(). Vous devez faire attention ici lorsque le navigateur change, l'événement de redimensionnement sera très déclenché. fréquemment. Déplacez légèrement le navigateur. L'avantage est de déclencher des dizaines d'événements de redimensionnement, puis la taille du navigateur sera recalculée des dizaines de fois, ce qui consomme des performances. Parlons simplement de la solution ici. Ce que je veux, c'est simplement la taille du navigateur après le changement. La taille finale n'a rien à voir avec le nombre de fois où elle a changé au milieu, nous pouvons donc retarder l'événement de calcul de la taille du navigateur de 200 millisecondes lorsque la fenêtre du navigateur change. . Si l'événement de redimensionnement est déclenché en continu pendant cette période, il continuera. Délai de 200 millisecondes, ce qui semble compliqué. En fait, le code est très simple :

var particle = [], w,h;     //粒子数组,浏览器宽高
var delay = 200,tid;        //延缓执行事件和setTimeout事件引用
function winResize(){
    clearTimeout(tid);
    tid = setTimeout(function(){
        getSize();          //获取浏览器宽高,在文章最上面有介绍
    },delay)
}
Copier après la connexion

De cette façon, toutes les animations de particules sont. terminé, puis vous pouvez tracer des lignes entre les particules, comme nous l'avons défini ci-dessus. Il y a une variable minDistance dans l'objet opt. Lorsque la ligne entre deux particules est inférieure à cette valeur, nous traçons une ligne entre elles.

Alors, comment calculer la distance entre deux particules ? Vous vous souvenez de la première leçon de mathématiques du collège, le théorème de Pythagore : la somme des carrés des deux côtés rectangles d'un triangle rectangle. est égal au carré de la troisième variable. Voir ci-dessous :

Explication détaillée de l'exemple de partage de code pour la création d'une animation de grille de particules dynamique à l'aide de HTML5 Canvas

Nous connaissons maintenant les coordonnées de l'axe des x et de l'axe des y de chaque particule, nous pouvons alors calculer la distance entre les deux points et écrivez une fonction, passez en deux points, comme suit :

function getDistance(point1,point2){
        return Math.sqrt(Math.pow(point1.x-point2.x,2) + Math.pow(point1.y - point2.y ,2));
    }
Copier après la connexion

现在我们可以计算出两个点的距离,那么我们就计算出所有每个粒子同其他所有粒子的距离,来确定它们之间是否需要连线,当然如果所有粒子的颜色深度都一模一样,那就有点丑了,所以我们这里可以根据两个粒子之间的距离来决定连线的透明度,两个粒子距离越近,越不透明,距离越远,越透明,超过一定距离就不显示了。

function linePoint(point,hub){
    for(let i = 0;i<hub.length;i++){
        let distance = getDistance(point,hub[i]);
        let opacity = 1 -distance/opt.minDistance;
        if(opacity > 0){
            ctx.lineWidth = 0.5;
            ctx.strokeStyle = "rgba("+line[0]+","+line[1]+","+line[2]+","+opacity+")";
            ctx.beginPath();
            ctx.moveTo(point.x,point.y);
            ctx.lineTo(hub[i].x,hub[i].y);
            ctx.closePath();
            ctx.stroke();
        }
    }
}
Copier après la connexion

上面传入的两个参数分别是一个点和整个点的数组,let opacity = 1 -distance/opt.minDistance;用于判断连线之间的透明度同时也判断了距离,距离大于opt.minDistance时,opacity为负,下面判断时就过滤掉了,上面的颜色用到了正则表达式,需要先解析最上面opt对象里给出的颜色,然后再加上透明度,这段代码如下:

var line = opt.lineColor.match(/\d+/g);
Copier après la connexion

最后在loop()函数里面不断循环计算距离就可以了,在loop()中加入代码后如下:

function loop(){
        ctx.clearRect(0,0,w,h);
        for(let i = 0;i<particle.length; i++){
            particle[i].update();
            particle[i].draw();
        }
        for(let i = 0;i<particle.length; i++){   //添加的是这个循环
            linePoint(particle[i],particle)
        }
        window.requestAnimationFrame(loop);
    }
Copier après la connexion

需要指出的是:如果添加过多的点和/或过多的连接距离(连接距离会创建过多的线条),动画也会扛不住。当视口变窄时最好降低粒子的运动速度:粒子的尺寸越小,在愈加狭窄空间内的移动速度貌似会越快。

显示整段代码:




    
    canvas粒子动画
    


<canvas id="canvas"></canvas>
<script>
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var opt = {
        particleAmount: 50,     //粒子个数
        defaultSpeed: 1,        //粒子运动速度
        variantSpeed: 1,        //粒子运动速度的变量
        particleColor: "rgb(32,245,245)",       //粒子的颜色
        lineColor:"rgb(32,245,245)",            //网格连线的颜色
        defaultRadius: 2,           //粒子半径
        variantRadius: 2,           //粒子半径的变量
        minDistance: 200            //粒子之间连线的最小距离
    };
    var line = opt.lineColor.match(/\d+/g);
    console.log(line);
    var particle = [], w,h;
    var delay = 200,tid;
    init();
    window.addEventListener("resize",function(){
        winResize()
    },false);

    function winResize(){
        clearTimeout(tid);
        tid = setTimeout(function(){
            getSize();
        },delay)
    }

    function init(){
        getSize();
        for(let i = 0;i<opt.particleAmount; i++){
            particle.push(new Partical());
        }
        loop();
    }

    function loop(){
        ctx.clearRect(0,0,w,h);
        for(let i = 0;i<particle.length; i++){
            particle[i].update();
            particle[i].draw();
        }
        for(let i = 0;i<particle.length; i++){
            linePoint(particle[i],particle)
        }
        window.requestAnimationFrame(loop);
    }

    function linePoint(point,hub){
        for(let i = 0;i<hub.length;i++){
            let distance = getDistance(point,hub[i]);
            let opacity = 1 -distance/opt.minDistance;
            if(opacity > 0){
                ctx.lineWidth = 0.5;
                ctx.strokeStyle = "rgba("+line[0]+","+line[1]+","+line[2]+","+opacity+")";
                ctx.beginPath();
                ctx.moveTo(point.x,point.y);
                ctx.lineTo(hub[i].x,hub[i].y);
                ctx.closePath();
                ctx.stroke();
            }
        }
    }

    function getDistance(point1,point2){
        return Math.sqrt(Math.pow(point1.x-point2.x,2) + Math.pow(point1.y - point2.y ,2));
    }

    function getSize(){
        w = canvas.width = window.innerWidth;
        h = canvas.height = window.innerHeight;
    }
    function Partical(){
        this.x = Math.random()*w;           
        //粒子的x轴坐标
        this.y = Math.random()*h;           
        //粒子的y轴坐标
        this.speed = opt.defaultSpeed + opt.variantSpeed*Math.random();     
        //粒子的运动速度
        this.directionAngle = Math.floor(Math.random()*360);                
        //粒子运动的方向
        this.color = opt.particleColor ;                                    
        //粒子的颜色
        this.radius = opt.defaultRadius+Math.random()*opt.variantRadius;    
        //粒子的半径大小
        this.vector = {
        
            x:this.speed * Math.cos(this.directionAngle),       
            //粒子在x轴的速度
            y:this.speed * Math.sin(this.directionAngle)        
            //粒子在y轴的速度
        }
        this.update = function(){                   
        //粒子的更新函数
            this.border();                           
            //判断粒子是否到了边界
            this.x += this.vector.x;                
            //粒子下一时刻在x轴的坐标
            this.y += this.vector.y;                
            //粒子下一时刻在y轴的坐标
        }
        this.border = function(){               
        //判断粒子是都到达边界
            if(this.x >= w || this.x<= 0){      
            //如果到达左右边界,就让x轴的速度变为原来的负数
                this.vector.x *= -1;
            }
            if(this.y >= h || this.y <= 0){     
            //如果到达上下边界,就让y轴的速度变为原来的负数
                this.vector.y *= -1;
            }
            if(this.x > w){                     
            //下面是改变浏览器窗口大小时的操作,改变窗口大小后有的粒子会被隐藏,让他显示出来即可
                this.x = w;
            }
            if(this.y > h){
                this.y = h;
            }
            if(this.x < 0){
                this.x = 0;
            }
            if(this.y < 0){
                this.y = 0;
            }
        }
        this.draw = function(){                 //绘制粒子的函数
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.radius ,0 ,Math.PI * 2);
            ctx.closePath();
            ctx.fillStyle = this.color;
            ctx.fill();
        }
    }
</script>

Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal