famo.us触发事件在动画的关键点

时间:2014-06-19 10:15:49

标签: javascript animation transform famo.us

我正试图在转换的进度(而不是时间)中途触发一个事件。这听起来很简单,但由于过渡可以有任何曲线,因此非常棘手。在我的特殊情况下,它不会被暂停或任何其他因素,以免考虑。

(简体)基本上我可以在这样的修饰符上触发动画:

function scaleModifierTo(stateModifier, scale, animationDuration) {
  stateModifier.setTransform(
    Transform.scale(scale, scale, scale),
    {
      duration: animationDuration,
      curve: this.options.curve   
    }
  );
}

当Transitionable的插值状态达到0.5(中途)时,我想触发一个功能。

我还没有深入挖掘famo.us的来源,但可能需要做类似的事情

  • 继承了某些东西并添加了在状态通过某一点时监听的可能性?
  • 反转定义的曲线并使用setTimeout(或尝试使用所选曲线算法(ew)的几次迭代找到接近度)

是否可以轻松完成此操作?我应该走哪条路?

2 个答案:

答案 0 :(得分:2)

我可以想到几种方法来实现这一点,并且都可以使用Modifier over StateModifier。如果你是新手,并且还没有机会探索差异,Modifier会从transformFrom方法中消耗状态,该方法接受一个返回变换的函数。这是我们可以使用我们自己的Transitionable在我们的修饰符的生命周期内提供状态。

为了达到你想要的效果,我使用了一个带有基本transformFrom的Modifier,它将根据Transitionable的值改变曲面的X位置。然后,我可以监视可转换的以确定它何时最接近,或者在我的情况下大于或等于最终值的一半。 prerender函数将在引擎的每个tick上被调用和检查,并且在我们击中目标时被解除绑定。

这是一个例子..

var Engine              = require('famous/core/Engine');
var Surface             = require('famous/core/Surface');
var Modifier            = require('famous/core/Modifier');
var Transform           = require('famous/core/Transform');

var Transitionable      = require('famous/transitions/Transitionable');
var SnapTransition      = require('famous/transitions/SnapTransition');

Transitionable.registerMethod('snap',SnapTransition);

var snap = { method:'snap', period:1000, damping:0.6};

var context = Engine.createContext();

var surface = new Surface({
    size:[200,200],
    properties:{
        backgroundColor:'green'
    }
});

surface.trans = new Transitionable(0);

surface.mod = new Modifier();

surface.mod.transformFrom(function(){
    return Transform.translate(surface.trans.get(),0,0);
});

context.add(surface.mod).add(surface);

function triggerTransform(newValue, transition) {

    var prerender = function(){

        var pos = surface.trans.get();

        if (pos >= (newValue / 2.0)) {

            // Do Something.. Emit event etc..
            console.log("Hello at position: "+pos);

            Engine.removeListener('prerender',prerender);
        }
    }

    Engine.on('prerender',prerender);

    surface.trans.halt();
    surface.trans.set(newValue,transition);
}

surface.on('click',function(){ triggerTransform(400, snap); });

此示例的缺点是您要查询可转换的两次。另一种方法是在transformFrom方法中添加可转换检查权限。这可能有点奇怪,但基本上我们正在修改transformFrom方法,直到我们达到目标值,然后我们恢复到原来的transformFrom方法.. triggerTransform将定义如下..

希望这有帮助!

function triggerTransform(newValue, transition) {
    surface.mod.transformFrom(function(){
        pos = surface.trans.get()
        if (pos >= newValue/2.0) {

            // Do something
            console.log("Hello from position: " + pos)

            surface.mod.transformFrom(function(){
                return Transform.translate(surface.trans.get(),0,0);
            });
        }
        return Transform.translate(pos,0,0)
    })

    surface.trans.set(newValue,transition);

}

答案 1 :(得分:0)

感谢您的回复,尤其是prerender事件的@johntraver,我不知道该事件是否存在。

我意识到我应该与我的移动动画一起处理这个逻辑更有意义,而不是规模之一。然后,我最终使用(非常hacky)方式访问转换的当前状态,并通过在px中定义阈值,我可以在需要时触发我的函数。

/**
 * Move view at index to a specified offset
 * @param  {Number} index
 * @param  {Number} xOffset   xOffset to move to
 * @param  {Object} animation Animation properties
 * @return void
 */
function moveView(index, xOffset, animation) {
  var rectModifier = this._views[index].modifiers.rect;
  var baseXOffset = rectModifier._transformState.translate.state[0];

  // After how long movement is reflow needed?
  // for the sake of this example I use half the distance of the animation
  var moveThreshold = Math.abs(baseXOffset - xOffset)/2;

  /**
   * Callback function triggered on each animation frame to see if the view is now covering
   * the opposite so we can trigger a reflow of the z index
   * @return void
   */
  var prerender = function() {
    var numPixelsMoved = Math.abs(baseXOffset - rectModifier._transformState.translate.state[0]);

    if (numPixelsMoved > moveThreshold) {
      Engine.removeListener('prerender', prerender);
      // trigger a method when this is reached
      _reflowZIndex.call(this);
    }
  }.bind(this);

  rectModifier.setTransform(
    Transform.translate(xOffset, 0, 0),
    animation,
    function() {
      Engine.removeListener('prerender', prerender);
    }
  );

  Engine.on('prerender', prerender);
}

显然._transformState.translate.state[0]是一个完整的黑客攻击,但是如果不添加我自己的Transitionable,我就无法想象得到这个值。 如果有更简洁的方法可以在Number - 0.0之间找到当前状态1.0,那将是王牌;有人知道吗?