zoukankan      html  css  js  c++  java
  • 【JavaScript】particle

    这是js实现的粒子动画,有两种模式,分别是zoom和line,它们对应的效果不同,但是原理都相同,具体分析如下:

    部分程序如下:

            var p = this;
            p.originParams = originParams;
            p.params = params;
            p.innerWidth = window.innerWidth;//页面视图区大小
            p.innerHeight = window.innerHeight;
            p.points = [];
            p.pageXY = {pageX:p.innerWidth/2,pageY:p.innerHeight/2};
            if(container[0] === '#') {
                p.container = container.split('#')[1];
            };
            //获取canvas元素
            p.canvas = document.getElementById(p.container);
            //创建context对象
            p.ctx = p.canvas.getContext('2d');
            //初始化
            p.init = function() {
                p.canvas.width = p.innerWidth;
                p.canvas.height = p.innerHeight;
                p.drawBackground();
                p.addOverlap();
                p.initDrawPoint();
                p.animation();
                p.mouseEvent();
                p.windowResize();
            };
            p.addOverlap=function(){
                p.overlap=document.createElement('div');
                p.overlap.style.width=p.innerWidth+'px';
                p.overlap.style.height=p.innerHeight+'px';
                p.overlap.style.position='absolute';
                p.overlap.style.top='0px';
                p.overlap.style.left='0px';
                p.overlap.style.zIndex='100';
                if(p.canvas.nextElementSibling){//??
                    p.canvas.parentNode.insertBefore(p.overlap,p.canvas.nextElementSibling);//insertBefore接收要插入的节点和作为参考的节点
                }else{
                    p.canvas.parentNode.appendChild(p.overlap);
                };
            };
            //粒子颜色
            p.color = function() {
                function random() {
                    return Math.round(Math.random() * 255);
                };
                this.r = random();
                this.g = random();
                this.b = random();//分别调用三次取随机值
                this.a = random(1, 0.8);
                this.rgba = 'rgba(' + this.r + ',' + this.g + ',' + this.b + ',' + this.a + ')';
                return this;
            };
            //获取随机数
            p.random = function(max, min) {
                var min = arguments[1] || 0;
                return Math.floor(Math.random() * (max - min + 1) + min);
            };
            //绘制背景图
            p.drawBackground = function() {
                if(!p.canvas) return;
                p.ctx.fillStyle = '#000';
                p.ctx.fillRect(0, 0, p.innerWidth, p.innerHeight);
            };
            //粒子
            p.point = function() {//每个粒子包括颜色,坐标、半径
                this.color = new p.color();
                this.x = Math.random() * p.innerWidth;//随机坐标
                this.y = Math.random() * p.innerHeight;
                this.vx = p.random(10, -10) / 40;//步进,调用p.random
                this.vy = p.random(10, -10) / 40;
                this.r = p.random(3, 1);//半径,调用p.random,半径最大为3,最小为1,在这个范围内波动
                this.scale = 1;//放大倍数
            };
            //初始化点
            p.initDrawPoint = function() {
                for(var i = 0; i < p.params.point; i++) {//所有点
                    var point = new p.point();
                    p.points.push(point);
                    p.ctx.beginPath();
                    p.ctx.fillStyle = point.color.rgba;
                    p.ctx.arc(point.x, point.y, point.r * point.scale, 0, Math.PI * 2, true);
                    p.ctx.fill();
                };
                p.ctx.closePath();
            };
            //点点连线
            p.connect = function() {
                function lineColor(p1, p2) {
                    var linear = p.ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);//起点终点坐标
                    linear.addColorStop(0, p1.color.rgba);//开始的颜色
                    linear.addColorStop(1, p2.color.rgba);//结束的颜色
                    return linear;
                };
                for(var i = 0; i < p.params.point; i++) {
                    for(var j = 0; j < p.params.point; j++) {
                        var p1 = p.points[i];
                        var p2 = p.points[j];
                        if(Math.abs(p2.x - p1.x) < p.params.minDis && Math.abs(p2.y - p1.y) < p.params.minDis) {//两点之间距离小于一定程度才连线
    
                            p.ctx.beginPath();
                            p.ctx.lineWidth = 0.2;
                            p.ctx.strokeStyle = lineColor(p1, p2);//采用渐变,描边样式
                            p.ctx.moveTo(p1.x, p1.y);
                            p.ctx.lineTo(p2.x, p2.y);
                            p.ctx.stroke();//描边,使用的是strokeStyle
                            p.ctx.closePath();
                        };
                    };
                };
            };
            p.lineto = function() {//和鼠标位置有关
                function isInView(point) {
                    return Math.abs(point.x - p.pageXY.pageX) < p.params.mouseDis && Math.abs(point.y - p.pageXY.pageY) < p.params.mouseDis;
                };
                (function line() {
                    function lineColor(p1, p2) {
                        var linear = p.ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);
                        linear.addColorStop(0, p1.color.rgba);
                        linear.addColorStop(1, p2.color.rgba);
                        return linear;
                    };
                    for(var i = 0; i < p.params.point; i++) {
                        for(var j = 0; j < p.params.point; j++) {
                            if(i != j) {
                                var p1 = p.points[i];
                                var p2 = p.points[j];
                                if(isInView(p1) && isInView(p2)) {
                                    if(Math.abs(p2.x - p1.x) < p.params.minDis && Math.abs(p2.y - p1.y) < p.params.minDis) {
                                        p.ctx.beginPath();
                                        p.ctx.lineWidth = 0.2;
                                        p.ctx.strokeStyle = lineColor(p1, p2);
                                        p.ctx.moveTo(p1.x, p1.y);
                                        p.ctx.lineTo(p2.x, p2.y);
                                        p.ctx.stroke();
                                        p.ctx.closePath();
                                    };
                                };
                            };
                        };
                    };
                })();
            };
            //无限循环动画
            p.animation = function() {
                p.ctx.clearRect(0, 0, p.innerWidth, p.innerHeight);
                p.drawBackground();
                for(var i = 0; i < p.params.point; i++) {
                    var point = p.points[i];
                    if(point.x < 0 || point.x > p.innerWidth) {//当小圆球碰到矩形壁以后反弹
                        point.vx = -point.vx;
                    };
                    if(point.y < 0 || point.y > p.innerHeight) {
                        point.vy = -point.vy;
                    };
                    p.ctx.beginPath();
                    p.ctx.fillStyle = point.color.rgba;
                    point.x += point.vx;  //小圆球不断移动
                    point.y += point.vy;
                    p.ctx.arc(point.x, point.y, point.r * point.scale, 0, Math.PI * 2, true);
                    p.ctx.fill();
                };
                if(p.params.effect == 'zoom') {
                    p.connect();//将小球与小球用线连接,鼠标移动事件定义在mouseEvent中
                } else if(p.params.effect == 'line') {
                    p.lineto();//该函数与鼠标位置有关,通过鼠标事件传入鼠标位置,在该位置附近连线
                };
                requestAnimationFrame(p.animation);
            };
            //鼠标事件
            p.mouseEvent = function() {
                p.overlap.addEventListener('mousemove', function(e) {//鼠标指针移动时触发div中的事件
                    var e = e || window.event;
                    var pageX = (e.clientX + document.body.scrollLeft || e.pageX) - this.offsetLeft;//offsetLeft指div到边框??
                    var pageY = (e.clientY + document.body.scrollTop || e.pageY) - this.offsetTop;
                    if(p.params.effect == 'zoom'){
                        for(var t = 0; t < p.params.point; t++) {
                            var point = p.points[t];
                            if(Math.abs(point.x - p.pageXY.pageX) < p.params.minDis && Math.abs(point.y - p.pageXY.pageY) < p.params.minDis) {//鼠标附近的点
                                point.scale = 5;
                            } else {
                                point.scale = 1;
                            };
                        };
                    };
                    p.pageXY.pageX = pageX;
                    p.pageXY.pageY = pageY;
                });
                p.overlap.addEventListener('mouseout', function(e) {//鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发
                    if(p.params.effect == 'zoom'){//zoom鼠标移出div都变为原来的比例
                        for(var i = 0; i < p.params.point; i++) {
                            var point = p.points[i];
                            if(point.scale != 1) {
                                point.scale = 1;
                            };
                        };
                    }else{
                        p.pageXY.pageX=p.innerWidth/2;//line方式鼠标移出div自动定位到中心
                        p.pageXY.pageY=p.innerHeight/2;
                    };
                });
            };
            p.windowResize = function() {
                window.addEventListener('resize', p.init);
            };
            p.init();
            return p;
        };
        //兼容requestAnimFrame
        window.requestAnimationFrame = (function() {//requestAnimationFrame??
            return window.requestAnimationFrame ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame ||
                function(callback) {//前面三个都不支持则采用该函数
                    window.setTimeout(callback, 1000 / 60);
                };
        })();
  • 相关阅读:
    轻松搭建基于 SpringBoot + Vue 的 Web 商城应用
    Serverless 实战 —— Funcraft + OSS + ROS 进行 CI/CD
    急速搭建 Serverless AI 应用:为你写诗
    O'Reilly 1500 份问卷调研:2019 年 Serverless 落地到底香不香?
    2019 阿里巴巴云原生这一年
    快速部署 Spring PetClinic 到函数计算平台
    1354. Construct Target Array With Multiple Sums
    1352. Product of the Last K Numbers
    1351. Count Negative Numbers in a Sorted Matrix
    1347. Minimum Number of Steps to Make Two Strings Anagram
  • 原文地址:https://www.cnblogs.com/yujihang/p/7003002.html
Copyright © 2011-2022 走看看