canvas贝塞尔曲线运动,canvas三次贝塞尔曲线
写在最前
这次来分享一下如何在canvas中“平滑”绘制的折线线段的棱角,也就是用贝塞尔曲线穿过各种描点来代替原来的折线图。
为什么要平滑拟合折线段
我们来看看e charts下折线图的渲染效果:
一开始我并没有注意到这条折线其实是穿过曲线的,我只觉得这是一个简单的点画,所以我一开始意识到的“简(丑)易(贱)”的版本是这样的:
不讲究风格,关键是实现之后我发现好像人家对Echarts的实现很顺利,导致了后来的讨论。如何有规律的画出光滑的曲线?
翻译
我们来看看最终模仿的实现:
因为不知道Echarts内部是怎么实现的(逃
它看起来非常圆,非常接近我们最初的想法。查看曲线是否穿过跟踪点:
好吧!结果显而易见。现在让我们再次看看我们的实现方法。
实施程序
绘制线图和贝塞尔曲线,平滑拟合仿真数据。
var data=[math . random()* 300];for(var I=1;i 50I) {//根据e charts data . push(math . round((math . random()-0.5)* 20 data[I-1]);} option={canvas: {ID: canvas},Series: {name: analog data ,Item Style: {color: RGB (255,70,131)},Areastyle: {color: RGB (255,158,68)绘制折线图
首先,初始化一个构造函数来放置您需要的数据:
函数linear gradient(option){ this . canvas=document . getelementbyid(option . canvas . id)this . CTX=this . canvas . get context( 2d )this . width=this . canvas . width this . height=this . canvas . height this . tooltip=option . tooltip this . title=option . text this . series=option.series//store模拟数据}绘制折线图:
linear gradient . prototype . draw 1=function(){//折线参考线.//考虑到canvas中的原点是左上角,//所以下面要做一些转换。//diff是x,y轴等于除以数据的最大值和最小值的范围。this . series . data . foreach(function(item,index) {var x=diffx * index,y=math.floor (self。height-diffy *(项目数据最小值))自身。CTX.lineto (x,y)//绘制每个数据点}).}
贝塞尔曲线的关键在于控制点的选取。这个网站可以动态显示不同控制点绘制的不同曲线。以及用于控制点的计算。笔者还是选择了百度。毕竟数学不好:)。对具体算法感兴趣的同学可以多了解一下。现在来说说直接计算控制点的结论。
上式涉及四个坐标点,当前点、前一点和后两点,坐标值如下图所示时绘制的曲线如下:
但是会有一个问题,起点和终点都不能用这个公式。但是,文章也给出了边界值的处理方法:
因此,当折线被平滑曲线代替时,计算边界值和其他控制点,然后代入贝塞尔函数以完成:
//this . series . data . foreach(function(item,index){//找到上一点和下一点之间的控制点var scale=0.1 //对于正数的ab控制点,可以自己分别调整var last1X=diffX * (index-1)。1 Last y=math . floor(self . height-diffy *(self . series . data[index-1]-data min)),//前一点的坐标last2X=diffX * (index-2),Last 2y=math . floor(self . height-diffy *(self . series . data[index-2]-data min)),//前两点的坐标nowX=diffX * (index),Nowy=math.floor (self。身高差异*(自我。series.data [index]-datamin)),//当前点坐标nextX=difx *(index 1),Nexty=math . floor(self . height-diffy *(self . series . data[index 1]-data min)),//下一点坐标cAx=last1X (nowX-last2X) * scale,cAy=last1Y (nowY - last2Y) * scale,cBx=nowX - (nextX - last1X) * scale,cBy=nowY-(Nexty-last 1y)* scale if(index===0 nowY)return } else if(index===1){ cAx=last 1x(nowX-0)* scale cAy=last 1y(nowY-self . height)* scale } else if(index===self . series . data . length-1){ cBx=nowX-(nowX-last 1x)* scale cBy=nowY-(nowY-last 1y)* scale } self . CTX . beziercurveto(cAx,cAy,cBx,cBy,nowX,nowY); //绘制前一点到当前点的贝塞尔曲线})因为我遍历的每一个点都是当前点,但是文章中给出的公式是会知道下一个点的控制点算法,所以我在代码实现中把所有点的计算都提前了一位。当index=0,也就是初始点的时候,就不需要画曲线了,因为我们画的是从上一点到当前点的曲线,没有到0的曲线需要画。从index=1,我们可以正常的画出从0到1的曲线。因为index=1前面没有第二个点,属于边值点,也就是需要特殊计算,最后一个点。其余按正规公式计算,将AB的xy坐标代入贝塞尔函数。
贝塞尔曲线平滑拟合
请在此处查看源代码。
这就是本文的全部内容。希望对大家的学习和支持有帮助。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。