360 front star DAY4
The fundamentals of animation
- The timer changes the properties of an object
- Rerender the animation based on the new properties
Types of animation
- JavaScript animation
- Operating the DOM
- Canvas
- CSS animations
- transition
- animation
- SVG animation
- SMIL
Advantages and disadvantages of JS animation
- Advantages: flexibility, controllability
- Cons: Ease of use
example
Simple animation
Use incremental control
let rotation = 0;
requestAnimationFrame(function update() {
block.style.transform = `rotate(${rotation++}deg)`;
requestAnimationFrame(update);
});
Copy the code
Given a period, calculated in time, most trajectories can be animated this way
let rotation = 0;
let startTime = null;
const T = 2000;
requestAnimationFrame(function update() {
if(! startTime) startTime = Date.now(); const p = (Date.now() - startTime)/T; block.style.transform = `rotate(${360 * p}deg)`;
requestAnimationFrame(update);
});
Copy the code
Generalization: Encapsulates Ticker objects in incremental mode
function update({target}, count) {
target.style.transform = `rotate(${count++}deg)`;
}
class Ticker {
tick(update, context) {
let count = 0;
requestAnimationFrame(function next() {
if(update(context, ++count) ! = =false) { requestAnimationFrame(next); }}); } } const ticker = new Ticker(); ticker.tick(update, {target: block});Copy the code
Generalization 2: The way to use time
function update({target}, {time}) {
target.style.transform = `rotate(${360 * time / 2000}deg)`;
}
class Ticker {
tick(update, context) {
let count = 0;
let startTime = Date.now();
requestAnimationFrame(function next() {
count++;
const time = Date.now() - startTime;
if(update(context, {count, time}) ! = =false) { requestAnimationFrame(next); }}); } } const ticker = new Ticker(); ticker.tick(update, {target: block});Copy the code
Generalization 3: Pass in a Canvas context using a canvas drawing method
functionupdate({context}, {time}) { context.clearRect(0, 0, 512, 512); context.save(); context.translate(100, 100); Context. The rotate (time * 0.005); context.fillStyle ='#00f';
context.fillRect(-50, -50, 100, 100);
context.restore();
}
class Ticker {
tick(update, context) {
let count = 0;
let startTime = Date.now();
requestAnimationFrame(function next() {
count++;
const time = Date.now() - startTime;
if(update(context, {count, time}) ! = =false) { requestAnimationFrame(next); }}); }}Copy the code
Timing: Timing using easing transform, rotation 5 weeks within 20 seconds
class Timing {
constructor({duration, easing} = {}) {
this.startTime = Date.now();
this.duration = duration;
this.easing = easing || function(p){return p};
}
get time() {
return Date.now() - this.startTime;
}
get p() {
returnThis much (Math. Min (enclosing time/this. Duration, 1.0)); } } class Ticker { tick(update, context, timing) {let count = 0;
timing = new Timing(timing);
requestAnimationFrame(function next() {
count++;
if(update(context, {count, timing}) ! = =false) { requestAnimationFrame(next); }}); }}function update({target}, {timing}) {
target.style.transform = `translate(${200 * timing.p}px, 0)`;
}
const ticker = new Ticker();
ticker.tick(update, {target: block}, {duration: 2000});
Copy the code
Implementation of various animations
Uniform motion
We’re moving 200px to the right in 2 seconds
function update({target}, {timing}) {
target.style.transform = `translate(${200 * timing.p}px, 0)`;
}
const ticker = new Ticker();
ticker.tick(update, {target: block}, {duration: 2000});
Copy the code
Free falling bodies accelerate uniformly
Ease square
function update({target}, {timing}) {
target.style.transform = `translate(0, ${200 * timing.p}px)`;
}
const ticker = new Ticker();
ticker.tick(update, {target: block}, {duration: 2000,easing: p => p ** 2});
Copy the code
Frictional uniform deceleration
Much is p * (2 -) p
function update({target}, {timing}) {
target.style.transform = `translate(${200 * timing.p}px, 0)`;
}
const ticker = new Ticker();
ticker.tick(update, {target: block}, {duration: 2000,easing: p => p * (2 - p)});
Copy the code
Horizontal cast
X is uniform speed and Y is uniform acceleration
class Timing {
constructor({duration, easing} = {}) {
this.startTime = Date.now();
this.duration = duration;
this.easing = easing || function(p){return p};
}
get time() {
return Date.now() - this.startTime;
}
get op() {
returnMath. Min (enclosing time/this. Duration, 1.0); } getp() {
returnthis.easing(this.op); }}function update({target}, {timing}) {
target.style.transform = `translate(${200 * timing.op}px, ${200 * timing.p}px)`;
}
Copy the code
Spin + flat throw
Join the rotate
function update({target}, {timing}) {
target.style.transform = `
translate(${200 * timing.op}px, ${200 * timing.p}px)
rotate(${720 * timing.op}deg)
`;
}
Copy the code
Bessel curve
- Smooth curve (second and third order Bessel)
- Third order: two vertices and two control points
function bezierPath(x1, y1, x2, y2, p) {
const x = 3 * x1 * p * (1 - p) ** 2 + 3 * x2 * p ** 2 * (1 - p) + p ** 3;
const y = 3 * y1 * p * (1 - p) ** 2 + 3 * y2 * p ** 2 * (1 - p) + p ** 3;
return [x, y];
}
functionUpdate ({target}, {timing}) {const [px, py] = bezierPath(0.2, 0.6, 0.8, 0.2, timing. P); target.style.transform = `translate(${100 * px}px, ${100 * py}px)`;
}
const ticker = new Ticker();
ticker.tick(update, {target: block}, {
duration: 2000,
easing: p => p * (2 - p),
});
Copy the code
Bessel much
Controlling time, like controlling easing, and then inverting p through Newton iterations
- B(px) input, B(py) output
- So let’s take p from B of px, let’s take p from B of py.
- You can use an off-the-shelf library
Bessel locus
function update({target}, {timing}) {
target.style.transform =
`translate(${100 * timing.p}px, ${100 * timing.op}px)`; } const ticker = new Ticker(); Ticker.tick (update, {target: block}, {duration: 2000, easing: BezierEasing(0.5, -1.5, 0.5, 2.5),});Copy the code
Periodic motion
class Timing {
constructor({duration, easing, iterations = 1} = {}) {
this.startTime = Date.now();
this.duration = duration;
this.easing = easing || function(p){return p};
this.iterations = iterations;
}
get time() {
return Date.now() - this.startTime;
}
get finished() {
returnTime/this.duration >= 1.0 * this. Iterations; } getop() {
letOp = math. min(this.time/this.duration, 1.0 * this.iterations);if(op < 1.0) return op;
op -= Math.floor(op);
returnop > 0 ? Op: 1.0; } getp() {
returnthis.easing(this.op); }}Copy the code
Continuous movement
Make the tick method return a promise
class Ticker {
tick(update, context, timing) {
let count = 0;
timing = new Timing(timing);
return new Promise((resolve) => {
requestAnimationFrame(function next() {
count++;
if(update(context, {count, timing}) ! = =false && !timing.finished) {
requestAnimationFrame(next);
} else{ resolve(timing); }}); }); }}Copy the code
Frame by frame animation
Switch the background position at regular intervals
<style type="text/css">
.sprite {
display:inline-block;
overflow:hidden;
background-repeat: no-repeat;
background-image:url(https://p.ssl.qhimg.com/t01f265b6b6479fffc4.png);
}
.bird0 {width:86px; height:60px; background-position: -178px -2px}
.bird1 {width:86px; height:60px; background-position: -90px -2px}
.bird2 {width:86px; height:60px; background-position: -2px -2px}
#bird{
position: absolute;
left: 100px;
top: 100px;
zoom: 0.5;
}
</style>
<div id="bird" class="sprite bird1"></div>
<script type="text/javascript">
var i = 0;
setInterval(function(){
bird.className = "sprite " + 'bird' + ((i++) % 3);
}, 1000/10);
</script>
Copy the code
Web Animation API
CSS keyframe animation with JS
Example: A sequence of ball motions encapsulates a promise
conclusion
- Implementation: increments and time
- For more accuracy: Timing classes
- Encapsulate the animation as a promise and resolve at the end of the animation