地图
在数据可视化中,地图是很重要的一部分。很多情况会与地图有关联,如中国各省的人口多少,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>