前言:
说到canvas,对于前端工程师来说并不陌生,但真正会的并没有几个,因为一般情况下用的会很少。但如果真正用到就会第一时间去百度又要一个一个代码试半天,费时又费力。此文抱着学习的态度带你去探究canvas的2d图形绘制奥义,带你去领略它的神奇之处。
绘制斜线:
- html部分:
<canvas id="canvas" width="500" height="500">您的浏览器不支持 HTML5 canvas 标签。</canvas>
注:请注意宽度和高度是没有单位的而且是内联的,如果通过style设置css并设置px单位会出现未知错误。
- css部分:
body{
width: 100vw;
height: 100vh;
display: flex;
}
#canvas{
border: 1px solid #333;
margin: auto;
}
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.moveTo(100,100);//定义起点坐标
ctx.lineTo(400,400);//定义终点坐标
ctx.stroke();//执行绘制函数
}
- 效果展示:

斜线颜色和宽度设置:
- html部分:
<canvas id="canvas" width="500" height="500">您的浏览器不支持 HTML5 canvas 标签。</canvas>
- css部分:
body{
width: 100vw;
height: 100vh;
display: flex;
}
#canvas{
border: 1px solid #333;
margin: auto;
}
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.moveTo(100,100);//定义起点坐标
ctx.lineTo(400,400);//定义终点坐标
ctx.lineWidth = 5;//线条宽度
ctx.strokeStyle = '#058';//线条颜色
ctx.stroke();//执行绘制函数
}
- 效果展示:

折线绘制:
前言:HTML部分和css部分不会做更改,后续会直接在前面的画布中作图,所以后续只会写js代码
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.moveTo(100,100);//定义起点坐标
ctx.lineTo(400,400);//定义终点坐标
ctx.lineTo(100,400);//定义终点坐标
ctx.stroke();//执行绘制函数
}
- 效果展示:

不封闭的箭头:
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.moveTo(200,200);//定义起点坐标
ctx.lineTo(300,200);//定义终点坐标
ctx.lineTo(300,150);//定义终点坐标
ctx.lineTo(350,220);//定义终点坐标
ctx.lineTo(300,290);//定义终点坐标
ctx.lineTo(300,240);//定义终点坐标
ctx.lineTo(200,240);//定义终点坐标
ctx.stroke();//执行绘制函数
}
- 效果展示:

3个箭头:
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.moveTo(100,150);//定义起点坐标
ctx.lineTo(200,250);//定义终点坐标
ctx.lineTo(100,350);//定义终点坐标
ctx.moveTo(150,150);//定义起点坐标
ctx.lineTo(250,250);//定义终点坐标
ctx.lineTo(150,350);//定义终点坐标
ctx.moveTo(200,150);//定义起点坐标
ctx.lineTo(300,250);//定义终点坐标
ctx.lineTo(200,350);//定义终点坐标
ctx.stroke();//执行绘制函数
}
- 效果展示:

绘制不同颜色的3个箭头:
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.lineWidth = 5;//线条宽度
ctx.beginPath();//指定第一条路径
ctx.moveTo(100,150);//定义起点坐标
ctx.lineTo(200,250);//定义终点坐标
ctx.lineTo(100,350);//定义终点坐标
ctx.strokeStyle = 'red';//线条颜色
ctx.stroke();//执行绘制函数
ctx.beginPath();//指定第二条路径
ctx.moveTo(150,150);//定义起点坐标
ctx.lineTo(250,250);//定义终点坐标
ctx.lineTo(150,350);//定义终点坐标
ctx.strokeStyle = 'green';//线条颜色
ctx.stroke();//执行绘制函数
ctx.beginPath();//指定第三条路径
ctx.moveTo(200,150);//定义起点坐标
ctx.lineTo(300,250);//定义终点坐标
ctx.lineTo(200,350);//定义终点坐标
ctx.strokeStyle = 'blue';//线条颜色
ctx.stroke();//执行绘制函数
}
- 效果展示:

带填充色的封闭的箭头:
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.lineWidth = 2;//线条宽度
ctx.strokeStyle = '#058';//线条颜色
ctx.beginPath();//指定路径
ctx.moveTo(200,200);//定义起点坐标
ctx.lineTo(300,200);//定义终点坐标
ctx.lineTo(300,150);//定义终点坐标
ctx.lineTo(350,220);//定义终点坐标
ctx.lineTo(300,290);//定义终点坐标
ctx.lineTo(300,240);//定义终点坐标
ctx.lineTo(200,240);//定义终点坐标
ctx.closePath();//封闭路径
ctx.fillStyle = 'yellow';//设置封闭图形的填充颜色
ctx.fill();//填充颜色
ctx.stroke();//执行绘制函数
}
注:如果绘制路径不在ctx.beginPath()和ctx.closePath()中间,会出现一个几像素的缺口,只有在线条足够粗的时候才能看见。
- 效果展示:

矩形绘制函数:
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
//绘制矩形的绘制函数:
function drawRectangle(ctx,x=0,y=0,width=100,height=100,borderW=1,borderC='#333',bgC='yellow') {
//此函数我用es6语法加了默认参数最简单的调用就是传个绘制环境就好了drawRectangle(ctx);
/*参数说明:ctx绘制环境;x,y起点坐标;width,height矩形的宽高;borderW,borderC边框宽度及颜色;bgC填充色。*/
ctx.beginPath();//指定路径
ctx.moveTo(x,y);//定义起点坐标
ctx.lineTo(x+width,y);//定义终点坐标
ctx.lineTo(x+width,y+height);//定义终点坐标
ctx.lineTo(x,y+height);//定义终点坐标
ctx.closePath();//封闭路径
ctx.lineWidth = borderW;//线条宽度
ctx.strokeStyle = borderC;//线条颜色
ctx.fillStyle = bgC;//设置封闭图形的填充颜色
ctx.fill();//填充颜色
ctx.stroke();//执行绘制函数
}
drawRectangle(ctx,250,250);//传参绘制
}
- 效果展示:

用自带api创建矩形绘制函数:
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
//绘制矩形的绘制函数:
function drawRectangle(ctx,x=0,y=0,width=100,height=100,borderW=1,borderC='#333',bgC='yellow') {
//此函数我用es6语法加了默认参数最简单的调用就是传个绘制环境就好了drawRectangle(ctx);
/*参数说明:ctx绘制环境;x,y起点坐标;width,height矩形的宽高;borderW,borderC边框宽度及颜色;bgC填充色。*/
ctx.lineWidth = borderW;//线条宽度
ctx.strokeStyle = borderC;//线条颜色
ctx.fillStyle = bgC;//设置封闭图形的填充颜色
ctx.fillRect(x,y,width,height);
ctx.strokeRect(x,y,width,height);
}
drawRectangle(ctx);//传参绘制
}
- 效果展示:

重叠透明的矩形:
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
//绘制矩形的绘制函数:
function drawRectangle(ctx,x=0,y=0,width=100,height=100,borderW=1,borderC='#333',bgC='yellow') {
//此函数我用es6语法加了默认参数最简单的调用就是传个绘制环境就好了drawRectangle(ctx);
/*参数说明:ctx绘制环境;x,y起点坐标;width,height矩形的宽高;borderW,borderC边框宽度及颜色;bgC填充色。*/
ctx.lineWidth = borderW;//线条宽度
ctx.strokeStyle = borderC;//线条颜色
ctx.fillStyle = bgC;//设置封闭图形的填充颜色
ctx.fillRect(x,y,width,height);
ctx.strokeRect(x,y,width,height);
}
drawRectangle(ctx);//传参绘制
drawRectangle(ctx,50,50,100,100,1,'#333','rgba(0,0,0,0.1)');//传参绘制
}
- 效果展示:

不同顶端形状的线条:
此属性只用于线条的开始处和结尾处
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.lineWidth = 50;//线条宽度
ctx.strokeStyle = '#058';//线条颜色
ctx.beginPath();//指定路径
ctx.moveTo(100,100);//定义起点坐标
ctx.lineTo(400,100);//定义终点坐标
ctx.lineCap = 'butt'; //默认
ctx.stroke();//执行绘制函数
ctx.beginPath();//指定路径
ctx.moveTo(100,250);//定义起点坐标
ctx.lineTo(400,250);//定义终点坐标
ctx.lineCap = 'round'; //圆头
ctx.stroke();//执行绘制函数
ctx.beginPath();//指定路径
ctx.moveTo(100,400);//定义起点坐标
ctx.lineTo(400,400);//定义终点坐标
ctx.lineCap = 'square'; //方头
ctx.stroke();//执行绘制函数
}
- 效果展示:

画一个五角星:
画五角星之前先给大家复习一下数学知识,否则此例数学不好会看不懂:
- 图例1:

deg为三角形的度数
正弦:sin(deg) = y(对边)/r(斜边)
余弦:cos(deg) = x(领边)/r(斜边)
- 图例2:

- 图解:
//大圆五角星顶点度数18的由来:
90-360/5=18
释义:大圆以供360度,大圆上一共5个点平均每个点相差72度,90度的点减去72则为第一个点的度数
//18度点x长度:
x=cos18*R //cos(deg) = x(领边)/r(斜边)
//18度点y长度:
y=-sin18*R //sin(deg) = y(对边)/r(斜边)
//小圆五角星顶点度数54的由来:
270+72*2-360=54
释义:小圆最底部点为270度,往右推2个点为第一个小圆的顶点,每个点相差72度,加起来之后减去360即为第一个点的度数
//54度点x长度:
x=cos54*r //cos(deg) = x(领边)/r(斜边)
//54度点y长度:
y=-sin54*r //sin(deg) = y(对边)/r(斜边)
- 具体代码:
前言:请注意js的sin和cos都是弧度制,必须转化为弧度制计算:弧度 = 度数/180*PI
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.lineWidth = 5;//线条宽度
ctx.strokeStyle = '#058';//线条颜色
ctx.beginPath();//指定路径
for (var i = 0; i < 5; i++) {
ctx.lineTo(Math.cos((18+i*72)/180*Math.PI)*200+250,-Math.sin((18+i*72)/180*Math.PI)*200+250);//定义终点坐标
ctx.lineTo(Math.cos((54+i*72)/180*Math.PI)*100+250,-Math.sin((54+i*72)/180*Math.PI)*100+250);//定义终点坐标
}
ctx.closePath();//封闭路径
ctx.stroke();//执行绘制函数
}
- 提升代码复用性:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.lineWidth = 5;//线条宽度
ctx.strokeStyle = '#058';//线条颜色
drawStar(ctx,100,200,250,250);
function drawStar(ctx,r,R,x,y){
ctx.beginPath();//指定路径
for (var i = 0; i < 5; i++) {
ctx.lineTo(Math.cos((18+i*72)/180*Math.PI)*R+x,-Math.sin((18+i*72)/180*Math.PI)*R+y);//定义终点坐标
ctx.lineTo(Math.cos((54+i*72)/180*Math.PI)*r+x,-Math.sin((54+i*72)/180*Math.PI)*r+y);//定义终点坐标
}
ctx.closePath();//封闭路径
ctx.stroke();//执行绘制函数
}
}
- 带旋转参数的五角星:
//函数封装
function drawStar(ctx,r,R,x,y,rot){
//rot为旋转,x、y为偏移量,r为小圆的五角星坐标,R为大圆的五角星坐标
ctx.beginPath();//指定路径
for (var i = 0; i < 5; i++) {
ctx.lineTo(Math.cos((18+i*72-rot)/180*Math.PI)*R+x,-Math.sin((18+i*72-rot)/180*Math.PI)*R+y);//定义终点坐标
ctx.lineTo(Math.cos((54+i*72-rot)/180*Math.PI)*r+x,-Math.sin((54+i*72-rot)/180*Math.PI)*r+y);//定义终点坐标
}
ctx.closePath();//封闭路径
ctx.stroke();//执行绘制函数
}
- 效果展示:

线条的连接:
1.js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.lineWidth = 5;//线条宽度
ctx.strokeStyle = '#058';//线条颜色
// ctx.lineJoin = 'bevel';//斜接
ctx.lineJoin = 'round';//圆角
drawStar(ctx,60,200,250,250);
//函数封装
function drawStar(ctx,r,R,x,y,rot=0){
//rot为旋转,x、y为偏移量,r为小圆的五角星坐标,R为大圆的五角星坐标
ctx.beginPath();//指定路径
for (var i = 0; i < 5; i++) {
ctx.lineTo(Math.cos((18+i*72-rot)/180*Math.PI)*R+x,-Math.sin((18+i*72-rot)/180*Math.PI)*R+y);//定义终点坐标
ctx.lineTo(Math.cos((54+i*72-rot)/180*Math.PI)*r+x,-Math.sin((54+i*72-rot)/180*Math.PI)*r+y);//定义终点坐标
}
ctx.closePath();//封闭路径
ctx.stroke();//执行绘制函数
}
}
- 效果示例:

画一片星空
前言:请将canvas的背景颜色设置为#000
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
ctx.lineWidth = 1;//线条宽度
ctx.strokeStyle = '#333';//线条颜色
// ctx.lineJoin = 'bevel';//斜接
ctx.lineJoin = 'round';//圆角
for(var i=0;i<200;i++){
var R = Math.random()*10+10;
var r = R/2.0;
var x = Math.random()*canvas.width;
var y = Math.random()*canvas.height;
var rot = Math.random()*360;
drawStar(ctx,r,R,x,y,rot);
}
//函数封装
function drawStar(ctx,r,R,x,y,rot=0){
//rot为旋转,x、y为偏移量,r为小圆的五角星坐标,R为大圆的五角星坐标
ctx.beginPath();//指定路径
for (var i = 0; i < 5; i++) {
ctx.lineTo(Math.cos((18+i*72-rot)/180*Math.PI)*R+x,-Math.sin((18+i*72-rot)/180*Math.PI)*R+y);//定义终点坐标
ctx.lineTo(Math.cos((54+i*72-rot)/180*Math.PI)*r+x,-Math.sin((54+i*72-rot)/180*Math.PI)*r+y);//定义终点坐标
}
ctx.fillStyle = 'yellow';//设置封闭图形的填充颜色
ctx.fill();//填充颜色
ctx.closePath();//封闭路径
ctx.stroke();//执行绘制函数
}
}
- 效果展示:

位置偏移后的bug:
偏移量是进行叠加的,在默认情况下: 1.js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
//绘制矩形的绘制函数:
function drawRectangle(ctx,x=0,y=0,width=100,height=100,borderW=1,borderC='#333',bgC='yellow') {
//此函数我用es6语法加了默认参数最简单的调用就是传个绘制环境就好了drawRectangle(ctx);
/*参数说明:ctx绘制环境;x,y起点坐标;width,height矩形的宽高;borderW,borderC边框宽度及颜色;bgC填充色。*/
ctx.lineWidth = borderW;//线条宽度
ctx.strokeStyle = borderC;//线条颜色
ctx.fillStyle = bgC;//设置封闭图形的填充颜色
ctx.translate(x,y);//图形位置偏移
ctx.fillRect(0,0,width,height);
ctx.strokeRect(0,0,width,height);
}
drawRectangle(ctx,100,100);//传参绘制
drawRectangle(ctx,100,100,100,100,1,'#333','green');//传参绘制
}
- 效果展示:

解决偏移量叠加的bug:
1.js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
//绘制矩形的绘制函数:
function drawRectangle(ctx,x=0,y=0,width=100,height=100,borderW=1,borderC='#333',bgC='yellow') {
//此函数我用es6语法加了默认参数最简单的调用就是传个绘制环境就好了drawRectangle(ctx);
/*参数说明:ctx绘制环境;x,y起点坐标;width,height矩形的宽高;borderW,borderC边框宽度及颜色;bgC填充色。*/
ctx.save();//保存当前绘制状态
ctx.lineWidth = borderW;//线条宽度
ctx.strokeStyle = borderC;//线条颜色
ctx.fillStyle = bgC;//设置封闭图形的填充颜色
ctx.translate(x,y);//图形位置偏移
ctx.fillRect(0,0,width,height);//绘制填充的形状
ctx.strokeRect(0,0,width,height);//绘制边框的形状
ctx.restore();//返回所有状态
}
drawRectangle(ctx,100,100);//传参绘制
drawRectangle(ctx,100,100,50,50,1,'#333','green');//传参绘制
}
- 效果展示:

五角星通过图形变换旋转和偏移
使用缩放时请将图形的外边框设置去掉,否则图形的外边框也会随着放大
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
for(var i=0;i<200;i++){
var R = Math.random()*10+10;
var x = Math.random()*canvas.width;
var y = Math.random()*canvas.height;
var rot = Math.random()*360;
drawStar(ctx,R,x,y,rot);
}
//执行具体的绘制参数:
function drawStar(ctx,R,x,y,rot){
ctx.save();//保存当前绘制状态
ctx.translate(x,y);//移动图形的位置坐标
ctx.rotate(rot/180*Math.PI);//旋转
ctx.scale(0.5,0.5);//缩放
ctx.fillStyle = 'yellow';//设置封闭图形的填充颜色
// ctx.lineWidth = 1;//线条宽度
// ctx.strokeStyle = '#333';//线条颜色
// ctx.lineJoin = 'bevel';//斜接
// ctx.lineJoin = 'round';//圆角
starPath(ctx,R);//绘制
ctx.fill();//填充颜色
ctx.stroke();//执行绘制函数
ctx.restore();//返回所有绘制状态
}
//封装五角星的绘制路径
function starPath(ctx,R){
//rot为旋转,x、y为偏移量,r为小圆的五角星坐标,R为大圆的五角星坐标
ctx.beginPath();//指定路径
for (var i = 0; i < 5; i++) {
ctx.lineTo(Math.cos((18+i*72)/180*Math.PI)*R,-Math.sin((18+i*72)/180*Math.PI)*R);//定义终点坐标
ctx.lineTo(Math.cos((54+i*72)/180*Math.PI)*R*0.5,-Math.sin((54+i*72)/180*Math.PI)*R*0.5);//定义终点坐标
}
ctx.closePath();//封闭路径
}
}
- 效果展示:

变换矩阵
transform变换矩阵如果十多个的话会产生级联,这个时候只需要调用setTransform,这个时候会先将其设置成最初无变化的单位矩阵,然后将单位矩阵进行变换
- js部分:
window.onload = function() {
var canvas = document.getElementById('canvas');//获取dom节点
//console.log(canvas);
var ctx=canvas.getContext("2d");//绘制2d图形
for(var i=0;i<200;i++){
var R = Math.random()*10+10;
var x = Math.random()*canvas.width;
var y = Math.random()*canvas.height;
var rot = Math.random()*360;
drawStar(ctx,R,x,y,rot);
}
//执行具体的绘制参数:
function drawStar(ctx,R,x,y,rot){
ctx.save();//保存当前绘制状态
//transform(a,b,c,d,e,f);
// a水平缩放[1],b水平倾斜[0],c垂直倾斜[0],d垂直缩放[1],e水平位移[0],f垂直位移[0],[]中括号中为默认值
ctx.rotate(rot/180*Math.PI);//旋转
ctx.transform(0.5,0,0,0.5,x,y);
ctx.fillStyle = 'yellow';//设置封闭图形的填充颜色
// ctx.lineWidth = 1;//线条宽度
// ctx.strokeStyle = '#333';//线条颜色
// ctx.lineJoin = 'bevel';//斜接
// ctx.lineJoin = 'round';//圆角
starPath(ctx,R);//绘制
ctx.fill();//填充颜色
ctx.stroke();//执行绘制函数
ctx.restore();//返回所有绘制状态
}
//封装五角星的绘制路径
function starPath(ctx,R){
//rot为旋转,x、y为偏移量,r为小圆的五角星坐标,R为大圆的五角星坐标
ctx.beginPath();//指定路径
for (var i = 0; i < 5; i++) {
ctx.lineTo(Math.cos((18+i*72)/180*Math.PI)*R,-Math.sin((18+i*72)/180*Math.PI)*R);//定义终点坐标
ctx.lineTo(Math.cos((54+i*72)/180*Math.PI)*R*0.5,-Math.sin((54+i*72)/180*Math.PI)*R*0.5);//定义终点坐标
}
ctx.closePath();//封闭路径
}
}
- 效果展示:

参考文献:
后记:
此篇文章,由于本人最近比较忙没有写完,后续有空了会继续完成的,如果可以的话点个赞,谢谢!