欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【带着canvas去流浪(6)】绘制雷达图

程序员文章站 2023-04-07 20:11:40
示例代码托管在: "http://www.github.com/dashnowords/blogs" 博客园地址: "《大史住在大前端》原创博文目录" 华为云社区地址: "【你要的前端打怪升级指南】" [TOC] 一. 任务说明 使用原生 绘制雷达图。(截图以及数据来自于百度Echarts官方示例库 ......

目录

【带着canvas去流浪(6)】绘制雷达图

示例代码托管在:http://www.github.com/dashnowords/blogs

博客园地址:

华为云社区地址:

一. 任务说明

使用原生canvasapi绘制雷达图。(截图以及数据来自于百度echarts官方示例库)。

【带着canvas去流浪(6)】绘制雷达图

二. 重点提示

雷达图绘制的看起来并不复杂,无非就是一些路径点的连线,其中的难点都在于一些细节。

  1. 坐标转换

    为了避免在绘制过程中不断根据夹角来计算某个数据点的坐标,我们可以让坐标系先移动到绘图中心,然后在绘制过程中逐步旋转并使用context.lineto(x,y)来连线即可,这样做的好处是很明显的。比如在绘制背景六边形的时候,每次旋转后,路径点压根就不需要移动,直接在循环中每次都调用context.lineto( )方法连线至同一个数据点即可,看起来位移没有变,实际上随着坐标系的旋转,连线绕过的是多边形的轨迹。

  2. 文字的对齐

    为了让文字保持正常的方向,我们需要将坐标系的旋转恢复到初始状态再进行绘制。绘制的过程中可以根据绘制点和中心连线相对于x轴的角度来动态修改其绘制时的相对点(left,right,center),否则就会出现下图的结果,也就是文字区域的中心到图形中心的距离的确是一致的,但这并不是我们想要的效果。

【带着canvas去流浪(6)】绘制雷达图

  1. canvas坐标系

    请时刻记得canvas坐标系的初始方向是x轴向右,y轴向下,和普通笛卡尔坐标系是不一样的,尤其是在旋转角度和坐标计算的时候,很容易出现和预期角度不相符的结果。

三. 示例代码

//options数据来自于百度echarts官方示例库
start(options);

/**
 * 绘制图表
 */
function start(options) {
    drawbg(options);
    drawdata(options);//绘制雷达图
    drawtext(options);//绘制文字
}

function drawbg(options) {
    let length = options.radar.indicator.length;
    let anglestep = -2 * math.pi / length;
    context.strokestyle="#b2b2b2";
    context.linewidth = 1;
    //调整坐标系
    //移动中心点
    context.translate(500,300);
    //将x轴旋转至竖直向上
    context.rotate(-90 * 2 * math.pi / 360);
    //每次以不同旋转半径绘制多个由大到小的图形
    for(let r = 200; r > 0 ; r -=40){
        //移动至第一个绘图点
        context.save();
        context.beginpath();
        context.moveto(r,0);
        
        //转动坐标系绘制所有点
         for(let i = 0; i < length; i++){
            context.rotate(anglestep);
            context.lineto(r,0);
         }
        context.closepath();
        context.stroke();
        //明暗色替换填充,此处从大到小切换颜色覆盖式绘制即可
        context.fillstyle = math.round(r / 40) % 2 ? 'white':'#eaeaea';
        context.fill();
        context.restore();
    }
}

/**
 * 绘制数据
 */
function drawdata(options) {
   //解构赋值拿到数据关键点
   let {radar:{indicator:indicators},series:[{data:data}]} = options;
   let colors = ['#c43e3a','#364c5a'];
   let length = indicators.length;
   let anglestep = -2 * math.pi / length;

   for(let i = 0; i < data.length; i++){
       
       context.save();
       context.beginpath();
       context.moveto(200 * data[i].value[0] / indicators[0].max,0);
    
       //遍历每组数据
       for(let j = 1; j < data[i].value.length; j++){
           context.rotate(anglestep);
           context.lineto(200 * data[i].value[j] / indicators[j].max,0);
       }
       context.restore();
       context.lineto(200 * data[i].value[0] / indicators[0].max,0);
       context.strokestyle = colors[i];
       context.linewidth = 2;
       context.stroke();
   }
   context.restore();
}

//绘制文字
function drawtext(options) {
   let {radar:{indicator:indicators}} = options;
   let length = indicators.length;
   let anglestep = 2 * math.pi / length;
   let r = 220;
   context.fillstyle = 'black';
   context.font = "14px bold 黑体";
   context.textalign = 'center';
   context.rotate(90 * math.pi * 2 / 360);
   for(let i = 0; i < indicators.length; i++){
     let curangle = -90*2*math.pi/360 - anglestep*i;
       //根据方向调整文字的对齐点
     let cos = math.cos(curangle);
     if (math.abs(cos) < 10e-4) {
        context.textalign = 'center';
     }else if(cos > 0){
        context.textalign = 'left';
     }else{
        context.textalign = 'right';
     }
     console.log(indicators[i].name, math.cos(curangle))
      context.filltext(indicators[i].name, r * math.cos(curangle), r * math.sin(curangle));
   }
}

浏览器中可查看效果:

【带着canvas去流浪(6)】绘制雷达图

百度echarts官方示例库中有这样一个,展示了在雷达图上表现时间维度的示例,感兴趣的读者可以自行查看。