0

I am playing with Famo.us and trying out some of thier layout and transitions.

I am trying to build a set of columns that just fall to the bottom then restart and fall again. Even and odd columns is a different color and starts at a different time to look staggared.

What I am finding is the animation is quickly going out of sync. Is there a way to use the same modifier over a bunch of views. I feel my problem is I created this huge array of views and of modifiers and then doing all the animations seperately. I think if I could just utilize two modifiers maybe they would better stay in sync.

Famo.us Version

define('main', function(require, exports, module) {
  var Engine = require('famous/core/Engine');
  var Surface = require('famous/core/Surface');
  var Transform = require('famous/core/Transform');
  var StateModifier = require('famous/modifiers/StateModifier');
  var GridLayout = require("famous/views/GridLayout");
  var el = document.getElementById('famous-app');
  var View = require('famous/core/View');
  var Modifier = require('famous/core/Modifier');

  surfaceCount = 550;
  width = parseInt($('#famous-app').width());

  boxSize = width / surfaceCount;

  var mainContext = Engine.createContext(el);

  var grid = new GridLayout({
    dimensions: [surfaceCount, 1]
  })

  var views = [];
  var modifiers = [];
  
  grid.sequenceFrom(views);

  for (var i = 0; i < surfaceCount; i++) {

    var stateModifier = new StateModifier();
    var view = new View();
    var color;

    // Set Even Bars to be blue
    if (parseInt(i) % 2 == 0) {
      color = "blue";
    } 
    // Set Odd Bars to be Green
    else {
      color = "green";
    }
 
    // Create the Surface
    var surface = new Surface({
      size: [boxSize, 300],
      properties: {
        color: color,
        textAlign: 'center',
        backgroundColor: color
      }
    });

    // Add the Surface and its unique Modifier to the View
    view.add(stateModifier).add(surface);

    // Create an array of all Views and thier Modifiers
    modifiers.push(stateModifier);
    views.push(view);
  }

  mainContext.add(grid);

  // Set up the loop to do the animation
  var setup = function() {

    // Go through and start all the bars at the top
    for (var index = 0; index < modifiers.length; index++) {
      modifiers[index].setTransform(
        Transform.translate(0, -300, 0))

    }

    // Start the animation on the odd bars after 500 ms delay.
    window.setTimeout(function() {
      for (var index = 1; index < modifiers.length; index += 2) {
        transform(modifiers[index], 0);

      }
    }, 500);

    // Start the animation on the even bars
    for (var index = 0; index < modifiers.length; index += 2) {
      transform(modifiers[index]);

    }
  }

  // Do the actual transform, when finished repeat
  var transform = function(modifier) {

    modifier.setTransform(
      // Slide bar down over one second
      Transform.translate(0, 300, 0), {
        duration: 1000,
        curve: 'linear'
      },
      function() {
        modifier.setTransform(
          // Move Bar back to starting position
          Transform.translate(0, -300, 0), {
            duration: 0,
            curve: 'linear'
          },
          function() {
            // Repeat
            transform(modifier);
          });

      });
  }

  setup();

});

require(['main']);
.testing-containers {
  height: 600px;
}
.test-container {
  height: 300px;
  overflow: hidden;
  margin: 24px 0;
  position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://requirejs.org/docs/release/2.1.16/minified/require.js"></script>
<script src="http://code.famo.us/lib/requestAnimationFrame.js"></script>
<script src="http://code.famo.us/lib/classList.js"></script>
<script src="http://code.famo.us/lib/functionPrototypeBind.js"></script>

<link rel="stylesheet" type="text/css" href="http://code.famo.us/famous/0.3.4/famous.css" />

<script src="http://code.famo.us/famous/0.3.4/famous.min.js"></script>



<div class="test-container">
  <div id="famous-app" style="overflow:hidden;"></div>
</div>
w3bMak3r
  • 882
  • 8
  • 13

2 Answers2

1

Timing of transitions are dependent on render timing and will go out of sync waiting for the engine to render items on next tick even though they were started at the same time.

Use one modifier for your odd column transition and one modifier for your your even column transition. Add the two modifiers to the context at the same level and create your odd and even nodes.

  var oddModifier = new StateModifier({
    transform: Transform.translate(0, -300, 0)
  });
  var evenModifier = new StateModifier({
    transform: Transform.translate(0, -300, 0)
  });

  var rootNodeOdd = mainContext.add(oddModifier);
  var rootNodeEven = mainContext.add(evenModifier);

There will still need to be a modifier for each column, because you need to position along the y-axis at different locations. The modifier will still be added to your view for each column. This replaces the need for having to use the GridLayout.

    if (parseInt(i) % 2 === 0) {
      rootNodeOdd.add(view);
      color = "blue";
    }
    // Set Odd Bars to be Green
    else {
      rootNodeEven.add(view);
      color = "green";
    }

Start the transition loops to set the transforms for your odd and even modifiers.

  var setupEven = function() {
    oddModifier.running = true;
    evenModifier.setTransform(
      // Slide bar down over one second
      Transform.translate(0, 300, 0), {
        duration: 1000,
        curve: 'linear'
      },
      function() {
        evenModifier.setTransform(
          // Move Bar back to starting position
          Transform.translate(0, -300, 0), {
            duration: 0,
            curve: 'linear'
          },
          function() {
            evenModifier.running = false;
            setup();
          }
        );

      });
  };
  var setupOdd = function() {
    oddModifier.running = true;
    oddModifier.setTransform(
      // Slide bar down over one second
      Transform.translate(0, 300, 0), {
        duration: 1000,
        curve: 'linear'
      },
      function() {
        oddModifier.setTransform(
          // Move Bar back to starting position
          Transform.translate(0, -300, 0), {
            duration: 0,
            curve: 'linear'
          },
          function() {
            oddModifier.running = false;
            setup();
          }

        );

      });
  };

  var setup = function() {
    if (!oddModifier.running && !evenModifier.running) {
      setupEven();
      Timer.setTimeout(setupOdd, 500);
    }
  }

  setup();

Note: use the Timer.setTimeout utility in Famo.us instead of the window.setTimeout. The grid is not needed in this case now.

define('main', function(require, exports, module) {
  var Engine = require('famous/core/Engine');
  var Surface = require('famous/core/Surface');
  var Transform = require('famous/core/Transform');
  var StateModifier = require('famous/modifiers/StateModifier');
  var GridLayout = require("famous/views/GridLayout");
  var View = require('famous/core/View');
  var Modifier = require('famous/core/Modifier');
  var Timer = require('famous/utilities/Timer');

  surfaceCount = 550;
  var el = document.getElementById('famous-app');
  width = parseInt($('#famous-app').width());

  boxSize = width / surfaceCount;

  var mainContext = Engine.createContext(el);

  var modifiers = [];

  var oddModifier = new StateModifier({
    transform: Transform.translate(0, -300, 0)
  });
  var evenModifier = new StateModifier({
    transform: Transform.translate(0, -300, 0)
  });

  var rootNodeOdd = mainContext.add(oddModifier);
  var rootNodeEven = mainContext.add(evenModifier);

  for (var i = 0; i < surfaceCount; i++) {

    var stateModifier = new StateModifier();
    var view = new View();
    var color;

    // Set Even Bars to be blue
    if (parseInt(i) % 2 === 0) {
      rootNodeOdd.add(view);
      color = "blue";
    }
    // Set Odd Bars to be Green
    else {
      rootNodeEven.add(view);
      color = "green";
    }

    // Create the Surface
    var surface = new Surface({
      size: [boxSize, 300],
      properties: {
        color: color,
        textAlign: 'center',
        backgroundColor: color
      }
    });

    // Add the Surface and its unique Modifier to the View
    view.add(stateModifier).add(surface);

    stateModifier.setTransform(Transform.translate(i * boxSize, 0, 0));

    // Create an array of all Views and thier Modifiers
    modifiers.push(stateModifier);
  }

  // Set up the loop to do the animation
  var setupEven = function() {
    oddModifier.running = true;
    evenModifier.setTransform(
      // Slide bar down over one second
      Transform.translate(0, 300, 0), {
        duration: 1000,
        curve: 'linear'
      },
      function() {
        evenModifier.setTransform(
          // Move Bar back to starting position
          Transform.translate(0, -300, 0), {
            duration: 0,
            curve: 'linear'
          },
          function() {
            evenModifier.running = false;
            setup();
          }
        );

      });
  };
  var setupOdd = function() {
    oddModifier.running = true;
    oddModifier.setTransform(
      // Slide bar down over one second
      Transform.translate(0, 300, 0), {
        duration: 1000,
        curve: 'linear'
      },
      function() {
        oddModifier.setTransform(
          // Move Bar back to starting position
          Transform.translate(0, -300, 0), {
            duration: 0,
            curve: 'linear'
          },
          function() {
            oddModifier.running = false;
            setup();
          }

        );

      });
  };

  var setup = function() {
    if (!oddModifier.running && !evenModifier.running) {
      setupEven();
      Timer.setTimeout(setupOdd, 500);
    }
  }

  setup();

});

require(['main']);
.testing-containers {
  height: 600px;
}
.test-container {
  height: 300px;
  overflow: hidden;
  margin: 24px 0;
  position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://requirejs.org/docs/release/2.1.16/minified/require.js"></script>
<script src="http://code.famo.us/lib/requestAnimationFrame.js"></script>
<script src="http://code.famo.us/lib/classList.js"></script>
<script src="http://code.famo.us/lib/functionPrototypeBind.js"></script>

<link rel="stylesheet" type="text/css" href="http://code.famo.us/famous/0.3.5/famous.css" />

<script src="http://code.famo.us/famous/0.3.5/famous.min.js"></script>



<div class="test-container">
  <div id="famous-app"></div>
</div>
talves
  • 13,993
  • 5
  • 40
  • 63
1

Your intuition about the modifiers is correct. It is much more reliable to have all these surfaces that are moving in conjuction with shared modifiers than to attempt to keep them all in sync using callbacks and setTimeout.

This becomes difficult with something like a gridLayout however, because none of the surfaces that the layout sequences from can share modifiers.

There are numerous ways of handling this. I cooked up a solution using two gridLayouts. Hope it helps!

Famous.loaded(function () {
var Engine = Famous.Core.Engine;
var Modifier = Famous.Core.Modifier;
var Transform = Famous.Core.Transform;
var Surface = Famous.Core.Surface;
var GridLayout = Famous.Views.GridLayout;
var Timer = Famous.Utilities.Timer;

var ctx = Engine.createContext();
var ctxSize = ctx.getSize();
var numSurfaces = 16;

/*
    CREATE PINK GRID
*/
var pinkGrid = new GridLayout({
    dimensions: [numSurfaces, 1],
});
var pinkGridMod = new Modifier({ size: [undefined, 220]});

/*
    CREATE RED GRID
*/
var redGrid = new GridLayout({
    dimensions: [numSurfaces, 1],
});
var redGridMod = new Modifier({
    size: [undefined, 220],
    transform: Transform.translate(0, 0, 0)
});

/*
    CREATE SURFACES
*/
var redSurfaces = [];
var pinkSurfaces = [];
for (var i = 0; i < numSurfaces; i++) {
    var input = i % 2 ? pinkSurfaces : redSurfaces;
    input[i] = new Surface({
        properties: {
            backgroundColor: i % 2 ? 'pink' : 'red'
        }
    });
}
pinkGrid.sequenceFrom(pinkSurfaces);
redGrid.sequenceFrom(redSurfaces);

/*
    ANIMATE
*/

Timer.every(function() { 
    pinkGridMod.setTransform(Transform.translate(0, 0, 0));
    pinkGridMod.setTransform(Transform.translate(0, ctxSize[1], 0), { duration: 1000 })
}, 100);

Timer.after(function() {
    Timer.every(function() {
        redGridMod.setTransform(Transform.translate(0, 0, 0));
        redGridMod.setTransform(Transform.translate(0, ctxSize[1], 0), { duration: 1000 })
    }, 100);
}, 50)

/*
    ADD GRIDS TO CONTEXT
*/

    ctx.add(pinkGridMod).add(pinkGrid);
    ctx.add(redGridMod).add(redGrid);
});

Check it out on JSFiddle here -> http://jsfiddle.net/z1kz5ndf/