Mapbox GL JSを使って自転車事故場所マップをWebGLな地図で描画するの巻

# はじめに

Mapbox GL JSは、WebGLとJavaScriptを使ってベクトル地図を描画するライブラリです。ラスタ地図と比較して、滑らかに動かしたり地図を傾けたりなどすることができます。今回はこれを使って鳥取県オープンデータを使って自転車事故の発生場所のデータをマッピングしてみました。

Mapbox GL JSがどんなものかを知るには、[Mapbox GL JS Examples](https://www.mapbox.com/mapbox-gl-js/examples/)にいろんなサンプルがあるのでこちらを見ると楽しいです。例えば、Google Earthっぽくスムーズに指定した地点へ飛んだり（[Slowly fly to location](https://www.mapbox.com/mapbox-gl-js/example/flyto-options/)）、地図を傾けたり（[Set initial pitch and bearing](https://www.mapbox.com/mapbox-gl-js/example/set-perspective/)）できる地図を簡単に扱えます。

今回は、前回のアドベントカレンダー（[鳥取県オープンデータで自転車事故の発生場所マップを作ってみたの巻](http://qiita.com/61503891/items/ae60420f53a17424a59d)）のデータをMapboxでWebGLな地図で表示するようにしてみました。

先にできたものをお見せします。

![image](https://qiita-image-store.s3.amazonaws.com/0/32894/00a5a76b-d7d4-1e7f-4f01-ed8220604149.png)

実際に動くデモは http://tottori.2574.jp で公開しています。またソースコードも https://github.com/mh61503891/2574 に公開しています。

（※この記事を書いた後に機能追加などしているので、記事とデモが少し違う点はご了承ください。）

# 開発

## 準備

まず、Mapboxのアカウントと[API access tokens](https://www.mapbox.com/studio/account/tokens)を取得します。API access tokensが無いとMapboxの地図データを受け取ることができません。


開発に必要なドキュメントは、主に以下の2つかと思います。APIリファレンスとExamplesです。

- [Mapbox GL JS API](https://www.mapbox.com/mapbox-gl-js/api/)
- [Mapbox GL JS Examples](https://www.mapbox.com/mapbox-gl-js/examples/)

ちなみに、[Mapbox JS API](https://www.mapbox.com/mapbox.js/)のAPIとは異なるのでごちゃ混ぜにならないように注意しましょう。（なりました。）

## 必要なファイル一覧

今回はこの4つです。`.geojson`は`.js`に入れてしまってもいいし、`.js`と`.css`も`.html`に入れてしまって1ファイルでやってしまう手もありますが、4つくらい分けておいたほうが無難かと思います。

- example.html
- example.js
- example.css
- example.geojson

## ウェブサーバの起動

`example.geojson`を読むにあたって、ウェブブラウザではローカルファイルは何かと参照させてくれないので、とりあえずウェブサーバを起動してしまいます。私は、ちょっとサンプルを動かしたりする時や面倒な時はRubyで以下のようにしてWebサーバを立ち上げてコーディングしています。もちろん、ウェブブラウザのオプションでローカルファイルへのアクセスを許可する仕方も良いかもです。

```bash
ruby -rwebrick -e 'WEBrick::HTTPServer.new({DocumentRoot:"./", Port:3000}).start'
```

## GeoJSONの作成

マップに表示したいピンのデータを作成します。の前回のアドベントカレンダー（[鳥取県オープンデータで自転車事故の発生場所マップを作ってみたの巻](http://qiita.com/61503891/items/ae60420f53a17424a59d)）で作成した https://gist.github.com/mh61503891/a2572598fa40f5bd0c08 を使います。

GistもMapboxを使ってGeoJSONを地図に表示してくれますので、Gistでうまく地図が表示されていれば、まずデータに問題はないっぽいです。

必要であれば以下のコマンドでダウンロードしてみてください。

```bash
wget 'https://gist.githubusercontent.com/mh61503891/a2572598fa40f5bd0c08/raw/b1068ed744137575faf4b36f7c7af5ab66b50406/tottori-opendata-bicycle-accident-2014.geojson' -O example.geojson
```

## HTMLの作成

[Example](https://www.mapbox.com/mapbox.js/example/v1.0.0/)から少し加工したものです。`mapbox-gl.js`と`mapbox-gl.css`を読み込むのと、`<div id='map'></div>`を書いておくのがポイントです。

```example.html
<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title>Example</title>
  <meta name='viewport' content='initial-scale=1,maximum-scale=1' />
  <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.12.0/mapbox-gl.js'></script>
  <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.12.0/mapbox-gl.css' rel='stylesheet' />
  <link href='example.css' rel='stylesheet' />
</head>
<body>
  <div id='map'></div>
  <script src='example.js'></script>
</body>
</html>
```

## CSSの作成

スマートフォンで全画面っぽく見えるように`margin`やら`padding`やらを0に詰めています。まあこれが無いと根本的に動かないといったものではないです。

```example.css
body {
  margin: 0;
  padding: 0;
}
#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}
```

## JavaScriptの作成

ここからが重要です。以下の4つが必要です。

- MapboxのAPIアクセストークン
- [LngLat](https://www.mapbox.com/mapbox-gl-js/api/#LngLat): 緯度経度
- [GeoJSONSource](https://www.mapbox.com/mapbox-gl-js/api/#GeoJSONSource): データソース
- [Map](https://www.mapbox.com/mapbox-gl-js/api/#Map): 地図

```example.js
// アクセストークンの設定
mapboxgl.accessToken = '<API access token>';

// 鳥取県の真ん中あたりの場所
var position = new mapboxgl.LngLat(133.842941, 35.375086).wrap();

// 地図のインスタンスを作成
var map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v8',
  center: [position.lng, position.lat],
  zoom: 8
});

// データのソースファイル
var source = new mapboxgl.GeoJSONSource({
  data: './example.geojson'
});

// 地図へのデータソースとレイヤのバインド
map.on('style.load', function() {
  map.addSource("example-data", source);
  map.addLayer({
    type: 'symbol',
    source: 'example-data',
    layout: {
      'icon-image': 'marker-15'
    }
  });
});
```

あとはウェブブラウザでアクセスすればOKです。

# おわりに

Mapbox GL JSでWebGLの地図を作ってみました。気になった点がいろいろ。

- Mapbox GL JSのAPIリファレンスをもう少し親切にしてほしい。わかりづらさあり。
- [Mapbox JSのExamples](https://www.mapbox.com/mapbox.js/example/v1.0.0/)と[Mapbox GL JSのExample](https://www.mapbox.com/mapbox-gl-js/examples/)のサンプルのバリエーションをある程度は揃えてほしい。Mapbox JSのサンプルコードはあるけどMapbox GL JSには無いんだけどやり方わからん〜。むき〜。
- マーカーの色の変え方がわからん〜。JSはできるけどGL JSはなんか動かへん。なんでや。
- WebGL、結構、重たい。
    - iPhone 5s → けっこう重い。ネイティブのマップに比べると重すぎ。iPhone 3の頃のレスポンス感。iPhone 6sだともうちょいましなのかな？iPhone 6sは持ってないので未確認。
    - Nexus 6 → まぁまぁ。さくさく。
- iOSで「ホームボタンに追加」してから起動するとまぁまぁ良い感じ。
- Androidで「ホーム画面に追加」してから起動するとほぼアプリっぽくて良い。AndroidのChromeは、ウェブブラウザから通知機能とかも使えるらいしAndroidに変えようかなと気持ちがゆらぐなど。ウェブブラウザだけそこそこ実用的なカーナビとか作れそう。
- どっちも横向き対応。

次回は現在地の追従などにトライしようかとおもっています。