Google Maps JavaScript API の addGeoJson で読み込んだ GeoJSON を扱う

GeoJSON を使うと動的にマップにデータを読むこむといったことができます．Google Maps JavaScript API の addGeoJson で GeoJSON を読み込んだときに，スタイルを適用したり，イベントを追加したりする方法を記事にしたいと思います．

# GeoJSON
GeoJSON 自体については，以下のようなページを見れば分かります．
[データレイヤ  |  Google Maps JavaScript API  |  Google Developers](https://developers.google.com/maps/documentation/javascript/datalayer)
[GeoJSON フォーマット仕様](http://s.kitazaki.name/docs/geojson-spec-ja.html)

扱えるデータとしては Point，MultiPoint，LineString，MultiLineString，Polygon，MultiPolygon といったものがあります．Google Maps で扱える Circle，Rectangle はありません（どちらもDB上では Polygon として扱えばいいと思います）．

読み込むGeoJSON は以下のようなものです．

```json:GeoJSON
{
    "features": [
        {
            "geometry": {
                "coordinates": [
                    135.04531860352, 
                    34.206123649908
                ], 
                "type": "Point"
            }, 
            "properties": {
                "color": "#00ff00", 
                "type": "point", 
                "description": "cat",
            }, 
            "type": "Feature"
        }, 
         {
            "geometry": {
                "coordinates": [
                    134.98489379883, 
                    34.585736286513
                ], 
                "type": "Point"
            }, 
            "properties": {
                "color": "#ff0000", 
                "type": "point", 
                "description": "dog",
            }, 
            "type": "Feature"
        }, 
        {
            "geometry": {
                "coordinates": [
                    [
                        [
                            135.14419555664, 
                            34.532581106491
                        ], 
                        [
                            135.17852783203, 
                            34.475995767559
                        ], 
                        [
                            135.23208618164, 
                            34.517872614017
                        ], 
                        [
                            135.17990112305, 
                            34.582344417658
                        ], 
                        [
                            135.17303466797, 
                            34.540499988011
                        ], 
                        [
                            135.14419555664, 
                            34.532581106491
                        ]
                    ]
                ], 
                "type": "Polygon"
            }, 
            "properties": {
                "color": "#0000ff", 
                "type": "polygon", 
                "description": "duck",
            }, 
            "type": "Feature"
        }, 
        {
            "geometry": {
                "coordinates": [
                    [
                        134.79537963867, 
                        34.228267666464
                    ], 
                    [
                        134.81048583984, 
                        34.228835385227
                    ], 
                    [
                        134.81254577637, 
                        34.246432768532
                    ], 
                    [
                        134.79537963867, 
                        34.236215380881
                    ]
                ], 
                "type": "LineString"
            }, 
            "properties": {
                "color": "#ff0000", 
                "type": "polyline", 
                "description": "wolf",
            }, 
            "type": "Feature"
        }, 
     ], 
    "type": "FeatureCollection"
}

```

# スタイルの適用

`properties` の `color` に色を， `type` に表示するタイプを入れています．GeoJSON のタイプと，色によって表示するスタイルを切り替えます．マーカー，ポリライン，ポリゴンとそれぞれ処理は違いますが，マーカーの場合の処理は関数化させています．

`map.data.setStyle` でスタイルの定義を行います．`feature` に各レイヤーのデータが入っていて，`feature.getProperty` を使ってレイヤーごとのプロパティを取得しています．

（自分は PHP と非同期通信して動的に生成した GeoJSON を表示させています．もちろん，非同期通信ではない場合でも使えます）


```js:JavaScript
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
  if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {

    // GeoJSON を受け取る
    var geojson = JSON.parse(xmlhttp.responseText);

    // マップに GeoJSON を追加
    // マップにポイントやラインが描画される
    // map は initMap() で定義
    map.data.addGeoJson(geojson);

    // レイヤーのスタイル定義
    map.data.setStyle(function(feature) {
      if (feature.getProperty('type') === 'point') {
        // マーカーの処理は関数を使って処理
        return ({
          icon: getMarkerColor(feature.getProperty('color')),
        }); 
      } else if (feature.getProperty('type') === 'polyline') {
        // ポリラインの処理
        return ({
          strokeColor: feature.getProperty('color'),
          strokeWeight: 2,
          clickable: true,
          zIndex: 1
        });
      } else {
        // ポリゴンの処理
        return ({
          fillColor: feature.getProperty('color'),
          fillOpacity: 0.5,
          strokeWeight: 0,
          clickable: true,
          zIndex: 1
        });
      }
    });
  }
}
xmlhttp.open('POST', 'get_geojson.php', true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.timeout = 10000;
xmlhttp.send(); 
```

```js:JavaScript
function getMarkerColor(color) {
  
  switch(color) {
  case '#ff0000':
    markerIcon = 'marker_red.png';
    break;
  case '#00ff00':
    markerIcon = 'marker_green.png';
    break;
  case '#0000ff':
    markerIcon = 'marker_blue.png';
    break;
  }

  return {
    url: './icon/' + markerIcon,
    scaledSize: new google.maps.Size(21, 32),  // scaledSize でリサイズ
  };
}

```


参考：
[Google Maps API Adds GeoJSON Support: Here is an example | Technical Tidbits From Spatial Analysis & Data Science:](http://zevross.com/blog/2014/04/01/google-maps-api-adds-geojson-support-here-is-an-example/)


# イベントの設定
読み込んだレイヤーにイベントを追加したい場合があると思います．今回はレイヤーに対して，インフォウィンドウ（[info windows](https://developers.google.com/maps/documentation/javascript/examples/infowindow-simple?hl=ja)）を追加する処理を書きます．

`event.feature` でレイヤーと同じように `feature` を取り出すことができ，プロパティを取得することができます．

```js:JavaScript
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
  if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {

    // GeoJSON を受け取る
    var geojson = JSON.parse(xmlhttp.responseText);

    // マップに GeoJSON を追加
    // マップにポイントやラインが描画される
    map.data.addGeoJson(geojson);

    // レイヤーのスタイル定義
    ...(略)

    // ユーザがレイヤーをクリックしたときの処理
    map.data.addListener('click', function(event) {
      // infowindow は initMap() 内で
      // infowindow = new google.maps.InfoWindow(); として定義
      var description = event.feature.getProperty('description'); // infowindow に入れる内容
      infowindow.setContent(description);
      infowindow.setPosition(event.latLng); // ここでinfowindowの位置を指定
      infowindow.setOptions({pixelOffset: new google.maps.Size(0,-30)});
      infowindow.open(map);
    });
  }
}
xmlhttp.open('POST', 'get_geojson.php', true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.timeout = 10000;
xmlhttp.send(); 
```