- 利用JS做出画图板
-曾老湿, 江湖人称曾老大。
-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。
利用JS做出画图板
准备工作 |
---|
在VScode中创建一个新的项目,并且初始化git仓库

新建一个 html 和一个 CSS,初始化git仓库
代码语言:javascript复制MacBook-Pro:canvas-demo-1 driverzeng$ git init .
MacBook-Pro:canvas-demo-1 driverzeng$ git add .
MacBook-Pro:canvas-demo-1 driverzeng$ git commit -v

有人看到上面这张图的时候,可能会秒变 黑人问号脸,What The Fuck?
这张图来的很突兀,没有错,正如你所看到的,我们今天要用代码,实现一个画板。可以让人画画的画板,你没有听错,也没有看错...
CanVas教程:MDN canvas

首先使用VScode,打开网页,方便调试

代码语言:javascript复制MacBook-Pro:canvas-demo-1 driverzeng$ http-server . -c-1
Starting up http-server, serving .
Available on:
http://127.0.0.1:8080
http://192.168.1.102:8080

鼠标点击 |
---|
首先,如果我们要做个画板,我们需要知道,用户想要画线条之类的东西,那么他们的鼠标第一下的点击会是在哪里呢?
代码语言:javascript复制<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>画板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="canvas"></div>
</body>
</html>
代码语言:javascript复制*{margin: 0;padding: 0;box-sizing: border-box;}
//给canvas加个样式
#canvas{
height: 100vh;
border: 1px solid red;
}

通过 JS 来调试获取用户第一次点击的坐标位置
代码语言:javascript复制 <script>
canvas.onclick = (e)=>{
console.log(e)
}
</script>

打开开发者工具,查看console,然后随便点击页面的白色位置,就会出现MouseEvent
这个就是鼠标点击事件。

我们可以看见有好几个X 和 Y,到底使用哪个呢?
我们先尝试一下clientX
和 clientY
<script>
canvas.onclick = (e)=>{
console.log(e.clientX)
console.log(e.clientY)
}
</script>

点击了很多次,发现这个坐标可以检测到我们鼠标点击的位置,于是接下来,我们需要,在用户点击的地方就出现一个圆点。
代码语言:javascript复制 <script>
canvas.onclick = (e)=>{
console.log(e.clientX)
console.log(e.clientY)
<!-- 让文档创建一个div的元素,这个是已经写好的api我们可以直接调用 -->
let div= document.createElement('div')
<!-- 接下来我们要让div出现在鼠标点击的位置,使用CSS的绝对定位 -->
div.style.position = 'absolute'
div.style.left = e.clientX 'px'
div.style.top = e.clientY 'px'
div.style.border = '1px solid red'
div.style.width = '5px'
div.style.height= '5px'
}
</script>
写完之后,我们再去点击页面,会发现.........咦?还是什么东西都没有,此时,再看一下上面的代码,我们只是创建了一个div,但是并没有说把这个div创建在哪里,所以此时这个div是在内存里,我们需要把它加入到页面当中。
代码语言:javascript复制canvas.appendChild(div)

如果你写完了,你点击后,你会发现,这个方框会出现在鼠标的右下角,而不是出现在鼠标的正中间,所以我们还需要把这个框修改到鼠标的正中间。
代码语言:javascript复制div.style.width = '6px'
div.style.height= '6px'
div.style.marginLeft = '-3px'
div.style.marginTop = '-3px'

接下来 ,我们需要把方框变成圆的,变成黑色实心的,去掉红色边框。
代码语言:javascript复制 <script>
canvas.onclick = (e)=>{
console.log(e.clientX)
console.log(e.clientY)
let div= document.createElement('div')
div.style.position = 'absolute'
div.style.left = e.clientX 'px'
div.style.top = e.clientY 'px'
div.style.width = '6px'
div.style.height= '6px'
div.style.marginLeft = '-3px'
div.style.marginTop = '-3px'
div.style.borderRadius = '50%'
div.style.backgroundColor = 'black'
canvas.appendChild(div)
}
</script>

提交第一版,可以获取到鼠标的位置,并且画出点.
代码语言:javascript复制MacBook-Pro:canvas-demo-1 driverzeng$ git add .
MacBook-Pro:canvas-demo-1 driverzeng$ git commit -v
使用canvas画线 |
---|
刚才我们已经可以准确的获取到鼠标的位置,并且画出点来,现在我们需要把这些点连成线。

如图所示,我们把 onclick
更改成 onmousemove
,在页面中,只要鼠标移动,就会出现黑点,慢慢移动就会变成线,但是如果移动速度很快,就会发现是断断续续的点。
所以我们需要忘记刚才的代码,有直接的方法就是 canvas ,学习官方的示例代码。

代码语言:javascript复制<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>画板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id='canvas'></canvas>
<script>
// 画线
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// 控制颜色
ctx.fillStyle = "rgb(200,0,0)";
// 控制 横坐标 纵坐标 宽度 高度
ctx.fillRect (10, 10, 55, 50);
</script>
</body>
</html>
代码语言:javascript复制*{margin: 0;padding: 0;box-sizing: border-box;}
#canvas{
height: 100vh;
width: 100vw;
display: block;
border: 1px solid red;
}

但是会发现,这个红色的框会很模糊,马赛克... AV画质。
就是因为我们在CSS中设置了宽度和高度。
canvas的宽 高 默认就设置了。

去掉CSS中的 宽高,使用用户的屏幕宽 高 来定义canvas的宽高。
但是,每个用户的宽和高又不一样,我们又不能把canvas的 宽高写死了,所以我们需要用到JS来获取用户屏幕的宽高

代码语言:javascript复制网页可见区域宽: document.body.clientWidth
网页可见区域高: document.body.clientHeight
网页可见区域宽: document.body.offsetWidth (包括边线的宽)
网页可见区域高: document.body.offsetHeight (包括边线的高)
网页正文全文宽: document.body.scrollWidth
网页正文全文高: document.body.scrollHeight
网页被卷去的高: document.body.scrollTop
网页被卷去的左: document.body.scrollLeft
网页正文部分上: window.screenTop
网页正文部分左: window.screenLeft
屏幕分辨率的高: window.screen.height
屏幕分辨率的宽: window.screen.width
屏幕可用工作区高度: window.screen.availHeight
屏幕可用工作区宽度: window.screen.availWidth
代码语言:javascript复制console.log(document.body.clientWidth)

获取一下宽度 试试
代码语言:javascript复制 <script>
// 画线
var canvas = document.getElementById("canvas");
canvas.width = document.body.clientWidth
canvas.height = document.body.clientHeight
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, 55, 50);
</script>

会发现,这个宽度 和 高度,是根据body的宽高来定的所以,不是这个
代码语言:javascript复制canvas.width = document.documentElement.clientWidth
canvas.height = document.documentElement.clientHeight
最终答案,使用documentElement,文档的高度
代码语言:javascript复制<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>画板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id='canvas'></canvas>
<script>
// 画线
var canvas = document.getElementById("canvas");
canvas.width = document.documentElement.clientWidth
canvas.height = document.documentElement.clientHeight
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, 55, 50);
</script>
</body>
</html>
代码语言:javascript复制*{margin: 0;padding: 0;box-sizing: border-box;}
#canvas{
display: block;
}
现在使用canvas,开始用鼠标来填充图案,先获取鼠标点击事件看看。
代码语言:javascript复制 <script>
// 画线
var canvas = document.getElementById("canvas");
canvas.width = document.documentElement.clientWidth
canvas.height = document.documentElement.clientHeight
var ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
ctx.fillRect (10, 10, 55, 50);
canvas.onclick = (e) =>{
console.log(e.clientX)
console.log(e.clientY)
}
</script>

依然可以获取到,因此,我们可以按照刚才的方式,先画点

然后居中,连线

但是现在鼠标,停不下来,只要移动就会画线。
所以我们可以设置一个信号,比如开车的时候,当你看到红灯,就会停车,当你看到绿灯就会开车。
代码语言:javascript复制<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>画板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id='canvas'></canvas>
<script>
// 画线
let canvas = document.getElementById("canvas");
canvas.width = document.documentElement.clientWidth
canvas.height = document.documentElement.clientHeight
let ctx = canvas.getContext("2d");
let painting = false
ctx.fillStyle = "black";
canvas.onmousedown = () => {
painting = true
}
canvas.onmousemove = (e) =>{
if (painting === true) {
ctx.fillRect (e.clientX -3, e.clientY -3, 6, 6);
} else {
console.log('啥都不做')
}
}
canvas.onmouseup = () => {
painting = false
}
</script>
</body>
</html>

现在把线条的方框,改成圆形

代码语言:javascript复制<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>画板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id='canvas'></canvas>
<script>
// 画线
let canvas = document.getElementById("canvas");
canvas.width = document.documentElement.clientWidth
canvas.height = document.documentElement.clientHeight
let ctx = canvas.getContext("2d");
let painting = false
ctx.fillStyle = "black";
ctx.strokeStyle = 'none'
canvas.onmousedown = () => {
painting = true
}
canvas.onmousemove = (e) =>{
if (painting === true) {
ctx.beginPath();
ctx.arc(e.clientX,e.clientY,5,0,2 * Math.PI);
ctx.stroke();
ctx.fill();
} else {
console.log('啥都不做')
}
}
canvas.onmouseup = () => {
painting = false
}
</script>
</body>
</html>

提交git仓库,使用canvas画线
代码语言:javascript复制MacBook-Pro:canvas-demo-1 driverzeng$ git add .
MacBook-Pro:canvas-demo-1 driverzeng$ git commit -v
优化:手机使用 |
---|
首先先要检测,是否支持触屏,鼠标点击事件,在手机上肯定是不好使了。
于是乎,经过多次辗转反侧的找文档,发现:
代码语言:javascript复制let isTouchDevice = 'ontouchstart' in document.documentElement;
console.log(isTouchDevice)
PC端,false


代码语言:javascript复制<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>画板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id='canvas'></canvas>
<script>
// 画线
let canvas = document.getElementById("canvas");
canvas.width = document.documentElement.clientWidth
canvas.height = document.documentElement.clientHeight
let ctx = canvas.getContext("2d");
let painting = false
ctx.fillStyle = "black";
ctx.strokeStyle = 'none'
let isTouchDevice = 'ontouchstart' in document.documentElement;
console.log(isTouchDevice)
if(isTouchDevice){
canvas.ontouchmove = (e) => {
let x = e.touches[0].clientX
let y = e.touches[0].clientY
ctx.beginPath();
ctx.arc(x,y,5,0,2 * Math.PI);
ctx.stroke();
ctx.fill();
}
}else{
canvas.onmousedown = () => {
painting = true
}
canvas.onmousemove = (e) =>{
if (painting === true) {
ctx.beginPath();
ctx.arc(e.clientX,e.clientY,5,0,2 * Math.PI);
ctx.stroke();
ctx.fill();
}
}
canvas.onmouseup = () => {
painting = false
}
}
</script>
</body>
</html>

优化,在点和点之间,连成一条线。
我们先要知道,如何画一条线

代码语言:javascript复制let ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
ctx.strokeStyle = 'none'
ctx.beginPath();
ctx.moveTo(125,125);
ctx.lineTo(125,45);
ctx.lineTo(45,125);
ctx.closePath();
ctx.stroke();

这个三角形是怎么做到的呢?
我们可以通过修改代码来看



beginPath: 是开始 moveTo:起点 lineTo:从起点画一根线 stroke:描边 fill:填充颜色

如果不要后面的,只要前面的起点和第一条线。

这样就出来了一条线,这样 我们可以写个画线的函数

通过传参 的方式
代码语言:javascript复制 function drawLine(x1,y1,x2,y2){
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
}
drawLine(0,0,500,500)
使用drawLine函数
代码语言:javascript复制<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>画板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id='canvas'></canvas>
<script>
// 画线
let canvas = document.getElementById("canvas");
canvas.width = document.documentElement.clientWidth
canvas.height = document.documentElement.clientHeight
let ctx = canvas.getContext("2d");
let painting = false
ctx.fillStyle = "black";
ctx.strokeStyle = 'none'
let isTouchDevice = 'ontouchstart' in document.documentElement;
function drawLine(x1,y1,x2,y2){
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
}
if(isTouchDevice){
canvas.ontouchmove = (e) => {
console.log(e.touches[0].clientX)
let x = e.touches[0].clientX
let y = e.touches[0].clientY
ctx.beginPath();
ctx.arc(x,y,5,0,2 * Math.PI);
ctx.stroke();
ctx.fill();
}
}else{
canvas.onmousedown = () => {
painting = true
}
canvas.onmousemove = (e) =>{
if (painting === true) {
drawLine(0,0,e.clientX,e.clientY)
}
}
canvas.onmouseup = () => {
painting = false
}
}
</script>
</body>
</html>
每画一个点,都会从(0,0)这个坐标点,开始,所以变成这样了。

所以,我们需要修改一下起点,改成上一个点
代码语言:javascript复制<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>画板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id='canvas'></canvas>
<script>
// 画线
let canvas = document.getElementById("canvas");
canvas.width = document.documentElement.clientWidth
canvas.height = document.documentElement.clientHeight
let ctx = canvas.getContext("2d");
let painting = false
ctx.fillStyle = "black";
ctx.strokeStyle = 'none'
let isTouchDevice = 'ontouchstart' in document.documentElement;
let last
function drawLine(x1,y1,x2,y2){
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
}
if(isTouchDevice){
canvas.ontouchmove = (e) => {
console.log(e.touches[0].clientX)
let x = e.touches[0].clientX
let y = e.touches[0].clientY
ctx.beginPath();
ctx.arc(x,y,5,0,2 * Math.PI);
ctx.stroke();
ctx.fill();
}
}else{
canvas.onmousedown = () => {
painting = true
last = [e.clientX, e.clientY]
}
canvas.onmousemove = (e) =>{
if (painting === true) {
drawLine(last[0],last[1],e.clientX,e.clientY)
}
}
canvas.onmouseup = () => {
painting = false
}
}
</script>
</body>
</html>

现在又变成每次从第一个点,开始画线,我们需要让上一次实时更新
代码语言:javascript复制<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>画板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id='canvas'></canvas>
<script>
// 画线
let canvas = document.getElementById("canvas");
canvas.width = document.documentElement.clientWidth
canvas.height = document.documentElement.clientHeight
let ctx = canvas.getContext("2d");
let painting = false
ctx.fillStyle = "black";
ctx.strokeStyle = 'none'
let isTouchDevice = 'ontouchstart' in document.documentElement;
let last
function drawLine(x1,y1,x2,y2){
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
}
if(isTouchDevice){
canvas.ontouchmove = (e) => {
console.log(e.touches[0].clientX)
let x = e.touches[0].clientX
let y = e.touches[0].clientY
ctx.beginPath();
ctx.arc(x,y,5,0,2 * Math.PI);
ctx.stroke();
ctx.fill();
}
}else{
canvas.onmousedown = (e) => {
painting = true
last = [e.clientX, e.clientY]
}
canvas.onmousemove = (e) =>{
if (painting === true) {
drawLine(last[0],last[1],e.clientX,e.clientY)
last = [e.clientX,e.clientY]
}
}
canvas.onmouseup = () => {
painting = false
}
}
</script>
</body>
</html>

加上线的宽度,太细了...

变粗了之后,会发现,画线中间会有缝隙。所以我们还需要调整一个参数

手机适配:
代码语言:javascript复制<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>画板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id='canvas'></canvas>
<script>
// 画线
let canvas = document.getElementById("canvas");
canvas.width = document.documentElement.clientWidth
canvas.height = document.documentElement.clientHeight
let ctx = canvas.getContext("2d");
let painting = false
ctx.fillStyle = "black";
ctx.strokeStyle = 'none'
ctx.lineWidth = 20;
ctx.lineCap = 'round'
let isTouchDevice = 'ontouchstart' in document.documentElement;
let last
function drawLine(x1,y1,x2,y2){
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
}
if(isTouchDevice){
canvas.ontouchstart = (e) => {
let x = e.touches[0].clientX
let y = e.touches[0].clientY
last = [x,y]
}
canvas.ontouchmove = (e) => {
let x = e.touches[0].clientX
let y = e.touches[0].clientY
drawLine(last[0],last[1],x,y)
last = [x,y]
}
} else {
canvas.onmousedown = (e) => {
painting = true
last = [e.clientX, e.clientY]
}
canvas.onmousemove = (e) =>{
if (painting === true) {
drawLine(last[0],last[1],e.clientX,e.clientY)
last = [e.clientX,e.clientY]
}
}
canvas.onmouseup = () => {
painting = false
}
}
</script>
</body>
</html>