<canvas> 标签定义图形,比如图表和其他图像

<canvas> 标签只是图形容器,您必须使用脚本来绘制图形

<canvas> 就是画布的意思,我们用脚本代码在上面作画,什么东西都能画

<canvas> 性能特别高,适用于大型动画、游戏

<canvas> 就是一个普通的标签,有 width 和 height 属性和 img 类似,不能用 css 去改变其宽高,只能用 width 和 height 属性去改变

<canvas> 的图形上下文:getContext(“2d”)

<canvas> 里面的路径操作只是一个范围,没有图形,路径圈起来后还需要描边或者填充才能出现图形

和路径相关的

  • moveTo(); //画笔移动到某一个点(起点位置)
  • lineTo(); //画到下一个点(终点位置)
  • beginPath(); //清除之前所有的路径,如果不清除的话,之前的路径是会重汇的,表现就是画过的有颜色的线条会被新的颜色所覆盖
  • 如果想要封口,不应该 lineTo 到起点,应该用 closePath() 代替,作用是闭合路径

简单运用路径画一个封口的三角形例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Title</title>
<style>
body{background:#000;text-align: center;}
#canvas1{background-color: white;}
</style>
</head>
<body>
<canvas id="canvas1" width="500" height="500" >
您的浏览器不支持 canvas
</canvas>
<script>
let c1 = document.getElementById("canvas1");
let gd = c1.getContext("2d");
gd.moveTo(100,100);//路径操作,移动画笔到
gd.lineTo(200,200);//路径操作,描线
gd.lineTo(100,300);//路径操作,描线
// gd.lineTo(100,100);//路径操作,描线
gd.closePath();//封口
gd.strokeStyle = "red";//描边颜色,只要是css里面认的颜色写法,canvas都是认识的
gd.lineWidth = '10';
gd.stroke();//画线
gd.fillStyle = "yellow";//填充颜色
gd.fill();//填充

gd.beginPath();//清除之前的路径
gd.strokeStyle = 'green';//设置线条的颜色
gd.moveTo(400,400);//起点
gd.lineTo(500,500);//终点
gd.stroke();//画线
</script>
</body>
</html>

一个简单的画板例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>画板例子</title>
<style>
body{background:#000;text-align: center;}
#canvas1{background-color: white;}
</style>
</head>
<body>
<input type="color" id="color01" /><br>
<canvas id="canvas1" width="800" height="800" >
您的浏览器不支持 canvas
</canvas>
<script>
window.onload = function() {
let c1 = document.getElementById("canvas1");
let gd = c1.getContext("2d");
let color = document.getElementById('color01');
color.onchange = function() {
color = this.value;//获取线条颜色
};
c1.onmousedown = function(ev) {
let lastX = ev.offsetX;
let lastY = ev.offsetY;
c1.onmousemove = function(ev) {
gd.beginPath();//清除路径,防止颜色重汇
gd.moveTo(lastX,lastY);//起点位置
gd.lineTo(ev.offsetX,ev.offsetY);//终点位置
lastX = ev.offsetX;//改变起点坐标
lastY = ev.offsetY;//改变起点坐标
gd.strokeStyle = color;//应用颜色
gd.stroke();//画线
}
};
c1.onmouseup = function() {
c1.onmousemove = null;
};
};
</script>
</body>
</html>

画矩形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>canvas-画矩形</title>
<style>
body{background:#000;text-align: center;}
#canvas1{background-color: white;}
</style>
</head>
<body>
<canvas id="canvas1" width="800" height="800" >
您的浏览器不支持 canvas
</canvas>
<script>
window.onload = function() {
let c1 = document.getElementById("canvas1");
let gd = c1.getContext("2d");
//1.路径版的 矩形 用rect()
gd.rect(10,10,50,50);//指定矩形的左上角坐标 和 宽高属性
gd.stroke();
gd.fill();
//2.直接出图像的 矩形用 strokeRect() 和 fillRect()
gd.strokeRect(100,100,300,200);//描边矩形
gd.fillRect(350,350,300,200);//填充矩形
};
</script>
</body>
</html>

画弧

  • arc() 方法创建弧/曲线(用于创建圆或部分圆)
  • 如需通过 arc() 来创建圆,请把起始角设置为 0,结束角设置为 2*Math.PI
  • 因为 arc() 绘制的是路径,请使用 stroke() 或 fill() 方法在画布上绘制实际的弧
  • context.arc(x,y,r,startAngle,endAngle,counterclockwise);六个参数说明:1:圆心的X 2:圆心的Y 3:半径 4:开始角度(单位为弧度) 5:结束角度(弧度) 6:是否逆时针 true为逆时针 false为顺时针
  • 弧的圆形的三点钟位置是 0 度
    pic
    arc角度图示
  • 小例子-画弧
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>canvas-画弧</title>
    <style>
    body{background:#000;text-align: center;}
    #canvas1{background-color: white;}
    </style>
    </head>
    <body>
    <canvas id="canvas1" width="800" height="800" >
    您的浏览器不支持 canvas
    </canvas>
    <script>
    window.onload = function() {
    let c1 = document.getElementById("canvas1");
    let gd = c1.getContext("2d");
    //用arc(cx,cy,r,startAng,endAng,是否逆时针)
    //这里的开始角度和结束角度 用的是弧度单位 右边为 0
    //弧都是路径
    gd.arc(400,400,200,0*Math.PI/180,270*Math.PI/180,false);
    // gd.fill();
    gd.strokeStyle = 'red';
    gd.stroke();
    };
    </script>
    </body>
    </html>

画一个扇形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>canvas-画扇形</title>
<style>
body{background:#000;text-align: center;}
#canvas1{background-color: white;}
</style>
</head>
<body>
<canvas id="canvas1" width="800" height="800" >
您的浏览器不支持 canvas
</canvas>
<script>
window.onload = function() {
//degree to radian
function d2a(d) {
return d*Math.PI/180;
}
//radian to degree
function a2d(a) {
return a*180/Math.PI;
}
//任务:画弧
let c1 = document.getElementById("canvas1");
let gd = c1.getContext("2d");
//给定圆心坐标cx cy 半径 r 开始角度和结束角度 sang and eang
let cx = 400,cy = 400,r = 200, sang = 30,eang = 270;
//#画OA A点坐标
let ax = cx + r * Math.cos(d2a(360 - sang));
let ay = cy - r * Math.sin(d2a(360 - sang));
gd.moveTo(cx,cy);
gd.lineTo(ax,ay);
//#画AB 弧
gd.arc(cx,cy,r,d2a(sang),d2a(eang),false);//顺时针画
//#3 封口 OB
gd.closePath();
gd.strokeStyle = 'red';
gd.lineWidth = '10';
gd.stroke();
gd.fillStyle = 'green';
gd.fill();
};
</script>
</body>
</html>

按数组数字数据画饼图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>canvas-画饼图</title>
<style>
body{background:#000;text-align: center;}
#canvas1{background-color: white;}
</style>
</head>
<body>
<canvas id="canvas1" width="800" height="800" >
您的浏览器不支持 canvas
</canvas>
<script>
window.onload = function() {
//degree to radian
function d2a(d) {
return d*Math.PI/180;
}
//radian to degree
function a2d(a) {
return a*180/Math.PI;
}
let c1 = document.getElementById("canvas1");
let gd = c1.getContext("2d");
//封装一个画弧的函数
function paintRadian(x,y,cr,sd,ed,lineColor='#000',fillColor='#f60') {
gd.beginPath();
//给定圆心坐标cx cy 半径 r 开始角度和结束角度 sang and eang
let cx = x, cy = y, r = cr, sang = sd, eang = ed;
//#画OA A点坐标
let ax = cx + r * Math.cos(d2a(360 - sang));
let ay = cy - r * Math.sin(d2a(360 - sang));
gd.moveTo(cx,cy);
gd.lineTo(ax,ay);
//#画AB 弧
gd.arc(cx,cy,r,d2a(sang),d2a(eang),false);//顺时针画
//#3 封口 OB
gd.closePath();
gd.strokeStyle = lineColor;
// gd.lineWidth = '10';
// gd.stroke();
gd.fillStyle = fillColor;
gd.fill();
}
//给出已知条件 圆心 半径
let cx = 400,cy=400,r=200;
//# 数据以数组的形式给出
let data = [100,200,300,400,500];
let color = ['#f60','green','blue','#892314','#009865'];
//#1 要求出总和
let sumData = data.reduce((p,c,index,arr)=>p+c);
//求出每一项所占的百分比 (应该占的角度 )
let persent = data.map((item,index,arr)=>{return 360 * item / sumData});
//起始角度为0
let startAng = 0 ,lineC = '#000' ,fillC = 'white';
persent.forEach((item,index,arr)=>{
paintRadian(cx,cy,r,startAng,startAng+item,lineC,color[index]);
startAng += item;
});
};
</script>
</body>
</html>

canvas 通过擦除再重汇模拟动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>canvas-模拟动画</title>
<style>
body{background:#000;text-align: center;}
#canvas1{background-color: white;}
</style>
</head>
<body>
<canvas id="canvas1" width="800" height="800" >
您的浏览器不支持 canvas
</canvas>
<script>
window.onload = function() {
let c1 = document.getElementById("canvas1");
let gd = c1.getContext("2d");
let l = 50;
setInterval(function(){
gd.clearRect(0,0,c1.width,c1.height);//清楚全部canvas画布区域
gd.strokeRect(l,200,100,40);
l += 5;
},10);
};
</script>
</body>
</html>

canvas 碰撞检测-矩形

  • 造类似鼠标点击,悬浮等事件,如悬浮,给整个canvas加onmouseover事件,通过判断当前鼠标是否在矩形内部,来造所汇矩形的事件,其实浏览器里面的其他区块元素的事件的内部原理也是这个样子的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>canvas-矩形自己造一个mousenove事件</title>
<style>
body{background:#000;text-align: center;}
#canvas1{background-color: white;}
</style>
</head>
<body>
<canvas id="canvas1" width="800" height="800" >
您的浏览器不支持 canvas
</canvas>
<script>
window.onload = function() {
let c1 = document.getElementById("canvas1");
let gd = c1.getContext("2d");
let l=200,t=200,w=200,h=100;
gd.strokeRect(l,t,w,h);
c1.onmousemove = function (ev) {
gd.clearRect(0,0,c1.width,c1.height);
if (ev.offsetX>=l && ev.offsetX<=l+w && ev.offsetY>=t && ev.offsetY<=t+h) {
gd.strokeStyle = '#f00';
gd.strokeRect(l,t,w,h);
} else {
gd.strokeStyle = '#000';
gd.strokeRect(l,t,w,h);
}
};
};
</script>
</body>
</html>

canvas 碰撞检测-圆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>canvas-给圆造一个mousenove事件</title>
<style>
body{background:#000;text-align: center;}
#canvas1{background-color: white;}
</style>
</head>
<body>
<canvas id="canvas1" width="800" height="800" >
您的浏览器不支持 canvas
</canvas>
<script>
window.onload = function() {
let c1 = document.getElementById("canvas1");
let gd = c1.getContext("2d");
let cx = 400,cy=400,r=200;
gd.arc(cx,cy,r,0 ,Math.PI*2,false);
gd.stroke();
c1.onmousemove = function (ev) {
gd.clearRect(0,0,c1.width,c1.height);
if ( Math.sqrt((ev.offsetX - cx)*(ev.offsetX - cx) + (ev.offsetY - cy)*(ev.offsetY - cy))<=r ) {
gd.strokeStyle = '#f00';
gd.stroke();
} else {
gd.strokeStyle = '#000';
gd.stroke();
}
};
};
</script>
</body>
</html>

canvas 变换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>canvas-变换的应用</title>
<style>
body{background:#000;text-align: center;}
#canvas1{background-color: white;}
</style>
</head>
<body>
<canvas id="canvas1" width="800" height="800" >
您的浏览器不支持 canvas
</canvas>
<script>
function d2a(d) {
return d*Math.PI/180;
}
window.onload = function() {
let c1 = document.getElementById("canvas1");
let gd = c1.getContext("2d");
let l = 200,t = 200,w = 400,h = 200;
gd.strokeRect(l,t,w,h);
let rotate = 0;
setInterval(function(){
gd.clearRect(0,0,c1.width,c1.height);
gd.save();
//这里其实是先旋转后 移动的
gd.translate(w/2 + l,h/2 + t);
gd.rotate(d2a(rotate++));//旋转画布一定的弧度

gd.strokeRect(-w/2,-h/2,w,h);

gd.restore();
},16);
};
</script>
</body>
</html>

注意

  • canvas 的属性 width 和 height 是决定绘图区的大小的,而在 css 样式里面 width 和height 是决定这个元素显示多大的,二者是不同的,建议用属性去定义
  • canvas 里面的图形只要画完了是不能修改的,要想修改,只有擦除后再重新画
  • canvas 不会保存任何图形的信息,这也是其性能高的原因,这是两方面的,不能修改,交互和拥有事件,如果想要这些东西,可以考虑 SVG 或者一些库
  • 碰撞检测对于矩形或圆是很简单的,可以检查在正多边形的内还是外,以及异型,可以看看包围检查方面的,思路:看点是否在线的同一侧
  • 使用路径操作的时候记得beginPath() , 在变换操作的还是记得 save() 和 restore()
  • 放大镜的思路:两张图片,一大一小,利用鼠标移动上去,位置变换