本文以中国地图为例,介绍地图的制作方法。
在数据可视化中,地图是很重要的一部分。
很多情况会与地图有关联,如中国各省的人口多少,GDP多少等,都可以和地图联系在一起。
地图数据的获取
制作地图需要 JSON 文件。
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
将 JSON 的格式应用于地理上的文件,叫做 GeoJSON 文件。
本文就是用这种文件绘制地图。
如何获取中国地图的 GeoJSON 文件呢,真的有点麻烦,可以参照: https://github.com/clemsos/d3-china-map 进行制作。
制作好的中国地图 GeoJSON 文件: china.geojson
这个文件是用 Natural Earth 上的数据,经过提取后制作而成。
只保留的中国的各省份的名字和 id 号
提供有关其他国家、以及具体到中国县级的地理文件:
好了,开始绘制地图吧。
投影函数
var projection = d3.geo.mercator()
.center([107, 31])
.scale(850)
.translate([width/2, height/2]);
由于 GeoJSON 文件中的地图数据,都是经度和纬度的信息。它们都是三维的,而要在网页上显示的是二维的,所以要*设定一个投影函数来转换经度纬度*。
如上所示,使用 d3.geo.mercator() 的投影方式。各种投影的函数,可以参考: https://github.com/mbostock/d3/wiki/Geo-Projections
center():设定地图的中心位置,[107,31] 指的是经度和纬度。
scale() : 设定放大的比例。
translate() : 设定平移。
地理路径生成器
为了根据地图的地理数据生成 SVG 中 path 元素的路径值,需要用到 d3.geo.path(),我称它为地理路径生成器。
var path = d3.geo.path()
.projection(projection);
projection() :是设定生成器的投影函数,把上面定义的投影传入即可。以后,当使用此生成器计算路径时,会自己加入投影的影响。
向服务器请求文件并绘制地图
d3.json("china.json", function(error, root) {
if (error)
return console.error(error);
console.log(root.features);
svg.selectAll("path")
.data( root.features )
.enter()
.append("path")
.attr("stroke","#000")
.attr("stroke-width",1)
.attr("fill", function(d,i){
return color(i);
})
.attr("d", path ) //使用地理路径生成器
.on("mouseover",function(d,i){
d3.select(this)
.attr("fill","yellow");
})
.on("mouseout",function(d,i){
d3.select(this)
.attr("fill",color(i));
});
});
注意: d3.json() 不能直接读取本地文件,因此你需要搭建一个服务器,例如 Apache。
接下来,就是给 svg 中添加 path 元素。
本例中,每一个 path 表示一个省。要注意 attr(“d”,path) 这一行代码,它相当于:
.attr("d",funtion(d){
return path(d);
})
这种省略用法是很常用的,请务必掌握。
结果图示:
源代码如下:
中国地图 GeoJSON 文件下载: china.geojson
<html>
<head>
<meta charset="utf-8">
<title>中国地图</title>
</head>
<style>
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 1000;
var height = 1000;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(0,0)");
var projection = d3.geo.mercator()
.center([107, 31])
.scale(850)
.translate([width/2, height/2]);
var path = d3.geo.path()
.projection(projection);
var color = d3.scale.category20();
d3.json("china.geojson", function(error, root) {
if (error)
return console.error(error);
console.log(root.features);
svg.selectAll("path")
.data( root.features )
.enter()
.append("path")
.attr("stroke","#000")
.attr("stroke-width",1)
.attr("fill", function(d,i){
return color(i);
})
.attr("d", path )
.on("mouseover",function(d,i){
d3.select(this)
.attr("fill","yellow");
})
.on("mouseout",function(d,i){
d3.select(this)
.attr("fill",color(i));
});
});
</script>
</body>
</html>