今回は世界地図にグリッドを重ねて表示します。
マップは球状の地球をモニターに投影しているので、どこかが歪んだり切り取られたりしています。グリッドがあると、これを基準に地図の中の距離を比較することができるようになります。
このマップでは、緯度と経度に沿ったグリッドと、ある地点を中心に円状に広がるグリッドの2つを表示することにします。
今回は世界地図を使っていますが、グリッド以外の部分は、D3.js マップ – 日本地図を表示するとほぼ同じです。
では、まず結果とコードを載せてから、詳しい説明をします。
世界地図のグリッドの結果とコード:
結果:

データ:
世界地図のtopojsonデータはリンク先にあります。
コード:
<!DOCTYPE html> <head> <meta charset="utf-8"> <style> body { background-color:LightCyan;} </style> </head> <body> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://d3js.org/topojson.v1.min.js"></script> <script> var width = 700, height = 500; var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var color = d3.scale.category20(); var mercator = d3.geo.mercator() .center([0,0]) .translate([width/2, height/2]) .scale(100); var path = d3.geo.path() .projection(mercator); // 地球の緯度経度グリッドの座標を出す。 var graticule = d3.geo.graticule() .step([5,5]); // stepでグリッドの幅。デフォルトは[10,10]で10度ずつ。 // 円状のグリッド。 var angles = d3.range(10,180,5); //10~180を5刻みで作り、リストに入れる。 var geocircle = d3.geo.circle() .origin([ 136.0,35.6 ]); d3.json("world-topo-min.json", function(error, world) { console.log(world.objects.countries); // objects.countriesの中にgeometriesが入っているので、ここをgeojsonに解凍する。 var geometries = topojson.feature(world,world.objects.countries); svg.selectAll(".subunit") .data(geometries.features) .enter().append("path") .attr("class", function(d) { return d.id; }) .attr("d", path) .attr("fill", function(d){ return d.properties.color; }); // 色情報がすでに入っている。 }); // 緯度経度グリッドの表示。 svg.append("path") .datum(graticule) // detumとしてgraticuleを入れる。 .attr("class", "graticule") .attr("d",path) .attr("fill","none") .attr("stroke","red"); // 円状のグリッド表示。 svg.append("g") .selectAll(".geocircle") .data(angles).enter() // angleのためのデータ。 .append("path") .attr("class", "geocircle") .attr("d", function(r) { return path(geocircle.angle(r)()); }) // データごとにangleを変える。 .attr("fill","none") .attr("stroke","green"); </script> </body> </html>
ではコードの説明をします。
グリッドの設定を作る
緯度と経度に沿って走るグリッドは、d3.geo.graticule()で設定を作ります。
.step([x,y])で、グリッドの幅を緯度と経度の角度で決めます。stepを設定しない場合はデフォルトで10度ずつになっています。
var graticule = d3.geo.graticule() .step([5,5]); // stepでグリッドの幅。デフォルトは[10,10]で10度ずつ。
円状のグリッドは、d3.geo.circle()で設定を作ります。
.origin([x,y])で、円の中心となる緯度と経度を決めます。今回は、日本の中心部である[ 136.0,35.6 ]にしました。
さらにanglesという変数に、角度を入れたリストを格納しています。これは、中心部から何度離れたところに円を描くかを指定しています。
このリストは、d3.range()を使って一気に作っています。
var angles = d3.range(10,180,5); //10~180の数を5刻みで作り、リストに入れる。 var geocircle = d3.geo.circle() .origin([ 136.0,35.6 ]);
グリッドを表示する
経度と緯度のグリッドは、pathのデータとして先ほど作ったgraticuleを入れます。
忘れてはいけないのは、attr(“d”,path)で、地理情報からpath要素を作るためのジェネレータであるpathを入れることです。
// 緯度経度グリッドの表示。 svg.append("path") .datum(graticule) // detumとしてgraticuleを入れる。 .attr("class", "graticule") .attr("d",path) .attr("fill","none") .attr("stroke","red");
円状のグリッドは、先ほど作ったanglesというリストデータを入れます。
.attr(“d”, function(r) { return path(geocircle.angle(r)()); }の部分でpathを作っています。
少しややこしいですが、データをそれぞれgeocircle.angle(r)として取り込んだ後、関数としてすぐ実行しています。これで円状グリッドの地理情報が出るので、path()で囲むことでpath要素に変換しています。
// 円状のグリッド表示。 svg.append("g") .selectAll(".geocircle") .data(angles).enter() // angleのためのデータ。 .append("path") .attr("class", "geocircle") .attr("d", function(r) { return path(geocircle.angle(r)()); }) // データごとにangleを変える。 .attr("fill","none") .attr("stroke","green");