资讯专栏INFORMATION COLUMN

从0开始撸一个支持单轴轮播的雷达图(Ehcarts的单轴显示问题)之头篇

wemall / 1690人阅读

摘要:引子最近做公司的数据展示项目,用的核心插件是,但在雷达图的展示案列上,需求上出现了需要单轴轮播标签和数据,在看完上的后,这个不支持,看了一下源码,似乎有点复杂,改了改,只实现了多个的轮播,和需求还是有差距,周末反正无聊,何不自己动手撸一个。

引子

最近做公司的数据展示项目,用的核心插件是Echarts,但在雷达图的展示案列上,需求上出现了需要单轴轮播标签和数据,在看完github上的issue后,这个Echarts3不支持,看了一下源码,似乎有点复杂,改了改,只实现了多个series的轮播,和需求还是有差距,周末反正无聊,何不自己动手撸一个。

整理一下思路

想实现如上图这样一个建议雷达图,需要几步?个人总结,需要:
初始化一个canvas对象;

以画布中心,绘制三个同心圆;

根据输入的点数,计算3根轴在外径圆上的6个坐标点,并以中心点,绘制6根轴线;

根据输入的标签,集合前面6个坐标点,完成6个标签在画布的绘制;

根据输入的数据,结合前面的6个坐标,计算得输入数据的坐标点,连线完成输入数据展示;

要实现轮播,主要解决的就是根据输入数据坐标点计算此点在Dom元素的位置,然后轮播显示;

如果想触发echarts那种hover tooltip的效果,你只需要添加一个mousemove事件,获取位置,并计算其相对应的坐标点。

好像要达到的效果就完成了,似乎不难,来吧,实现它。

分布实现 初始化一块画布

首先引入一个canvas函数,并为其制定长高,然后获取这个元素,并得到一块平面画布,代码如下:

 
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);   

这样我们就初始化了一块画布,并将其坐标原点移到了画布的中心.
这里提示两点:

添加canvas为其指定宽高时,需要用width和height属性直接指定,而不能用style的宽高指定其宽高,如果是样式指定,画出来的线或圆是模糊且变形的;

虽然上面变换了坐标原点,但是canvas坐标系默认是向下,向右为正,所以我们改变了坐标原点,但这个特点并未改变,所以像(0,120)这个点是位于坐标原点正下方的,而非通常我们认知的正上方;

画同心圆

在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

点计算好了,接下来我们需要连接每个点到圆心得连线

    /*输入画布,和要连接的点*/
    function drawLine(ctx,data){
        ctx.beginPath();
        ctx.strokeStyle = "blue";
        for(let i= 0;i

提示:其实绘制这几根极坐标也可以采用坐标变换rotate API来执行,比如这样

rotate(single);
ctx.lingeTo(0,r);

这样也很简单,但为了后面,我们需要知道这些极坐标也圆的交点,这在后面会很有用,但不得否认canvas的translate和retate是两个很好用的方法.

根据前面标签的计算点,绘制标签

canvas文字绘制,涉及到的属性和方法有font(设置字体样式),textAlign(设置左右对齐),textBaseline(设置基线,上下对齐),fillText(文字绘制)直接上代码:

let label= ["卫生","安全","交通","住宿","景点","吃88喝"];
for(let i = 0;i=-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

也许拐点区域特殊处理,更有味道

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

至此,我们基础的图形就画完了,现在我们要做最重要的一步,也就是轮播了。

做一个简单的自动轮播

还是直接上代码吧,下一篇文章再详说:

    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 ,转载请注明

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84897.html

相关文章

  • 0开始一个支持单轴播的雷达之加强篇(解决Echarts单轴轮播问题)

    摘要:如果你嫌上面太琐碎,可以直接取看我的试验源码,文件是欢迎本文后续从开始撸一个支持单轴轮播的雷达图之末篇本文首发于 在线示例如果你还不了解canvas,还不知道要讲啥,建议从首篇看起:从0开始写一个支持单轴轮播的雷达图在首篇我们已经讲了怎么实现轮播,在这里我们将要用这一篇文章来说一下雷达图的单轴hover效果的实现,也是我写这篇文章的原因,因为echarts只支持单个series的hov...

    xcold 评论0 收藏0
  • 0开始一个支持单轴播的雷达之未篇-解决Echarts雷达单轴轮播

    摘要:今天要用到的理论在前两篇都讲过,如果你错过了前两篇,你应该先看看。但是我们可否用生成一个图,自己为其写一个呢答案是肯定的。但一切的一切前提是,要支持单轴轮播,这个图只有一个系列。 今天要用到的理论在前两篇都讲过,如果你错过了前两篇,你应该先看看。从0开始写一个支持单轴轮播的雷达图之首篇从0开始写一个支持单轴轮播的雷达图之中篇 前言 通过前面我们自己实现了一个Radar图,并对其实现了单...

    Prasanta 评论0 收藏0
  • 【30分钟学完】canvas动画|游戏基础(7):动量守恒与多物体碰撞

    摘要:科普动量是守恒量。动量守恒定律表示为一个系统不受外力或者所受外力之和为零,这个系统中所有物体的总动量保持不变。动量守恒定律可由机械能对空间平移对称性推出。在可以忽略碰撞以外的因素时,动量是守恒的。 前言 一路沿着本系列教程学习的朋友可能会发现,前面教程中都尽量避免提及质量的概念,很多运动概念也时刻提醒大家这不是真实的物体运动。因为真实的物体运动其实跟质量都是密不可分的,而且质量的引入自...

    Dr_Noooo 评论0 收藏0
  • 【30分钟学完】canvas动画|游戏基础(7):动量守恒与多物体碰撞

    摘要:科普动量是守恒量。动量守恒定律表示为一个系统不受外力或者所受外力之和为零,这个系统中所有物体的总动量保持不变。动量守恒定律可由机械能对空间平移对称性推出。在可以忽略碰撞以外的因素时,动量是守恒的。 前言 一路沿着本系列教程学习的朋友可能会发现,前面教程中都尽量避免提及质量的概念,很多运动概念也时刻提醒大家这不是真实的物体运动。因为真实的物体运动其实跟质量都是密不可分的,而且质量的引入自...

    scq000 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<