前言

再简单介绍下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="/UploadFiles/2021-04-02/d3.v3.min.js">

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

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

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

模拟数据

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

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

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

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

添加纵轴

接着我们把纵轴也添加上。纵轴就是添加一根根的线条,连接中心点和最外层的多边形上的点,需要的数据可以从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;
  });

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

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

计算雷达图区域并添加

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

// 计算雷达图表的坐标
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;
}

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

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

计算文字标签坐标并添加

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

// 计算文字标签坐标
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,雷达图,js雷达图,d3.js

免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
评论“D3.js实现雷达图的方法详解”
暂无“D3.js实现雷达图的方法详解”评论...

《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。