canvas实现画图,canvas画图
本文主要介绍:
介绍项目效果展示,逐步实现项目效果,踩坑一、项目介绍
名称:智慧画板
技术堆栈:HTML5、CSS3、JavaScript、移动
功能描述:
支持PC端和移动端在线绘画功能,实现画笔颜色任意选择、画笔粗细调整、橡皮擦擦除等绘画功能,实现在线画板本地保存功能,支持取消和返回操作,自定义背景色二、项目效果展示。
项目地址预览地址
预览图片
PC预览:
移动终端的预览:
看了上面的预告,体验了智绘画板,觉得还可以。记得赞一下。不管你是不是很激动,反正我挺激动的。毕竟自己一个人做到了项目效果,还是挺自豪的。说了一大堆废话,就可以开始敲代码了,达到想要的效果!
注:以下项目效果主要是关于JavaScript的,以下仅提供实现思路的代码,并非全部代码。
三、一步步实现项目效果
(1)分析页面
通过用例图,我们知道用户进入我们的网站有哪些功能。
用户可以做什么:
改变画笔粗细,切换画笔颜色,用橡皮擦擦掉不想要的部分,清空画板,将自己的画另存为图片,撤销和重做,切换画板背景色,兼容移动终端(支持触摸)(2)制作HTML布局。
在写html的时候,我介绍了css文件和js文件。
!DOCTYPE html lang= en 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=快捷图标href= ./image/favicon。png type= image/x-icon link rel=样式表 href= ./CSS/style。CSS /床头画布id= canvas /canvas div class= BG-BTN /div div class= color-group id= BG group H3选择背景颜色:/H3 ul class= clear fix Li class= bgcolor-item style= background-color:blue;/Li Li class= bgcolor-item style= background-color:black;/Li Li class= bgcolor-item style= background-color:# ff 3333;/Li Li class= bgcolor-item style= background-color:# 0066 ff;/Li Li class= bgcolor-item style= background-color:# ffff 33;/Li Li class= bgcolor-item style= background-color:# 33cc 66;/Li Li class= bgcolor-item style= background-color:gray;/Li Li class= bgcolor-item style= background-color:# f 34334;/Li Li class= bgcolor-item style= background-color:# fff;盒影:0 1px 2px 0 rgba(32,33,36,0.28);/Li Li class= bgcolor-item style= background-color:# 9b 27 AC;/Li Li class= bgcolor-item style= background-color:# 4cb 050;/Li Li class= bgcolor-item style= background-color:# 029688;/Li/ul I class=关闭BTN /I/div div class=工具 div class=容器按钮class=保存 id=保存 title=保存/button button class= brush active id= brush title=画笔/button button class= eraser id= eraser title=橡皮擦/button button class= clear id= clear title=清屏/button button class= 撤消 id=撤消 title=撤销/button button class=重做id=重做title=再做/button/div/div div class= pen-detail id= pen detail I class= closeb TN /I p笔大小/p span class= circle-box id= thickness /I/span输入类型= range id= range 1 min= 1 max= 10 value= 1 p笔颜色/p ul class= pen-color clear fix Li class= color-item active style= background-color:black; /Li Li class= color-item style= background-color:# ff 3333;/Li Li class= color-item style= background-color:# 99cc 00;/Li Li class= color-item style= background-color:# 0066 ff;/Li Li class= color-item style= background-color:# ffff 33;/Li Li class= color-item style= background-color:# 33cc 66;/li /ul p不透明度/p i class=showOpacity/i输入类型= range id= range 2 min= 1 max= 10 value= 1 /div script src= ./js/main.js/script/body/html(三)用半铸钢钢性铸铁(铸造半钢)美化界面
钢性铸铁代码可以根据个人习惯进行美化界面,所以这里就不写钢性铸铁的代码了,大家可以直接看项目代码或者从开发者工具中审查元素观看。如果有问题可以私聊我,我觉得问题不大。
(四)使用射流研究…实现项目的具体功能
1.准备工作
首先,准备个容器,也就是画板了,前面的超文本标记语言已经书写好这个容器,这里纯属是废话。
画布id=画布/canvas然后初始化射流研究…
让画布=文档。getelementbyid(“canvas”);让上下文=画布。获取上下文(“2d”);我打算把画板做成全屏的,所以接下来设置一下帆布的宽高
让页面宽度=文档。documentelement。客户端宽度;让页面高度=文档。documentelement。客户身高;canvas . width=page width canvas . height=page height由于部分工业管理学(工业工程)不支持画布,如果要兼容即,我们可以创建一个画布,然后使用excanvas初始化,针对工业管理学(工业工程)加上exCanvas.js,这里我们明确不考虑即。
但是我在电脑上对浏览器的窗口进行改变,画板不会自适应的放缩。解决办法:
//记得执行函数autoSetSize。函数AutosetSize(){ canvas setsize();//执行该函数时,首先设置画布的宽度和高度。函数canvas setsize(){ let page width=document . documentelement . client width;let page height=document . documentelement . client height;canvas.width=pageWidthcanvas.height=pageHeight}//窗口大小改变后,会触发resize事件,重置画布窗口的宽度和高度,onresize=function(){ canvas setsize();}}2.实现绘图功能
实现思路:监控鼠标事件,用drawLine()方法绘制记录的数据。
初始化当前画板的画笔状态,painting=false。当鼠标被按下(mousedown)时,将painting设置为true,这意味着绘画正在进行中,并且鼠标没有被释放。记录鼠标点。鼠标按下时,mousemove为把点记录并绘制。如果鼠标移动太快,浏览器跟不上绘制速度,那么点与点之间就会有空隙,所以我们需要用线将绘制的点连接起来(lineTo())。当释放鼠标(mouseup)时,将painting设置为false。注意:这种drawCircle的方法其实不用写字也可以用。这个方法只是为了让大家明白从哪里开始点击?
函数listent touser(){//定义一个变量来初始化画笔状态let painting=false//记录画笔let last point的最后位置={x: undefined,y:undefined };//鼠标按下事件canvas . onmousedown=function(e){ painting=true;设x=e.clientX设y=e.clientYlastPoint={x:x, y :y };drawCircle(x,y,5);}//鼠标移动事件canvas . onmousemove=function(e){ if(painting){ let x=e . clientx;设y=e.clientY设newPoint={x:x, y :y };drawLine(lastPoint.x,lastPoint.y,newPoint.x,new point . y);lastPoint=newPoint} }//鼠标释放事件canvas . onmouseup=function(){ painting=false;} }//画点函数函数画圆(x,y,半径){//新建路径。生成后,图形绘制命令指向路径生成路径。context . begin path();//以(x,y)为圆心,画一个半径为的圆弧(圆)。//按照逆时针(默认为顺时针)给定的方向,从startAngle到endAngle的末端生成。context.arc(x,y,半径,0,数学。PI * 2);//通过填充路径的内容区域生成实心图形context . fill();//路径关闭后,图形绘制命令再次指向上下文。context . close path();}函数drawline (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 . close path();}3.实现橡皮擦功能
实施思路:
获取橡皮擦元素设置的橡皮擦初始状态,eraserEnabled=false。监控橡皮擦点击事件,点击橡皮擦,改变橡皮擦状态,eraserEnabled=true,切换类实现被激活的效果。当eraserEnabled为true时,移动鼠标使用context.clearRect()实现橡皮擦。但是我发现在canvas API中,clearRect方法是可以清除像素的方法,但是clearRect方法的清除区域是矩形的。毕竟大部分人的橡皮擦都是圆的,所以引入了这个强大的裁剪区域功能,也就是clip方法。下面的代码使用context.clearRect()实现eraser。请看坑踩部分,了解如何更好的实现橡胶抛光。
让橡皮擦=文档。getelementbyid( eraser );let eraserEnabled=false//记得要执行听众这个函数哦函数listenToUser() { //.代表省略了之前写的代码//.//鼠标按下事件画布。onmousedown=function(e){//.if(eraserEnabled){//要使用eraser context.clearRect(x-5,y-5,10,10) }else{ lastPoint={x:x, y:y} } } //鼠标移动事件画布。onmousemove=function(e){ let x=e . clientx;设y=e .客户如果(!画图){ return } if(eraserEnabled){ context。clear rect(x-5,y-5,10,10);}else{ var newPoint={x:x, y :y };drawLine(lastPoint.x,lastPoint.y,newPoint.x,newPoint。y);lastPoint=newPoint} } //.}//点击橡皮檫橡皮擦。onclick=function(){ eraser enabled=true;橡皮擦。班级名单。添加(“活动”);刷。班级名单。删除(“活动”);}4.实现清屏功能
实现思路:
获取元素节点。
点击清空按钮清空帆布画布。
让reSetCanvas=document。getelementbyid( clear );//实现清屏resetcanvas。onclick=函数(){ CTX。清除rect(0,0,canvas.width,canvas。身高);setCanvasBg("白色");}//重新设置帆布背景颜色函数setCanvasBg(color){ CTX。填充样式=颜色;ctx.fillRect(0,0,canvas.width,canvas。身高);}5.实现保存成图片功能
实现思路:
获取画布。今日网址在页面里创建并插入一个a标签a标签超链接等于canvas.toDateURL,并添加下载属性点击保存按钮,一个标签触发点击事件让保存=文档。getelementbyid(“save”);//下载图片保存。onclick=function(){ let imgUrl=canvas。toda taurl( image/png );让saveA=document。createelement( a );文档。身体。appendchild(saveA);savea . href=imgurlsavea . download= mypic (新日期)。getTime();saveA.target= _ blanksavea。单击();}6.实现改变背景颜色的功能
实现思路:
获取相应的元素节点。给每一个班级为背景颜色-项目的标签添加点击事件,当点击事件触发时,改变背景颜色。点击设置背景颜色的差异之外的地方,实现隐藏那个第5部分。让我们选择BG=document。查询选择器(.BG-BTN’);设BG group=document。查询选择器(.颜色组);设bgcolorBtn=document。查询selectorall(.bgcolor-item );让penDetail=document。getelementbyid( penDetail );let activeBgColor= # fff//实现了切换背景颜色对于(设I=0;长度i ) { bgcolorBtn[i].onclick=function (e) { //阻止冒泡e。停止传播();对于(设I=0;I bgcolorBtn . length I){ bgcolorBtn[I]。班级名单。删除(“活动”);这个。班级名单。添加(“活动”);activeBgColor=this。风格。背景颜色;setCanvasBg(activeBgColor);} } }文档。onclick=function(){ BG group。班级名单。删除(“活动”);}选择BG。onclick=function(e){ BG group。班级名单。添加(“活动”);e。停止传播();}7.实现改变画笔粗细的功能
实现思路:
实现让设置画笔的属性的对话框出现。获取相应的元素节点。当输入=范围的元素发生改变的时候,获取到的值赋值给lWidth。然后设置context.lineWidth=lWidth。设范围1=文档。getelementbyid(“范围1”);设lWidth=2;设ifPop=falserange 1。onchange=function(){ console。日志(范围1。值);控制台。日志(范围1的类型。值)厚度。风格。transform= scale((parse int(range 1。值)));控制台。原木(厚度。风格。transform)lWidth=parse int(范围1。值* 2);}//画线函数函数画线(x1,y1,x2,y2){ //.context.lineWidth=lWidth//.}//点击画笔刷。onclick=function(){ eraserEnabled=false;刷。班级名单。添加(“活动”);橡皮擦。班级名单。删除(“活动”);如果(!ifPop){ //弹出框console.log(弹一弹)pendetail。班级名单。添加(“活动”);} else { pendetail。班级名单。删除(“活动”);} ifPop=!ifPop}8。实现改变画笔颜色的功能
实现思路跟改变画板背景颜色的思路类似。
设aColorBtn=document。getelementsbyclassname( color-item );getColor();函数getColor(){ for(设I=0;长度;长度;长度;长度.onclick=function () { for(设I=0;长度;长度;长度。班级名单。删除(“活动”);这个。班级名单。添加(“活动”);主动色=这个。风格。背景颜色;CTX。填充样式=活动颜色;CTX。笔画样式=活动颜色;} } }}9.实现改变撤销和重做的功能
实现思路:
保存快照:每完成一次绘制操作则保存一份帆布快照到帆布历史数组(生成快照使用帆布的toDataURL()方法,生成的是base64的图片);撤销和反撤销:把帆布历史数组中对应索引的快照使用帆布的drawImage()方法重绘一遍;绘制新图像:执行新的绘制操作时,删除当前位置之后的数组记录,然后添加新的快照让撤销=文档。getelementbyid(“undo”);让重做=文档。getelementbyid(重做);//.画布。onmouseup=function(){ painting=false;canvasDraw();}让画布历史=[];设step=-1;//绘制方法函数canvasDraw(){ step;如果(step canvashistory。长度){ canvashistory。长度=步长;//截断数组} //添加新的绘制到历史记录画布历史。推(画布。toda taurl());}//撤销方法函数canvasUndo(){ if(第0步){ step-;//ctx.clearRect(0,0,canvas.width,canvas。身高);let canvasPic=new Image();canvaspic。src=画布历史[步骤];canvasPic。onload=函数(){ CTX。绘制图像(canvasPic,0,0);}撤销。班级名单。添加(“活动”);} else { undo。班级名单。删除(“活动”);警报(不能再继续撤销了);}}//重做方法函数canvasRedo(){ if(步骤画布历史。长度-1){步长;let canvasPic=new Image();canvaspic。src=画布历史[步骤];canvaspic。onload=function(){//CTX。清除rect(0,0,canvas.width,canvas。身高);ctx.drawImage(canvasPic,0,0);}重做。班级名单。添加(“活动”);} else {重做。班级名单。移除(“活动”)警报(已经是最新的记录了);} }撤销。onclick=function(){ canvasUndo();}重做。onclick=function(){ canvasRedo();}10.兼容移动端
实现思路:
判断设备是否支持触摸没错,则使用触控事件;假的,则使用老鼠事件//.if (document.body.ontouchstart!==未定义){ //使用触控事件一个vas。ontouchstart=function(e){//开始触摸}画布。ontouchmove=function(e){//开始滑动}画布。ontouchend=function(){//滑动结束}}else{ //使用老鼠事件//.}//.四、踩坑
问题1:在电脑上对浏览器的窗口进行改变,画板不会自适应
解决办法:
在onresize响应事件处理中,获取的页面大小参数就是变更后的参数。
当窗口大小改变时,重置画布的宽度和高度。简单地说,在窗口改变后,给canvas.width和canvas.height赋值
//记得执行函数autoSetSize。函数AutosetSize(){ canvas setsize();//执行该函数时,首先设置画布的宽度和高度。函数canvas setsize(){ let page width=document . documentelement . client width;let page height=document . documentelement . client height;canvas.width=pageWidthcanvas.height=pageHeight}//窗口大小改变后,会触发resize事件,重置画布窗口的宽度和高度,onresize=function(){ canvas setsize();}}问题2:当绘制线条宽度比较小的时候还好,一旦比较粗就会出现问题
解决方法:看文档获取方法,只需简单修改绘制线条的代码即可。
//画线函数functiondrawline (x1,y1,x2,y2){ context . begin path();context.lineWidth=lWidth/////设置线端样式。context.lineCap= round//设置行的样式context.lineJoin=round 和行的间接连接;//-join-context.moveto (x1,y1);context.lineTo(x2,y2);context . stroke();context . close path();}问题3:如何实现圆形的橡皮檫?
解决方案:
在canvas API中,clearRect方法是可以清除像素的方法,但是clearRect方法有一个矩形的清除区域。毕竟大部分人的橡皮擦都是圆的,所以引入了这个强大的裁剪区域功能,也就是clip方法。用法很简单:
CTX . save()CTX . begin path()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 viewport属性,告诉浏览器不要缩放页面,页面宽度=用户设备的屏幕宽度。
meta name= viewport content= width=device-width,initial-scale=1,User-scale=no,maximum-scale=1.0,Minimum-scale=1.0/*页面宽度=mobile width:width=device-width用户无法缩放:User-scaled=no scaling:initial-scale=1最大缩放:maximum-scale=1.0最小缩放:minimum-scale=1.0*/2。几乎用在移动端
由于移动终端是触摸事件,应该使用H5的属性touchstart/touchmove/touchend。但是PC端只支持鼠标事件,所以需要进行特征检测。
在触摸事件中,坐标是通过。触摸[0]。clientX和。触摸[0]。clientY,不同于鼠标事件。
问题5:出现一个问题就是清空之后,重新画,然后出现原来的画的东西
嗯,问题不大。只是我省略了写context . begin path();并且还花了一点时间在上面解决bug,提醒我“千万行代码,注释第一行;编程不规范,同事两行泪。”按照文件操作规范操作还是好的。好香啊!
这就是本文的全部内容。希望对大家的学习和支持有帮助。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。