- 预览链接">预览链接
- 1.用 div 当画点
- 2.用 canvas 属性
- 2.1.样式暂定
- canvas mdn (复制过来以下内容到 script)">2.2.搜索 canvas mdn (复制过来以下内容到 script)
- 2.3.如何让画板自适应到整个屏幕
- 2.4.打 log,监听鼠标位置
- 2.5.设置开关(鼠标按下去开始画,松开停止)
- 2.6.解决锯齿问题
- 3.让手机上也能使用画板
- canvas 画线">4.canvas 画线
- 补充
预览链接
1.用 div 当画点
1.1.监听鼠标位置(打 log 监听)
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>画板</title><link rel="stylesheet" href="style.css" /> <!-- 引入一个CSS样式文档 --></head><body><div id="canvas"></div> <!-- id 可以直接用来做全局变量 --><script>canvas.onclick = (e) => {//监听 canvas 的事件,这里先用 onclick 事件,出问题再改console.log(e);//console 调试};</script></body></html>
* {margin: 0;padding: 0;box-sizing: border-box;}#canvas {height: 100vh;border: 1px solid red;}
- 开启终端,输入 http-server . -c-1 进入其中一个网址,刷新不出来就在链接后面加上路径,如:/index.html
- 打开浏览器的开发者模式,
- 在画板的左上角点击一下(这里的XY应该都是0),进入下图位置

- 点开 MouseEvent

- 会发现里面有好几个显示 X Y 的,都是显示现在点击的那个点,选择其中一个来用,出现问题了再换
确认可以读出鼠标点击的点的位置后,打出X和Y
console.log(e.clientX);console.log(e.clientY);
1.2.让鼠标点击出现一个实心圆点(给div加样式)
let div = document.createElement("div");//让文档创建一个元素div,默认在内存里,不在 canvas 里div.style.position = "absolute";//让 div 里的内联元素样式为 absolutediv.style.left = e.clientX + "px";div.style.top = e.clientY + "px";//注意加单位div.style.border = "1px solid red";div.style.width = "6px";div.style.height = "6px";canvas.appendChild(div);//让div在canvas里,而不是在内存里,不加这个的话点击不会显示任何东西
此时鼠标每次点击会出现一个 6px 的矩形框

并且鼠标的箭头指的位置是矩形框的左上角,我们需要它是在中间,并且为实心圆形
div.style.marginLeft = "-3px";div.style.marginTop = "-3px"; //鼠标的箭头指的位置是矩形框的中间div.style.borderRadius = "50%";//变圆div.style.backgroundColor = "black";//实心,此时可去掉 border
效果图,实心圆点
1.3.连续的点
- 将 onclick 换成 onmousemove ,鼠标移动就会画点(弊病:不会停止,只要鼠标在图框里移动就会画点)
最终的 script 里的内容
<script>canvas.onmousemove = (e) => {//监听 canvas 的事件,这里先用 onclick 事件,出问题再改,后面改成了 onmousemoveconsole.log(e.clientX);console.log(e.clientY);// console.log 调试大法let div = document.createElement("div");//让文档创建一个元素div,默认在内存里,不在 canvas 里div.style.position = "absolute";//让 div 里的内联元素样式为 absolutediv.style.left = e.clientX + "px";div.style.top = e.clientY + "px";//注意加单位div.style.width = "6px";div.style.height = "6px"; //使点击出来的为一个6px的矩形框div.style.marginLeft = "-3px";div.style.marginTop = "-3px"; //鼠标的箭头指的位置是矩形框的中间div.style.borderRadius = "50%"; //变圆div.style.backgroundColor = "black"; //实心,此时可去掉 bordercanvas.appendChild(div);//让div在canvas里,而不是在内存里};</script>
效果图

弊端:鼠标移动太快会间断
- 会一直产生新的 DOM 点,画的越多越卡
2.用 canvas 属性
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>画板</title><link rel="stylesheet" href="style.css" /><!-- 引入一个CSS样式文档 --></head><body><canvas id="canvas" width="100" height="100"></canvas><script></script></body></html>
2.1.样式暂定
* {margin: 0;padding: 0;box-sizing: border-box;}#canvas {height: 100vh;width: 100vw;border: 1px solid red;display: block;}/* 暂定这样,后面会有问题;目的,既没有左右,又没有上下的滚动条 */
2.2.搜索 canvas mdn (复制过来以下内容到 script)
const canvas = document.getElementById("canvas");const ctx = canvas.getContext("2d");ctx.fillStyle = "blue";//填充样式ctx.fillRect(20, 20, 60, 60);//间距左,右,宽,高

- 此时会看到一个比较模糊的背景色(原因是前面的样式出了问题)
canvas 有一个原始的宽高,强行咋 CSS 里改样式会让其直接拉伸,而不会自适应,所有会有模糊状态
[x] 去掉 CSS 里的宽高
#canvas {border: 1px solid red;display: block;}
2.3.如何让画板自适应到整个屏幕
加入下面代码到 script
canvas.width = document.documentElement.clientWidth;canvas.height = document.documentElement.clientHeight;//把canvas的宽高变成文档的宽高(注意不要变成body的宽高,宽度合适,但是高度只有body的高)删除 canvas 的border
2.4.打 log,监听鼠标位置
canvas.onmousemove = (e) => {console.log(e.clientX);console.log(e.clientY);ctx.fillRect(e.clientX - 5, e.clientY - 5, 10, 10); //间距左,右,宽,高};
用 onclick 打单个点,用 onmousemove 跟随鼠标打点,鼠标到哪点打到哪儿
2.5.设置开关(鼠标按下去开始画,松开停止)
前面的 const 改成 let
加上let painting = false; //painting 是自己取的名字canvas.onmousedown = (e) => {painting = true;};//鼠标按下时 painting = truecanvas.onmousemove = (e) => {if (painting === true) {ctx.fillRect(e.clientX - 5, e.clientY - 5, 10, 10);} else {console.log("什么都不做");}};//如果painting === true ,执行画矩形点的命令,否则什么都不做canvas.onmouseup = () => {painting = false;};//鼠标抬起时 painting = false
2.6.解决锯齿问题
2.6.1.将矩形框改成圆形(参考教程)
将之前的canvas.onmousemove 内容改成如下
canvas.onmousemove = (e) => {if (painting === true) {ctx.beginPath();ctx.arc(e.clientX, e.clientY, 10, 0, 2 * Math.PI);//圆心到左边框距离,上,半径,起始弧度0,中止弧度2πctx.stroke();ctx.fill();//填充} else {console.log("什么都不做");}};
改变背景填充色为黑色
效果如下
目前看的感觉还是拼凑的,但是没有像之前用矩形时有锯齿
最终的代码如下<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>画板</title><link rel="stylesheet" href="style.css" /><!-- 引入一个CSS样式文档 --></head><body><canvas id="canvas" width="100" height="100"></canvas><script>let canvas = document.getElementById("canvas"); //获取 canvaslet ctx = canvas.getContext("2d");canvas.width = document.documentElement.clientWidth;canvas.height = document.documentElement.clientHeight;//把canvas的宽高变成文档的宽高(注意不要变成body的宽高,宽度合适,但是高度只有body的高)let painting = false; //painting 是自己取的名字ctx.fillStyle = "black"; //填充样式canvas.onmousedown = () => {painting = true;}; //鼠标按下时 painting = truecanvas.onmousemove = (e) => {if (painting === true) {ctx.beginPath();ctx.arc(e.clientX, e.clientY, 10, 0, 2 * Math.PI);//圆心到左边框距离,上,半径,起始弧度0,中止弧度2πctx.stroke();ctx.fill(); //填充} else {console.log("什么都不做");}};//如果painting === true ,执行画矩形点的命令,否则什么都不做canvas.onmouseup = () => {painting = false;};//鼠标抬起时 painting = false</script></body></html>
3.让手机上也能使用画板
3.1.怎么确认手机模式是否支持鼠标
可搜索 js 浏览器是否支持触屏/js detect touch support
寻找代码,打 log 试出来的
(如果没找出来就只能设置屏幕宽度来制定是电脑还是触屏设备)var isTouchDevice = "ontouchstart" in document.documentElement;console.log(isTouchDevice);
3.2.如何分别执行两种模式
3.2.1.代码如下(先用 log 看手机模式是否发生事件)
```javascript
if (isTouchDevice) {canvas.ontouchmove = (e) => {console.log(e);};} else {canvas.onmousedown = () => {painting = true;}; //鼠标按下时 painting = truecanvas.onmousemove = (e) => {if (painting === true) {ctx.beginPath();ctx.arc(e.clientX, e.clientY, 10, 0, 2 * Math.PI);//圆心到左边框距离,上,半径,起始弧度0,中止弧度2πctx.stroke();ctx.fill(); //填充} else {console.log("什么都不做");}};//如果painting === true ,执行画矩形点的命令,否则什么都不做canvas.onmouseup = () => {painting = false;//鼠标抬起时 painting = false};}//如果是触屏模式执行前面的新加的,如果不是触屏模式,执行之前的三个鼠标模式(将之前的三个鼠标模式放入else里)
- 因为触摸手机不一定是一根手指,所以 x y 在touches 里- 切换成手机模式会,鼠标在上面移动几下,会出现很多事件,点击其中一个,如下图:<a name="rd7tG"></a>#### 3.2.2.实现鼠标点击出现x,y```javascriptcanvas.ontouchmove = (e) => {let x = e.touches[0].clientX;let y = e.touches[0].clientY;console.log(x, y);};
3.2.3.画点(触屏就不需要再设置鼠标按下事件了,没触屏的时候自然没有按在屏幕上)
以下代码加入到 canvas.ontouchmove 里
ctx.beginPath();ctx.arc(x, y, 10, 0, 2 * Math.PI);ctx.stroke();ctx.fill();
4.canvas 画线
4.1.加一个函数,把画线的代码放进去
function drawLine(x1, y1, x2, y2) {ctx.beginPath();ctx.moveTo(x1, y1);ctx.lineTo(x2, y2);ctx.stroke();}
可以先让第二个点为鼠标点的那个点,第一个点暂设(0,0)
canvas.onmousemove = (e) => {if (painting === true) {drawLine(0, 0, e.clientX, e.clientY);} else {console.log("什么都不做");}};
4.2.怎么让第一个点为上一个点
[x] 先声明一个 last 变量
let last; //声明一个 last 变量
[x] 第一个点没有上一个点,所以在第一个点加上上一个点,同时要定义一个在 canvas.onmousedown上定义一个值,这里是定义的 e
canvas.onmousedown = (e) => {painting = true;last = [e.clientX, e.clientY]; //第一的点的上一个点也设置成第一个点};
[x] 实时更新 last
canvas.onmousemove = (e) => {if (painting === true) {drawLine(last[0], last[1], e.clientX, e.clientY);last = [e.clientX, e.clientY]; //实时更新 last,画完一个点就让这个点变成下一个点的上一个点} else {console.log("什么都不做");}};
4.3.设置线宽
ctx.lineWidth = 8;
此时会出现一个问题,线比较宽(>4px)时,转角的地方会出现空缺

明显一点点图
4.4.处理转角的地方,使其更圆滑
加上一句代码即可
ctx.lineCap = "round";
4.5.画线-手机模式调试
此时就先需要加一个起始点 canvas.ontouchstart
再调整 canvas.ontouchmovecanvas.ontouchstart = (e) => {let x = e.touches[0].clientX;let y = e.touches[0].clientY; //声明x,ylast = [x, y];};canvas.ontouchmove = (e) => {let x = e.touches[0].clientX;let y = e.touches[0].clientY; //声明x,ydrawLine(last[0], last[1], x, y);last = [x, y];};
补充
解析 canvas.onmousemove = (e) => {}
浏览器会调用 canvas.onmousemove,其中的e可以改成别的任意代替
canvas.onmousemove (事件相关信息)
let、var、const的区别
let 的用法类似于 var,但是 let 只在所在的代码块内有效,所以我们一般使用 let 替代 var。而 const 用来声明常量。


