Famo.us y Angular
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/802468/famous-angular-logos.png)
Gonzalo Ruiz de Villa
@gruizdevilla
http://slides.com/gruizdevilla/angular-famo-us
Meetup AngularJS Madrid
about me
Gonzalo Ruiz de Villa
@gruizdevilla
@adesis
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/805272/avatar.png)
siguientes meetups
¿Qué es Famo.us?
- Un motor OSS de renderizado web.
- Permite realizar animaciones con gran rendimiento de forma imperativa
- Tiene como objetivo conseguir que las aplicaciones web den la sensación de aplicaciones nativas
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/802496/icon.png)
Pero en AngularJS las animaciones son por CSS3
Lo cual puede estar muy bien para cosas sencillas.
.reveal-animation.ng-enter {
-webkit-animation: enter_sequence 1s linear; /* Safari/Chrome */
animation: enter_sequence 1s linear; /* IE10+ and Future Browsers */
}
@-webkit-keyframes enter_sequence {
from { opacity:0; }
to { opacity:1; }
}
@keyframes enter_sequence {
from { opacity:0; }
to { opacity:1; }
}
Pero cuando queremos algo SOLO UN POCO
más sofisticado...
.element-animation{
animation: animationFrames linear 4s;
animation-iteration-count: 1;
transform-origin: ;
-webkit-animation: animationFrames linear 4s;
-webkit-animation-iteration-count: 1;
-webkit-transform-origin: ;
-moz-animation: animationFrames linear 4s;
-moz-animation-iteration-count: 1;
-moz-transform-origin: ;
-o-animation: animationFrames linear 4s;
-o-animation-iteration-count: 1;
-o-transform-origin: ;
-ms-animation: animationFrames linear 4s;
-ms-animation-iteration-count: 1;
-ms-transform-origin: ;
}
@keyframes animationFrames{
0% {
left:-299px;
top:-196px;
opacity:1;
transform: rotate(-1deg) scaleX(1) scaleY(1) ;
}
50% {
left:-137px;
top:25px;
transform: rotate(976deg) scaleX(0.77) scaleY(3.179999999999998) ;
}
100% {
left:200px;
top:0px;
opacity:1;
transform: rotate(24deg) scaleX(3.52) scaleY(3.179999999999998) ;
}
}
@-moz-keyframes animationFrames{
0% {
left:-299px;
top:-196px;
opacity:1;
-moz-transform: rotate(-1deg) scaleX(1) scaleY(1) ;
}
50% {
left:-137px;
top:25px;
-moz-transform: rotate(976deg) scaleX(0.77) scaleY(3.179999999999998) ;
}
100% {
left:200px;
top:0px;
opacity:1;
-moz-transform: rotate(24deg) scaleX(3.52) scaleY(3.179999999999998) ;
}
}
@-webkit-keyframes animationFrames {
0% {
left:-299px;
top:-196px;
opacity:1;
-webkit-transform: rotate(-1deg) scaleX(1) scaleY(1) ;
}
50% {
left:-137px;
top:25px;
-webkit-transform: rotate(976deg) scaleX(0.77) scaleY(3.179999999999998) ;
}
100% {
left:200px;
top:0px;
opacity:1;
-webkit-transform: rotate(24deg) scaleX(3.52) scaleY(3.179999999999998) ;
}
}
@-o-keyframes animationFrames {
0% {
left:-299px;
top:-196px;
opacity:1;
-o-transform: rotate(-1deg) scaleX(1) scaleY(1) ;
}
50% {
left:-137px;
top:25px;
-o-transform: rotate(976deg) scaleX(0.77) scaleY(3.179999999999998) ;
}
100% {
left:200px;
top:0px;
opacity:1;
-o-transform: rotate(24deg) scaleX(3.52) scaleY(3.179999999999998) ;
}
}
@-ms-keyframes animationFrames {
0% {
left:-299px;
top:-196px;
opacity:1;
-ms-transform: rotate(-1deg) scaleX(1) scaleY(1) ;
}
50% {
left:-137px;
top:25px;
-ms-transform: rotate(976deg) scaleX(0.77) scaleY(3.179999999999998) ;
}
100% {
left:200px;
top:0px;
opacity:1;
-ms-transform: rotate(24deg) scaleX(3.52) scaleY(3.179999999999998) ;
}
}
¿Te gusta?
No gusta porque
- Es muy pesado
- Esos malditos prefijos y tanta repetición (¿gulp-autoprefixer al rescate?)
- ¿Pero qué es lo que está haciendo exactamente?
- El código declarativo tiene limitaciones para explicar ciertas cosas (grunt vs gulp, ya que estamos...).
Famo.us tiene otra filosofía
- Las animaciones se describen mejor de forma imperativa
- Tiene sus propios artefactos que nos permiten abstraernos y el motor se ejecuta permanentemente actualizando la pantalla
- Los usuarios (de móviles) esperan de las aplicaciones muchas animaciones, unas más vistosas y otras más sutiles.
var sync = new GenericSync({
"mouse" : {},
"touch" : {},
"scroll" : {scale : .5}
});
sync.on('update', function(data){
var currentPosition = position.get();
position.set([
currentPosition[0] + data.delta[0],
currentPosition[1] + data.delta[1]
]);
});
¿Cómo funciona Famo.us?
- Usa transformaciones CSS3, que permiten pasar por la GPU para mejorar el rendimiento
- Usa requestAnimationFrame para ir a 60fps
- En cada tick, calcula la posición mediante álgebra lineal, multiplicando matrices y acaba informando de sus posiciones a cada elemento.
Pero Famo.us es 100% JavaScript
Crea un contexto y debajo cuelga sus piezas
context var context = Engine.createContext();
│
surface context.add(surface);'
El árbol de Famo.us es JS y no DOM
context var context = Engine.createContext();
│
modifier var chain = context.add(modifier);
│
surface chain.add(surface);
context
│
modifier
│
scrollview
┌───┬───┼───────┐
S1 S2 S3 ⋯ S10
┌─────┴─────┐
modifier1 modifier2
│ │
surface1 surface2
div.app
│
┌───┬───┼───────┐
div div div ⋯ div
Aunque tengamos un árbol complicado, en el DOM se ve una estructura plana donde se modifica la propiedad style con transformaciones CSS3 de cada capa
Recapitulando sobre Famo.us
- No hay HTML
- Si queremos usar un MVC, ¿donde están las Views?
- DOM con HTML funciona muy bien para representar estructurar jerárquicas, como los UI
- Pero en Famo.us no tenemos DOM, utilizamos otra semántica
Famo.us y AngularJS v0
- Sin disponer de HTML, no hay un sitio común donde se puedan encontrar AngularJS y Famo.us
- AngularJS se construye a partir del estándar HTML, enriqueciéndolo (compilando los nodos y bindeándolos)
- La aproximación de Famo.us es radicalmente opuesta
- Los dos frameworks tienen puntos muy fuertes para algunas cosas y débiles en otras. Están especializados.
Ignorando los problemas anteriores...
¿Qué es lo que queremos?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803817/AllTheGuy3.png)
¡Mantener el rendimiento de Famo.us!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
¿Y que más queremos?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803817/AllTheGuy3.png)
¡Usar el databinding de AngularJS!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
¿Y que más queremos?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803817/AllTheGuy3.png)
¡Usar componentes de AngularJS! (incluso de terceros)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
¿Y que más queremos?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803817/AllTheGuy3.png)
¡Usar componentes de Famo.us! (incluso de terceros)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
¿Y que más queremos?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803817/AllTheGuy3.png)
¡Minimizar el esfuerzo conceptual!
Usando las convenciones de cada librería cuando sea posible.
Pues dad al César lo que es del César, y a Dios lo que es de Dios
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
Veamos que propone
famous-angular
¿Por donde empezar?
- Famo.us tiene un RenderTree que es eso, un árbol, como el DOM.
- ¿Y si en lugar de intentar conseguir que ambos mundos convivan en el mismo espacio y con los mismos elementos DOM, tratamos de agregar un paso de compilación?
- AngularJS ya tiene un compilador de DOM para las directivas. ¿Y si somos capaces de comunicar esta estructura (jerarquía) definida con DOM a Famo.us?
Comunicando la jerarquía
- Angular mantiene una jerarquía que se corresponde con scopes hijos
- Esta jerarquía es la que se transformará en el árbol de renderizado de Famo.us
- La forma de resolver esto es con eventos: cada hijo envía un evento a su padre. A medida que la jerarquía de scopes es recorrida por los eventos, las directivas atan entre ellos a los correspondientes componentes de Famo.us.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803866/scopes.png)
DOM tree -> Famo.us tree
- AngularJS tiene varios pasos en la compilación de una directiva: compile, controller, prelink, postlink.
- En relación al árbol, prelink se ejecuta antes de recorrer los hijos y postlink después de recorrerlos.
- En prelink creamos los observadores de eventos, y en post link los disparamos.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803942/scopestree.png)
¿Qué hemos conseguido?
- Hemos creado un DSl para definir el árbol de Famo.us mediante DOM. AngularJS compila nuevas directivas que crean los componentes del árbol de renderizado.
- Precisamente, definir un árbol es algo que se puede hacer muy bien con markup.
- Este código de Famo.us
- Se ve ahora así (con binding incluido!!!):
var myView = new View();
var mySurface = new Surface();
mySurface.setContent("<div>I'm a surface</div>");
myView.add(mySurface);
<fa-view>
<fa-surface>
<div>I'm {{data.bound}}</div>
</fa-surface>
</fa-view>
Beneficios
- Es muy fácil integrar Famo.us con aplicaciones HTML o Angular
- Podemos usar el databinding de Angular con Famous
- Ayuda a separar responsabilidades
- Podemos usar nuestras directivas dentro de Famo.us
- Mantienes los beneficios tradicionales de Angular, como organización, tests, etc.
$digest
- Fundamental dentro de AngularJS
- Pero es muy pesado, por eso sólo se lanza como reacción a eventos
- Famo.us tiene un ciclo que dura 1/60 s.
- Si el $digest dura un poco más, tenemos un problema, si dura un poco menos apenas deja tiempo para hacer cosas.
- Luego hay que desacoplar el ciclo de $digest con el ciclo de renderizado de AngularJS
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/803815/AllTheGuy.png)
¡Desacoplando todos los ciclos!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/805172/cycles.png)
- Se usa la función $parse de Angular para crear funciones que están vinculados a los Modifiers de Famo.us
- Se fuerza un flujo unidireccional de Angular a Famo.us para que este no tenga efectos laterales (digests) durante el renderizado.
Un poco de código, por favor
Recursos
- https://github.com/famous/famous-angular/
- http://famo.us/integrations/angular/
- https://github.com/thomasstreet/famous-angular-starter
- http://thomasstreet.com/blog/famous-angular/2014/04/28/famous-angular.html
- http://thomasstreet.com/famous-angular-google/
- http://famo.us/university/home/#/famous-angular
- https://famo.us/integrations/angular/docs/api/index.html
¡Gracias!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/gruizdevilla/images/815080/qrplanet.png)
Angular + Famo.us
By Gonzalo Ruiz de Villa
Angular + Famo.us
Angular y Famo.us: combinando lo mejor de dos mundos distintos
- 3,486