Bagikan melalui


Membuat sumber data di iOS SDK (Pratinjau)

Catatan

Penghentian Azure Peta iOS SDK

Azure Peta Native SDK untuk iOS sekarang tidak digunakan lagi dan akan dihentikan pada 31/3/3/25. Untuk menghindari gangguan layanan, migrasikan ke Azure Peta Web SDK dengan 3/31/25. Untuk informasi selengkapnya, lihat Panduan migrasi Azure Peta iOS SDK.

Azure Maps iOS SDK menyimpan data di sumber data. Menggunakan sumber data akan mengoptimalkan operasi data untuk pembuatan kueri dan penyajian. Saat ini, ada dua jenis sumber data:

  • Sumber GeoJSON: Mengelola data lokasi mentah dalam format GeoJSON secara lokal. Baik untuk himpunan data kecil hingga menengah (di atas ratusan ribu bentuk).
  • Sumber petak peta vektor: Memuat data yang diformat sebagai petak peta vektor untuk tampilan peta saat ini, didasarkan pada sistem petak peta. Ideal untuk himpunan data besar hingga masif (jutaan atau miliaran bentuk).

Sumber data GeoJSON

Azure Maps menggunakan GeoJSON sebagai salah satu model data utamanya. GeoJSON adalah cara standar geospasial terbuka untuk mewakili data geospasial dalam format JSON. Kelas GeoJSON tersedia di Azure Maps iOS SDK untuk membuat dan menserialisasikan data GeoJSON dengan mudah. Muat dan simpan data GeoJSON di kelas DataSource dan render menggunakan layer. Kode berikut menunjukkan cara objek GeoJSON dapat dibuat di Azure Maps.

/*
    Raw GeoJSON feature

    {
        type": "Feature",
        "geometry": {
            "type": "Point",
            "coordinates": [-100, 45]
        },
        "properties": {
            "custom-property": "value"
        }
    }

*/

//Create a point feature.
let feature = Feature(Point(CLLocationCoordinate2D(latitude: 45, longitude: -100)))

//Add a property to the feature.
feature.addProperty("custom-property", value: "value")

//Add the feature to the data source.
source.add(feature: feature)

Atau properti dapat dimuat ke dalam kamus (JSON) terlebih dahulu kemudian diteruskan ke fitur saat membuatnya, seperti yang ditunjukkan oleh kode berikut:

//Create a dictionary to store properties for the feature.
var properties: [String: Any] = [:]
properties["custom-property"] = "value"

let feature = Feature(Point(CLLocationCoordinate2D(latitude: 45, longitude: -100)), properties: properties)

Setelah Anda membuat fitur GeoJSON, sumber data dapat ditambahkan ke peta melalui properti sources peta. Kode berikut memperlihatkan cara membuat DataSource, menambahkannya ke peta, dan menambahkan fitur ke sumber data.

//Create a data source and add it to the map.
let source = DataSource()
map.sources.add(source)

//Add GeoJSON feature to the data source.
source.add(feature: feature)

Kode berikut menunjukkan beberapa cara untuk membuat GeoJSON Feature, FeatureCollection, dan geometri.

// GeoJSON Point Geometry
let point = Point(location)

// GeoJSON LineString Geometry
let polyline = Polyline(locations)

// GeoJSON Polygon Geometry
let polygon = Polygon(locations)

let polygonWithInteriorPolygons = Polygon(locations, interiorPolygons: polygons)

// GeoJSON MultiPoint Geometry
let pointCollection = PointCollection(locations)

// GeoJSON MultiLineString Geometry
let multiPolyline = MultiPolyline(polylines)

let multiPolylineFromLocations = MultiPolyline(locations: arrayOfLocationArrays) // [[CLLocationCoordinate2D]]

// GeoJSON MultiPolygon Geometry
let multiPolygon = MultiPolygon(polygons)

let multiPolygonFromLocations = MultiPolygon(locations: arrayOfLocationArrays) // [[CLLocationCoordinate2D]]

// GeoJSON GeometryCollection Geometry

let geometryCollection = GeometryCollection(geometries)

// GeoJSON Feature
let pointFeature = Feature(Point(location))

// GeoJSON FeatureCollection
let featureCollection = FeatureCollection(features)

Serialisasi dan deserialisasi GeoJSON

Koleksi fitur, fitur, dan kelas geometri semuanya memiliki metode statis fromJson(_:) dan toJson(), yang membantu serialisasi. String JSON yang valid yang diformat melewati fromJson() metode membuat objek geometri. fromJson() Metode ini juga berarti Anda dapat menggunakan JSONSerialization atau strategi serialisasi/deserialisasi lainnya. Kode berikut menunjukkan cara mengambil fitur GeoJSON yang dirangkai dan deserialize ke dalam kelas Feature, lalu membuat serial kembali menjadi karakter GeoJSON.

// Take a stringified GeoJSON object.
let geoJSONString = """
    {
        "type": "Feature",
        "geometry": {
            "type": "Point",
            "coordinates": [-100, 45]
        },
        "properties": {
            "custom-property": "value"
        }
    }
"""

// Deserialize the JSON string into a feature.
guard let feature = Feature.fromJson(geoJSONString) else {
    throw GeoJSONSerializationError.couldNotSerialize
}

// Serialize a feature collection to a string.
let featureString = feature.toJson()

Mengimpor data GeoJSON dari folder aset atau web

Sebagian besar file GeoJSON berisi FeatureCollection. Baca file GeoJSON sebagai karakter dan gunakan metode FeatureCollection.fromJson(_:) untuk mendeserialisasinya.

Kelas DataSource ini memiliki metode bawaan yang disebut importData(fromURL:) yang dapat dimuat dalam file GeoJSON menggunakan URL ke file di web atau perangkat.

// Create a data source.
let source = DataSource()

// Import the geojson data and add it to the data source.
let url = URL(string: "URL_or_FilePath_to_GeoJSON_data")!
source.importData(fromURL: url)

// Examples:
// source.importData(fromURL: URL(string: "asset://sample_file.json")!)
// source.importData(fromURL: URL(string: "https://example.com/sample_file.json")!)

// Add data source to the map.
map.sources.add(source)

Metode ini importData(fromURL:) menyediakan cara untuk memuat umpan GeoJSON ke sumber data tetapi memberikan kontrol terbatas tentang bagaimana data dimuat dan apa yang terjadi setelah dimuat. Kode berikut adalah kelas yang dapat digunakan kembali untuk mengimpor data dari folder web atau aset sebagai string dan menampilkannya ke rangkaian UI melalui fungsi panggilan balik. Dalam panggilan balik, Anda kemudian dapat menambahkan lebih banyak logika pemuatan posting untuk memproses data, menambahkannya ke peta, menghitung kotak pembatasnya, dan memperbarui kamera peta.

import Foundation

@objc
public class Utils: NSObject {
    /// Imports data from a web url or local file url and returns it as a string to a callback on the main thread.
    /// - Parameters:
    ///     - url: A web url or local file url that points to data to load.
    ///     - completion: The callback function to return the data to.
    @objc
    public static func importData(fromURL url: URL, completion: @escaping (String?) -> Void) {
        URLSession.shared.dataTask(with: url) { data, _, _ in
            DispatchQueue.main.async {
                if let data = data {
                    completion(String(decoding: data, as: UTF8.self))
                } else {
                    completion(nil)
                }
            }
        }.resume()
    }
}

Kode berikut menunjukkan cara menggunakan utilitas ini untuk mengimpor data GeoJSON sebagai string dan mengembalikannya ke utas utama melalui panggilan balik. Dalam panggilan balik, data string dapat diserialisasikan ke dalam koleksi Fitur GeoJSON dan ditambahkan ke sumber data. Secara opsional, perbarui kamera peta untuk fokus pada data.

// Create a data source and add it to the map.
let source = DataSource()
map.sources.add(source)

// Create a web url or a local file url
let url = URL(string: "URL_to_GeoJSON_data")!
// Examples:
// let url = Bundle.main.url(forResource: "FeatureCollectionSample", withExtension: "geojson")!
// let url = URL(string: "www.yourdomain.com/path_to_feature_collection_sample")!

// Import the geojson data and add it to the data source.
Utils.importData(fromURL: url) { result in
    guard let result = result else {
        // No data imported.
        return
    }

    // Parse the data as a GeoJSON Feature Collection.
    guard let fc = FeatureCollection.fromJson(result) else {
        // Invalid data for FeatureCollection type.
        return
    }

    // Add the feature collection to the data source.
    source.add(featureCollection: fc)

    // Optionally, update the maps camera to focus in on the data.

    // Calculate the bounding box of all the data in the Feature Collection.
    guard let bbox = BoundingBox.fromData(fc) else {
        // The feature collection is empty.
        return
    }

    // Update the maps camera so it is focused on the data.
    map.setCameraBoundsOptions([
        .bounds(bbox),
        .padding(20)
    ])
}

Memperbarui fitur

Kelas DataSource memudahkan untuk menambahkan dan menghapus fitur. Memperbarui geometri atau properti sebuah fitur memerlukan penggantian fitur dalam sumber data. Ada dua metode yang dapat digunakan untuk memperbarui fitur:

  1. Buat fitur baru dengan pembaruan yang diinginkan dan ganti semua fitur di sumber data menggunakan metode set. Metode ini bekerja dengan baik ketika Anda ingin memperbarui semua fitur di sumber data.
var source: DataSource!

private func onReady(map: AzureMap) {
    // Create a data source and add it to the map.
    source = DataSource()
    map.sources.add(source)

    // Create a feature and add it to the data source.
    let myFeature = Feature(Point(CLLocationCoordinate2D(latitude: 0, longitude: 0)))
    myFeature.addProperty("Name", value: "Original value")
    source.add(feature: myFeature)
}

private func updateFeature() {
    // Create a new replacement feature with an updated geometry and property value.
    let myNewFeature = Feature(Point(CLLocationCoordinate2D(latitude: -10, longitude: 10)))
    myNewFeature.addProperty("Name", value: "New value")

    // Replace all features to the data source with the new one.
    source.set(feature: myNewFeature)
}
  1. Lacak instans fitur dalam variabel, dan teruskan ke dalam metode remove sumber data untuk menghapusnya. Buat fitur baru dengan pembaruan yang diinginkan, perbarui referensi variabel, dan tambahkan ke sumber data menggunakan metode add.
var source: DataSource!
var myFeature: Feature!

private func onReady(map: AzureMap) {
    // Create a data source and add it to the map.
    source = DataSource()
    map.sources.add(source)

    // Create a feature and add it to the data source.
    myFeature = Feature(Point(CLLocationCoordinate2D(latitude: 0, longitude: 0)))
    myFeature.addProperty("Name", value: "Original value")
    source.add(feature: myFeature)
}

private func updateFeature() {
    // Remove the feature instance from the data source.
    source.remove(feature: myFeature)

    // Get properties from original feature.
    var props = myFeature.properties

    // Update a property.
    props["Name"] = "New value"

    // Create a new replacement feature with an updated geometry.
    myFeature = Feature(
        Point(CLLocationCoordinate2D(latitude: -10, longitude: 10)),
        properties: props
    )

    // Re-add the feature to the data source.
    source.add(feature: myFeature)
}

Tip

Jika Anda memiliki beberapa data yang akan diperbarui secara berkala, dan data lain yang akan jarang diubah, sebaiknya Anda membaginya menjadi instans sumber data yang terpisah. Ketika pembaruan terjadi di sumber data, pembaruan ini memaksa peta untuk menggambar ulang semua fitur dalam sumber data. Dengan membagi data ini, hanya fitur yang diperbarui secara berkala yang akan digambar ulang ketika pembaruan terjadi di satu sumber data, sementara fitur di sumber data lain tidak perlu digambar ulang. Hal ini akan membantu performa.

Sumber petak peta vektor

Sumber petak peta vektor menjelaskan cara mengakses lapisan petak peta vektor. Gunakan kelas VectorTileSource untuk membuat contoh sumber petak peta vektor. Lapisan petak peta vektor mirip lapisan petak peta tetapi tidak sama. Lapisan petak peta adalah gambar raster. Lapisan petak peta vektor adalah file terkompresi, dalam format PBF. File terkompresi ini terdiri atas data peta vektor dan satu atau beberapa lapisan. File dapat dirender dan ditata pada klien, berdasarkan gaya setiap lapisan. Data dalam petak peta vektor terdiri atas fitur geografis dalam bentuk titik, garis, dan poligon. Ada beberapa keuntungan menggunakan lapisan petak peta vektor daripada lapisan petak peta raster:

  • Ukuran file petak peta vektor biasanya jauh lebih kecil daripada petak peta raster yang setara. Dengan demikian, lebih sedikit bandwidth akan digunakan. Ini berarti latensi yang lebih rendah, peta yang lebih cepat, dan pengalaman pengguna yang lebih baik.
  • Karena petak peta vektor dirender pada klien, petak peta beradaptasi dengan resolusi perangkat tempat peta ditampilkan. Akibatnya, peta yang dirender tampak lebih terdefinisi dengan baik, dengan label sejernih kristal.
  • Mengubah gaya data di peta vektor tidak memerlukan pengunduhan data lagi karena gaya baru dapat diterapkan pada klien. Sebaliknya, mengubah gaya lapisan petak peta raster biasanya perlu memuat petak peta dari server, kemudian menerapkan gaya baru.
  • Karena data dikirimkan dalam bentuk vektor, ada lebih sedikit pemrosesan sisi server yang diperlukan untuk menyiapkan data. Akibatnya, data yang lebih baru dapat tersedia lebih cepat.

Azure Maps mematuhi Spesifikasi Petak Peta Vektor Mapbox, sebuah standar terbuka. Azure Maps menyediakan layanan petak peta vektor berikut sebagai bagian dari platform:

Tip

Saat menggunakan petak peta gambar vektor atau raster dari layanan render Azure Maps dengan iOS SDK, Anda dapat mengganti atlas.microsoft.com dengan AzureMapproperti' domainPlaceholder. Tempat penampung ini akan diganti dengan domain yang sama, yang digunakan oleh peta dan akan secara otomatis menambahkan detail autentikasi yang sama juga. Ini sangat menyederhanakan autentikasi dengan layanan render saat menggunakan autentikasi Microsoft Entra.

Untuk menampilkan data dari sumber petak peta vektor di peta, sambungkan sumber ke salah satu lapisan penyajian data. Semua lapisan yang menggunakan sumber vektor harus menentukan nilai sourceLayer dalam opsi. Kode berikut memuat layanan petak peta vektor alur lalu lintas Azure Maps sebagai sumber petak peta vektor, lalu menampilkannya di peta menggunakan lapisan baris. Sumber petak peta vektor ini memiliki satu himpunan data di lapisan sumber yang disebut "Alur lalu lintas". Data baris dalam himpunan data ini memiliki properti bernama traffic_level yang digunakan dalam kode ini untuk memilih warna dan menskalakan ukuran baris.

// Formatted URL to the traffic flow vector tiles.
let trafficFlowUrl = "\(map.domainPlaceholder)/traffic/flow/tile/pbf?api-version=1.0&style=relative&zoom={z}&x={x}&y={y}"

// Create a vector tile source and add it to the map.
let source = VectorTileSource(options: [
    .tiles([trafficFlowUrl]),
    .maxSourceZoom(22)
])
map.sources.add(source)

// Create a layer for traffic flow lines.
let layer = LineLayer(
    source: source,
    options: [

        // The name of the data layer within the data source to pass into this rendering layer.
        .sourceLayer("Traffic flow"),

        // Color the roads based on the traffic_level property.
        .strokeColor(
            from: NSExpression(
                forAZMInterpolating: NSExpression(forKeyPath: "traffic_level"),
                curveType: .linear,
                parameters: nil,
                stops: NSExpression(forConstantValue: [
                    0: UIColor.red,
                    0.33: UIColor.yellow,
                    0.66: UIColor.green
                ])
            )
        ),

        // Scale the width of roads based on the traffic_level property.
        .strokeWidth(
            from: NSExpression(
                forAZMInterpolating: NSExpression(forKeyPath: "traffic_level"),
                curveType: .linear,
                parameters: nil,
                stops: NSExpression(forConstantValue: [
                    0: 6,
                    1: 1
                ])
            )
        )
    ]
)

// Add the traffic flow layer below the labels to make the map clearer.
map.layers.insertLayer(layer, below: "labels")

Cuplikan layar peta dengan garis jalan berkode warna memperlihatkan tingkat arus lalu lintas.

Menyambungkan sumber data ke lapisan

Data dirender di peta menggunakan lapisan penyajian. Satu atau beberapa lapisan penyajian dapat mereferensikan satu sumber data. Lapisan penyajian berikut memerlukan sumber data:

Kode berikut menunjukkan cara membuat sumber data, menambahkannya ke peta, mengimpor data titik GeoJSON dari lokasi yang jauh ke sumber data, lalu menyambungkannya ke lapisan gelembung.

// Create a data source.
let source = DataSource()

// Create a web url or a local file url
let url = URL(string: "URL_or_FilePath_to_GeoJSON_data")!
// Examples:
// let url = Bundle.main.url(forResource: "FeatureCollectionSample", withExtension: "geojson")!
// let url = URL(string: "yourdomain.com/path_to_feature_collection_sample")!

// Import the geojson data and add it to the data source.
source.importData(fromURL: url)

// Add data source to the map.
map.sources.add(source)

// Create a layer that defines how to render points in the data source and add it to the map.
let layer = BubbleLayer(source: source)
map.layers.addLayer(layer)

Ada lapisan penyajian lain yang tidak terhubung ke sumber data ini, tetapi mereka langsung memuat data untuk penyajian.

Satu sumber data dengan beberapa lapisan

Beberapa lapisan dapat disambungkan ke satu sumber data. Ada banyak skenario berbeda saat opsi ini berguna. Contohnya, pertimbangkan skenario saat pengguna menggambar poligon. Kita harus merender dan mengisi area poligon saat pengguna menambah titik ke peta. Menambah garis bergaya untuk menguraikan poligon membuatnya lebih mudah melihat tepi poligon, saat pengguna menggambar. Untuk mengedit posisi individu dengan mudah di poligon, kita dapat menambahkan handel, seperti pin atau penanda, di atas setiap posisi.

Cuplikan layar peta memperlihatkan beberapa lapisan yang merender data dari satu sumber data.

Di sebagian besar platform pemetaan, Anda memerlukan objek poligon, objek baris, dan pin untuk setiap posisi di poligon. Saat poligon dimodifikasi, Anda harus memperbarui baris dan pin secara manual, yang dapat dengan cepat menjadi kompleks.

Dengan Azure Peta, yang Anda butuhkan hanyalah satu poligon dalam sumber data seperti yang ditunjukkan dalam kode berikut.

// Create a data source and add it to the map.
let source = DataSource()
map.sources.add(source)

// Create a polygon and add it to the data source.
source.add(geometry: Polygon([
    CLLocationCoordinate2D(latitude: 33.15, longitude: -104.5),
    CLLocationCoordinate2D(latitude: 38.5, longitude: -113.5),
    CLLocationCoordinate2D(latitude: 43, longitude: -111.5),
    CLLocationCoordinate2D(latitude: 43.5, longitude: -107),
    CLLocationCoordinate2D(latitude: 43.6, longitude: -94)
]))

// Create a polygon layer to render the filled in area of the polygon.
let polygonLayer = PolygonLayer(
    source: source,
    options: [.fillColor(UIColor(red: 1, green: 165/255, blue: 0, alpha: 0.2))]
)

// Create a line layer for greater control of rendering the outline of the polygon.
let lineLayer = LineLayer(source: source, options: [
    .strokeColor(.orange),
    .strokeWidth(2)
])

// Create a bubble layer to render the vertices of the polygon as scaled circles.
let bubbleLayer = BubbleLayer(
    source: source,
    options: [
        .bubbleColor(.orange),
        .bubbleRadius(5),
        .bubbleStrokeColor(.white),
        .bubbleStrokeWidth(2)
    ]
)

// Add all layers to the map.
map.layers.addLayers([polygonLayer, lineLayer, bubbleLayer])

Tip

Anda juga dapat menggunakan metode map.layers.insertLayer(_:below:), di mana ID atau turunan dari lapisan yang ada dapat diteruskan sebagai parameter kedua. Hal ini akan memberi tahu peta itu untuk memasukkan lapisan baru yang ditambahkan di bawah lapisan yang ada. Selain melewati ID lapisan, metode ini juga mendukung nilai-nilai berikut.

  • "labels" - Memasukkan lapisan baru di bawah lapisan label peta.
  • "transit" - Memasukkan lapisan baru di bawah jalan peta dan lapisan transit.

Informasi Tambahan

Lihat artikel berikut untuk mengetahui sampel kode lainnya yang akan ditambahkan ke peta Anda: