【Canvas学习笔记】基础篇(一)
一、写在前面
最近在项目中遇到一个绘制雷达图的需求,以前我都是直接使用echarts来进行一些图表的绘制,但是这个项目中的雷达图非常的简单,而且整个项目中只有这一处需要进行类似的图形绘制,为了这个小小的雷达图而引入 echarts感觉有点不划算,哈哈。所以我决定直接使用canvas元素进行绘制,以前也看过canvas的一些使用方法,但是一直没有用过,因此有些遗忘,所以趁着这次雷达图的开发,把canvas的基础使用进行一个记录。
二、<canvas>元素简介
HTML5添加了一些新的元素,其中就有<canvas>。使用<canvas>元素,我们可以在页面中设定一个指定大小的区域,然后在这个区域中通过JavaScript动态绘制图形。与<canvas>相关的有一组API,我们就是通过各种花式操作这些API来完成我们各种图形的绘制,比如最基本的:路径、盒、弧、字符以及添加图像。
当然啦,不是所有的浏览器都支持canvas元素,下面表格中列出了各浏览器支持<canvas>元素的第一个版本号。
支持<canvas>元素的浏览器会只渲染<canvas>标签,而忽略出现<canvas>开始和结束标签中的内容,不支持的浏览器则会直接渲染<canvas>开始和结束标签中的内容,因此对于那些不支持<canvas>元素的浏览器,我们可以使用在<canvas>标签中添加内容的方式,在相应的区域展示替代内容(优雅降级)。
比如使用文本替代:
<canvas id="my-canvas" width="300" height="300">your browser can not support 'canvas' element</canvas>
注意:<canvas>标签的结束标签</canvas>不可以省略,如果省略了,那么文档中的其余部分都会被认为是替代内容,在支持<canvas>元素的浏览器中将不会展示。
从上面的代码中我们可以看到,<canvas>元素有两个特殊属性:width、height,这两个属性都是可选的,如果没有设置width和height属性。则默认width为300,height为150,单位都是px。当然,也可以通过css属性来设置宽高,但是如果宽高属性和初始比例(2:1)不一致,会出现扭曲。所以,建议不要使用css属性来设置<canvas>元素的宽高。
除了具备特殊的width和height属性之外,<canvas>标签也支持HTML中的全局属性和事件属性。
三、2D上下文
1、获取2D上下文对象
canvas就像一块画布,要想在画布上绘图,除了需要画布,我们还需要画笔,即绘图上下文,通过绘图上下文来绘制和处理要展示在画布中的内容。
通过调用getContext()方法并传入上下文类型,就可以取得绘图上下文对象的引用,比如传入“2d”,就可以取得2D上下文对象(本笔记只讲述2D上下文)。
1 <script> 2 // 获取画布 3 var canvas = document.getElementById('my-canvas'); 4 // 判断浏览器是否支持<canvas>元素 5 if (canvas.getContext) { 6 // 获取绘图上下文(画笔) 7 var ctx = canvas.getContext('2d'); 8 } 9 </script>
2、Canvas坐标
我们可以把Canvas画布看成一个二维坐标系,坐标系原点位于画布左上角的顶点,表示为(0, 0),如下图,所有坐标值都是基于原点进行计算,x值越大表示越靠右,y值越大表示越靠左。2D上下文的初始位置位于坐标系的原点。
3、填充和描边
2D上下文的两种基本绘图操作是填充fill()和描边stroke()。
填充,就是指使用指定的样式(颜色、渐变或者图像)来填充某个图形,就像绘画中的上色;描边,就是指沿着图形的边缘画线,就像绘画中的勾勒。大部分2D上下文操作都需要使用填充或者描边来完成路径的渲染,从而将图形展示到页面上。填充和描边操作的结果依赖fillStyle和strokeStyle这两个属性。这两个属性的值可以是字符串、渐变对象或模式对象,默认值为'#000000',如果需要将这两个属性的值表示为颜色,可以使用css中指定颜色值的任何格式,比如颜色名、十六进制码、rgb.......
1 <script> 2 // 获取画布 3 var canvas = document.getElementById('my-canvas'); 4 // 判断浏览器是否支持<canvas>元素 5 if (canvas.getContext) { 6 // 获取绘图上下文(画笔) 7 var ctx = canvas.getContext('2d'); 8 // 设置填充色 9 ctx.fillStyle = "red"; 10 // 设置描边色 11 ctx.strokeStyle = "#999"; 12 } 13 </script>
上面的代码中,设置了fillStyle为'red',设置了strokeStyle为'#999',后面所有涉及到fill()和stroke()的操作都将使用这两个样式,直到重新设置了这两个值。
4、绘制矩形
矩形是唯一一个可以直接绘制的形状。与绘制矩形相关的有三个方法:
- fillRect(x, y, width, height):绘制实心矩形(自带填充操作),矩形颜色由fillStyle指定
- strokeRect(x, y, width, height):绘制空心矩形(自带描边操作),矩形边框颜色由strokeStyle指定
- clearRect(x, y, width, height):清除指定位置、指定大小的矩形区域
以上三个方法都有四个参数,分别表示:矩形的x坐标,矩形的y坐标、矩形的宽度、矩形的高度,且,这些参数的单位都是px。注意哦,(x, y)这个坐标表示的是矩形左上角顶点的位置。
1 var canvas = document.getElementById('my-canvas'); 2 if (canvas.getContext) { 3 var ctx = canvas.getContext('2d'); 4 // 设置填充色 5 ctx.fillStyle = "red"; 6 // 设置描边色 7 ctx.strokeStyle = "#999"; 8 // 绘制实心矩形 9 ctx.fillRect(10, 10, 100, 50); 10 // 绘制空心矩形 11 ctx.strokeRect(150, 10, 100, 50); 12 }
如上图,绘制了一个红色的实心矩形和一个灰色边框的矩形,接下来调用clearRect()方法清除指定区域
ctx.clearRect(20, 20, 30, 30)
5、绘制路径
图形的基本元素是路径。路径由线段或者曲线相连接形成的不同形状的点的集合。每一个路径都是闭合的。使用路径绘制图形不同于矩形绘制,他需要一些额外的步骤:
- 创建路径起始点
- 调用绘制方法绘制路径
- 封闭路径
- 通过填充或者描边路径区域来渲染图形
下面是涉及到的方法:
- beginPath():表示要开始绘制新路径
- moveTo(x, y):将画笔移动到指定坐标(x,y),相当于设置路径的起始点坐标,此时不画线
- lineTo(x, y):绘制一条从当前位置到(x, y)的直线
- arc(x, y, radius, startAngle, endAngle, counterclockwise):以(x, y)为圆心,绘制一条半径为radius的弧线,且弧的起始角度为startAngle,结束角度为endAngle。counterclockwise表示是否逆时针绘制,默认值为false(顺时针)
- arcTo(x1, y1, x2, y2, radius):以radius为半径,从当前位置绘制一条弧到(x2, y2),且当前位置以及(x2, y2) 与(x1, y1)的连线分别与弧相切
- quadraticCurveTo(cx, cy, x, y):绘制二次贝塞尔曲线
- bezierCurveTo(cx1, cy1, cx2, cy2, x, y):绘制三次贝塞尔曲线
- closePath():闭合路径,此时图形绘制命令又重新指向到上下文中。
- fill():填充
- stroke():描边
下面是一些具体的栗子
5.1 绘制线段
1 var canvas = document.getElementById('my-canvas'); 2 if (canvas.getContext) { 3 var ctx = canvas.getContext('2d'); 4 ctx.beginPath(); // 新建一条path 5 ctx.moveTo(10, 30); // 画笔移动到(10, 30) 6 ctx.lineTo(100, 30); // 绘制一条从当前位置(10, 30)到(100, 30)的直线 7 ctx.closePath(); // 闭合路径 8 ctx.stroke(); // 绘制路径 9 }
5.2 绘制三角形
1 var canvas = document.getElementById('my-canvas'); 2 if (canvas.getContext) { 3 var ctx = canvas.getContext('2d'); 4 ctx.beginPath(); 5 ctx.moveTo(10, 30); 6 ctx.lineTo(100, 30); 7 ctx.lineTo(10, 100); 8 ctx.closePath(); // 虽然只绘制了两条线段,但是closePath会闭合路径。就形成了一个三角形 9 ctx.stroke(); // 描边 10 11 ctx.beginPath(); 12 ctx.moveTo(120, 30); 13 ctx.lineTo(220, 30); 14 ctx.lineTo(120, 100); 15 ctx.closePath(); 16 ctx.fill(); // 填充,实心三角形 17 }
5.3 绘制圆弧
5.3.1 使用arc()绘制圆弧
这个方法涉及到弧度取值问题,注意,是弧度,不是角度哦。
弧度计算公式:弧度 = 弧长 / 半径 = (n * π * r /180) / r = (n * π) / 180 ,其中n为圆心角
将上面的数学计算公式转换为JS表示的计算公式,可以得出:弧度 = Math.PI * (n / 180),其中n为圆心角,也就是我们通常所说的角度。因此如果是45度角,则弧度为Math.PI / 4。
确定好弧度之后,我们还需要知道画弧的起始点,如下图:
圆弧demo1
1 var canvas = document.getElementById('my-canvas'); 2 if (canvas.getContext) { 3 var ctx = canvas.getContext('2d'); 4 ctx.beginPath(); 5 ctx.arc(100, 100, 100, 0, Math.PI / 2, false); // 以(100, 100)为圆心顺时针绘制一个半径为100像素的弧,开始和结束弧度分别为0、Math.PI/2 6 ctx.stroke(); // 没有调用closePath(),因此弧度不闭合 7 }
圆弧demo2
1 var canvas = document.getElementById('my-canvas'); 2 if (canvas.getContext) { 3 var ctx = canvas.getContext('2d'); 4 ctx.beginPath(); 5 ctx.arc(100, 100, 100, 0, Math.PI / 2, true); // 以(100, 100)为圆心逆时针绘制一个半径为100的圆弧,开始和结束角度为0、Math.PI/2 6 ctx.stroke(); 7 }
圆弧demo3
1 var canvas = document.getElementById('my-canvas'); 2 if (canvas.getContext) { 3 var ctx = canvas.getContext('2d'); 4 ctx.beginPath(); 5 ctx.arc(50, 50, 50, 0, 2 * Math.PI); 6 ctx.closePath(); 7 ctx.stroke(); 8 9 ctx.beginPath(); 10 ctx.arc(150, 50, 50, 0, 2 * Math.PI); 11 ctx.closePath(); 12 ctx.fill(); 13 }
5.3.2 使用arcTo()绘制圆弧
arcTo(x1, y1, x2, y2, radius)是用来绘制两条切线之间的弧。两条切线分别是:当前位置与(x1, y1)的连线、(x2, y2)与(x1, y1)的连线。
1 var canvas = document.getElementById('my-canvas'); 2 if (canvas.getContext) { 3 var ctx = canvas.getContext('2d'); 4 ctx.beginPath(); 5 ctx.moveTo(50, 50); 6 ctx.arcTo(200, 50, 200, 200, 100); 7 ctx.lineTo(200, 200); 8 ctx.stroke(); 9 }