Canvas 制作美国著名画布表面动画的首选方法

Canvas 制作美国著名画布表面动画的首选方法,canvas,famo.us,Canvas,Famo.us,我一直在浏览famo.us的讨论和文档(仍然很少),寻找我希望是显而易见的东西:在画布表面制作画布动画。我真的很惊讶,我没有发现一个例子 我已经取得了一些进步,所以我希望这篇文章能帮助一些人踏上人生的阶梯 这是我的基本代码(以前使用的是window.requestAnimationFrame,但现在进行了调整以扩展内置的渲染方法),它目前可以工作,但我感到困惑 我的问题如下: define(function (require) { "use strict"; var Engine

我一直在浏览famo.us的讨论和文档(仍然很少),寻找我希望是显而易见的东西:在画布表面制作画布动画。我真的很惊讶,我没有发现一个例子

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

这是我的基本代码(以前使用的是
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')
(redraw函数中的第一行)是必需的。我本以为ctxt已经定义并在范围内了(请参见声明redraw函数之前的内容)

事实上,如果您记录ctxt,在这两种情况下都会得到一个2dcanvas上下文。但由于某些原因,在重画函数中生成的画布上下文与第一次重画之前生成的画布上下文是不同的实例

这可以通过插入
console.log(ctxt==surface.getContext('2d'))
作为重画函数的第一行来演示(在重新定义ctxt之前)。它是假的。我不明白为什么。有人能解释一下吗

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

那为什么呢


最初,我还有第二个问题,但可能相关的问题是关于requestAnimationFrame的。从注释中,我可以将其替换为行
surface.render=redraw
,并确保我的redraw方法返回曲面id,从而允许Famo.us处理动画同步。感谢安德鲁在评论中的建议。

我在著名的lagometer项目中制作了画布动画:

基本上我在View.render()中进行画布渲染。 乘以两倍的大小,是为了在视网膜上显示额外的crips

/**
 * 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();
};

当查看CanvasSurface的代码时,它似乎使用了两种上下文。可能是一个用于渲染的对象,而另一个对象正在显示。当下一个动画帧开始时,它会翻转上下文

/**
 * 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);
};

我必须回到这一点,但对于初学者来说,我不知道requestAnimationFrame是否是正确的方法。。Famo.us允许您使用Engine.on('prerender',fn),这似乎是连续更新画布的可靠候选。从画布表面继承,然后实现
render
方法,在其中执行所有更新工作。根据Andrew的建议,我现在添加了一个渲染方法。棘手的部分是让它返回有意义的renderSpec,但有意义的renderSpec只是曲面的id。然而,我仍然有一个奇怪的问题,那就是在重画之前和之后都必须调用getContext。有人吗?原型方法的有用示例,谢谢。(我更喜欢避免原型,而是使用模块模式,如上面的示例所示)。但我问题的要点仍然没有解决。我注意到,每次调用render时,您也会调用getContext。我仍然很好奇为什么这是必要的,为什么我们不能只调用它一次,在初始化视图时存储返回的值,并在render()中使用存储的值。很抱歉,在发布之前我没有阅读您的整个问题。在将实际的HTML元素添加到DOM之前,我希望getContext()不起作用。这应该在下一个渲染周期之后。我想我知道答案,这与使用后缓冲的画布表面有关。我将把它作为一个新问题发布。干杯