JS烟花案例优化版

Posted 小小荧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS烟花案例优化版相关的知识,希望对你有一定的参考价值。

技术图片

不明白为什么是烟花优化版本的先参考作者的烟花基础版本

烟花优化版本主要实在优化爆炸的范围和运动上做了优化,爆炸范围我们采用已圆的爆炸方式,以鼠标点击的位置为圆形爆炸的烟花效果

<!DOCTYPE html>
<!--
 * @Descripttion: 
 * @version: 
 * @Author: 小小荧
 * @Date: 2020-03-18 19:15:15
 * @LastEditors: 小小荧
 * @LastEditTime: 2020-03-18 20:31:12
 -->
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .container {
            width: 80%;
            height: 600px;
            border: 2px solid red;
            background: #000;
            margin: 20px auto;
            cursor: pointer;
            position: relative;
            left: 0;
            top: 0;
            overflow: hidden;
        }

        .fire {
            width: 10px;
            height: 10px;
            position: absolute;
            bottom: 0;
        }
    </style>
</head>

<body>
    <div class="container"></div>
    <script src="./js/animate.js"></script>
    <script src="./js/utils.js"></script>
    <script src="./js/index.js"></script>
    <script>
        let container_ele = document.querySelector(".container");
        container_ele.addEventListener("click", function(evt){
            var e = evt || event;
            new FireWork(e.offsetX, e.offsetY, ".container", "circular");
        })
    </script>
</body>

</html>

运动函数部分

/*
 * @Descripttion: 
 * @version: 
 * @Author: 小小荧
 * @Date: 2020-03-17 18:01:21
 * @LastEditors: 小小荧
 * @LastEditTime: 2020-03-18 20:49:13
 */
/**
 * 多属性的动画函数
 * @param {*} ele 需要运动的节点
 * @param {*} attr_options 传入的是一个需要运动的属性包括运动的目标值,操作的节点属性 
 * @param {*} timefn 运动的形式,默认是缓冲运动
 * @param {*} speed  运动的速度
 */
function animate(ele, attr_options, callback, timefn = "swing", speed = 5) {

    // 我们需要把传入的options处理成
    /* 
        {“width : {
            target : 200,
            iNow : 100
        }}这个形式
    */

    for (var attr in attr_options) {
        attr_options[attr] = {
            target: attr === "opacity" ? parseInt(attr_options[attr] * 100) : attr_options[attr],
            // 需要计算得到
            iNow: attr === "opacity" ? parseInt(getComputedStyle(ele)[attr] * 100) : parseInt(getComputedStyle(ele)[attr])
        }
    }

    //    为了防止每个节点的定时器冲突,每次进入的时候我们需要先清理下节点的定时器
    clearInterval(ele.timer);
    //    然后再去设置定时器
    ele.timer = setInterval(function () {

        // 因为是多属性运动,我们首先循环遍历每一个属性
        for (var attr in attr_options) {

            var target = attr_options[attr].target;

            var iNow = attr_options[attr].iNow;

            // 计算speed 判断是不是缓冲运动
            if (timefn === "swing") {
                speed = (target - iNow) / 20;
                // 为了防止速度无法达到一个整数
                speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
            }
            // 判断是不是匀速运动
            else if (timefn === "liner") {
                speed = attr_options[attr].iNow < attr_options[attr].target ? Math.abs(speed) : -Math.abs(speed);
            }
            // 运动之中条件的判断
            if (Math.abs(target - iNow) <= Math.abs(speed)) {
                console.log(1);
                if (attr === "opacity") {
                    ele.style[attr] = target / 100;
                } else {

                    ele.style[attr] = target + "px";

                }

                // 每次一个属性运动完成之后我们就直接将它删除
                delete attr_options[attr];

                // 每次都去循环看一下还有没有属性需要操作
                for (var num in attr_options) {
                    return false;
                }
                // 清理定时器 因为我们是一个定时器绑定多个属性操作所以我们需要保证所有的属性都完成之后我们才可以将定时器清除
                clearInterval(ele.timer);
                // 等结束之后我们需要判断这个回到函数是函数我们就回调
                typeof callback === "function" ? callback() : ""

            } else {
                attr_options[attr].iNow += speed;
                if (attr === "opacity") {
                    ele.style[attr] = attr_options[attr].iNow / 100;
                } else {
                    ele.style[attr] = attr_options[attr].iNow + "px";
                }
            }
        }


    }, 30);
}

工具类

 let res = "#";
        for (let i = 0; i < 6; i++) {
            res += parseInt(Math.random() * 10).toString(16);
        }
        return res;

核心烟花JS代码

/*
 * @Descripttion: 
 * @version: 
 * @Author: 小小荧
 * @Date: 2020-03-18 19:16:48
 * @LastEditors: 小小荧
 * @LastEditTime: 2020-03-21 13:51:37
 */
class FireWork {
    // 构造器
    /**
     * 
     * @param {*} x x轴坐标
     * @param {*} y y轴坐标
     * @param {*} seletor 选择器名
     */
    constructor(x, y, seletor, blastType) {
        // 父容器的节点 单例模式,因为这个父盒子只有一个随意每次创建烟花的时候我们需要判断一下,如果存在了这个父盒子我们就不需要再去冲去获取节点元素了
        if(FireWork.main && FireWork.main.seletor === seletor){
            this.main = FireWork.main.ele;
            console.log("dasd");
        }else {
            FireWork.main = {
                ele : document.querySelector(seletor),
                seletor : seletor,
            }
            this.main = FireWork.main.ele;
        }
        this.blastType = blastType;

        // 初始化
        this.init(x, y);
    }

    /**
     * 初始化方法
     * @param {*} x x的坐标 
     * @param {*} y y的坐标
     */
    init(x, y) {

        this.x = x;
        this.y = y;

        // 创建的烟花的节点
        this.ele = this.createFireWorkEle();
        // 运动的最大left值
        this.left_max = this.main.offsetWidth - this.ele.offsetWidth;
        // 运动的最大的top值
        this.top_max = this.main.offsetHeight - this.ele.offsetHeight;

        // 设置烟花的开始颜色
        this.randomColor(this.ele);
        // 烟花开始运动
        this.fireworkUp(this.ele);
    }
    /**
     * 创建烟花的元素
     */
    createFireWorkEle() {
        // 创建节点
        let ele = document.createElement("div");
        // 设置类名
        ele.className = "fire";
        // 在父容器追加节点
        this.main.appendChild(ele);
        return ele;
    }

    /**
     * 
     * 烟花运动的方法
     * @param {*} ele 运动的这个烟花
     */
    fireworkUp(ele) {

        // 设置left
        ele.style.left = this.x + "px";
        // 烟花向上的运动我们使用animate动画
        animate(ele, {
            top: this.y,
        }, () => {

            // 等到这个烟花运动结束之后呢我们需要将这个烟花给删除了
            ele.parentNode.removeChild(ele);
            // 结束之后烟花开始爆炸
            this.fireworkBlast();

        });

    }

    /**
     * 烟花爆炸的方法
     */
    fireworkBlast() {
        // 我们设置爆炸的数量为20
        for (let i = 0; i < 20; i++) {
            // 我们需要重新创建烟花的元素
            let ele = this.createFireWorkEle();
            // 给元素设置随机背景颜色和left,top,圆角属性值
            this.randomColor(ele);

            ele.style.left = this.x + "px";

            ele.style.top = this.y + "px";

            ele.style.borderRadius = "50%";

            // 然后我们需要让这些元素开始运动,先获取随机坐标带你
            animate(ele, this.blastType === "circular" ? this.circularBlast(i, 20) : this.randomPos(), () => {
                // 删除烟花
                ele.parentNode.removeChild(ele)
            });
        }
    }

    /**
     * 原型烟花爆炸状态
     * @param {*} now_index 当前的元素下标
     * @param {*} total 总共的下标
     */
    circularBlast(now_index, total) {
        // 设定圆的半径为100
        let r = 100;
        // 我们需要计算圆的角度
        let deg = now_index / total * 360;
        // 在计算弧度
        let reg = Math.PI / 180 * deg;

        // 返回结果
        return {
            left: parseInt(Math.cos(reg) * r) + this.x,
            top: parseInt(Math.sin(reg) * r) + this.y,
        }
    }

    /**
     * 随机获取坐标点
     */
    randomPos() {
        return {
            left: Math.round(Math.random() * this.left_max),
            top: Math.round(Math.random() * this.top_max)
        }
    }

    /**
     * 
     * 随机背景颜色
     * @param {*} ele 小烟花的元素
     */
    randomColor(ele) {

        return ele.style.backgroundColor = utils.randomColor();
    }

}

以上是关于JS烟花案例优化版的主要内容,如果未能解决你的问题,请参考以下文章

机器学习实战应用案例100篇(十七)-烟花算法从原理到实战应用

机器学习实战应用案例100篇(十七)-烟花算法从原理到实战应用

Android在canvas中实现高性能的烟花/粒子特效

烟花代码,予心上人最璀璨烟花—— 附源码与成品(HTML+CSS+JS)

单目标优化求解 基于matlab烟花算法求解单目标问题含Matlab源码 1599期

Js烟花代码分享