Creare un'origine dati (Android SDK)
Android SDK di Mappe di Azure archivia i dati nelle origini dati. L'uso delle origini dati ottimizza le operazioni sui dati per l'esecuzione di query e il rendering. Attualmente sono disponibili due tipi di origini dati, ovvero:
- Origine GeoJSON: gestisce i dati località non elaborati in formato GeoJSON in locale. È idonea per set di dati di piccole e medie dimensioni (oltre a centinaia di migliaia di forme).
- Origine riquadro vettoriale: carica i dati formattati come riquadri vettoriali per la visualizzazione della mappa corrente, in base al sistema di riquadri delle mappe. Ideale per set di dati di grandi dimensioni (milioni o miliardi di forme).
Nota
Ritiro di Android SDK di Mappe di Azure
Azure Maps Native SDK per Android è ora deprecato e verrà ritirato il 3/31/25. Per evitare interruzioni del servizio, eseguire la migrazione al Web SDK di Mappe di Azure entro il 31/3/25. Per altre informazioni, vedere La guida alla migrazione di Android SDK di Mappe di Azure.
Origine dati GeoJSON
Mappe di Azure usa GeoJSON come uno dei modelli di dati principali. GeoJSON è una soluzione standard geospaziale aperta per la rappresentazione dei dati geospaziali in formato JSON. Classi GeoJSON disponibili in Android SDK di Mappe di Azure per creare e serializzare facilmente i dati GeoJSON. Caricare e archiviare i dati GeoJSON nella classe DataSource
ed eseguirne il rendering usando i livelli. Il codice seguente illustra come creare oggetti GeoJSON in Mappe di Azure.
/*
Raw GeoJSON feature
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-100, 45]
},
"properties": {
"custom-property": "value"
}
}
*/
//Create a point feature.
Feature feature = Feature.fromGeometry(Point.fromLngLat(-100, 45));
//Add a property to the feature.
feature.addStringProperty("custom-property", "value");
//Add the feature to the data source.
source.add(feature);
/*
Raw GeoJSON feature
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-100, 45]
},
"properties": {
"custom-property": "value"
}
}
*/
//Create a point feature.
val feature = Feature.fromGeometry(Point.fromLngLat(-100, 45))
//Add a property to the feature.
feature.addStringProperty("custom-property", "value")
//Add the feature to the data source.
source.add(feature)
Suggerimento
I dati GeoJSON possono essere aggiunti a un'istanza di DataSource
usando uno dei tre metodi seguenti: add
, importDataFromUrl
e setShapes
. Il metodo setShapes
offre un modo efficiente per sovrascrivere tutti i dati in un'origine dati. Se si chiamano i metodi clear
e successivamente add
per sostituire tutti i dati in un'origine dati, verranno effettuate due chiamate di rendering alla mappa. Il metodo setShape
cancella e aggiunge i dati all'origine dati con una singola chiamata di rendering alla mappa.
In alternativa, le proprietà possono essere caricate prima in un JsonObject, quindi passate alla funzionalità in fase di creazione, come illustrato nel codice di esempio seguente.
//Create a JsonObject to store properties for the feature.
JsonObject properties = new JsonObject();
properties.addProperty("custom-property", "value");
Feature feature = Feature.fromGeometry(Point.fromLngLat(-100, 45), properties);
//Create a JsonObject to store properties for the feature.
val properties = JsonObject()
properties.addProperty("custom-property", "value")
val feature = Feature.fromGeometry(Point.fromLngLat(-100, 45), properties)
Dopo aver creato una funzionalità GeoJSON, è possibile aggiungere un'origine dati alla mappa tramite la proprietà sources
della mappa. Il codice seguente illustra come creare un elemento DataSource
, aggiungerlo alla mappa e aggiungere una funzionalità all'origine dati.
//Create a data source and add it to the map.
DataSource source = new DataSource();
map.sources.add(source);
//Add GeoJSON feature to the data source.
source.add(feature);
Il codice seguente illustra diversi modi per creare una funzionalità GeoJSON, FeatureCollection e geometrie.
//GeoJSON Point Geometry
Point point = Point.fromLngLat(LONGITUDE, LATITUDE);
//GeoJSON Point Geometry
LineString linestring = LineString.fromLngLats(PointList);
//GeoJSON Polygon Geometry
Polygon polygon = Polygon.fromLngLats(listOfPointList);
Polygon polygonFromOuterInner = Polygon.fromOuterInner(outerLineStringObject,innerLineStringObject);
//GeoJSON MultiPoint Geometry
MultiPoint multiPoint = MultiPoint.fromLngLats(PointList);
//GeoJSON MultiLineString Geometry
MultiLineString multiLineStringFromLngLat = MultiLineString.fromLngLats(listOfPointList);
MultiLineString multiLineString = MultiLineString.fromLineString(singleLineString);
//GeoJSON MultiPolygon Geometry
MultiPolygon multiPolygon = MultiPolygon.fromLngLats(listOflistOfPointList);
MultiPolygon multiPolygonFromPolygon = MultiPolygon.fromPolygon(polygon);
MultiPolygon multiPolygonFromPolygons = MultiPolygon.fromPolygons(PolygonList);
//GeoJSON Feature
Feature pointFeature = Feature.fromGeometry(Point.fromLngLat(LONGITUDE, LATITUDE));
//GeoJSON FeatureCollection
FeatureCollection featureCollectionFromSingleFeature = FeatureCollection.fromFeature(pointFeature);
FeatureCollection featureCollection = FeatureCollection.fromFeatures(listOfFeatures);
//GeoJSON Point Geometry
val point = Point.fromLngLat(LONGITUDE, LATITUDE)
//GeoJSON Point Geometry
val linestring = LineString.fromLngLats(PointList)
//GeoJSON Polygon Geometry
val polygon = Polygon.fromLngLats(listOfPointList)
val polygonFromOuterInner = Polygon.fromOuterInner(outerLineStringObject, innerLineStringObject)
//GeoJSON MultiPoint Geometry
val multiPoint = MultiPoint.fromLngLats(PointList)
//GeoJSON MultiLineString Geometry
val multiLineStringFromLngLat = MultiLineString.fromLngLats(listOfPointList)
val multiLineString = MultiLineString.fromLineString(singleLineString)
//GeoJSON MultiPolygon Geometry
val multiPolygon = MultiPolygon.fromLngLats(listOflistOfPointList)
val multiPolygonFromPolygon = MultiPolygon.fromPolygon(polygon)
val multiPolygonFromPolygons = MultiPolygon.fromPolygons(PolygonList)
//GeoJSON Feature
val pointFeature = Feature.fromGeometry(Point.fromLngLat(LONGITUDE, LATITUDE))
//GeoJSON FeatureCollection
val featureCollectionFromSingleFeature = FeatureCollection.fromFeature(pointFeature)
val featureCollection = FeatureCollection.fromFeatures(listOfFeatures)
Serializzare e deserializzare GeoJSON
Le classi feature collection, feature e geometry hanno tutte metodi statici fromJson()
e toJson()
, che agevolano la serializzazione. La stringa JSON valida formattata elaborata con il metodo fromJson()
crea l'oggetto geometry. Questo metodo fromJson()
significa anche che è possibile usare Gson o altre strategie di serializzazione/deserializzazione. Il codice seguente illustra come acquisire una funzionalità GeoJSON stringata e deserializzarla nella classe feature, per poi serializzarla nuovamente in una stringa GeoJSON.
//Take a stringified GeoJSON object.
String GeoJSON_STRING = "{"
+ " \"type\": \"Feature\","
+ " \"geometry\": {"
+ " \"type\": \"Point\""
+ " \"coordinates\": [-100, 45]"
+ " },"
+ " \"properties\": {"
+ " \"custom-property\": \"value\""
+ " },"
+ "}";
//Deserialize the JSON string into a feature.
Feature feature = Feature.fromJson(GeoJSON_STRING);
//Serialize a feature collection to a string.
String featureString = feature.toJson();
//Take a stringified GeoJSON object.
val GeoJSON_STRING = ("{"
+ " \"type\": \"Feature\","
+ " \"geometry\": {"
+ " \"type\": \"Point\""
+ " \"coordinates\": [-100, 45]"
+ " },"
+ " \"properties\": {"
+ " \"custom-property\": \"value\""
+ " },"
+ "}")
//Deserialize the JSON string into a feature.
val feature = Feature.fromJson(GeoJSON_STRING)
//Serialize a feature collection to a string.
val featureString = feature.toJson()
Importare i dati GeoJSON dal Web o dalla cartella assets
La maggior parte dei file GeoJSON contiene un oggetto FeatureCollection. Leggere i file GeoJSON come stringhe e usare il metodo FeatureCollection.fromJson
per eseguirne la deserializzazione.
La classe DataSource
include un metodo predefinito denominato importDataFromUrl
che può essere caricato nei file GeoJSON usando un URL a un file sul Web o nella cartella degli asset. Questo metodo deve essere chiamato prima dell'aggiunta dell'origine dati alla mappa.
zone_pivot_groups: azure-maps-android
//Create a data source and add it to the map.
DataSource source = new DataSource();
//Import the geojson data and add it to the data source.
source.importDataFromUrl("URL_or_FilePath_to_GeoJSON_data");
//Examples:
//source.importDataFromUrl("asset://sample_file.json");
//source.importDataFromUrl("https://example.com/sample_file.json");
//Add data source to the map.
map.sources.add(source);
//Create a data source and add it to the map.
var source = new DataSource()
//Import the geojson data and add it to the data source.
source.importDataFromUrl("URL_or_FilePath_to_GeoJSON_data")
//Examples:
//source.importDataFromUrl("asset://sample_file.json")
//source.importDataFromUrl("https://example.com/sample_file.json")
//Add data source to the map.
map.sources.add(source)
Il metodo importDataFromUrl
è un modo semplice per caricare un feed GeoJSON in un'origine dati, ma offre un controllo limitato sulla modalità di caricamento dei dati e su cosa accade dopo il caricamento. Il codice seguente è una classe riutilizzabile per l'importazione di dati dal Web o dalla cartella di asset e la restituzione al thread di UI tramite una funzione di richiamata. Quindi, è possibile aggiungere più logica di postcaricamento nel callback per elaborare i dati, aggiungerli alla mappa, calcolarne il rettangolo di selezione e aggiornare la fotocamera delle mappe.
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.webkit.URLUtil;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.net.ssl.HttpsURLConnection;
public class Utils {
interface SimpleCallback {
void notify(String result);
}
/**
* Imports data from a web url or asset file name and returns it to a callback.
* @param urlOrFileName A web url or asset file name that points to data to load.
* @param context The context of the app.
* @param callback The callback function to return the data to.
*/
public static void importData(String urlOrFileName, Context context, SimpleCallback callback){
importData(urlOrFileName, context, callback, null);
}
/**
* Imports data from a web url or asset file name and returns it to a callback.
* @param urlOrFileName A web url or asset file name that points to data to load.
* @param context The context of the app.
* @param callback The callback function to return the data to.
* @param error A callback function to return errors to.
*/
public static void importData(String urlOrFileName, Context context, SimpleCallback callback, SimpleCallback error){
if(urlOrFileName != null && callback != null) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
String data = null;
try {
if(URLUtil.isNetworkUrl(urlOrFileName)){
data = importFromWeb(urlOrFileName);
} else {
//Assume file is in assets folder.
data = importFromAssets(context, urlOrFileName);
}
final String result = data;
handler.post(() -> {
//Ensure the resulting data string is not null or empty.
if (result != null && !result.isEmpty()) {
callback.notify(result);
} else {
error.notify("No data imported.");
}
});
} catch(Exception e) {
if(error != null){
error.notify(e.getMessage());
}
}
});
}
}
/**
* Imports data from an assets file as a string.
* @param context The context of the app.
* @param fileName The asset file name.
* @return
* @throws IOException
*/
private static String importFromAssets(Context context, String fileName) throws IOException {
InputStream stream = null;
try {
stream = context.getAssets().open(fileName);
if(stream != null) {
return readStreamAsString(stream);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// Close Stream and disconnect HTTPS connection.
if (stream != null) {
stream.close();
}
}
return null;
}
/**
* Imports data from the web as a string.
* @param url URL to the data.
* @return
* @throws IOException
*/
private static String importFromWeb(String url) throws IOException {
InputStream stream = null;
HttpsURLConnection connection = null;
String result = null;
try {
connection = (HttpsURLConnection) new URL(url).openConnection();
//For this use case, set HTTP method to GET.
connection.setRequestMethod("GET");
//Open communications link (network traffic occurs here).
connection.connect();
int responseCode = connection.getResponseCode();
if (responseCode != HttpsURLConnection.HTTP_OK) {
throw new IOException("HTTP error code: " + responseCode);
}
//Retrieve the response body as an InputStream.
stream = connection.getInputStream();
if (stream != null) {
return readStreamAsString(stream);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// Close Stream and disconnect HTTPS connection.
if (stream != null) {
stream.close();
}
if (connection != null) {
connection.disconnect();
}
}
return result;
}
/**
* Reads an input stream as a string.
* @param stream Stream to convert.
* @return
* @throws IOException
*/
private static String readStreamAsString(InputStream stream) throws IOException {
//Convert the contents of an InputStream to a String.
BufferedReader in = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
return response.toString();
}
}
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.webkit.URLUtil
import java.net.URL
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class Utils {
companion object {
/**
* Imports data from a web url or asset file name and returns it to a callback.
* @param urlOrFileName A web url or asset file name that points to data to load.
* @param context The context of the app.
* @param callback The callback function to return the data to.
*/
fun importData(urlOrFileName: String?, context: Context, callback: (String?) -> Unit) {
importData(urlOrFileName, context, callback, null)
}
/**
* Imports data from a web url or asset file name and returns it to a callback.
* @param urlOrFileName A web url or asset file name that points to data to load.
* @param context The context of the app.
* @param callback The callback function to return the data to.
* @param error A callback function to return errors to.
*/
public fun importData(urlOrFileName: String?, context: Context, callback: (String?) -> Unit, error: ((String?) -> Unit)?) {
if (urlOrFileName != null && callback != null) {
val executor: ExecutorService = Executors.newSingleThreadExecutor()
val handler = Handler(Looper.getMainLooper())
executor.execute {
var data: String? = null
try {
data = if (URLUtil.isNetworkUrl(urlOrFileName)) {
URL(urlOrFileName).readText()
} else { //Assume file is in assets folder.
context.assets.open(urlOrFileName).bufferedReader().use{
it.readText()
}
}
handler.post {
//Ensure the resulting data string is not null or empty.
if (data != null && !data.isEmpty()) {
callback(data)
} else {
error!!("No data imported.")
}
}
} catch (e: Exception) {
error!!(e.message)
}
}
}
}
}
}
Il codice seguente illustra come usare questa utilità per importare dati GeoJSON come stringa e restituirli al thread di UI tramite un callback. Nel callback, i dati della stringa possono essere serializzati in una raccolta di funzionalità GeoJSON e aggiunti all'origine dati. In alternativa, aggiornare la fotocamera delle mappe per concentrarsi sui dati.
//Create a data source and add it to the map.
DataSource source = new DataSource();
map.sources.add(source);
//Import the geojson data and add it to the data source.
Utils.importData("URL_or_FilePath_to_GeoJSON_data",
this,
(String result) -> {
//Parse the data as a GeoJSON Feature Collection.
FeatureCollection fc = FeatureCollection.fromJson(result);
//Add the feature collection to the data source.
source.add(fc);
//Optionally, update the maps camera to focus in on the data.
//Calculate the bounding box of all the data in the Feature Collection.
BoundingBox bbox = MapMath.fromData(fc);
//Update the maps camera so it is focused on the data.
map.setCamera(
bounds(bbox),
padding(20));
});
//Create a data source and add it to the map.
DataSource source = new DataSource();
map.sources.add(source);
//Import the GeoJSON data and add it to the data source.
Utils.importData("SamplePoiDataSet.json", this) {
result: String? ->
//Parse the data as a GeoJSON Feature Collection.
val fc = FeatureCollection.fromJson(result!!)
//Add the feature collection to the data source.
source.add(fc)
//Optionally, update the maps camera to focus in on the data.
//Calculate the bounding box of all the data in the Feature Collection.
val bbox = MapMath.fromData(fc);
//Update the maps camera so it is focused on the data.
map.setCamera(
bounds(bbox),
//Padding added to account for pixel size of rendered points.
padding(20)
)
}
Aggiornare una funzionalità
La classe DataSource
semplifica l'aggiunta e la rimozione di funzionalità. Per aggiornare la geometria o le proprietà di una funzionalità, è necessario sostituire la funzionalità nell'origine dati. Esistono due metodi per aggiornare una o più funzionalità:
- Creare le nuove funzionalità con gli aggiornamenti desiderati e sostituire tutte le funzionalità nell'origine dati usando il metodo
setShapes
. Questo metodo è indicato quando si desidera aggiornare tutte le funzionalità in un'origine dati.
DataSource source;
private void onReady(AzureMap map) {
//Create a data source and add it to the map.
source = new DataSource();
map.sources.add(source);
//Create a feature and add it to the data source.
Feature myFeature = Feature.fromGeometry(Point.fromLngLat(0,0));
myFeature.addStringProperty("Name", "Original value");
source.add(myFeature);
}
private void updateFeature(){
//Create a new replacement feature with an updated geometry and property value.
Feature myNewFeature = Feature.fromGeometry(Point.fromLngLat(-10, 10));
myNewFeature.addStringProperty("Name", "New value");
//Replace all features to the data source with the new one.
source.setShapes(myNewFeature);
}
var source: DataSource? = null
private fun 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.
val myFeature = Feature.fromGeometry(Point.fromLngLat(0.0, 0.0))
myFeature.addStringProperty("Name", "Original value")
source!!.add(myFeature)
}
private fun updateFeature() {
//Create a new replacement feature with an updated geometry and property value.
val myNewFeature = Feature.fromGeometry(Point.fromLngLat(-10.0, 10.0))
myNewFeature.addStringProperty("Name", "New value")
//Replace all features to the data source with the new one.
source!!.setShapes(myNewFeature)
}
- Tenere traccia dell'istanza della funzionalità in una variabile e passarla al metodo
remove
delle origini dati per rimuoverla. Creare le nuove funzionalità con gli aggiornamenti desiderati, aggiornare il riferimento alla variabile e aggiungerlo all'origine dati usando il metodoadd
.
DataSource source;
Feature myFeature;
private void onReady(AzureMap map) {
//Create a data source and add it to the map.
source = new DataSource();
map.sources.add(source);
//Create a feature and add it to the data source.
myFeature = Feature.fromGeometry(Point.fromLngLat(0,0));
myFeature.addStringProperty("Name", "Original value");
source.add(myFeature);
}
private void updateFeature(){
//Remove the feature instance from the data source.
source.remove(myFeature);
//Get properties from original feature.
JsonObject props = myFeature.properties();
//Update a property.
props.addProperty("Name", "New value");
//Create a new replacement feature with an updated geometry.
myFeature = Feature.fromGeometry(Point.fromLngLat(-10, 10), props);
//Re-add the feature to the data source.
source.add(myFeature);
}
var source: DataSource? = null
var myFeature: Feature? = null
private fun 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.fromGeometry(Point.fromLngLat(0.0, 0.0))
myFeature.addStringProperty("Name", "Original value")
source!!.add(myFeature)
}
private fun updateFeature() {
//Remove the feature instance from the data source.
source!!.remove(myFeature)
//Get properties from original feature.
val props = myFeature!!.properties()
//Update a property.
props!!.addProperty("Name", "New value")
//Create a new replacement feature with an updated geometry.
myFeature = Feature.fromGeometry(Point.fromLngLat(-10.0, 10.0), props)
//Re-add the feature to the data source.
source!!.add(myFeature)
}
Suggerimento
Se si dispone di alcuni dati che verranno aggiornati regolarmente e di altri dati che verranno modificati di rado, è consigliabile suddividerli in istanze dell'origine dati separate. Quando si verifica un aggiornamento in un'origine dati, questo forza la mappa ad aggiornare tutte le funzionalità nell'origine dati. Suddividendo questi dati, solo le funzionalità che vengono aggiornate regolarmente sono aggiornate quando si verifica un aggiornamento in tale origine dati, mentre le funzionalità nell'altra origine dati non necessitano di aggiornamento. Ciò contribuisce a migliorare le prestazioni.
Origine riquadro vettoriale
Un'origine riquadro vettoriale descrive come accedere a un livello di riquadro vettoriale. Usare la classe VectorTileSource
per creare un'istanza di un'origine riquadro vettoriale. I livelli di riquadro vettoriale sono simili ai livelli a riquadri, ma non sono uguali. Un livello riquadro è un'immagine raster. I livelli riquadro vettoriale sono un file compresso in formato PBF. Questo file compresso contiene i dati vettoriali della mappa e uno o più livelli. È possibile eseguire il rendering e l'applicazione dello stile del file nel client, in base allo stile di ogni livello. I dati in un riquadro vettoriale contengono funzionalità geografiche sotto forma di punti, linee e poligoni. L'uso dei livelli riquadro vettoriale offre diversi vantaggi rispetto ai livelli riquadro raster:
- Le dimensioni di un file di un riquadro vettoriale sono in genere molto più piccole rispetto a quelle di un riquadro raster equivalente. Di conseguenza, viene usata una larghezza di banda inferiore. A sua volta, ciò si traduce in una latenza inferiore, una creazione più veloce della mappa e un'esperienza utente migliore.
- Poiché il rendering dei riquadri vettoriali viene eseguito nel client, questi riquadri si adattano alla risoluzione del dispositivo su cui vengono visualizzati. Pertanto, le mappe sottoposte a rendering risultano più definite e presentano etichette perfettamente nitide.
- La modifica dello stile dei dati nelle mappe vettoriali non richiede un nuovo download dei dati, perché il nuovo stile può essere applicato nel client. Al contrario, la modifica dello stile di un livello riquadro raster in genere richiede il caricamento di riquadri dal server e la successiva applicazione del nuovo stile.
- Poiché i dati vengono forniti in formato vettoriale, per preparare i dati è necessaria meno elaborazione sul lato server. Di conseguenza, i dati più recenti possono essere resi disponibili più velocemente.
Mappe di Azure è conforme allo standard aperto Mapbox Vector Tile Specification. Mappe di Azure offre i seguenti servizi di riquadri vettoriali nell’ambito della piattaforma:
- Riquadri stradali
- Incidenti stradali
- Flusso del traffico
- Creatore di Mappe di Azure supporta anche la creazione e l'accesso a riquadri vettoriali personalizzati tramite l'API Rendering - Get Map Tile
Suggerimento
Quando si usano riquadri vettoriali o di immagini raster dal servizio di rendering di Mappe di Azure con SDK Web, è possibile sostituire atlas.microsoft.com
con il segnaposto azmapsdomain.invalid
. Questo segnaposto verrà sostituito con lo stesso dominio usato dalla mappa e aggiungerà automaticamente anche gli stessi dettagli di autenticazione. Ciò semplifica notevolmente l'autenticazione con il servizio di rendering quando si usa l'autenticazione di Microsoft Entra.
Per visualizzare i dati da un'origine riquadro vettoriale sulla mappa, connettere l'origine a uno dei livelli di rendering dei dati. Tutti i livelli che usano un'origine vettoriale devono specificare un valore sourceLayer
nelle opzioni. Il codice seguente carica il servizio di riquadri vettoriali del flusso di traffico di Mappe di Azure come origine di riquadri vettoriali, quindi lo visualizza su una mappa usando un livello linea. Questa origine di riquadri vettoriali ha un singolo set di dati nel livello di origine denominato "Flusso di traffico". I dati di linea in questo set di dati hanno una proprietà denominata traffic_level
utilizzata in questo codice per selezionare il colore e ridimensionare le linee.
//Formatted URL to the traffic flow vector tiles, with the maps subscription key appended to it.
String trafficFlowUrl = "https://azmapsdomain.invalid/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.
VectorTileSource source = new VectorTileSource(
tiles(new String[] { trafficFlowUrl }),
maxSourceZoom(22)
);
map.sources.add(source);
//Create a layer for traffic flow lines.
LineLayer layer = new LineLayer(source,
//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(
interpolate(
linear(),
get("traffic_level"),
stop(0, color(Color.RED)),
stop(0.33, color(Color.YELLOW)),
stop(0.66, color(Color.GREEN))
)
),
//Scale the width of roads based on the traffic_level property.
strokeWidth(
interpolate(
linear(),
get("traffic_level"),
stop(0, 6),
stop(1,1)
)
)
);
//Add the traffic flow layer below the labels to make the map clearer.
map.layers.add(layer, "labels");
//Formatted URL to the traffic flow vector tiles, with the maps subscription key appended to it.
val trafficFlowUrl = "https://azmapsdomain.invalid/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.
val source = VectorTileSource(
tiles(arrayOf(trafficFlowUrl)),
maxSourceZoom(22)
)
map.sources.add(source)
//Create a layer for traffic flow lines.
val layer = LineLayer(
source, //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(
interpolate(
linear(),
get("traffic_level"),
stop(0, color(Color.RED)),
stop(0.33, color(Color.YELLOW)),
stop(0.66, color(Color.GREEN))
)
), //Scale the width of roads based on the traffic_level property.
strokeWidth(
interpolate(
linear(),
get("traffic_level"),
stop(0, 6),
stop(1, 1)
)
)
)
//Add the traffic flow layer below the labels to make the map clearer.
map.layers.add(layer, "labels")
Connessione di un'origine dati a un livello
Il rendering dei dati viene eseguito sulla mappa mediante livelli di rendering. Uno o più livelli di rendering possono fare riferimento a una singola origine dati. I livelli di rendering seguenti richiedono un'origine dati:
- Livello bolla: esegue il rendering dei dati dei punti come cerchi ridimensionati sulla mappa.
- Livello simbolo: esegue il rendering dei dati dei punti come icone o testo.
- Livello mappa termica: esegue il rendering dei dati dei punti come mappa termica della densità.
- Livello linea: esegue il rendering di una linea o del contorno dei poligoni.
- Livello poligono: riempie l'area di un poligono con un colore a tinta unita o un motivo con immagine.
Il codice seguente mostra come creare un'origine dati, aggiungerla alla mappa e connetterla a un livello bolla. Quindi, vengono importati nell'origine dati i dati dei punti GeoJSON da una posizione remota.
//Create a data source and add it to the map.
DataSource source = new DataSource();
//Import the geojson data and add it to the data source.
source.importDataFromUrl("URL_or_FilePath_to_GeoJSON_data");
//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.
BubbleLayer layer = new BubbleLayer(source);
map.layers.add(layer);
//Create a data source and add it to the map.
val source = DataSource()
//Import the geojson data and add it to the data source.
source.importDataFromUrl("URL_or_FilePath_to_GeoJSON_data")
//Add data source to the map.
map.sources.add(source)
Esistono più livelli di rendering che non si connettono a queste origini dati, ma caricano direttamente i dati per il rendering.
- Livello riquadro: sovrappone un livello riquadro raster sopra la mappa.
Un'origine dati con più livelli
È possibile connettere più livelli a una singola origine dati. Questa opzione è utile in numerosi scenari. Si consideri, ad esempio, lo scenario in cui un utente disegna un poligono. È necessario eseguire il rendering e riempire l'area del poligono man mano che l'utente aggiunge punti alla mappa. L'aggiunta di una linea con stile per delineare il poligono semplifica la visualizzazione dei bordi del poligono man mano che l'utente disegna. Per modificare facilmente una singola posizione nel poligono, è possibile aggiungere un punto di controllo, ad esempio un segnaposto o un indicatore, sopra ogni posizione.
Nella maggior parte delle piattaforme di mapping, sarebbero necessari un oggetto poligono, un oggetto linea e un segnaposto per ogni posizione nel poligono. Man mano che il poligono viene modificato, sarebbe necessario aggiornare manualmente la linea e i segnaposto, rendendo la struttura molto complessa.
Con Mappe di Azure, è sufficiente un singolo poligono in un'origine dati, come illustrato nel codice seguente.
//Create a data source and add it to the map.
DataSource source = new DataSource();
map.sources.add(source);
//Create a polygon and add it to the data source.
source.add(Polygon.fromLngLats(/* List of points */));
//Create a polygon layer to render the filled in area of the polygon.
PolygonLayer polygonLayer = new PolygonLayer(source,
fillColor("rgba(255,165,0,0.2)")
);
//Create a line layer for greater control of rendering the outline of the polygon.
LineLayer lineLayer = new LineLayer(source,
strokeColor("orange"),
strokeWidth(2f)
);
//Create a bubble layer to render the vertices of the polygon as scaled circles.
BubbleLayer bubbleLayer = new BubbleLayer(source,
bubbleColor("orange"),
bubbleRadius(5f),
bubbleStrokeColor("white"),
bubbleStrokeWidth(2f)
);
//Add all layers to the map.
map.layers.add(new Layer[] { polygonLayer, lineLayer, bubbleLayer });
//Create a data source and add it to the map.
val source = DataSource()
map.sources.add(source)
//Create a polygon and add it to the data source.
source.add(Polygon.fromLngLats())
//Create a polygon layer to render the filled in area of the polygon.
val polygonLayer = PolygonLayer(
source,
fillColor("rgba(255,165,0,0.2)")
)
//Create a line layer for greater control of rendering the outline of the polygon.
val lineLayer = LineLayer(
source,
strokeColor("orange"),
strokeWidth(2f)
)
//Create a bubble layer to render the vertices of the polygon as scaled circles.
val bubbleLayer = BubbleLayer(
source,
bubbleColor("orange"),
bubbleRadius(5f),
bubbleStrokeColor("white"),
bubbleStrokeWidth(2f)
)
//Add all layers to the map.
map.layers.add(arrayOf<Layer>(polygonLayer, lineLayer, bubbleLayer))
Suggerimento
Quando si aggiungono livelli alla mappa usando il metodo map.layers.add
, l'ID o l'istanza di un livello esistente può essere trasmesso come secondo parametro. In questo modo, si indica alla mappa di inserire il nuovo livello aggiunto sotto il livello esistente. Oltre a trasmettere un ID livello, questo metodo supporta anche i valori seguenti.
"labels"
: inserisce il nuovo livello sotto i livelli di etichetta della mappa."transit"
: inserisce il nuovo livello sotto i livelli stradali e di transito della mappa.
Passaggi successivi
Per altri esempi di codice da aggiungere alle mappe, vedere gli articoli seguenti: