0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Mapbox for iOSでサードパーティ製のスタイルを設定する

Last updated at Posted at 2019-10-02

##はじめに
地図系のフレームワークで有名で、最近ではゼンリンとの提携がニュースになったりした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スタイルにアクセスするためのものでした。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?