LeafletでOpenStreetMapを表示してみる

OpenStreetMapを使用する上で、Leafletがとても扱いやすかったため、
簡単に使い方をまとめておきます。

# Leafletとは
![Leaflet.png](https://qiita-image-store.s3.amazonaws.com/0/256451/3beda71d-65f9-10cd-6d1f-69b07162b78f.png)
https://leafletjs.com/
Web地図のJavaScriptライブラリです。
簡単にWeb地図を表示することができます。
公式ドキュメントが丁寧で読み易いです。

# 地図を表示する
<img width="586" alt="地図表示" src="https://qiita-image-store.s3.amazonaws.com/0/256451/8c2342df-69af-a262-f4d1-ccd20ec1f657.png">
日本を中心にした地図を表示します。

```html:map_display.html
<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>地図表示</title>
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
    <script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script> 
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script type="text/javascript" src=“map_display.js"></script>
    <link rel="stylesheet" type="text/css" href="common.css">
</head>
<body>
	<div class="container">
		<div id="map"></div>
	</div>
</body>
```
```css:common.css
#map {
    width: 500px;
    height: 500px;
}
```
```javascript:map_display.js
var map = L.map('map').setView([36.575,135.984], 5);	// 日本を中心に設定

var tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
      attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
      maxZoom: 19
    });
tileLayer.addTo(map);
```
# マーカーを表示する
<img width="587" alt="マーカー表示" src="https://qiita-image-store.s3.amazonaws.com/0/256451/aa5d337c-2565-013d-400a-b16e1239f2c8.png">
任意の場所にマーカーを表示します。
HTMLファイルとCSSファイルに変更点は無いため、JSファイルだけ記述します。

```javascript:map_display.js
var map = L.map('map').setView([36.575,135.984], 5);	// 日本を中心に設定

var tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
      attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
      maxZoom: 19
    });
tileLayer.addTo(map);

// 追加部分
L.marker([35.69, 139.69]).addTo(map); // 東京の緯度,経度を指定してマーカーを立てる
```
また、GeoJSON形式でマーカーを設定することもできます。
単にマーカーを立てるだけなら上の手法の方が楽ですが、
この後紹介するポップアップ機能などを付けたい時にはこちらの方が便利です。

```javascript:map_display.js
// ここから
var map = L.map('map').setView([36.575,135.984], 5);	// 日本を中心に設定

var tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
      attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
      maxZoom: 19
    });
tileLayer.addTo(map);
// ここまで変更無し

// GeoJSON形式でマーカーを設定する
var geojsonFeature = [{
  "type": "Feature",
  "geometry": {
      "type": "Point",
      "coordinates": [139.69, 35.69]     // 経度,緯度の順になるので注意！
  }
}];
// GeoJSON形式のマーカーをマップに追加する
L.geoJson(geojsonFeature).addTo(map);
```
# マーカーにポップアップを付ける
<img width="509" alt="ポップアップ設定" src="https://qiita-image-store.s3.amazonaws.com/0/256451/60a39dfe-1a0d-abca-58fe-d59ae4a0fed4.png">
GeoJSON形式のマーカーにpropertiesメンバーを追加することで、
ポップアップを設定することができます。
クリックしたらポップアップが出るように設定してみます。

```javascript:map_display.js
var map = L.map('map').setView([36.575,135.984], 5);	// 日本を中心に設定

var tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
      attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
      maxZoom: 19
    });
tileLayer.addTo(map);

// GeoJSON形式でマーカーを設定する
var geojsonFeature = [{
  "type": "Feature",
  "geometry": {
      "type": "Point",
      "coordinates": [139.69, 35.69]
  },
  "properties": {                // ポップアップを設定
    "popupContent": "東京"        // ポップアップで表示する内容
  }
}];

// クリックしたらポップアップが出るように設定する
L.geoJson(geojsonFeature,
    {
       onEachFeature: function(feature, layer){
        if (feature.properties && feature.properties.popupContent) {
          layer.bindPopup(feature.properties.popupContent);
        } 
      }
    }).addTo(map);
```

# マーカーを複数個設定する
<img width="519" alt="複数個マーカー" src="https://qiita-image-store.s3.amazonaws.com/0/256451/b8f3c3c1-38fb-294b-b071-1ed11f0b2f7a.png">
マーカーの情報を配列に格納しておけば、複数個マーカーを設定することができます。

```javascript:map_display.js
var map = L.map('map').setView([36.575,135.984], 5);	// 日本を中心に設定

var geojsonFeature = [];                                // マーカー情報を格納する配列
var popupContents = ["東京", "大阪", "札幌", "那覇"];      // ポップアップで表示する内容
var lat = [35.69, 34.69, 43.06, 26.2125];               // 緯度
var lon = [139.69, 135.5, 141.35, 127.6811];            // 経度

var tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
      attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
      maxZoom: 19
    });
tileLayer.addTo(map);

// GeoJSON形式で複数個のマーカーを設定する
for (var i = 0; i < 4; i++){
	geojsonFeature.push({     // 1つのマーカーの情報を格納する
        "type": "Feature",
        "properties": {
            "popupContent": popupContents[i]
        },
        "geometry": {
            "type": "Point",
            "coordinates": [lon[i], lat[i]]
        }
    });
}

// クリックしたらポップアップが出るように設定する
L.geoJson(geojsonFeature,
    {
       onEachFeature: function(feature, layer){
        if (feature.properties && feature.properties.popupContent) {
          layer.bindPopup(feature.properties.popupContent);
        } 
      }
    }).addTo(map);
```

# オリジナル画像のマーカーを出してみる
<img width="516" alt="オリジナル画像マーカー" src="https://qiita-image-store.s3.amazonaws.com/0/256451/50351d76-9ea2-b7fa-e30e-b24ddc407628.png">
Leafletのデフォルトのマーカーの色が青だったのですが、
個人的に「赤いマーカーの方がいいな」と思ったので、画像を用意して設定しました。
![marker-red.png](https://qiita-image-store.s3.amazonaws.com/0/256451/9452b5d2-535c-8368-4079-42e64a62d40f.png)　←使用した画像です。

```javascript:map_display.js
var map = L.map('map').setView([36.575,135.984], 5);	// 日本を中心に設定

var geojsonFeature = [];                                // マーカー情報を格納する配列
var popupContents = ["東京", "大阪", "札幌", "那覇"];      // ポップアップで表示する内容
var lat = [35.69, 34.69, 43.06, 26.2125];               // 緯度
var lon = [139.69, 135.5, 141.35, 127.6811];            // 経度

var tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
      attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
      maxZoom: 19
    });
tileLayer.addTo(map);

// GeoJSON形式で複数個のマーカーを設定する
for (var i = 0; i < 4; i++){
	geojsonFeature.push({     // 1つのマーカーの情報を格納する
        "type": "Feature",
        "properties": {
            "popupContent": popupContents[i]
        },
        "geometry": {
            "type": "Point",
            "coordinates": [lon[i], lat[i]]
        }
    });
}

// クリックしたらポップアップが出るように設定する
L.geoJson(geojsonFeature,
    {
       onEachFeature: function(feature, layer){
        if (feature.properties && feature.properties.popupContent) {
          layer.bindPopup(feature.properties.popupContent);
        } 
      },
      // オリジナル画像を設定する
      pointToLayer: function(feature, latlng){
            var myIcon = L.icon({
                iconUrl: 'marker-red.png',  // 画像のURI
                iconSize: [25, 41],         // 画像のサイズ設定
                iconAnchor: [12, 40],       // 画像の位置設定
                popupAnchor: [0, -40]       //　　ポップアップの表示を開始する位置設定
            });
            return L.marker(latlng, {icon: myIcon});  // マーカーに画像情報を設定
        }
      }
    }).addTo(map);
```

# まとめ
簡単な概要はこの程度ですが、工夫すると、ポップアップに表示する内容をDBから取得して、動的にマーカーを必要な分だけ生成したりすることもできます。
仕組みが簡単なので、自由度が高くて使い易いです。