前言
Canvas标签可以通过Javascript来绘制图形
创建一个Canvas标签
- 兼容性问题,Canvas内部文字只有不支持的浏览器才会看到,主要针对IE6、IE7、IE8
1
| <canvas>当前浏览器版本不支持,请升级浏览器</canvas>
|
属性
- 画布宽高
- 不要使用CSS设置宽高,CSS设置宽高会拉伸画布,使画布失真
1
| <canvas width="" height=""></canvas>
|
绘制上下文对象
2d
:上下文有两个,分别是2d和3d
1 2
| let canvas = document.querySelector("canvas"); let ctx = canvas.getContext("2d");
|
Canvas的像素化
- 我们使用Canvas绘制了一个图形,Canvas就会像素化图形,Canvas没有能力从画布上再次更改已经在画布上的内容,这个就是Canvas比较轻量的原因
Canvas的动画思想
- 如果我们想要让Canvas绘制的图形移动,必须按照
清屏
->更新
->渲染
的逻辑进行编程,总之就是重新再画一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
let left = 100;
setInterval(function() { ctx.clearRect(0, 0, canvas.width, canvas.height); left += 1; ctx.fillRect(left, 100, 100, 100); }, 30);
|
面向对象实现Canvas动画
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
function Rect(x, y, w, h, color) { this.x = x; this.y = y; this.w = w; this.h = h; this.color = color; }
Rect.prototype.update = function() { this.x += 1; };
Rect.prototype.render = function() { ctx.fillStyle = this.color; ctx.fillRect(this.x, this.y, this.w, this.h); };
let r1 = new Rect(100, 100, 50, 50, "black");
setInterval(function() { ctx.clearRect(0, 0, canvas.width, canvas.height); r1.update(); r1.render(); }, 10);
|
Canvas的API
填充图形
设置颜色
<color>
:颜色名称
1
| ctx.fillStyle = "<color>";
|
填充矩形
<x>
:图形距离原点(左上角)的横坐标
<y>
:图形距离原点(左上角)的纵坐标
<w>
:矩形的长
<h>
:矩形的宽
1
| ctx.fillRect(<x>, <y>, <w>, <h>);
|
绘制图形
设置颜色
1
| ctx.strokeStyle = "<color>";
|
绘制矩形
1
| ctx.strokeRect(<x>, <y>, <w>, <h>);
|
清屏
<w>
:清屏的长范围
<d>
:清屏的宽范围
1
| ctx.clearRect(<x>, <y>, <w>, <h>);
|
绘制路径
- 绘制路径目的是设置一个不规则的多边形状态,路径都是闭合的,使用路径进行绘制的时候需要既定的步骤
- 设置路径的起点
- 使用画图命令,画出路径
- 关闭封闭路径
- 填充或者绘制已经封闭路径的形状
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ctx.beginPath();
ctx.moveTo(<x>, <y>);
ctx.lineTo(<x>, <y>); ctx.lineTo(<x>, <y>);
ctx.closePath();
ctx.strokeStyle = "<color>"; ctx.stroke();
ctx.fillStyle = "<color>"; ctx.fill();
|
对于stroke,如果不使用closePath()封闭绘制,则边框不会自动封闭
对于fill,如果不使用closePath()封闭填充,则图形会自动封闭
圆弧
<x>
:圆心横坐标
<y>
:圆心纵坐标
<radius>
:半径
<startAngle>
:开始位置,如果是数字表示圆的弧度
<endAngle>
:结束位置,如果是数字表示圆的弧度,值为2*Math.PI
、2*3.14
、7
时表示一个完整的圆
anticlockwise
:顺时针或逆时针状态,true表示顺时针,false表示逆时针
1 2 3 4 5 6 7 8
| ctx.beginPath(); ctx.art(<x>, <y>, <radius>, <startAngle>, <endAngle>, <anticlockwise>);
ctx.strokeStyle = "<color>"; ctx.stroke();
ctx.fillStyle = "<color>"; ctx.fill();
|
设置透明度
<num>
:1~0之间的数,1为不透明,0为透明
1
| ctx.globalAlpha = <num>;
|
线型
设置粗细
<num>
:粗细值,默认为1.0,表示1像素
设置末端的形状
<value>
butt
:缺省值,末端以方形结束
round
:末端以圆形结束
square
:末端以方形结束,但是增加了一个__宽度是线段相同,高度是线段厚度一半__的矩形区域
1
| ctx.lineCap = "<value>";
|
设置相连部分的形状
<value>
round
:相连部分为圆角
bevel
:相连部分为平角
miter
:缺省值,相连部分为尖角
设置虚线
<value>
[a,b]
a
:线的长度
b
:空的距离
1
| ctx.setLineDash(<value>);
|
起始偏移量
<value>
:偏移量值
1
| ctx.lineDashOffset = <value>;
|
绘制文本
设置画笔
<size>
:字号,单位px
<family>
:字体名
1
| ctx.font = "<size> <family>";
|
绘制文本
<str>
:文本内容
<x>
:文本位置横坐标
<x>
:文本位置纵坐标
1
| ctx.fillText(<str>, <x>, <y>);
|
设置文本对齐方式
<value>
left
:基于x轴左对齐
right
:基于x轴右对齐
center
:基于x轴居中
start
:缺省值,基于x轴起始对齐
end
:基于x轴末尾对齐
1
| ctx.textAlign = "<value>";
|
渐变
线性渐变
<x_1>
:开始点横坐标
<y_1>
:开始点纵坐标
<x_2>
:结束点横坐标
<y_2>
:结束点纵坐标
<num>
:1~0之间的数
<color>
:颜色值字符串
1 2 3 4 5
| let linear = ctx.createLinearGradient(<x_1>, <y_1>, <x_2>, <y_2>); linear.addColorStop(<num>, <color>); linear.addColorStop(<num>, <color>);
ctx.fillStyle = linear;
|
径像渐变
<x_1>
:开始圆心横坐标
<y_1>
:开始圆心纵坐标
<r_1>
:开始圆的半径
<x_2>
:结束圆心横坐标
<y_2>
:结束圆心纵坐标
<r_2>
:结束圆的半径
1 2 3 4 5
| let linear = ctx.createRadialGradient(<x_1>, <y_1>, <r_1>, <x_2>, <y_2>, <r_2>); linear.addColorStop(<num>, <color>); linear.addColorStop(<num>, <color>);
ctx.fillStyle = linear;
|
阴影
<x>
:阴影水平方向偏移量,默认值为0,负数向左,正数向右
<y>
:阴影垂直方向偏移量,默认值为0,负数向上,正数向下
<num>
:模糊效果,默认值为0
<color>
:阴影的颜色
1 2 3 4
| ctx.shadowOffsetX = <x>; ctx.shadowOffsetY = <y>; ctx.shadowBlur = <num>; ctx.shadowColor = "<color>";
|
使用图片
- Canvas使用dradImage来绘制图片,主要是把外部图片导入进来绘制到画布上
两个参数
<src>
:图片路径
<x>
:图片放置横坐标
<y>
:图片放置纵坐标
1 2 3 4 5
| let image = new Image(); image.src = "<src>"; image.onload = function() { ctx.drawImage(image, <x>, <y>); }
|
四个参数
<width>
:图片宽度
<height>
:图片高度
1 2 3 4 5
| let image = new Image(); image.src = "<src>"; image.onload = function() { ctx.drawImage(image, <x>, <y>, <width>, <height>); }
|
八个参数
<cut_x>
:裁切图片的位置横坐标
<cut_y>
:裁切图片的位置纵坐标
<cut_width>
:裁切的宽度
<cut_height>
:裁切的高度
<slice_x>
:切片放置的位置横坐标
<slice_y>
:切片放置的位置纵坐标
<slice_width>
:切片形变后的宽度
<slice_height>
:切片形变后的高度
1 2 3 4 5
| let image = new Image(); image.src = "<src>"; image.onload = function() { ctx.drawImage(image, <cut_x>, <cut_y>, <cut_width>, <cut_height>, <slice_x>, <slice_y>, <slice_width>, <slice_height>); }
|
资源管理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| function Game() {
this.ctx = document.querySelector("canvas").getContext("2d");
// 将资源地址保存在R属性中 this.R = { "wp01": "./img/WallPaper01.jpg", "wp02": "./img/WallPaper02.jpg", "wp03": "./img/WallPaper03.jpg", "wp04": "./img/WallPaper04.jpg" }
// 获取资源图片的总数 let len = Object.keys(this.R).length;
// 定义计数器,用于计数加载完毕的资源数 let count = 0;
// 将R中的所有图片地址重新赋值为Image对象 for (let k in this.R) { // 创建一个Image对象 let img = new Image(); // 备份图片地址到Image对象的src属性中 img.src = this.R[k]; // 把图片对象重新存放在R属性中 this.R[k] = img; }
// 遍历所有Image对象,并加载 for (let k in this.R) { // 为了在内部继续使用this,所以将this定义为变量 let self = this; // 加载图片 this.R[k].onload = function () { // 加载完图片,计数器+1 count += 1;
// 清屏 self.ctx.clearRect(0, 0, 600, 400); // 在页面渲染加载进度 self.ctx.font = "20px 苹方"; self.ctx.fillText(`图片已经加载${count}/${len}`, 100, 100);
// 判断是否加载游戏,如果加载完了,开始游戏 if (count == len) { self.ctx.clearRect(0, 0, 600, 400); self.ctx.font = "20px 苹方"; self.ctx.fillText(`开始游戏`, 100, 100); }
} }
}
Game();
|
变形
状态
- 每一次保存,可以将当前画笔状态创建快照
- 每一次恢复,可以还原上一次快照的画笔状态
- 可以进行多次保存,创建多个快照,多次保存之后可以进行多次恢复,按顺序恢复上一次快照
保存画布状态
恢复画布状态
平移
<x>
:横坐标偏移量
<y>
:纵坐标偏移量
1
| ctx.translate(<x>, <y>);
|
旋转
<num>
:旋转的角度,0~1之间的数
缩放
<x>
:x轴缩放的倍数,01直接的数表示缩小,大于的数表示放大
<y>
:y轴缩放的倍数,01直接的数表示缩小,大于的数表示放大
综合属性
<zoom_x>
:水平方向缩放
<zoom_y>
:垂直方向缩放
<tilt_x>
:水平方向倾斜
<tilt_y>
:垂直方向倾斜
<move_x>
:水平方向移动
<move_y>
:垂直方向移动
1
| ctx.transform(<zoom_x>, <tilt_x>, <tilt_y>, <zoom_y>, <move_x>, <move_y>)
|
合成
<value>
destination-in
:只显示旧图形∈新图形
destination-over
:将新图形绘制在旧图形的底部
destination-out
:只显示旧图形∉新图形
destination-atop
:新图形绘制在旧图形底部的同时,只显示新图形的部分
source-in
:只显示新图形∩旧图形
source-over
:缺省值,将新图形绘制在旧图形的顶部
source-out
:只显示新图形∉旧图形
source-atop
:只显示非新图形∉旧图形
1
| ctx.globalCompositeOperation = "<value>";
|
完成
参考文献
哔哩哔哩——web前端小清风