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实现雷达的全部内容,希望这篇文章对大家的学习和工作能有所帮助。如果有疑问大家可以留言交流,感兴趣的朋友们请大家继续关注我们。

(0)

相关推荐

  • D3.js实现直方图的方法详解

    一.直方图简介 直方图就是一种照片的分析方式,横向代表亮度,纵向代表像素数量.首先分析出照片中所有像素的亮度,然后计算出具体数值,再把它们映射到横轴上.这样的话,越高,这个亮度上的像素就越多. 直方图的观看规则就是"左黑右白",左边代表暗部,右边代表亮部,而中间则代表中间调. 纵向上的高度代表像素密集程度,越高,代表的就是分布在这个亮度上的像素很多. 直方图用于描述概率分布,D3 提供了直方图的布局 Histogram 用于转换数据. 假设有数组 a = [10, 11, 11.5,

  • D3.js实现散点图和气泡图的方法详解

    前言 小编之前已经跟大家分享过了<D3.js实现柱状图的方法详解>和<D3.js实现折线图的方法详解>这两篇文章,已经介绍过柱状图和折线图了.下面就来说说和这两种非常相似的图表--散点图和气泡图.有需要的朋友们可以参考学习. 散点图和气泡图的实现 还是和之前一样,我们先把简单的画图框架搭起来,添加SVG画布: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q

  • D3.js实现折线图的方法详解

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

  • D3.js实现饼状图的方法详解

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

  • JavaScript可视化图表库D3.js API中文参考

    D3库所提供的所有 API 都在 d3 命名空间下.d3 库使用语义版本命名法(semantic versioning). 你可以用 d3.version 查看当前的版本信息. d3 (核心部分) 选择集 d3.select - 从当前文档中选择一系列元素. d3.selectAll - 从当前文档中选择多项元素. selection.attr - 设置或获取指定属性. selection.classed - 添加或删除选定元素的 CSS 类(CSS class). selection.styl

  • 使用D3.js制作图表详解

    D3是用于数据可视化的Javascript库.使用SVG,Canvas和HTML.结合强大的可视化技术和数据驱动的DOM操作方法. D3与JQuery的区别 D3是数据驱动的,JQuery不是:我们使用JQuery直接操纵元素:但是使用D3 时我们需要通过D3专有的data(),enter()和exit()方法提供数据和回调,然后D3操作元素. D3通常用于数据可视化:JQuery用于创建Web应用.D3有很多数据可视化扩展:JQuery有很多Web应用插件.两者都是Javascript DOM

  • D3.js实现柱状图的方法详解

    D3.js介绍 D3.js 是一个基于数据操作文档JavaScript库.D3帮助你给数据带来活力通过使用HTML.SVG和CSS.D3重视Web标准为你提供现代浏览器的全部功能,而不是给你一个专有的框架.结合强大的可视化组件和数据驱动方式Dom操作.这里也可以看到它是用SVG来呈现图表的,所以使用D3.js是需要一定的SVG基础的. 如何用D3.js实现柱状图? 柱状图里面有坐标轴和柱子.然而我们还需要SVG画布来画这些东西.先把大概的画图框架搭起来,代码如下(请注意此时我在body标签里添加

  • d3.js实现简单的网络拓扑图实例代码

    前言 了解了D3.js的基本开发和组件以后,我们开始应用它激动人心之处:绚丽的预定义图形,应用D3.js,我们在它的示例文件的基础上稍加变动即可应用于我们的数据可视化工作中,D3.js将后台的运算已经预定义好,我们只需少量代码和规范的数据,就能做出很花哨(请原谅我的用词不当)的效果. 力学图(也称为导向图,也有叫网络拓补图的,反正就是通过排斥得到关系远近的结构)在社交网络研究.信息传播途径等群体关系研究中应用非常广泛,它可以直观地反映群体与群体之间联系的渠道.交集多少,群体内部成员的联系强度等.

  • 基于d3.js实现实时刷新的折线图

    先来看看效果图 下面直接上源代码,html文件 <html> <head> <meta charset="utf-8"> <title>实时刷新折线图</title> <style> .axis path, .axis line{ fill: none; stroke: black; shape-rendering: crispEdges; } .axis text { font-family: sans-seri

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

    前言 再简单介绍下D3.js,D3.js 是一个基于数据操作文档JavaScript库.D3帮助你给数据带来活力通过使用HTML.SVG和CSS.D3重视Web标准为你提供现代浏览器的全部功能,而不是给你一个专有的框架.结合强大的可视化组件和数据驱动方式Dom操作.这里也可以看到它是用SVG来呈现图表的,所以使用D3.js是需要一定的SVG基础的. 本文依然是先把简单的画图框架搭起来,添加SVG画布.这里和饼图有点类似,为了方便后面的绘制,我们把组合这些元素的g元素移动到画布的中心: <!DOC

  • 原生js封装的一些jquery方法(详解)

    用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

  • 基于js对象,操作属性、方法详解

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

  • Matlab绘制雨云图的方法详解

    目录 介绍 横向雨云图 纵向雨云图 介绍 写了俩代码模板,用来绘制横向云雨图与纵向云雨图,云雨图其实就是用把小提琴图拆开来的模板,想获取小提琴图绘制函数的可以看这里:基于Matlab绘制小提琴图的示例代码 后面的俩模板用的时候只需要换换数据,颜色及每一类名称即可,雨云图绘制效果如下: 横向雨云图 function rainCloudsTMPL1 % @author: slandarer % 在这里放入你的数据============================================

  • 利用Pytorch实现获取特征图的方法详解

    目录 简单加载官方预训练模型 图片预处理 提取单个特征图 提取多个特征图 简单加载官方预训练模型 torchvision.models预定义了很多公开的模型结构 如果pretrained参数设置为False,那么仅仅设定模型结构:如果设置为True,那么会启动一个下载流程,下载预训练参数 如果只想调用模型,不想训练,那么设置model.eval()和model.requires_grad_(False) 想查看模型参数可以使用modules和named_modules,其中named_modul

  • EasyX绘制透明背景图的方法详解

    目录 三元光栅操作 优化方案 三元光栅操作 根据在网上的搜索总结得到两种方案,最常见的绘制带有透明背景的图像的方案都是采用如下的源图像和掩码图像叠加来消去边缘部分: IMAGE img[2]; loadimage(&img[0], "sun1.png", 100, 100); // 掩码图像 loadimage(&img[1], "sun0.png", 100, 100); // 源图像 putimage(0, 0, &img[0], NOT

  • d3.js实现立体柱图的方法详解

    前言 众所周知随着大数据时代的来临,数据可视化的重要性也越来越凸显,那么今天就基于d3.js今天给大家带来可视化基础图表柱图进阶:立体柱图,之前介绍过了d3.js实现柱状图的文章,感兴趣的朋友们可以看一看. 关于d3.js d3.js是一个操作svg的图表库,d3封装了图表的各种算法.对d3不熟悉的朋友可以到d3.js官网学习d3.js. 另外感谢司机大傻(声音像张学友一样性感的一流装逼手)和司机呆(呆萌女神)等人对d3.js进行翻译! HTML+CSS <!DOCTYPE html> <

  • JS创建Tag标签的方法详解

    本文实例讲述了JS创建Tag标签的方法.分享给大家供大家参考,具体如下: 一 . 创建标签其原理就是 创建一个节点: var x = document.createElement("TagName") 赋予节点样式: x.setAttribute("class",类名) 对节点进行赋值: x.innerHTML = 内容 //赋值 添加节点到父元素 要添加到的元素.appendChild(x); 二. 样式图: 三. 主要代码流程: HTML部分: <div

随机推荐