What is the difference between Modifier and StateModifier in famo.us? - famo.us

I see that the famo.us examples mostly refer to Modifier class, however the famo.us university tutorials primarily reference StateModifier class.
How do these two differ and which is the most appropriate application for each?

Currently, these is no difference.
Use the StateModifier if you need setTransform,setSize,setOrigin and setOpacity.
Currently the Modifier still supports these methods, but they are Deprecated.
The StateModifier use a Transitionable, which can be used to smoothly transition between values. Just provide a transition when using these methods:
stateModifier.setTransform(Transform.rotateZ(Math.random()*Math.PI/2), { curve: 'easeOut', duration: 5000 });
The Modifier is more limited and uses transformFrom,sizeFrom,originFrom and opacityFrom. These methods can take in a value, getter-function, or an object with a get function.

According to the Famous University, these are the differences:
Statemodifiers create a new Transitionable for each instance, meaning that you cannot reuse a given transitionable.
With Modifiers you can:
- share state across components / derive states from one another
http://famo.us/university/famous-102/transitionables/6/

There is an important difference in their constructors' options. StateModifier accepts only constant values as an initial values. Modifier accepts both constant values and functions with appropriate returning values. The function will be evulated at 60fps.
1) StateModifier
var stateModifier = new StateModifier({
size: [200, 200],
opacity: 1,
transform: [1, 0.5, 0, 0, -0.5, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
//transform: Transform.translate(20, 20, 0), // --> this is still constant
});
2) Modifier
var transitionable = new Transitionable(0);
transitionable.set(2*3.14, {duration: 2000});
var modifier = new Modifier({
origin: [0.5, 0.5],
transform: function(){
var state = transitionable.get();
transition = Transform.rotateZ(state);
return transition; // --> this will cause rotating
},
opacity: function(){
return Math.random(); // --> this will cause blinking (60fps)
},
});

There are performance and design considerations around your choice of either.
You use a Modifier when your object has static positioning, or will change its transform details infrequently. An example would be if you had a group of objects which sat relative to a parent object, and you only needed to set their position once. You use a Modifier because once you have layed them out there's no need to worry about touching the render tree where they are concerned.
You use a StateModifier when you need to control the transform of your object more frequently. This is when you want to animate or control their transforms every frame, or whenever events happen.
The StateModifier uses either a pull or push approach. This gives you two ways to change/animate an objects transform. Pull means you are providing a function and using some object to determine the value of the object (like a Transitionable or your own object with a .get() method). This could be useful if you had a game object that was always tracking something else, you'd use a function which is hit each frame asking for the objects transform value. Push means that you decide when to change things, and use the .setOpacity or .setTransform methods of the StateModifier. This would better suit UI objects which remain stationary until some event fires. You can also use different easing curves whenever you call these methods or just have the change happen immediately.
The performance and design consideration comes from the fact that you should always try to write an application which doesn't have to do more than it needs to. If all of your objects use a StateModifier with a *pull model (using a function which is called each frame) you can imagine that this would cost more CPU power than if you only needed to change an object occasionally and you used the push method to change the object state when needed. This might not be a problem for a small UI but if you scaled your app up to control hundreds if not thousands of objects you can see where you start to cost more CPU power.
So in summary, Modifer is great for just placing stuff somewhere and forgetting about it, where as StateModifier is better for being able to move stuff, but you must chose between constantly being asked what it's doing (pull) or telling it when you are ready (push).

Related

Which is the appropriate lifecycle hook to draw a line?

I want to draw a line to show the zero value on a y axis. I have this working:
afterDraw(chart) {
const {ctx, scales} = chart;
Object.keys(scales).forEach((key) => {
const scale = scales[key];
if (scale.axis !== 'y') {
return;
}
const yCoordinate = scale.getPixelForValue(ZERO_COORDINATE);
ctx.fillStyle = 'blue';
ctx.fillRect(0, yCoordinate, 200, 5);
});
},
I had first attempted to use afterBuildTicks, but that didn't draw the line - or at least it wasn't visible. Is there guidance regarding when to use the different lifecycle hooks? Some seem obvious, others less so.
If I use the chart's context in any lifecycle hook, how do I ensure what I draw is on top of the chart? I saw an example where someone changed the background by supplying a beforeDraw callback - is the stacking context managed by order in which we draw via the different hooks?
There is a diagram in the chart.js documentation that shows when each hook is being called in the rendering process and what chart.js does between those hooks like drawing datasets, grids etc.
If you want to make sure what you are drawing is on top of everything else you will need to use the afterDraw hook to draw the things on the canvas that you want there.

Famo.us' Scrollview pagination: How to snap only when NEAR an edge?

The Famo.us Scrollview has a pagination feature that allows you to snap to the closest item.
Imagine you have a small container which has items with lots of content.
As soon as you want to scroll down to read the content outside the container, it either snaps back to the top, or snaps to the next item.
Does anybody know how to activate pagination only within a thresshold (X pixels) of an edge? That would be awesome.
Codepen demonstrating the problem here: http://codepen.io/markmarijnissen/pen/AGxaC?editors=001
var scroll = new Scrollview({
paginated: true,
pagePeriod: 500,
pageStopSpeed: 0.01, // mysterious option which might provide solution
pageSwitchSpeed: 100, // mysterious option which might provide solution
});
https://github.com/Famous/famous/blob/master/views/Scrollview.js
The TOLERANCE constant is not configurable yet. But you could easily contribute to make it configurable ;)

RaphaelJS Multiple animate same element

I currently have the following working fiddle
var moveAnim = Raphael.animation({ progress: 1 }, 5000, 'bounce').repeat(Infinity);
I animate a circle along a line.
I also want to make the circle flash at the same time but I can't seem to work out a way to do this?
I thought about adding the circle to a set and applying the additional animation to this but I can't see to get this either!
Any ideas?
This is a hack and I make no attempt to hide it, but it could be made a bit nicer.
There's a couple of problems depending on 'how' you want to animate the flash. The main problem is having 2 simultaneous animation on the same object, as Raphael doesn't do this (to my knowledge). Its easier if you want to animate an alternate attribute than the same one. If you want to animate a scale to indicate a flash, you will need to append the scale transform to the end of the path transform string ('t,s').
Example here, just uses opacity attribute.
Probably the nicest method would be to include something that figures out time running and amends an attribute manually within the animation function (paper.customAttributes.progress). However, that will probably take a bit longer.
Another alternative could be to animate another object off screen, that does all the calculations for you. It feels a bit ugly, but should work.
So earlier we create a dummy object off screen...
var dummy = paper.circle(-100,-100,10).attr({ opacity: 0 });
Within the progress func, you can then set the real circles opacity to be the same as the offscreen one.
this.attr('opacity', dummy.attr('opacity'));
And we get the dummy animation triggering later
dummy.animate(flashingAnim);
jsfiddle
As mentioned, I think there are cleaner ways, but may involve you writing a small linear animation func separately, but this may help if performance isn't an issue and you don't mind extra elements in the dom.
An alternative solution that I came up with is a looping callback. The very sound of a looping callback sounds ugly but I guess thats what an animation is?
It does appear that you can attach multiple animations to an element! Here's a an example
function animateIn() {
flashingCircle.animate({ fill: '#f00' }, 1000, animateOut);
}
function animateOut() {
flashingCircle.animate({ fill: '#fff' }, 1000, animateIn);
}
animateIn();

Infinite parallax scrolling with famo.us

I have a scrollview and an image as a background in different surface with lower z-index. I want to scroll the image with half the speed of the scrollview.
Any ideas on how to implement it ?
I can't give you a COMPLETE solution, but this should take you down a decent path.
1) Famo.us has worked on multiple scrollViews. Each has a slightly different method to get the 'scrollTop' value from it.
The one created earlier only gives you the scrollTop value for the first visible element in the list. So, in this case you can get how many elements have been scrolled away and calculate the actual value yourself. OR if you have a small, and limited number of the elements in the scrollView you should wrap all the elements in a single view and pass a singleView to the scrollView. This way Famo.us has to do calculations for off-screen elements, but if the number of elements is small enough, it can make many animations/calculations much easier.
The second scrollView was call LimitedScrollView internally. I don't have much experience with it yet, but it should give you the correct values anyway.
2) ScrollView fires events on scroll. use that to update the value of a transitionable.
Pseudo Code:
scrollView.on('scroll', function(){
transitionable.set(scrollView.scrollTop)
});
3) You can now bind the transform value for the background to the transitionable.
Pseudo Code:
background.transformFrom(function(){
return Transform.translate(0, -transitionable.get()/2, 0);
});
Now, things should work correctly.
Hope that helps.

How to remove surfaces from a layout?

I'm creating a lot of little surfaces that get added to a layout ( int this case a header footer layout), animated, then need to go away. However, I'm not sure how to remove the surfaces once added?
Kraig is right about using a RenderController when possible, but I would not suggest it for your case. RenderController works well with large layouts and not so much for small particles and such. RenderController only shows one view at a time.
I have asked about this on the IRC channel and it turns out the way I do it, feels really hacky, but is still the recommended most straight forward approach. The idea is to just redefine the render function to return null.
// surface to remove
surface.render = function(){ return null; }
That's it!
Just make sure you remove all references in your code as well!
I often do it from an object..
delete littleSurfaces['little-surface-key']
FWIW The more advanced approach is to actually define a view that controls specifically the surfaces that get rendered. You do this by defining the render function on a custom view that returns what is known as a renderSpec. A renderSpec is a list of hashes that define the surfaces that will be rendered. The example everyone points to is the Flipper class. Take a look at Flippers render function..
https://github.com/Famous/views/blob/master/Flipper.js
Good Luck!
You can add/remove surfaces using a RenderController object. You can also apply an optional transition when things are shown and hidden.
The DOM may lie to you sometimes, as Famo.us repurposes and recycles DOM Elements for efficiency.
https://famo.us/docs/api/latest/views/RenderController