Criar uma fonte de dados (Android SDK)

O SDK do Azure Maps para Android armazena dados em fontes de dados. O uso de fontes de dados otimiza as operações de dados para consulta e renderização. Atualmente, existem dois tipos de fontes de dados:

  • Origem GeoJSON: gerencia dados brutos de localização no formato GeoJSON localmente. Bom para conjuntos de dados pequenos a médios (mais de centenas de milhares de formas).
  • Origem do mosaico vetorial: carrega dados formatados como mosaicos vetoriais para a vista de mapa atual, com base no sistema de mosaico de mapas. Ideal para conjuntos de dados grandes a massivos (milhões ou bilhões de formas).

Nota

Aposentadoria do SDK do Android do Azure Maps

O SDK nativo do Azure Maps para Android foi preterido e será desativado em 31/03/25. Para evitar interrupções de serviço, migre para o SDK da Web do Azure Maps até 31/03/25. Para obter mais informações, consulte O guia de migração do SDK do Android do Azure Maps.

Fonte de dados GeoJSON

O Azure Maps usa GeoJSON como um de seus principais modelos de dados. GeoJSON é uma maneira padrão geoespacial aberta para representar dados geoespaciais no formato JSON. Classes GeoJSON disponíveis no SDK do Android do Azure Maps para criar e serializar dados GeoJSON facilmente. Carregue e armazene dados GeoJSON na DataSource classe e renderize-os usando camadas. O código a seguir mostra como os objetos GeoJSON podem ser criados no Azure Maps.

/*
    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)

Gorjeta

Os dados GeoJSON podem ser adicionados a uma DataSource instância usando um dos três métodos; add, importDataFromUrl, e setShapes. O setShapes método fornece uma maneira eficiente de substituir todos os dados em uma fonte de dados. Se você chamar os clear métodos then add para substituir todos os dados em uma fonte de dados, duas chamadas de renderização serão feitas para o mapa. O setShape método limpa e adiciona os dados à fonte de dados com uma única chamada de renderização para o mapa.

Como alternativa, as propriedades podem ser carregadas em um JsonObject primeiro e, em seguida, passadas para o recurso ao criá-lo, conforme mostrado no código de exemplo a seguir.

//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)

Depois de criar um recurso GeoJSON, uma fonte de dados pode ser adicionada ao mapa por meio sources da propriedade do mapa. O código a seguir mostra como criar um DataSource, adicioná-lo ao mapa e adicionar um recurso à fonte de dados.

//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);

O código a seguir mostra várias maneiras de criar um GeoJSON Feature, FeatureCollection e geometrias.

//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)

Serializar e desserializar GeoJSON

A coleção de recursos, o recurso e as classes de geometria têm fromJson()toJson() métodos estáticos, que ajudam na serialização. A String JSON válida formatada fromJson() passada pelo método cria o objeto de geometria. Esse fromJson() método também significa que você pode usar Gson ou outras estratégias de serialização/desserialização. O código a seguir mostra como pegar um recurso GeoJSON stringified e desserializá-lo na classe Feature e, em seguida, serializá-lo novamente em uma cadeia de caracteres 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()

Importar dados GeoJSON da Web ou da pasta de ativos

A maioria dos arquivos GeoJSON contém um FeatureCollection. Leia arquivos GeoJSON como strings e usou o FeatureCollection.fromJson método para desserializá-lo.

A DataSource classe tem um método interno chamado importDataFromUrl que pode carregar em arquivos GeoJSON usando uma URL para um arquivo na Web ou na pasta de ativos. Esse método deve ser chamado antes que a fonte de dados seja adicionada ao mapa.

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)

O importDataFromUrl método fornece uma maneira fácil de carregar um feed GeoJSON em uma fonte de dados, mas fornece controle limitado sobre como os dados são carregados e o que acontece depois que eles são carregados. O código a seguir é uma classe reutilizável para importar dados da pasta Web ou ativos e retorná-los ao thread da interface do usuário por meio de uma função de retorno de chamada. Em seguida, adicione mais lógica de pós-carregamento no retorno de chamada para processar os dados, adicione-os ao mapa, calcule sua caixa delimitadora e atualize a câmera de mapas.

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)
                    }
                }
            }
        }
    }
}

O código a seguir demonstra como usar esse utilitário para importar dados GeoJSON como uma cadeia de caracteres e retorná-los ao thread da interface do usuário por meio de um retorno de chamada. No retorno de chamada, os dados da cadeia de caracteres podem ser serializados em uma coleção GeoJSON Feature e adicionados à fonte de dados. Opcionalmente, atualize a câmera de mapas para se concentrar nos dados.

//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)
        )
    }

Atualizar um recurso

A DataSource classe facilita a adição e remoção de recursos. A atualização da geometria ou das propriedades de um recurso requer a substituição do recurso na fonte de dados. Há dois métodos que podem ser usados para atualizar um recurso:

  1. Crie o(s) novo(s) recurso(s) com as atualizações desejadas e substitua todos os recursos na fonte de dados usando o setShapes método. Esse método funciona bem quando você deseja atualizar todos os recursos em uma fonte de dados.
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)
}
  1. Acompanhe a instância do recurso em uma variável e passe-a para o método de fontes remove de dados para removê-la. Crie o(s) novo(s) recurso(s) com as atualizações desejadas, atualize a referência da variável e adicione-a à fonte de dados usando o add método.
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)
}

Gorjeta

Se você tiver alguns dados que serão atualizados regularmente e outros dados que raramente serão alterados, é melhor dividi-los em instâncias de fonte de dados separadas. Quando uma atualização ocorre em uma fonte de dados, ela força o mapa a repintar todos os recursos na fonte de dados. Ao dividir esses dados, apenas os recursos que são atualizados regularmente seriam repintados quando uma atualização ocorre nessa fonte de dados, enquanto os recursos na outra fonte de dados não precisariam ser repintados. Isso ajuda no desempenho.

Origem do mosaico vetorial

Uma fonte de mosaico vetorial descreve como aceder a uma camada de mosaico vetorial. Use a VectorTileSource classe para instanciar uma fonte de bloco vetorial. As camadas de mosaico vetorial são semelhantes às camadas de mosaico, mas não são iguais. Uma camada de mosaico é uma imagem rasterizada. As camadas de mosaico vetorial são um ficheiro comprimido, em formato PBF . Esse arquivo compactado contém dados de mapa vetorial e uma ou mais camadas. O arquivo pode ser renderizado e estilizado no cliente, com base no estilo de cada camada. Os dados em um bloco vetorial contêm características geográficas na forma de pontos, linhas e polígonos. Há várias vantagens de usar camadas de mosaico vetorial em vez de camadas de mosaico raster:

  • Um tamanho de arquivo de um bloco de vetor é normalmente muito menor do que um bloco raster equivalente. Como tal, menos largura de banda é usada. Isso significa menor latência, um mapa mais rápido e uma melhor experiência do usuário.
  • Como os blocos vetoriais são renderizados no cliente, eles se adaptam à resolução do dispositivo em que estão sendo exibidos. Como resultado, os mapas renderizados aparecem mais bem definidos, com rótulos cristalinos.
  • Alterar o estilo dos dados nos mapas vetoriais não requer baixar os dados novamente, uma vez que o novo estilo pode ser aplicado no cliente. Por outro lado, alterar o estilo de uma camada de mosaico raster normalmente requer carregar blocos do servidor e, em seguida, aplicar o novo estilo.
  • Como os dados são entregues em forma vetorial, há menos processamento do lado do servidor necessário para preparar os dados. Como resultado, os dados mais recentes podem ser disponibilizados mais rapidamente.

O Azure Maps adere à Mapbox Vetor Tile Specification, um padrão aberto. O Azure Maps fornece os seguintes serviços de blocos vetoriais como parte da plataforma:

Gorjeta

Ao usar blocos de imagem vetorial ou raster do serviço de renderização do Azure Maps com o SDK da Web, você pode substituir atlas.microsoft.com pelo espaço reservado azmapsdomain.invalid. Esse espaço reservado será substituído pelo mesmo domínio usado pelo mapa e também acrescentará automaticamente os mesmos detalhes de autenticação. Isso simplifica muito a autenticação com o serviço de renderização ao usar a autenticação do Microsoft Entra.

Para exibir dados de uma fonte de bloco vetorial no mapa, conecte a fonte a uma das camadas de renderização de dados. Todas as camadas que usam uma fonte de vetor devem especificar um sourceLayer valor nas opções. O código a seguir carrega o serviço de bloco de vetor de fluxo de tráfego do Azure Maps como uma fonte de bloco vetorial e, em seguida, o exibe em um mapa usando uma camada de linha. Esta fonte de mosaico vetorial tem um único conjunto de dados na camada de origem chamado "Fluxo de tráfego". Os dados de linha neste conjunto de dados tem uma propriedade chamada traffic_level que é usada neste código para selecionar a cor e dimensionar o tamanho das linhas.

//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")

Mapa com linhas rodoviárias codificadas por cores mostrando os níveis de fluxo de tráfego

Conectando uma fonte de dados a uma camada

Os dados são renderizados no mapa usando camadas de renderização. Uma ou mais camadas de renderização podem fazer referência a uma única fonte de dados. As seguintes camadas de renderização exigem uma fonte de dados:

  • Camada de bolhas - renderiza dados de pontos como círculos dimensionados no mapa.
  • Camada de símbolos- renderiza dados de pontos como ícones ou texto.
  • Camada de mapa de calor - renderiza dados de pontos como um mapa de calor de densidade.
  • Camada de linha - renderiza uma linha e/ou renderiza o contorno de polígonos.
  • Camada de polígono - preenche a área de um polígono com uma cor sólida ou padrão de imagem.

O código a seguir mostra como criar uma fonte de dados, adicioná-la ao mapa e conectá-la a uma camada de bolhas. E, em seguida, importe dados de ponto GeoJSON de um local remoto para a fonte de dados.

//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)

Há mais camadas de renderização que não se conectam a essas fontes de dados, mas carregam diretamente os dados para renderização.

  • Camada de mosaico - sobrepõe uma camada de mosaico raster no topo do mapa.

Uma fonte de dados com várias camadas

Várias camadas podem ser conectadas a uma única fonte de dados. Existem muitos cenários diferentes em que esta opção é útil. Por exemplo, considere o cenário no qual um usuário desenha um polígono. Devemos renderizar e preencher a área do polígono à medida que o usuário adiciona pontos ao mapa. Adicionar uma linha estilizada para delinear o polígono torna mais fácil ver as bordas do polígono, à medida que o usuário desenha. Para editar convenientemente uma posição individual no polígono, podemos adicionar uma alça, como um pino ou um marcador, acima de cada posição.

Mapa mostrando várias camadas renderizando dados de uma única fonte de dados

Na maioria das plataformas de mapeamento, você precisaria de um objeto de polígono, um objeto de linha e um pino para cada posição no polígono. À medida que o polígono é modificado, você precisa atualizar manualmente a linha e os pinos, que podem se tornar complexos rapidamente.

Com o Azure Maps, tudo o que você precisa é de um único polígono em uma fonte de dados, conforme mostrado no código a seguir.

//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))

Gorjeta

Ao adicionar camadas ao mapa usando o map.layers.add método, a ID ou instância de uma camada existente pode ser passada como um segundo parâmetro. Isso daria a esse mapa para inserir a nova camada que está sendo adicionada abaixo da camada existente. Além de passar um ID de camada, esse método também suporta os seguintes valores.

  • "labels" - Insere a nova camada abaixo das camadas do rótulo do mapa.
  • "transit" - Insere a nova camada abaixo das camadas de estrada e trânsito do mapa.

Próximos passos

Consulte os seguintes artigos para obter mais exemplos de código para adicionar aos seus mapas: