d3js 绘制地图 | Geo布局

549 阅读3分钟

在数据可视化中,地图是很重要的一部分。很多情况会与地图有关联,如中国各省的人口多少,GDP多少等,都可以和地图联系在一起。

制作地图需要 JSON 文件,将 JSON 的格式应用于地理上的文件,叫做 GeoJSON 文件。本文就是用这种文件绘制地图。 那么如何获取中国地图的 GeoJSON 文件呢? 如下链接,打开并下载至本地,并命名为ChinaGeoFull.json,后面实现会用到。 geo.datav.aliyun.com/areas_v2/bo…

html

<script src="./d3.v7.min.js"></script>
<body>
  <svg width="900" height="700"></svg>
</body>

获取svg

  //获取svg
  var svg = d3.select('svg');
  var width = svg.attr('width');
  var height = svg.attr('height');

  //创建区域分组
  var g = svg.append('g').attr('transform', 'translate(0,0)');

投影函数

由于 GeoJSON 文件中的地图数据,都是经度和纬度的信息。它们都是三维的,而要在网页上显示的是二维的,所以要设定一个投影函数来转换经度纬度。

 //创建一个地图投影
  var mercator = d3.geoMercator()
    .center([107, 31])//设置投影的中心点 经纬度
    .scale(550)//设置缩放因子
    .translate([width / 2, height / 2]);//设置平移偏移量

地理路径生成器

为了根据地图的地理数据生成 SVG 中 path 元素的路径值,需要用到d3.geoPath([projection[, context]),称它为地理路径生成器。

  //创建一个地理路径生成器
  var geoPath = d3.geoPath(mercator);

获取中国地图的GeoJson

./mapfull.json是100000_full.json去了湖北省的第四组数据,不去除地图溢出,不正常。

d3.json('./mapfull.json').then(function (data) {//D3 v5版本d3.json()现在将返回一个你可以在.then()方法中处理的Promise
    console.log(data);//features

});

新建一个颜色比例尺

//新建一个颜色比例尺
var scaleColor = d3.scaleOrdinal()
  .domain(d3.range(data.features.length))
  .range(d3.schemeCategory10);

绘制区域

//绘制区域
g.append('g')
  .selectAll('path')
  .data(data.features)
  .enter()
  .append('path')
  .attr('stroke', 'gray')
  .attr('strok-widht', 1)
  .attr('d', geoPath)
  .attr('fill', function (d, i) {
    return scaleColor(i);
  })
  .on('mouseover', function (d, i) {
    d3.select(this).attr('fill', 'yellow');
  })
  .on('mouseout', function (d, i) {
    d3.select(this).attr('fill', scaleColor(i));
  });

绘制文字

//绘制文字
g.append('g')
  .selectAll('text')
  .data(data.features)
  .enter()
  .append('text')
  .attr('font-size', 12)
  .attr('text-anchor', 'middle')
  .attr('x', function (d, i) {
    var position = mercator(d.properties.centroid || [0, 0]);
    return position[0];
  })
  .attr('y', function (d, i) {
    var position = mercator(d.properties.centroid || [0, 0]);
    return position[1];
  })
  .attr('dy', function (d, i) {
    //这里为什么这么写呢,因为澳门和香港重合了,挤到一起了。
    if (d.properties.name === '澳门特别行政区') {
      return 10;
    }
  })
  .text(function (d, i) {
    return d.properties.name;
  });

完整代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>中国地图</title>
  <script src="./d3.v7.min.js"></script>
</head>

<body>

  <svg width="900" height="700"></svg>


</body>

<script>

  //获取svg
  var svg = d3.select('svg');
  var width = svg.attr('width');
  var height = svg.attr('height');

  //创建区域分组
  var g = svg.append('g').attr('transform', 'translate(0,0)');

  //创建一个地图投影
  var mercator = d3.geoMercator()
    .center([107, 31])//设置投影的中心点 经纬度
    .scale(550)//设置缩放因子
    .translate([width / 2, height / 2]);//设置平移偏移量

  //创建一个地理路径生成器
  var geoPath = d3.geoPath(mercator);

  //获取中国地图的json文件
  //利用node.js 在本地起一个http-server (./mapfull.json是100000_full.json去了湖北省的第四组数据,不去除地图溢出,不正常。)
  d3.json('./mapfull.json').then(function (data) {//D3 v5版本d3.json()现在将返回一个你可以在.then()方法中处理的Promise
    console.log(data);//features

    //新建一个颜色比例尺
    var scaleColor = d3.scaleOrdinal()
      .domain(d3.range(data.features.length))
      .range(d3.schemeCategory10);


    //绘制区域
    g.append('g')
      .selectAll('path')
      .data(data.features)
      .enter()
      .append('path')
      .attr('stroke', 'gray')
      .attr('strok-widht', 1)
      .attr('d', geoPath)
      .attr('fill', function (d, i) {
        return scaleColor(i);
      })
      .on('mouseover', function (d, i) {
        d3.select(this).attr('fill', 'yellow');
      })
      .on('mouseout', function (d, i) {
        d3.select(this).attr('fill', scaleColor(i));
      });

    //绘制文字
    g.append('g')
      .selectAll('text')
      .data(data.features)
      .enter()
      .append('text')
      .attr('font-size', 12)
      .attr('text-anchor', 'middle')
      .attr('x', function (d, i) {
        var position = mercator(d.properties.centroid || [0, 0]);
        return position[0];
      })
      .attr('y', function (d, i) {
        var position = mercator(d.properties.centroid || [0, 0]);
        return position[1];
      })
      .attr('dy', function (d, i) {
        //这里为什么这么写呢,因为澳门和香港重合了,挤到一起了。
        if (d.properties.name === '澳门特别行政区') {
          return 10;
        }
      })
      .text(function (d, i) {
        return d.properties.name;
      });

  });

</script>

</html>