【d3.js教程14】可拖动的地图详解
最后更新于:2022-04-01 14:18:24
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-23_5742b93ab2ac9.jpg)
~~~
<html>
<head>
<meta charset="utf-8">
<title>中国地图</title>
</head>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
.link {
stroke: #ccc;
stroke-width: 0.5;
}
</style>
<body>
<script src="js/d3.min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var width = 2000;
var height = 1000;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(0,0)");
/*定义投影*/
var projection1 = d3.geo.mercator() //麦克托投影法
.center([107, 31]) //地图的经纬度(将制定的经纬度设定为地图的中心)
.scale(850) //地图放大比例
.translate([width/2, height/2]); //位移
/*传入投影,并计算路径*/
var path = d3.geo.path()
.projection(projection1); //将三维地图投影到二维坐标上。为了避免混淆,特意将projection改成projection1
var force = d3.layout.force().size([900, 900]); //size设定容器的中心
var color = d3.scale.category20();
d3.json("json/chinamap.json", function(error, root) {
if (error)
return console.error(error);
/*定义两个数组存储节点和边*/
var nodes = [];
var links = [];
root.features.forEach(function(d, i) {
var centroid = path.centroid(d); //计算出数据的中点
centroid.x = centroid[0]; //数组0元素中存着中点的横坐标
centroid.y = centroid[1]; //数组1元素中存着中点的纵坐标
centroid.feature = d; //把数据存到feature中
nodes.push(centroid); //将节点推进组数
});
var triangles = d3.geom.voronoi().triangles(nodes); //将节点进行三角剖分,将结果保存在triangles中
triangles.forEach(function(d,i){ //用循环,将每个三角的三个点两两相连,推进边数组中
links.push( edge( d[0] , d[1] ) ); //edge函数在后面
links.push( edge( d[1] , d[2] ) );
links.push( edge( d[2] , d[0] ) );
});
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("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; } );
force.on("tick", function() { //及时设定force的源头和末尾
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) { //也就是nodes的数据一直在变,及时将位移改变
return "translate(" + d.x + "," + d.y + ")";
});
});
});
/*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)
};
}
</script>
</body>
</html>
~~~