フリーダムの日記

GIS(地理情報システム)を中心に技術的なことを書いています。

ArcGIS で iOS SDK を使用してみた!

今回は、ArcGISiOS 版の SDK を使用して、住所検索、品川区の観光情報のデータを地図に表示してみましたので、紹介したいと思います。

最終版のイメージは以下になります。

f:id:freedom0625:20200502234719p:plain:w300

また、今回作成したアプリは GitHub にも公開していますので参考にしてください! github.com

はじめに

地図アプリ開発SDK には、ArcGIS が提供している ArcGIS Runtime SDK for iOS を利用しました。ArcGIS Runtime SDK for iOS は、Google Maps と同じように iOS 版の地図アプリを開発することができます。主に ArcGIS プラットフォーム を利用して、空間検索などの GIS(地理情報システム) に特化した機能からよく利用するジオコーディングやルート検索などの機能までと幅広い機能を利用して地図アプリが開発できます。

developers.arcgis.com

今回は、地図表示や住所検索、さらに品川区の観光情報のデータを ArcGIS プラットフォームに登録して利用しました。品川区の観光情報は、東京都のオープンデータのカタログサイトに登録されているものを利用しました。

catalog.data.metro.tokyo.lg.jp

プロジェクトの作成と SDK のインストールについて

はじめに Xcode を起動してプロジェクトを作成します。そして、SDKをインストールしますが、ここではインストール方法は割愛します。インストールについては Install and set up の手順について本家サイトをご参照ください。SDK のダウンロードについても以下のサイトでご案内があります。

developers.arcgis.com

地図表示と住所検索

次に背景地図を表示するために以下のコードを記述します。背景地図は AGSMap クラスを利用して、ベースマップの指定(navigationVector)と初期位置(緯度経度)、ズームレベルを指定します。

import UIKit
import ArcGIS

class ViewController: UIViewController {

         @IBOutlet weak var mapView: AGSMapView!

         override func viewDidLoad() {
                 super.viewDidLoad()
                 // Do any additional setup after loading the view.

                 mapView.map = AGSMap(basemapType: .navigationVector, latitude: 35.681236, longitude: 139.767125, levelOfDetail: 15)
         }
}

SearchBar から入力されたテキスト情報から該当の場所に遷移するための機能を追加します。

例えば SearchBar に東京駅と入力されたら東京駅の緯度経度を取得して、東京駅に遷移して地図にその位置を表示することができます。 この時に ArcGIS のジオコーディングサービスを利用します。こちらのサービスは、リクエスト結果を保存しなければ 100 万リクエストまでは、無償で使用することができます。

developers.arcgis.com

ジオコーディングサービスは AGSLocatorTask クラスを利用し、ジオコーディングサービスのリクエスト結果の表示には、AGSGraphic クラスを使用します。

Graphic は一時的なデータを表示する場合に利用します。具体的な使用例については以下を参照してください。 developers.arcgis.com

import UIKit
import ArcGIS

class ViewController: UIViewController {
 
    @IBOutlet weak var mapView: AGSMapView!
    
    let locationOverlay = AGSGraphicsOverlay()
    
    let locatorTask = AGSLocatorTask(url: URL(string:"https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer")!)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        mapView.map = AGSMap(basemapType: .navigationVector, latitude: 35.681236, longitude: 139.767125, levelOfDetail: 15)
        
        mapView.graphicsOverlays.add(locationOverlay)
    }
}

extension ViewController: UISearchBarDelegate {
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        guard let searchText = searchBar.text else { return }
        
        locationOverlay.graphics.removeAllObjects()
        
        locatorTask.geocode(withSearchText: searchText) { [weak self] (results, error) in
            if let error = error {
                print("Error geocoding: \(error.localizedDescription)")
                return
            }
            
            guard let result = results?.first else { return }
            
            if let extent = result.extent {
                self?.mapView.setViewpoint(AGSViewpoint(targetExtent: extent))
            }
            
            if let location = result.displayLocation {
                let graphic = AGSGraphic(geometry: location, symbol: AGSSimpleMarkerSymbol(style: .circle, color: .red, size: 12), attributes: nil)
                self?.locationOverlay.graphics.add(graphic)
            }
            
            searchBar.resignFirstResponder()
        }
    }
}

結果の表示

以下の例では、中目黒を検索して表示しています。

f:id:freedom0625:20200502234209p:plain:w300

観光情報の表示

最後は、品川区の観光情報の表示です。

品川区の観光情報の表示には、フィーチャ レイヤーを使用します。フィーチャ レイヤーは、ArcGIS プラットフォームから REST API で配信されているため、REST のエンドポイントを指定することで地図に表示できたり、そのデータに対して検索などもできます。 フィーチャ レイヤーは、最初に AGSServiceFeatureTableインスタンスを作成して、AGSFeatureLayer のプロパティに指定して作成します。そして、map オブジェクトに追加して地図に表示します。

〜

    fileprivate func makeMap() -> AGSMap {
        
        let map = AGSMap(basemapType: .navigationVector, latitude: 35.681236, longitude: 139.767125, levelOfDetail: 15)
        
        let featureTable = AGSServiceFeatureTable(url: URL(string:"https://services5.arcgis.com/HzGpeRqGvs5TMkVr/arcgis/rest/services/kankojohoShinagawa100kei/FeatureServer/0")!)
        let featureLayer = AGSFeatureLayer(featureTable: featureTable)
        map.operationalLayers.add(featureLayer)
        
        return map
        
    }

〜

観光情報の属性情報を取得して表示したい場合があるかと思いますが、属性情報を取得する場合には、geoView クラスの identifyLayers メソッドを利用します。そして、取得した属性情報を吹き出しなどで表示する場合は、callout メソッドを利用します。

override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        mapView.map = makeMap()
        
        mapView.touchDelegate = self
    }

extension ViewController:AGSGeoViewTouchDelegate {
    func geoView(_ geoView: AGSGeoView, didTapAtScreenPoint screenPoint: CGPoint, mapPoint: AGSPoint) {
        mapView.identifyLayers(atScreenPoint: screenPoint, tolerance: 20, returnPopupsOnly: false) { (results, error) in
            if let error = error {
                print("Error identifying: \(error.localizedDescription)")
                return
            }
            
            if let result = results?.first,
                let feature = result.geoElements.first as? AGSFeature {
                self.mapView.callout.title = feature.attributes["name"] as? String
                self.mapView.callout.detail = feature.attributes["description_ja"] as? String
                self.mapView.callout.show(for: feature, tapLocation: mapPoint, animated: true)
            } else {
                self.mapView.callout.dismiss()
            }
        }
    }
}
〜    

ArcGIS プラットフォームに登録した観光情報

https://valuecreation.maps.arcgis.com/home/item.html?id=fff29ca0609b4b83853010b2a616292b

観光情報の REST のエンドポイント  services5.arcgis.com

結果の表示

以下のように目的の場所をクリックすると吹き出しを表示します。 f:id:freedom0625:20200502234719p:plain:w300

さいごに

今回は ArcGISiOS SDK を利用した地図アプリについて紹介しましたが、色々な機能があるので、次回も紹介できればと思います。