在 iOS SDK (預覽版) 中建立資料來源
注意
Azure 地圖服務 iOS SDK 淘汰
適用於 iOS 的 Azure 地圖服務 原生 SDK 現在已被取代,將於 3/31/25 淘汰。 若要避免服務中斷,請透過 3/31/25 移轉至 Azure 地圖服務 Web SDK。 如需詳細資訊,請參閱 Azure 地圖服務 iOS SDK 移轉指南。
Azure 地圖服務 iOS SDK 會將資料儲存在資料來源中。 使用資料來源可將查詢和轉譯的資料作業最佳化。 目前,資料來源有兩種不同的類型:
- GeoJSON 來源:在本機管理 GeoJSON 格式的原始位置資料。 適用於小型到中型資料集 (數十萬個圖形)。
- 向量圖格來源:根據地圖底圖系統,為目前的地圖檢視載入格式化為向量圖格的資料。 適合用於大型資料集 (數百萬或數十億個圖形)。
GeoJSON 資料來源
Azure 地圖服務使用 GeoJSON 作為其主要資料模型之一。 GeoJSON 是以 JSON 格式表示地理空間資料的開放式地理空間標準方法。 透過 Azure 地圖服務 iOS SDK 中提供的 GeoJSON 類別,即可輕鬆建立及序列化 GeoJSON 資料。 在 DataSource
類別中載入及儲存 GeoJSON 資料,並使用圖層加以轉譯。 下列程式碼說明如何在 Azure 地圖服務中建立 GeoJSON 物件。
/*
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)
或者,可先將屬性載入字典中 (JSON),然後在建立特徵時將其傳入特徵中,如下列程式碼所示:
//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)
建立 GeoJSON 特徵後,即可透過地圖的 sources
屬性將資料來源新增至地圖。 下列程式碼說明如何建立 DataSource
、將其新增至地圖,並將特徵新增至資料來源。
//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)
下列程式碼說明用來建立 GeoJSON Feature
、 FeatureCollection
和幾何的數種方式。
// 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)
序列化和還原序列化 GeoJSON
特徵集合、特徵和幾何類別全都有 fromJson(_:)
和 toJson()
靜態方法,有助於序列化。 透過 fromJson()
方法傳遞的格式化有效 JSON 字串,會建立幾何物件。 此 fromJson()
方法也意味著您可以使用 JSONSerialization
或其他序列化/還原序列化策略。 下列程式碼說明如何取用字串化的 GeoJSON 功能,並將其還原序列化為 Feature
類別,然後再將其序列化回 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()
從 Web 或資產資料夾匯入 GeoJSON 資料
大部分的 GeoJSON 檔案都包含 FeatureCollection
。 以字串的形式讀取 GeoJSON 檔案,並使用 FeatureCollection.fromJson(_:)
方法將其還原序列化。
DataSource
類別具有名為 importData(fromURL:)
的內建方法,該方法可使用 Web 上或裝置中所含檔案的 URL 載入 GeoJSON 檔案。
// 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)
importData(fromURL:)
方法可讓您將 GeoJSON 摘要載入資料來源中,但只能有限地控制資料的載入方式,以及資料載入後會發生什麼情況。 下列程式碼是可重複使用的類別,可從 Web 或資產資料夾匯入資料,並透過回呼函式將其傳回至 UI 執行緒。 在回呼中,您可以新增額外的後續載入邏輯來處理資料、將其新增至地圖、計算其週框方塊,以及更新地圖相機。
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()
}
}
下列程式碼說明如何使用此公用程式將 GeoJSON 資料匯入為字串,並透過回撥將其傳回至主要執行緒。 在回呼中,字串資料可序列化為 GeoJSON 特徵集合,並新增至資料來源。 您可以選擇性地更新地圖相機,以將焦點放在資料上。
// 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)
])
}
更新特徵
類別 DataSource
可讓您輕鬆新增及移除特徵。 更新特徵的幾何或屬性時,需要取代資料來源中的特徵。 有兩種方法可用來更新特徵:
- 使用所需的更新建立新特徵,並使用
set
方法來取代資料來源中的所有特徵。 如果您想要更新資料來源中的所有特徵,此方法將可發揮效用。
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)
}
- 追蹤變數中的特徵執行個體,並將其傳入資料來源
remove
方法中,而加以移除。 使用所需的更新建立新特徵、更新變數參考,並使用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)
}
提示
如果您有一些會定期更新的資料,還有一些很少變更的資料,最好將這些資料分割到個別的資料來源執行個體。 資料來源發生更新時,會強制地圖重新繪製資料來源中的所有特徵。 藉由分割此資料,在該資料來源發生更新時,將只會重新繪製要定期更新的特徵,其他資料來源中的特徵將無需重新繪製。 這有助於提升效能。
向量圖格來源
向量圖格來源說明如何存取向量圖格圖層。 使用 VectorTileSource
類別將向量圖格來源具現化。 向量圖格圖層類似於圖格圖層,但兩者並不相同。 圖格圖層是點陣影像。 向量圖格圖層是 PBF 格式的壓縮檔案。 這個壓縮的檔案包含向量地圖資料,以及一或多個圖層。 此檔案可根據每個圖層的樣式,在用戶端上轉譯及設定樣式。 向量圖格中的資料包含點、線條和多邊形形式的地理特徵。 使用向量圖格圖層 (而非點陣圖格圖層) 有數個優點:
- 向量圖格的檔案大小通常比對等的點陣圖格小很多。 因此,會使用較少頻寬。 這意味著延遲較低、地圖效能更快,使用者體驗更加理想。
- 向量圖格會在用戶端上轉譯,因此會根據其顯示所在裝置的解析度進行調整。 因此,轉譯的地圖會顯得更加清晰,可清楚看到標籤。
- 變更向量地圖中的資料樣式時不需要再次下載資料,因為新的樣式可套用在用戶端上。 相對地,變更點陣圖格圖層的樣式時通常需要從伺服器載入圖格,然後再套用新樣式。
- 由於資料是以向量形式傳遞的,準備資料時所需的伺服器端處理會比較少。 因此,較新的資料可更快成為可用資料。
Azure 地圖服務遵循 Mapbox 向量圖格規格,這是一個開放式標準。 Azure 地圖服務提供下列向量圖格服務作為平台的一部分:
- 道路圖格
- 交通事故
- 交通流量
- Azure 地圖服務 Creator 也允許透過轉譯 -取得地圖底圖 API 來建立和存取自訂向量圖格
提示
使用 Azure 地圖服務轉譯服務中的向量或點陣圖格搭配 iOS SDK 時,您可以將 atlas.microsoft.com
取代為 AzureMap
的 domainPlaceholder
屬性。 此預留位置將會取代為地圖所使用的相同網域,並且會自動附加相同的驗證詳細資料。 這可大幅簡化使用 Microsoft Entra 驗證時對轉譯服務進行驗證的程序。
若要在地圖上顯示向量圖格來源的資料,請將來源連線至其中一個資料轉譯圖層。 所有使用向量來源的圖層,都必須在選項中指定 sourceLayer
值。 下列程式碼會將 Azure 地圖服務的交通流量向量圖格服務載入為向量圖格來源,然後使用線條圖層將其顯示在地圖上。 此向量圖格來源在來源圖層中有單一資料集,名為「交通流量」。 此資料集中的線條資料具有名為 traffic_level
的屬性,可在此程式碼中用來選取色彩和調整線條的大小。
// 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")
將資料來源連線至圖層
資料會使用轉譯圖層在地圖上轉譯。 一或多個轉譯圖層可參考單一資料來源。 下列轉譯圖層需要資料來源:
- 泡泡圖層 - 將點資料轉譯為地圖上的縮放圓圈。
- 符號圖層 - 將點資料轉譯為圖示或文字。
- 熱度圖圖層 - 將點資料轉譯為密度熱度圖。
- 線條圖層 - 轉譯線條,或轉譯多邊形的外框。
- 多邊形圖層 - 以單色或影像圖樣填滿多邊形的區域。
下列程式碼顯示如何建立資料來源、將其新增至地圖、將 GeoJSON 學分資料從遠端位置匯入資料來源,然後將其連接到泡泡圖層。
// 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)
還有其他不會連線至這些資料來源的轉譯圖層,但這類圖層會直接載入資料以進行轉譯。
- 圖格圖層 - 將點陣圖格圖層疊加地圖之上。
一個具有多個圖層的資料來源
多個圖層可連線至單一資料來源。 在許多不同的情況下,此選項都有其效益。 例如,請考量使用者繪製了多邊形的案例。 當使用者將點新增至地圖時,我們應轉譯並填滿多邊形區域。 對多邊形的外框新增樣式線條,使用者在繪製時就更能清楚看到多邊形的邊緣。 為了方便編輯多邊形中的個別位置,我們可以在每個位置上方新增一個控點,例如圖釘或標記。
在大部分的地圖平台中,您都需要多邊形物件、線條物件,以及多邊形中各個位置的圖釘。 當多邊形經過修改時,您必須手動更新線條和圖釘,這很快就會變得複雜起來。
透過 Azure 地圖服務,您只需在資料來源中有一個多邊形即可,如下列程式碼所示。
// 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])
提示
您也可以使用 map.layers.insertLayer(_:below:)
方法,此方法可以將現有圖層的識別碼或執行個體當做第二個參數傳入。 這會指示地圖插入在現有圖層底下新增的新圖層。 除了傳入圖層識別碼以外,此方法也支援下列值。
"labels"
- 在地圖標籤圖層底下插入新圖層。"transit"
- 在地圖道路和交通圖層底下插入新圖層。
其他資訊
請參閱下列文章,以取得更多可新增至地圖的程式碼範例: