Tecnologia

HTML5 Canvas: Empilhamento de estados

Por: , janeiro 20, 2014

Introdução

Este post é o primeiro de uma série sobre HTML5 Canvas. Neste artigo explicarei como funcionam os métodos context.save() e context.restore().
Estes métodos são responsáveis para salvar e restaurar o estado do contexto de renderização. Mas o que significa isto?

This post is also available in english.

O que é um estado em Canvas?

Primeiro, é necessário saber o que é um estado. A resposta simplificada é: Tudo que não é desenhado!
A API do Canvas providencia um conjunto de métodos que podem ser distinguidos entre métodos que pintam no quadro (o Canvas) e métodos auxiliares. Uma grande parte dos métodos auxiliares são usados para definir a aparência de itens pintados.
Métodos como strokeStyle, fillStyle, globalAlpha, lineWidth, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, font, textAlign, textBaseline, etc. modificam o estado do contexto. Tambem considerado como um estado é a matrix de transformação que pode ser alterado usando os métodos translate, rotate, scale e setTransform. Uma outra forma de estado é a região de corte (Clipping region) modificado via clip. Todos os objetos modificados por estes métodos fazem parte do estado do contexto que pode ser empilhado.

O que posso fazer com este empilhamento?

Como podemos perceber, é fácil restaurar um estado apenas retirando da pilha, porque as vezes pode ser trabalhoso definir um estado. Assim o código fica mais limpo. Usando a pilha até pode melhorar a performance como é demonstrado no JsPerf. Uma outra vantagem importante é o isolamento das operações dependentes de estado. No próximo parágrafo explicarei este conceito mais detalhado.

Isolamento das operações dependentes de estado

Com o empilhamento de estados se pode isolar e/ou agrupar operações muito simples. Imagine um carro se movendo. Você pode separar a rotação das rodas e a translação do carro usando a técnica de empilhamento. Para isso, basta salvar a “matrix de translação” (movimento linear do automóvel) antes de rotacionar as rodas. Após a aplicacação da rotação você simplesmente restaura a “matrix de translação” e avança para o próximo frame. O exemplo em seguida demonstra esta técnica. Primeiro segue o resultado visual.

E agora segue o código:
[code language=”javascript”]
function main(){
var context = document.getElementById(‘myCanvas’).getContext(‘2d’);
var painter = new Painter(context);
painter.setFillColor(255,0,0,1);
painter.drawText(“Text 1”, 50);
painter.pushState();
painter.rotate(320, 100, 45);
painter.setFillColor(0,0,255,1);
painter.drawText(“Text 2”, 100);
painter.popState();
painter.drawText(“Text 3”, 150);
}
function Painter(ctx){
var context = ctx;
var DEG2RAD = Math.PI/180.0;
var center = {};
var init = function(ctx){
context = ctx;
center[0] = context.canvas.width/2;
center[1] = context.canvas.height/2;
};
this.pushState = function(){
context.save();
};
this.popState = function(){
context.restore();
};
this.rotate = function(posX, posY, angle){
context.translate(posX, posY);
context.rotate(angle * DEG2RAD);
context.translate(-posX, -posY);
};
this.setFillColor = function(r,g,b,a){
context.fillStyle = “rgba(” + r + “,” + g + “,” + b + “,” + a +”)”;
};
this.drawText = function(text, ypos){
context.font = “30px Arial”;
context.textAlign = “center”;
context.fillText(text, center[0], ypos);
};
init(ctx);
}
[/code]

  • Receba nosso conteúdo em primeira mão.