这篇文章主要介绍了html5如何通过canvas设置画板,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

一、项目介绍

名称:智绘画板

技术栈:HTML5,CSS3,JavaScript,移动端

功能描述:

支持PC端和移动端在线绘画功能

实现任意选择画笔颜色、调整画笔粗细以及橡皮檫擦除等绘画功能

实现在线画板的本地保存功能

支持撤销和返回操作

自定义背景颜色

二、项目效果展示

项目地址 预览地址

预览图

PC端的预览图:

移动端的预览图:

看完上面的预览图和体验过 智绘画板 觉得还可以的,记得点个赞哦,不管你是否十分激动,反正我是挺激动的,毕竟自己实现出现的项目效果,挺自豪的,说了一堆废话,下面就可以动起手来敲代码,实现自己想要的效果!!!

注:下面实现项目效果主要是关于JavaScript方面的,下面仅仅是提供 实现思路的代码 , 并非全部代码 。

三、一步步实现项目效果

(一)分析页面

通过 用例图 ,我们知道用户进入我们这个网站有哪些功能?

用户可以进行的操作:

画画

改变画笔的粗细

切换画笔的颜色

使用橡皮檫擦除不想要的部分

清空画板

将自己画的东西保存成图片

进行撤销和重做操作

切换画板背景颜色

兼容移动端(支持触摸)

(二)进行HTML布局

我书写html的同时,引入了css文件和js文件

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><metahttp-equiv="X-UA-Compatible"content="ie=edge"><title>智绘画板</title><linkrel="shortcuticon"href="./image/favicon.png"type="image/x-icon"><linkrel="stylesheet"href="./css/style.css"></head><body><canvasid="canvas"></canvas><divclass="bg-btn"></div><divclass="color-group"id="bgGroup"><h4>选择背景颜色:</h4><ulclass="clearfix"><liclass="bgcolor-item"></li><liclass="bgcolor-item"></li><liclass="bgcolor-item"></li><liclass="bgcolor-item"></li><liclass="bgcolor-item"></li><liclass="bgcolor-item"></li><liclass="bgcolor-item"></li><liclass="bgcolor-item"></li><liclass="bgcolor-item"></li><liclass="bgcolor-item"></li><liclass="bgcolor-item"></li><liclass="bgcolor-item"></li></ul><iclass="closeBtn"></i></div><divclass="tools"><divclass="container"><buttonclass="save"id="save"title="保存"></button><buttonclass="brushactive"id="brush"title="画笔"></button><buttonclass="eraser"id="eraser"title="橡皮擦"></button><buttonclass="clear"id="clear"title="清屏"></button><buttonclass="undo"id="undo"title="撤销"></button><buttonclass="redo"id="redo"title="再做"></button></div></div><divclass="pen-detail"id="penDetail"><iclass="closeBtn"></i><p>笔大小</p><spanclass="circle-box"><iid="thickness"></i></span><inputtype="range"id="range1"min="1"max="10"value="1"><p>笔颜色</p><ulclass="pen-colorclearfix"><liclass="color-itemactive"></li><liclass="color-item"></li><liclass="color-item"></li><liclass="color-item"></li><liclass="color-item"></li><liclass="color-item"></li></ul><p>不透明度</p><iclass="showOpacity"></i><inputtype="range"id="range2"min="1"max="10"value="1"></div><scriptsrc="./js/main.js"></script></body></html>

(三)用CSS美化界面

css代码可以根据个人习惯进行美化界面,所以这里就不写css的代码了,大家可以直接看 项目代码 或者从开发者工具中审查元素观看。如果有问题可以私聊我,我觉得问题不大。

(四)使用JS实现项目的具体功能

1.准备工作

首先,准备个容器,也就是画板了,前面的html已经书写好这个容器,这里纯属是废话。

<canvasid="canvas"></canvas>

然后初始化js

letcanvas=document.getElementById('canvas');letcontext=canvas.getContext('2d');

我打算把画板做成全屏的,所以接下来设置一下 canvas 的宽高

letpageWidth=document.documentElement.clientWidth;letpageHeight=document.documentElement.clientHeight;canvas.width=pageWidth;canvas.height=pageHeight;

由于部分IE不支持 canvas ,如果要兼容IE,我们可以创建一个 canvas ,然后使用 excanvas 初始化,针对IE加上exCanvas.js,这里我们明确不考虑IE。

但是我在电脑上对浏览器的窗口进行改变,画板不会自适应的放缩。解决办法:

//记得要执行autoSetSize这个函数哦functionautoSetSize(){canvasSetSize();//当执行这个函数的时候,会先设置canvas的宽高functioncanvasSetSize(){letpageWidth=document.documentElement.clientWidth;letpageHeight=document.documentElement.clientHeight;canvas.width=pageWidth;canvas.height=pageHeight;}//在窗口大小改变之后,就会触发resize事件,重新设置canvas的宽高window.onresize=function(){canvasSetSize();}}

2.实现画画的功能

实现思路:监听鼠标事件, 用 drawLine() 方法把记录的数据画出来。

初始化当前画板的画笔状态, painting = false

当鼠标按下时( mousedown ),把 painting 设为 true ,表示正在画,鼠标没松开。把鼠标点记录下来。

当按下鼠标的时候,鼠标移动( mousemove )就 把点记录 下来并画出来。 如果鼠标移动过快,浏览器跟不上绘画速度,点与点之间会出现间隙,所以我们需要将画出的点用线连起来( lineTo() )。

鼠标松开的时候( mouseup ),把 painting 设为 false

注: drawCircle 这个方法其实可以不用书写,这个只是为了让大家能够理解开始点击的位置在哪里?

functionlistenToUser(){//定义一个变量初始化画笔状态letpainting=false;//记录画笔最后一次的位置letlastPoint={x:undefined,y:undefined};//鼠标按下事件canvas.onmousedown=function(e){painting=true;letx=e.clientX;lety=e.clientY;lastPoint={'x':x,'y':y};drawCircle(x,y,5);}//鼠标移动事件canvas.onmousemove=function(e){if(painting){letx=e.clientX;lety=e.clientY;letnewPoint={'x':x,'y':y};drawLine(lastPoint.x,lastPoint.y,newPoint.x,newPoint.y);lastPoint=newPoint;}}//鼠标松开事件canvas.onmouseup=function(){painting=false;}}//画点函数functiondrawCircle(x,y,radius){//新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。context.beginPath();//画一个以(x,y)为圆心的以radius为半径的圆弧(圆),//从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。context.arc(x,y,radius,0,Math.PI*2);//通过填充路径的内容区域生成实心的图形context.fill();//闭合路径之后图形绘制命令又重新指向到上下文中。context.closePath();}functiondrawLine(x1,y1,x2,y2){//设置线条宽度context.lineWidth=10;//设置线条末端样式。context.lineCap="round";//设定线条与线条间接合处的样式context.lineJoin="round";//moveTo(x,y)将笔触移动到指定的坐标x以及y上context.moveTo(x1,y1);//lineTo(x,y)绘制一条从当前位置到指定x以及y位置的直线context.lineTo(x2,y2);//通过线条来绘制图形轮廓context.stroke();context.closePath();}

3.实现橡皮擦功能

实现思路:

获取橡皮擦元素

设置橡皮擦初始状态, eraserEnabled = false

监听橡皮擦 click 事件,点击橡皮擦,改变橡皮擦状态, eraserEnabled = true ,并且切换class,实现 被激活 的效果。

eraserEnabledtrue 时,移动鼠标用 context.clearRect() 实现了 橡皮檫。

但是我发现canvas的API中,可以清除像素的就是clearRect方法,但是clearRect方法的清除区域矩形,毕竟大部分人的习惯中的橡皮擦都是圆形的,所以就引入了剪辑区域这个强大的功能,也就是clip方法。下面的代码是使用 context.clearRect() 实现了 橡皮檫。请看踩坑部分,了解如何更好的实现橡皮檫。

leteraser=document.getElementById("eraser");leteraserEnabled=false;//记得要执行listenToUser这个函数哦functionlistenToUser(){//...代表省略了之前写的代码//...//鼠标按下事件canvas.onmousedown=function(e){//...if(eraserEnabled){//要使用erasercontext.clearRect(x-5,y-5,10,10)}else{lastPoint={'x':x,'y':y}}}//鼠标移动事件canvas.onmousemove=function(e){letx=e.clientX;lety=e.clientY;if(!painting){return}if(eraserEnabled){context.clearRect(x-5,y-5,10,10);}else{varnewPoint={'x':x,'y':y};drawLine(lastPoint.x,lastPoint.y,newPoint.x,newPoint.y);lastPoint=newPoint;}}//...}//点击橡皮檫eraser.onclick=function(){eraserEnabled=true;eraser.classList.add('active');brush.classList.remove('active');}

4.实现清屏功能

实现思路:

获取元素节点。

点击清空按钮清空canvas画布。

letreSetCanvas=document.getElementById("clear");//实现清屏reSetCanvas.onclick=function(){ctx.clearRect(0,0,canvas.width,canvas.height);setCanvasBg('white');}//重新设置canvas背景颜色functionsetCanvasBg(color){ctx.fillStyle=color;ctx.fillRect(0,0,canvas.width,canvas.height);}

5.实现保存成图片功能

实现思路:

获取canvas.toDateURL

在页面里创建并插入一个a标签

a标签href等于canvas.toDateURL,并添加download属性

点击保存按钮,a标签触发click事件

letsave=document.getElementById("save");//下载图片save.onclick=function(){letimgUrl=canvas.toDataURL('image/png');letsaveA=document.createElement('a');document.body.appendChild(saveA);saveA.href=imgUrl;saveA.download='mypic'+(newDate).getTime();saveA.target='_blank';saveA.click();}

6.实现改变背景颜色的功能

实现思路:

获取相应的元素节点。

给每一个class为bgcolor-item的标签添加点击事件,当点击事件触发时,改变背景颜色。

点击设置背景颜色的div之外的地方,实现隐藏那个div。

letselectBg=document.querySelector('.bg-btn');letbgGroup=document.querySelector('.color-group');letbgcolorBtn=document.querySelectorAll('.bgcolor-item');letpenDetail=document.getElementById("penDetail");letactiveBgColor='#fff';//实现了切换背景颜色for(leti=0;i<bgcolorBtn.length;i++){bgcolorBtn[i].onclick=function(e){//阻止冒泡e.stopPropagation();for(leti=0;i<bgcolorBtn.length;i++){bgcolorBtn[i].classList.remove("active");this.classList.add("active");activeBgColor=this.style.backgroundColor;setCanvasBg(activeBgColor);}}}document.onclick=function(){bgGroup.classList.remove('active');}selectBg.onclick=function(e){bgGroup.classList.add('active');e.stopPropagation();}

7.实现改变画笔粗细的功能

实现思路:

实现让设置画笔的属性的对话框出现。

获取相应的元素节点。

当input=range的元素发生改变的时候,获取到的值赋值给lWidth。

然后设置context.lineWidth = lWidth。

letrange1=document.getElementById('range1');letlWidth=2;letifPop=false;range1.onchange=function(){console.log(range1.value);console.log(typeofrange1.value)thickness.style.transform='scale('+(parseInt(range1.value))+')';console.log(thickness.style.transform)lWidth=parseInt(range1.value*2);}//画线函数functiondrawLine(x1,y1,x2,y2){//...context.lineWidth=lWidth;//...}//点击画笔brush.onclick=function(){eraserEnabled=false;brush.classList.add('active');eraser.classList.remove('active');if(!ifPop){//弹出框console.log('弹一弹')penDetail.classList.add('active');}else{penDetail.classList.remove('active');}ifPop=!ifPop;}

8.实现改变画笔颜色的功能

实现思路跟 改变画板背景颜色 的思路类似。

letaColorBtn=document.getElementsByClassName("color-item");getColor();functiongetColor(){for(leti=0;i<aColorBtn.length;i++){aColorBtn[i].onclick=function(){for(leti=0;i<aColorBtn.length;i++){aColorBtn[i].classList.remove("active");this.classList.add("active");activeColor=this.style.backgroundColor;ctx.fillStyle=activeColor;ctx.strokeStyle=activeColor;}}}}

9.实现改变撤销和重做的功能

实现思路:

保存快照:每完成一次绘制操作则保存一份 canvas 快照到 canvasHistory 数组(生成快照使用 canvas 的 toDataURL() 方法,生成的是 base64 的图片);

撤销和反撤销:把 canvasHistory 数组中对应索引的快照使用 canvas 的 drawImage() 方法重绘一遍;

绘制新图像:执行新的绘制操作时,删除当前位置之后的数组记录,然后添加新的快照。

letundo=document.getElementById("undo");letredo=document.getElementById("redo");//...canvas.onmouseup=function(){painting=false;canvasDraw();}letcanvasHistory=[];letstep=-1;//绘制方法functioncanvasDraw(){step++;if(step<canvasHistory.length){canvasHistory.length=step;//截断数组}//添加新的绘制到历史记录canvasHistory.push(canvas.toDataURL());}//撤销方法functioncanvasUndo(){if(step>0){step--;//ctx.clearRect(0,0,canvas.width,canvas.height);letcanvasPic=newImage();canvasPic.src=canvasHistory[step];canvasPic.onload=function(){ctx.drawImage(canvasPic,0,0);}undo.classList.add('active');}else{undo.classList.remove('active');alert('不能再继续撤销了');}}//重做方法functioncanvasRedo(){if(step<canvasHistory.length-1){step++;letcanvasPic=newImage();canvasPic.src=canvasHistory[step];canvasPic.onload=function(){//ctx.clearRect(0,0,canvas.width,canvas.height);ctx.drawImage(canvasPic,0,0);}redo.classList.add('active');}else{redo.classList.remove('active')alert('已经是最新的记录了');}}undo.onclick=function(){canvasUndo();}redo.onclick=function(){canvasRedo();}

10.兼容移动端

实现思路:

判断设备是否支持触摸

true ,则使用 touch 事件; false ,则使用 mouse 事件

//...if(document.body.ontouchstart!==undefined){//使用touch事件anvas.ontouchstart=function(e){//开始触摸}canvas.ontouchmove=function(e){//开始滑动}canvas.ontouchend=function(){//滑动结束}}else{//使用mouse事件//...}//...

四、踩坑

问题1:在电脑上对浏览器的窗口进行改变,画板不会自适应

解决办法:

onresize响应事件处理中,获取到的页面尺寸参数是变更后的参数 。

当窗口大小发生改变之后,重新设置canvas的宽高,简单来说,就是窗口改变之后,给canvas.width和canvas.height重新赋值。

//记得要执行autoSetSize这个函数哦functionautoSetSize(){canvasSetSize();//当执行这个函数的时候,会先设置canvas的宽高functioncanvasSetSize(){letpageWidth=document.documentElement.clientWidth;letpageHeight=document.documentElement.clientHeight;canvas.width=pageWidth;canvas.height=pageHeight;}//在窗口大小改变之后,就会触发resize事件,重新设置canvas的宽高window.onresize=function(){canvasSetSize();}}

问题2:当绘制线条宽度比较小的时候还好,一旦比较粗就会出现问题

解决办法:看一下文档,得出方法,只需要简单修改一下 绘制线条的代码 就行

//画线函数functiondrawLine(x1,y1,x2,y2){context.beginPath();context.lineWidth=lWidth;//-----加入-----//设置线条末端样式。context.lineCap="round";//设定线条与线条间接合处的样式context.lineJoin="round";//-----加入-----context.moveTo(x1,y1);context.lineTo(x2,y2);context.stroke();context.closePath();}

问题3:如何实现圆形的橡皮檫?

解决办法:

canvas的API中,可以清除像素的就是clearRect方法,但是clearRect方法的清除区域矩形,毕竟大部分人的习惯中的橡皮擦都是圆形的,所以就引入了剪辑区域这个强大的功能,也就是clip方法。用法很简单:

ctx.save()ctx.beginPath()ctx.arc(x2,y2,a,0,2*Math.PI);ctx.clip()ctx.clearRect(0,0,canvas.width,canvas.height);ctx.restore();

上面那段代码就实现了圆形区域的擦除,也就是先实现一个圆形路径,然后把这个路径作为剪辑区域,再清除像素就行了。有个注意点就是需要先保存绘图环境,清除完像素后要重置绘图环境,如果不重置的话以后的绘图都是会被限制在那个剪辑区域中。

问题4:如何兼容移动端?

1.添加meta标签

因为浏览器初始会将页面现在手机端显示时进行缩放,因此我们可以在meta标签中设置meta viewport属性,告诉浏览器不将页面进行缩放,页面宽度=用户设备屏幕宽度

<metaname="viewport"content="width=device-width,initial-scale=1,user-scalable=no,maximum-scale=1.0,minimum-scale=1.0"/>/*页面宽度=移动宽度:width=device-width用户不可以缩放:user-scalable=no缩放比例:initial-scale=1最大缩放比例:maximum-scale=1.0最小缩放比例:minimum-scale=1.0*/

2.在移动端几乎使用的都是touch事件,与PC端不同

由于移动端是触摸事件,所以要用到H5的属性touchstart/touchmove/touchend,但是PC端只支持鼠标事件,所以要进行特性检测。

touch 事件里,是通过 .touches[0].clientX.touches[0].clientY 来获取坐标的,这点要和 mouse 事件区别开。

问题5:出现一个问题就是清空之后,重新画,然后出现原来的画的东西

这个嘛,问题不大,只不过是我漏写context.beginPath(); ,也花了一点时间在上面解决bug,让我想起“代码千万行,注释第一行;编程不规范,同事两行泪 ”,还是按照文档操作规范操作好,真香!!!

感谢你能够认真阅读完这篇文章,希望小编分享的“html5如何通过canvas设置画板”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!