中国地図をD3.jsで書いてみる

## 完成図
![china.png](https://qiita-image-store.s3.amazonaws.com/0/873/1c88abe1-3eb9-da01-9d98-0ccf5e1fd371.png)


## 注意
正直 "Natural Earth" の地図は不完全。特に都市の情報は抜け落ちていたり間違っていると考えた方が良い。

* 都市データから県庁所在地(州都)がだいぶ抜けている
* 日本の地図だと、苫小牧が県庁所在地になっていたりする（札幌も一応入ってる）


## 事前準備
org2orgおよびtopojsonコマンドのインストール

```bash
$ brew install gdal
$ npm install -g topojson
```


## 地図データの取得
[Natural Earth](http://www.naturalearthdata.com/downloads/) から下記二つのデータをダウンロードする

* 1:10m Cultural Admin 1 – States, Provinces
* 1:10m Cultural Populated Places


## ソースコード

zipファイルを解凍してから、`build.sh`を実行。その後、`index.html`で表示。

### build.sh
```bash
#!/bin/bash

rm subunits.json
rm places.json

# 県の境界線情報の抽出
ogr2ogr -f GeoJSON -where "ADM0_A3 IN ('CHN')" subunits.json ne_10m_admin_1_states_provinces_lakes.shp
# 都市の情報の抽出 Admin-%で首都・州都・県庁所在地が抜き出せる(要調整)
ogr2ogr -f GeoJSON -where "ADM0_A3 IN ('CHN') AND FEATURECLA LIKE 'Admin-%'" places.json ne_10m_populated_places.shp

# 2つのファイルをtopojsonにまとめる
# -p <name> で元データから出力する属性を制限する
# 本当は name,name=NAME として一つにまとめたいが、これをやると'name'の方が出力されなくなる
topojson -p name,NAME,latitude,longitude -o cn.json -- subunits.json places.json
```

###  index.html

```html
<!DOCTYPE html>

<head>
  <meta charset="utf-8">
  <style>
    .subunit {
      fill: #ddc;
      stroke: #777;
      stroke-width: 0.5;
    }
    .subunit-label {
      fill: #777;
      font-size: 8px;
      font-family: 'Arial';
      text-anchor: middle;
    }
    .place {
      fill: #000;
      point-radius: 1px;
    }
    .place-label {
      fill: #000;
      font-size: 8px;
      font-family: 'Arial';
    }
  </style>
</head>

<body>
  <script src="http://d3js.org/d3.v3.min.js"></script>
  <script src="http://d3js.org/topojson.v0.min.js"></script>
  <script>
    var width = 800,
      height = 600;

    var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height);

    d3.json("cn.json", function(error, cn) {
      var subunits = topojson.object(cn, cn.objects.subunits).geometries;
      var places = topojson.object(cn, cn.objects.places).geometries;

      var projection = d3.geo.mercator()
        .center([104, 36]) // 中央の緯度経度
        .scale(600)
        .translate([width / 2, height / 2]);

      var path = d3.geo.path()
        .projection(projection)
        .pointRadius(2);

      // 県の境界
      svg.selectAll(".subunit")
        .data(subunits)
        .enter().append("path")
        .attr("class", "subunit")
        .attr("d", path);

      svg.selectAll(".subunit-label")
        .data(subunits)
        .enter().append("text")
        .attr("class", "subunit-label")
        .attr("dy", "0.35em")
        .attr("transform", function(d) {
          var coordinates = [d.properties.longitude, d.properties.latitude];
          return "translate(" + projection(coordinates) + ")";
        })
        .text(function(d) {
          return d.properties.name;
        });

      // 県庁所在地
      svg.selectAll(".place")
        .data(places)
        .enter().append("path")
        .attr("class", "place")
        .attr("d", path);

      svg.selectAll(".place-label")
        .data(places)
        .enter().append("text")
        .attr("class", "place-label")
        .attr("dx", "0.5em")
        .attr("dy", "0.35em")
        .attr("transform", function(d) {
          var coordinates = d.coordinates;
          return "translate(" + projection(coordinates) + ")";
        })
        .text(function(d) {
          return d.properties.NAME;
        });
    });
  </script>
</body>
```