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

  1. JavaScript animation
    • Operating the DOM
    • Canvas
  2. CSS animations
    • transition
    • animation
  3. 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