您的位置:首页 > Web前端 > JavaScript

奇舞-javaScript 基础动画-笔记

2018-02-23 16:49 309 查看
一些动画的实现思路

先看一些实现思路

圆周运动

椭圆运动

一些复杂动画

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);
});
});


直线运动

<
18e5b
li>匀速运动

匀加速运动

匀减速运动

平面上的直线运动

匀速运动

//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);
});
});




平面上的简单运动

斜线运动

曲线运动

圆周运动

斜线运动

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);
}
})
})


圆的参数方程



连续的运动

动画的简易封装

周期和折线运动

动画队列

改良动画队列

连贯动画

弹跳和滚动

连续平滑动

对动画模型进行抽象



圆周运动

//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>




动画与贝塞尔曲线

构造贝塞尔曲线

使用贝塞尔曲线实现动画

贝塞尔曲线的css3动画



cubic-bezier easing

https://github.com/gre/bezier-easing

http://cubic-bezier.com/

http://easings.net/zh-cn

贝塞尔曲线动画

//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动画

翻转

逐帧动画

翻转动画

//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和序列帧动画
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: