• fabric.js动画制作简单的落雪效果播放


    老规矩先上代码

      1 <template>
      2   <div class="animate">
      3     <el-button
      4       id="toggle"
      5       @keyup.space.native
      6       class="elBtn"
      7       :class="{ active: isFirst && autoPlay }"
      8       >▷</el-button
      9     >
     10     <canvas id="canvas"></canvas>
     11   </div>
     12 </template>
     13 
     14 <script>
     15 import { fabric } from "fabric";
     16 export default {
     17   data() {
     18     return {
     19       // radius/left/top/opacity is belong to circle
     20       radius: [],
     21       left: [],
     22       top: [],
     23       opacity: [],
     24       // decide the tag of first pause
     25       isFirst: false,
     26       // autoPlay is the same statement with [playing]
     27       autoPlay: false,
     28     };
     29   },
     30   mounted() {
     31     let playing = false;
     32     let snowBallN = 100;
     33     let cir = [];
     34 
     35     this.radius = Array(snowBallN).fill("");
     36     this.left = Array(snowBallN).fill("");
     37     this.top = Array(snowBallN).fill("");
     38     this.opacity = Array(snowBallN).fill("");
     39 
     40     const windowSize = {
     41        "1000",
     42       height: "600",
     43     };
     44 
     45     // 产生静态 canvas
     46     const canvas = new fabric.StaticCanvas("canvas", {
     47       height: windowSize.height,
     48        windowSize.width,
     49     });
     50 
     51     //animate(设置动画属性,动画结束值,可选对象)
     52     //可选对象为动画详细信息,包括持续时间、回调、缓动等
     53     //在每个动画帧上调用canvas.renderAll才能够看到实际的动画,重新渲染
     54 
     55     // add snowBallN circle
     56     for (let i = 0; i < snowBallN; i++) {
     57       // cir Array is the gather of the single CIRCLE ANIMATION
     58       cir[i] = new fabric.Circle({
     59         radius: getRandomInt(0.1, 1),
     60         left: getRandomInt(0, windowSize.width),
     61         top: getRandomInt(0, windowSize.height),
     62         opacity: getRandomInt(0.1, 1),
     63         fill: "#fff",
     64       });
     65       // tag the last add cir[i]
     66       cir[i].lastAdd = i === snowBallN - 1;
     67       canvas.add(cir[i]);
     68       // set animate when it achieve the last circle
     69       playing && setAnimate(cir[i]);
     70     }
     71     console.log("Circle Array", cir);
     72 
     73     // pause button
     74     document.querySelector("#toggle").addEventListener("click", (e) => {
     75       const targetEl = e.target;
     76       this.isFirst = true;
     77 
     78       // When playing is true, it should save the statement.
     79       if (playing) {
     80         targetEl.innerHTML = "▷";
     81 
     82         for (let i = 0; i < snowBallN; i++) {
     83           this.radius[i] = canvas.getObjects()[i].radius;
     84           this.left[i] = canvas.getObjects()[i].left;
     85           this.top[i] = canvas.getObjects()[i].top;
     86           this.opacity[i] = canvas.getObjects()[i].opacity;
     87         }
     88         // EveryTime, this array and the next is same,
     89         // but the root of CANNOT SAVE is the simple CIRCLE.
     90         // Just load every circle into the big cir Array, it's done.
     91         // console.table("暂停Before Pause this.left", this.left.slice(0, 5));
     92         // console.table("Before Pause this.top", this.top.slice(0, 5));
     93       } else {
     94         // Else, it should load in the shape what'll move.
     95         targetEl.innerHTML = "▢";
     96         // console.log("this.left[0]", this.left[0]);
     97         // think about the initial suitation, it should be divided.
     98         // When radius/left/top/opacity array isn't null, it should reload in cir.
     99         if (this.left[0]) {
    100           for (let i = 0; i < snowBallN; i++) {
    101             cir[i].set("radius", this.radius[i]);
    102             // console.log("INNER DPACE", this.left[i]);
    103             cir[i].set("left", this.left[i]);
    104             cir[i].set("top", this.top[i]);
    105             cir[i].set("opacity", this.opacity[i]);
    106           }
    107         }
    108         //   console.table("开始Before Play this.left", this.left.slice(0, 5));
    109         //   console.table("Before Play this.top", this.top.slice(0, 5));
    110         // When it begin to play first, every circle need to set Animation.
    111         canvas.getObjects().forEach((key) => setAnimate(key));
    112       }
    113       this.autoPlay = !this.autoPlay;
    114 
    115       // Change statement model
    116       playing = !playing;
    117     });
    118     // get Random number
    119     function getRandomInt(min, max) {
    120       return Math.floor(Math.random() * (max - min + 1)) + min;
    121     }
    122 
    123     // 设定动画函数
    124     function setAnimate(circle) {
    125       // 变化半径
    126       circle.animate("radius", getRandomInt(0.1, 5), {
    127         duration: getRandomInt(1000, 5000),
    128       });
    129       // 变化透明度
    130       circle.animate("opacity", getRandomInt(0.1, 0.9), {
    131         duration: getRandomInt(1000, 5000),
    132       });
    133       // 变化坐标
    134       circle.animate("left", getRandomInt(0, windowSize.width), {
    135         easing: fabric.util.ease.easeInOutCubic,
    136         duration: getRandomInt(1000, 5000),
    137       });
    138       // 变化坐标
    139       circle.animate("top", getRandomInt(0, windowSize.height), {
    140         // onChange and onComplete is two statement about the animation
    141         // onChange decide the movement,
    142         // onComplete decide the end action when the animation ends.
    143         onChange: () => {
    144           if (circle.lastAdd) playing && canvas.renderAll();
    145         },
    146         onComplete: () => playing && setAnimate(circle),
    147         easing: fabric.util.ease.easeInOutCubic,
    148         duration: getRandomInt(1000, 5000),
    149       });
    150     }
    151   },
    152 };
    153 </script>
    154 <style>
    155 .animate {
    156   background-image: url(../assets/black.png);
    157   position: absolute;
    158   display: flex;
    159   justify-content: center;
    160   align-items: center;
    161 }
    162 #toggle {
    163   position: absolute;
    164   z-index: 999;
    165    200px;
    166   height: 200px;
    167   font-size: 100px;
    168 }
    169 .elBtn {
    170   opacity: 0.4;
    171 }
    172 .active {
    173   opacity: 0;
    174 }
    175 </style>
    View Code

    这个落雪效果是我仿照

    Fabric.js 动画 - 略知三二一 (321332211.com)

    这个网页的一百个圆随机动画制作的,加入了暂停与恢复播放的状态保存,优化了暂停播放按钮效果,在第一次通过鼠标点击播放后能够使用空格控制播放。

    注意点:每次animation动画暂停(onChange),如果不保存状态,就会从随机位置再次播放!←我设定的是这样的

    做的还是有点麻瓜,过程也有点不撞南墙不回头的意思,一直重复着一百个雪花的失败,脑袋都不清醒了,晚上睡觉前忽然想到要控制下数量,化繁为简,早上立马就发现问题所在了!总之,还是要淡定~

    效果如图

    人生到处知何似,应似飞鸿踏雪泥。
  • 相关阅读:
    (纯代码)QQ登录界面:
    (纯代码)图片浏览器:
    (纯代码 )transform旋转:
    苹果API常用英语名词:
    纯代码创建Button控件:
    GCD
    UISegmentedControl 开发笔记
    UISwitch 开关控件 开发笔记
    Xcode6中怎么添加空工程模板
    HTTP Live Streaming直播(iOS直播)技术分析与实现
  • 原文地址:https://www.cnblogs.com/lepanyou/p/15165115.html
Copyright © 2020-2023  润新知