[TOC]
## 状态
Canvas 是基于 “状态” 来绘制图形的。每一次绘制(stroke() 或者 fill()),Canvas 都会检测整个程序定义的所有状态,一个绘画的状态包括:
* 当前应用的变形(即移动,旋转和缩放)
* `strokeStyle`,`fillStyle`,`globalAlpha`,`lineWidth`,`lineCap`,`lineJoin`,`miterLimit`,`shadowOffsetX`,`shadowOffsetY`,`shadowBlur`,`shadowColor`,`globalCompositeOperation` 的值
* 当前的裁切路径(`clipping path`)
Canvas 提供了两个操作状态的方法:save() 和 restore()
我们可以认为 Canvas 的状态存储在一个栈中,每当 save() 方法被调用,当前状态就被推入状态栈中,可以调用任意多次 save() 方法。而 restore() 方法就相当于弹出状态栈的栈顶状态并恢复到这个状态。
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas</title>
</head>
<body>
<canvas id="canvas" width="500" height="200" style="border: 1px solid gray; display: block; margin: 0 auto"></canvas>
<script>
window.onload = function(){
let cnv = document.getElementById('canvas')
let cxt = cnv.getContext('2d')
// cxt.save()
cxt.fillStyle = 'HotPink'
cxt.translate(30, 30)
cxt.fillRect(0, 0, 100, 50)
// cxt.restore()
cxt.fillStyle = 'LightSkyBlue'
cxt.translate(60, 60)
cxt.fillRect(0, 0, 100, 50)
}
</script>
</body>
</html>
```
![](https://img.kancloud.cn/fa/f4/faf410b99607a403f24c53f4a7e899d1_681x276.png)
上面这个例子中,如果我们想让第二次 translate() 相对于最初的坐标原点进行移动,就可以利用 save() 和 restore() 方法来实现。
![](https://img.kancloud.cn/e2/94/e2947aa06103376a5e40f69dc97c2c10_671x271.png)
## 路径
Canvas 提供了三种操作路径的方法
| 方法 | 说明 |
| --- | --- |
| beginPath() | 开始一条新的路径 |
| closePath() | 关闭当前路径 |
| isPointPath() | 判断某一个点是否存在于当前路径 |
案例:
```js
// 开始路径
context.beginPath();
context.strokeStyle = 'blue';
context.moveTo(60, 20);
context.lineTo(220, 20);
context.stroke();
// 开始路径 again
context.beginPath();
context.strokeStyle = 'green';
context.moveTo(60, 20);
context.lineTo(160, 120);
context.stroke();
```
![](https://img.kancloud.cn/4e/78/4e7801c53e89b749db74337db33bc592_403x204.png =300x)
再看下面的代码:
```js
// 开始路径
context.beginPath();
context.strokeStyle = 'blue';
context.moveTo(60, 20);
context.lineTo(220, 20);
context.stroke();
context.strokeStyle = 'green';
context.moveTo(60, 20);
context.lineTo(160, 120);
context.stroke();
```
![](https://img.kancloud.cn/91/72/9172c1bea7e5add38cde40636d989912_394x204.png =300x)
之前提到过,Canvas 是基于状态来绘制图形的,那么当一个状态值没有被改变时,Canvas 就一直使用最初的值,而当一个状态值被改变时,就要分两种情况考虑:
(1) 如果使用 beginPath() 开始一个新的路径,则不同路径使用不同的值,即绘制结果不影响之前的路径。
(2) 如果没有使用 beginPath() 开始一个新的路径,则后面的值会覆盖前面的值。
比如上面的第二张图两条直线属于同一路径,用新的状态来绘制时自然就会影响这两条直线了。
### closePath()
closePath() 方法的作用是连接起点与终点,使其成为一个封闭的图形,即 “关闭路径”。需要注意的是 “关闭路径” 并不等同于 “结束路径”,即其并没有起到新调用一次 beginPath() 的作用。
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas</title>
</head>
<body>
<canvas id="canvas" width="500" height="300" style="border: 1px solid gray; display: block; margin: 0 auto"></canvas>
<script>
window.onload = function(){
let cnv = document.getElementById('canvas')
let cxt = cnv.getContext('2d')
cxt.beginPath()
cxt.strokeStyle = 'red'
cxt.arc(70, 70, 50, 0, -90 * Math.PI / 180, true)
cxt.closePath()
cxt.stroke()
// cxt.beginPath()
cxt.strokeStyle = 'blue'
cxt.arc(70, 120, 50, 0, -90 * Math.PI / 180, true)
cxt.closePath()
cxt.stroke()
}
</script>
</body>
</html>
```
![](https://img.kancloud.cn/e6/91/e691049a07ce4b12dfa618494cd3924b_654x395.png =300x)
添加了 beginPath() 后才能达到预期的效果。
![](https://img.kancloud.cn/4c/d2/4cd2dca2ed0567e5f67a0653e3b01bec_653x395.png =300x)
### isPointPath() 方法
```js
cxt.isPointInPath(x, y)
```
该方法用于判断点(x,y)是否位于当前路径中,如果存在则返回 true,否则返回 false。