Commit 05c5139f authored by 熊东起's avatar 熊东起

22

parent e298b2c1
## 为什么学习canvas # 一、canvas基础知识
### 优点 ### 优点
1. 相比较于dom渲染,canvas更快速,在复杂的图形处理上更胜一筹。 1. 相比较于dom渲染,canvas更快速,在复杂的图形处理上更胜一筹。
...@@ -12,9 +12,7 @@ ...@@ -12,9 +12,7 @@
3. 开发略麻烦,相比较一个html一个页面,canvas显得笨。 3. 开发略麻烦,相比较一个html一个页面,canvas显得笨。
## canvas第一步 ## canvas标签
### 一、`<canvas></canvas>`标签
#### `width`和`height`属性 #### `width`和`height`属性
canvas唯二的两个属性。<br/> canvas唯二的两个属性。<br/>
...@@ -62,10 +60,11 @@ canvas.width = document.documentElement.clientWidth; ...@@ -62,10 +60,11 @@ canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight; canvas.height = document.documentElement.clientHeight;
``` ```
#### `getContext()` 渲染上下文 ## 渲染上下文
`getContext()` 渲染上下文
用来获取canvas上的渲染上下文和绘画功能。<br/> 用来获取canvas上的渲染上下文和绘画功能。<br/>
什么叫【渲染上下文】---- emm 知道名字就好了 什么叫【渲染上下文】<br/>
---- emm 知道名字就好了
``` ```
var canvas = document.getElementById('canvas'); var canvas = document.getElementById('canvas');
...@@ -99,13 +98,13 @@ canvas.height = document.documentElement.clientHeight; ...@@ -99,13 +98,13 @@ canvas.height = document.documentElement.clientHeight;
`2d``webgl`做了解即可. `2d``webgl`做了解即可.
#### canvas坐标系统 ## 坐标系统
canvas坐标系与web的一致。X轴向右为正,Y轴向下为正。与`left``top`异曲同工。<br/> canvas坐标系与web的一致。X轴向右为正,Y轴向下为正。与`left``top`异曲同工。<br/>
![canvas坐标系](https://yun.duiba.com.cn/spark/assets/6ad27b8ba5404a16997d464ef5341de15eb7f188.png "canvas坐标系") ![canvas坐标系](https://yun.duiba.com.cn/spark/assets/6ad27b8ba5404a16997d464ef5341de15eb7f188.png "canvas坐标系")
##### 坐标变换 ### 坐标变换
* 平移 * 平移
* 缩放 * 缩放
* 旋转 * 旋转
...@@ -115,7 +114,8 @@ canvas坐标系与web的一致。X轴向右为正,Y轴向下为正。与`left` ...@@ -115,7 +114,8 @@ canvas坐标系与web的一致。X轴向右为正,Y轴向下为正。与`left`
鼠标、手指获得坐标是窗口坐标,而canvas中的位置需要相对于canvas,所以需要进行转换。 鼠标、手指获得坐标是窗口坐标,而canvas中的位置需要相对于canvas,所以需要进行转换。
::: :::
#### toBlob() 将canvas图像转化为可保存的图片文件 ## 图片转化
### toBlob() 将canvas图像转化为可保存的图片文件
`canvas.toBlob(callback, type, encoderOptions)` `canvas.toBlob(callback, type, encoderOptions)`
* callback 回调 * callback 回调
...@@ -162,7 +162,7 @@ if (!HTMLCanvasElement.prototype.toBlob) { ...@@ -162,7 +162,7 @@ if (!HTMLCanvasElement.prototype.toBlob) {
} }
``` ```
#### toDataURL() 返回一个图片的base64 URL ### toDataURL() 返回一个图片的base64 URL
`canvas.toDataURL(type, encoderOptions)` `canvas.toDataURL(type, encoderOptions)`
* type 图片格式 * type 图片格式
...@@ -182,3 +182,196 @@ document.body.appendChild(_img); ...@@ -182,3 +182,196 @@ document.body.appendChild(_img);
toDataURL()相较于toBlob()兼容性良好。一般用toDataURL()就可以了。<br/> toDataURL()相较于toBlob()兼容性良好。一般用toDataURL()就可以了。<br/>
toBlob()为异步。多一个callback回调。 toBlob()为异步。多一个callback回调。
::: :::
## 绘制图形
`canvas`只支持两种形式的图形绘制:`矩形``路径`<br/>
其他图形可以通过一条或者多条路径组合而成。
### 绘制矩形
* 绘制一个填充的矩形<br/>
`fillRect`
* 绘制一个矩形的边框<br/>
`strokeRect`
* 指定清除一个矩形区域<br/>
`clearRect`
```
var ctx = c.getContext("2d");
ctx.fillRect(10,10,100,100);
ctx.strokeRect(0,0,120,120);
ctx.clearRect(40,40,40,40);
```
## 绘制路径
图形的基本元素是路径。<br/>
路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的点的集合。<br/>
一个路径一定是闭合的。
::: tip 步骤
* 创建路径起点
* 使用画图命令画出路径
* 闭合路径
* 描边或者填充路径来渲染出形状
:::
| 属性 | 介绍 |
| :-- | :-- |
| beginPath() | 开始一个新的路径 |
| closePath() | 闭合一段路径 |
| moveTo(x,y) | 新路径的起始点 |
| lineTo(x,y) | 链接上一步的终点到下一步的x,y |
| rect(x, y, width, height) | 创建矩形路径 |
| arc(x, y, radius, startAngle, endAngle, anticlockwise) | 绘制圆弧路径,`anticlockwise` false 默认顺时针,`startAngle`起始弧度,`endAngle`结束弧度 |
| arcTo(x1, y1, x2, y2, radius) | 根据2个控制点和半径绘制圆弧路径 |
| quadraticCurveTo(cpx, cpy, x, y) | 起始点,控制点,终点,三点确定的一条二阶贝塞尔曲线,cpx,cpy为控制点,x,y为终点 |
| bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) | 起始点,2个控制点,终点,三点确定的一条三阶贝塞尔曲线 |
::: tip 注意点
* 绘图基本上`moveTo(x,y)`的x,y为起始点。
* `beginPath()`会清空子路径列表。
* `closePath()`会从当前点到起始点绘制一条直线。
* `lineTo()` 不会真正的绘制直线。
* `arcTo()`使用起始点和控制点1,控制点1和控制点2的连接直线作为圆弧的切线。
* `ellipse()`绘制椭圆的方法暂时有兼容~
* 当你调用`fill()`函数时,所有没有闭合的形状都会自动闭合,所以你不需要调用`closePath()`函数。
* 调用`stroke()`时不会自动闭合。
:::
**举一个🌰 -- 画一个人脸**
```
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(100, 100, 100, 0, Math.PI * 2, true);//逆时针
ctx.moveTo(180,135);
ctx.arc(100,100,80,Math.PI*1/6,Math.PI*5/6,false);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.moveTo(160,80);
ctx.arc(155,75,10,0,Math.PI*2,true);
ctx.fill();
ctx.beginPath();
ctx.moveTo(50,80);
ctx.arc(45,75,10,0,Math.PI*2,false);
ctx.moveTo(20,60);
ctx.quadraticCurveTo(45,50,90,80);
ctx.moveTo(110,80);
ctx.quadraticCurveTo(155,50,175,50);
ctx.moveTo(100,90);
ctx.lineTo(110,110);
ctx.lineTo(90,110);
ctx.stroke();
```
![画一个人脸](../../resources/canvas3.png ) 人脸如图所示。
::: tip 注意点
* `Path2D`对象也可以绘制图形,不过兼容性不好,官方说明还在实验中。
:::
## 样式和色彩
### 1、`fillStyle` 和`strokeStyle`
`fillStyle`设置图形的填充颜色。<br/>
`strokeStyle`设置图形的描边颜色。<br/>
两者的属性值可以是CSS颜色值的字符串、渐变对象、图案对象。<br/>
**举个🌰 -- 画4 * 4的方格填充和4 * 4的圆格填充**
```
for(var i = 0;i < 16;i++){
let _r = i % 4;
let _c = i / 4 >> 0;
ctx.fillStyle = `rgba(${Math.floor(255 - 42.5 * _r)},${Math.floor(255-42.5*_c)},0)`;
ctx.fillRect(_r*25,_c*25,25,25);
}
for(var j = 0;j < 16;j++){
let _r = j % 4;
let _c = j / 4 >> 0;
ctx.strokeStyle = `rgba(0,${Math.floor(255 - 42.5 * _r)},${Math.floor(255-42.5*_c)})`;
ctx.beginPath();
ctx.arc(120+25*_r,10+25*_c,10,0,Math.PI*2,true);
ctx.stroke();
}
```
![画方格和圆格](../../resources/canvas4.png ) 如图所示。
### 2、`globalAlpha`
设置图形和图片的透明度。值为0~1。<br/>
将当前绘制点的所有绘制图形的透明度都设置为同一个值。
::: tip 注意点
如果是单个图形,可以使用`raba` 的形式设置透明度。
:::
### 3、线型
#### `lineWidth` 定义线段的粗细。
是指给定路径的中心到两边的粗细。在路径两边各绘制线宽的一半。<br/>
::: tip 注意点
在canvas中绘制1像素线宽时,坐标位置需要错开0.5像素。<br>
后面设置的`lineWidth`会覆盖之前的。
:::
#### `lineCap` 设置线条末端样式,线帽。
* `butt` 默认样式,平齐
* `round` 一般线宽的半圆
* `square` 一半线宽的正方形
#### `lineJoin` 设置两线段连接处的样式
* `round` 在相连处填充一个扇形。
* `bevel` 在相连处填充一个三角形。
* `miter`在相连处填充一个菱形。
**举个🌰 -- 画三种连接**
```
var _linJoin = ['round','bevel','miter'];
for(var i = 0;i < _linJoin.length;i++)
{
ctx.lineWidth = 30;
ctx.beginPath();
ctx.lineJoin = _linJoin[i];
ctx.moveTo(20+100*i,50);
ctx.lineTo(80+100*i,50);
ctx.lineTo(80+100*i,150);
ctx.stroke();
}
```
![线线相连](../../resources/cnavas5.png ) 如图所示。
#### `miterLimit`斜接值
当两个线段夹角很小的时候,链接两条线段的长度就会非常长。<br/>
当超过你设置的`miterLimit`值时,会以`bevel`的形式处理。
#### `setLineDash(segments)`设置虚线
`segments`是一个数组,交替绘制线段长度和间距。如果数组元素为奇数,会被复制并重复。<br/>
#### `lineDashOffset` 设置虚线偏移量
属性值是float精度的数字。<br/>
**举个🌰 -- 绘制蚂蚁线**
```
var offset = 0;
function draw() {
ctx.clearRect(0,0, canvas.width, canvas.height);
ctx.lineWidth = 2;
ctx.setLineDash([4, 2]);
ctx.lineDashOffset = -offset;
ctx.strokeRect(100,100, 100, 100);
}
function march() {
offset++;
if (offset > 16) {
offset = 0;
}
draw();
setTimeout(march, 20);
}
march();
```
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment