目录
- 目标
- 准备工作
- 原理
- 思路
- 实现过程
- 画点
- 画线
- 画点
- 永远都要考虑移动端
- 部署到 GitHub Pages
目标
能画丁老头的画板
准备工作
创建项目目录,并初始化git
#预览
hs . -c-1
面向谷歌编程
google搜
js create div mdn
-
document.createElement('div')
google搜
js insert div into page mdn
- 在页面中添加这个元素
<canvas id='canvas' width="100" height="100"></canvas>
let div = document.createElement('div')
let canvas = document.getElementById("canvas");
canvas.appendChild(div)
google搜
js get body mdn
代码
让canvas占满屏幕,并且没有滚动条
增加样式
div.style.xxx
点出现在鼠标中间,而不是右下角,对称,偶数
由方变圆,变实心
点击事件改成鼠标移动事件
canvas.onclick = (e) => {
//console.log()调试大法
console.log(e.clientX, e.clientY)
//创建div 在内存里,并不在页面(文档里)
let div = document.createElement('div')
div.id = 'canvas'
//绝对定位
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 = '6px'
div.style.height = '6px'
//点出现在鼠标中间,而不是右下角
div.style.marginLeft = '-3px'
div.style.marginTop = '-3px'
//由方变圆
div.style.borderRadius = '50%'
div.style.backgroundColor = 'black'
//添加已在内存中创建的节点
canvas.appendChild(div)
}
这样会卡 JS操作DOM 低效 跨线程通信
用Canvas
画点
<canvas></canvas>
默认的display:inline
,类似于<img>
改为
display:block
干掉影响总宽高的滚动条加上
width: 100vw; height: 100vh;
但会导致
canvas
模糊,所以不行
<canvas></canvas>
的宽高需在一开始就确定
可以在
<canvas></canvas>
上写宽高,但会被CSS覆盖,同<img>
- 用JS获取屏幕宽高,并设置
canvas.width = document.body.clientWidth
canvas.height = document.body.clientHeight
但body 默认是由子元素决定,未撑开
所以要直接获取文档的高度
var canvas = document.getElementById("canvas");
canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;
这就让canvas占满屏幕,并且没有滚动条
画点
//样式
var ctx = canvas.getContext("2d")
ctx.fillStyle = "orange";
canvas.onclick = (e) => {
console.log(e.clientX)
console.log(e.clientY)
ctx.fillRect(e.clientX-5, e.clientY-5, 10, 10)
}
e.clientX-5
让宽度减一半,使其在鼠标中心
onclick
改成onmousemove
没有新建任何节点,只是在画像素点,不需要操作DOM
加开关,标记,按下,抬起鼠标左键的开关记号
let painting = false
加动作,鼠标按下
canvas.onmousedown = () => {
painting = true
}
加判断,开关开启,动作执行
canvas.onmousemove = (e) => {
if (painting === true) {
console.log(e.clientX)
console.log(e.clientY)
ctx.fillRect(e.clientX - 5, e.clientY - 5, 10, 10)
} else {
console.log('什么都不做')
}
}
加关闭触发动作
canvas.onmouseup = () => {
painting = false
}
锯齿太严重,换圆形试试
ctx.beginPath();
ctx.arc(e.clientX, e.clientY, 10, 0, 2 * Math.PI);
ctx.fill()
ctx.stroke();
一些注意事项
浏览器会调用
-
canvas.onmousemove(事件相关信息)
,传参e
单位
-
<canvas></canvas>
是HTML标签的单位同<img>
<canvas id='canvas' width="100" height="100"></canvas>
100vh
是CSS单位
canvas.width
也是HTML的属性单位,而canvas.style.width
的单位是CSS样式的单位,即
<canvas id='canvas' width="100" height="100" style= 'width:100vh'></canvas>
手机适配
google搜
js detect touch support
,得判断代码
var isTouchDevice = 'ontouchstart' in document.documentElement;
console.log(isTouchDevice);
写判断
if (isTouchDevice === true) {
// console.log('目前什么也不写');
} else {
//把PC端的代码扔进来
}
把PC端的代码扔进
else{}
里后,开始写手机端代码
//监听触屏事件
canvas.ontouchmove = (e) => {
console.log(e)
}
第一根手指
//监听触屏事件
canvas.ontouchmove = (e) => {
// console.log(e.touches[0]);//获取第一个手指
let x = e.touches[0].clientX;
let y = e.touches[0].clientY;
console.log(x, y)
}
后面加上PC端抄来的代码,改吧改吧
ctx.beginPath();
ctx.arc(x, y, 10, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
发现不用监听手指抬起,比PC端更简单,特殊app内置浏览器会有向下划同步向下滚动的bug,以后处理
画线
回到PC页面,由点画线,解决不连贯的问题
从画三角,抽象一个画线的函数
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
ctx.strokeStyle = 'none';
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(500, 500);
ctx.lineTo(0, 500);
ctx.closePath();
ctx.stroke();
画线的函数
function drawLine(x1, x2, y1, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
需要记录上一次的位置,每当按下鼠标后,就记录一次,修改
canvas.onmousedown
事件
canvas.onmousedown = (e) =>{
painting = true;
last = [e.clientX, e.clientY];
}
修改
canvas.onmousemove
事件
drawLine(last[0], last[1], e.clientX, e.clientY);
画完,需要每次更新
last = [e.clientX, e.clientY]
drawLine(last[0], last[1], e.clientX, e.clientY);
last = [e.clientX, e.clientY];//实时更新当前位置
流程小结
- 在最外面声明
last
变量
- 再当鼠标按下时,赋值此时的点的位置坐标给
last
- 在鼠标动的时候,以
last
和移动后点坐标的四个值,画线
- 更新当前点的坐标
其他细节
- 线型变粗
ctx.lineWidth
- 线转弯处的节点有缺口,搜
js line end round
,得ctx.lineCap
,使其圆润
- 实验放大
ctx.lineWidth = 4; drawLine(0,0,300,300); drawLine(300,300,500,200);
,突然变向
- 实验放大
别忘了改手机端
- 手机没有
onmousedown
事件,取而代之的是ontouchstart
事件
- 相对应的还有
ontouchstart
和ontouchend
- 坐标位置变为
let x = e.touches[0].clientX; let y = e.touches[0].clientY;
- 同样要记录上次位置,和更新上次位置
部署到 GitHub 上
总结
事物规律,常识抽象到代码
思维方式到了,直到搜什么
用
console.log()
验证不断试错
·未完待续·
参考链接
相关文章
- 无
- 作者: Joel
- 文章链接:
-
版权声明
- 非自由转载-非商用-非衍生-保持署名