使用canvas绘制图形步骤,如何用canvas画画

  使用canvas绘制图形步骤,如何用canvas画画

  最近写了一个类似截图的简单画图小工具,画线,画矩形,画圆形,还可以选颜色,就像这样。

  在写的过程中,遇到了一些坑,还好爬了出来。也得到了几个老板的建议。我稍微碰了一下zrender,录在这里。

  坑1,绘制过程的预览

  用画布画线没什么不好。移动到和线到。来个代码凑成字数吧(:joy:)

  按下鼠标,开始绘制,记录初始鼠标的位置start paint=(e)={ this . startpaintflag=true;this . paint startx=e . clientx;this . paint starty=e . clienty;}鼠标抬起时,stop drawing stop paint=(e)={ this . startpaintflag=false;} painting=(e)={ const { active color,activeShape }=this.state在绘制过程中,if(this . startpaintflag){ const CTX=this . canvas . get context( 2d );CTX . stroke style=active color;CTX . line width=2;CTX . begin path();if(active shape=== pen ){ CTX . move to(this . paint startx,this . paint starty);ctx.lineTo(e.clientX,e . clienty);} if(active shape=== circle ){ const r=math . sqrt(math . pow(e . clientx-this . paint startx,2)math . pow(e . clienty-this . paint starty,2));ctx.arc(this.paintstartX,this.paintstartY,r,0,2*Math。PI)} if(active shape=== rect ){ CTX . rect(this . paint startx,this.paintstartY,e.clientX - this.paintstartX,e . clienty-this . paint starty);} ctx.stroke()。为下一张图纸记录该运动的最后位置。this . paint startx=e . clientx;this . paint starty=e . clienty;}}}但是画矩形和圆形有一个意外,因为截图工具在画矩形和圆形的时候,有一个预览效果,就是我在画的同时,可以看到我画的形状有多大。如果我按照线条画的思路,我会得到这样一堆图形。

  很好理解,因为mousemove一直在改变位置和距离。那么如果我在开始的时候记录位置,在画矩形和圆形的时候不改变初始位置,那么我会得到如下图

  这也很容易理解,因为没有擦除,每一幅画都在画布上。抹去它不是很好吗?不好,因为画布上画的不是只有一个人。如果我先画一条线,再画一个圆,那么一旦我把它擦掉,之前画的线就没了,这就是纠结QAQ。

  我有一个想法,只有这个图形内部的形状,如上面的一堆同心圆,将被删除。可惜还是不行。一方面可能有其他线条画在里面,另一方面可以拖动图形放大或缩小。那我该怎么办呢?

  叹了口气,喝了一杯水,凝视着窗外,我想到了一个解决办法。为什么我不在画布上再叠一张画布呢?我可以在这叠画布上做任何我想做的事,对吗?

  我们来做个示意图。黑色框架是我们显示的画布,黑色形状表示已经绘制的内容,红色框架是我们在绘制具有预览效果的图片时使用的临时画布,红色形状表示我们在鼠标拖动过程中绘制的预览内容。每次需要绘制预览内容时,我们会生成一个临时画布,放在顶层,随心所欲地绘制,绘制完成后销毁临时画布(鼠标向上),在显示画布(黑框)上绘制最终画布。

  一段代码帮助你理解。

  开始绘制=(e)={ this。startpaintflag=true这个。paint startx=e . clientx这个。油漆开始=e . clienty画矩形和圆形时临时生成一个画布if (this.state.activeShape!==笔){这个。临时画布=文档。createelement(“canvas”);这个。临时画布。宽度=这个。画布。宽度;这个。临时画布。身高=这个。画布。身高;设置一些定位样式这个。临时画布。风格。CSS text= position:absolute;top:0;左:0;z索引:0;;附加到需要的容器元素里document.querySelector( .包含)。appendChild(这个。临时画布);}};停画=(e)={ this。startpaintflag=falseconst { activeShape,active color }=this . state if(active shape!==钢笔){从容器元素里删除临时画布document.querySelector( .包含)。移除子代(this。临时画布);this.tempCanvas=null将lastDrawData记录的绘制数据,绘制到展示用的画布上const CTX=这个。画布。获取上下文(“2d”);CTX。笔画样式=活动颜色;CTX。线宽=2;CTX。begin path();if(active shape=== circle ){ const { x,y,r }=this.lastDrawDatactx.arc(x,y,r,0,2 * Math .PI);} else { const { x,y,width,height }=this . lastdrawdatactx . rect(x,y,width,height);} ctx.stroke().this.lastDrawData=null } }painting=(e)={ const { active color,activeShape }=this.stateif(this。startpaintflag){ const CTX=this。画布。获取上下文(“2d”);CTX。笔画样式=活动颜色;CTX。线宽=2;画线的逻辑不动if(active shape=== pen ){ CTX。begin path();ctx.moveTo(this.paintstartX,this。油漆开始);ctx.lineTo(e.clientX,e . clienty);CTX。笔画();这个。paint startx=e . clientx这个。油漆开始=e . clienty}否则{有预览的图形绘制在临时画布上const tempCtx=this。临时画布。获取上下文(“2d”);tempctx。笔画样式=活动颜色;tempctx。线宽=2;每次绘制前清除画布tempCtx.clearRect(0,0,this.canvas.width,this。画布。身高);tempctx。begin path();if(活动形状=== circle ){ const r=math。sqrt(数学。pow(e . clientx-this。画图startx,2)数学。pow(e . clienty-this。画图starty,2));tempCtx.arc(this.paintstartX,this.paintstartY,r,0,2 * Math .PI);绘制的数据记录在一个变量里这个。lastdrawdata={ x:this。paint startx,y: this.paintstartY,r,};} else { tempctx。rect(这个。paint startx,this.paintstartY,e.clientX - this.paintstartX,e . clienty-this。油漆开始);这个。lastdrawdata={ x:this。paint startx,y: this.paintstartY,width:e . clientx-this。油漆开始x,高度:e .客户-这一点。paint starty,};} tempctx。笔画();} }};坑2,窗口大小变更

  如果画着画着,突然用户将窗口大小变了,你说我是保持画布大小不变呢,还是让画布大小随着窗口改变而改变,如果窗口缩小,那么保持画布大小不变是没什么大问题的,但是窗口如果变大,画布区域又是自适应的,那么就不得不跟随改变了,但是帆布的宽高改变的话,内容是会清除的,那么就面临两种选择:

  用变量将绘制的每一个坐标记录下来,宽高变更后重新绘制;将画布的内容直接作为图像(这个形容不准确,理解意思就行)保存下来第一种我没试过,不过可想而知如果画的内容多了,应该会闪烁一下,第二种,就我所知有两种形式

  首先用getImageData保存图像,改变大小,用putImageData绘制,只能裁剪图像,不能拉伸constimgdata=CTX。GetImageData (0,0,canvas.width,canvas . height);画布.=newWidthcanvas.height=newHeightctx.putImageData(imgData,0,0);第二,创建一个临时画布,把图形向下画,改变大小,用drawImage来画,就是const new canvas=document . createelement( canvas )可以拉伸图像;new canvas . width=canvas . width;new canvas . height=canvas . height;newCanvas.getContext(2d )。drawImage(canvas,0,0);画布.=newWidthcanvas.height=newHeightctx.drawImage(newCanvas,0,0);起初,我选择了drawImage。如果窗口没有按比例缩放(一般是无法按比例缩放的),图像是可以拉伸的,但是拉伸一两次后图像就变得很模糊了,所以可能还是不要改变图像的比例比较好,具体看场景。

  这就是这篇关于踩着原生画布绘图小工具的坑往上爬的文章。更多相关画布绘图小工具,请搜索之前的文章或继续浏览下面的相关文章。希望你以后能支持我!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: