canvas是什么?
简单来说,<canvas> 是HTML5中的标签,它是一个容器,可以使用JS在其中绘制图形或文字。
MDN:<canvas>是一个可以使用脚本 (通常为JavaScript) 来绘制图形的 HTML 元素。例如,它可以用于绘制图表、制作图片构图或者制作简单的动画。主要聚焦于2D图形。
预备知识
canvas标签本身
canvas标签是一张画布,如果你写了一个canvas标签,打开live server,在支持canvas的浏览器上显示是这样的:
你可能会问怎么啥都没有呢?因为canvas标签只是一个默认长300像素,宽150像素的白色画布,你可以给它加上页面居中和box-shadow
的css样式:
如果你觉得这个画布太小了,施展不开,那么你可以通过标签属性来自定义宽高:
<canvas height="600" width="700"></canvas>
设置后:
这里注意,设置画布的宽高只能在html标签里通过height和width属性来设置(canvas标签有且只有这两个属性),如果你在css中设置:
canvas {
height: 600px;
width: 700px;
}
上边的这种方式只是将画布拉伸变形了,就好像拿放大镜看一样,会导致失真,其实它本质上的大小并没有变化,比如:
所以canvas的宽高还是要在html中使用标签属性设置。
支持的浏览器
那么如果你的浏览器不支持canvas呢?那么你canvas标签中的文字就派上用场了,浏览器上会显示出你canvas标签里的文字,比如:
<canvas>你的浏览器不支持canvas,快去升级浏览器吧!</canvas>
(为了演示方便,以下教程全部默认浏览器支持canvas,且给画布加上了居中和阴影效果。)
详细教程
基本步骤
我们以现实生活中画水墨画为例:如果我们要画一幅画,要有以下的准备步骤:
①首先要有一用来画画的纸;
②找到这张纸;
③决定是画二维还是三维的画
类比于canvas,也是这样的几个步骤:
①首先要有一用来画画的纸:
<!-- 创建canvas标签: -->
<canvas id="canvas" height="600" width="700"></canvas>
②找到这张纸:
// 我们现在要使用JS获得这个canvas标签的DOM对象:
<script>
const canvas = document.getElementById('canvas')
</script>
③决定是画二维还是三维的画:
// 通过getContext()方法来获得渲染上下文和它的绘画功能:
<script>
const ctx = canvas.getContext('2d') // 这里我们先聚焦于2D图形
</script>
坐标系
Canvas
使用的是 W3C 坐标系 ,也就是遵循我们屏幕、报纸的阅读习惯,从上往下,从左往右。
已经做好了准备工作,接下来就可以开始画画了!
一、绘制基础图形
1. 画线段
画线之前你需要知道canvas上下文的以下几个api:
moveTo(x,y)
:定义画线的起始点;
lineTo(x,y)
:定义画线的折点;
stroke()
:通过线条来绘制图形轮廓
完整代码:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.moveTo(200, 300) // 起点为(200,300)
ctx.lineTo(500, 300)
ctx.stroke()
</script>
当然,你也可以同时画多条折线:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.moveTo(10, 300)
ctx.lineTo(100, 300)
ctx.lineTo(100, 200)
ctx.lineTo(200, 200)
ctx.lineTo(200, 300)
ctx.lineTo(300, 300)
ctx.lineTo(300, 200)
ctx.lineTo(400, 200)
ctx.lineTo(400, 300)
ctx.lineTo(500, 300)
ctx.stroke()
// 绘制第二条:
ctx.moveTo(100, 400)
ctx.lineTo(500, 500)
ctx.stroke()
</script>
给线段设置样式
strokeStyle = '颜色'
:设置线的颜色;
lineWidth = 数字
:设置线的宽度;
lineCap = 'round/butt/square'
:设置线帽为圆型/默认/方形;
lineJoin = 'miter/round/bevel'
:设置线段连接处为默认/圆形/平直形式;
globalAlpha = 数字
:设置图案的透明度
一个简单的示例,设置一条线的线宽:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d")
ctx.moveTo(200, 300)
ctx.lineTo(500, 300)
ctx.lineWidth = 10 // 设置线宽为10像素
ctx.stroke()
</script>
显示:
这里有一个地方需要注意,就是样式的设置必须写在绘制图形轮廓(stroke()
)方法之前!否则会不生效!(因为stroke()
方法是进行绘制,如果已经绘制了再设置线段的样式,自然会不生效)
同时画多条线并分别设置样式
如果现在你画了两条宽20 像素圆角的线,并且想一条设置为红色,一条设置为天蓝色,那么你可能会这样写:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.moveTo(200, 200)
ctx.lineTo(500, 200)
ctx.strokeStyle = 'skyblue' // 设置为天蓝色
ctx.lineWidth = 20
ctx.lineCap = 'round'
ctx.stroke()
// 绘制第二条线:
ctx.moveTo(200, 300)
ctx.lineTo(500, 300)
ctx.strokeStyle = 'red'
ctx.lineWidth = 20
ctx.lineCap = 'round'
ctx.stroke()
</script>
但是显示的会是这样:
两条线都显示的是红色,这是因为第二条线的颜色“覆盖”了第一条线的颜色。如果我们想分别设置每条线的样式,就需要用到下面两个方法:
beginPath()
:开启一条新路径,生成之后,图形绘制命令会被指向到新路径上;
closePath()
:关闭上一条路径的绘制
在每条路径开始和结束的时候加上这两个方法即可分别设置两条线的样式:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.moveTo(200, 200)
ctx.lineTo(500, 200)
ctx.strokeStyle = 'skyblue' // 设置为天蓝色
ctx.lineWidth = 20
ctx.lineCap = 'round'
ctx.stroke()
ctx.closePath()
// 绘制第二条线:
ctx.beginPath()
ctx.moveTo(200, 300)
ctx.lineTo(500, 300)
ctx.strokeStyle = 'red'
ctx.lineWidth = 20
ctx.lineCap = 'round'
ctx.stroke()
ctx.closePath()
</script>
显示:
综合示例:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d")
ctx.beginPath()
ctx.moveTo(150, 200)
ctx.lineTo(250, 100)
ctx.lineTo(350, 200)
ctx.lineTo(450, 100)
ctx.lineTo(550, 200)
ctx.lineWidth = 20
ctx.strokeStyle = 'skyblue' // 设置颜色为天蓝色
ctx.lineCap = 'round' // 设置线帽为圆形
ctx.lineJoin = 'miter' // 设置线段连接处为默认形式
ctx.stroke()
ctx.beginPath()
ctx.moveTo(150, 350)
ctx.lineTo(250, 250)
ctx.lineTo(350, 350)
ctx.lineTo(450, 250)
ctx.lineTo(550, 350)
ctx.lineWidth = 10
ctx.strokeStyle = 'red' // 设置线段颜色为红色
ctx.lineCap = 'square' // 设置线帽为方形
ctx.lineJoin = 'round' // 设置线段连接处为圆形
ctx.stroke()
ctx.beginPath()
ctx.moveTo(150, 500)
ctx.lineTo(250, 400)
ctx.lineTo(350, 500)
ctx.lineTo(450, 400)
ctx.lineTo(550, 500)
ctx.lineWidth = 30
ctx.strokeStyle = '#a37400' // 设置线段颜色
ctx.lineCap = 'butt' // 设置线帽为默认形式
ctx.lineJoin = 'bevel' // 设置线段连接处为平直的形式
ctx.stroke()
ctx.beginPath()
ctx.arc(350, 300, 300, 0, [(Math.PI) / 180] * 360)
ctx.globalAlpha = 0.3 // 设置圆的透明度为0.3
ctx.fillStyle = 'skyblue'
ctx.fill()
</script>
显示:
p.s.:其实在画第二条线的时候只需要开启(beginPath()
)新路径即可,两条线仍然可以分别设置样式,但是为了规范起见,还是建议写上closePath()
2. 画三角形
画三角形其实也是用画线的思路,只需要注意首尾点连接起来即可:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.moveTo(200, 200)
ctx.lineTo(500, 200)
ctx.lineTo(500, 500)
ctx.lineTo(200, 200) // 第四个点要和第一个点的坐标一致才能画出三角形
ctx.stroke()
ctx.closePath()
</script>
显示:
如果要设置样式也和画线是一样的:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.moveTo(200, 200)
ctx.lineTo(500, 200)
ctx.lineTo(500, 500)
ctx.lineTo(200, 200)
ctx.strokeStyle = 'skyblue'
ctx.lineWidth = 20
ctx.stroke()
ctx.closePath()
</script>
显示:
可能有人会想把三角形左上角的闭合处显示的更衔接一点,那么我们可以使用closePath()
方法,它会把线段的终点和起点连接起来,这样看上去就更更衔接了:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.moveTo(200, 200)
ctx.lineTo(500, 200)
ctx.lineTo(500, 500)
ctx.closePath()
ctx.strokeStyle = 'skyblue'
ctx.lineWidth = 20
ctx.stroke()
</script>
显示:
3. 画矩形
(1)空心矩形
绘制矩形有三种方法,第一种和画三角形的思路一样,比如:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.moveTo(200, 150)
ctx.lineTo(500, 150)
ctx.lineTo(500, 450)
ctx.lineTo(200, 450)
ctx.lineTo(200, 150)
ctx.stroke()
ctx.closePath()
</script>
显示:
第二种方法是直接使用ctx
身上的strokeRect()
方法:
例如:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.strokeRect(200, 150, 300, 300) // 起点为(200,150),宽300像素,高300像素
ctx.closePath()
</script>
显示:
第三种方法和第二种类似,只是把strokeRect()
方法拆成了stroke()
和rect()
方法,好处就是使用rect()
暂时生成了矩形,但是必须调用stroke()
方法才会绘制出来,比如可以使用下面的方式延迟两秒钟再绘制矩形:
<canvas id="canvas" height="600" width="700"></canvas>
<script>
const canvas &#