• js 抛物线 笔记备份


        var funParabola = function(element, target, options) {
                /*
                 * 网页模拟现实需要一个比例尺
                 * 如果按照1像素就是1米来算,显然不合适,因为页面动不动就几百像素
                 * 页面上,我们放两个物体,200~800像素之间,我们可以映射为现实世界的2米到8米,也就是100:1
                 * 不过,本方法没有对此有所体现,因此不必在意
                */
                
                var defaults = {
                    speed: 166.67, // 每帧移动的像素大小,每帧(对于大部分显示屏)大约16~17毫秒
                    curvature: 0.001,  // 实际指焦点到准线的距离,你可以抽象成曲率,这里模拟扔物体的抛物线,因此是开口向下的
                    progress: function() {},
                    complete: function() {}
                };
                
                var params = {}; options = options || {};
                
                for (var key in defaults) {
                    params[key] = options[key] || defaults[key];
                }
                
                var exports = {
                    mark: function() { return this; },
                    position: function() { return this; },
                    move: function() { return this; },
                    init: function() { return this; }
                };
                
                /* 确定移动的方式 
                 * IE6-IE8 是margin位移
                 * IE9+使用transform
                */
                var moveStyle = "margin", testDiv = document.createElement("div");
                if ("oninput" in testDiv) {
                    ["", "ms", "webkit"].forEach(function(prefix) {
                        var transform = prefix + (prefix? "T": "t") + "ransform";
                        if (transform in testDiv.style) {
                            moveStyle = transform;
                        }
                    });        
                }
                
                // 根据两点坐标以及曲率确定运动曲线函数(也就是确定a, b的值)
                /* 公式: y = a*x*x + b*x + c;
                */
                var a = params.curvature, b = 0, c = 0;
                
                // 是否执行运动的标志量
                var flagMove = true;
                
                if (element && target && element.nodeType == 1 && target.nodeType == 1) {
                    var rectElement = {}, rectTarget = {};
                    
                    // 移动元素的中心点位置,目标元素的中心点位置
                    var centerElement = {}, centerTarget = {};
                    
                    // 目标元素的坐标位置
                    var coordElement = {}, coordTarget = {};
                    
                    // 标注当前元素的坐标
                    exports.mark = function() {
                        if (flagMove === false) return this;
                        if (typeof coordElement.x == "undefined") this.position();
                        element.setAttribute("data-center", [coordElement.x, coordElement.y].join());
                        target.setAttribute("data-center", [coordTarget.x, coordTarget.y].join());
                        return this;
                    }
                    
                    exports.position = function() {
                        if (flagMove === false) return this;
                        
                        var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft,
                            scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
                        
                        // 初始位置
                        if (moveStyle == "margin") {
                            element.style.marginLeft = element.style.marginTop = "0px";
                        } else {
                            element.style[moveStyle] = "translate(0, 0)";
                        }
                        
                        // 四边缘的坐标
                        rectElement = element.getBoundingClientRect();
                        rectTarget = target.getBoundingClientRect();
                        
                        // 移动元素的中心点坐标
                        centerElement = {
                            x: rectElement.left + (rectElement.right - rectElement.left) / 2 + scrollLeft,
                            y: rectElement.top + (rectElement.bottom - rectElement.top) / 2    + scrollTop
                        };
                        
                        // 目标元素的中心点位置
                        centerTarget = {
                            x: rectTarget.left + (rectTarget.right - rectTarget.left) / 2 + scrollLeft,
                            y: rectTarget.top + (rectTarget.bottom - rectTarget.top) / 2 + scrollTop        
                        };
                        
                        // 转换成相对坐标位置
                        coordElement = {
                            x: 0,
                            y: 0    
                        };
                        coordTarget = {
                            x: -1 * (centerElement.x - centerTarget.x),
                            y:  -1 * (centerElement.y - centerTarget.y)    
                        };
                        
                        /*
                         * 因为经过(0, 0), 因此c = 0
                         * 于是:
                         * y = a * x*x + b*x;
                         * y1 = a * x1*x1 + b*x1;
                         * y2 = a * x2*x2 + b*x2;
                         * 利用第二个坐标:
                         * b = (y2+ a*x2*x2) / x2
                        */
                        // 于是
                        b = (coordTarget.y - a * coordTarget.x * coordTarget.x) / coordTarget.x;    
                        
                        return this;
                    };        
                    
                    // 按照这个曲线运动
                    exports.move = function() {
                        // 如果曲线运动还没有结束,不再执行新的运动
                        if (flagMove === false) return this;
                        
                        var startx = 0, rate = coordTarget.x > 0? 1: -1;
    
                        var step = function() {
                            // 切线 y'=2ax+b
                            var tangent = 2 * a * startx + b; // = y / x
                            // y*y + x*x = speed
                            // (tangent * x)^2 + x*x = speed
                            // x = Math.sqr(speed / (tangent * tangent + 1));
                            startx = startx + rate * Math.sqrt(params.speed / (tangent * tangent + 1));
                            
                            // 防止过界
                            if ((rate == 1 && startx > coordTarget.x) || (rate == -1 && startx < coordTarget.x)) {
                                startx = coordTarget.x;
                            }
                            var x = startx, y = a * x * x + b * x;
                            
                            // 标记当前位置,这里有测试使用的嫌疑,实际使用可以将这一行注释
                            element.setAttribute("data-center", [Math.round(x), Math.round(y)].join());
                            
                            // x, y目前是坐标,需要转换成定位的像素值
                            if (moveStyle == "margin") {
                                element.style.marginLeft = x + "px";
                                element.style.marginTop = y + "px";
                            } else {
                                element.style[moveStyle] = "translate("+ [x + "px", y + "px"].join() +")";
                            }
                            
                            if (startx !== coordTarget.x) {
                                params.progress(x, y);
                                window.requestAnimationFrame(step);    
                            } else {
                                // 运动结束,回调执行
                                params.complete();
                                flagMove = true;    
                            }
                        };
                        window.requestAnimationFrame(step);
                        flagMove = false;
                        
                        return this;
                    };
                    
                    // 初始化方法
                    exports.init = function() {
                        this.position().mark().move();
                    };
                }
                
                return exports;
            }
    
    
    
    /* 元素 */
     var element = document.getElementById("element"), target = document.getElementById("target");
    
    // 抛物线元素的的位置标记
     var parabola = funParabola(element, target).mark();
    
    // 抛物线运动的触发
     document.body.onclick = function() {
         element.style.marginLeft = "0px";
         element.style.marginTop = "0px";
         parabola.init();
     };
    /* 元素 */
    var element = document.getElementById("element"), 
      target = document.getElementById("target");
    // 抛物线元素的的位置标记
    var parabola = funParabola(element, target).mark();
    // 抛物线运动的触发
    document.body.onclick = function() {
      element.style.marginLeft = "0px";
      element.style.marginTop = "0px";
      parabola.init();
    };
    加入购物车实战:
    /* 本demo演示脚本基于ieBetter.js, 项目地址:https://github.com/zhangxinxu/ieBetter.js */
    
    // 元素以及其他一些变量
    var eleFlyElement = document.querySelector("#flyItem"), eleShopCart = document.querySelector("#shopCart");
    var numberItem = 0;
    // 抛物线运动
    var myParabola = funParabola(eleFlyElement, eleShopCart, {
      speed: 400,
      curvature: 0.002,  
      complete: function() {
        eleFlyElement.style.visibility = "hidden";
        eleShopCart.querySelector("span").innerHTML = ++numberItem;
      }
    });
    // 绑定点击事件
    if (eleFlyElement && eleShopCart) {
      [].slice.call(document.getElementsByClassName("btnCart")).forEach(function(button) {
        button.addEventListener("click", function() {
          // 滚动大小
          var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft || 0,
            scrollTop = document.documentElement.scrollTop || document.body.scrollTop || 0;
    
          eleFlyElement.style.left = event.clientX + scrollLeft + "px";
          eleFlyElement.style.top = event.clientY + scrollTop + "px";
          eleFlyElement.style.visibility = "visible";
          
          // 需要重定位
          myParabola.position().move(); 
        });
      });
    }
    

      

    学习版本

    <!DOCTYPE html>
    <html lang="en" >
    
    <head>
    
      <meta charset="UTF-8">
      <link rel="shortcut icon" type="image/x-icon" href="https://static.codepen.io/assets/favicon/favicon-8ea04875e70c4b0bb41da869e81236e54394d63638a1ef12fa558a4a835f1164.ico" />
      <link rel="mask-icon" type="" href="https://static.codepen.io/assets/favicon/logo-pin-f2d2b6d2c61838f7e76325261b7195c27224080bc099486ddd6dccb469b8e8e6.svg" color="#111" />
      <title>CodePen - gwcpwx</title>
      
      
      
      
          <style>
          #goods {  
      cursor: pointer;
      width: 100px;
      height: 40px;
      line-height: 40px;
      border: 1px solid deeppink;
      text-align: center;
      color: deeppink;  
    }  
    #goods:hover {  
      color: #fff;  
      background-color: deeppink;  
    }
    #cart {
      position: fixed;
      right: 0;
      bottom: 100px;
      color: deeppink;
      border: 1px solid deeppink;  
    }  
        </style>
    
      <script>
    
    </script>
    
     
    
    </head>
    
    <body translate="no" >
    y = ax² + bx + c
      <div id="goods"> 
    商品
    </div> 
    
    
    <br><br><br><br>
    <br><br><br><br><br> 
    <br><br><br><br><br>
    <div id="cart"> 
    购物车  
    </div>
    
     
    
        <script >
              var goodsDom = document.querySelector("#goods");
        var cartDom = document.querySelector("#cart");
        goodsDom.onclick = function () {
        var goodsXLeft = goodsDom.offsetLeft;
        var goodsYTop = goodsDom.offsetTop;
        var startX = goodsXLeft + 100;
        var startY = goodsYTop - document.body.scrollTop + 12;
        var endX = cartDom.offsetLeft;
        var endY = cartDom.offsetTop;
        var diffX = endX - startX;
        var diffY = endY - startY;
        //  假设中点(0, 0),也就是方程中的c为0
        var c = 0;
        var a = (endY/endX-startY/startX)/(endX - startX);
        var b = endY/endX - a*endX;
        // 创建一个移动的dom
        var movingDom = document.createElement("div");
        movingDom.style.position = 'fixed';
        movingDom.style.left = startX + 'px';
        movingDom.style.top = startY + 'px';
        movingDom.style.height = '16px';
        movingDom.style.width = '16px';
        movingDom.style.borderRadius = '8px';
        movingDom.style.background = 'red';
        document.body.appendChild(movingDom)
        // 定义移动的dom的x, y
        var x = startX;
        var y = startY;
        var ax2 = 0;
        var bx = 0;
        var time = setInterval(function(){
          if(x < endX) {
            x = x + 2;
            ax2 = a*x*x;
            bx = b*x;
            y = ax2 + bx;
            console.log(ax2, bx, y)
            movingDom.style.left = x + 'px';
            movingDom.style.top = y + 'px';
          } else {
            movingDom.parentNode.removeChild(movingDom)
            clearInterval(time);
          }
         },10)
        }
          //# sourceURL=pen.js
        </script>
    
    
    
      
      
    
    </body>
    
    </html>
     

     vue实现抛物线

    <template>
      
          <div>   
              <ul class="lists">
                  <li>商品1商品1<i @click="ball_fly($event)">+</i></li>
                  <li>商品12商品1<i @click="ball_fly($event)">+</i></li>
                  <li>商品13商品1<i @click="ball_fly($event)">+</i></li>
                  
                  <li>商品1商品1<i @click="ball_fly($event)">+</i></li>
                  <li>商品12商品1<i @click="ball_fly($event)">+</i></li>
                  <li>商品13商品1<i @click="ball_fly($event)">+</i></li>
                  
                  <li>商品1商品1<i @click="ball_fly($event)">+</i></li>
                  <li>商品12商品1<i @click="ball_fly($event)">+</i></li>
                  <li>商品13商品1<i @click="ball_fly($event)">+</i></li>
                  
                  <li>商品1商品1<i @click="ball_fly($event)">+</i></li>
                  <li>商品12商品1<i @click="ball_fly($event)">+</i></li>
                  <li>商品13商品1<i @click="ball_fly($event)">+</i></li>
              </ul>
              
                  <div class="targetbox"><div class="target car_icon"  ref="carIcon">购物车</div>  </div> 
    
          </div>
       
         
        </template>
    <script>
    
    export default {
      name: 'business',
      data () {
        return {
          showMe: false,
          // 计算商品区域高度
          computedContentHeight: window.innerHeight - (window.innerWidth / 10 * 4.2),
         
        };
      },
      
       
      
      methods: {
        // 初始化
        init () {
         
          // 给购物车添加animationend事件,动画结束后去掉有animation的class
          this.$refs.carIcon.addEventListener('animationend', () => {
            this.$refs.carIcon.classList.remove('tantantan');
          }, false);
        },
     
       
    
    
        // 修改版抛球效果,使用css3中的贝塞尔曲线实现
        ball_fly (e) {
          // 被点元素位置
          var bound = e.target.getBoundingClientRect();
          var boundTop = bound.top;// 点击top值
          var boundLeft = bound.left;// 点击left值
          // 目标元素位置
          var target = this.$refs.carIcon;
          var targetData = target.getBoundingClientRect();
          var targetTop = targetData.top;// 目标top值
          var targetLeft = targetData.left;// 目标left值
          // 创建父球(父球横向运动)
          var father = document.createElement('div');
          father.className = 'father flyball';
          // 创建子球(子球垂直css3贝塞尔曲线运动,先上后下,得到抛球效果)
          var child = document.createElement('div');
          child.className = 'child inner';
          father.appendChild(child);
          // 设置父盒子生成的位置
          // father.style.cssText = 'top:' + boundTop + 'px;left:' + boundLeft + 'px;';
          father.style.top = boundTop + 'px';
          father.style.left = boundLeft + 'px';
          // append小球到页面中
          document.body.appendChild(father);
          setTimeout(() => {
            // 目标left - 所点元素left + 目标元素宽度的一半(修正落点)
            father.style.transform = 'translate3d(' + (targetLeft - boundLeft + targetData.width / 2) + 'px, 0px, 0px)';
            child.style.cssText = 'transform: translate3d(0px, ' + (targetTop - boundTop) + 'px, 0px);';
            // 运动结束后删掉小球
            setTimeout(() => {
              // 移除小球
              father.parentNode.removeChild(father);
              // 购物车添加弹弹弹的css
              this.$refs.carIcon.classList.add('tantantan');
               // 给购物车添加animationend事件,动画结束后去掉有animation的class
          this.$refs.carIcon.addEventListener('animationend', () => {
            this.$refs.carIcon.classList.remove('tantantan');
          }, false);
              
            }, 500);
          }, 10);
        }
        // 生成小球抛出 计算left top 生成动画 不流畅 (css3的没想好)
        /* ball_fly (e) {
          // 被点元素宽高
          var bound = e.target.getBoundingClientRect(); // 被点元素位置
          // 创造元素
          var qiu = document.createElement('div');
          qiu.className = 'qiu';
          qiu.style.top = bound.top + 'px';
          qiu.style.left = bound.left + 'px';
          document.body.appendChild(qiu);
          // 目标元素位置
          var dsa = this.$refs.carIcon;
          var mubiao = dsa.getBoundingClientRect();
          var mubiaoT = mubiao.top;
          var mubiaoL = mubiao.left;
          var timer = null;
          // top差值 left差值
          var chaTop = mubiaoT - bound.top;
          // 要减掉目标宽度一半 让落点对准目标中心
          var chaLeft = bound.left - mubiaoL - dsa.offsetWidth / 2;
          // 规定上抛初速度为 top 差值的55分之1
          var g = chaTop / 55;
          // 规定上抛初速度为 top 差值的15分之1
          var vTop = chaTop / 15;
          timer = setInterval(() => {
            qiu.style.top = (qiu.getBoundingClientRect().top + (-vTop + g)) + 'px';
            qiu.style.left = (qiu.getBoundingClientRect().left + (-chaLeft / 14)) + 'px';
            // 每次 g 对速度的影响
            vTop -= g;
            if (qiu.getBoundingClientRect().top >= mubiaoT) {
              clearInterval(timer);
              qiu.parentNode.removeChild(qiu);
              this.$refs.carIcon.classList.add('tantantan');
            }
          }, 1000 / 25);
        } */
      }
    };
    </script>
    
    <style lang="less">
    .business_box{
      100%;
      height:100%;
      
      } 
     @keyframes mymove {
    0% {
        transform: scale(1);
    }
    25% {
        transform: scale(0.8);
    }
    50% {
        transform: scale(1.1);
    }
    75% {
        transform: scale(0.9);
    }
    100% {
        transform: scale(1);
    }
    }
    /* 购物车弹弹弹 */
    .tantantan {
      animation: mymove 1s;
    }
    /* 修正版抛球效果所需CSS */
    .flyball {
        position:fixed;
        top:0;
        left:0;
        -webkit-transition:-webkit-transform .5s linear;
        transition:-webkit-transform .5s linear;
        transition:transform .5s linear;
        transition:transform .5s linear, -webkit-transform .5s linear
    }
    .flyball .inner {
        position:absolute;
        top:0;
        left:0;
        background-color:#3190e8;
        border-radius:50%
    }
    .flyball, .flyball .inner {
        will-change:transform;/* css3自带的开启GPU加速 */
        -webkit-transform:translateZ(0);
        transform:translateZ(0)
    }
    .flyball .inner {
        -webkit-transition:-webkit-transform .5s cubic-bezier(.3, -.2, 1, 0);
        transition:-webkit-transform .5s cubic-bezier(.3, -.2, 1, 0);
        transition:transform .5s cubic-bezier(.3, -.2, 1, 0);
        transition:transform .5s cubic-bezier(.3, -.2, 1, 0), -webkit-transform .5s cubic-bezier(.3, -.2, 1, 0)
    }
    
    /* 父盒子的样式 */
    .father{
       20px;;
      height:20px;
      position: fixed;
      z-index: 999;
    }
    /* 子盒子(小球)的样式 */
    .child{
       20px;;
      height:20px;
      background: #3190e8;
      position: absolute;
      top: 0;
      left: 0;
    }
    
    .lists{  100%;  height: auto;; overflow: hidden;}
    
    .lists li{ height: 44px; line-height: 40px; background: #f1f1f1; margin-bottom: 20px; position: relative; padding: 0 10px;}
    .lists li i{  20px;  height: 20px; text-align: center;; line-height: 19px;; display: block; border-radius: 15px; overflow: hidden; position: absolute; right: 20px; top:10px;; background: #3190e8; color: #fff; ;}
    .targetbox{ position: fixed; bottom: 54px; left: 0;  100%; height: 54px; background: #666;}
    .target{   50px; height: 50px; color: #fff; line-height: 50px; text-align: center;}
    .car_icon {
      
       
       
        background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zd…48Y2lyY2xlIGN4PSIxMiIgY3k9IjUxIiByPSI0IiBmaWxsPSIjRkZGIi8+PC9nPjwvc3ZnPg==) #3190e8 center no-repeat;
       
        border-radius: 50%;
        background-size: 60% auto;
    }
    </style>

     css 实现抛物线

    <!DOCTYPE html>
    <html lang="en" style="100%;height:100%;">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <style>
            * {
                padding: 0;
                margin: 0;
            }
            #ball {
                12px;
                height:12px;
                background: #5EA345;
                border-radius: 50%;
                position: fixed;
                transition: left 1s linear, top 1s ease-in;
            }
        </style>
        <title>CSS3 水平抛物线动画</title>
    </head>
    <body style="100%;height:100%;">
        <div id="ball"></div>
    </body>
    <script>
        var $ball = document.getElementById('ball');
        document.body.onclick = function (evt) {
            console.log(evt.pageX,evt.pageY)
            $ball.style.top = evt.pageY+'px';
            $ball.style.left = evt.pageX+'px';
            $ball.style.transition = 'left 0s, top 0s';
            setTimeout(()=>{
                $ball.style.top = window.innerHeight+'px';
                $ball.style.left = '0px';
                $ball.style.transition = 'left 1s linear, top 1s ease-in';
            }, 20)
        }
    </script>
    </html>
    

      

    小程序

    cartAnimation(x, y) { // x y 为手指点击的坐标,即球的起始坐标
        let self = this,
            cartY = app.globalData.winHeight - 50, // 结束位置(购物车图片)纵坐标
            cartX = 50, // 结束位置(购物车图片)的横坐标
            animationX = flyX(cartX, x), // 创建球的横向动画
            animationY = flyY(cartY, y) // 创建球的纵向动画
        this.setData({
              ballX: x,
              ballY: y,
              showBall: true
        })
        setTimeoutES6(100).then(() => { // 100 ms 延时,确保球已经到位并显示
            self.setData({
                animationX: animationX.export(),
                animationY: animationY.export(),
            })
            return setTimeoutES6(400) // 400 ms 是球的抛物线动画时长
        }).then(() => { // 400 ms 延时后隐藏球
            this.setData({
                showBall: false,
            })
        })
    }
     
    function setTimeoutES6(sec) { // Promise 化 setTimeout
        return new Promise((resolve, reject) => {
            setTimeout(() => {resolve()}, sec)
        })
    }
     
    function flyX(cartX, oriX) { // 水平动画
        let animation = wx.createAnimation({
            duration: 400,
            timingFunction: 'linear',
        })
        animation.left(cartX).step()
        return animation
    }
     
    function flyY(cartY, oriY) { // 垂直动画
        let animation = wx.createAnimation({
            duration: 400,
            timingFunction: 'ease-in',
        })
        animation.top(cartY).step()
        return animation
    }
    

      

    222

        var funParabola = function(element, target, options) {
                /*
                 * 网页模拟现实需要一个比例尺
                 * 如果按照1像素就是1米来算,显然不合适,因为页面动不动就几百像素
                 * 页面上,我们放两个物体,200~800像素之间,我们可以映射为现实世界的2米到8米,也就是100:1
                 * 不过,本方法没有对此有所体现,因此不必在意
                */
                
                var defaults = {
                    speed: 166.67, // 每帧移动的像素大小,每帧(对于大部分显示屏)大约16~17毫秒
                    curvature: 0.001,  // 实际指焦点到准线的距离,你可以抽象成曲率,这里模拟扔物体的抛物线,因此是开口向下的
                    progress: function() {},
                    complete: function() {}
                };
                
                var params = {}; options = options || {};
                
                for (var key in defaults) {
                    params[key] = options[key] || defaults[key];
                }
                
                var exports = {
                    mark: function() { return this; },
                    position: function() { return this; },
                    move: function() { return this; },
                    init: function() { return this; }
                };
                
                /* 确定移动的方式 
                 * IE6-IE8 是margin位移
                 * IE9+使用transform
                */
                var moveStyle = "margin", testDiv = document.createElement("div");
                if ("oninput" in testDiv) {
                    ["", "ms", "webkit"].forEach(function(prefix) {
                        var transform = prefix + (prefix? "T": "t") + "ransform";
                        if (transform in testDiv.style) {
                            moveStyle = transform;
                        }
                    });        
                }
                
                // 根据两点坐标以及曲率确定运动曲线函数(也就是确定a, b的值)
                /* 公式: y = a*x*x + b*x + c;
                */
                var a = params.curvature, b = 0, c = 0;
                
                // 是否执行运动的标志量
                var flagMove = true;
                
                if (element && target && element.nodeType == 1 && target.nodeType == 1) {
                    var rectElement = {}, rectTarget = {};
                    
                    // 移动元素的中心点位置,目标元素的中心点位置
                    var centerElement = {}, centerTarget = {};
                    
                    // 目标元素的坐标位置
                    var coordElement = {}, coordTarget = {};
                    
                    // 标注当前元素的坐标
                    exports.mark = function() {
                        if (flagMove === false) return this;
                        if (typeof coordElement.x == "undefined") this.position();
                        element.setAttribute("data-center", [coordElement.x, coordElement.y].join());
                        target.setAttribute("data-center", [coordTarget.x, coordTarget.y].join());
                        return this;
                    }
                    
                    exports.position = function() {
                        if (flagMove === false) return this;
                        
                        var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft,
                            scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
                        
                        // 初始位置
                        if (moveStyle == "margin") {
                            element.style.marginLeft = element.style.marginTop = "0px";
                        } else {
                            element.style[moveStyle] = "translate(0, 0)";
                        }
                        
                        // 四边缘的坐标
                        rectElement = element.getBoundingClientRect();
                        rectTarget = target.getBoundingClientRect();
                        
                        // 移动元素的中心点坐标
                        centerElement = {
                            x: rectElement.left + (rectElement.right - rectElement.left) / 2 + scrollLeft,
                            y: rectElement.top + (rectElement.bottom - rectElement.top) / 2    + scrollTop
                        };
                        
                        // 目标元素的中心点位置
                        centerTarget = {
                            x: rectTarget.left + (rectTarget.right - rectTarget.left) / 2 + scrollLeft,
                            y: rectTarget.top + (rectTarget.bottom - rectTarget.top) / 2 + scrollTop        
                        };
                        
                        // 转换成相对坐标位置
                        coordElement = {
                            x: 0,
                            y: 0    
                        };
                        coordTarget = {
                            x: -1 * (centerElement.x - centerTarget.x),
                            y:  -1 * (centerElement.y - centerTarget.y)    
                        };
                        
                        /*
                         * 因为经过(0, 0), 因此c = 0
                         * 于是:
                         * y = a * x*x + b*x;
                         * y1 = a * x1*x1 + b*x1;
                         * y2 = a * x2*x2 + b*x2;
                         * 利用第二个坐标:
                         * b = (y2+ a*x2*x2) / x2
                        */
                        // 于是
                        b = (coordTarget.y - a * coordTarget.x * coordTarget.x) / coordTarget.x;    
                        
                        return this;
                    };        
                    
                    // 按照这个曲线运动
                    exports.move = function() {
                        // 如果曲线运动还没有结束,不再执行新的运动
                        if (flagMove === false) return this;
                        
                        var startx = 0, rate = coordTarget.x > 0? 1: -1;
    
                        var step = function() {
                            // 切线 y'=2ax+b
                            var tangent = 2 * a * startx + b; // = y / x
                            // y*y + x*x = speed
                            // (tangent * x)^2 + x*x = speed
                            // x = Math.sqr(speed / (tangent * tangent + 1));
                            startx = startx + rate * Math.sqrt(params.speed / (tangent * tangent + 1));
                            
                            // 防止过界
                            if ((rate == 1 && startx > coordTarget.x) || (rate == -1 && startx < coordTarget.x)) {
                                startx = coordTarget.x;
                            }
                            var x = startx, y = a * x * x + b * x;
                            
                            // 标记当前位置,这里有测试使用的嫌疑,实际使用可以将这一行注释
                            element.setAttribute("data-center", [Math.round(x), Math.round(y)].join());
                            
                            // x, y目前是坐标,需要转换成定位的像素值
                            if (moveStyle == "margin") {
                                element.style.marginLeft = x + "px";
                                element.style.marginTop = y + "px";
                            } else {
                                element.style[moveStyle] = "translate("+ [x + "px", y + "px"].join() +")";
                            }
                            
                            if (startx !== coordTarget.x) {
                                params.progress(x, y);
                                window.requestAnimationFrame(step);    
                            } else {
                                // 运动结束,回调执行
                                params.complete();
                                flagMove = true;    
                            }
                        };
                        window.requestAnimationFrame(step);
                        flagMove = false;
                        
                        return this;
                    };
                    
                    // 初始化方法
                    exports.init = function() {
                        this.position().mark().move();
                    };
                }
                
                return exports;
            }
    
    
    
    /* 元素 */
     var element = document.getElementById("element"), target = document.getElementById("target");
    
    // 抛物线元素的的位置标记
     var parabola = funParabola(element, target).mark();
    
    // 抛物线运动的触发
     document.body.onclick = function() {
         element.style.marginLeft = "0px";
         element.style.marginTop = "0px";
         parabola.init();
     };

    333

    <!doctype html >
    <html>
    <head>
      <meta charset="utf-8"/>
      <title>抛物线运动</title>
      <style>
        .pwx_rect{position:absolute;left:10px;top:300px;background-color:#888;height:50px;50px;}
        .pwx_hr{border-top:2px solid #ddd;position:absolute;98%;left:0px;top:350px;}
      </style>
      <script>
        test = function(){
          var rect = document.getElementById("rect");
          pwx(rect,60,5); //参数2:抛物线角度,参数3:横向速度每次增加5
        }
        function pwx(rect,radian,step){
          var animate = function(opt){
            var cos = Math.cos(opt.radian*Math.PI/180);//邻边比斜边,60度的话等于1/2
            var sin = Math.sin(opt.radian*Math.PI/180);//对边比斜边,30度的话等于1/2
            var left = opt.rect.offsetLeft;
            var top = opt.rect.offsetTop;
            if(opt.radian>0){
              left+=opt.step;
              opt.radian-=1; //角度递减1
              var a = left - opt.initLeft;
              var c = (a/cos);
              var b = (sin*c);
              opt.rect.style.left = opt.initLeft+a+"px";
              opt.rect.style.top = opt.initTop-b+"px";
              setTimeout(function(){
                animate(opt);
              },10);
            }else{
              opt.rect.style.left = left+opt.step+"px";
              opt.rect.style.top = opt.initTop+"px";
            }
          }
          animate({
            step : step,
            rect : rect,
            radian : radian,
            initTop : rect.offsetTop,
            initLeft : rect.offsetLeft
          });
        }
      </script>
    </head>
    <body>
    
    <input type="button" value="抛物线" onclick="test()"/>
      <div class="pwx_rect" id="rect"></div>
      <div class="pwx_hr"></div>
    </body>
    </html>
    

      

    /*!
     * parabola trajectory v1.0
     *
     * Contact: https://github.com/xiaolin3303
     * 2016-09-30
     *
     * Designed and built with all the love of Web
     */
    ;(function (window, Math) {
        /*
         * @params Object opts
         */
        function Parabola (opts) {
            opts = opts || {};
            // required `startPos`, `endPos` params in opts
            if (!opts.startPos) {
                throw new Error('`startPos` is required in init options');
            }
    
            if (!opts.endPos) {
                throw new Error('`endPos` is required in init options');
            }
            // opts.curvature = opts.curvature || 0.003;
            opts.duration = opts.duration || 2000;
    
            this.opts = opts;
    
            this.calCurvature();
        }
    
        Parabola.prototype.calCurvature = function () {
    
            this.opts.driftX = this.opts.endPos.left - this.opts.startPos.left;
            this.opts.driftY = this.opts.endPos.top - this.opts.startPos.top;
    
            // 在不超出屏幕范围的前提下,尽量抛得更高,计算合适的曲率 (a)
            var yMin = -1 * this.opts.startPos.top;
    
            var a = this.power(this.opts.driftX, 4);
            var b = (4 * yMin - 2 * this.opts.driftY) * this.power(this.opts.driftX, 2);
            var c = this.power(this.opts.driftY, 2);
    
            this.opts.curvature = (-1 * b + Math.sqrt((this.power(b, 2) - 4 * a * c))) / (2 * a);
    
            this.opts.b = (this.opts.driftY - this.opts.curvature * this.opts.driftX * this.opts.driftX) / this.opts.driftX;
        }
    
        Parabola.prototype.power = function (v, n) {
            if (n === 1) {
                return v;
            } else {
                return v * arguments.callee(v, (n - 1));
            }
        }
    
        Parabola.prototype.calPosition = function (progress) {
            // 当前进度下的X轴的位置
            x = this.opts.driftX * progress;
            // 当前进度下的Y轴的位置
            // y = a*x*x + b*x + c,  c = 0
            y = this.opts.curvature * x * x + this.opts.b * x;
    
            return {
                left: Math.round(x + this.opts.startPos.left),
                top: Math.round(y + this.opts.startPos.top)
            }
        }
    
        Parabola.prototype.start = function () {
            var opts = this.opts;
            var me = this;
            var startTimeStamp = +new Date();
            var animationFrame = window.requestAnimationFrame  ||
                window.webkitRequestAnimationFrame  ||
                window.mozRequestAnimationFrame     ||
                window.oRequestAnimationFrame       ||
                window.msRequestAnimationFrame      ||
                function (callback) { window.setTimeout(callback, 1000 / 60); };
    
            function step () {
                var currentTimeStamp = +new Date();
    
                var progress = Math.min((currentTimeStamp - startTimeStamp) / opts.duration, 1);
                if (progress === 1) {
                    // 动画结束
                    return false;
                } else {
                    var position = me.calPosition(progress);
                    opts.onStep && opts.onStep(position);
    
                    return true;
                }
            }
    
            function progress () {
                if (step()) {
                    animationFrame(progress);
                } else {
                    if (typeof opts.onFinish === 'function') {
                        opts.onFinish(opts.endPos);
                    }
                }
            }
    
            animationFrame(progress);
        }
    
        if ( typeof module !== 'undefined' && module.exports ) {
            module.exports = Parabola;
        } else if ( typeof define === 'function' && define.amd ) {
            define( function () { return Parabola; } );
        } else {
            window.Parabola = Parabola;
        }
    
    })(window, Math)
    
    window.onload = function () {
        var btn = document.querySelector('button');
    		var target = document.querySelector('.dot');
    		var parabola = new Parabola({
    			startPos: {
    				left: 100,
    				top: 60
    			},
    			endPos: {
    				left: 500,
    				top: 200
    			},
          duration: 1000,
    			onStep (pos) {
    				target.style.left = pos.left + 'px';
    				target.style.top = pos.top + 'px';
    			},
    			onFinish (pos) {
            target.classList.add('scaleAnimation');
    				console.log('Animation Finished!');
    			}
    		});
    
    		// parabola.start();
        btn.addEventListener('click', function () {
            target.classList.remove('scaleAnimation');
            parabola.start();
        }, false);
    }
    

    fly.js

    /*
     * jquery.fly
     * 
     * 抛物线动画
     * @github https://github.com/amibug/fly
     * Copyright (c) 2014 wuyuedong
     * copy from tmall.com
     */
    (function ($) {
      $.fly = function (element, options) {
        // 默认值
        var defaults = {
          version: '1.0.0',
          autoPlay: true,
          vertex_Rtop: 20, // 默认顶点高度top值
          speed: 1.2,
          start: {}, // top, left, width, height
          end: {},
          onEnd: $.noop
        };
    
        var self = this,
          $element = $(element);
    
        /**
         * 初始化组件,new的时候即调用
         */
        self.init = function (options) {
          this.setOptions(options);
          !!this.settings.autoPlay && this.play();
        };
    
        /**
         * 设置组件参数
         */
        self.setOptions = function (options) {
          this.settings = $.extend(true, {}, defaults, options);
          var settings = this.settings,
            start = settings.start,
            end = settings.end;
    
          $element.css({marginTop: '0px', marginLeft: '0px', position: 'fixed'}).appendTo('body');
          // 运动过程中有改变大小
          if (end.width != null && end.height != null) {
            $.extend(true, start, {
               $element.width(),
              height: $element.height()
            });
          }
          // 运动轨迹最高点top值
          var vertex_top = Math.min(start.top, end.top) - Math.abs(start.left - end.left) / 3;
          if (vertex_top < settings.vertex_Rtop) {
            // 可能出现起点或者终点就是运动曲线顶点的情况
            vertex_top = Math.min(settings.vertex_Rtop, Math.min(start.top, end.top));
          }
    
          /**
           * ======================================================
           * 运动轨迹在页面中的top值可以抽象成函数 y = a * x*x + b;
           * a = curvature
           * b = vertex_top
           * ======================================================
           */
    
          var distance = Math.sqrt(Math.pow(start.top - end.top, 2) + Math.pow(start.left - end.left, 2)),
            // 元素移动次数
            steps = Math.ceil(Math.min(Math.max(Math.log(distance) / 0.05 - 75, 30), 100) / settings.speed),
            ratio = start.top == vertex_top ? 0 : -Math.sqrt((end.top - vertex_top) / (start.top - vertex_top)),
            vertex_left = (ratio * start.left - end.left) / (ratio - 1),
            // 特殊情况,出现顶点left==终点left,将曲率设置为0,做直线运动。
            curvature = end.left == vertex_left ? 0 : (end.top - vertex_top) / Math.pow(end.left - vertex_left, 2);
    
          $.extend(true, settings, {
            count: -1, // 每次重置为-1
            steps: steps,
            vertex_left: vertex_left,
            vertex_top: vertex_top,
            curvature: curvature
          });
        };
    
        /**
         * 开始运动,可自己调用
         */
        self.play = function () {
          this.move();
        };
    
        /**
         * 按step运动
         */
        self.move = function () {
          var settings = this.settings,
            start = settings.start,
            count = settings.count,
            steps = settings.steps,
            end = settings.end;
          // 计算left top值
          var left = start.left + (end.left - start.left) * count / steps,
            top = settings.curvature == 0 ? start.top + (end.top - start.top) * count / steps : settings.curvature * Math.pow(left - settings.vertex_left, 2) + settings.vertex_top;
          // 运动过程中有改变大小
          if (end.width != null && end.height != null) {
            var i = steps / 2,
              width = end.width - (end.width - start.width) * Math.cos(count < i ? 0 : (count - i) / (steps - i) * Math.PI / 2),
              height = end.height - (end.height - start.height) * Math.cos(count < i ? 0 : (count - i) / (steps - i) * Math.PI / 2);
            $element.css({ width + "px", height: height + "px", "font-size": Math.min(width, height) + "px"});
          }
          $element.css({
            left: left + "px",
            top: top + "px"
          });
          settings.count++;
          // 定时任务
          var time = window.requestAnimationFrame($.proxy(this.move, this));
          if (count == steps) {
            window.cancelAnimationFrame(time);
            // fire callback
            settings.onEnd.apply(this);
          }
        };
    
        /**
         * 销毁
         */
        self.destroy = function(){
          $element.remove();
        };
    
        self.init(options);
      };
    
      // add the plugin to the jQuery.fn object
      $.fn.fly = function (options) {
        return this.each(function () {
          if (undefined == $(this).data('fly')) {
            $(this).data('fly', new $.fly(this, options));
          }
        });
      };
    })(jQuery);
    <script>
    $(function() {
        var offset = $("#end").offset();
        $(".addcar").click(function(event){
            var addcar = $(this);
            var img = addcar.parent().find('img').attr('src');
            var flyer = $('<img class="u-flyer" src="'+img+'">');
            flyer.fly({
                start: {
                    left: event.pageX,
                    top: event.pageY
                },
                end: {
                    left: offset.left+10,
                    top: offset.top+10,
                     0,
                    height: 0
                },
                onEnd: function(){
                    $("#msg").show().animate({ '250px'}, 200).fadeOut(1000);
                    addcar.css("cursor","default").removeClass('orange').unbind('click');
                    this.destory();
                }
            });
        });
    });
    </script>

      

  • 相关阅读:
    JS命名空间的使用
    PHPexcel的用法
    python爬取百度贴吧帖子
    python自动抢票
    int 与 String 与 char 之间的互相转换
    数据库备份和恢复
    Mysql 基础
    Mysql错误:Every derived table must have its own alias
    frameset框架集
    文件的上传(TCP)
  • 原文地址:https://www.cnblogs.com/surfaces/p/6699219.html
Copyright © 2020-2023  润新知