ANIMATION

In the world of states

(has comments to each slide)

Durability

Usefulness

Beauty

Is it really important?

Browser animation

Ideal one,

has a smooth animation, works at regular intervals

Misconception #1

setTimeout, may not be finished in time

requestAnimationFrame, will be called at the optimal redrawing time

// Or use a polyfill:
// import requestAnimationFrame from 'raf';

const { requestAnimationFrame } = window;

const animate = () => {
    requestAnimationFrame(animate);

    // Perform an animation step
    x += velocity;
}

// Fire it up
requestAnimationFrame(animate);

Pattern

Misconception #2

(permanent speed)

requestAnimationFrame(timestamp => {
    // DOMHighResTimeStamp
    // timestamp ~> 30485.84100000153
});
const animate = timestamp => {
    const delta = timestamp - prevTimestamp;

    // Note, it's a function now!
    x += velocity(delta);

    requestAnimationFrame(animate);
};

Let's reuse the timestamp

The result w/ Delta

Example

const redraw = _ => {
    points.forEach(point => {
        // make sure `will-change: transform` is set
	point.element.style.transform = `
	    translate3d(${point.x}px, ${point.y}px, 0.0px)
            rotate(${point.angle}rad)`
    });
};

const tick = ts => {
    _lastRaf = requestAnimationFrame(tick);

    physicsStep(delta);
    redraw(delta);
}

‘will-change: transform’

Stateful applications

Immutable UI is an essentials for the up-to-date web-applications. DOM visualizes the current state.

Immutable UI

Application is a chain of states

// CSS property
// transition: transform is ease;

// Conditional state change
<div className ={isVisible ? 'is-visible' : 'is-hidden'} />

// Direct style manipulation
<div style={{ transform: `translate(${scale})` }} />

Because it's simple

Good, but not enough

Much better

React-Motion

"Dirty" animations

class Dialog extends Component{
    componentDidMount(){
        const node = findDOMNode(this);
        // Or $.animate, anime.js, GSAP, D3 ...
	Velocity(node, {scale: 1.5},
	    {duration: 1000});
    }

    render(){ ... };
};
class Dialog extends Component{
    componentDidMount(){
        const node = findDOMNode(this);

        // animate returns a cancellable
        // promise-like object
	this._anim = animate(node, { ... });
    }

    componentWillUnmount(){
        this._anim && this._anim.cancel();
    }
};

Modal window

<Animated>
    { this.state.showDialog && <Dialog /> }
</Animated>
<div>
    { this.state.showDialog && <Dialog /> }
</div>

vs.

States map

const element = <Dialog size="medium" />
// => { type: Dialog, props: { size: 'medium' }, ... }
const element = React.createElement(Dialog, { size: 'medium'});

What's hidden in JSX?

componentWillReceiveProps(nextProps){
    // Exit transition
    if(this.props.children && !nextProps.children){
        return this.transitionState(st.EXITING,
	    {children: this.props.children})
    };
}

transitionState(transitionTo, opt = {}){
    // .. FSM logic ..
    // Wait for `this._content.animateExit()`
}

Modal window v2.0

import Transition from 'react-transition-group/Transition';

// `state` is 'entered', 'entering', 'exited' etc.
<Transition in={isVisible} timeout={duration}>
    {state => <ModalDialog animationState={state} />}
</Transition>

Interception of responsibility

render(){
    return <canvas />
}

// Render only once!
shouldComponentUpdate() {
    return false;
}

componentWillReceiveProps(nextProps){
    if(this.props.color != nextProps.color){
        // Animate on canvas...
    }
}

Cool, but not enough

Much better

// Limit delta to avoid divergence
const delta = Math.min(100.0, ts - prevTs);
const P = 0.001 + delta;

this.x = P + (this.target - x);

P-controller

The End

ANIMATION

By Serge Zdobnov

ANIMATION

  • 567