制作一个中国地图的力导向地图,支持鼠标拖拽,省份作为节点,连线用三角剖分生成。
访问地址:http://106.14.147.72/Graphtest/forcemap.html
效果图:
- 定义一个力导向布局、投影和地理路径生成器
创建一个力导向布局,一个墨卡托投影和一个地理路径生成器
var width = 1600;
var height = 1000;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(0,0)");
var force = d3.layout.force()
.size([width, height]);
var projection = d3.geo.mercator()
.center([107, 31])
.scale(850)
.translate([width/2, height/2]);
var path = d3.geo.path()
.projection(projection);
2.请求GeoJSON文件
文件名称为China.geojson,保存了中国各省份的地理信息通过d3.json读入。
var color = d3.scale.category20();
d3.json("china.geojson", function(error, root) {
if (error)
return console.error(error);
console.log(root.features);
3.计算节点数组和连线数组
var nodes = [];
root.features.forEach(function(d, i) {
//计算省份的中心坐标
var centroid = path.centroid(d);
//定义两个变量x和y,保存中心坐标
centroid.x = centroid[0];
centroid.y = centroid[1];
//将地理特征保存在对象里
centroid.feature = d;
//添加到节点数组中
nodes.push(centroid);
});
var voronoi = d3.geom.voronoi()
.x(function(d){
return d.x;
})
.y(function(d){
return d.y;
});
var links = voronoi.links(nodes);
console.log(nodes);
console.log(links);
4.设定力导向布局的属性
最重要的是两节点之间的距离设置,使其节点之间保持适当的位置间隔。
force.gravity(0)
.charge(0)
.linkDistance(function(d){
var dx = d.source.x - d.target.x;
var dy = d.source.y - d.target.y;
return Math.sqrt( dx*dx + dy*dy );
})
.nodes(nodes)
.links(links)
.start();
5.绘制节点和连线
var nodeGroups = 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 lines = 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; } );
6.运动更新
当鼠标进行拖拽时,力导向发生作用。
force.on("tick", function() {
lines.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; });
nodeGroups.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});