当前位置: 首页 > 编程笔记 >

D3.js实现雷达图的方法详解

鄢修德
2023-03-14
本文向大家介绍D3.js实现雷达图的方法详解,包括了D3.js实现雷达图的方法详解的使用技巧和注意事项,需要的朋友参考一下

前言

再简单介绍下D3.js,D3.js 是一个基于数据操作文档JavaScript库。D3帮助你给数据带来活力通过使用HTML、SVG和CSS。D3重视Web标准为你提供现代浏览器的全部功能,而不是给你一个专有的框架。结合强大的可视化组件和数据驱动方式Dom操作。这里也可以看到它是用SVG来呈现图表的,所以使用D3.js是需要一定的SVG基础的。

本文依然是先把简单的画图框架搭起来,添加SVG画布。这里和饼图有点类似,为了方便后面的绘制,我们把组合这些元素的g元素移动到画布的中心:

<!DOCTYPE html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <title>雷达图</title>
  <style>
   .container {
    margin: 30px auto;
    width: 600px;
    height: 300px;
    border: 1px solid #000;
   }

  </style>
 </head>
 <body>
  <div class="container">
   <svg width="100%" height="100%"></svg>
  </div>
  <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
  <script>
   window.onload = function() {
    var width = 600, height = 300;
    // 创建一个分组用来组合要画的图表元素
    var main = d3.select('.container svg').append('g')
      .classed('main', true)
      .attr('transform', "translate(" + width/2 + ',' + height/2 + ')');

   };
   function getColor(idx) {
    var palette = [
     '#2ec7c9', '#b6a2de', '#5ab1ef', '#ffb980', '#d87a80',
     '#8d98b3', '#e5cf0d', '#97b552', '#95706d', '#dc69aa',
     '#07a2a4', '#9a7fd1', '#588dd5', '#f5994e', '#c05050',
     '#59678c', '#c9ab00', '#7eb00a', '#6f5553', '#c14089'
    ]
    return palette[idx % palette.length];
   }
  </script>
 </body>
</html>

这里为什么我会说雷达图和饼图会有点类似呢?看一下下面这张图。

可以看到,雷达图的网轴(蓝色部分)是由多个正多边形所组成的,而正多边形的绘制正好是可以利用圆半径的特性来绘制的,所以从一开始把绘制的原点移动到画布的中心是很方便后面的绘制工作的。

模拟数据

我们先模拟一些原始数据。

var data = {
 fieldNames: ['语文','数学','外语','物理','化学','生物','政治','历史'],
 values: [
  [10,20,30,40,50,60,70,80]
 ]
};

计算网轴坐标并绘制

在前面的其他图表的实现中,都有比例尺或者布局这样的东西来为我们转化数据提供便利,雷达图是否也存在这样的工具函数呢?答案是没有!没有!没有!重要的事情说三遍!(-_-) 所以,我们只能开动自己的小脑瓜自己算了。

// 设定一些方便计算的常量
var radius = 100,
 // 指标的个数,即fieldNames的长度
 total = 8,
 // 需要将网轴分成几级,即网轴上从小到大有多少个正多边形
 level = 4,
 // 网轴的范围,类似坐标轴
 rangeMin = 0,
 rangeMax = 100,
 arc = 2 * Math.PI;
// 每项指标所在的角度
var onePiece = arc/total;
// 计算网轴的正多边形的坐标
var polygons = {
 webs: [],
 webPoints: []
};
for(var k=level;k>0;k--) {
 var webs = '',
   webPoints = [];
 var r = radius/level * k;
 for(var i=0;i<total;i++) {
  var x = r * Math.sin(i * onePiece),
   y = r * Math.cos(i * onePiece);
  webs += x + ',' + y + ' ';
  webPoints.push({
   x: x,
   y: y
  });
 }
 polygons.webs.push(webs);
 polygons.webPoints.push(webPoints);
} 

计算网轴的坐标就是计算一个个多边形的各点坐标,为了后面添加polygon元素时方便绘制(points属性的赋值),我们需要在求点坐标的时候顺便把它们拼成字符串。上述代码的for循环中,外层循环代表一个多边形,内层循环代表多边形上的点,多边形与多边形之间差异仅仅在于它们的外圆的半径不同,而同一多边形的点与点之间的差异在于它们的角度不同。点的坐标由半径乘以角度的正弦或者余弦来求得。

得到了计算好的坐标以后,我们就开始添加网轴。

// 绘制网轴
var webs = main.append('g')
  .classed('webs', true);
webs.selectAll('polygon')
  .data(polygons.webs)
  .enter()
  .append('polygon')
  .attr('points', function(d) {
   return d;
  });

添加一个g元素用来组合所有代表网轴的元素,选择其中的polygon元素并绑定polygons.webs数组,enter()搭配append()添加新的polygon元素,对points属性进行复制。完成这一系列在前面几篇文章中已经反复练习的操作以后,为了让网轴更加的明显,我们给它加一点样式。

.webs polygon {
 fill: white;
 fill-opacity: 0.5;
 stroke: gray;
 stroke-dasharray: 10 5;
} 

我们得到了如下图所示的网轴。

添加纵轴

接着我们把纵轴也添加上。纵轴就是添加一根根的线条,连接中心点和最外层的多边形上的点,需要的数据可以从polygons.webPoints[0]中取。

// 添加纵轴
var lines = main.append('g')
  .classed('lines', true);
lines.selectAll('line')
  .data(polygons.webPoints[0])
  .enter()
  .append('line')
  .attr('x1', 0)
  .attr('y1', 0)
  .attr('x2', function(d) {
   return d.x;
  })
  .attr('y2', function(d) {
   return d.y;
  });

雷达图的坐标轴部分就完成了。

计算雷达图区域并添加

雷达图区域也是一个多边形,只不过是一个不规则的多边形。但是他的几个点始终处在纵轴上,并且点在纵轴上的位置可以通过点所代表的值在纵轴范围内的占比计算出来的。

// 计算雷达图表的坐标
var areasData = [];
var values = data.values;
for(var i=0;i<values.length;i++) {
 var value = values[i],
   area = '',
   points = [];
 for(var k=0;k<total;k++) {
  var r = radius * (value[k] - rangeMin)/(rangeMax - rangeMin);
  var x = r * Math.sin(k * onePiece),
   y = r * Math.cos(k * onePiece);
  area += x + ',' + y + ' ';
  points.push({
   x: x,
   y: y
  })
 }
 areasData.push({
  polygon: area,
  points: points
 });
}

计算完点的坐标以后我们就可以添加雷达图区域了。为了使雷达图更可观,我们除了添加多边形表示雷达图的区域以外,也把多边形在各纵轴上的点标记出来。

// 添加g分组包含所有雷达图区域
var areas = main.append('g')
 .classed('areas', true);
// 添加g分组用来包含一个雷达图区域下的多边形以及圆点 
areas.selectAll('g')
 .data(areasData)
 .enter()
 .append('g')
 .attr('class',function(d, i) {
  return 'area' + (i+1);
 });
for(var i=0;i<areasData.length;i++) {
 // 依次循环每个雷达图区域
 var area = areas.select('.area' + (i+1)),
   areaData = areasData[i];
 // 绘制雷达图区域下的多边形
 area.append('polygon')
   .attr('points', areaData.polygon)
   .attr('stroke', function(d, index) {
    return getColor(i);
   })
   .attr('fill', function(d, index) {
    return getColor(i);
   });
 // 绘制雷达图区域下的点 
 var circles = area.append('g')
   .classed('circles', true);
 circles.selectAll('circle')
   .data(areaData.points)
   .enter()
   .append('circle')
   .attr('cx', function(d) {
    return d.x;
   })
   .attr('cy', function(d) {
    return d.y;
   })
   .attr('r', 3)
   .attr('stroke', function(d, index) {
    return getColor(i);
   }); 
}

这里为了体验层次关系,我用areas包含住所有雷达图区域,又在里面用一个g分组表示一个雷达图区域,在雷达图区域里包含组成该区域的多边形和圆点。这里因为我们数据用一个雷达图区域就表示了,所以这个for循环只会循环一次。给绘制好的区域加上样式。

.areas polygon {
 fill-opacity: 0.5;
 stroke-width: 3;
}
.areas circle {
 fill: white;
 stroke-width: 3;
}

于是得到了下图这个样子的图表。

计算文字标签坐标并添加

为了让上面的图表更完整一些,我们给它加上文字标签。文字标签标注在网轴的外围,所以可以以计算网轴多边形点坐标的同样的原理计算文字标签的坐标。

// 计算文字标签坐标
var textPoints = [];
var textRadius = radius + 20;
for(var i=0;i<total;i++) {
 var x = textRadius * Math.sin(i * onePiece),
   y = textRadius * Math.cos(i * onePiece);
 textPoints.push({
  x: x,
  y: y
 });
} 

计算好坐标以后再添加到画布中。

// 绘制文字标签
var texts = main.append('g')
  .classed('texts', true);
texts.selectAll('text')
  .data(textPoints)
  .enter()
  .append('text')
  .attr('x', function(d) {
   return d.x;
  })
  .attr('y', function(d) {
   return d.y;
  })
  .text(function(d,i) {
   return data.fieldNames[i];
  }); 

最后的样子是这样的。

总结

以上就是利用D3.js实现雷达的全部内容,希望这篇文章对大家的学习和工作能有所帮助。如果有疑问大家可以留言交流,感兴趣的朋友们请大家继续关注小牛知识库。

 类似资料:
  • 本文向大家介绍D3.js实现饼状图的方法详解,包括了D3.js实现饼状图的方法详解的使用技巧和注意事项,需要的朋友参考一下 前言 小编在之前已经跟大家分享过关于怎样用柱状图和折线图这两种基本图表。这两种图表都是有坐标轴的,现在来说一种没有坐标轴的图表——饼图。 饼状图实现 还是和之前一样,我们先把简单的画图框架搭起来,添加SVG画布。但是这里需要注意的是,为了方便后面画饼图上的弧形,我们把组合这些

  • 本文向大家介绍D3.js实现折线图的方法详解,包括了D3.js实现折线图的方法详解的使用技巧和注意事项,需要的朋友参考一下 前言 D3.js是一个帮助开发者操纵基于数据的文档的JavaScript类库,在《D3.js实现柱状图的方法详解》中已经给大家介绍过如何用D3.js来实现一个简单的柱状图了,今天我们来学习用D3.js来实现折线图,感兴趣的朋友们下面来一起看看吧。 折线图由坐标轴、线条和点组成

  • 本文向大家介绍D3.js实现柱状图的方法详解,包括了D3.js实现柱状图的方法详解的使用技巧和注意事项,需要的朋友参考一下 D3.js介绍 D3.js 是一个基于数据操作文档JavaScript库。D3帮助你给数据带来活力通过使用HTML、SVG和CSS。D3重视Web标准为你提供现代浏览器的全部功能,而不是给你一个专有的框架。结合强大的可视化组件和数据驱动方式Dom操作。这里也可以看到它是用SV

  • 本文向大家介绍python批量制作雷达图的实现方法,包括了python批量制作雷达图的实现方法的使用技巧和注意事项,需要的朋友参考一下 前言 因为工作需要有时候要画雷达图,但是数据好多组怎么办?不能一个一个点excel去画吧,那么可以利用python进行批量制作,得到样式如下: 首先制作一个演示的excel,评分为excel随机数生成: 加入标签等得到的excel样式如下(部分,共计32行): 那

  • 本文向大家介绍js实现跨域的方法实例详解,包括了js实现跨域的方法实例详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了js实现跨域的方法。分享给大家供大家参考。具体分析如下: 由于同源策略的限制,XMLHttpRequest只允许请求当前源(包含域名、协议、端口)的资源。 json与jsonp的区别: JSON是一种数据交换格式,而JSONP是一种依靠开发人员创造出的一种非官方跨域数据

  • 本文向大家介绍JS轮播图的实现方法,包括了JS轮播图的实现方法的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了JS轮播图的实现代码,供大家参考,具体内容如下 需求: 自动轮播,鼠标移入轮播停止、移出继续,小圆点点击切图,左右箭头切图 效果图: 思路 通过编写过渡动画实现轮播效果,图片的出现动画以及移出动画。显示区的图片移出,切换的图进入分别调用动画,程序关键点:哪张图应该进入,哪张图