Open closertb opened 4 years ago
写于:2017-08-25
最近做公司的数据展示项目,用的核心插件是Echarts,但在雷达图的展示案列上,需求上出现了需要单轴轮播标签和数据,在看完github上的issue后,这个Echarts3不支持,看了一下源码,似乎有点复杂,改了改,只实现了多个series的轮播,和需求还是有差距,周末反正无聊,何不自己动手撸一个。
想实现如上图这样一个建议雷达图,需要几步?个人总结,需要: 初始化一个canvas对象;
好像要达到的效果就完成了,似乎不难,来吧,实现它。
首先引入一个canvas函数,并为其制定长高,然后获取这个元素,并得到一块平面画布,代码如下:
<div id='main' > <canvas id='canvas' width='600px' height='400px'></canvas> </div>
const draw = document.getElementById('canvas'); const ctx = draw.getContext('2d');
为了后面更方便的计算,我们需要把坐标原点从画布的右上角移到画布的中心,所以我们首先获取画布的长宽,接着使用translate方法,转移坐标原点
const offset = { x:draw.offsetWidth, y:draw.offsetHeight }; ctx.translate(offset.x/2,offset.y/2);
这样我们就初始化了一块画布,并将其坐标原点移到了画布的中心. 这里提示两点:
在echarts中,圆的个数可通过splitNum配置,其实这个实现也不难,可通过下面的代码实现:
const m = Math; const PI = m.PI;//这两个参数后面经常会用,这里提前简单申明 /* 输入参数 *ctx 画布 * radius 要画的最外层圆的半径 * spiltNum 要画的圆的个数 * */ function drawArc(ctx,radius,splitNum){ ctx.beginPath(); //开始画路径 /*这个可通过stokeColor与fillColor设置圆边的颜色和圆的填充色*/ const splitStep =radius/splitNum; for(let i=1;i<=splitNum;i ){ //按splitNum个数,计算并画出相应的圆 ctx.moveTo(i*splitStep,0); //这一句很重要,你需要手动移动你的画笔,而不是任其在画布上连续移动,画出不应该出现的线; ctx.arc(0,0,i*splitStep,0,2*PI,false); } ctx.stroke(); } drawArc(ctx,raduis,3);
这一步就提示一点: ctx.beginPath()与ctx.stroke();总是成对成对出现,缺一个,这线必须出不来。
首先回忆一个高中数学知识,已知一个圆的大小,其一条线与O度角直径成x度角,求其这条线沿Y轴正方向与圆的交点,好难,有没有,久了不摸,知识瞬间回到幼儿园,答案是:(r*sin(x),r.cos(x)),答案怎么这么简单,不信,不信你可以用三个和四个点验证,我会说我就干过这事嘛。好了,进入正题,直接上函数,顺便说一句,我们在计算这个点的同时,也可以把标签的坐标点也一起算出来,直接上代码:
let l = 6; //极坐标点的个数,也急速雷达的维度个数; const single = 2*PI /l ;//计算偏转角度; let pointData=[],labelData=[];//声明两个数组,用于存储计算所得的坐标点; for(let i = 0;i<l;i ){ let x = m.sin(i*single),y=m.cos(i*single); arcData.push([raduis*x,raduis*y]); labelData.push([(raduis 16)*x,(raduis 16)*y]); //这里的16是设置你的标签和你圆周之间的距离值,可以设成一个常量,方便修改; } /*点计算好了,接下来我们需要连接每个点到圆心得连线 输入画布,和要连接的点*/ function drawLine(ctx,data){ ctx.beginPath(); ctx.strokeStyle = 'blue'; for(let i= 0;i<data.length;i ){ ctx.moveTo(0,0);//再次提示,你需要手动移动你的画笔,来开启你的下一次画线 ctx.lineTo(data[i][0],data[i][1]) } ctx.stroke(); } drawLine(ctx,arcData);
提示:其实绘制这几根极坐标也可以采用坐标变换rotate API来执行,比如这样
rotate(single); ctx.lingeTo(0,r);
这样也很简单,但为了后面,我们需要知道这些极坐标也圆的交点,这在后面会很有用,但不得否认canvas的translate和retate是两个很好用的方法.
canvas文字绘制,涉及到的属性和方法有font(设置字体样式),textAlign(设置左右对齐),textBaseline(设置基线,上下对齐),fillText(文字绘制)直接上代码:
let label= ['卫生','安全','交通','住宿','景点','吃88喝']; for(let i = 0;i<l;i ++){ label[i] = { label:label[i], position:labelData[i] } } function drawText(ctx,data,style) { const max = data.length; ctx.font = 'bold 14px Arial'; ctx.textBaseline ='middle'; //这个和textAlign都很重要,决定了整个图的美丑 ctx.fillStyle ='red'; //style.backgroundColor console.log(ctx); /*下面这些很重要,至于为什么,自己体会*/ for(let i=0;i<max;i ){ let x= data[i].position[0]; if((x>=-1)&&(x<=1)){ //由于single值的问题,所以很多时候没有x=0的出现,都是0.000001这种浮点数出现; ctx.textAlign ='center'; }else if(x>1){ ctx.textAlign ='left'; }else{ ctx.textAlign ='right'; } ctx.fillText(data[i].label,...data[i].position); } } drawText(ctx,label);
提示:strokeText与fillText都可以为文本描边,但strokeText使用效果更好;另外使用fillText时,是使用fillStyle为文字设置颜色属性,而strokeText是采用strokeStyle设置文字颜色属性,很重要
其实这一步也相当简单,就是根据点计算在响应极坐标上的落点,然后一一连线,然后为封闭区域着色,直接上代码:
let data = [120,50,150,80,100,140]; for(let i = 0;i<l;i ){ let ratio = data[i]/raduis; pointData.push([arcData[i][0]*ratio,arcData[i][1]*ratio]); } function drawRegion(ctx,data) { const max = data.length; ctx.strokeStyle = 'yellowgreen'; ctx.fillStyle='rgba(10,50,200,0.5)'; //设置了透明度,这样显得更美观 ctx.beginPath(); ctx.moveTo(...data[0]); for(let i=0;i<max;i ){ ctx.lineTo(...data[i]); } ctx.lineTo(...data[0]); ctx.fill() ctx.stroke(); } drawRegion(ctx,pointData);
Echarts怎么做的,Echarts可以配置拐点样式,那我们也为我们的雷达图加上拐点吧。 如果你想用绘制一个线,并根据拐点圆的大小和切入角度,然后计算出这条线的长度,再绘制这个拐点,然后再接着画线,这样真的很难,有没有简单点的,有,就是投机取巧,绘完线后再绘制拐点,并将这个拐点圆填充,这样看起来就像是我们连着画的啦,但这样也有bug,如果我们没有填充颜色,或者填充的颜色有透明度,那么拐点下两条线相交就可见了,我们的连续绘制假象也就被自己拆穿了。还是上代码把:
function drawPoint(ctx,data) { const max = data.length; const r= 3; ctx.fillStyle='white'; //rgba(10,50,200,0.5) ctx.beginPath(); for(let i=0;i<max;i ){ ctx.moveTo(data[i][0] r,data[i][1]); ctx.arc(...data[i],r,0,2*PI); ctx.fill(); } ctx.stroke(); drawPoint(ctx,pointData); }
至此,我们基础的图形就画完了,现在我们要做最重要的一步,也就是轮播了。
还是直接上代码吧,下一篇文章再详说:
let step =-1; function removeLabel(dom) { (dom.querySelectorAll('label').length)&&(dom.removeChild(dom.querySelector('label'))); } function autoLabel(point){ removeLabel(); let label =document.createElement('label'); label.innerHTML ='show:0999'; //这里先写成定值,后面会详述怎样定制轮播值 label.style.position='absolute'; label.style.top=point[1] offset.y/2 'px'; label.style.left=point[0] offset.x/2 'px' ; label.style.border='1px solid yellowgreen'; label.style.background = 'gray'; label.style.opacity = '0.5' label.style.zIndex = 999; dom.appendChild(label); } setInterval(function(){ step = (step 1)%6; autoLabel(draw,pointData[step]); },1000)
好了,至此我们就简单的实现了一个暂时没法定制的雷达轮播图,在下一篇文章我们将会根据这里提到的思想,开发一个与简易版的echarts radar插件。 如果发现有任何叙述不正确之处或有更好的想法,还请指正。 源码地址,经供参考
本文系列: 从0开始撸一个支持单轴轮播的雷达图(Ehcarts的单轴显示问题)之中篇 从0开始撸一个支持单轴轮播的雷达图(Ehcarts的单轴显示问题)之末篇 本文首发于:http://closertb.site ,转载请注明
写于:2017-08-25
引子
最近做公司的数据展示项目,用的核心插件是Echarts,但在雷达图的展示案列上,需求上出现了需要单轴轮播标签和数据,在看完github上的issue后,这个Echarts3不支持,看了一下源码,似乎有点复杂,改了改,只实现了多个series的轮播,和需求还是有差距,周末反正无聊,何不自己动手撸一个。
整理一下思路
想实现如上图这样一个建议雷达图,需要几步?个人总结,需要: 初始化一个canvas对象;
好像要达到的效果就完成了,似乎不难,来吧,实现它。
分布实现
初始化一块画布
首先引入一个canvas函数,并为其制定长高,然后获取这个元素,并得到一块平面画布,代码如下:
为了后面更方便的计算,我们需要把坐标原点从画布的右上角移到画布的中心,所以我们首先获取画布的长宽,接着使用translate方法,转移坐标原点
这样我们就初始化了一块画布,并将其坐标原点移到了画布的中心. 这里提示两点:
画同心圆
在echarts中,圆的个数可通过splitNum配置,其实这个实现也不难,可通过下面的代码实现:
这一步就提示一点: ctx.beginPath()与ctx.stroke();总是成对成对出现,缺一个,这线必须出不来。
计算极坐标线与外侧圆的交点
首先回忆一个高中数学知识,已知一个圆的大小,其一条线与O度角直径成x度角,求其这条线沿Y轴正方向与圆的交点,好难,有没有,久了不摸,知识瞬间回到幼儿园,答案是:(r*sin(x),r.cos(x)),答案怎么这么简单,不信,不信你可以用三个和四个点验证,我会说我就干过这事嘛。好了,进入正题,直接上函数,顺便说一句,我们在计算这个点的同时,也可以把标签的坐标点也一起算出来,直接上代码:
提示:其实绘制这几根极坐标也可以采用坐标变换rotate API来执行,比如这样
这样也很简单,但为了后面,我们需要知道这些极坐标也圆的交点,这在后面会很有用,但不得否认canvas的translate和retate是两个很好用的方法.
根据前面标签的计算点,绘制标签
canvas文字绘制,涉及到的属性和方法有font(设置字体样式),textAlign(设置左右对齐),textBaseline(设置基线,上下对齐),fillText(文字绘制)直接上代码:
提示:strokeText与fillText都可以为文本描边,但strokeText使用效果更好;另外使用fillText时,是使用fillStyle为文字设置颜色属性,而strokeText是采用strokeStyle设置文字颜色属性,很重要
根据输入的点,绘制雷达闭合区域
其实这一步也相当简单,就是根据点计算在响应极坐标上的落点,然后一一连线,然后为封闭区域着色,直接上代码:
也许拐点区域特殊处理,更有味道
Echarts怎么做的,Echarts可以配置拐点样式,那我们也为我们的雷达图加上拐点吧。 如果你想用绘制一个线,并根据拐点圆的大小和切入角度,然后计算出这条线的长度,再绘制这个拐点,然后再接着画线,这样真的很难,有没有简单点的,有,就是投机取巧,绘完线后再绘制拐点,并将这个拐点圆填充,这样看起来就像是我们连着画的啦,但这样也有bug,如果我们没有填充颜色,或者填充的颜色有透明度,那么拐点下两条线相交就可见了,我们的连续绘制假象也就被自己拆穿了。还是上代码把:
至此,我们基础的图形就画完了,现在我们要做最重要的一步,也就是轮播了。
做一个简单的自动轮播
还是直接上代码吧,下一篇文章再详说:
好了,至此我们就简单的实现了一个暂时没法定制的雷达轮播图,在下一篇文章我们将会根据这里提到的思想,开发一个与简易版的echarts radar插件。 如果发现有任何叙述不正确之处或有更好的想法,还请指正。 源码地址,经供参考
本文系列: 从0开始撸一个支持单轴轮播的雷达图(Ehcarts的单轴显示问题)之中篇 从0开始撸一个支持单轴轮播的雷达图(Ehcarts的单轴显示问题)之末篇 本文首发于:http://closertb.site ,转载请注明