いまさっき思ったこと

あとで読み返したときになにかが生まれるかもしれないし、生まれないかもしれないけど、それはそれでいい

GoogleマップをLeafletを使って差し替える(OpenStreetMapと国土地理院の切り替え対応)

この話の背景

6月に Google Maps API が Google Maps Platform に変更となり、7/16から有料となりました。
正確には無料枠があるのですが、たとえば地図を表示するために使っていた「Maps JavaScript API」だと、これまでの25,000回/日から28,000回/月(約933回/日)と大幅に減ったため、課金されるユーザーが一気に増えることになると思います。
いちおう無料クレジット枠(毎月200ドル分)が用意されているのと、移行期間中の特別クレジットが配布されたため、7月にいきなり請求が届いた人は少ないと思いますが、ぼくが運営している攻城団も地図を大量に呼び出しているため、10万円近くの請求が発生していました(ただし無料枠とクレジットで相殺されてました)。

攻城団のような全国のランドマークを表示するようなデータベース系のサイトや、写真のEXIF情報を利用して撮影場所の地図を表示するようなサービスを運営している個人や法人であれば、かなりの出費になるんじゃないかと思います。
(月に数万PVの個人ブログであってもバズった途端に請求が発生するのはリスクが高いので、一定回数以上は表示させない=無料枠内で使う、といった設定はしておいたほうがいいかもしれません)

予想としてはもっと阿鼻叫喚の図が繰り広げられて、ともに苦しむ仲間の存在を確認したかったのですが、ツイッターなどを見ていても、ぜんぜんこの件について語ってる人がいないんですよね。なんでだろ。従来からGoogleマップを有料で使っていたのか、あるいは払える金額内でおさまっているのかのどちらかなのかなと思っています。
ただうちは悲鳴をあげるレベルなので、ひとまずGoogleマップの利用を諦めることにしました。

ではどのサービスに乗り換える?

法人利用において、Googleマップからの乗り換えを検討する場合、現状の選択肢としてはOpenStreetMap国土地理院(地理院タイル)の地図の二択になるかと思います。
(個人だとYahoo! JavaScriptマップAPIというのも選択肢になりえますが、こちらもGoogleよりは多いものの無料表示枠が50,000回/日と制限があるので注意)
なお、iframeで呼び出すタイプの地図であれば現在も無料で利用できるので、これに置き換える方法もありますが、アイコンを変更できないのと、複数のピンが刺せないので攻城団では採用できませんでした。ただし会社の地図ページとかであればぜんぜんOKだと思います。

では代替サービスに乗り換えるとして、選択基準の決め手になるのはなにかというと、地図の場合は「デザイン(見た目)」と「品質」です。
この2点においてGoogleマップがいかに優れていたのかということが今回ほんとうによくわかりました。百聞は一見にしかずということで、すべて並べてみますね。

Googleマップ

OpenStreetMap

国土地理院

いずれも姫路城を中心に描画した地図ですが、圧倒的にGoogleマップの見た目がいいですよね。度重なるデザインの調整もあって、見やすいし、わかりやすい。
とはいえ、OpenStreetMapか国土地理院かを選ばなきゃいけない以上、見た目だけで決めるならOpenStreetMapのほうがまだマシかなあという感じです。そしてもうひとつの地図のクオリティについてですが、これは逆に国土地理院のほうがいい。OpenStreetMapは「地図版Wikipedia」といわれるように基本的にはスポット情報などもみんなで整備していくので、地方にいけばいくほど情報も粗くなります。攻城団の場合、お城は地方にあることが大半なのでそれを考えると国土地理院に分があります。

一長一短の結果になってしまいました。じつに悩ましい。

Leafletを使って地図を表示する

じつはこれを解決する手段があります。それもかなり簡単に。
「Leaflet」というJavaScriptライブラリを使って、表示する方法です。Leafletはインタラクティブな地図を実装するために開発されたオープンソースソフトウェアで、かなりいろんなことができるのですが、とりあえず今回は「地図の表示」と「アイコンの変更」さえできれば十分なので、プログラムの知識もほとんど不要です。

 

まずCDNから読み込みます。

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>

地図を表示させる場所はこれまでGoogleマップで指定したものと同じでかまいません。
(サイズの指定はGoogleマップ同様、必須なので忘れずに)

<div id="map" style="width: 640px; height: 200px;"></div>

あとは地図データの指定と、ランドマークの緯度経度を指定してオリジナルのアイコンを設置しましょう。

<script type="text/javascript">

// タイルレイヤーを作成する
var cyberjapandata = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', {
	  maxZoom: 18,
	  attribution: '&copy; <a href="https://maps.gsi.go.jp/development/ichiran.html" target="_blank">国土地理院</a>',
	  }),
	openstreetmap = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
	  attribution: '&copy; <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>'
	  });
var baseMaps = {
    "国土地理院": cyberjapandata,
    "OpenStreetMap": openstreetmap
};

// 地図を作成する
var mymap = L.map('map', {layers: [cyberjapandata]});
L.control.layers(baseMaps).addTo(mymap);

// 地図の中心座標とズームレベルを設定する
mymap.setView([34.8393664,134.694024], 12);

// アイコンを作成する
var castleIcon  = L.icon({
	iconUrl:      '//kojodan.com/parts/parts-img/shiro4gmap.png', // アイコン画像のURL
    iconSize:     [26, 32], // アイコンの大きさ
	iconAnchor:   [13, 32], // 画像内でマーカーの位置を指し示す点の位置
	popupAnchor:  [0, -24]  // ポップアップが出現する位置(iconAnchorからの相対位置)
});
 
// 上記で作成したアイコンを使用してマーカーを作成する
var marker  = L.marker([34.8393664,134.694024], {icon: castleIcon}).addTo(mymap);
// クリックした際にポップアップメッセージを表示する
marker.bindPopup("姫路城");

</script>

完成したのはこんな感じです。画面右上にあるボタンで地図を切り替えることができます。

今回は国土地理院をデフォルトにしましたが、OpenStreetMapを最初に表示したい場合は

var mymap = L.map('map', {layers: [openstreetmap]});

にすれば変更できます。たぶんこういうのを利用するサイトは動的に緯度経度やランドマーク名をDBから取り出していると思いますが、複数のピンを打ちたい場合は配列にして流し込めばいけます。

このほかにも駅からの道順を示すための線を引いたり、Leafletを使えばあれこれできることはありますが、今日はここまで。ひとりでも救われる人がいたらいいなと思うので、ここで公開します。

おもしろき こともなき世を おもしろく すみなしものは 心なりけり