If I create a context and add some layout and surfaces, but later want to restart the entire app is there a way to do this?
Is there a method on the Engine?
Basically I am asking if there is something that is the opposite of Engine.createContext ?
You can use a RenderController to add/remove content from the render-tree:
// import dependencies
var Engine = require('famous/core/Engine');
var RenderNode = require('famous/core/RenderNode');
var RenderController = require('famous/views/RenderController');
// create context & render-controller
var context = Engine.createContext();
var renderController = new RenderController();
context.add(renderController);
function restart() {
// create content you want to show
var content = new AppView();
// Show content
var renderNode = new RenderNode(content);
renderController.show(renderNode, {duration: 0});
}
restart();
Related
I am new to famo.us. I am interested in creating animation where surface/object is in continuous motion and also its opacity keeps changing( ranging from 0->1 and back). I have am able to continuously rotate a surface and change its opacity from 1 to 0 once. I am stuck here as I am not sure how to proceed forward. Can someone suggest me some ideas ?
There are a couple ways you can go about doing this. It really depends on the exact effect you are trying to achieve. Here is an example using Modifier and its opacityFrom method to achieve a never ending sine effect.
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var RenderNode = require('famous/core/RenderNode');
var Modifier = require('famous/core/Modifier');
var context = Engine.createContext();
surface = new Surface({
size:[200,200],
properties:{
backgroundColor:'green'
}
})
surface.node = new RenderNode();
surface.mod = new Modifier({origin:[0.5,0.5]});
var startTime = Date.now();
var period = 1000;
surface.mod.opacityFrom(function(){
currentTime = Date.now();
return Math.abs(Math.sin((((currentTime - startTime) / period))));
});
surface.node.add(surface.mod).add(surface);
context.add(surface.node);
Or if you would like, you could achieve a never ending animation by just using StateModifier the callback function in setOpacity. Here I am recursively calling the same function, in a nested callback. This is what that looks like.
Hope some of this helps!
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var RenderNode = require('famous/core/RenderNode');
var StateModifier = require('famous/modifiers/StateModifier');
var Easing = require('famous/transitions/Easing');
var context = Engine.createContext();
surface = new Surface({
size:[200,200],
properties:{
backgroundColor:'green'
}
})
surface.node = new RenderNode();
surface.mod = new StateModifier({origin:[0.5,0.5]});
surface.state = 0
surface.setState = function(state,transition){
surface.state = (state == 0) ? 1 : 0;
surface.mod.setOpacity(state,transition,function(){
surface.setState(surface.state,transition);
});
}
surface.node.add(surface.mod).add(surface);
context.add(surface.node);
surface.setState(surface.state,{duration:1000, curve:Easing.inOutQuad});
I'm searching for an code example of the Lightbox demo from famo.us. Unfortunately, the interesting part of the app in the codepen is uglified in the pens version of the famous.lib.js.
It's not the whole gallery thing I'm interested in, its "just" a scollable view with multiple elements in one row, depending on their size and the screen size.
Has anyone experiences in developing a View/Layout like this?
Thanks in advance
I have been doing some work with Scrollview and GridLayout. You can calculate grid dimensions based on contextSize and target/min cell size.
Here is an example to get you started. I am essentially adding a gridLayout as the sole view in Scrollview. I know this may work against scrollviews efficient rendering in that scrollview will always be rendering the entire grid, but I am doing it for the examples sake. I use Modifier around the gridLayout to ensure the size of the view is always calculated and scrollview always scrolls the right amount. So anyway, here is what I did..
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var RenderNode = require('famous/core/RenderNode');
var Modifier = require('famous/core/Modifier'); // edited
var Scrollview = require('famous/views/Scrollview');
var GridLayout = require('famous/views/GridLayout');
var context = Engine.createContext();
var scrollViews = [];
var scrollview = new Scrollview();
scrollview.sequenceFrom(scrollViews);
var gridCells = [];
var grid = new GridLayout();
grid.sequenceFrom(gridCells);
grid.mod = new Modifier();
var cellCount = 24;
var cellMinWidth = 200.0;
grid.mod.sizeFrom(function(){
var size = context.getSize();
var cellsX = Math.floor(size[0] / cellMinWidth);
var cellsY = Math.ceil(cellCount * 1.0 / cellsX);
var cellHeight = size[0] * 1.0 / cellsX;
grid.setOptions({dimensions:[cellsX,cellsY]});
return [undefined,cellsY*cellHeight];
});
grid.node = new RenderNode();
grid.node.add(grid.mod).add(grid);
for (var i = 0; i < cellCount; i++) {
var surface = new Surface({
size:[undefined,undefined],
properties: {
backgroundColor:'hsl('+(i*360/12)+',75%,50%)'
}
});
gridCells.push(surface);
surface.pipe(scrollview);
};
scrollViews.push(grid.node);
context.add(scrollview);
FWIW To really maximize the efficiency of scrollview, you need to have a list of views that are rendered sequentially. Since we are only rendering one view in scrollview, we are always rendering everything, all the time. I have thought of a couple ways to get around this though, that both extend beyond the scope is this example.
You could do the visibility check yourself and render nodes based on the position of the scrollview.
You could create a gridLayout for each row, then manage the cells within each grid using list manipulation techniques.
BONUS:
If you just want to use GridLayout just for the modifiers, I found using _modifiers property rather helpful (Note: only available after deploy!). I was able to create a rearrangeable layout using this technique. The surfaces are all floating outside the gridlayout and only being positioned via their draggable modifier based on the gridlayouts modifiers. Here is that working demo of that..
http://higherorderhuman.com/examples/rearrangeable.html
Hope this helps!
I'm willing to build an endless animation using famous (for example an endless rolling gear or a randomly shaken surface). Should I write a custom Transitionable with an infinite duration or there is something smarter to achieve this ?
I would recommend using Modifiers transformFrom method to define a position or rotation based on time. This allows you to set a transform that will be updated on every tick of the engine, but will be controlled via actual time.
Here is an example of that..
Hope it helps!
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var Transform = require('famous/core/Transform');
var Modifier = require('famous/core/Modifier');
var context = Engine.createContext();
var surface = new Surface({
size:[200,200],
content: "Hello",
properties: {
lineHeight:"200px",
color:"white",
textAlign:"center",
backgroundColor:'green'
}
})
surface.mod = new Modifier({
origin: [0.5,0.5],
align:[0.5,0.5]
});
var startTime = (new Date).getTime();
surface.mod.transformFrom(function(){
var currentTime = (new Date).getTime();
var rotation = (currentTime - startTime) / 360.0;
return Transform.rotate(0,0,rotation);
});
context.add(surface.mod).add(surface);
The answer is to use Transitionables
First you use use Transitionable.set(destination, {duration: VALUE})
Each Engine 'prerender' (every frame), you use Transitionable.get() to update a Modifier Transform
At the end of the Transitionable, it will run a callback to update the new destination
this.transit = new Transitionable(0);
// ------- when i say twerk, you twerk ----->
var _createWheelMod = function() {
var _setWheelModRotation = function() {
Engine.on("prerender", function() {
this.wheelMod.setTransform(Transform.rotate(0, 0, this.transit.get()));
}.bind(this));
};
// ------------ charge lasers ------->
var _setDestination = function() {
this.transit.set(100 + this.transit.get(), {duration: 2e5},
_setDestination.bind(this)); // callback when the transition has finished
};
_setWheelModRotation.call(this);
_setDestination.call(this);
};
I've just moved to Famo.us and think it has some amazing potential. I am trying to build a new App using Famo.us and will be having 'layered' Views, one of which has a CanvasSurface inside.
My question is about how I would populate the CanvasSurface? I have checked the Docs and while they talk about some of the parameter options they do not tell you how.
I have a View within which I add a Layout and then a Surface to that Layout. Other Views that have ImageSurfaces work fine - but I do not know if I am on the right track with CanvasSurface.
So far I have: (part of inside a BackgroundView.js file)
function BackgroundView() {
View.apply(this, arguments);
_createLayout.call(this);
_createBody.call(this);
_setListeners.call(this);
}
function _createBody() {
this.bodySurface = new CanvasSurface({
canvasSize : [undefined, undefined]
});
var bodyContext= this.bodySurface.getContext('2d');
bodyContext.fillText("Text on Canvas", 100, 100);
this.layout.content.add(this.bodySurface);
}
It runs with no errors, but shows nothing. The CanvasSurface is rendered...
Are there any examples using CanvasSurface or does anyone have any thoughts?
Thanks again for your help in advance.
:)
There are a couple of things I added to your code.. Defining the prototype and prototype.constructor, as well as adding the CanvasSurface to the BackgroundView. I found that canvasSize does not currently support the undefined size attribute like Surface does. You need to be explicit and use pixel size.
Check out what I did to your code.. Hope this helps..
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var View = require('famous/core/View');
var CanvasSurface = require('famous/surfaces/CanvasSurface');
var context = Engine.createContext();
function BackgroundView() {
View.apply(this, arguments);
// _createLayout.call(this);
_createBody.call(this);
// _setListeners.call(this);
}
BackgroundView.prototype = Object.create(View.prototype);
BackgroundView.prototype.constructor = BackgroundView;
function _createBody() {
this.bodySurface = new CanvasSurface({
size:[400,200]
});
var bodyContext= this.bodySurface.getContext('2d');
bodyContext.font="20px Georgia";
bodyContext.fillText("Hello World!",50,50);
this.add(this.bodySurface);
}
var bg = new BackgroundView();
context.add(bg);
If I have a transform translate thats animating something vertically between say 0 -> 1000, over 5 seconds, is there a way if I have click events to change the horizontal position without interrupting the vertical animation?
p.setTransform(Transform.translate(20,1000,0),
{
duration: 5000,
curve: 'linear'
});
then on some random click, I want to start changing the x position over 100ms or so, and it might have multiple of these before the 5000 duration has finished
I can play with the origin and animate that independently, but I really need pixel control. So is there a way to animate just the x?
If I add a setTransform, it chains after the first one rather than concurrently.
Yes, you most certainly can achieve this. You will want to use a ModifierChain. ModifierChain allows you to chain your modifiers together and control the transforms independently. Check out this example..
Hope this helps!
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var StateModifier = require('famous/modifiers/StateModifier');
var Transform = require('famous/core/Transform');
var ModifierChain = require('famous/modifiers/ModifierChain');
var Easing = require('famous/transitions/Easing');
var context = Engine.createContext();
var surface = new Surface({
size:[200,200],
properties: { backgroundColor:'green' }
});
surface.yState = new StateModifier();
surface.xState = new StateModifier();
var x = 0;
var y = context.getSize()[1] - 200;
surface.on('click',function(){
x += 100;
surface.xState.halt();
surface.xState.setTransform(Transform.translate(x,0,0),{duration:200});
});
surface.chain = new ModifierChain();
surface.chain.addModifier(surface.yState);
surface.chain.addModifier(surface.xState);
context.add(surface.chain).add(surface);
surface.yState.setTransform(Transform.translate(0,y,0), {duration:5000});