0

I'm trying to get a square to change color on click in Famo.us, with a transition. I'm currently using CSS classes:

var square = new Surface({
  size: [200, 200],
  content: 'Hello.',
  properties: {
    lineHeight: '200px',
    textAlign: 'center'
  }
});

square.on('click', function() {
  square.addClass('active');
});

And the styling (written in Stylus):

.famous-container
  .famous-surface
    background: rgba(200, 200, 200, 0.5)

    transition: background 0.3s ease

    &.active
      background: rgba(200, 255, 200, 0.5)

It doesn't feel right, and I can't leverage things like Snap/SpringTransition. Is there a better way?

Theodor Vararu
  • 401
  • 2
  • 9

2 Answers2

2

The best way would be to use a RenderController object.

RenderController allows you to hide and show different renderable items with a transition of your choice.

Check out this example (slightly modified for you) posted under the Famo.us Github account.

https://github.com/Famous/examples/blob/master/src/examples/views/RenderController/example.js

var Engine           = require("famous/core/Engine");
var Modifier         = require("famous/core/Modifier");
var Surface          = require("famous/core/Surface");
var RenderController = require("famous/views/RenderController");

var mainContext = Engine.createContext();
var renderController = new RenderController();
var surfaces = [];
var counter = 0;

surfaces.push(new Surface({
     content: "Surface 1",
     size: [200, 200],
     properties: {
         backgroundColor: "green",
         lineHeight: "200px",
         textAlign: 'center'
     }
}));

surfaces.push(new Surface({
     content: "Surface: 2",
     size: [200, 200],
     properties: {
         backgroundColor: "red",
         lineHeight: "200px",
         textAlign: 'center'
     }
}));

renderController.show(surfaces[0]);

Engine.on("click", function() {
    var next = (counter++ + 1) % surfaces.length;
    this.show(surfaces[next]);
}.bind(renderController));

mainContext.add(new Modifier({origin: [.5, .5]})).add(renderController);

Fixed: Added missing parenthesis at the end of both surfaces.push(...) calls.

johntraver
  • 3,612
  • 18
  • 17
  • Looks good on paper, my only objection is that if you use this to create some togglable buttons/controls then you are effectively using 2-4 surfaces where there would normally only be one. Are complex GUIs in famous supposed to be composed of hundreds and hundreds of surfaces? (aka, does this approach scale/perform adequately?) – Theodor Vararu Apr 16 '14 at 20:39
  • 1
    Hey Theodor.. Yes again from the performance guides and pitfalls, they mentions this case.. "Transitioning color values causes large amounts of repainting and is very non-performant. To achieve a similar effect, try stacking a handful of canvas elements or divs of different colors and then opacitate them in/out accordingly." https://famo.us/guides/dev/pitfalls.html – johntraver Apr 16 '14 at 20:45
0

The simplest way I could think of is to update backgroundColor using setProperties method of a Surface.

Do that in Surface's render method, which is called on every render tick. Remember to return render spec (spec id).

Instead of using strings or hex values for colors, use rgb() or rgba() which accept number values. Number values are obtained from Transitionable objects using get method.

Toggle number values using Transitionable's set method in "click" event handler.

Remember to pass tween options when setting Transitionable value (duration and easing curve) for a smooth animated effect.

Here's the code:

var bgColorRed = new Transitionable(0);
var bgColorGreen = new Transitionable(255);
var bgColorBlue = new Transitionable(0);

var colorTweenTime = 500;

var clicked = false; 

var square = new Surface({
  size: [200, 200],
  content: 'Hello.',
  properties: {
    lineHeight: '200px',
    textAlign: 'center'
  }
});

square.render = function() {
    var red = Math.ceil(bgColorRed.get()),
        green = Math.ceil(bgColorGreen.get()),
        blue = Math.ceil(bgColorBlue.get());

    this.setProperties({
        backgroundColor: 'rgb(' + red + ', ' + green + ', ' + blue + ')'
    });

    return this.id;
};

square.on('click', function() {
    if (clicked) {
        bgColorRed.set(0, { duration: colorTweenTime, curve: 'easeIn' });
        bgColorGreen.set(255, { duration: colorTweenTime, curve: 'easeIn' });
    } else {
        bgColorRed.set(255, { duration: colorTweenTime, curve: 'easeIn' });
        bgColorGreen.set(0, { duration: colorTweenTime, curve: 'easeIn' });
    }
    clicked = !clicked;
});

jsFiddle available here: http://jsfiddle.net/mcr85/6fx9jo9e/

macro
  • 76
  • 4