本人的个人博客为:www.ourd3js.com
csdn博客为:blog.csdn.net/lzhlzz
转载请注明出处,谢谢。
本节是结合9.2节 和
10节 的内容制作的一个可力学导向的中国地图,用户可以拖动中国的各个省份。
数据用的是 10.1节 中简化的中国地图文件: china_simplify.json
1. 定义各函数
var projection = d3.geo.mercator() .center([107, 31]) .scale(850) .translate([width/2, height/2]); var path = d3.geo.path() .projection(projection); var force = d3.layout.force().size([width, height]); var color = d3.scale.category20();
projection 函数是用于将三维地图的坐标投影到二维所用的投影函数。具体可见: 10节
path 函数用于绘制地图路径,里面要传入投影函数 projection 。具体可见: 10节
force 是定义力学图的 layout 。具体可见: 9.2节
color 是颜色函数。
2. 读取数据
d3.json("china_simplify.json", function(error, root) { if (error) return console.error(error); console.log(root.features); }
和前几节一样,用 d3.json() 读取文件,后面两句是用于检测错误,以及输出错误信息。
3. 转换数据
var nodes = []; var links = []; root.features.forEach(function(d, i) { var centroid = path.centroid(d); centroid.x = centroid[0]; centroid.y = centroid[1]; centroid.feature = d; nodes.push(centroid); }); var triangles = d3.geom.voronoi().triangles(nodes); triangles.forEach(function(d,i){ links.push( edge( d[0] , d[1] ) ); links.push( edge( d[1] , d[2] ) ); links.push( edge( d[2] , d[0] ) ); });
读取后的文件信息都存在变量 root 中,上面的代码是将 root 中的数据分别转换为力学图所需要的点和线,存在变量 nodes 和 links 中。
第1-2行: 定义变量 nodes 和 links
第4-10行: 对于 root.features 中存有每一个省的数据, root.features.forEach() 即对每一个省的数据,执行后面的无名函数,函数里面是计算出各省的中点,保存在 centroid.x 和 centroid.y 中,再把其他信息赋值给 centroid.feature,最后插入到 nodes 中。
第12行: 对 nodes 中的顶点进行三角剖分,即用三角形来连接各顶点,结果保存在 triangles 中。
第14-18行: 将三角形的各边存到 links 变量中。其中的 edge 函数的实现为:
function edge(a, b) { var dx = a[0] - b[0], dy = a[1] - b[1]; return { source: a, target: b, distance: Math.sqrt(dx * dx + dy * dy) }; }
4. 绘制地图
force.gravity(0) .charge(0) .nodes(nodes) .links(links) .linkDistance(function(d){ return d.distance; }) .start(); var node = svg.selectAll("g") .data(nodes) .enter().append("g") .attr("transform", function(d) { return "translate(" + -d.x + "," + -d.y + ")"; }) .call(force.drag) .append("path") .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) .attr("stroke","#000") .attr("stroke-width",1) .attr("fill", function(d,i){ return color(i); }) .attr("d", function(d){ return path(d.feature); } ); var link = svg.selectAll("line") .data(links) .enter() .append("line") .attr("class","link") .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; } );
第1-6行: 设定 force 的各参数进行设定。
第8-22行: 绘制各顶点,即中国各省。其中要注意,第11行和第14行,是完全相反的两个平移函数,不错,这么做就是为了移过去,再移回来,即初始时显示的是各省拼成的完整的地图且显示在最初设定的位置,因为拖拽的过程中变化的量是 d.x 和 d.y ,所以要这么做。这里有点难理解,请好好体会一下,如有疑问,请在下面留言。另外,第12行是调用 force.drag 函数。
第24-32行: 绘制连接各省的线条。
5. 力学图的结合
force.on("tick", function() { link.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; }); node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); });
这里和 9.2节 一样,tick 指的是时间间隔,也就是每一个时间间隔之后就刷新一遍画面,刷新的内容写在后面的无名函数 function 中, function 函数中写上作图的内容。这里看到了吧,第7-9行里是用于平移的,平移的参数为 d.x 和 d.y 。
结果图:
拖动试试吧,哈哈:
自己用鼠标试试吧,点击下面的链接,完整代码请右键点击浏览器后选择查看:
http://www.ourd3js.com/demo/mapforce.html
谢谢阅读。