canvas


title: canvas画板

date: 2019-08-27 13:39:26

tags: html5

categories:  # 这里写的分类会自动汇集到 categories 页面上,分类可以多级

  • HTML5 # 一级分类
  • canvas # 二级分类

简介

canvas 本身没有绘图能力,只是定义了一个容器,都是由 canvas 内部的 CanvasRenderingContext2D 对象来做,需要我们用 JavaScript 脚本完成绘制工作。

基础

  1. html 引入<canvas>标签

<canvas id="canvas"></canvas>

  1. js 获取<canvas>属性,使用 2d 绘制上下文.
1
2
3
var canvas = getElementById("canvas");
var context = canvas.getContext("2d");
//使用context进行绘制
  1. 设置宽高

使用canvas.width设置宽度.

canvas.height设置高度.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<body>
<canvas id="canvas" sytle="border: 1px solid #aaa;display: block;margin: 50px auto;"></canvas>
<script>
window.onload = function(){
var canvas = document.getElementById("canvas")
canvas.width: 1024;
canvas.height: 768;
if(canvas.getContext("2d")){
//如果浏览器支持canvas,可以使用
var context = canvas.getContext("2d")
}else{
alert('当前浏览器不支持,请使用谷歌浏览器')
}
}
</script>
</body>

设置全屏

1
2
3
4
5
let pageWidth = document.documentElement.clientWidth;
let pageHeight = document.documentElement.clientHeight;

canvas.width = pageWidth;
canvas.height = pageHeight;

绘制线段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var context = canvas.getContext("2d");
conext.beginPath(); //开始第一段绘制,与其他绘制可以区别开
context.moveTo(100, 100); //以画布左上角为原点,从坐标(100,100)开始
context.lineTO(700, 700); //把线画到(700,700)位置
context.lineTO(100, 700); //折到(100,700)位置
context.lineTO(100, 100); //线段完成封闭,形成三角形
context.closePath(); //结束本段状态

context.fillStyle = "rgab(168,168,168)"; //设置三角形填充颜色
context.fill(); //执行填充颜色

context.lineWidth = 5; //设置线段宽度
context.strokeStyle = "red"; //设置线段颜色
context.stroke; //执行绘图

conext.beginPath(); //开始第二段绘制,与其他绘制可以区别开
context.moveTo(200, 100); //以画布左上角为原点,从坐标(200,100)开始
context.lineTO(700, 600); //把线画到(700,600)位置
context.closePath(); //结束本段状态

context.strokeStyle = "blue"; //设置线段颜色
context.stroke; //执行第二段绘图
  1. 标签属性

    标签 描述
    height 设置 canvas 的高度
    width 设置 canvas 的宽度
    fill() 可以填充
    fillRect(x,y,width,height) 绘制一个矩形边框
    fillRect(x,y,width,height) 绘制一个填充的矩形
    clearRect(x,y,width,height) 清除指定矩形区域,让清除部分完全透明
    ctx.strokeStyle 可以改变画笔颜色
    ctx.beginPath() 设置开始路径
    ctx.moveTo(x,y) 设置起点
    ctx.lineTo(x,y) 设置终点
    ctx.stroke() 绘制
    ctx.closePath() 结束路径
    ctx.arc(弧形圆心 x 坐标,y 坐标,半径,起始角(以 3 点钟的位置开始),结束角、方向(true 表示逆时针,false 表示顺时针)) 绘制一个弧形
    ctx.quadraticCurveTo(cpx,cpy,x,y)参数是控制点 x 坐标,控制点 y 坐标,结束点 x 坐标,结束点 y 坐标 绘制二次贝塞尔曲线
    ctx.quadraticCurveTo(cpx1,cpy1,cpx2,cpy2,x,y)参数是控制点 1 的 x 坐标,控制点 1 的 y 坐标,控制点 2 的 x 坐标,控制点 2 的 y 坐标,结束点 x 坐标,结束点 y 坐标 绘制三次贝塞尔曲线
  2. canvas 画板代码实现

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<canvas id="canvas"></canvas>
<div id="actions"class="actions x">

<svg id="pen"class="icon">
<use xlink:href="#icon-pencil"></use>
</svg>

<svg id="eraser"class="icon">
<use xlink:href="#icon-eraser"></use>
</svg>

<svg id="clear"class="icon">
<use xlink:href="#icon-delete"></use>
</svg>

<svg id="download"class="icon">
<use xlink:href="#icon-download"></use>
</svg>


<ul class='colorCir'>
<li id="black"class="black"></li>
<li id="red"class="red"></li>
<li id="yellow"class="yellow"></li>
<li id="blue"class="blue"></li>
</ul>

<ul class='lineWidth'>
<li id="thin" class="thin"></li>
<li id="thick" class="thick"></li>
</ul>
</div>
</body>
</html>

css

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
*{
margin:0;
padding:0;
}
body{
background:#eee
}
ul,ol{
list-style: none;
}

.colorCir{
top:60px;
left:20px;
position: fixed;
}
.colorCir li{
border: 1px solid grey;
height:20px;
width: 20px;
border-radius: 50%;
margin-bottom:10px;
}

.colorCir .red{
background:red;
}
.colorCir .yellow{
background:yellow;
}
.colorCir .blue{
background:blue;
}
.colorCir .black{
background:black;
}

.colorCir .red.active{
transform: scale(1.2);
transition: all 0.3s;
}
.colorCir .yellow.active{
transform: scale(1.2);
transition: all 0.3s;
}
.colorCir .blue.active{
transform: scale(1.2);
transition: all 0.3s;
}
.colorCir .black.active{
transform: scale(1.2);
transition: all 0.3s;
}

.icon {
width: 1em; height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}

body{
overflow: hidden;
}
#canvas{
display: block;
position: fixed;
top:0px;
left:0px;
}

.actions{
position: fixed;
top:0px;
left:0px;
padding-top:20px;
padding-left:15px;
}
.actions svg{
width:1.5em;
height:1.5em;
transition: all 0.3s;
margin:0 5px;
}

.actions svg.active{
fill:red;
transform: scale(1.2);
}

.lineWidth{
position: relative;
left:-10px;
top:140px;
}

.lineWidth .thin{
height:0px;
width:40px;
border-top:2px solid black;
margin:15px;
}

.lineWidth .thick{
height:0px;
width:40px;
border-top:6px solid black;
margin:15px;
}

.lineWidth .thin.active{
transform: scale(1.2);
}

.lineWidth .thick.active{
transform: scale(1.2);
}

js

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");

var using = false;
var lastPoint = {
x: undefined,
y: undefined,
};

/*画板逻辑 */
autoSetSize(canvas);

listenToUser(canvas);

/********/
//画笔、橡皮擦按钮替换
var eraserEnabled = false;

pen.onclick = function () {
eraserEnabled = false;
pen.classList.add("active");
eraser.classList.remove("active");
};
eraser.onclick = function () {
eraserEnabled = true;
eraser.classList.add("active");
pen.classList.remove("active");
};

//颜色替换并高亮
red.onclick = function () {
context.fillStyle = "red";
context.strokeStyle = "red";
red.classList.add("active");
yellow.classList.remove("active");
blue.classList.remove("active");
black.classList.remove("active");
};
yellow.onclick = function () {
context.fillStyle = "yellow";
context.strokeStyle = "yellow";
yellow.classList.add("active");
red.classList.remove("active");
blue.classList.remove("active");
black.classList.remove("active");
};
blue.onclick = function () {
context.fillStyle = "blue";
context.strokeStyle = "blue";
blue.classList.add("active");
yellow.classList.remove("active");
red.classList.remove("active");
black.classList.remove("active");
};
black.onclick = function () {
context.fillStyle = "black";
context.strokeStyle = "black";
black.classList.add("active");
yellow.classList.remove("active");
blue.classList.remove("active");
red.classList.remove("active");
};
/********/

thin.onclick = function () {
thin.classList.add("active");
thick.classList.remove("active");
context.lineWidth = 2;
};

thick.onclick = function () {
thick.classList.add("active");
thin.classList.remove("active");
context.lineWidth = 4;
};

clear.onclick = function () {
context.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
};

download.onclick = function () {
var url = canvas.toDataURL("image/png");
var a = document.createElement("a");
document.body.appendChild(a);
a.href = url;
a.download = "my drawing";
a.click();
};

//drawLine
function drawLine(x1, y1, x2, y2) {
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.stroke();
context.closePath();
}

//drawCir
function drawCir(x, y) {
context.beginPath();
context.arc(x, y, 0.1, 0, Math.PI * 2);
context.fill();
}

//重置canvas画板宽高
function setCanvasSize() {
var pageWidth = document.documentElement.clientWidth;
var pageHeight = document.documentElement.clientHeight;

canvas.width = pageWidth;
canvas.height = pageHeight;
}

//自动设置canvas画板宽高
function autoSetSize() {
setCanvasSize();
window.onresize = function () {
setCanvasSize();
};
}
function preventBehavior(e) {
e.preventDefault();
}

document.addEventListener("touchmove", preventBehavior, false);

function listenToUser() {
//特性检测
if (document.body.ontouchstart !== undefined) {
//是触屏设备
canvas.ontouchstart = function (aaa) {
var x = aaa.touches[0].clientX;
var y = aaa.touches[0].clientY;
using = true;
lastPoint = { x: x, y: y };
if (eraserEnabled) {
context.clearRect(x - 10, y - 10, 20, 20);
} else {
drawCir(x, y);
}
};
//
canvas.ontouchmove = function (aaa) {
var x = aaa.touches[0].clientX;
var y = aaa.touches[0].clientY;
var newPoint = { x: x, y: y };
if (using) {
if (eraserEnabled) {
context.clearRect(x - 10, y - 10, 20, 20);
} else {
drawCir(x, y);
drawLine(lastPoint.x, lastPoint.y, newPoint.x, newPoint.y);
lastPoint = newPoint;
}
}
};
canvas.ontouchend = function (aaa) {
using = false;
};
} else {
//不是触屏设备
canvas.onmousedown = function (aaa) {
var x = aaa.clientX;
var y = aaa.clientY;
using = true;
lastPoint = { x: x, y: y };
if (eraserEnabled) {
context.clearRect(x - 10, y - 10, 20, 20);
} else {
drawCir(x, y);
}
};

//鼠标移动监听
canvas.onmousemove = function (aaa) {
var x = aaa.clientX;
var y = aaa.clientY;
var newPoint = { x: x, y: y };
if (using) {
if (eraserEnabled) {
context.clearRect(x - 10, y - 10, 20, 20);
} else {
drawCir(x, y);
drawLine(lastPoint.x, lastPoint.y, newPoint.x, newPoint.y);
lastPoint = newPoint;
}
}
};
//鼠标松开监听
canvas.onmouseup = function (aaa) {
using = false;
};
}
}