保存多个状态并还原到每个状态

时间:2015-08-12 18:17:56

标签: javascript html5 canvas

HTML5 <canvas>元素有一种保存状态机制,通过反复调用cxt.save()cxt.restore(),其中cxt<canvas>的“上下文” “,例如,打电话给document.getElementById('my-canvas')。但是,我还没有看到过一次保存/恢复到多个状态的方法。似乎<canvas>可以访问多个状态,因为多次调用restore会恢复每个“最后”保存的状态。

有没有办法在没有多次调用restore的情况下跳回到“最后”状态之前?还有,有没有办法通过各州“前进”?如果我们可以给每个州一个名字,这可能会更容易做,但如果我需要,我可以使用ID。最后它可能看起来类似于Adobe Photoshop的“图层”概念。

我还会得到一个答案,将每个州保存到另一个变量,或者可以复制上下文而不创建全新的<canvas>。复制函数如angular.copy似乎不适用于上下文,可能是因为它们不是技术上的对象;我相信他们继承了接口。

最后,这有效吗?我知道图形密集型<canvas>是如何,它在客户端的计算机上是多么重要。是否有更好的方法来操纵上下文而不破坏画布的其他部分而不是实现分层系统?

1 个答案:

答案 0 :(得分:4)

某些背景:

context.savecontext.restore保存并恢复上下文状态。上下文状态包括样式,转换,合成等。

.save会将当前状态推送到堆栈顶部。 .restore将从堆栈顶部弹出最后添加的状态。因此,他们充当了先进先出的状态。

你可以做多个.save,它会将多个状态推送到堆栈上。然后,您可以通过执行多个.restore来从堆栈中弹出多个状态。

由于.save将保存所有上下文状态,因此保存&amp;恢复是相对昂贵的操作。

多次保存/恢复的示例:

context.fillStyle='red';
context.fillRect(0,0,10,10);    // red rectangle
context.save();                 // fillStyle=='red'
context.fillStyle='blue';       // fillStyle='blue'
context.fillRect(0,0,10,10);    // blue rectangle
context.save();                 // fillStyle=='blue'
context.fillStyle='green';      // fillStyle=='green'
context.fillRect(0,0,10,10);    // green rectangle
context.restore();              // fillStyle='blue';
context.fillRect(0,0,10,10);    // blue rectangle
context.restore();              // fillStyle='red'
context.fillRect(0,0,10,10);    // red rectangle

回答#1:不,如果不执行多次恢复,则无法回退到之前保存的状态。状态保存在堆栈中,因此与状态数组不同,您无法“跳转”到状态[2]。

回答#2:实际上,不使用保存/恢复更常见,而是使用javascript对象来存储最少状态信息

例如:

// put various fillStyles in a fills object
var fills={};
fills.red='red';
fills.green='green';
fills.blue='blue';

// create a function that draws a rect with specified fillStyle
function styledRect(x,y,w,h,fill){
    var priorFill=context.fillStyle;
    context.fillStyle=fill;
    context.fillRect(x,y,w,h);
    context.fillStyle=priorFill;
}

// use the fills object to control the fillStyle "state"
styledRect(0,0,10,10,fills.red);

更复杂的“州”对象可能如下所示:

buttonStyles={};
buttonStyles.normal={ font:'12px verdana', fill:'black' };
buttonStyles.warning={font:'12px italic verdana', fill:'orange' };
buttonStyles.danger={ font:'14px italic verdana', fill:'red' };

// example usage
someButtonDrawingFunction("You're in danger!",buttonStyles.danger);