如果出现错误,确保平衡的画布保存/恢复

时间:2015-06-03 13:59:50

标签: javascript html5 html5-canvas

在HTML5 / ECMAScript / JavaScript中进行图形处理时,一个非常常见的模式是执行context.save(),应用坐标转换,然后执行context.restore()。不幸的是,即使绘制上下文被丢弃并重新创建,HTML5的设计似乎仍然会像转换一样继续作为画布的一部分。如果在转换坐标时发生错误,绘图上下文将处于混乱状态"永远"。

如果使用保存/恢复的每一段代码都被try块保护,它可以确保在退出时恢复上下文。但是,如果使用save的任何代码抛出异常而不恢复上下文,那么将导致调用上下文的任何恢复操作恢复不正确的状态。

有没有干净的做法,如:

var savedContext = contextCapturer.capture(context);
try
{
   ... code that might call a save without restore
}
finally
{      
  savedContext.restore();
}

我认为有可能让一个上下文保护对象修改上下文的保存/恢复方法,这样他们就可以保留一个可以用来确保事物平衡的计数,但我不确定如何编写这样的代码,以便即使它调用,或被其他同样的代码调用,也能正常工作。 restore执行后,保存的上下文不一定可用;什么是必要的,如果"尝试"阻止执行例如五次保存和三次恢复,savedContext.restore()操作必须在上下文中执行两次额外的恢复,以弥补不平衡。

为了澄清,我在这里考虑像showFramed方法这样的事情;给定一个期望在inRect定义的范围内绘制的过程,它会转换坐标和剪辑,使其出现在outRect定义的范围内(在这种情况下也会绘制一个黄色边框)。



function showFramed(ctx, inRect, outRect, bColor, bWidth, proc)
{
  ctx.save();
  ctx.strokeStyle=bColor;
  ctx.lineWidth=bWidth;
  ctx.beginPath();
  ctx.rect(outRect[0],outRect[1],outRect[2],outRect[3]);
  ctx.stroke();
  ctx.restore();
  
  ctx.save();
  ctx.clip();
  ctx.translate(outRect[0],outRect[1]);
  ctx.scale(outRect[2]/inRect[2], outRect[3]/inRect[3]);
  ctx.translate(-inRect[0],-inRect[1]);
  proc();
  ctx.restore();
}

function showScreen(ctx)
{
  var i;
  ctx.beginPath();
  for (i=0; i<=160; i+=10)
    {
      ctx.moveTo(i,0);
      ctx.lineTo(0,160-i);
      ctx.lineTo(i/2+80,i/2+80);
      ctx.lineTo(160-i,160);
    }
  ctx.stroke();
}

function showScreen2(ctx)
{
  showScreen(ctx);
  ctx.save();
  ctx.strokeStyle="#007F00";
  showFramed(ctx, [0,0,160,160], [20,90,60,60], "#FFFF00", 3,
            function() {showScreen(ctx); });
  ctx.strokeStyle="#7F0000";
  showFramed(ctx, [0,40,80,80], [90,90,60,60], "#FFFF00", 3,
            function() {showScreen(ctx); });
  ctx.restore();  
}


function demo1()
{
  var c=document.getElementById("canv");
  var ctx=c.getContext("2d");
  ctx.strokeStyle="#0000FF";
  showScreen2(ctx);
}

function demo2()
{
  var c=document.getElementById("canv");
  var ctx=c.getContext("2d");

  ctx.strokeStyle="#00FF00";
  showFramed(ctx, [0,0,160,160], [80,10,60,60], "#FFFF00", 3,
            function() {showScreen2(ctx); });
}
&#13;
<canvas id="canv" Width=160 height=160></canvas>
<button onClick="demo1()">Demo1</button>
<button onClick="demo2()">Demo2</button>
&#13;
&#13;
&#13;

drawFramed方法不知道在输入时适用哪种转换。如果从传入的过程中抛出异常,则不应该吞下它,但我建议showFramed应该将上下文恢复到输入之前的状态;不应该吗?

0 个答案:

没有答案