この記事はモバイルファクトリー Advent Calendar 2017 10日目の記事です。
今回は、go-staticmaps
というライブラリを紹介したいと思います。
https://github.com/flopp/go-staticmaps
go-staticmaps
このライブラリは、地図のタイルデータ(地図のデータを四角く小さく切ったようなもの)に対してマーカーを置いたりパスを引くことができたり、最終的に画像として出力することができます。
手軽に自分のオリジナルの地図画像を作りたいときにもってこいのライブラリです。
さっそく使ってみる
といきたいところですが、その前に、今回使うタイルデータを準備します。
今回はOpenMapTilesの地図タイルデータを使用します。
実は、自前でタイルデータを用意しなくても、go-staticmapsはデフォルトでOpenStreetMapのタイルデータを使用して地図を表示させることができます。
しかし、OpenMapTilesはデフォルトでいくつかスタイルが用意されていて、自分好みに変えることもできるため、今回はあえて自分でタイルサーバを立てて使ってみることにします。
タイルデータの準備
準備は簡単です。公式でDockerを使ってタイルサーバを立てる手順が提供されているので、その通りに進めていきます。
https://openmaptiles.com/server/#install
少し時間はかかりますが、特につまるところはないと思われるので、詳細は割愛しますが、日本全体のタイルデータをダウンロードしてlocalhostでつなぐとこんな感じな地図が表示されると思います。
go-staticmapsを使う
それではgo-taticmapsを使っていきましょう。
最初にソースコードを載せます。
package main
import (
"image/color"
"github.com/flopp/go-staticmaps"
"github.com/fogleman/gg"
"github.com/golang/geo/s2"
)
func newTileProvider() *sm.TileProvider {
t := new(sm.TileProvider)
t.Name = "example-map"
t.Attribution = "(c) OpenMapTiles"
t.TileSize = 256
t.URLPattern = "http://localhost:32769/styles/klokantech-basic/%[2]d/%[3]d/%[4]d.png"
t.Shards = []string{"a", "b", "c"}
return t
}
func main() {
ctx := sm.NewContext()
ctx.SetTileProvider(newTileProvider()) //タイルデータ指定
ctx.SetSize(400, 300)
ctx.SetZoom(17)
//マーカーを追加
spot := s2.LatLngFromDegrees(35.6259434, 139.7251859)
ctx.AddMarker(sm.NewMarker(spot, color.RGBA{0xff, 0, 0, 0xff}, 16.0))
// 画像として出力
img, _ := ctx.Render()
gg.SavePNG("my-map.png", img)
}
これをmain.goとして保存して実行すると、以下の画像が出力されます。
解説
ソースコードの解説をしていきます。
newTileProvider
関数
地図の表示に使うタイルデータを指定しています。
(最初にも言ったようにデフォルトのタイルデータを使用するのであれば、この関数は必要ないです。)
ここでは先ほど準備したOpenMapTilesのタイルデータのURLの指定の他にもいくつかパラメータを設定していますが、URLPattern
とTileSize
以外は必須ではないので、なくてもかまいません。
Attribution
を指定しなければ画像の下の黒い帯は表示されません。
URLPattern
の%[2]d
、%[3]d
、%[4]d
は、それぞれズーム、x座標、y座標に対応しています。
URLPatternのURLは以下の場所から取得しましょう。そして{z}
となっているところを%[2]d
という具合にxとyも変換すれば大丈夫です。
main
関数
ctx.SetSize
やctx.SetZoom
は任意で設定できるパラメータです。地図画像全体のサイズ、ズームを指定できます。
指定しなければよさげなサイズやズームに自動で調整されます。
マーカーを追加する部分では、座標を一度s2.LatLngFromDegrees
に渡しています。
これにより数値の座標がLatLng
型に変換され、sm.NewMarker
に渡すことができるようになります。
sm.NewMarker
にはマーカーを置きたい座標、色、サイズを指定して、マーカーのインスタンスを生成します。
Render
関数では、タイルデータに対してマーカーやパスなどを描画して返却してくれています。
それをgg.SavePNG
を使うことで拡張子、ファイル名を指定して保存しています。
パスも追加したい
さきほどのコードに少し手を加えることで、マーカー同士にパスをひくことも可能です。
//マーカーを追加
spot1 := s2.LatLngFromDegrees(35.6259434, 139.7251859)
ctx.AddMarker(sm.NewMarker(spot1, color.RGBA{0xff, 0, 0, 0xff}, 16.0))
spot2 := s2.LatLngFromDegrees(35.620023, 139.72818)
ctx.AddMarker(sm.NewMarker(spot2, color.RGBA{0, 0xff, 0, 0xff}, 16.0))
// パスを追加
path := new(sm.Path)
path.Positions = []s2.LatLng{spot1, spot2}
path.Color = color.RGBA{0, 0, 0xff, 0xff} //パスの色
path.Weight = 3.0 //パスの幅
ctx.AddPath(path)
エリアを追加したい
マーカーやパスだけではなく、指定した箇所を塗りつぶすこともできます。
//マーカーを追加
spot1 := s2.LatLngFromDegrees(35.6259434, 139.7251859)
ctx.AddMarker(sm.NewMarker(spot1, color.RGBA{0xff, 0, 0, 0xff}, 16.0))
spot2 := s2.LatLngFromDegrees(35.620023, 139.72818)
spot3 := s2.LatLngFromDegrees(35.626159, 139.723602)
// エリアを追加
area := new(sm.Area)
area.Positions = []s2.LatLng{spot1, spot2, spot3}
area.Color = color.RGBA{0, 0, 0xff, 0xff} //パスの色
area.Fill = color.RGBA{0, 0xff, 0xff, 0xff} //塗りつぶす色
area.Weight = 3.0 //パスの幅
ctx.AddArea(area)
まとめ
なんとも簡単に地図タイルサーバの準備から、地図タイルデータに対してマーカーを置いたりパスを引いたりすることができました。すごい!!
これでいつでも自分だけの地図画像を作ることができます。
ライブラリの中身もシンプルで追いやすいと思うので、興味ある人はのぞいてみると面白いと思います。
おまけ
え?いまでも十分手軽だけどもっと手軽に地図画像を作りたい?
そんな方のために(?)、go-staticmapsはコマンドラインからも実行が可能です。
go get -u github.com/flopp/go-staticmaps/create-static-map
でインストールし、
$ create-static-map -m "35.6259434,139.7251859"
こうなります。圧倒的な手軽さ。もちろん、パスを引いたり、エリアで囲んだり、ライブラリの時とほぼほぼ機能は変わりません。
ただ、OpenMapTilesのような自前で用意したタイルサーバからはタイルデータを取得できないので、そこだけご注意ください。
それでは快適な地図画像ライフを。