奇舞-javaScript 基础动画-笔记

一些动画的实现思路

先看一些实现思路

  1. 圆周运动
  2. 椭圆运动
  3. 一些复杂动画

css圆周运动

//html
 <div id="ball"></div>
//css

    #ball {
        position: absolute;
        width: 20px;
        height: 20px;
        background: green;
        border-radius: 50%;
        top: 100px;
        left: 200px;
        transform-origin: 10px 110px;
        transform: rotate(0deg);
        animation: roll 2s linear infinite;
    }

    @keyframes roll {
        0% {
            transform: rotate(0deg);
        }
        100% {
            transform: rotate(360deg);
        }
    }

JS圆周运动

//html
 <div id="ball"></div>
//css

#ball {
    position: absolute;
    width: 20px;
    height: 20px;
    background: green;
    border-radius: 50%;
    top: 100px;
    left: 200px;
    transform-origin: 10px 110px;
}

//js

function startCircle(el) {
    let startTime = Date.now(),
        cycle = 2000;

    requestAnimationFrame(function update() {
        let currentTime = Date.now();
        let p = (currentTime - startTime) / cycle;
        ball.style.transform = `rotate(${360 * p}deg)`;
        requestAnimationFrame(update);
    })
}

startCircle();

JS椭圆运动

//html

 <div id="ball"></div>
//css

#ball {
    position: absolute;
    width: 20px;
    height: 20px;
    background: green;
    border-radius: 50%;
    top: 200px;
    left: 200px;
    transform: translate(0, -100px);
}

//js

function startCircle(el) {
    let startTime = Date.now(),
        cycle = 4000,
        a = 160,
        b = 80;

    requestAnimationFrame(function update() {
        let currentTime = Date.now(),
            p = (currentTime - startTime) / cycle,
            [x, y] = [a * Math.cos(Math.PI * 2 * p), b * Math.sin(Math.PI * 2 * p)];

        ball.style.transform = `translate(${x}px, ${y}px)`;
        requestAnimationFrame(update)
    })
}
startCircle();

复杂一些的动画

//html

    <button id="playBtn">play</button>
    <div class="wall"></div>

    <div class="ball" id="ball1"></div>
    <div class="ball ball--hidden" id="ball2"></div>
//css

    .wall {
        position: absolute;
        height: 100%;
        width: 100px;
        padding: 0;
        margin: 0;
        margin-left: 300px;
        background-color: black;
    }

    .ball {
        position: absolute;
        width: 20px;
        height: 20px;
        border-radius: 50%;
        background-color: green;
    }

    .ball--hidden{
        /*display: none;*/
    }
//js

    function drop(ball, from, to, onupdate, duration =2000) {
        let startTime = Date.now(),
        [x0, y0] = from,
        [x1, y1] = to;

        requestAnimationFrame(function update() {
            let currentTime = Date.now(),
            p = (currentTime - startTime) / duration;

            p = Math.min(p, 1.0);

            let x = x0 + (x1 - x0) * p,
            y = y0 + (y1 - y0) * p * p;
            onupdate(ball, x, y);
            ball.style.left = x + 'px';
            ball.style.top = y + 'px';

            if (p < 1) {
                requestAnimationFrame(update)
            }
        })
    }

    playBtn.onclick = function () {
        drop(ball1, [50, 50], [400, 600], function (ball, x, y) {
            if (x < 290) {
                ball.className = 'ball';
            }
            if (x>= 290) {
                ball.className  = 'ball ball--hidden';
            }
        })

        drop(ball2, [530, 50], [180, 600] ,function (ball, x, y) {
            if (x < 290 ) {
                ball.className = 'ball';
            }

            if (x >= 290) {
                ball.className = 'ball ball--hidden';
            }
        })
    }

动画是关于事件的函数

这里写图片描述
这里写图片描述

一个反例

//html

 <div id="block"></div>
//css

#block {
    position: absolute;
    left: 200px;
    top: 200px;
    width: 100px;
    height: 100px;
    background-color: #0c8;
    line-height: 100px;
    text-align: center;
}

//js

var deg = 0;
block.addEventListener('click', function() {
    var self = this;
    requestAnimationFrame(function change() {
        self.style.transform = 'rotate(' + (deg++) + 'deg)';
        requestAnimationFrame(change);
    });
});

直线运动

  1. 匀速运动
  2. 匀加速运动
  3. 匀减速运动
  4. 平面上的直线运动

匀速运动

//html
    <h2>匀速直线运动,滑块在2秒内移动200px</h2>
    <div id="block">click me</div>
//css

        #block {
            position: absolute;
            left: 200px;
            top: 200px;
            width: 100px;
            height: 100px;
            background: #0c8;
            line-height: 100px;
            text-align: center;
        }
//js

    block.addEventListener('click', function () {
        var self = this, 
      startTime =  Date.now();
      distance = 200, duration = 2000;

        requestAnimationFrame(function step() {
            var p = Math.min(1.0, (Date.now() - startTime)/ duration);

            self.style.transform = 'translateX('+ (distance * p)+'px)';
            if (p < 1.0) {
                requestAnimationFrame(step)
            }
        })
    })

这里写图片描述

匀加速直线运动

  block.addEventListener('click', function(){
    var self = this, startTime = Date.now(),
        distance = 200, duration = 2000;

    requestAnimationFrame(function step(){
      var p = Math.min(1.0, (Date.now() - startTime) / duration);
      self.style.transform = 'translateX(' + (distance * p * p) +'px)';
      if(p < 1.0) requestAnimationFrame(step);
    });
  });

这里写图片描述

匀减速度直线运动

block.addEventListener('click', function(){
  var self = this, startTime = Date.now(),
      distance = 200, duration = 2000;

  requestAnimationFrame(function step(){
    var p = Math.min(1.0, (Date.now() - startTime) / duration);
    self.style.transform = 'translateX(' 
      + (distance * p * (2-p)) +'px)';
    if(p < 1.0) requestAnimationFrame(step);
  });
});

这里写图片描述

平面上的简单运动

  1. 斜线运动
  2. 曲线运动
  3. 圆周运动

斜线运动

block.addEventListener('click', function(){
  var self = this, startTime = Date.now(),
      distance = 200, T = 2000;
  requestAnimationFrame(function step(){
    var p = Math.min(1.0, (Date.now() - startTime) / T);
    var tx = distance * p;
    var ty = tx;

    self.style.transform = 'translate(' 
      + tx + 'px' + ',' + ty +'px)';
    if(p < 1.0) requestAnimationFrame(step);
  });
});

圆锥曲线运动

block.addEventListener('click', function() {
    var self = this,
        startTime = Date.now(),
        disX = 200,
        disY = 200,
        duration = 500 * Math.sqrt(2 * disY / 98);
    // 假设10px 是1米 disY= 20 米

    requestAnimationFrame(function step() {
        var p = Math.min(1.0, (Date.now() - startTime) / duration);
        var tx = disX * p;
        var ty = disY * p * p;

        self.style.transform = 'translate(' +tx + 'px' + ',' + ty + 'px)';
        if (p < 1.0) requestAnimationFrame(step);
    })
})

正弦线运动

block.addEventListener('click', function() {
    var self = this,
        startTime = Date.now(),
        distance = 100,
        duration = 2000;

    requestAnimationFrame(function step() {
        var p = Math.min(1.0, (Date.now() - startTime) / duration);
        var ty = distance * Math.sin(2 * Math.PI * p);
        var tx = 2 * distance * p;

        self.style.transform = 'translate(' + tx + 'px,' + ty + 'px)';

        if (p < 1.0) {
            requestAnimationFrame(step);
        }
    })
})

椭圆运动

block.addEventListener('click', function() {
    var self = this,
        startTime = Date.now(),
        a = 150,
        b = 100,
        duration = 2000;

    requestAnimationFrame(function step() {
        var p = Math.min(1.0, (Date.now() - startTime) / duration);
        var tx = a * Math.sin(2 * Math.PI * p);
        var ty = b * Math.cos(2 * Math.PI * p);

        self.style.transform = 'translate(' + tx + 'px,' + ty + 'px)';

        if (p < 1.0) {
            requestAnimationFrame(step);
        }
    })
})

圆的参数方程

这里写图片描述

连续的运动

  1. 动画的简易封装
  2. 周期和折线运动
  3. 动画队列
  4. 改良动画队列
  5. 连贯动画
  6. 弹跳和滚动
  7. 连续平滑动

对动画模型进行抽象

这里写图片描述

圆周运动

//html
    <h2>圆周循环运动</h2>
    <div id="block">click</div>
//css
    #block {
        position: absolute;
        left: 150px;
        top: 200px;
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background: #0c8;
        line-height: 50px;
        text-align: center;
        transform: translateY(-100px);
    }
//js

    <script src="https://s4.ssl.qhres.com/!2fb39e02/animator-0.1.0.min.js"></script>
let animator = new Animator(2000, function(p) {
    let tx = -100 * Math.sin(2 * Math.PI * p),
        ty = -100 * Math.cos(2 * Math.PI * p);
    block.style.transform = 'translate(' + tx + 'px,' + ty + 'px)';
});

block.addEventListener('click', async function(evt) {

    let i = 0;
    while(1) {
        await animator.animate()
        block.style.background = ['red', 'green', 'blue'][i++ % 3]
    }
})

折线运动

//html
    <h2>折线运动</h2>
    <div id="block">click</div>

//css

    #block {
        position: absolute;
        left: 150px;
        top: 100px;
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background: #0c8;
        line-height: 50px;
        text-align: center;
    }
//js

var a1 = new Animator(500, function(p) {
    var tx = 100 * p;

    block.style.transform = 'translateX(' + tx + 'px)'
});

var a2 = new Animator(1000, function(p) {
    var ty = 100 * p;

    block.style.transform = 'translate(100px, ' + ty + 'px)';
})

block.addEventListener('click', async function() {
    await a1.animate()
    await a2.animate()
})

连续的运动

//html
    <h2>连续的运动</h2>
    <div id="block">click</div>
//css

    #block {
        position: absolute;
        left: 150px;
        top: 100px;
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background: #0c8;
        line-height: 50px;
        text-align: center;
    }
//js

var a1 = new Animator(500, function(p) {
    var tx = 100 * p;

    block.style.transform = 'translateX(' + tx + 'px)'
});

var a2 = new Animator(1000, function(p) {
    var ty = 100 * p;

    block.style.transform = 'translate(100px, ' + ty + 'px)';
})

var a3 = new Animator(1000,  function(p){
  var tx = 100 * (1-p);
  block.style.transform = 'translate(' 
    + tx + 'px, 100px)';     
});

var a4 = new Animator(1000,  function(p){
  var ty = 100 * (1-p);
  block.style.transform = 'translateY('  
    + ty + 'px)';     
});

block.addEventListener('click', async function() {
    await a1.animate()
    await a2.animate()
    await a3.animate()
    await a4.animate()
})

弹跳的小球

//html

    <h2>弹跳的小球</h2>
    <div id="block">click</div>
//css

    #block {
        position: absolute;
        left: 150px;
        top: 100px;
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background-color: #0c8;
        line-height: 50px;
        text-align: center;
    }


//js

var a1 = new Animator(1414, function(p) {
    var ty = 200 * p * p;
    block.style.transform = 'translateY(' + ty + 'px)'
})


var a2 = new Animator(1414, function (p) {
   var ty = 200 - 200 * p * (2-p);

   block.style.transform = 'translateY('+ ty +'px)';
})

block.addEventListener('click', async function () {
   while(1) {
    await a1.animate()
    await a2.animate();
   }
})

这里写图片描述

改进弹跳的小球

设置阻力系数:

  • T’ = 0.7T
  • S’ = 0.49S
//html

    <h2>弹跳小球</h2>
    <div id="block">click</div>
//css


  #block{
    position:absolute;
    left: 150px;
    top: 300px;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background: #0c8;
    line-height: 50px;
    text-align: center;
    transform: translateY(-200px);
  }

//js

<script src="https://s4.ssl.qhres.com/!2fb39e02/animator-0.1.0.min.js"></script>

block.addEventListener('click', async function() {
    var T = 1414,
        loss = 0.7;

    var a1 = new Animator(T, function(p) {
        var s = this.duration * 200 / T;
        var ty = s * (p * p -1);
        console.log(this.duration);
        block.style.transform = 'translateY(' + ty + 'px)'
    })

    var a2 = new Animator(T, function(p) {
        var s = this.duration * 200 / T;
        var ty = -s * p * (2 - p);

        block.style.transform = 'translateY(' + ty + 'px)'
    })

    while(a2.duration > 0.001) {
        await a1.animate();
        a2.duration *= 0.7;
        await a2.animate();
        a1.duration *= 0.7
    }

})

滚动的小球

//html

    <h2>弹跳小球</h2>
    <div id="block">click</div>
//css

#block{
    position:absolute;
    left: 50px;
    top: 100px;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background: #0c8;
    line-height: 50px;
    text-align: center;
  }

//js

<script src="https://s4.ssl.qhres.com/!2fb39e02/animator-0.1.0.min.js"></script>
<script type="text/javascript">
var a1 = new Animator(4000, function(p) {
    var rotation = 720 * p,
        x = 50 + 314 * p;

    block.style.transform = 'rotate(' + 720 * p + 'deg)'
    block.style.left = x + 'px';
})

block.addEventListener('click', async function () {
  await a1.animate();
})
</script>

小球被惯性甩出

//html
    <h2>甩出小球</h2>
    <div id="block">click</div>

//css
#block {
    position: absolute;
    left: 100px;
    top: 100px;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background: #0c8;
    line-height: 50px;
    text-align: center;
}


//js
<script src="https://s4.ssl.qhres.com/!2fb39e02/animator-0.1.0.min.js"></script>
<script type="text/javascript">
var a1 = new Animator(2800, function(p) {
    var x = -100 * Math.sin(2.8 * Math.PI * p);
    var y = 100 - 100 * Math.cos(2.8 * Math.PI * p);

    block.style.transform = 'translate(' + x + 'px,' +
        y + 'px)';
})

var a2 = new Animator(5000, function(p) {
    var x = -100 * Math.sin(2.8 * Math.PI) - 100 * Math.cos(2.8 * Math.PI) * Math.PI * 5 * p;
    var y = 100 - 100 * Math.cos(2.8 * Math.PI) +
        100 * Math.sin(2.8 * Math.PI) * Math.PI * 5 * p;

    console.log(y)

    block.style.transform = 'translate(' + x + 'px,' + y + 'px)'
    // block.style.transform = 'translate(' + x + 'px,' + y + 'px)'; 
});

block.addEventListener('click', async function() {
    await a1.animate()
    await a2.animate()
})

这里写图片描述

摩擦力

小球加速运动100px ,匀速运动100px, 减速运动50px 后停下

//html

    <h2>摩擦力</h2>
    <div id="block">click</div>

//css

#block {
    position: absolute;
    left: 100px;
    top: 100px;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background: #0c8;
    line-height: 50px;
    text-align: center;
}


//js


<script src="https://s4.ssl.qhres.com/!2fb39e02/animator-0.1.0.min.js"></script>
<script type="text/javascript">
var a1 = new Animator(1000, function(p) {
    var x = 100 * p * p

    block.style.transform = 'translateX(' + x + 'px)';
});

var a2 = new Animator(500, function(p) {

    var x = 100 + 100 * p;

    block.style.transform = 'translateX('+ x + 'px)';
});

var a3 = new Animator(500, function(p) {
    var x = 200 + 50 * p * (2 - p);

    block.style.transform = 'translateX(' + x + 'px)'
})

block.addEventListener('click', async function() {
    await a1.animate();
    await a2.animate();
    await a3.animate();
})
</script>

这里写图片描述

动画与贝塞尔曲线

  1. 构造贝塞尔曲线
  2. 使用贝塞尔曲线实现动画
  3. 贝塞尔曲线的css3动画

这里写图片描述

cubic-bezier easing

贝塞尔曲线动画

//html

    <h2>贝塞尔曲线</h2>
    <div id="block">click</div>
//css

   #block {
        position: absolute;
        left: 100px;
        top: 100px;
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background: #0c8;
        line-height: 50px;
        text-align: center;
    }
//js


var easing = BezierEasing(0.86, 0, 0.07, 1);
//easeInOutQuint

var a1 = new Animator(2000, function(ep, p) {
    var x = 200 * ep;

    block.style.transform = 'translateX(' + x + 'px)';
}, easing);


block.addEventListener('click', async function() {
    await a1.animate();
});


//贝塞尔曲线动画2 
var easing = BezierEasing(0.68, -0.55, 0.265, 1.55);
//easeInOutBack

var a1 = new Animator(2000, function(ep,p){
  var x = 200 * ep;

  block.style.transform = 'translateX(' + x + 'px)';
}, easing);


block.addEventListener('click', async function(){
  await a1.animate();
});

//贝塞尔曲线动画3

var easing = BezierEasing(0.68, -0.55, 0.265, 1.55);
//easeInOutBack

var a1 = new Animator(2000, function(ep,p){
  var x = 200 * p;
  var y = -200 * ep;

  block.style.transform = `translate(${x}px, ${y}px)`;
}, easing);


block.addEventListener('click', async function(){
  await a1.animate();
});

贝塞尔曲线 CSS3 动画


//html
    <h2>贝塞尔曲线</h2>
    <div id="block">click</div>
//css

    #block {
        position: absolute;
        left: 100px;
        top: 100px;
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background: #0c8;
        line-height: 50px;
        text-align: center;
        transition: transform 2s cubic-bezier(0.68, -0.55, 0.265, 1.55);
    }
//js

<script type="text/javascript">
block.addEventListener('click', function() {
    block.className = 'moved';
});
</script>

3D动画

  1. 翻转
  2. 逐帧动画

翻转动画

//html

    <h2>翻转动画</h2>
    <div id="block">click</div>
//css


#block {
    position: absolute;
    left: 100px;
    top: 400px;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background: #0c8;
    line-height: 50px;
    text-align: center;
}

//js
<script src="https://s.ssl.qhimg.com/!bfe40c57/bezier-easing.min.js"></script>
<script src="https://s4.ssl.qhres.com/!2fb39e02/animator-0.1.0.min.js"></script>
<script type="text/javascript">
var easing = BezierEasing(0.68, -0.55, 0.265, 1.55);

var a1 = new Animator(2000, function(ep, p) {
    var y = -200 * ep;
    var x = 200 * p;
    var r = 360 * ep;

    block.style.transform = 'translate(' + x + 'px,' +y + 'px) rotateY(' + r + 'deg)';
}, easing)

block.addEventListener('click', async function() {
    await a1.animate();
})

逐帧动画

//html
    <div id="bird" class="sprite bird bird1"></div>
//css

.sprite {
    display: inline-block;
    overflow: hidden;
    background-repeat: no-repeat;
    background-image: url(https://p1.ssl.qhimg.com/d/inn/0f86ff2a/8PQEganHkhynPxk-CUyDcJEk.png);
}

.bird {
    width: 86px;
    height: 60px;
}

.bird0 {

    background-position: -178px -2px
}

.bird1 {

    background-position: -90px -2px
}

.bird2 {

    background-position: -2px -2px
}

//js

<script type="text/javascript">

  var i = 0;

  setInterval(function () {
    bird.className = 'sprite bird ' + 'bird' + ((i++)%3)
  }, 1000/10);

</script>

Web Animations API

W3C Editor’s Draft

Polyfill

//html

    <div id="block">click</div>
    <div id="bird" class="sprite"></div>
//css

#block {
    text-align: center;
    color: #aaa;
    line-height: 50px;
    position: absolute;
    width: 50px;
    height: 50px;
    left: 100px;
    top: 100px;
    background-color: #077;
}

#bird {
    position: absolute;
    left: 100px;
    top: 100px;
    zoom: 0.5;
    display: inline-block;
    overflow: hidden;
    width: 86px;
    height: 60px;
    background: url(https://p1.ssl.qhimg.com/d/inn/0f86ff2a/8PQEganHkhynPxk-CUyDcJEk.png) no-repeat -178px -2px;
}

//js

block.addEventListener('click', e => {
    block.animate([{
            offset: 0,
            transform: 'rotate(0deg)'
        },
        {
            offset: 1,
            transform: 'rotate(360deg)'
        }
    ], {
        duration: 3000,
        direction: 'normal',
        fill: 'both',
        iterations: Infinity
    });

    function backgroundPosition(x, y) {
        return `url(https://p1.ssl.qhimg.com/d/inn/0f86ff2a/8PQEganHkhynPxk-CUyDcJEk.png) no-repeat ${x}px ${y}px`;
    }

    bird.animate([{
            offset: 0,
            background: backgroundPosition(-178, -2)
        },
        {
            offset: 0.33,
            background: backgroundPosition(-178, -2)
        },
        {
            offset: 1,
            background: backgroundPosition(-2, -2)
        }
    ], {
        duration: 500,
        direction: 'normal',
        fill: 'both',
        iterations: Infinity,
        easing: 'steps(3, start)'
    });
});

总结

本课通过例子学习了实现动画的基本原理和思路

  • 动画是关于时间的函数
  • 动画的数学计算
  • 动画的封装和组合动画
  • 贝塞尔曲线
  • 3D和序列帧动画
使用优化算法,以优化VMD算法的惩罚因子惩罚因子 (α) 和分解层数 (K)。 1、将量子粒子群优化(QPSO)算法与变分模态分解(VMD)算法结合 VMD算法背景: VMD算法是一种自适应信号分解算法,主要用于分解信号为不同频率带宽的模态。 VMD的关键参数包括: 惩罚因子 α:控制带宽的限制。 分解层数 K:决定分解出的模态数。 QPSO算法背景: 量子粒子群优化(QPSO)是一种基于粒子群优化(PSO)的一种改进算法,通过量子行为模型增强全局搜索能力。 QPSO通过粒子的量子行为使其在搜索空间中不受位置限制,从而提高算法的收敛速度与全局优化能力。 任务: 使用QPSO优化VMD中的惩罚因子 α 和分解层数 K,以获得信号分解的最佳效果。 计划: 定义适应度函数:适应度函数根据VMD分解的效果来定义,通常使用重构信号的误差(例如均方误差、交叉熵等)来衡量分解的质量。 初始化QPSO粒子:定义粒子的位置和速度,表示 α 和 K 两个参数。初始化时需要在一个合理的范围内为每个粒子分配初始位置。 执行VMD分解:对每一组 α 和 K 参数,运行VMD算法分解信号。 更新QPSO粒子:使用QPSO算法更新粒子的状态,根据适应度函数调整粒子的搜索方向和位置。 迭代求解:重复QPSO的粒子更新步骤,直到满足终止条件(如适应度函数达到设定阈值,或最大迭代次数)。 输出优化结果:最终,QPSO算法会返回一个优化的 α 和 K,从而使VMD分解效果最佳。 2、将极光粒子(PLO)算法与变分模态分解(VMD)算法结合 PLO的优点与适用性 强大的全局搜索能力:PLO通过模拟极光粒子的运动,能够更高效地探索复杂的多峰优化问题,避免陷入局部最优。 鲁棒性强:PLO在面对高维、多模态问题时有较好的适应性,因此适合海上风电时间序列这种非线性、多噪声的数据。 应用场景:PLO适合用于优化VMD参数(α 和 K),并将其用于风电时间序列的预测任务。 进一步优化的建议 a. 实现更细致的PLO更新策略,优化极光粒子的运动模型。 b. 将PLO优化后的VMD应用于真实的海上风电数据,结合LSTM或XGBoost等模型进行风电功率预测。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值