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

前言

再简单介绍下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
, 雷达图
js雷达图
ios雷达图 实现、javascript闭包详解、javascript详解、javascript 继承详解、javascript bind详解,以便于您获取更多的相关知识。

时间: 2024-10-23 12:35:58

D3.js实现雷达图的方法详解_javascript技巧的相关文章

D3.js实现折线图的方法详解_javascript技巧

前言 D3.js是一个帮助开发者操纵基于数据的文档的JavaScript类库,在<D3.js实现柱状图的方法详解>中已经给大家介绍过如何用D3.js来实现一个简单的柱状图了,今天我们来学习用D3.js来实现折线图,感兴趣的朋友们下面来一起看看吧. 折线图由坐标轴.线条和点组成.和实现柱状图一样,我们还是先把大概的画图框架搭起来,代码如下(别忘了添加D3.js): <!DOCTYPE html> <html lang="en"> <head>

基于js对象,操作属性、方法详解_javascript技巧

一,概述 在Java语言中,我们可以定义自己的类,并根据这些类创建对象来使用,在Javascript中,我们也可以定义自己的类,例如定义User类.Hashtable类等等. 目前在Javascript中,已经存在一些标准的类,例如Date.Array.RegExp.String.Math.Number等等,这为我们编程提供了许多方便.但对于复杂的客户端程序而言,这些还远远不够. 与Java不同,Java2提供给我们的标准类很多,基本上满足了我们的编程需求,但是Javascript提供的标准类很

原生js封装的一些jquery方法(详解)_javascript技巧

用js封装一些常用的jquery方法 记录一下 hasClass:判断是否有class function hasClass(ele, cls) { if (!ele || !cls) return false; if (ele.classList) { return ele.classList.contains(cls); } else { return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')); } } addCl

D3.js实现饼状图的方法详解_javascript技巧

前言 小编在之前已经跟大家分享过关于怎样用柱状图和折线图这两种基本图表.这两种图表都是有坐标轴的,现在来说一种没有坐标轴的图表--饼图. 饼状图实现 还是和之前一样,我们先把简单的画图框架搭起来,添加SVG画布.但是这里需要注意的是,为了方便后面画饼图上的弧形,我们把组合这些元素的g元素移动到画布的中心: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"

JS组件Bootstrap Select2使用方法详解_javascript技巧

在介绍select组件的时候,之前分享过一篇JS组件中bootstrap multiselect两大组件较量的文章,这两个组件的功能确实很强大,本文分享下select组件的一些用法和特性. 一些通用的单选.多选.分组等功能这里就不多做介绍了,multiselect这方面是强项.重点介绍下select2的一些特性效果:一.特性效果1.多选效果 可以设置最多只能选几个 2.图文结合的效果 3.远程搜索功能(即在用户输入搜索内容时动态去后台取数据) 输入内容前 输入空格搜索出全部 滚动条滑动到底部自动

js显示动态时间的方法详解_javascript技巧

本文实例讲述了js显示动态时间的方法.分享给大家供大家参考,具体如下: Date对象的方法 Date 对象能够使你获得相对于国际标准时间(格林威治标准时间,现在被称为 UTC-Universal Coordinated Time)或者是 Flash 播放器正运行的操作系统的时间和日期.要使用Date对象的方法,你就必须先创建一个Date对象的实体(Instance). Date 对象必须使用 Flash 5 或以后版本的播放器. Date 对象的方法并不是静态的,但是在使用时却可以应用于所指定的

JS延时提示框实现方法详解_javascript技巧

本文实例讲述了JS延时提示框实现方法.分享给大家供大家参考,具体如下: 提示框功能:当鼠标指向头像时,弹出一个信息框,鼠标可移动到信息框,当鼠标离开头像时信息框消失,当鼠标离开信息框时信息框消失. 实现功能思路: 1.获取元素. 2.当鼠标指向Div1时,Div2显示. 3.当鼠标离开Div1时,使Div2延迟0.5秒消失,这样以便有时间把鼠标移到Div2. 4.当鼠标指向Div2时,Div2显示.因为第3步设置setTimeout使Div2消失,所以把用clearTimeout()把setTi

js中unicode转码方法详解_javascript技巧

有时候遇到unicode不得不转码,我们只好人工编码进行转码.昨天在网上看到一个unitcode转码的方法,非常好用!小编把它和大家分享一下.JavaScript脚本UniCode转码函数: <script type="text/javascript"> var GB2312UnicodeConverter = { ToUnicode: function (str) { return escape(str).toLocaleLowerCase().replace(/%u/g

Vue.js路由组件vue-router使用方法详解_javascript技巧

使用Vue.js + vue-router 创建单页应用是非常简单的.只需要配置组件和路由映射,然后告诉 vue-router 在哪里渲染即可. 一.普通方式基本例子: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue-router使用方法</title> </head> <bod