Fork me on GitHub

从0开始撸一个支持单轴轮播的雷达图之末篇

今天要用到的理论在前两篇都讲过,如果你错过了前两篇,你应该先看看。
从0开始写一个支持单轴轮播的雷达图之首篇
从0开始写一个支持单轴轮播的雷达图之中篇

前言

通过前面我们自己实现了一个Radar图,并对其实现了单轴轮播和hover,我们已经明白了其中的坐标变换,在工作中,我们用自己写的雷达图来做产品的可能性不大,毕竟精力有限,而且和Echarts的图表相比,展示效果和鲁棒性都没法比。但是我们可否用Echarts生成一个radar图,自己为其写一个tooltip呢,答案是肯定的。
但一切的一切前提是,要支持单轴hover轮播,这个Radar图只有一个系列。其实现的核心思想:通过实例化Echarts对象的option,我们可以获取画布大小,获取标签和值,生成坐标系,算出要hover点的坐标,然后添加上面说的hover事件和自动轮播事件,直接上源码:

第一步绘制对应坐标系

/*target 添加画布的容器,option即为setOption中的Option,autoOption用于设定是否自动轮播,是否hover触发,*/  
 function addHover(target,option,autoOption={autoShow:false,hoverEnable:true,time:1000}){
    const m =Math;
    var center ={  //获取画布的中心偏离比,因为echarts支持百分数控制radar图在画布中的位置,所以我们需要计算这个点,当然我们也可以为了方便,不在option中设置,这样我们就可以直接用画布的中心点,即(0.5,0.5);
        pointx:(option.radar.center&&Number(option.radar.center[0].substr(0,option.radar.center[0].length-1))/100)||0.5,  //计算X轴的偏离比例
        pointy:(option.radar.center&&Number(option.radar.center[1].substr(0,option.radar.center[1].length-1))/100)||0.5, //计算y轴的偏离比例
    };
    var x=target.offsetWidth*center.pointx,y=target.offsetHeight*center.pointy; //计算radar中心点x的值,计算radar中心点x的值
    var indicator = option.radar.indicator; //获取option中radar的标签
    var data = option.series[0].data[0].value;//获取option中radar的值,我们在这里只去第一个series的值;
    var length = indicator.length; //获取标签的长度,即雷达的拐点数,这个很重要
    var step =-1; //自动轮播要用到的参数
    var hovering =false ; //这个参数是控制轮播与hover同时触发,显示hover值,暂停轮播显示
    var radius=option.radar.radius,pointData=[]; //获取radar的半径
    var style ={  //hover显示的样式
        color:'#fff',
        border:'1px solid rgb(51,51,51)',
        borderRadius:'4px',
        backgroundColor:'rgba(50,50,50,0.7)'
    };

    const single = 2*m.PI /length*(-1);
    for(let i = 0;i<length;i++){
    var ratio = data[i]/indicator[i].max;                   
    pointData.push([radius*m.sin(i*single)*ratio,radius*m.cos(i*single)*ratio]);
    }


    /*获取鼠标在canvas画布上的位置(**不是浏览器窗口的鼠标位置)
    * clientX获取的相对浏览器窗口左上角的位置,适用于所有浏览器
    * 在chrome浏览器中,有一个zrX属性,是相对于元素本身的相对位置
    * getBoundingClientRect()函数是获取元素边框相对于浏览器窗口的位置
    * */
    function getMousePos(canvas, event) {
        var rect = canvas.getBoundingClientRect();
        return {
            x: event.clientX - rect.left ,
            y: event.clientY - rect.top
        }
    }

创建hover事件和自动轮播显示标签

创建标签

let label =document.createElement('label');
label.style.position='absolute';
label.style.display='none';
target.appendChild(label);
function hoverLabel(label,point,text,style){
    label.style.display ='none';
    label.style.top=point.y+'px';
    label.style.left=point.x+'px';
    label.style.border=style.border;
    label.style.color =style.color;
    label.style.borderRadius=style.borderRadius;
    label.style.backgroundColor = style.backgroundColor;
    label.style.transition ='left 0.4s cubic-bezier(0.23,1,0.32,1),top 0.4s cubic-bezier(0.23,1,0.32,1)';
    label.style.zIndex = 999;
    label.innerHTML =text;
    label.style.display ='inline';
}
function removeLabel(dom) {
    dom.style.display ='none';
}

添加轮播事件

autoOption.autoShow&&(setInterval(function () { //控制轮播
    step = (step+1)%length;
    var showPoint={
        x:pointData[step][0]+x,
        y:y-pointData[step][2]
    }
    var tag =indicator[step];
    var text = tag.name+':'+m.round(data[step]*100/tag.max)+"%";
    (!hovering)&&hoverLabel(label,showPoint,text,style);
},autoOption.time||1000));
target.addEventListener('click',function(event){
    console.log(event);
});

添加hover事件

    autoOption.hoverEnable&&(target.addEventListener('mousemove',function(event){  //控制hover
        const canvas= target.querySelector('canvas');
        const mouse = getMousePos(canvas, event);
        let point={};
        let index =-1;
        const r =5;
        point.x=mouse.x-x;
        point.y=y-mouse.y;
        for(let i=0;i<pointData.length;i++) {
            let item = pointData[i];
            if (point.x > (item[0] - r) && point.x < (item[0] + r) && point.y > (item[1] - r) && point.y < (item[1] + r)) {
                index = i;
                break;
            }
        }
       if(index!==-1){
            var tag =indicator[index]
            var text = tag.name+':'+m.round(data[index]*100/tag.max)+"%";
            hovering =true;
            hoverLabel(label,mouse,text,style);
        }else{
            hovering =false;
            removeLabel(label);
        }
    }))
}

至于调用,那就简单了
第一步:
var ele = document.getElementById(‘chart’);
var draw = echarts.init(ele);
第二步:
配置你的option
var option ={};
第三步画出你的雷达图
draw.setOption(option);
第四步:绑定事件:
addHover(ele,option,{autoShow:true,hoverEnable:true});

上面,其实只是一个简易的版本,在实际应用中,我们需要考虑很多问题。

  1. 图表局部刷新带来的数据重载,就上面的代码,完全不行,我们没有清除定时器,这样会找出多个hover重叠
  2. 用过Echarts的人,我们都知道,tooltip有个formatter函数,用于显示数据的格式化,以便展示出我们想要的效果。
  3. 性能问题,每次Hover生成一个labe元素,是否太消耗性能,作为产品,我们应该怎样优化
  4. 怎样才能更通用,更方便的让人使用
    基于上述问题,我对这个轮播函数做了改进和封装,使用方法是这样的:

    /Echarts图表的正常实例化/

    var target = document.getElementById('highOpinionChart');
    myChart = echarts.init(target);
    myChart.setOption(option);
    /*为图表绑定轮播事件和Hover事件*/
    var radarAutoInfo = {hoverEnable: true, autoShow: true, time: 2000, formatter:function(v){
        return v.text + ':' + (v.value*100/v.max).toFixed(2)+'%';
    }};        
    RadarAutoTip(myChart,target, option, radarAutoInfo);  //绑定
    //测试停止,开始和重置方法
    document.querySelector('#reset').addEventListener('click',function (e) {
       console.log(e);
       if(e.target.innerText === '停止'){
           e.target.innerText ='开始'
           myChart.radarAutoTip.stop();
       }else{
           e.target.innerText  = '停止';
           myChart.radarAutoTip.start();
       }
    });
    document.querySelector('#rereset').addEventListener('click',function (e) {
        myChart.radarAutoTip.reset();
    });
    

至此,我们就完全解决了Echarts单轴轮播问题。
如果你嫌上面讲的太琐碎,不直观,可以直接取github看我的试验源码,文件是radarAutoTip.html,欢迎star

-------------本文结束感谢您的阅读-------------