图形开发学院|GraphAnyWhere
第一章:绘制基本图形
本章的内容包括:
- 绘制矩形
- 绘制折线和多边形
- 绘制圆和圆弧
- 绘制椭圆和椭圆弧
1. 矩形
\quad 矩形是日常生活和工作中最常见到的图形,Canvas提供了非常简单的方式,只需一行代码就能够绘制矩形,其语法如下:
绘制矩形的边框:
ctx.strokeRect(x, y, width, height)
绘制填充的矩形:
ctx.fillRect(x, y, width, height)
\quad
在这两个方法中只需指定矩形的起始坐标(x,y)和矩形的宽和高,就能够绘制矩形。先看一个示例的运行效果图:
源代码如下:
<!DOCTYPE html>
<html>
<head>
<title>绘制基本图形</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body style="overflow: hidden; margin:0px;">
<canvas id="canvas" width="1200" height="800"></canvas>
</body>
<script>
// 从页面中获取画布对象
let canvas = document.getElementById('canvas');
// 从画布中获取“2D渲染上下文”对象
let ctx = canvas.getContext('2d');
// 绘制左侧矩形(描边)
ctx.strokeRect(50, 50, 200, 100);
// 绘制右侧填充矩形
ctx.fillRect(350, 50, 200, 100);
</script>
</html>
\quad 这个示例中:
let canvas = document.getElementById('canvas')
可取得页面中的canvas对象;let ctx = canvas.getContext('2d');
可取得Canvas对象的渲染上下文对象ctx.strokeRect(50, 50, 200, 100)
和ctx.fillRect(350, 50, 200, 100)
分别绘制了一个非填充的矩形和一个填充的矩形,其各参数分的含义如下:- 第一个参数表示矩形的起点横坐标为(x),左侧矩形的x=50, 右侧矩形的x=350
- 第二个参数表示矩形的起点纵坐标为(y),两个矩形的y均为50
- 第三个参数表示矩形的宽度(width),两个矩形的width均为200
- 第四个参数表示矩形的高度(height),两个矩形的height均为100
\quad
坐标的原点在左上角,水平方向为x轴,垂直方向为y轴,各个坐标在图中的位置如下图所示:
\quad Canvas还提供了其他的一些api,可以调整矩形效果,例如使用不用颜色绘制矩形,指定矩形的边框大小等等,均是通过Canvas的渲染上下文对象进行赋值,这些api如下所示:
// 改变线宽
ctx.lineWidth = value;
// 画笔颜色
ctx.strokeStyle = color;
// 填充颜色
ctx.fillStyle = color;
其运行效果如下图所示:
源代码如下:
<!-- 略过html部分的内容-->
<script>
// 从页面中获取画布对象
let canvas = document.getElementById('canvas');
// 从画布中获取“2D渲染上下文”对象
let ctx = canvas.getContext('2d');
// 绘制左侧矩形
ctx.lineWidth = 10;
ctx.strokeRect(100, 300, 200, 100);
// 绘制右侧矩形
ctx.lineWidth = 5;
ctx.fillStyle = "#0000FF"
ctx.fillRect(400, 300, 200, 100);
ctx.strokeStyle = "#FF0000"
ctx.strokeRect(400, 300, 200, 100);
</script>
\quad
此外,Canvas的渲染上下文还提供了在路径中绘制矩形rect()
和清空一个矩形区域clearRect()
,其参数与strokeRect()
及fillRect()
完全一样,后续文章将会讲解路径的使用方法。清空一个矩形区域,将会实现让清除部分完全透明,通常用于清除Canvas原有内容,以下代码可清除整个Canvas中的内容:
ctx.clearRect(0, 0, canvas.width, canvas.height);
2. 折线和多边形
\quad
线段的应用非常广泛,不仅包含了普通的直线,还包括了折线,虚线等等,先看一个例子:
\quad 这个例子中我们使用Canvas绘制了四条直线,其中第一条最简单的直线,第二条直线增加了线宽属性,第三条直线增加了颜色属性,第四条直线为虚线,代码如下:
<script>
// 从页面中获取画布对象
let canvas = document.getElementById('canvas');
// 从画布中获取“渲染上下文”对象
let ctx = canvas.getContext('2d');
// 绘制简单直线
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(450, 50);
ctx.stroke();
// 绘制加粗的直线
ctx.beginPath();
ctx.moveTo(50, 110);
ctx.lineTo(450, 110);
ctx.lineWidth=5;
ctx.stroke();
// 绘制蓝色直线
ctx.beginPath();
ctx.moveTo(50, 170);
ctx.lineTo(450, 170);
ctx.strokeStyle="blue";
ctx.stroke();
// 绘制虚线
ctx.beginPath();
ctx.moveTo(50, 230);
ctx.lineTo(450, 230);
ctx.setLineDash([20, 15]);
ctx.stroke();
</script>
这个示例使用了Canvas的渲染上下文的以下几个方法:
ctx.beginPath() // 开始路径
ctx.moveTo(x,y) // 将路径起点移动到起始点(x,y)坐标
ctx.lineTo(x,y) // 使用直线连接路径至终点(x,y)坐标
ctx.stroke() // 绘制当前路径
\quad 绘制折线其实是由绘制“路径”这个功能实现的,其过程为:
- 开始绘制路径:ctx.beginPath()
- 将路径移动到起始点:ctx.moveTo(x, y)
- 使用直线连接路径至某个点:ctx.lineTo(x, y),如果需要可以继续使用直线连接路径至某个点
- 设置样式:
指定线宽:ctx.lineWidth=5
指定边框颜色:ctx.strokeColor=“red”
指定填充颜色:ctx.fillColor=“#CCCCCC”
使用虚线模式:ctx.setLineDash([10,10]) - 描边或填充
描边:ctx.stroke()
填充:ctx.fill();
下图标识了上述这四条直线的坐标值,可以更好的理解绘制直线的过程:
整个绘制的过程如下:
- 1、将画笔移动到坐标(50,50),绘制直线至坐标(450,50);
- 2、将画笔移动到坐标(50,110),绘制直线至坐标(450,110);
- 3、将画笔移动到坐标(50,170),绘制直线至坐标(450,170);
- 4、将画笔移动到坐标(50,230),绘制直线至坐标(450,230);
在绘制过程中,可根据需要改变线宽或颜色等属性。
\quad 上述的几张效果图中均包含了灰色的网格线,这个网格线也是通过循环绘制直线功能来实现的,其代码如下:
/**
* 绘制网格线
* @param color 颜色
* @param stepX x轴网格间距
* @param stepY y轴网格间距
*/
function drawGrid(color, stepX, stepY) {
ctx.save();
ctx.beginPath();
// 水平线
for (var i = stepX; i < canvas.width; i += stepX) {
ctx.moveTo(i, 0);
ctx.lineTo(i, canvas.height)
}
// 垂直线
for (var i = stepY; i < canvas.height; i += stepY) {
ctx.moveTo(0, i);
ctx.lineTo(canvas.width, i);
}
// 绘制
ctx.lineWidth = 0.5;
ctx.strokeStyle = color;
ctx.stroke();
ctx.restore();
}
我们在来看一个绘制折线图的例子:
实现的逻辑也很简单,其代码如下:
<script>
// 从页面中获取画布对象
let canvas = document.getElementById('canvas');
// 从画布中获取“2D渲染上下文”对象
let ctx = canvas.getContext('2d');
// 绘制坐标系
ctx.lineWidth = 6;
drawLine([[76, 45], [76, 285], [316, 285]]);
ctx.stroke();
drawLine([[90, 51], [76, 23], [62, 51], [90, 51]]);
ctx.fill();
drawLine([[310, 271], [338, 285], [310, 299], [310, 271]]);
ctx.fill();
// 绘制数据走向
drawLine([[105, 256], [192, 169], [222, 227], [309, 140]]);
ctx.strokeStyle = "blue";
ctx.stroke();
drawLine([[105, 215], [192, 110], [222, 157], [309, 52]]);
ctx.strokeStyle = "red";
ctx.stroke();
/**
* 绘制折线
*/
function drawLine(pixel) {
ctx.beginPath();
ctx.moveTo(pixel[0][0], pixel[0][1]);
for (let m = 1; m < pixel.length; m += 1) {
ctx.lineTo(pixel[m][0], pixel[m][1]);
}
}
</script>
\quad
接下来我们讲解一下如何绘制虚线,绘制虚线是在设置样式时由ctx.setLineDash([])
方法指定的,这个方法接受一个整数数组作为参数,其含义为:“虚线长度 空格长度 虚线长度 空格长度”,画布在绘制虚线时就会按照这个数组的长度信息重复绘制,使用不同的参数可得到不同的选线效果,我们看看以下示例:
完整的代码如下:
<script>
// 从页面中获取画布对象
let canvas = document.getElementById('canvas');
// 从画布中获取“2D渲染上下文”对象
let ctx = canvas.getContext('2d');
// 绘制虚线n
ctx.lineWidth=2;
let y = 100;
drawDashedLine([2, 2]);
drawDashedLine([10, 10]);
drawDashedLine([20, 5]);
drawDashedLine([15, 4, 4, 4]);
drawDashedLine([20, 4, 4, 4, 4, 4, 4, 4]);
drawDashedLine([12, 4, 4]);
function drawDashedLine(pattern) {
ctx.beginPath();
ctx.setLineDash(pattern);
ctx.moveTo(500, y);
ctx.lineTo(800, y);
ctx.stroke();
y += 40;
}
</script>
\quad
多边形的绘制和绘制折线的过程非常相似,其区别是最后一个点需和第一个点的坐标重合,也可使用closePath()
实现闭合折线。接下来我们看一个绘制多边形(五角星)的例子:
其源代码如下:
<script>
// 从页面中获取画布对象
let canvas = document.getElementById('canvas');
// 从画布中获取“2D渲染上下文”对象
let ctx = canvas.getContext('2d');
// 建立五角星的绘制路径
ctx.beginPath();
ctx.moveTo(100, 20);
ctx.lineTo(53, 164);
ctx.lineTo(176, 76);
ctx.lineTo(24, 76);
ctx.lineTo(147, 164)
ctx.closePath();
// 绘制
ctx.fillStyle = "red";
ctx.fill();
</script>
\quad
在这个例子中,可以看到在moveTo()
之后,接着lineTo()
,lineTo()
……,就实现了多边形的绘制。
\quad
如果没有执行moveTo()
,则表示从当前位置开始绘制,初始位置是坐标原点(0,0)。
\quad
这个例子中还执行了一个closePath()
方法,表示从最后一个点至第一个点之间绘制一条直线,闭合了这段折线,首尾进行了相连,实现了多边形的绘制。
在建立路径后,需执行
stroke()
或fill()
命令,表示将路径绘制出来。
stroke()
将会对路径进行描边,fill()
将会对路径进行填充。
3. 圆和圆弧
Canvas 2D API 提供了arc()命令,用于绘制圆或圆弧,其语法如下:
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
参数名 | 说明 |
---|---|
x | 圆弧中心(圆心)的 x 轴坐标 |
y | 圆弧中心(圆心)的 y 轴坐标 |
radius | 圆弧的半径 |
startAngle | 圆弧的起始点,x 轴方向开始计算,单位以弧度表示 |
endAngle | 圆弧的终点,单位以弧度表示。 |
anticlockwise | 可选的Boolean值(默认值为: false),表示顺时针绘制圆弧,为 true表示逆时针绘制圆弧 |
\quad
圆的绘制也是通过建立路径开始的,我们通过几个例子,来了解各个参数的含义,首先看看绘制圆的示例,其运行效果如下图所示:
这个例子中绘制了一个带边框的圆和一个填充圆,其代码如下:
<script>
// 从页面中获取画布对象
let canvas = document.getElementById('canvas');
// 从画布中获取“2D渲染上下文”对象
let ctx = canvas.getContext('2d');
// 绘制背景网格线
drawGrid('lightgray', 10, 10);
// 绘制一个带边框的圆
ctx.beginPath();
ctx.arc(150, 150, 100, 0, 2 * Math.PI);
ctx.lineWidth = 4;
ctx.stroke();
// 绘制一个蓝色填充的圆
ctx.beginPath();
ctx.arc(400, 150, 100, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
</script>
我们挑选出关键的几条语句:
// 绘制一个带边框的圆
ctx.arc(150, 150, 100, 0, 2 * Math.PI);
ctx.stroke();
// 绘制一个蓝色填充的圆
ctx.arc(400, 150, 100, 0, 2 * Math.PI);
ctx.fill();
我们在回顾一下arc()
的语法:
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
\quad
前两个参数为圆心的坐标(x,y),第3个参数为圆的半径,下图显示圆心坐标和半径:
\quad 第4和第5个参数是圆的起始角度和终止角度,上面这个例子中,指定开始角度为0,结束角度为2π,因此绘制的是一个完整的圆,而当开始角度至结束角度不到2π时,绘制的就是一个圆弧。需要特别提醒的是:我们之前在学校学习的时候,用到的角度单位通常是度,例如30°/45°/60°/90°/180°/360°等等,而acr()中需使用弧度作为单位,我们知道一周的弧度数是2π(2πr/r),因此可以通过以下代码将角度转为弧度:
/**
* 将弧度转换为度
* @param {number} angleInRadians 以弧度为单位的角度
* @return {number} 角度(以度为单位)
*/
function toDegrees(angleInRadians) {
return (angleInRadians * 180) / Math.PI;
}
/**
* 将度数转换为弧度
* @param {number} angleInDegrees 以度为单位的角度
* @return {number} 角度(弧度)
*/
function toRadians(angleInDegrees) {
return (angleInDegrees * Math.PI) / 180;
}
\quad
接来下看一下圆弧的例子,运行效果如下图:
\quad
在这里例子中绘制了3段圆弧,绿色的半圆,红色的顺时针135°圆弧,蓝色的逆时针135°圆弧,下图中标注了坐标信息:
\quad 这三段弧线都是从0°开始,可以看出0°位于圆心右侧的x坐标轴上,默认时按顺时针方向绘制圆弧,如果anticlockwise=true则逆时针绘制圆弧。绘制这三段圆弧的源代码如下:
<script>
// 从页面中获取画布对象
let canvas = document.getElementById('canvas');
// 从画布中获取“2D渲染上下文”对象
let ctx = canvas.getContext('2d');
// 绘制背景网格线
drawGrid('lightgray', 10, 10);
// 绘制一个绿色半圆
ctx.lineWidth = 8;
ctx.beginPath();
ctx.arc(150, 150, 100, 0, Math.PI);
ctx.strokeStyle = "green";
ctx.stroke();
// 绘制一个红色圆弧
ctx.beginPath();
ctx.arc(400, 150, 100, 0, 135 * Math.PI / 180, true);
ctx.strokeStyle = "blue";
ctx.stroke();
// 绘制另一个蓝色圆弧
ctx.beginPath();
ctx.arc(400, 150, 100, 0, 135 * Math.PI / 180, false);
ctx.strokeStyle = "red";
ctx.stroke();
</script>
\quad
接下来我们来看一个有趣的例子,绘制一张笑脸,其效果和代码分别如下:
<script>
// 从页面中获取画布对象
let canvas = document.getElementById('canvas');
// 从画布中获取“2D渲染上下文”对象
let ctx = canvas.getContext('2d');
// 绘制背景网格线
drawGrid('lightgray', 10, 10);
// 绘制笑脸
drawFace(140, 140, 10);
// 笑脸绘制函数
function drawFace(x, y, size) {
ctx.save();
ctx.translate(x, y);
ctx.beginPath();
ctx.arc(0, 0, 10 * size, 0, Math.PI * 2, true); // Outer circle
ctx.fillStyle="yellow";
ctx.fill();
ctx.beginPath();
ctx.arc(0, 0, 7 * size, 0, Math.PI, false); // Mouth
ctx.lineWidth = 4;
ctx.strokeStyle = "rgb(0,0,0)";
ctx.stroke();
ctx.beginPath();
ctx.arc(0 - 3 * size, 0 - 2.5 * size, size, 0, Math.PI * 2, true); // Left eye
ctx.moveTo(0 + 4 * size, 0 - 2.5 * size);
ctx.arc(0 + 3 * size, 0 - 2.5 * size, size, 0, Math.PI * 2, true); // Right eye
ctx.fillStyle="black";
ctx.fill();
ctx.restore();
}
</script>
4. 椭圆和椭圆弧
\quad 绘制椭圆和绘制圆的方法非常相似,也是从建立路径开始的,通过ellipse()命令来绘制椭圆或椭圆弧,其语法如下:
ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise);
参数名 | 说明 |
---|---|
x | 椭圆圆心的 x 轴坐标 |
y | 椭圆圆心的 y 轴坐标 |
radiusX | 椭圆长轴的半径 |
radiusY | 椭圆短轴的半径 |
rotation | 椭圆的旋转角度,单位以弧度表示 |
startAngle | 将要绘制的起始点角度,从 x 轴测量,以弧度表示 |
endAngle | 椭圆将要绘制的结束点角度,以弧度表示 |
anticlockwise | 可选的Boolean值,如果为 true,逆时针绘制圆弧,反之,顺时针绘制 |
\quad
我们通过一个例子,来了解各个参数的含义,其运行效果如下图所示:
<script>
// 从页面中获取画布对象
let canvas = document.getElementById('canvas');
// 从画布中获取“2D渲染上下文”对象
let ctx = canvas.getContext('2d');
// 绘制左侧椭圆
ctx.beginPath();
ctx.ellipse(100, 100, 75, 50, 0, 0, 2 * Math.PI);
ctx.stroke();
// 绘制右侧椭圆
ctx.beginPath();
ctx.ellipse(300, 100, 50, 70, 0, 0, 2 * Math.PI);
ctx.stroke();
// 绘制辅助线
ctx.beginPath()
ctx.moveTo(0, 100)
ctx.lineTo(850, 100);
ctx.moveTo(100, 0);
ctx.lineTo(100, 200)
ctx.moveTo(300, 0);
ctx.lineTo(300, 200)
ctx.setLineDash([4, 4]);
ctx.stroke();
</script>
\quad
从这个例子可以看出,绘制椭圆ctx.ellipse()
由中心点坐标、x方向半径、y方向半径、起始角度、终止角度等几个参数绘制而成,其参数和圆的绘制非常相似。
比较特殊的是绘制椭圆多了一个旋转角度参数:
ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise);
\quad
通过一个示例了解一下这个参数,其运行效果和源代码分别如下:
<script>
// 从页面中获取画布对象
let canvas = document.getElementById('canvas');
// 从画布中获取“2D渲染上下文”对象
let ctx = canvas.getContext('2d');
// 绘制背景网格线
drawGrid('lightgray', 10, 10);
// 绘制红色椭圆
ctx.lineWidth = 4;
ctx.beginPath();
ctx.ellipse(120, 120, 110, 50, 0, 0, 2 * Math.PI);
ctx.strokeStyle = "red";
ctx.stroke();
// 绘制蓝色椭圆
ctx.beginPath();
ctx.ellipse(120, 120, 110, 50, 60 * Math.PI / 180, 0, 2 * Math.PI);
ctx.strokeStyle = "blue";
ctx.stroke();
// 绘制绿色椭圆
ctx.beginPath();
ctx.ellipse(120, 120, 110, 50, 120 * Math.PI / 180, 0, 2 * Math.PI);
ctx.strokeStyle = "green";
ctx.stroke();
</script>
\quad 在这里示例中,三个椭圆除旋转角度外,其他参数均相同,可以看出椭圆以圆心为中心点进行了旋转。
5 本章小结
\quad 本节讲解了如何在Canvas绘制矩形、线、多边形、圆、椭圆等内容,并讲解了绘制边和填充、设置线宽、设置颜色等内容,本节内容使用了Canvas 2D API以下方法:
参数名 | 说明 |
---|---|
strokeRect() | 绘制一个矩形的边框 |
fillRect() | 绘制一个填充的矩形 |
rect() | 在路径中绘制矩形 |
clearRect() | 清除指定矩形区域,让清除部分完全透明 |
beginPath() | 开始一个新的路径 |
closePath() | 将笔点返回到当前子路径起始点 |
moveTo() | 将一个新的子路径的起始点移动到 (x,y) 坐标 |
lineTo() | 绘制直线(使用直线连接子路径的终点到 x,y 坐标) |
arc() | 绘制圆弧路径 |
ellipse() | 绘制椭圆路径 |
stroke() | 绘制当前或已经存在的路径 |
fill() | 填充当前或已存在的路径 |
同时也使用了Canvas 2D API修改了绘图时的以下样式:
参数名 | 说明 |
---|---|
strokeStyle | 描述画笔(绘制图形)颜色或者样式的属性 |
fillStyle | 描述填充时颜色和样式的属性 |
lineWidth | 设置线段宽度的属性 |
setLineDash() | 填充线时使用虚线模式 |
练习一下
基本形状
- 练习1:绘制一个绿色的(green),填充的,大小为整个画布的矩形;
- 练习2:绘制一个金色的(gold),填充的,大小为100的圆;
- 练习3:绘制一条蓝色的(blue),长度为200, 粗细为6的带箭头的线;
七巧板
\quad 七巧板是由五个三角形、一个平行四边形和一个正方形组成,以下是七巧板中各块板的坐标,使用这些数据可以绘制出下面这个图形,你也动手试一试吧。
[
{ "coords": [[100, 50], [340, 50], [220, 170]], "fillColor": "#caff67" },
{ "coords": [[100, 50], [220, 170], [100, 290]], "fillColor": "#67becf" },
{ "coords": [[340, 50], [340, 170], [280, 230], [280, 110]], "fillColor": "#ef3d61" },
{ "coords": [[280, 110], [280, 230], [220, 170]], "fillColor": "#f9f51a" },
{ "coords": [[220, 170], [280, 230], [220, 290], [160, 230]], "fillColor": "#a54c09" },
{ "coords": [[160, 230], [220, 290], [100, 290]], "fillColor": "#fa8ccc" },
{ "coords": [[340, 170], [340, 290], [220, 290]], "fillColor": "#f6ca29" }
]
相关资料
▶ 系列教程及代码资料:https://GraphAnyWhere.com
▶ 图形系统开发实战课程:基础篇——图形系统概述
作者信息
作者 : 图形开发学院
CSDN: https://blog.csdn.net/2301_81340430?type=blog
官网:https://graphanywhere.com