Thibault Mahé - may 2017 - v1
Why animating an interface can enhance the UX?
Animating is...
An animation is
a set of values
over time
Loader
Parallax
transform
property valuesanimation-duration
, animation-delay
, animation-iteration-count
, ...animation-timing-function
values
, from
, to
, ...dur
, repeatCount
, begin
, end
, ...keytimes
, ...calcMode
, keySplines
, ...Angular 2
Cycle JS
Material Motion
[ ]
[ ]
...
[ ]
...
-- -->
[ ]
...
-- -->
An Observable is a set of values over time
Observables are:
An observable is an "interface" that can:
1- Create an Observable
2- Manipulate a stream: the operators
3- Listen to a stream: the subscription
Streams can be created from anything:
We can listen to those streams and react accordingly
var myvariable = 'foo';// The observable emits that value, then completes.var variableStream$ = Rx.Observable.of(myvariable);// The observable emits each item from the array, then completes.var arrayStream$ = Rx.Observable.from([1, 2, 3, 4, 5]);// The observable emits the promise result eventually, then completes (or errors).var promiseStream$ = Rx.Observable.fromPromise(fetch('http://example.com/users'));// The observable continuously emits events from the event listener.var mouseMove$ = Rx.Observable.fromEvent(window, 'mousemove');
Using Rx.js, a JavaScript implementation of ReactiveX
--a---b---c---d---X---|->
Visualizing Observables
Shematisation
stream$.subscribe( (value) => doSomething(value), (error) => console.error(error), () => console.log('complete'));
Example of a basic non-reactive animation: a moving ball
Example of a basic non-reactive animation: a moving ball
Schedule a stream on animation frame
Limit a stream with takeWhile
Map a velocity function (px / ms)
Map an easing function
Rx.Observable
...
.interval( 0, Rx.Scheduler.animationFrame )
.takeWhile( (t) => t <= duration )
.map( (t) => velocity(t) )
.map( (t) => elasticOut(t) )
--0--1--2--3--4--5--6--7--8--9--10--[...]->
Stream of intervals: --0--1--2--3--4--5--6--7--8--9--10--[...]->
Stream of ms: --2--6--17--18--31--32--48--[...]--1998--2012--|->
Stream of px: --2--4--8--[...]--123--125--[...]--297--300--|-->
Stream of px: --1--2--4--[...]--61--65--[...]--297--300--|-->
// Eventdocument.getElementById('foo') .addEventListener('click', listener);// Promisefetch('/foo/1') .then(listener)// Array[1, 2, 3, 4] .forEach(listener)
clickStream$.subscribe({ next: listener});fetchResponseStream$.subscribe({ next: listener});arrayStream$.subscribe({ next: listener});
.subscribe()
.var mouseStream$ = Rx.Observable .fromEvent(document, 'mousemove');var manipulateStream$ = moveStream$ .map(function(pos) { return changeData(pos) });
Manage data
manipulateStream$.subscribe(function(value) { updateUI(value);});
Manage rendering
hueStream$
est utilisé à 2 reprises : pour changer le bkg et pour changer le label central
Arc move from one location to another
Arc transition in which the center of the context moves along an arc path.
Choreographed transition to create a perception of contextual expansion
A dialog that expands from a location and reveals contents
Material Motion: "eliminate the concept of a design/engineering “hand off” by encouraging both designers and engineers to think of motion in a common language".
"V1 ideal journey"
The "handoff" is still here, but the Material Motion language helps the motion designers to describe their concept. Source
Material Motion: "eliminate the concept of a design/engineering “hand off” by encouraging both designers and engineers to think of motion in a common language".
"V2 ideal journey"
There is no more "handoff", the motion designer (or anyone else) directly use the Material Motion language to prototype the concept. Source
var $target = document.querySelector('...');
With Event listener:
document.addEventListener('mousemove', function(e) { $target.innerHTML = `(${e.clientX})`;});
With Observable subscription:
mouseMove$.subscribe(function(val) { $target.innerHTML = `(${val.clientX})`; });
Issues in both cases:
const mouse$ = Rx.Observable .fromEvent(document, 'mousemove') .map(({ x, y }) => ({ x, y }));const style$ = RxCSS({ mouse: mouse$,})style$.subscribe(...);
:root { --mouse-x: 0; --mouse-y: 0;}.ball { transform: translate(calc(var(--mouse-x) * 1px)) translateY(calc(var(--mouse-y) * 1px));}
Elements from http://slides.com/davidkhourshid/reactanim#/
Let's go !
Why animating an interface can enhance the UX?
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
Esc | Back to slideshow |