阅读 361

如何画一条抛物线引导成烟花炸开效果?看这篇就够了

这是我参与8月更文挑战的第 4 天,活动详情查看: 8月更文挑战

老规矩,先点赞在查看,谢谢

描述

最近要实现一个抛物线运动到指定地点,然后喷发更多的抛物线运动,其实就像烟花一样的效果

思路

  • 刚开始,我本来想走css动画的路线的,因为css使用animate做动画,对浏览器性能会有好很多,特别是这些抛物线多且长,一直执行渲染的话,对浏览器确实不太友好。
  • 寻找了许久,发现贝塞尔曲线在css中使用只是控制运动物体的速度,并不是用来控制物体的抛物线的,这就让我痛苦万分,如果想要使用css做一个抛物线运动,那我们只能使用2个div去实现,css实现的思路:2个div,一个父级,一个子级,2个元素都要绑定过渡动画属性transition: all 2s cubic-bezier(0,1.26,.51,1.35);,添加后就让他运动起来,运动的话其实要使用transform: translateX(100px)进行左右移动,分别给父级向上位移,给子元素向下移动,然后就形成了抛物线的卑微效果。
  • 主角
    • 使用css效果好像并不能达到我想要的效果,并且要控制运动也不容易,于是百度一番,找到了一个新的方法,就是使用贝塞尔曲线运动画路径的方法js贝塞尔曲线路径点,写的不错,并且直接使用就可以了,曲线计算方法如下:(说实话,我看不懂,数学的奥秘)

image.png

  • 具体使用方法很简单,你想要画什么曲线都可以,只需要把坐标位置写上去,然后就会遍历出密密麻麻的点,连接起来就是你想要的曲线轨迹,此公式威力巨大。

代码

  • 首先我们来看看公式转换成代码后,是怎样写的 (以下是共用函数,接下来的例子我不重复写了,你们记得要引入)
//anchorpoints:贝塞尔基点
//pointsAmount:生成的点数    
//return 路径点的Array
        function CreateBezierPoints(anchorpoints, pointsAmount) {
            var points = [];
            for (var i = 0; i < pointsAmount; i++) {
                var point = MultiPointBezier(anchorpoints, i / pointsAmount);
                points.push(point);
            }
            return points;
        }

        function MultiPointBezier(points, t) {
            var len = points.length;
            var x = 0, y = 0;
            var erxiangshi = function (start, end) {
                var cs = 1, bcs = 1;
                while (end > 0) {
                    cs *= start;
                    bcs *= end;
                    start--;
                    end--;
                }
                return (cs / bcs);
            };
            for (var i = 0; i < len; i++) {
                var point = points[i];
                x += point.x * Math.pow((1 - t), (len - 1 - i)) * Math.pow(t, i) * (erxiangshi(len - 1, i));
                y += point.y * Math.pow((1 - t), (len - 1 - i)) * Math.pow(t, i) * (erxiangshi(len - 1, i));
            }
            return { x: x, y: y };
        }
复制代码
  • 知道怎么一个函数,然后我们来画一条长长的抛物线,固定2点,画起来
<div>
      <div id="move_div" ref="flagMove"
        style=" position: absolute; left: 0px; top: 0px; height: 10px; width: 10px; background-color: red;"
      ></div>
      <div
        v-for="item in flagPoint" :key="item.x" :style="'left:' + item.x + 'px;' + 'top:' + item.y + 'px;'"
        style="position: absolute; width: 2px; height: 2px; overflow: hidden; background-color: #ff0000;"
      ></div>
    </div>
复制代码
data() {
    return {
      flagPoint: [],
      flagCss: {},
      }
    },
 mounted() {
    this.startFlag();
 },
methods: {
    startFlag() {
      let that = this;
      let flagPoint = this.flagPoint;
      let index = 0;
      let ps = [
        { x: 100, y: 800 },
        { x: 200, y: 400 },
        { x: 500, y: 100 },
        { x: 800, y: 200 },
        { x: 1000, y: 350 },
      ];
      flagPoint = CreateBezierPoints(ps, 800);
      let moveobj = this.$refs.flagMove;
      console.log(moveobj, "moveobj");
      let timer = setInterval(function () {
        let p = flagPoint[index];
        // console.log(p.x);
        moveobj.style.left = p.x + "px";
        moveobj.style.top = p.y + "px";
        // moveobj.css({ left: p.x, top: p.y });
        index++;
        if (index >= flagPoint.length) {
          index = 0;
          clearInterval(timer);
        }
      }, 1000 / 100);
      this.flagPoint = flagPoint;
    },
复制代码

渲染出来的效果图:

image.png

  • 当运动点到顶端后,我们就开始画烟花一样的效果了,只是多调一下封装好的函数而已,简单直接上代码
<div>
      <div :id="'move_div'+index" v-for="(item, index) in signList" :key="index" :ref="'sign' + index"
        style="position: absolute; left: 0px; top: 0px; height: 10px; width: 10px; background-color: red;"
      ></div>
      <div v-for="(item, index) in guijiPointList" :key="index">
        <div v-for="(items) in item" :key="items.x" :style="'left:' + items.x + 'px;' + 'top:' + items.y + 'px;'"
        style="position: absolute; width: 2px; height: 2px; overflow: hidden; background-color: #ff0000;"
      ></div>
      </div>
    </div>
复制代码
data() {
    return {
      signList: [
        [
          { x: 1000, y: 350 },
          { x: 1000, y: 200 },
          { x: 1100, y: 150 },
          { x: 1050, y: 120 },
          { x: 1000, y: 100 },
        ],
        [
          { x: 1000, y: 350 },
          { x: 1000, y: 200 },
          { x: 1030, y: 250 },
          { x: 1050, y: 220 },
          { x: 1100, y: 200 },
        ],
        [
          { x: 1000, y: 350 },
          { x: 1000, y: 200 },
          { x: 1050, y: 220 },
          { x: 1100, y: 250 },
          { x: 1200, y: 300 },
        ],
        [
          { x: 1000, y: 350 },
          { x: 1000, y: 200 },
          { x: 1100, y: 250 },
          { x: 1200, y: 300 },
          { x: 1300, y: 400 },
        ],
        [
          { x: 1000, y: 350 },
          { x: 1000, y: 200 },
          { x: 1050, y: 300 },
          { x: 1100, y: 400 },
          { x: 1150, y: 450 },
        ],
        [
          { x: 1000, y: 350 },
          { x: 1000, y: 200 },
          { x: 950, y: 400 },
          { x: 900, y: 500 },
          { x: 1000, y: 600 },
        ],
        [
          { x: 1000, y: 350 },
          { x: 1000, y: 200 },
          { x: 950, y: 250 },
          { x: 900, y: 300 },
          { x: 800, y: 400 },
        ],
        [
          { x: 1000, y: 350 },
          { x: 1000, y: 200 },
          { x: 850, y: 250 },
          { x: 700, y: 280 },
          { x: 600, y: 300 },
        ],
        [
          { x: 1000, y: 350 },
          { x: 1000, y: 200 },
          { x: 900, y: 250 },
          { x: 750, y: 220 },
          { x: 650, y: 200 },
        ],
        [
          { x: 1000, y: 350 },
          { x: 1000, y: 200 },
          { x: 900, y: 220 },
          { x: 800, y: 150 },
          { x: 700, y: 100 },
        ],
        [
          { x: 1000, y: 350 },
          { x: 1000, y: 200 },
          { x: 980, y: 220 },
          { x: 950, y: 150 },
          { x: 900, y: 100 },
        ],
      ],
      guijiPointList: []
    };
  },
  methods: {
      morePoint() {
      let that = this;
      let ps1 = this.signList;
      ps1.forEach(function (obj, i) {
        console.log(obj, "obj", i);
        that.signPoint(obj, i);
      });
    },
    signPoint(data, i) {
      // console.log(data, "data");
      let flagPoint = [];
      let index = 0;
      let ps = data;
      flagPoint = CreateBezierPoints(ps, 500);
      this.guijiPointList.push(flagPoint);
      let moveobj = this.$refs[`sign${i}`][0];
      if(!moveobj) return;
      let timer = setInterval(function () {
        let p = flagPoint[index];
        moveobj.style.left = p.x + "px";
        moveobj.style.top = p.y + "px";
        // moveobj.css({ left: p.x, top: p.y });
        index++;
        if (index >= flagPoint.length) {
          index = 0;
          clearInterval(timer);
        }
      }, 1000 / 100);
    },
  }
复制代码

最好得到的效果就是如下:

image.png

总结

注意这里需要说明下,坐标点是可以自己增加或减少的,看轨迹需要来增减吧,我这边只是做个大概效果,具体更好看的效果只能自己动手丰衣足食了

文章分类
前端
文章标签