##はじめに
地図系のフレームワークで有名で、最近ではゼンリンとの提携がニュースになったりしたMapboxはiOS向けにもフレームワークを提供しています。
##Mapbox for iOSの導入
ただ地図を表示するだけなら、チュートリアルのとおりとてもシンプルに書けます。
import Mapbox
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "mapbox://styles/mapbox/streets-v11") //Mapbox公式スタイル
let mapView = MGLMapView(frame: view.bounds, styleURL: url)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.setCenter(CLLocationCoordinate2D(latitude: 59.31, longitude: 18.06), zoomLevel: 9, animated: false)
view.addSubview(mapView)
}
}
しかし上記コードのコメントにも書いたとおり、基本的には公式スタイルを設定するように作られています。
スタイルは、.json形式のデータにも関わらず、です。
公式スタイルを参照するのが最もラクですが、そのためにはAPIトークンが必要で、アクセス数に応じて料金が発生します。
けれどもMapbox公式スタイルでなくとも、OpenStreetMapなどオープンデータを活用する事も出来るはず…という事で色々試しました。
##サードパーティ製のスタイルを適用する
Mapboxのスタイルは、MGLMapViewの初期化時にstyleURLという引数で設定します。
つまりURLを渡さなければなりませんが、どこかのサーバーにJSONファイルを置いておく、というのはナンセンスです。ローカルで完結させたい。
という訳で、①:好きなデータ等を設定したスタイルを.json形式で作成する、②:①のローカルアドレスを取得しMGLMapViewに渡す、という方針になりました。
###①:スタイルを.json形式で作成する
Swiftでの.jsonの取り扱い等は本記事では割愛します。
スタイルの.jsonファイル、言い換えると辞書形式のデータ構造は以下のとおりです。
private var style:[String:Any] = [
"version":8,
"sources":[],
"layers":[],
]
versionは8で固定です。sourcesはレイヤーデータの形式等の設定、layersはsourcesのデータをどのように表示するか(透過度など)の設定となっています。
ここではsourcesとlayersに適切な初期データを与えて、.jsonデータを作成します。
mutating func setBasemap(name:String, tileUrlStr:String, attributionUrl:String="", tileSize:Int=256) {
let sources = [
name:[
"type":"raster",
"tiles":[tileUrlStr],
"attribution":"<a href='" + attributionUrl + "'>" + name + "</a>",
"tileSize":tileSize
]
]
let layers = [
[
"id":name,
"type":"raster",
"source":name,
"minzoom":0,
"maxzoom":18
]
]
self.style["sources"] = sources
self.style["layers"] = layers
}
上記のコードは、とあるラスターレイヤーをスタイルに設定するサンプルです。
レイヤーのnameとタイルのtileUrlStrを与えてやればスタイルに追記します。
.jsonファイルの出力については、長くなるのでサンプルだけ貼ります。
func writeJson(outputDir:String, filename:String) -> URL? {
let nsHomeDir = NSHomeDirectory()
let outputPath = nsHomeDir + outputDir + "/" + filename + ".json"
do {
let jsonData = try JSONSerialization.data(withJSONObject: self.style, options: .prettyPrinted)
try jsonData.write(to: URL(fileURLWithPath: outputPath))
return URL(fileURLWithPath: outputPath)
} catch {
print("error")
return nil
}
}
②:①のローカルアドレスを取得しMGLMapViewに渡す
①のローカルアドレスは、writeJson()の返り値です。つまり以下のとおり書けます。
let tmpStyleUrl = msManager.writeJson(outputDir: "/tmp", filename: "style")
mapView = MGLMapView(frame: rect, styleURL: tmpStyleUrl!)
ここで、msManagerとはスタイル全般を取り扱うクラスです。
アプリを起動する度に、writeJson()でiOS内の/tmpにstyle.jsonとして出力しています。
/tmpは、アプリを終了した後のデータの保存は保証されない、一次保存用フォルダです。
今回のような用途にもってこいですね。
さて、これで純正スタイルを設定する必要がなくなりました。
API tokenを削除してみましたが、問題なく動作します。API tokenはMapboxスタイルにアクセスするためのものでした。