从0开始撸一个支持单轴轮播的雷达图之未篇(解决 Echarts 雷达图单轴轮播)

发布于 2023-07-04 04:19:00 字数 5847 浏览 36 评论 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。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

聽兲甴掵

暂无简介

文章
评论
26 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文