js实现购物车的抛物线

我们经常在电商网站上买东西,当我们将心仪的商品加入购物车时,可能碰到下面的画面。
js实现购物车的抛物线_第1张图片
注意小球的运动,请自主忽略画技;
小球的运动轨迹呈现抛物线,且小球的体积由大变小在由小变大;对于一个编程人员,不探究其原理都可能睡不着,所以就研究一下其原理;
首先小球的运动轨迹是一个抛物线,则我们可以使用抛物线方程来计算水平方向和垂直方向的关系;
js实现购物车的抛物线_第2张图片
求抛物线的方程首先的需要至少最少三个坐标点,当然三个坐标点你肯定知道了或者你可以设定,开始与结束的坐标点是一定的,第三个坐标点是小球运动的最高点;
再者小球的体积变化和小球水平运动也可以使用方程来表示:
js实现购物车的抛物线_第3张图片
y轴表示小球的缩放变化,小球的变化是通过transform: scale(xxx)来表示,如scale变化从1 –> 0.1 –> 1;
注意:
小球在屏幕运动的最小单位是1px,所以你计算的时候需要把运动结果的取整;

<main class="main flex-center">
     <section class="rectangle">
         <section class="wrapper max-size">
             <span class="ball">span>
         section>
     section>
 main>
html, body, .main {
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: #000;
}
.main {
    position: relative;
    .rectangle {
        position: absolute;
        width: 50%;
        height: 400px;
        .wrapper {
            position: relative;
            .ball {
                position: absolute;
                left: 11rem;
                top: 380px;
                display: inline-block;
                width: 20px;
                height: 20px;
                border-radius: 50%;
                background: #fff;
            }
            &:before, &:after {
                position: absolute;
                background: #f00;
                content: '';
                display: block;
            }
            &:before {
                left: -1px;
                bottom: px2rem(-20);
                width: 1px;
                height: 100%;
            }
            &:after {
                left: px2rem(-20);
                bottom: -1px;
                width: 100%;
                height: 1px;
            }
        }
    }
}
class BallAnimation {
        constructor() {
            this.ball = document.querySelector('.rectangle .ball');
            this.startPosition = {
                x: this.ball.offsetLeft,
                y: this.ball.offsetTop
            };
            this.endPosition = {
                x: 37,
                y: 389
            };
            this.timer = null;
            this.duaration = 800;
            this.timerTime = 60;
            this.diffDis = Math.floor(this.endPosition.x - this.startPosition.x);
            this.direct = this.diffDis > 0? 1 : -1;
            this.counts = this.duaration / this.timerTime;
            this.speed = Math.floor(this.diffDis / this.counts);

            TB.print('constructor function: ', {
                startPosition: this.startPosition,
                speed: this.speed
            });
        }

        init() {
            this.start();
        }

        getBallPositionY(x) {
            return (-90/7569) * x * x + (22320/7569) * x -746783/7569;
        }

        getBallScale(x) {
            let middle = Math.floor(Math.abs(this.endPosition.x - this.startPosition.x));
            if (x < middle){
                return (-9/970) * x + (1303/970);
            } else {
                return (9/770) * x - (1129/770);
            }
        }

        setBallStyle(x = 0) {
            this.ball.style.left = x + 'px';
            this.ball.style.top = this.endPosition.y - Math.floor(this.getBallPositionY(x)) + 'px';
            this.ball.style.transform = 'scale(' + parseFloat(this.getBallScale(x), 2) + ')';
        }

        start() {
            let surplusDistance = Math.floor(Math.abs(this.endPosition.x - this.startPosition.x) % Math.abs(this.speed));

            this.endPosition.x = this.endPosition.x + this.direct * -1 * surplusDistance;

            this.timer = setInterval(() => {
                let _left;
                if (this.ball.offsetLeft == this.endPosition.x) {
                    _left = this.ball.offsetLeft + (this.direct * surplusDistance);
                    this.setBallStyle(_left);
                    clearInterval(this.timer);
                    this.timer = null;
                } else {
                    _left = this.ball.offsetLeft + this.speed;
                    this.setBallStyle(_left);
                }
            }, this.timerTime);
        }
    }

    let ballAnimate = new BallAnimation();
    ballAnimate.init();

而垂直方向和小球体积变化都与水平的方向都相同,所以只需要关心水平方向的运动;
当然我们都清楚任何运动都是通过定时器来实现,定时器的每次变化其实水平方向的运动一部分,但是通过js中的speed变量可知,运动到最后可知不可能完美的到达终点,实际上会超出一些,所以我们将最后不足的一部分距离单独拿出来,最后将该距离作为speed,则这样的话就可以100%到达终点;
再来复习一下高中的求方程吧:

抛物线方程: a*x*x + b*x + c = y;

坐标点:(37, 10) (124, 100) (211, 10);

(37 * 37)a + 37b + c = 10;
(124 * 124)a + 124b + c = 100;
(211 * 211)a + 211b + c = 10;

(211*211 - 37*37)a + (211 - 37)b = 0;       =>      43152a + 174b = 0;
(124*124 - 37*37)a + (124 - 37)b = 90;      =>      14007a + 87b = 90;      => 28014a + 174b = 180;

15138a = -180;      
a = (-90/7569);

87b = 90 + 14007 * (90/7569);       =>      (90* 7569 + 14007 * 90)/7569;   
b = 22320/7569;

c = (10*7569 + 37*37*90 - 37*22320)/7569;
c = (-746783/7569);

直线方程
(37, 1) (134, 0.1) (211, 1)

37a + b = 1;
134a + b = 0.1;
211a + b = 1;

97a = -0.9;
a = -9/970;
b = 1303/970;

77a = 0.9;
a = 9 /770;
b = -1129/770; 

你可能感兴趣的:(程序员笔记,web开发笔记)