地圖
在數據可視化中,地圖是很重要的一部分。很多情況會與地圖有關聯,如中國各省的人口多少,GDP多少等,都可以和地圖聯繫在一起。
地圖數據的獲取
製作地圖需要 JSON 文件,將 JSON 的格式應用於地理上的文件,叫做 GeoJSON 文件。本文就是用這種文件繪製地圖。
那麼如何獲取中國地圖的 GeoJSON 文件呢? 如下鏈接,打開並下載至本地,並命名爲ChinaGeoFull.json,後面實現會用到。
https://geo.datav.aliyun.com/areas_v2/bound/100000_full.json
投影函數
由於 GeoJSON 文件中的地圖數據,都是經度和緯度的信息。它們都是三維的,而要在網頁上顯示的是二維的,所以要設定一個投影函數來轉換經度緯度。如:
var projection = d3.geoMercator()
.center([107, 31])
.scale(850)
.translate([width/2, height/2]);
文檔: https://www.d3js.org.cn/document/d3-geo/#projections
其中,
- center() 設定地圖的中心位置,[107,31] 指的是經度和緯度。
- scale() 設定放大的比例。
- translate() 設定平移。
地理路徑生成器
爲了根據地圖的地理數據生成 SVG 中 path 元素的路徑值,需要用到d3.geoPath([projection[, context]),稱它爲地理路徑生成器。
文檔:https://www.d3js.org.cn/document/d3-geo/#paths
使用默認的設置創建一個新的地理路徑生成器. 如果指定了 projection, 則設置 當前投影. 如果指定了 context 則設置當前 當前上下文.
var path = d3.geoPath(projection)
向服務器請求文件並繪製地圖
d3.json("./ChinaGeoFull.json").then(function(data){
console.log(data)
svg.selectAll("g")
.data(data.features)
.enter()
.append("g")
.append("path")
.attr('d',path)//使用地理路徑生成器
.attr("stroke","#000")
.attr("stroke-width",1)
.attr("fill", function(d,i){
return color[i%10];
})
.on("mouseover",function(d,i){
d3.select(this).attr("fill","yellow");
})
.on("mouseout",function(d,i){
d3.select(this).attr("fill",color(i));
});
//添加座標
svg.selectAll("g")
.append('text')
.attr('font-size', 12)
.attr('text-anchor', 'middle')
.attr('x', d => {
var position = projection(d.properties.centroid || [0, 0]);
return position[0];
})
.attr('y', d => {
var position = projection(d.properties.centroid || [0, 0]);
return position[1];
})
.attr('dy', d => {
//澳門和香港重合了,擠到一起了
if (d.properties.name === '澳門') {
return 15;
}
})
.text(d => d.properties.name);
})
完整代碼
<body>
<svg width="1000" height="1000"></svg>
<script>
var marge = {top:60,bottom:60,left:60,right:60}
var svg = d3.select("svg")
var width = svg.attr("width")
var height = svg.attr("height")
var g = svg.append("g").attr("transform","translate("+marge.top+","+marge.left+")");
//投影函數
var projection = d3.geoMercator()
.center([107, 31])
.scale(800)
.translate([width/2, height/2]);
//路徑
var path = d3.geoPath(projection);
var color = d3.schemeCategory10;
d3.json("./ChinaGeoFull.json").then(function(data){
console.log(data)
svg.selectAll("g")
.data(data.features)
.enter()
.append("g")
.append("path")
.attr('d',path)//使用地理路徑生成器
.attr("stroke","#000")
.attr("stroke-width",1)
.attr("fill", function(d,i){
return color[i%10];
})
.on("mouseover",function(d,i){
d3.select(this).attr('opacity', 0.5);
})
.on("mouseout",function(d,i){
d3.select(this).attr('opacity', 1);
});
//添加座標
svg.selectAll("g")
.append('text')
.attr('font-size', 12)
.attr('text-anchor', 'middle')
.attr('x', d => {
var position = projection(d.properties.centroid || [0, 0]);
return position[0];
})
.attr('y', d => {
var position = projection(d.properties.centroid || [0, 0]);
return position[1];
})
.attr('dy', d => {
//這裏爲什麼這麼寫呢,因爲澳門和香港重合了,擠到一起了。
if (d.properties.name === '澳門') {
return 15;
}
})
.text(d => d.properties.name);
})
</script>
</body>