2014-06-19 4 views
1

Я изучал (все еще скудные) обсуждения и документацию famo.us, ища то, что я надеялся, было бы очевидной: анимируйте холст в CanvasSurface. Я действительно удивлен, что не нашел ни одного примера.Предпочтительный способ оживить 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. Из комментариев я смог заменить это на строку surface.render = redraw и убедиться, что мой метод перерисовки возвращает идентификатор поверхности, что позволяет Famo.us обрабатывать синхронизацию анимации. Спасибо Андрею за его предложение в комментариях.

+1

мне придется вернуться к этому, но для начала, я не знаю, если requestAnimationFrame правильный подход .. Famo.us позволяет использовать Engine.on («пререндер», п), который кажется уверенным кандидатом на постоянное обновление холста. – johntraver

+1

Наследовать от CanvasSurface, а затем реализовать метод «render», где вы выполняете всю работу по обновлению. –

+0

Теперь я добавил метод рендеринга, согласно предложению Андрея. Сложная часть заключалась в том, что он возвращал значимый renderSpec, но значимый renderSpec - это только идентификатор поверхности. У меня все еще есть странный вопрос о необходимости вызова getContext как до, так и после нереализованного перерисовывания. Любые берущие? – brennanyoung

ответ

2

При взгляде на код 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); 
}; 
1

Я сделал Canvas анимации в знаменитом-lagometer проекта: https://github.com/IjzerenHein/famous-lagometer

В основном я холст рендеринга в view.render(). Умножение на два размера, чтобы сделать его дополнительным падением на сетчатых дисплеях.

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

Полезный пример для прототипа, спасибо. (Я предпочитаю избегать прототипа и вместо этого использовать шаблон модуля, как показано в моем примере выше). Но главный вопрос моего вопроса до сих пор не решен. Я замечаю, что вы также вызываете getContext каждый раз, когда вызывается render. Мне все еще интересно, почему это необходимо, и почему мы не можем просто вызвать его один раз, сохранить возвращаемое значение при инициализации представления и использовать сохраненное значение в render(). – brennanyoung

+1

Прошу прощения, я не прочитал весь ваш вопрос перед публикацией. Я бы ожидал, что getContext() не будет работать до тех пор, пока фактический HTML-элемент не будет добавлен в DOM. Это должно быть после следующего цикла рендеринга. Я думаю, что знаю ответ, он связан с CanvasSurface с использованием обратного буфера. Я отправлю его как новый вопрос. ура – IjzerenHein

Смежные вопросы