mdn 文档
canvas 能够用于动画、游戏画面、数据可视化、图片编辑以及实时视频解决等内容。
canvas api 次要聚焦于 2D 图形。
WebGL api 次要聚焦于硬件加速的 2D 和 3D 图形。
先来看一个根底事例:
<canvas id="canvas">
Your browser not support canvas, please update browser.
</canvas>
<script>
function draw() {
// 获取 canvas 元素
const canvas = document.getElementById('canvas');
// 创立画板
const context = canvas.getContext('2d');
// 填充形态
context.fillRect(10, 10, 55, 50);
// 填充色彩
context.fillStyle = 'black';
}
draw();
</script>
这时,浏览器会呈现一个彩色的方块:
绘制图形
首先学习如何绘制矩形。
绘制矩形
canvas 提供了 3 种办法来绘制矩形:
- fillRect(x, y, width, height): 绘制了一个填充的矩形;
- strokeRect(x, y, width, height): 绘制了一个矩形的边框;
- clearRect(x, y, width, height): 分明指定矩形区域,让分明局部齐全通明;
- rect(x, y, width, height): 矩形门路
应用以上三个办法构建一个空心矩形:
function draw() {const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
context.fillRect(25, 25, 100, 100);
context.clearRect(50, 50, 50, 50);
}
draw();
如图下所示:
绘制门路
绘图的根本元素是门路。
门路:通过不同色彩和宽度的线段或曲线相连造成的不同形态的点的汇合
一下是所须要的函数:
- beginPath(): 新建一条门路,生成之后,图形绘制命令被指向到门路上生成门路;
- closePath(): 闭合门路之后图形绘制命令又从新指向到上下文中;
- stroke(): 通过线条来绘制图形轮廓;
- fill(): 通过填充门路的内容区域生成实心的图形了;
用以上的办法来构建一个矩形:
function draw() {const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
context.beginPath();
context.moveTo(100, 100);
context.lineTo(100, 0);
context.lineTo(0, 0);
context.lineTo(0, 100);
context.fill();}
draw();
生成门路:
- beginPath(): 实质上,门路是由很多子门路形成,这些子门路都是在一个列表中,所有的子门路来形成图形。每次调用这个办法,列表都会清空,而后就能够从新绘制新的图形了;
- moveTo(): 设置门路之后,指定起始地位;
- lineTo(): 调用函数 绘制门路;
- closePath(): 闭合门路(非必须),在调用 fill() 函数时,所有没有闭合的形态都会主动闭合。
挪动笔
moveTo(): 从画布上的一个点挪动到另外一个点。
绘制直线
应用 lineTo(x, y) 办法:从以后地位到 (x, y) 的领导地位的线段。
绘制圆弧
- arc(x, y, radius, startAngle, endAngle, anticlockwise): 画一个以 (x, y) 为圆心的以 radius 为半径的圆弧 / 园。从 startAngle 开始,到 endAngle 完结,依照 anticlockwise 给定的方向。
- arcTo(x1, y1, x2, y2, radius): 依据给定的控制点和半径画一段圆弧,再以直线链接两个控制点。
arc()
函数中,示意角度的单位是弧度,不是角度。角度转弧度的公式为:弧度 = 角度 * (π/ 180)
应用以上办法,画一个实心圆:
function draw() {const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
context.beginPath();
context.moveTo(50, 50);
context.arc(50, 50, 25, 0, 2 * Math.PI, true);
context.fill();}
draw();
如图下所示:
Path2D
为了简化代码以及进步性能,咱们能够应用 Path2D 用来缓存或者记录绘画命令。
来试验一下,来画一个内切圆:
function draw() {const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const rectangle = new Path2D();
rectangle.rect(0, 0, 100, 100);
const circle = new Path2D();
circle.moveTo(50, 50);
circle.arc(50, 50, 50, 2 * Math.PI, false);
context.stroke(rectangle);
context.stroke(circle);
}
draw();
SVG Path
能够应用 svg path data 来初始化 canvas 下面的门路
到当初为止,咱们能够应用一系列门路来将咱们所须要的图形,绘画在画布下面了。大体上的步骤如下:
- 创立画布
- 开始门路
- 设置初始点
- 绘画门路
- 闭合门路
示例
接下来,就通过下面学习到的常识来画一个简略的柱状图:
轴线
生成轴线:
// 坐标轴生成
createAxle(type = 'x') {const {point, axleLength} = this.defaults;
const axle = new Path2D();
axle.moveTo(...point);
if (type === 'x') {axle.lineTo(point[0] + axleLength, point[1]);
} else {axle.lineTo(point[0], point[1] - axleLength);
}
this.context.stroke(axle);
}
刻度
生成刻度:
// 生成刻度
createScale(type = 'x') {const {point, count, axleLength, scaleLength} = this.defaults;
const ruleWidth = parseInt(axleLength / count, 10);
const scale = new Path2D();
for (let i = 0; i <= axleLength; i += ruleWidth) {if (type === 'x') {scale.moveTo(point[0] + i, point[1]);
scale.lineTo(point[0] + i, point[1] + scaleLength);
} else {scale.moveTo(point[0], point[1] - i);
scale.lineTo(point[0] - scaleLength, point[1] - i);
}
}
this.context.stroke(scale);
}
画出柱状图
最初一步,咱们就要画出柱状图的要害,柱子了。
// 画柱状图
createRect() {const {point, axleLength, count} = this.defaults;
const rectLength = parseInt(axleLength / count, 10);
const rect = new Path2D();
for (let i = 0; i <= count; i += 1) {
rect.rect(point[0] + (rectLength * i),
point[1],
rectLength,
-rectLength * i
);
}
this.context.fill(rect);
}
残缺代码
class LineChart {constructor(config) {const canvas = document.getElementById('canvas');
this.context = canvas.getContext('2d');
this.defaults = {point: [50, 120],
axleLength: 100,
count: 5,
scaleLength: 5
};
Object.assign(this.defaults, config);
}
// 坐标轴生成
createAxle(type = 'x') {const {point, axleLength} = this.defaults;
const axle = new Path2D();
axle.moveTo(...point);
if (type === 'x') {axle.lineTo(point[0] + axleLength, point[1]);
} else {axle.lineTo(point[0], point[1] - axleLength);
}
this.context.stroke(axle);
}
// 坐标标尺
createScale(type = 'x') {const {point, count, axleLength, scaleLength} = this.defaults;
const ruleWidth = parseInt(axleLength / count, 10);
const scale = new Path2D();
for (let i = 0; i <= axleLength; i += ruleWidth) {if (type === 'x') {scale.moveTo(point[0] + i, point[1]);
scale.lineTo(point[0] + i, point[1] + scaleLength);
} else {scale.moveTo(point[0], point[1] - i);
scale.lineTo(point[0] - scaleLength, point[1] - i);
}
}
this.context.stroke(scale);
}
// 画柱状图
createRect() {const {point, axleLength, count} = this.defaults;
const rectLength = parseInt(axleLength / count, 10);
const rect = new Path2D();
for (let i = 0; i <= count; i += 1) {
rect.rect(point[0] + (rectLength * i),
point[1],
rectLength,
-rectLength * i
);
}
this.context.fill(rect);
}
draw() {this.createAxle('x');
this.createAxle('y');
this.createScale('x');
this.createScale('y');
this.createRect();}
}
const lineChart = new LineChart();
lineChart.draw();
后果如下所示:
剩下的工作还有一些,之后在更新吧!
- [] 丑化这个柱状图啊,当初这个太黑了
- [] 标上刻度
- [] 依据数据来对柱子进行调节