程序员人生 网站导航

D3.js 以圆做点绘制力图(一)

栏目:互联网时间:2014-11-24 08:42:17

SVG是甚么?

如何在SVG上绘制1个圆?

如何在SVG上绘制1条线?

力图的基本属性有哪些?

这些问题将由本文来逐一解答。

在代码方面,我们沿用上文的网页框架,把body里面的js替换成现在的js便可。


SVG

  SVG,可缩放的矢量图,我们以后所绘制 的数据展现图大都是在SVG这个大容器内完成的,它相当于画布。创建SVG,就是有益于导出、保存绘制好的图形。

  简单的SVG标签格式 <svg width="500" height="50"></svg>,在SVG标签中可以嵌入很多可见元素,包括 rect、circle、ellipse、line、text和path。

  下面,我们在body中创建1个js标签,在里面创建1个svg对象,代码以下:

<span style="font-size:14px;">var w = 500; var h = 500; var svg = d3.select("body") .append("svg") .attr("width", w) //设置宽度 .attr("height", h); //设置高度 </span>
 
绘制圆

在svg内添加circle元素,先介绍下circle的基本属性:cx 圆心x坐标  cy圆心y坐标   r半径

接下来,绘制5个半径顺次增大的圆,并将它们的圆心放到同1条y轴上,代码以下

<span style="font-size:14px;"> var dataset = [ 5, 10, 15, 20, 25 ]; var circles = svg.selectAll("circle") .data(dataset) .enter() .append("circle"); circles.attr("cx", function(d, i) {//圆心坐标从左向右顺次递增,注意:i表示引入数据在数组的下标,如:d=5,i=0 return (i * 50) + 25; }) .attr("cy", h/2) //将圆心放到svg高度中间 .attr("r", function(d) {//半径 return d; })</span>

紧接着设置各圆的属性

<span style="font-size:14px;"> .attr("fill", "yellow") //给各圆填充黄色 .attr("stroke", "orange") //给各圆边涂成橘黄 .attr("stroke-width", function(d) { //按比例设置边的厚度 return d/2; }); </span>

至此,SVG上的圆就绘制完成了见下图


绘制线

在svg绘制1条线,首先要定义它的两个端点,出发点和终点 (x1,y1)和(x2,y2)

线的基本属性包括:

  • x1 属性在 x 轴定义线条的开始
  • y1 属性在 y 轴定义线条的开始
  • x2 属性在 x 轴定义线条的结束
  • y2 属性在 y 轴定义线条的结束

<span style="font-size:14px;">var line = svg.append('line') .attr('x1',100) .attr('y1',100) .attr('x2',200) .attr('y2',200) .attr('style','stroke:rgb(99,99,99);stroke-width:2'); //描边宽度</span>
显示效果图以下:



用力图简介

  有点有线,那末有关联的点用线相连,再设置下点之间的电荷排挤力,让没关联的点保持距离, 那末力图的雏形就构成了。

  力学图( Force ),也有被翻译做力导向图等。这类图很成心思,先从初始数据开始,看下面代码:

{ "nodes":[ {"name":"Myriel","group":3,"QQ":"635511111"}, {"name":"Napoleon","group":1,"QQ":"635511112"}, {"name":"Mlle.Baptistine","group":1,"QQ":"635511113"}, {"name":"Mme.Magloire","group":1,"QQ":"635511114"}, {"name":"CountessdeLo","group":1,"QQ":"635511115"}, {"name":"Geborand","group":1,"QQ":"635511116"}, {"name":"Champtercier","group":1,"QQ":"635511117"}, {"name":"Cravatte","group":1,"QQ":"635512111"}, {"name":"Count","group":1,"QQ":"635513111"}, {"name":"OldMan","group":1,"QQ":"635514111"}, {"name":"Labarre","group":2,"QQ":"635515111"}, {"name":"Valjean","group":2,"QQ":"635516111"}, {"name":"Marguerite","group":3,"QQ":"635531111"}, {"name":"Mme.deR","group":2,"QQ":"635511311"}, {"name":"Isabeau","group":2,"QQ":"635511211"}, {"name":"Gervais","group":2,"QQ":"635514111"}, {"name":"Tholomyes","group":3,"QQ":"635571111"}, {"name":"Listolier","group":3,"QQ":"635581111"}, {"name":"Fameuil","group":3,"QQ":"635511011"}, {"name":"Blacheville","group":3,"QQ":"635211111"}, {"name":"Favourite","group":3,"QQ":"635510111"}, {"name":"Dahlia","group":3,"QQ":"635511121"} ], "links":[ {"source":1,"target":0,"value":1}, {"source":2,"target":0,"value":8}, {"source":3,"target":0,"value":10}, {"source":3,"target":2,"value":6}, {"source":4,"target":0,"value":1}, {"source":5,"target":0,"value":1}, {"source":6,"target":0,"value":1}, {"source":7,"target":0,"value":1}, {"source":8,"target":0,"value":2}, {"source":9,"target":0,"value":1}, {"source":11,"target":1,"value":1}, {"source":11,"target":3,"value":3}, {"source":11,"target":2,"value":3}, {"source":11,"target":0,"value":5}, {"source":12,"target":2,"value":1}, {"source":13,"target":2,"value":1}, {"source":14,"target":2,"value":1}, {"source":15,"target":2,"value":1}, {"source":17,"target":3,"value":4}, {"source":18,"target":3,"value":4}, {"source":18,"target":3,"value":4}, {"source":19,"target":3,"value":4}, {"source":19,"target":2,"value":4}, {"source":19,"target":3,"value":4}, {"source":20,"target":4,"value":3}, {"source":20,"target":1,"value":3}, {"source":20,"target":2,"value":3}, {"source":20,"target":3,"value":4}, {"source":21,"target":16,"value":3}, {"source":21,"target":17,"value":3}, {"source":21,"target":18,"value":3}, {"source":21,"target":19,"value":3}, {"source":21,"target":20,"value":5} ] }

这些数据包括两部份,点(nodes)和边(links),source 和target的数值代表nodes数组该数值下标对应的元素。

注意的1点,不管nodes元素有多少属性,source和target都暂时指向人名,如source 1 target0 表示napoleon和myriel连接

细细1看就会发现,这些点只是些人员的属性而已,光靠这些是没法知道每一个点该画到哪儿。

  所以就需要先了解1下D3 画力图的1些专有方法了 。下面为大家罗列1些必要的方法和解释:

  为了使用方便先将上面的json数据,赋值给 dataset,放到js里

(以后这些数据都会保存在相应格式的文件中,由d3加载,加载方法在 D3整体展现篇已略有介绍) 

var force = d3.layout.force() //转换数据的方法,将点转换为坐标格式 .nodes(<span style="font-size:14px;">dataset.</span>nodes) //传入点 .links(dataset.links) //传入边 .size([w, h]) //设置图形宽高 .start(); //开始转换

以上代码是 用力图最基础的布局方法。

这些基本布局其实不能满足所有数据集,我们还要在这基础上添加1些layout的自定义方法,

 比如设置节点间连线的长度、节点间互斥力大小。完善以后的代码显示以下:

var force = d3.layout.force() .nodes(dataset.nodes) .links(dataset.edges) .size([w, h]) .linkDistance([50]) // 节点连线长度 .charge([⑴00]) // 排挤力 .start();
至此,力图基本初始化布局完成

 接下来创建连线

var edges = svg.selectAll("line") .data(dataset.edges) .enter() .append("line") .style("stroke", "#ccc") .style("stroke-width", 1);

这里的连线色彩和宽度都可以编写函数随便设定,例犹如类人员设为同色,重要人员连线加粗等

然后为每一个节点创建圆,方便阅读

var nodes = svg.selectAll("circle") .data(dataset.nodes) .enter() .append("circle") .attr("r", 10) .style("fill", function(d, i) { return colors(i); }) .call(force.drag); //增加拖动效果,拉动节点
 最后,我们就要打点,将点线绘制到画布上

force.on("tick", function() { edges.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); nodes.attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }); });
这样,每次打点,获得线和点的坐标,在更新到画布上。那末这些坐标哪儿来的?就是layout初始化转换传入的点线数据后,

 为他们摹拟1些坐标信息。你可以在阅读器控制台输入dataset查看各点线坐标信息

  好了,最简单的用力图就这样完成了,后文会继续在此基础上讲授如作甚个点设置图标、如何实现不同分组的群成员聚类缩放、如何显示成员信息、如何将圆替换为矩形块放置属性联系方式等,敬请期待!




------分隔线----------------------------
------分隔线----------------------------

最新技术推荐