canvas 画曲线,canvas画曲线图
功能需求
需求:需要实现一个可以自由书写的小画板。
简单实现
对于熟悉canvas的人来说,这个要求很简单,大致逻辑如下:
1)监控事件指针下降、指针移动、指针上升
2)标记是否拖放画线模式变量isDrawing,在down事件中设置为true,在up事件中设置为false。
3)使用canvas的api,设置线条样式,调用画线接口的lineTo方法。
只用几十行代码就可以实现:
!doctype html htmlhead meta charset=utf-8样式canvas { border:1px solid # CCC } body { margin:0;}/style/head body style= overflow:hidden;背景色:rgb(250,250,250);触摸操作:无;canvas id= c width= 1920 height= 1080 /canvas脚本var El=document . getelementbyid( c );var CTX=El . get context( 2d );//设置画线样式ctx.strokeStyle= redCTX . line width=1;ctx.lineJoin= roundctx.lineCap= roundvar正在绘制;//标记是否绘制//存储坐标点let lastX,lastYdocument . body . onpointerdown=function(e){ console . log( pointer down );isDrawing=truelastX=e.clientXlastY=e.clientY};document . body . onpointermove=function(e){ console . log( pointer move );if (isDrawing) { draw(e.clientX,e.clientY,lastX,lastY);} lastX=e.clientX,lastY=e.clientY};document . body . onpointerup=function(e){ if(is drawing){ draw(e . clientx,e.clientY,lastX,lastY);} lastX=e.clientX,lastY=e.clientYisDrawing=false};函数draw(x,y,lastX,lastY){ CTX . begin path();ctx.moveTo(lastX,lastY);ctx.lineTo(x,y);CTX . stroke();} /script/body/html实现效果如下:
以上简单实现了画板功能,要求不高的用户可以使用,但是一旦达到某些要求,就无法交付这个产品了。仔细看的话,断线感太强了。
为什么会有折线感呢?
主要原因:
我们调用的api方法lineTo是两点连接,也就是一条直线。
浏览器频繁地收集鼠标事件mousemove,并不是鼠标移动经过的每个像素都会触发该事件。
鼠标移动越快,两点之间的距离越远,断线感越明显。
如何能绘制平滑的曲线?
canvas提供的api中有现成的接口,贝塞尔系列的接口可以满足我们的要求。接下来说一下用二次贝塞尔曲线画光滑曲线。
quadraticCurveTo(cpx,cpy,x,y)
二次贝塞尔曲线接口需要四个参数,cpx和cpy是曲线的控制点,X和Y是曲线的端点。
有人问那条曲线的起点在哪里?其实曲线的起点取决于最后的运行状态,可以是moveTo的位置,也可以是lineTo的位置,也可以是Bessel的终点。
那么如何调用quadraticCurveTo,如何传递参数呢?
我们需要找出关键位置,用例子直接告诉你。
1)如果我们用鼠标收集ABCDEF的六个点。
2)取前三个点ABC进行计算,BC的中点B1,以A为起点,B为控制点,B1为终点,那么就可以用quadraticCurveTo画出这样一条贝塞尔曲线。
3)接下来,以B1为起点,C为控制点,C1为终点,计算CD的中点C1。然后用quadraticCurveTo就可以画出这样的贝塞尔曲线。
4)以此类推,当到达最后一点时,以D1为起点,E为控制点,F为终点,完成贝塞尔作图。
根据算法进行代码改造
好了,我们引入了特定算法的影响,然后用这个算法来改造我们之前的代码:
!doctype html html head meta charset=utf-8样式canvas { border:1px solid # CCC }正文{ margin:0;}/style/head body style= overflow:hidden;背景色:rgb(250,250,250);触摸操作:无;画布id= c width= 1920 height= 1080 /canvas脚本var El=文档。getelementbyid( c );var CTX=El。获取上下文(“2d”);//设置绘制线条样式ctx.strokeStyle= redCTX。线宽=1;CTX . line join= round CTX . line cap= round var正在绘制;//标记是否要绘制//存储坐标点让点数=[];文档。身体。onpointerdown=函数(e){ console。log(“指针向下”);is drawing=true points . push({ x:e . clientx,y:e . clienty });};文档。身体。onpointermove=function(e){ console。日志(“指针移动”);if (isDrawing) { draw(e.clientX,e . clienty);} };文档。身体。onpointerup=函数(e){ if(正在绘制){ draw(e . clientx,e . clienty);}点=[];is drawing=false };函数draw(mousex,mousey) { points.push({ x: mousex,y:mousey });CTX。begin path();设x=(点数[点数。长度- 2]。x点[点数.长度- 1].x)/2,y=(点数[点数。长度- 2]。y点[点数.长度- 1].y)/2;如果(分。长度==2){ CTX。移到(点[点。长度-2]).x,点数[点数.长度- 2].y);ctx.lineTo(x,y);} else { let lastX=(points[points。长度-3]).x点[点数.长度- 2].x)/2,lastY=(点数[点数。长度- 3]。y点[点数.长度- 2].y)/2;ctx.moveTo(lastX,lastY);CTX。二次曲线到(点[点]。长度-2]).x,点数[点数.长度- 2].y,x,y);} ctx.stroke().points.slice(0,1);}/脚本/正文/html在原有基础上我们用了一个数组点保存鼠标经过的点,根据算法可知绘制贝塞尔曲线至少要用三个点,绘制过程中维护点数组。
实现效果如下,可见平滑了很多!
后续文章:
实现蜡笔效果,实现笔锋效果,画笔性能优化
到此这篇关于帆布小画板之平滑曲线的实现的文章就介绍到这了,更多相关帆布平滑曲线内容请搜索以前的文章或继续浏览下面的相关文章,希望大家以后多多支持!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。