在前端领域,如果只是懂 Vue 或者 React ,未来在职场的竞争力可能会比较弱。
根据我多年在家待业履历来看,前端未来在 数据可视化 和 AI 这两个领域会比较喷鼻香,而 Canvas 是数据可视化在前端方面的根本技能。
本文就用光的速率将 canvas 给入门了。
要入门一个技能,前期最主要是快!
以是本文只讲入门内容,能搪塞大略项目。深入的知识点会在其他文章讲解。
Canvas 是什么?Canvas 中文名叫 “画布”,是 HTML5 新增的一个标签。Canvas 许可开拓者通过 JS在这个标签上绘制各种图案。Canvas 拥有多种绘制路径、矩形、圆形、字符以及图片的方法。Canvas 在某些情形下可以 “代替” 图片。Canvas 可用于动画、游戏、数据可视化、图片编辑器、实时视频处理等领域。
Canvas 和 SVG 的差异Canvas
SVG
用JS动态天生元素(一个HTML元素)
用XML描述元素(类似HTML元素那样,可用多个元向来描述一个图形)
位图(受屏幕分辨率影响)
矢量图(不受屏幕分辨率影响)
不支持事宜
支持事宜
数据发生变革须要重绘
不须要重绘
就上面的描述而言可能有点难懂,你可以打开 AntV 旗下的图形编辑引擎做比拟。G6 是利用 canvas 开拓的,X6 是利用 svg 开拓的。
我的建议是:如果要展示的数据量比较大,比如一条数据便是一个元素节点,那利用 canvas 会比较得当;如果用户操作的交互比较多,而且对清晰度有哀求(矢量图),那么利用 svg 会比较得当。
起步
学习前端一定要动手敲代码,然后看效果展示。
起步阶段会用几句代码解释 canvas 如何利用,本例会画一条直线。
画条直线在 HTML 中创建 canvas 元素通过 js 获取 canvas 标签从 canvas 标签中获取到绘图工具通过绘图工具,在 canvas 标签上绘制图形
<!-- 1、创建 canvas 元素 --><canvas id="c" width="300" height="200" style="border: 1px solid #ccc;"></canvas><script> // 2、获取 canvas 工具 const cnv = document.getElementById('c') // 3、获取 canvas 高下文环境工具 const cxt = cnv.getContext('2d') // 4、绘制图形 cxt.moveTo(100, 100) // 出发点坐标 (x, y) cxt.lineTo(200, 100) // 终点坐标 (x, y) cxt.stroke() // 将出发点和终点连接起来</script>
moveTo 、 lineTo 和 stroke 方法暂时可以不用管,它们的浸染是绘制图形,这些方法在后面会讲到~
把稳点1、默认宽高
canvas 有 默认的 宽度(300px) 和 高度(150px)
如果不在 canvas 上设置宽高,那 canvas 元素的默认宽度是300px,默认高度是150px。
2、设置 canvas 宽高
canvas 元素供应了 width 和 height 两个属性,可设置它的宽高。
须要把稳的是,这两个属性只需传入数值,不须要传入单位(比如 px 等)。
<canvas width="600" height="400"></canvas>
利用 css 设置 canvas 的宽高,会涌现 内容被拉伸 的后果!
!
!
<style> #c { width: 400px; height: 400px; border: 1px solid #ccc; }</style><canvas id="c"></canvas><script> // 1、获取canvas工具 const cnv = document.getElementById('c') // 2、获取canvas高下文环境工具 const cxt = cnv.getContext('2d') // 3、绘制图形 cxt.moveTo(100, 100) // 出发点 cxt.lineTo(200, 100) // 终点 cxt.stroke() // 将出发点和终点连接起来 console.log(cnv.width) // 获取 canvas 的宽度,输出:300 console.log(cnv.height) // 获取 canvas 的高度,输出:150</script>
canvas 的默认宽度是300px,默认高度是150px。
如果利用 css 修正 canvas 的宽高(比如本例变成 400px 400px),那宽度就由 300px 拉伸到 400px,高度由 150px 拉伸到 400px。利用 js 获取 canvas 的宽高,此时返回的是 canvas 的默认值。末了涌现的效果如上图所示。
4、线条默认宽度和颜色
线条的默认宽度是 1px ,默认颜色是玄色。
但由于默认情形下 canvas 会将线条的中央点和像素的底部对齐,以是会导致显示效果是 2px 和非纯玄色问题。
5、IE兼容性高
暂时只有 IE 9 以上才支持 canvas 。但好是 IE 已经有自己的墓碑了。
如需兼容 IE 7 和 8 ,可以利用 ExplorerCanvas 。但纵然是利用了 ExplorerCanvas 仍旧会有所限定,比如无法利用 fillText() 方法等。
根本图形坐标系
在绘制根本图形之前,须要先搞打消 Canvas 利用的坐标系。
Canvas 利用的是 W3C 坐标系 ,也便是遵照我们屏幕、报纸的阅读习气,从上往下,从左往右。
W3C 坐标系 和 数学直角坐标系 的 X轴 是一样的,只是 Y轴 的反向相反。
W3C 坐标系 的 Y轴 正方向向下。
直线一条直线
最大略的起步办法是画一条直线。这里所说的 “直线” 是几何学里的 “线段” 的意思。
须要用到这3个方法:
moveTo(x1, y1):出发点坐标 (x, y)lineTo(x2, y2):下一个点的坐标 (x, y)stroke():将所有坐标用一条线连起来起步阶段可以先这样理解。
<canvas id="c" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 绘制直线 cxt.moveTo(50, 100) // 出发点坐标 cxt.lineTo(200, 50) // 下一个点的坐标 cxt.stroke() // 将上面的坐标用一条线连接起来</script>
上面的代码所呈现的效果,可以看下图阐明(手不太聪明,画得不是很标准,希望能看懂)
多条直线
如需画多条直线,可以用会上面那几个方法。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.moveTo(20, 100) cxt.lineTo(200, 100) cxt.stroke() cxt.moveTo(20, 120.5) cxt.lineTo(200, 120.5) cxt.stroke()</script>
仔细不雅观察一下,为什么两条线的粗细不一样的?
明明利用的方法都是一样的,只是第二条直线的 Y轴 的值是有小数点。
答:默认情形下 canvas 会将线条的中央点和像素的底部对齐,以是会导致显示效果是 2px 和非纯玄色问题。
上图每个格子代表 1px。
线的中央点会和画布像素点的底部对齐,以是会线中间是玄色的,但由于一个像素就不能再切割了,以是会有半个像素被染色,就变成了浅灰色。
以是如果你设置的 Y轴 值是一个整数,就会涌现上面那种情形。
设置样式lineWidth:线的粗细strokeStyle:线的颜色lineCap:线帽:默认: butt; 圆形: round; 方形: square
<canvas id="c" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 绘制直线 cxt.moveTo(50, 50) cxt.lineTo(200, 50) // 修端正线的宽度 cxt.lineWidth = 20 // 修端正线的颜色 cxt.strokeStyle = 'pink' // 修端正线两端样式 cxt.lineCap = 'round' // 默认: butt; 圆形: round; 方形: square cxt.stroke()</script>
开辟新路径的方法:
beginPath()在绘制多条线段的同时,还要设置线段样式,常日须要开辟新路径。
要不然样式之间会相互污染。
比如这样
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 第一条线 cxt.moveTo(20, 100) cxt.lineTo(200, 100) cxt.lineWidth = 10 cxt.strokeStyle = 'pink' cxt.stroke() // 第二条线 cxt.moveTo(20, 120.5) cxt.lineTo(200, 120.5) cxt.stroke()</script>
如果不想相互污染,须要做2件事:
利用 beginPath() 方法,重新开一个路径设置新线段的样式(必须项)如果上面2步却了个中1步都会有影响。
只利用 beginPath()<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 第一条线 cxt.moveTo(20, 100) cxt.lineTo(200, 100) cxt.lineWidth = 10 cxt.strokeStyle = 'pink' cxt.stroke() // 第二条线 cxt.beginPath() // 重新开启一个路径 cxt.moveTo(20, 120.5) cxt.lineTo(200, 120.5) cxt.stroke()</script>
第一条线的样式会影响之后的线。
但如果利用了 beginPath() ,后面的线段不会影响前面的线段。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 第一条线 cxt.moveTo(20, 100) cxt.lineTo(200, 100) cxt.stroke() // 第二条线 cxt.beginPath() // 重新开启一个路径 cxt.moveTo(20, 120.5) cxt.lineTo(200, 120.5) cxt.lineWidth = 4 cxt.strokeStyle = 'red' cxt.stroke()</script>
这个情形会反过来,后面的线能影响前面的线。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 第一条线 cxt.moveTo(20, 100) cxt.lineTo(200, 100) cxt.lineWidth = 10 cxt.strokeStyle = 'pink' cxt.stroke() // 第二条线 cxt.moveTo(20, 120.5) cxt.lineTo(200, 120.5) cxt.lineWidth = 4 cxt.strokeStyle = 'red' cxt.stroke()</script>
在设置 beginPath() 的同时,也各自设置样式。这样就能做到相互不影响了。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.moveTo(20, 100) cxt.lineTo(200, 100) cxt.lineWidth = 10 cxt.strokeStyle = 'pink' cxt.stroke() cxt.beginPath() // 重新开启一个路径 cxt.moveTo(20, 120.5) cxt.lineTo(200, 120.5) cxt.lineWidth = 4 cxt.strokeStyle = 'red' cxt.stroke()</script>
和 直线 差不多,都是利用 moveTo() 、lineTo() 和 stroke() 方法可以绘制折线。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.moveTo(50, 200) cxt.lineTo(100, 50) cxt.lineTo(200, 200) cxt.lineTo(250, 50) cxt.stroke()</script>
画这种折线,最好在草稿纸上画一个坐标系,自己打算并描述一下每个点大概在什么什么位置,末了在 canvas 中看看效果。
矩形
根据前面的根本,我们可以 利用线段来描述矩形,但 canvas 也供应了 rect() 等方法可以直接天生矩形。
利用线段描述矩形
可以利用前面画线段的方法来绘制矩形
canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 绘制矩形 cxt.moveTo(50, 50) cxt.lineTo(200, 50) cxt.lineTo(200, 120) cxt.lineTo(50, 120) cxt.lineTo(50, 50) // 须要闭合,又或者利用 closePath() 方法进行闭合,推举利用 closePath() cxt.stroke()</script>
上面的代码几个点分别对应下图。
利用 strokeRect() 描边矩形strokeStyle:设置描边的属性(颜色、渐变、图案)strokeRect(x, y, width, height):描边矩形(x和y是矩形左上角出发点;width 和 height 是矩形的宽高)strokeStyle 必须写在 strokeRect() 前面,不然样式不生效。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // strokeStyle 属性 // strokeRect(x, y, width, height) 方法 cxt.strokeStyle = 'pink' cxt.strokeRect(50, 50, 200, 100)</script>
上面的代码可以这样理解
利用 fillRect() 添补矩形
fillRect() 和 strokeRect() 方法差不多,但 fillRect() 的浸染是添补。
须要把稳的是,fillStyle 必须写在 fillRect() 之前,不然样式不生效。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // fillStyle 属性 // fillRect(x, y, width, height) 方法 cxt.fillStyle = 'pink' cxt.fillRect(50, 50, 200, 100) // fillRect(x, y, width, height)</script>
同时利用 strokeRect() 和 fillRect() 会产生描边和添补的效果
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.strokeStyle = 'red' cxt.strokeRect(50, 50, 200, 100) // strokeRect(x, y, width, height) cxt.fillStyle = 'yellow' cxt.fillRect(50, 50, 200, 100) // fillRect(x, y, width, height)</script>
rect() 和 fillRect() 、strokeRect() 的用法差不多,唯一的差异是:
strokeRect() 和 fillRect() 这两个方法调用后会立即绘制;rect() 方法被调用后,不会急速绘制矩形,而是须要调用 stroke() 或 fill() 赞助渲染。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.strokeStyle = 'red' cxt.fillStyle = 'pink' cxt.rect(50, 50, 200, 100) // rect(x, y, width, height) cxt.stroke() cxt.fill()</script>
等价公式:
cxt.strokeStyle = 'red',cxt.rect(50, 50, 200, 100)cxt.stroke()// 等价于cxt.strokeStyle = 'red'cxt.strokerect(50, 50, 200, 100)// -----------------------------cxt.fillStyle = 'hotpink'cxt.rect(50, 50, 200, 100)cxt.fill()// 等价于cxt.fillStyle = 'yellowgreen'cxt.fillRect(50, 50, 200, 100)
利用 clearRect() 方法可以清空指定区域。
clearRect(x, y, width, height)
其语法和创建 cxt.rect() 差不多。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.fillStyle = 'pink' // 设置添补颜色 cxt.fillRect(50, 50, 200, 200) // 添补矩形 cxt.clearRect(60, 60, 180, 90) // 清空矩形</script>
canvas 画布元素是矩形,以是可以通过下面的代码把全体画布清空掉。
// 省略部分代码cxt.clearRect(0, 0, cnv.width, cnv.height)
要清空的区域:从画布左上角开始,直到画布的宽和画布的高为止。
多边形
Canvas 要画多边形,须要利用 moveTo() 、 lineTo() 和 closePath() 。
三角形
虽然三角形是常见图形,但 canvas 并没有供应类似 rect() 的方法来绘制三角形。
须要确定三角形3个点的坐标位置,然后利用 stroke() 或者 fill() 方法天生三角形。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.moveTo(50, 50) cxt.lineTo(200, 50) cxt.lineTo(200, 200) // 把稳点:如果利用 lineTo 闭合图形,是不能很好闭合拐角位的。 cxt.lineTo(50, 50) // 闭合 cxt.stroke()</script>
把稳,默认情形下不会自动从末了一个点连接到出发点。末了一步须要设置一下 cxt.lineTo(50, 50) ,让它与 cxt.moveTo(50, 50) 一样。这样可以让路径回到出发点,形成一个闭合效果。
但这样做实在是有点问题的,而且也比较麻烦,要记住起始点坐标。
上面的闭合操作,如果碰着设置了 lineWidth 或者 lineJoin 就会有问题,比如:
// 省略部分代码cxt.lineWidth = 20
当线段变粗后,起始点和结束点的链接处,拐角就涌现“不正常”征象。
如果须要真正闭合,可以利用 closePath() 方法。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.moveTo(50, 50) cxt.lineTo(200, 50) cxt.lineTo(200, 200) // 手动闭合 cxt.closePath() cxt.lineJoin = 'miter' // 线条连接的样式。miter: 默认; bevel: 斜面; round: 圆角 cxt.lineWidth = 20 cxt.stroke()</script>
利用 cxt.closePath() 可以自动将终点和起始点连接起来,此时看上去就正常多了。
菱形
有一组邻边相等的平行四边形是菱形
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.moveTo(150, 50) cxt.lineTo(250, 100) cxt.lineTo(150, 150) cxt.lineTo(50, 100) cxt.closePath() cxt.stroke()</script>
要绘制直线类型的图形,在草稿纸上标记出起始点和每个拐角的点,然后再连线即可。相对曲线图形来说,直线图形是比较随意马虎的。
圆形
绘制圆形的方法是 arc()。
语法:
arc(x, y, r, sAngle, eAngle,counterclockwise)
x 和 y: 圆心坐标r: 半径sAngle: 开始角度eAngle: 结束角度counterclockwise: 绘制方向(true: 逆时针; false: 顺时针),默认 false
开始角度和结束角度,都因此弧度为单位。例如 180°就写成 Math.PI ,360°写成 Math.PI 2 ,以此类推。
在实际开拓中,为了让自己或者别的开拓者更随意马虎看懂弧度的数值,1°该当写成 Math.PI / 180。
100°: 100 Math.PI / 180110°: 110 Math.PI / 180241°: 241 Math.PI / 180把稳:绘制圆形之前,必须先调用 beginPath() 方法!
!
!
在绘制完成之后,还须要调用 closePath() 方法!
!
!
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.beginPath() cxt.arc(150, 150, 80, 0, 360 Math.PI / 180) cxt.closePath() cxt.stroke()</script>
如果利用 arc() 方法画圆时,没做到刚好绕完一周(360°)就直接闭合路径,就会涌现半圆的状态。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.beginPath() cxt.arc(150, 150, 100, 0, 180 Math.PI / 180) // 顺时针 cxt.closePath() cxt.stroke()</script>
上面的代码中,cxt.arc 末了一个参数没传,默认是 false ,所以是顺时针绘制。
如果希望半圆的弧面在上方,可以将 cxt.arc 末了一个参数设置成 true
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.beginPath() cxt.arc(150, 150, 100, 0, 180 Math.PI / 180, true) cxt.closePath() cxt.stroke()</script>
利用 arc() 方法画半圆时,如果末了不调用 closePath() 方法,就不会涌现闭合路径。也便是说,那是一条弧线。
在 canvas 中,画弧线有2中方法:arc() 和 arcTo() 。
arc() 画弧线
如果想画一条 0° ~ 30° 的弧线,可以这样写
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.beginPath() cxt.arc(150, 150, 100, 0, 30 Math.PI / 180) cxt.stroke()</script>
事理如下图所示,红线代表画出来的那条弧线。
arcTo() 画弧线
arcTo() 的利用方法会更加繁芜,如果初学看不太懂的话可以先跳过,看完后面的再回来补补。
语法:
arcTo(cx, cy, x2, y2, radius)
cx: 两切线交点的横坐标cy: 两切线交点的纵坐标x2: 结束点的横坐标y2: 结束点的纵坐标radius: 半径
个中,(cx, cy) 也叫掌握点,(x2, y2) 也叫结束点。
是不是有点奇怪,为什么没有 x1 和 y1 ?
(x1, y1) 是开始点,常日是由 moveTo() 或者 lineTo() 供应。
arcTo() 方法利用 开始点、掌握点和结束点形成的夹角,绘制一段与夹角的两边相切并且半径为 radius 的圆弧。
举个例子
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.moveTo(40, 40) cxt.arcTo(120, 40, 120, 120, 80) cxt.stroke()</script>
前面学完根本图形,接下来可以开始理解一下如何设置元素的根本样式。
描边 stroke()
前面的案例中,实在已经知道利用 stroke() 方法进行描边了。这里就不再多讲这个方法。
线条宽度 lineWidth
lineWidth 默认值是 1 ,默认单位是 px。
语法:
lineWidth = 线宽
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 线宽 10 cxt.beginPath() cxt.moveTo(50, 50) cxt.lineTo(250, 50) cxt.lineWidth = 10 // 设置线宽 cxt.stroke() // 线宽 20 cxt.beginPath() cxt.moveTo(50, 150) cxt.lineTo(250, 150) cxt.lineWidth = 20 // 设置线宽 cxt.stroke() // 线宽 30 cxt.beginPath() cxt.moveTo(50, 250) cxt.lineTo(250, 250) cxt.lineWidth = 30 // 设置线宽 cxt.stroke()</script>
利用 strokeStyle 可以设置线条颜色
语法:
strokeStyle = 颜色值
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.moveTo(50, 50) cxt.lineTo(250, 50) cxt.lineWidth = 20 cxt.strokeStyle = 'pink' // 设置颜色 cxt.stroke()</script>
为了展示方便,我将 lineWidth 设为 20。
线帽 lineCap
线帽指的是线段的开始和结尾处的样式,利用 lineCap 可以设置
语法:
lineCap = '属性值'
属性值包括:
butt: 默认值,无线帽square: 方形线帽round: 圆形线帽<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 设置线宽,方便演示 cxt.lineWidth = 16 // 默认线帽 butt cxt.beginPath() cxt.moveTo(50, 60) cxt.lineTo(250, 60) cxt.stroke() // 方形线帽 square cxt.beginPath() cxt.lineCap = 'square' cxt.moveTo(50, 150) cxt.lineTo(250, 150) cxt.stroke() // 圆形线帽 round cxt.beginPath() cxt.lineCap = 'round' cxt.moveTo(50, 250) cxt.lineTo(250, 250) cxt.stroke()</script>
利用 square 和 round 的话,会使线条变得轻微长一点点,这是给线条增加线帽的部分,这个长度在日常开拓中须要把稳。
线帽只对线条的开始和结尾处产生浸染,对拐角不会产生任何浸染。
拐角样式 lineJoin
如果须要设置拐角样式,可以利用 lineJoin 。
语法:
lineJoin = '属性值'
属性值包括:
miter: 默认值,尖角round: 圆角bevel: 斜角<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.lineWidth = 20 // 默认,尖角 cxt.moveTo(50, 40) cxt.lineTo(200, 40) cxt.lineTo(200, 90) cxt.stroke() // 斜角 bevel cxt.beginPath() cxt.moveTo(50, 140) cxt.lineTo(200, 140) cxt.lineTo(200, 190) cxt.lineJoin = 'bevel' cxt.stroke() // 圆角 round cxt.beginPath() cxt.moveTo(50, 240) cxt.lineTo(200, 240) cxt.lineTo(200, 290) cxt.lineJoin = 'round' cxt.stroke()</script>
利用 setLineDash() 方法可以将描边设置成虚线。
语法:
setLineDash([])
须要传入一个数组,且元素是数值型。
虚线分3种情形
只传1个值有2个值有3个以上的值<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.lineWidth = 20 cxt.strokeStyle = 'pink' cxt.moveTo(50, 50) cxt.lineTo(200, 50) cxt.setLineDash([10]) // 只传1个参数,实线与空缺都是 10px cxt.stroke() cxt.beginPath() cxt.moveTo(50, 100) cxt.lineTo(200, 100) cxt.setLineDash([10, 20]) // 2个参数,此时,实线是 10px, 空缺 20px cxt.stroke() cxt.beginPath() cxt.moveTo(50, 150) cxt.lineTo(200, 150) cxt.setLineDash([10, 20, 5]) // 传3个以上的参数,此例:10px实线,20px空缺,5px实线,10px空缺,20px实线,5px空缺 …… cxt.stroke()</script>
此外,还可以始终 cxt.getLineDash() 获取虚线不重复的间隔;
用 cxt.lineDashOffset 设置虚线的偏移位。
添补
利用 fill() 可以添补图形,根据前面的例子该当节制了如何利用 fill()
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.fillStyle = 'pink' cxt.rect(50, 50, 200, 100) cxt.fill()</script>
可以利用 fillStyle 设置添补颜色,默认是玄色。
非零环抱添补
在利用 fill() 方法添补时,须要把稳一个规则:非零环抱添补。
在利用 moveTo 和 lineTo 描述图形时,如果是按顺时针绘制,计数器会加1;如果是逆时针,计数器会减1。
当图形所处的位置,计数器的结果为0时,它就不会被添补。
这样说有点繁芜,先看看例子
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 外层矩形 cxt.moveTo(50, 50) cxt.lineTo(250, 50) cxt.lineTo(250, 250) cxt.lineTo(50, 250) cxt.closePath() // 内层矩形 cxt.moveTo(200, 100) cxt.lineTo(100, 100) cxt.lineTo(100, 200) cxt.lineTo(200, 200) cxt.closePath() cxt.fill()</script>
请看看上面的代码,我画了2个矩形,它们都没有用 beginPath() 方法开辟新路径。
内层矩形是逆时针绘制的,以是内层的值是 -1 ,它又经由外层矩形,而外层矩形是顺时针绘制,以是经由外层市价 +1,终极内层的值为 0 ,以是不会被添补。
文本
Canvas 供应了一些操作文本的方法。
为了方便演示,我们先理解一下在 Canvas 中如何给本文设置样式。
样式 font
和 CSS 设置 font 差不多,Canvas 也可以通过 font 设置样式。
语法:
cxt.font = 'font-style font-variant font-weight font-size/line-height font-family'
如果须要设置字号 font-size,须要同事设置 font-family。
cxt.font = '30px 宋体'
利用 strokeText() 方法进行文本描边
语法:
strokeText(text, x, y, maxWidth)
text: 字符串,要绘制的内容x: 横坐标,文本左边要对齐的坐标(默认左对齐)y: 纵坐标,文本底边要对齐的坐标maxWidth: 可选参数,表示文本渲染的最大宽度(px),如果文本超出 maxWidth 设置的值,文本会被压缩。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.font = '60px Arial' // 将字号设置成 60px,方便不雅观察 cxt.strokeText('雷猴', 30, 90)</script>
利用 strokeStyle 设置描边颜色。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.font = '60px Arial' // 将字号设置成 60px,方便不雅观察 cxt.strokeStyle = 'pink' // 设置文本描边颜色 cxt.strokeText('雷猴', 30, 90)</script>
利用 fillText() 可添补文本。
语法和 strokeText() 一样。
fillText(text, x, y, maxWidth)
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.font = '60px Arial' cxt.fillText('雷猴', 30, 90)</script>
利用 fillStyle 可以设置文本添补颜色。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') cxt.font = '60px Arial' cxt.fillStyle = 'pink' cxt.fillText('雷猴', 30, 90)</script>
measureText().width 方法可以获取文本的长度,单位是 px 。
<canvas id="c" width="300" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') let text = '雷猴' cxt.font = 'bold 40px Arial' cxt.fillText(text, 40, 80) console.log(cxt.measureText(text).width) // 80</script>
利用 textAlign 属性可以设置笔墨的水平对齐办法,一共有5个值可选
start: 默认。在指定位置的横坐标开始。end: 在指定坐标的横坐标结束。left: 左对齐。right: 右对齐。center: 居中对齐。红线是赞助参考线。
<canvas id="c" width="400" height="400" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 竖向的赞助线(参考线,在画布中间) cxt.moveTo(200, 0) cxt.lineTo(200, 400) cxt.strokeStyle = 'red' cxt.stroke() cxt.font = '30px Arial' // 横坐标开始位对齐 cxt.textAlign = 'start' // 默认值, cxt.fillText('雷猴 start', 200, 40) // 横坐标结束位对齐 cxt.textAlign = 'end' // 结束对齐 cxt.fillText('雷猴 end', 200, 100) // 左对齐 cxt.textAlign = 'left' // 左对齐 cxt.fillText('雷猴 left', 200, 160) // 右对齐 cxt.textAlign = 'right' // 右对齐 cxt.fillText('雷猴 right', 200, 220) // 居中对齐 cxt.textAlign = 'center' // 右对齐 cxt.fillText('雷猴 center', 200, 280)</script>
从上面的例子看,start 和 left 的效果彷佛是一样的,end 和 right 也彷佛是一样的。
在大多数情形下,它们的确一样。但在某些国家或者某些场合,阅读笔墨的习气是 从右往左 时,start 就和 right 一样了,end 和 left 也一样。这是须要把稳的地方。
垂直对齐办法 textBaseline
利用 textBaseline 属性可以设置笔墨的垂直对齐办法。
在利用 textBaseline 前,须要自行理解 css 的文本基线。
用一张网图阐明一下基线
textBaseline 可选属性:
alphabetic: 默认。文本基线是普通的字母基线。top: 文本基线是 em 方框的顶端。bottom: 文本基线是 em 方框的底端。middle: 文本基线是 em 方框的正中。hanging: 文本基线是悬挂基线。红线是赞助参考线。
<canvas id="c" width="800" height="300" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 横向的赞助线(参考线,在画布中间) cxt.moveTo(0, 150) cxt.lineTo(800, 150) cxt.strokeStyle = 'red' cxt.stroke() cxt.font = '20px Arial' // 默认 alphabetic cxt.textBaseline = 'alphabetic' cxt.fillText('雷猴 alphabetic', 10, 150) // 默认 top cxt.textBaseline = 'top' cxt.fillText('雷猴 top', 200, 150) // 默认 bottom cxt.textBaseline = 'bottom' cxt.fillText('雷猴 bottom', 320, 150) // 默认 middle cxt.textBaseline = 'middle' cxt.fillText('雷猴 middle', 480, 150) // 默认 hanging cxt.textBaseline = 'hanging' cxt.fillText('雷猴 hanging', 640, 150)</script>
把稳:在绘制笔墨的时候,默认因此笔墨的左下角作为参考点进行绘制
图片
在 Canvas 中可以利用 drawImage() 方法绘制图片。
渲染图片
渲染图片的办法有2中,一种是在JS里加载图片再渲染,另一种是把DOM里的图片拿到 canvas 里渲染。
渲染的语法:
drawImage(image, dx, dy)
image: 要渲染的图片工具。dx: 图片左上角的横坐标位置。dy: 图片左上角的纵坐标位置。
在 JS 里加载图片并渲染,有以下几个步骤:
创建 Image 工具引入图片等待图片加载完成利用 drawImage() 方法渲染图片<canvas id="c" width="500" height="500" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') // 1 创建 Image 工具 const image = new Image() // 2 引入图片 image.src = './images/dog.jpg' // 3 等待图片加载完成 image.onload = () => { // 4 利用 drawImage() 方法渲染图片 cxt.drawImage(image, 30, 30) }</script>
<style> #dogImg { display: none; }</style><img src="./images/dog.jpg" id="dogImg"/><canvas id="c" width="500" height="500" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') const image = document.getElementById('dogImg') cxt.drawImage(image, 70, 70)</script>
由于图片是从 DOM 里获取到的,以是一样平常来说,只要在 window.onload 这个生命周期内利用 drawImage 都可以正常渲染图片。
本例利用了 css 的办法,把图片的 display 设置成 none 。由于我不想被 <img> 影响到本例讲解。
实际开拓过程中按照实际情形设置即可。
设置图片宽高
前面的例子都是直接加载图片,图片默认的宽高是多少就加载多少。
如果须要指定图片宽高,可以在前面的根本上再添加两个参数:
drawImage(image, dx, dy, dw, dh)
image、 dx、 dy 的用法和前面一样。
dw 用来定义图片的宽度,dh 定义图片的高度。
<canvas id="c" width="500" height="500" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') const image = new Image() image.src = './images/dog.jpg' image.onload = () => { cxt.drawImage(image, 30, 30, 100, 100) }</script>
我把图片的尺寸设为 100px 100px,图片看上去比之前就小了很多。
截取图片
截图图片同样利用drawImage() 方法,只不过传入的参数数量比之前都多,而且顺序也有点不一样了。
drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
以上参数缺一不可
image: 图片工具sx: 开始截取的横坐标sy: 开始截取的纵坐标sw: 截取的宽度sh: 截取的高度dx: 图片左上角的横坐标位置dy: 图片左上角的纵坐标位置dw: 图片宽度dh: 图片高度<canvas id="c" width="500" height="500" style="border: 1px solid #ccc;"></canvas><script> const cnv = document.getElementById('c') const cxt = cnv.getContext('2d') const image = new Image() image.src = './images/dog.jpg' image.onload = () => { cxt.drawImage(image, 0, 0, 100, 100, 30, 30, 200, 200) }</script>
本文紧张讲解了在 Canvas 中绘制一些根本图形,还有一些根本样式设置。
还有更多高等的玩法会在之后的文章中讲到,比如渐变、投影、滤镜等等。
代码仓库
⭐雷猴 Canvas
推举阅读
《Fabric.js 从入门到膨胀》
《『Three.js』起飞!
》
《console.log也能插图!
!
!
》
《纯css实现117个Loading效果》
《视差殊效的事理和实现方法》
《这18个网站能让你的页面背景炫酷起来》
点赞 + 关注 + 收藏 = 学会了