Tworzenie źródła danych (Android SDK)

W Azure Maps Android SDK dane są przechowywane w źródłach danych. Użycie źródeł danych optymalizuje operacje na danych pod kątem wykonywania zapytań i renderowania. Obecnie istnieją dwa typy źródeł danych:

  • Źródło GeoJSON: zarządza nieprzetworzoną lokalizacją lokalnie w formacie GeoJSON. Dobra w przypadku małych i średnich zestawów danych (w górę setek tysięcy kształtów).
  • Źródło kafelka wektorowego: ładuje dane sformatowane jako kafelki wektorowe dla bieżącego widoku mapy na podstawie systemu kafelków map. Idealne rozwiązanie w przypadku dużych i ogromnych zestawów danych (miliony lub miliardy kształtów).

Źródło danych GeoJSON

Azure Maps korzysta z danych GeoJSON jako jednego z podstawowych modeli danych. GeoJSON to otwarty standardowy sposób reprezentowania danych geoprzestrzennych w formacie JSON. Klasy GeoJSON dostępne w interfejsie Azure Maps Android SDK łatwe tworzenie i serializowanie danych GeoJSON. Ładowanie i przechowywanie danych GeoJSON w DataSource klasie oraz renderowanie ich przy użyciu warstw. Poniższy kod pokazuje, jak można tworzyć obiekty GeoJSON w 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)

Alternatywnie właściwości można najpierw załadować do obiektu JsonObject, a następnie do funkcji podczas jej tworzenia, jak pokazano poniżej.

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

Po utworzeniu funkcji GeoJSON można dodać źródło danych do mapy za pośrednictwem sources właściwości mapy. Poniższy kod pokazuje, jak utworzyć obiekt , dodać go do mapy i DataSource dodać funkcję do źródła danych.

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

Poniższy kod przedstawia kilka sposobów tworzenia funkcji GeoJSON, obiektu FeatureCollection i geometrii.

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

Serializowanie i deserializowanie danych GeoJSON

Wszystkie klasy kolekcji cech, cech i geometrii mają metody statyczne i fromJson() toJson() , które ułatwiają serializację. Sformatowany prawidłowy ciąg JSON przekazany przez fromJson() metodę spowoduje utworzenie obiektu geometrii. Ta fromJson() metoda oznacza również, że można użyć Gson lub innych strategii serializacji/deserializacji. Poniższy kod pokazuje, jak wykonać ciągizoną funkcję GeoJSON i deserializować ją do klasy Feature, a następnie serializować ją z powrotem do ciągu 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()

Importowanie danych GeoJSON z folderu web lub assets

Większość plików GeoJSON zawiera element FeatureCollection. Odczytaj pliki GeoJSON jako ciągi i zdeserializuj je za FeatureCollection.fromJson pomocą metody .

Poniższy kod to klasa wielokrotnego użytku do importowania danych z internetowego lub lokalnego folderu assets jako ciągu i zwracania ich do wątku interfejsu użytkownika za pośrednictwem funkcji wywołania zwrotnego.

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

Poniższy kod pokazuje, jak używać tego narzędzia do importowania danych GeoJSON jako ciągu i zwracania ich do wątku interfejsu użytkownika za pośrednictwem wywołania zwrotnego. W wywołaniu zwrotowym dane ciągu mogą być serializowane do kolekcji funkcji GeoJSON i dodawane do źródła danych. Opcjonalnie zaktualizuj kamerę mapy, aby skoncentrować się na danych.

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

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

Źródło kafelka wektorowego

Źródło kafelka wektorowego opisuje sposób uzyskiwania dostępu do warstwy kafelka wektorowego. Użyj klasy VectorTileSource , aby utworzyć wystąpienia źródła kafelka wektorowego. Warstwy kafelków wektorowych są podobne do warstw kafelków, ale nie są takie same. Warstwa kafelka to obraz rastrowy. Warstwy kafelków wektorowych są skompresowanym plikiem w formacie PBF. Ten skompresowany plik zawiera dane mapy wektorowej i co najmniej jedną warstwę. Plik można renderować i styliować na kliencie na podstawie stylu każdej warstwy. Dane na kafelku wektorowym zawierają cechy geograficzne w postaci punktów, linii i wielokątów. Używanie warstw kafelków wektorowych zamiast warstw kafelek rastrowych ma kilka zalet:

  • Rozmiar pliku kafelka wektorowego jest zwykle znacznie mniejszy niż równoważny kafelek rastrowy. W związku z tym używana jest mniejsza przepustowość. Oznacza to mniejsze opóźnienie, szybsze mapowanie i lepsze środowisko użytkownika.
  • Ponieważ kafelki wektorowe są renderowane na kliencie, dostosowują się do rozdzielczości urządzenia, na których są wyświetlane. W związku z tym renderowane mapy wyglądają na bardziej dobrze zdefiniowane z etykietami z przezroczystym przezroczystym przezroczystym obrazem.
  • Zmiana stylu danych w mapach wektorowych nie wymaga ponownego pobrania danych, ponieważ nowy styl można zastosować na kliencie. Natomiast zmiana stylu warstwy kafelka rastrowego zwykle wymaga załadowania kafelków z serwera, a następnie zastosowania nowego stylu.
  • Ponieważ dane są dostarczane w postaci wektorowej, do ich przygotowania jest mniej przetwarzania po stronie serwera. W związku z tym nowsze dane mogą być udostępniane szybciej.

Azure Maps jest zgodna ze specyfikacją mapbox vector tile (specyfikacjaotwartego standardu). Azure Maps udostępnia następujące usługi kafelków wektorowych w ramach platformy:

Porada

W przypadku używania kafelków obrazu wektorowego lub rastrowego z Azure Maps renderowania przy użyciu internetowego zestawu SDK można zastąpić element atlas.microsoft.com symbolem zastępczym azmapsdomain.invalid . Ten symbol zastępczy zostanie zastąpiony tą samą domeną, która jest używana przez mapę, i automatycznie dołączy te same szczegóły uwierzytelniania. Znacznie upraszcza to uwierzytelnianie za pomocą usługi renderowania podczas korzystania Azure Active Directory uwierzytelniania.

Aby wyświetlić dane ze źródła kafelka wektorowego na mapie, połącz źródło z jedną z warstw renderowania danych. Wszystkie warstwy, które używają źródła wektora, muszą sourceLayer określać wartość w opcjach. Poniższy kod ładuje usługę Azure Maps kafelka wektorowego przepływu ruchu jako źródło kafelka wektorowego, a następnie wyświetla go na mapie przy użyciu warstwy liniowej. To źródło kafelka wektorowego zawiera jeden zestaw danych w warstwie źródłowej o nazwie "Przepływ ruchu". Dane liniowe w tym zestawie danych mają właściwość o nazwie , która jest używana w tym kodzie do wybierania koloru i traffic_level skalowania rozmiaru wierszy.

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

Mapowanie za pomocą kolorowych linii kierunkowych przedstawiających poziomy przepływu ruchu

Łączenie źródła danych z warstwą

Dane są renderowane na mapie przy użyciu warstw renderowania. Do pojedynczego źródła danych może odwoływać się co najmniej jedna warstwa renderowania. Następujące warstwy renderowania wymagają źródła danych:

Poniższy kod pokazuje, jak utworzyć źródło danych, dodać je do mapy i połączyć z warstwą bąbelkową. Następnie zaimportuj dane punktu GeoJSON ze zdalnej lokalizacji do źródła danych.

//Create a data source and add it to the map.
DataSource source = new DataSource();
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);

//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.
        dataSource.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.
val source = DataSource()
map.sources.add(source)

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

//Import the geojson data and add it to the data source.
Utils.importData("URL_or_FilePath_to_GeoJSON_data", this) { 
    result: String? ->
        //Parse the data as a GeoJSON Feature Collection.
        val fc = FeatureCollection.fromJson(result!!)

        //Add the feature collection to the data source.
        dataSource.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(20)
        )
    }

Istnieją dodatkowe warstwy renderowania, które nie łączą się z tymi źródłami danych, ale bezpośrednio ładują dane do renderowania.

Jedno źródło danych z wieloma warstwami

Z pojedynczym źródłem danych można podłączyć wiele warstw. Istnieje wiele różnych scenariuszy, w których ta opcja jest przydatna. Rozważmy na przykład scenariusz, w którym użytkownik rysuje wielokąt. Obszar wielokąta powinien być renderowany i wypełniany, gdy użytkownik doda punkty do mapy. Dodanie linii w stylu w celu konturu wielokąta ułatwia wyświetlanie krawędzi wielokąta, gdy użytkownik rysuje. Aby wygodnie edytować pojedyncze położenie wielokąta, możemy dodać uchwyt, taki jak pinezkę lub znacznik, nad każdą pozycją.

Mapa przedstawiająca wiele warstw renderujących dane z jednego źródła danych

Na większości platform mapowania potrzebujesz obiektu wielokąta, obiektu liniowego i pinezki dla każdej pozycji wielokąta. W przypadku modyfikacji wielokąta należy ręcznie zaktualizować linię i pinezki, co może szybko stać się złożone.

W Azure Maps wystarczy jeden wielokąt w źródle danych, jak pokazano w poniższym kodzie.

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

Porada

Podczas dodawania warstw do mapy przy użyciu metody identyfikator lub wystąpienie istniejącej warstwy może zostać przekazane map.layers.add jako drugi parametr. Dzięki temu mapa zostanie wstawiła nową warstwę, która zostanie dodana poniżej istniejącej warstwy. Oprócz przekazywania identyfikatora warstwy ta metoda obsługuje również następujące wartości.

  • "labels" — Wstawia nową warstwę poniżej warstw etykiet mapy.
  • "transit" — Wstawia nową warstwę poniżej warstwy drogi i tranzytu mapy.

Następne kroki

Więcej przykładów kodu do dodania do map można znaleźć w następujących artykułach: