2016-05-13 53 views
2

我已经开始通过O'Reilly书“HTML5帆布”工作。我在第二章,其中一个例子提供了一些没有很好解释的代码。实施例2-5:帆布剪辑区域和帆布堆栈

  1. 画出一个黑箱
  2. 推状态
  3. 设置在顶小剪辑区域左
  4. 拉伸圆
  5. 弹出状态
  6. 设定得较大剪切区域
  7. 画另一个圆圈

但我无法理解一些事情:

context.fillStyle = 'black'; 
context.fillRect(10, 10, 200, 200); 

context.save(); 

context.beginPath(); 
context.rect(0, 0, 50, 50); 
context.clip(); 

context.beginPath(); 
context.strokeStyle = 'red'; 
context.lineWidth = 5; 
context.arc(100, 100, 100, 0, 2*Math.PI, false); 
context.stroke(); 
context.closePath(); 

context.restore(); 

context.beginPath(); 
context.rect(0, 0, 500, 500); 
context.clip(); 

context.beginPath(); 
context.strokeStyle = 'blue'; 
context.lineWidth = 5; 
context.arc(100, 100, 50, 0, 2*Math.PI, false); 
context.stroke(); 
context.closePath(); 

我的问题:

首先,不context.clip()隐含关闭上下文路径( “context.closePath()”)?它前面有一个context.beginPath(),后面跟着另一个context.beginPath()。像这样:

context.beginPath(); 
context.rect(0, 0, 50, 50); 
context.clip(); 
context.beginPath(); 

其次,为什么需要推送上下文状态?为什么我不能修改剪辑区域?这似乎是必要的,因为它没有推动国家就无法运作。如果我不推动状态然后恢复它,那么蓝色的大圈就不会出现,我不明白为什么。

+1

beginPath开始一个全新的路径并转储旧的路径。 closePath与beginPath无关。 ClosePath只需创建一个从当前位置到最后一个moveTo位置的lineTo您可以根据需要设置尽可能多的closePath,每个渲染输出(stroke(),fill())只能有一个beginPath。剪辑是累积性的,每次添加一个剪辑时,剪辑会被上一个剪辑剪辑,每个剪辑区域变得越来越小。要恢复您必须使用保存和恢复。 – Blindman67

回答

3

是否context.clip()隐含关闭上下文路径?...
它由context.beginPath(前面),并紧接着又context.beginPath()。就像这样:[...]

是的,这只是创造),这是需要剪裁,所以如果一个closePath()不叫夹(近似的形状将在内部封闭道路的方式。

specification states:

打开子路径必须计算剪切区域时,会自动关闭,不会影响实际的子路径。

beginPath()将清除当前主路径及其所有子路径。剪辑仍然处于活动状态,但现在您可以执行其他路径操作,这些操作在光栅化时将受到剪辑区域的影响。

为什么需要推送上下文状态?

没有办法,虽然它已建议,并讨论了重新剪辑区(有标准一resetClip()但尚未得到广泛的支持)。Calling clip()几次 -

夹子()方法必须通过计算当前剪辑区域的交叉点创建一个新的剪辑区域[...]

换句话说,它不会如果我们说为整个绘图表面定义了一个剪辑区域,则将其替换。

所以我们可以删除剪辑的唯一方法是保存状态,设置剪辑然后恢复删除它。

+1

好解释!只适用于适用于这些边缘案例的小插件:剪裁在调整canvas元素大小时也会被清除。这是因为调整canvas元素的大小时会重置所有上下文状态。 – markE