>  기사  >  웹 프론트엔드  >  HTML5 Canvas를 사용하여 동적 입자 그리드 애니메이션을 생성하기 위한 샘플 코드 공유에 대한 자세한 설명

HTML5 Canvas를 사용하여 동적 입자 그리드 애니메이션을 생성하기 위한 샘플 코드 공유에 대한 자세한 설명

黄舟
黄舟원래의
2018-05-28 17:48:393209검색

이 글에서는 주로 HTML5 캔버스를 사용하여 동적 입자 그리드 애니메이션을 만드는 방법을 소개합니다. 이는 매우 실용적인 가치가 있으며 도움이 필요한 친구들이 참고할 수 있습니다. 그것.

최근에 아주 멋진 입자 그리드 애니메이션을 봤는데 배경으로도 잘 어울리네요. CSDN은 2M를 초과하는 이미지를 업로드할 수 없으므로 단순히 정적 이미지를 잘라냅니다.

이 효과를 얻는 방법부터 시작하겠습니다.

HTML5 Canvas를 사용하여 동적 입자 그리드 애니메이션을 생성하기 위한 샘플 코드 공유에 대한 자세한 설명

우선, 물론 캔버스를 추가할 시간입니다:

<canvas id="canvas"></canvas>

스타일은 다음과 같습니다:

<style>
    #canvas{
        position: absolute;
        display: block;
        left:0;
        top:0;
        background: #0f0f0f;
        z-index: -1;
     }
</style>

위 캔버스의 z-index: -1은 일부 요소 아래에 배경으로 배치될 수 있습니다.

캔버스가 브라우저 전체를 채울 수 있도록 하려면 캔버스의 너비와 높이를 브라우저와 동일하게 설정해야 합니다.

function getSize(){
    w = canvas.width = window.innerWidth;
    h = canvas.height = window.innerHeight;
}

위의 w와 h는 브라우저의 너비와 높이입니다.

브라우저의 너비와 높이를 얻은 후 다음 단계는 내부에 입자를 그리는 것입니다. 여기서는 몇 가지 입자 매개변수를 미리 정의해야 합니다.

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

위의 속도 변수와 반경 변수 입자의 크기와 속도가 정확히 동일하지 않은지 확인하십시오.

그런 다음 입자를 초기화하는 클래스를 만듭니다. 코드가 비교적 길어서 주석을 추가했습니다.

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();
    }
}

1. 무작위로 생성되며, 파티클의 색상은 관련 설정 옵션에 따라 결정됩니다.

2. This.Vector는 입자의 이동 방향을 저장하는 데 사용됩니다. this.Vector.x가 1이면 입자가 -1이면 입자가 왼쪽으로 이동합니다. 마찬가지로 this.Vector.y가 음수이면 입자는 위쪽으로 이동하고, 양수이면 입자는 아래쪽으로 이동합니다.

This.update는 각 입자의 다음 위치 좌표를 업데이트하는 데 사용됩니다. 먼저 가장자리 감지가 수행됩니다. 입자의 움직임이 캔버스 크기를 초과하면 방향 벡터에 -1을 곱하여 움직임의 반대 방향을 생성합니다.

3. 창 ​​크기 조정으로 인해 입자가 경계를 넘어갈 수 있으므로 가장자리 감지 기능이 이를 캡처할 수 없으므로 이러한 상황을 감지하고 입자 위치를 현재 경계로 재설정하려면 일련의 if 문이 필요합니다. 캔버스의.

4. 마지막 단계는 이 점들을 캔버스에 그리는 것입니다.

파티클 클래스가 작성되었으니 그려 보겠습니다.

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

opt.particleAmount 파티클 object는 위에서 초기화되었지만 객체는 초기화되지 않았습니다. 다음은 루프 함수입니다.

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);
}

loop() 함수가 실행될 때마다 캔버스의 내용이 지워지고 다음의 update() 함수를 통해 입자의 좌표가 다시 계산됩니다. 입자 객체를 생성하고 마지막으로 입자 객체의 update() 함수 draw() 함수를 통해 입자를 그립니다. 이때 효과는 다음과 같습니다.

HTML5 Canvas를 사용하여 동적 입자 그리드 애니메이션을 생성하기 위한 샘플 코드 공유에 대한 자세한 설명

단, 브라우저 창 크기를 변경하면 일부 파티클이 사라지게 됩니다. 이때 를 추가해야 합니다. 이벤트 브라우저 크기 변경 여부 모니터링:

window.addEventListener("resize",function(){
    winResize()
},false);

그런 다음 winResize() 함수를 작성해야 합니다. 여기서는 브라우저가 변경될 때 크기 조정 이벤트가 매우 자주 트리거된다는 점에 유의해야 합니다. 크기 조정 이벤트가 수십 번 발생하면 브라우저 크기가 수십 번 다시 계산되므로 성능이 저하됩니다. 실제로 여기서는 해결 방법에 대해 이야기해 보겠습니다. Size는 브라우저 변경 후의 최종 크기일 뿐이며, 중간에 몇 번 변경되는지는 저희와 무관하므로 브라우저 창이 변경될 때 브라우저 크기를 계산하는 이벤트를 200밀리초 동안 지연시킬 수 있습니다. . 이 기간 동안 크기 조정 이벤트가 계속 발생하면 200밀리초 동안 지연됩니다. 사실 코드는 매우 간단합니다.

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

이렇게 하면 모든 입자가 애니메이션이 완료되면 입자 사이에 선을 그릴 수 있습니다. 위에서 정의한 opt 객체에는 minDistance 변수가 있습니다. 두 입자 사이의 선이 이 값보다 작으면 입자 사이에 선을 그립니다.

그럼 두 입자 사이의 거리를 계산하는 방법은 무엇입니까? 중학교 수학의 첫 번째 교훈인 직각삼각형의 두 직각 변의 제곱의 합을 떠올려 보세요. 는 세 번째 변수의 제곱과 같습니다.

HTML5 Canvas를 사용하여 동적 입자 그리드 애니메이션을 생성하기 위한 샘플 코드 공유에 대한 자세한 설명

이제 각 입자의 x축과 y축 좌표를 알았으므로 계산할 수 있습니다. 두 점 사이의 거리를 계산하고 함수를 작성하여 다음과 같이 두 점을 전달합니다.

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

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

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();
        }
    }
}

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

var line = opt.lineColor.match(/\d+/g);

最后在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);
    }

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

显示整段代码:




    
    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>

위 내용은 HTML5 Canvas를 사용하여 동적 입자 그리드 애니메이션을 생성하기 위한 샘플 코드 공유에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.