【问题标题】:Preferred way to Animate a Famo.us CanvasSurface为 Famo.us CanvasSurface 设置动画的首选方式
【发布时间】:2014-06-30 04:46:46
【问题描述】:

我一直在搜索 famo.us 的(仍然很少)讨论和文档,寻找我希望的显而易见的东西:在 CanvasSurface 中为画布设置动画。我真的很惊讶我没有找到一个例子。

我已经取得了一些进展,所以我希望这篇文章能帮助人们踏上阶梯。

这是我的基本代码(以前使用window.requestAnimationFrame,但现在调整为扩展内置的渲染方法),目前可以工作,但我很困惑。

我的问题跟在代码后面:

define(function (require) {
    "use strict";
    var Engine = require('famous/core/Engine'),
        View = require('famous/core/View'),
        CanvasSurface = require('famous/surfaces/CanvasSurface'),
        context = Engine.createContext(),
        //
        VividCanvas = function () {
            var v = new View(),
                cw = 320,
                ch = 240,
                c = 0,
                surface = new CanvasSurface({size: [cw, ch]}),
                ctxt = surface.getContext('2d'),
                //
                redraw = function () {
                    ctxt = surface.getContext('2d'); // WHY IS THIS LINE NECESSARY?
                    c += 1;
                    c = c % 360;
                    ctxt.fillStyle = "hsl(" + c + ", 100%" + ", 50%)";
                    ctxt.fillRect(0, 0, cw, ch);
                    window.requestAnimationFrame(redraw);
                    return surface.id; // i.e. a valid renderSpec
                };
            surface.render = redraw;
            v.add(surface);
            return v;
        };
    //
    context.add(new VividCanvas());
});

让我困惑的是ctxt = surface.getContext('2d')这行(重绘函数的第一行)是必须的。我会认为 ctxt 已经定义并在范围内(请参阅重绘函数声明之前的内容)。

确实,如果您记录 ctxt,您将在这两种情况下获得 2d Canvas Context。但是由于某种原因,在重绘函数中创建的画布上下文与第一次重绘之前创建的实例不同。

这可以通过插入console.log(ctxt === surface.getContext('2d')) 作为重绘函数的第一行来证明(在重新定义 ctxt 之前)。它记录为假。我不懂为什么。谁能解释一下?

如果觉得 ctxt 应该始终指向正确的东西,并且不应该需要调整,那么第二次调用 getContext 应该是不必要的。但是,如果我省略它,画布只会绘制一次。

那是为什么呢?

最初,我有第二个问题,但可能相关的问题是关于 requestAnimationFrame。在 cmets 中,我可以将其替换为 surface.render = redraw 行,并确保我的重绘方法返回表面 id,从而允许 Famo.us 处理动画同步。感谢 Andrew 在 cmets 中提出的建议。

【问题讨论】:

  • 我将不得不回到这个,但对于初学者来说,我不知道 requestAnimationFrame 是否是正确的方法.. Famo.us 允许您使用 Engine.on('prerender' ,fn) 这似乎是不断更新画布的可靠候选者..
  • 从 CanvasSurface 继承,然后实现 render 方法,您可以在其中执行所有更新工作。
  • 按照 Andrew 的建议,我现在添加了一个渲染方法。棘手的部分是让它返回一个有意义的 renderSpec,但一个有意义的 renderSpec 只是表面的 id。但是,我仍然有一个奇怪的问题,即必须在重绘之前和之后都调用 getContext 未解决。有接受者吗?

标签: canvas famo.us


【解决方案1】:

查看 CanvasSurface 的代码时,似乎使用了两个上下文。可能是您用来渲染的一个,而另一个则显示。当下一个 AnimationFrame 开始时,它会翻转上下文。

/**
 * Returns the canvas element's context
 *
 * @method getContext
 * @param {string} contextId context identifier
 */
CanvasSurface.prototype.getContext = function getContext(contextId) {
    this._contextId = contextId;
    return this._currTarget ? this._currTarget.getContext(contextId) : this._backBuffer.getContext(contextId);
};

【讨论】:

    【解决方案2】:

    我在着名的 lagometer 项目中做了 Canvas 动画: https://github.com/IjzerenHein/famous-lagometer

    基本上我在 View.render() 中进行画布渲染。 将大小乘以 2 是为了使其在视网膜显示器上更加粗糙。

    /**
     * Renders the view.
     */
    MyView.prototype.render = function render() {
        var context = this.canvas.getContext('2d');
        var size = this.getSize();
        var canvasSize = [size[0] * 2, size[1] * 2];
        this.canvas.setSize(size, canvasSize);
    
        // Do canvas drawing here...
        context.clearRect(0, 0, canvasSize[0], canvasSize[1]);
        context.fillStyle = this.options.backgroundColor;
        context.fillRect(0, 0, canvasSize[0], canvasSize[1]);
        context.lineWidth = 1;
        context.strokeStyle = this.options.borderColor;
        context.strokeRect(0, 0, canvasSize[0], canvasSize[1]);
        ...
    
        // Call super
        return this._node.render();
    };
    

    【讨论】:

    • 原型方法的有用示例,谢谢。 (我更喜欢避免原型,而是使用模块模式,如我上面的示例所示)。但是我的问题的重点仍然没有解决。我注意到您每次调用 render 时也会调用 getContext 。我仍然很好奇为什么这是必要的,为什么我们不能只调用一次,在初始化视图时存储返回值并在 render() 中使用存储的值。
    • 很抱歉,我在发帖前没有阅读您的整个问题。在将实际的 HTML 元素添加到 DOM 之前,我希望 getContext() 不起作用。这应该在下一个渲染周期之后。我想我知道答案,它与使用后台缓冲区的 CanvasSurface 有关。我会把它作为一个新问题发布。干杯
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-16
    • 1970-01-01
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多