Learn Famo.us [part 2]: Displaying and Positioning Elements

In part 2 of my series on Famo.us, it’s day 1 of the thesis project of Hack Reactor and the Famo.us HQ is amazing! WP_20140729_006   An entire side of the building on the Penthouse Suite + Patio with a view + Free food + Showers = Can I live here? Unfortunately, I can only stay as long as late as the last employee each night…

During our first day, we took an in-depth dive to Famo.us University, it was much more detailed and nicely explained the nuances not touched in the tutorials. For this post, I decided to go really in-depth as well due to the lack of documentation and resources out there. Simply put, I want this to be the best resource for those now starting to learn Famo.us.

What is a Surface?

A Surface is a renderable. In laymen terms, a renderable is something you can to the main context (more on this later) and see on the screen. The function of a surface is to display, visually, the data you give it. Surfaces have no knowledge of its position on the screen or its opacity. Also, in terms of the render tree (will write a post on this soon, in the meantime, read this), you can think of a surface as a leaf. You cannot add anything to a leaf in a tree.

How to create a surface Creating a surface is simple. Just require the surface class and use the new keyword. I’ve also included the boilerplate code that is required with almost every Famo.us app.

define(function(require, exports, module) {

  // main requires
  var Engine  = require('famous/core/Engine');
  var Surface = require('famous/core/Surface');

  // create the main context
  var mainContext = Engine.createContext();

  // create a new surface and
  // pass in the options object
  var mySurface = new Surface({
    size: [100, 100],
    content: 'Hello Famo.us!',
    properties: {
      backgroundColor: 'red',
      color: 'white'
    }
  });

  // add our surface to the mainContext
  // so we can see it on the screen
  mainContext.add(mySurface);

});

Size. You can define the size [width, height] in pixels inside of the options object. A size of [100, 100] is 100 pixels wide and 100 pixels long. You can also pass in true, for example a size of [true, true] would be just enough space for the content. And a size of [undefined, undefined] will take up the entire screen and also resize accordingly. You can also interchange the true and undefined with specific pixel values. A size of [500, undefined] would be a surface that is 500 pixels wide but is as long as the screen. Stringified percentages (‘50%’) can also be used.

Content. of the content, you can use HTML to help with formatting. Trying passing in ‘Hello Famo.us!’ to see the effect. You can also attach an image using a div with a src to the picture url (ImageSurface would be better in this situation).

Properties. For those with more CSS experience, you can pass in CSS in the properties object. It’s a little different though with camelCase instead of dashes. For example, background-color -> backgroundColor.

Other. You can add classes to surfaces and apply CSS that way. You can use different classes that extend from surfaces such as a CanvasSurface, ContainerSurface, ImageSurface, InputSurface, TextareaSurface and VideoSurface. I won’t go into these in this post, but just know that they exist and that some might be better suited for your situation.

What is a Modifier?

A Modifier is also a renderable. It can be applied to the main context to change the position and other properties, such as opacity, of surfaces. In terms of the render tree, modifiers will affect anything below it on the same branch. And unlike surfaces, modifiers can be chained together. You can have as many modifiers affecting a surface or a group of surfaces as you want.

How to create a Modifier We’ll use the same code as above and add in a StateModifier.

define(function(require, exports, module) {

  // main requires
  var Engine     = require('famous/core/Engine');
  var Surface    = require('famous/core/Surface');
  var Modifier   = require('famous/modifiers/StateModifier');
  var Transform  = require('famous/core/Transform');

  // create the main context
  var mainContext = Engine.createContext();

  // create a new surface and
  // pass in the options object
  var mySurface = new Surface({
    size: [100, 100],
    content: 'Hello Famo.us!',
    properties: {
      backgroundColor: 'red',
      color: 'white'
    }
  });

  // now let's create a modifier
  // and pass in some options
  var myModifier = new Modifier({
    origin: [0.5, 0.5],
    align: [0.5, 0.5],
    transform: Transform.rotateZ(10)
  });

  // add our surface (and now our modifier as well!)
  // to the mainContext so we can see it on the screen
  mainContext.add(myModifier).add(mySurface);

});

The modifier we applied will simply set the origin and align to [0.5, 0.5] effectively centering the red surface on the screen. It also resizes according to the screen size, maintaining its center position.

Kyle’s analogy. Say you have a cork board (the brown board you stick push pins in) on the wall. We’ll let this represent the main context. Now let an index card represent a surface. You want to add the index card in the bottom left of the cork board. How would you do this in Famo.us?

Origin vs Align. By understanding the difference between the two, you can position surfaces effectively on the screen. In the above example, you can control where you stick the push-pin through the index card with origin. And you can control where you place the index card (currently with the push-pin through it) on the cork board using align. In more technical terms: origin controls the child anchor and the align controls the parent anchor. Be sure to always include an align if you set the origin since the align, by default, is set to the origin.

Transform. You can also rotate and translate using Transform.rotate and Transform.translate. You can rotate in a single dimension by doing Transform.rotateX(), Transform.rotateY(), Transform.rotateZ() or rotate all at once by doing Transform.rotate(x, y, z). Transform.translate(x, y, z) works in a similar fashion. I recommend playing around with the rotations and translations to get a better feel for using Transform. An interesting distinction is that translate is in pixels and rotation ranges from 0 to 2π.

Chaining. You can apply as many modifiers as you want to the context. The way it works is that any surface below modifiers on the render tree will be affected by those modifiers. This covers the basics on surfaces and modifiers.

In my future posts, I will explain the render tree with visuals and  show more practical code examples. Also, I am working on compiling every last bit of information and learning resource there is on Famo.us into a post. Subscribe if you’d like access.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s