LoginSignup
19
10

More than 5 years have passed since last update.

d3.js (v5) を使って白地図を描く

Last updated at Posted at 2018-09-09

d3.js (v5) を使って、最短で白地図を描く方法について、メモ。

  • 前提として基本的なd3.jsでのデータの扱い方は知っていることとする。(こういうやつ http://bl.ocks.org/alansmithy/e984477a741bc56db5a5)
  • d3は v3 -> v4 のアップデートでめちゃくちゃ名前空間が変わっている & v4 で callback書く系の関数がv5ではPromiseを返すようになっているため、過去記事のコードはほとんどそのままでは動かない。

目次

シンプルな白地図を描くために、最低限必要な以下の2つのステップについて説明する。

  • 地図のGeoJSONデータを用意する
  • GeoJSONをsvg形式に変換するd3関数 d3.geoMercator() と d3.geoPath() を理解する

この2つができれば、以下のExampleのような短いスクリプトで世界地図が描けるようになる。

ちなみに、

  • 白地図ではなく、地名や人口密度などの情報も重ねて表示したい場合は、GeoJSONのデータ形式をちゃんと理解する必要がある。
  • 描画を高速化したい場合、GeoJSONから無駄な情報を除いたり、TopoJSONに変換してファイルサイズを削減したりする必要がある。

これらについては後日まとめたいと思う。

Shapefileをダウンロードし、GeoJSONに変換する

Natural Earth から無料で世界地図のshapefileがダウンロードできる。
例えば、1:50mサイズ (http://www.naturalearthdata.com/downloads/50m-cultural-vectors/) の中から、国の境界のshapefile (Admin 0 – Countries の Download coutries)をダウンロードしてくる。

そしてチュートリアル Part 1 と同じように、shp2jsonを使えばGeoJSONに変換できる。

npm install -g shapefile  # shp2jsonのインストール
cd [shpファイルのあるフォルダ]
shp2json ne_50m_admin_0_countries.shp -o hogehoge.json  # 変換

GeoJSONをブラウザ上でsvgに変換して描画

d3.geoMercator(): 点から点への変換

d3.geoMercator()は、「緯度経度の点座標」を「svg上の点座標」に変換する関数。デフォルトでは世界地図をw960×h500のsvg領域に収めるような変換が設定されている。

>> var projection = d3.geoMercator();
>> console.log(projection([135, 40])); // 経度・緯度を入力すると
[840.375, 133.31457058917871] // svgの座標になる

世界地図ではなく特定の地域などを描画したい場合は、以下のパラメータを設定する。

  • translate: svgの中心座標
  • center: svgの中心(translate)に表示する緯度経度
  • scale: 地図の縮尺。メルカトル図法の場合は[svgの幅]/[表示したい経度幅のラジアン値]を入力すれば良いらしい...が、この辺は試行錯誤で数値を変えれば良い。

d3.geoMercator() はメルカトル図法で地図を描くための関数だが、他にも 色々なprojection関数 が提供されているので、描きたい地図に合わせて適切なものを選ぶとよい。

d3.geoPath(): 線から線への変換

d3.geoPath()は、GeoJSONのgeometryの情報を、svgのpath要素のd属性の形式に変換する関数。
イメージとしては、d3.geoMercator()が点から点への変換関数だったのに対して、d3.geoPath()は線から線への変換関数となっている。

>> var projmerc = d3.geoMercator(); 
>> var path = d3.geoPath(projmerc);
>> console.log(path({"type": "LineString", "coordinates": [[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]]})) // GeoJSONのgeometry情報
"M752.2833333333333,250L754.9527777777778,247.3304200186872L757.6222222222223,250L760.2916666666667,247.3304200186872" // path要素のd属性の形式

いよいよd3を使って地図を描く

例えば日本周辺の地図を描く場合、以下のようにする。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<script>
    // svgのサイズ
    var width = 400;
    var height = 800;

    // 描きたい緯度経度の領域(日本周辺)
    var west = 120;
    var east = 150;
    var north = 46;
    var south = 24;

    // svg要素を追加
    var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);

    // projectionを定義
    var projection = d3.geoMercator()
        .center([(west + east) / 2, (north + south) / 2]) // 緯度経度領域の中心
        .translate([width / 2, height / 2]) // svgの中心
        .scale(width / (2 * Math.PI * ((east - west) / 360)));

    // pathを定義
    var path = d3.geoPath(projection);

    // GeoJSONを読み込み、描画. ここでthenを使うのがv4との違い.
    d3.json("hogehoge.json").then(function(json) {
        svg.append("g").selectAll("path")
            .data(json.features)
            .enter()
            .append("path")
            .attr("d", path) // GeoJSONのgeometryの情報をpath関数で変換
            .attr("stroke", "black") // 線の色
            .attr("fill", "none"); // 塗りつぶしの色
        }
    )
</script>
</body>
</html>

Screen Shot 2018-09-11 at 1.53.32.png

Next Step

白地図を描くために必要な最低限の手順をまとめたが、地図にもっと情報を付け加えようとすると色々課題が出てくる。例えば、

  • 県境まで描画したい -> 1:10mのprovinceデータを使うことになるが、上にまとめた方法だと、地図が表示されるまで30秒くらい時間がかかってしまう。原因は主に以下の2つ。
    • 日本以外の見えない領域の描画にも時間を費やしてしまっている。
    • GeoJSONのファイルが大きすぎて読み込みに時間がかかる。
  • 人口密度や地名を表示したい -> GeoJSONに人口密度や地名のデータを追加する必要がある。

このへんを解決するためには、

  • GeoJSONから不必要な情報を削除する
  • GeoJSONに必要な情報を追加する
  • GeoJSONを軽量なTopoJSON形式に変換する

などの作業をする必要があるため、GeoJSONとTopoJSONというデータ形式についてキチンと理解する必要がある。
そのへんの説明はまた後日まとめたいと思う。

19
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
10