MapLibre SwiftUI を触ってみた

2024年もあっという間に師走になり、新しい年を迎えようとしています。

今年は、iOSのMapLibre Nativeでは、レンダリングがMetalに変更となり、ライブラリの名前や関数の名前もMapLibreに寄せるように変更されたりと、大きな変更がありました。

そして、今年の2月に突如として登場したのが、MapLibre SwiftUIです。

https://github.com/maplibre/swiftui-dsl

## Maplibre SwiftUIとは

MapLibre Nativeは、そのままライブラリで導入してSwiftUIで使おうとすると `UIViewRepresentable` を作成する必要があります。

https://qiita.com/kyotonagoya/items/9f369017ab52796d36f6

以前は、iOSアプリで地図を表示するライブラリとして提供されているMapKitも `UIViewRepresentable` に準拠したViewを作成して利用する必要がありました。

しかし [WWDC23の MapKit for SwiftUI](https://developer.apple.com/videos/play/wwdc2023/10043/) での発表で、MapKitもSwiftUIで利用できるようになり、 `UIViewRepresentable` を定義しなくともお手軽にSwiftUIで地図表示などが実装できるようになりました。

そして今年、それに追うような形でMapLibre NativeをSwiftUIで使えるようにしたライブラリが登場しました。それが [MapLibre SwiftUI](https://github.com/maplibre/swiftui-dsl) です。

## MapLibre SwiftUI の導入方法

::: note info
MapLibre Swiftは、記事執筆時点ではバージョンが0番台であることもあり、今後書き方や導入方法などが変更となる場合があります。また、動作が不安定の可能性もあります。
:::

MapLibre SwiftUIは、MapLibre Nativeの導入方法と同じ形でSwift Package Managerを使って導入します。

Xcodeから　File -> Add Package Dependencies をクリックして、MapLibre SwiftUIのGitHubのURLを右上の検索欄にいれることで追加できます。

![スクリーンショット 2024-12-10 0.27.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93706/30d2b2f3-9732-e05a-8d52-e66b294d9e36.png)

導入すると、MapLibre Native本体を含めたライブラリがインストールされます。

![スクリーンショット 2024-12-10 0.28.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93706/8f0fc394-d1d0-bb6c-c5db-05e461a285df.png)

## MapLibre SwiftUIでラインを表示させる

実際に、MapLibre SwiftUIでラインを表示させるコードを書くと、以下のようなソースコードとなります。

```swift
import SwiftUI
import MapLibre
import MapLibreSwiftDSL
import MapLibreSwiftUI
import CoreLocation

struct PolyLineMapSampleView: View {

  // スタイル用のURLを定義
  let styleURL = URL(string: "https://tile.openstreetmap.jp/styles/osm-bright-ja/style.json")!

  // 表示する線形の座標配列
  let waypoints: [CLLocationCoordinate2D] = [
    CLLocationCoordinate2D(latitude: 35.713586, longitude: 139.777218),
    CLLocationCoordinate2D(latitude: 35.713451, longitude: 139.777545),
    CLLocationCoordinate2D(latitude: 35.713334, longitude: 139.777803),
    CLLocationCoordinate2D(latitude: 35.713107, longitude: 139.777658),
    CLLocationCoordinate2D(latitude: 35.712846, longitude: 139.777449)
  ]

  var body: some View {
    MapView(styleURL: styleURL, camera: .constant(.center(waypoints.first!, zoom: 17.0))) {
      // ソースを定義
      let polylineSource = ShapeSource(identifier: "polyline-source") {
        MLNPolylineFeature(coordinates: waypoints, count: UInt(waypoints.count))
      }

      // レイヤーを定義
      LineStyleLayer(identifier: "polyline-style-layer", source: polylineSource)
        .lineCap(.round)
        .lineJoin(.round)
        .lineColor(.blue)
        .lineWidth(
          interpolatedBy: .zoomLevel,
          curveType: .exponential,
          parameters: NSExpression(forConstantValue: 2.0),
          stops: NSExpression(forConstantValue: [
            14: 4,
            18: 8
          ])
        )
    }
    .ignoresSafeArea()
  }
}

#Preview {
  PolyLineMapSampleView()
}

```

SwiftUIでMapViewを定義して、スタイルのURLとカメラの位置・ズームレベルをを引数として指定します。

MapViewの中に描画したいライン（線形）のデータを定義します。MapLibreなので、ラインとして描画するSourceと、ラインのレイアウトを決めるLayerを定義します。

そして、これの実行結果が以下となります。

![スクリーンショット 2024-12-12 9.03.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93706/9b031752-e4e7-0236-1af1-82ff596381a0.png)

なんて便利なのでしょう！これだけでラインを表示することができます。

## 余談: MapKit for SwiftUIでラインを表示する

ちなみに、MapKit for SwiftUI でラインを表示する処理を書くときは、以下のような書き方となります。

```swift
import SwiftUI
import MapKit

struct MapKitSampleView: View {
  // 表示する線形の座標配列
  let waypoints: [CLLocationCoordinate2D] = [
    CLLocationCoordinate2D(latitude: 35.713586, longitude: 139.777218),
    CLLocationCoordinate2D(latitude: 35.713451, longitude: 139.777545),
    CLLocationCoordinate2D(latitude: 35.713334, longitude: 139.777803),
    CLLocationCoordinate2D(latitude: 35.713107, longitude: 139.777658),
    CLLocationCoordinate2D(latitude: 35.712846, longitude: 139.777449)
  ]

  // 表示するPositionを設定
  let position: MapCameraPosition = .region(
    MKCoordinateRegion(
      center: CLLocationCoordinate2D(
        latitude: 35.713586,
        longitude: 139.777218
      ),
      latitudinalMeters: 200,
      longitudinalMeters: 200)
  )

  // ラインスタイルを定義
  let lineStyle: StrokeStyle = .init(
    lineWidth: 4,
    lineCap: .round,
    lineJoin: .round
  )

  var body: some View {
    Map(initialPosition: position) {
      MapPolyline( coordinates: waypoints)
        .stroke(Color.blue, style: lineStyle)
    }
  }
}

#Preview {
  MapKitSampleView()
}

```

そして、プレビューでの実行結果は以下の通り。

![スクリーンショット 2024-12-12 9.07.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93706/bc6c258a-ec74-1005-2488-482f4947fc8a.png)

MapKit for SwiftUI でも `Map` というViewを宣言して、その中にラインのデータを定義して表示させている形となります。

## 個人的な感想

MapLibre SwiftUI も　MapKit for SwiftUI のような書き方で地図表示や地物の描画できるので、 MapLibreを使う上での概念を学習すれば比較的とっつきやすい印象を受けました。

まだバージョンが0番台であることから正式リリースではない状態ですが、MapLibreをSwiftUIで書きたいというときには有効的な選択肢となりそうです。