This is the 4th day of my participation in the August More Text Challenge

Same old rule. Click “like” and check. Thank you

describe

Recently, the goal was to achieve a parabolic movement to a specific location, and then erupt more parabolic movement, in effect, like a firework

Train of thought

  • At first, I wanted to go the CSS animation route, because CSS usesanimateAnimation is much better for browser performance, especially if these parabolas are so many and long that rendering all the time is really not browser-friendly.
  • After looking for a long time, I found that Bessel curve in CSS is only used to control the speed of the moving object, not to control the parabola of the object, which made me extremely painful. If we want to use CSS to do a parabolic motion, we can only use two divs to achieve the CSS implementation idea: Transition: all 2s cubic-bezier(0,1.26,.51,1.35); To make it move, use transform: translateX(100px) to move it left and right, move the parent up and the child down, and then create the humble effect of parabola.
  • The protagonist
    • Effect of using CSS and seems to be able to achieve the result that I want, and it’s not easy to control movement, and baidu, found a new method, is to use the bezier curve motion path of painting methods of js Bessel curve points, write well, and directly use, curve calculation method is as follows: to be honest, I don’t understand, the mysteries of math)

  • It’s very simple, you can draw any curve you want, you just write the coordinates on it, and then you have a bunch of points that you can connect to the path you want, and it’s a very powerful formula.

code

  • So first of all, what does this formula look like when it’s translated into code(The following are common functions, and I’m not going to repeat the examples, so you have to introduce them.)
// Anchorpoints
//pointsAmount: number of points generated
//return pathpoint 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 };
        }
Copy the code
  • You know what a function is, and then let’s draw a long parabola, fixed 2 points. Let’s draw it, okay
<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>
Copy the code
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; },Copy the code

Renderings:

  • When the motion point reaches the top, we start to draw the fireworks effect, just adjust the packaged function, simple and direct to the code
<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>
Copy the code
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); }},Copy the code

The best results are as follows:

conclusion

Note that the coordinate points can be increased or decreased by themselves, depending on the trajectory needs to be increased or decreased, I just make a general effect, specific better effect can only be done by yourself