Partager via


Clustering de données de point dans le kit iOS SDK (préversion)

Remarque

Mise hors service du kit de développement logiciel (SDK) iOS Azure Maps

Le Kit de développement logiciel (SDK) natif Azure Maps pour iOS est désormais déconseillé et sera mis hors service le 31 mars 2025. Pour éviter toute interruption de service, nous vous recommandons de migrer vers le kit de développement logiciel (SDK) web Azure Maps avant le 31 mars 2025. Pour plus d’informations, consultez le Guide de migration du kit de développement logiciel (SDK) iOS Azure Maps.

Lorsque vous affichez de nombreux points de données sur la carte, ceux-ci peuvent se chevaucher. Le chevauchement peut rendre la carte illisible et difficile à utiliser. Le clustering de point de données est le processus permettant de combiner des données de point proches les unes des autres et de les représenter sur une carte en tant qu’un point de données en cluster unique. Lorsque l’utilisateur effectue un zoom avant sur la carte, les clusters se décomposent pour afficher les points de données individuels qui les composent. Quand vous travaillez avec un grand nombre de points de données, utilisez les processus de clustering pour améliorer l’expérience de vos utilisateurs.

Internet des objets - Clustering de données de point dans Azure Maps

Prérequis

Veillez à suivre la procédure du document Démarrage rapide : Créer une application iOS. Les blocs de code de cet article peuvent être insérés dans la fonction viewDidLoad de ViewController.

Activer le clustering sur une source de données

Activez le clustering dans la classe DataSource en définissant l’option cluster sur true. Définissez la valeur clusterRadius pour sélectionner des points de données à proximité et les combiner dans un cluster. La valeur de clusterRadius est en points. Utilisez clusterMaxZoom pour spécifier un niveau de zoom auquel désactiver la logique de clustering. Voici un exemple montrant comment activer le clustering dans une source de données.

// Create a data source and enable clustering.
let source = DataSource(options: [
    //Tell the data source to cluster point data.
    .cluster(true),

    //The radius in points to cluster data points together.
    .clusterRadius(45),

    //The maximum zoom level in which clustering occurs.
    //If you zoom in more than this, all points are rendered as symbols.
    .clusterMaxZoom(15)
])

Attention

Le clustering fonctionne uniquement avec les fonctionnalités Point. Si votre source de données contient des fonctionnalités d’autres types de géométrie, tels que Polyline ou Polygon, une erreur se produit.

Conseil

Si deux points de données sont proches l’un de l’autre sur le sol, il est possible que le cluster ne se décompose jamais, quelle que soit l’importance du zoom avant effectué par l’utilisateur. Pour résoudre ce problème, vous pouvez définir l’option clusterMaxZoom de façon à désactiver la logique de clustering et à simplement afficher tous les éléments.

La classe DataSource fournit également les méthodes relatives au clustering suivantes.

Méthode Type de retour Description
children(of cluster: Feature) [Feature] Récupère les enfants du cluster donné sur le niveau de zoom suivant. Ces enfants peuvent être une combinaison de fonctionnalités et sous-clusters. Les sous-clusters deviennent des fonctionnalités dont les propriétés correspondent à ClusteredProperties.
zoomLevel(forExpanding cluster: Feature) Double Calcule un niveau de zoom à partir duquel le cluster commence à se développer ou à se décomposer.
leaves(of cluster: Feature, offset: UInt, limit: UInt) [Feature] Récupère tous les points dans un cluster. Définissez le paramètre limit de manière à renvoyer un sous-ensemble des points et utilisez offset pour parcourir les points.

Afficher les clusters à l’aide d’une couche de bulles

Un calque de bulles est un bon moyen de rendre des points de données regroupés en cluster. Utilisez des expressions pour mettre à l’échelle le rayon et changer la couleur en fonction du nombre de points du cluster. Si vous affichez des clusters sous la forme d’un calque de bulles, vous devez également utiliser un calque distinct pour rendre les points de données non regroupés dans le cluster.

Pour afficher la taille du cluster en haut de la bulle, utilisez un calque de symboles avec du texte, et n’utilisez pas une icône.

Le code suivant affiche des points en cluster à l’aide d’un calque de bulles et le nombre de points dans chaque cluster à l’aide d’un calque de symboles. Un deuxième calque de symboles est utilisé pour afficher des points individuels qui ne se trouvent pas dans un cluster.

// Create a data source and enable clustering.
let source = DataSource(options: [
    // Tell the data source to cluster point data.
    .cluster(true),

    // The radius in points to cluster data points together.
    .clusterRadius(45),

    // The maximum zoom level in which clustering occurs.
    // If you zoom in more than this, all points are rendered as symbols.
    .clusterMaxZoom(15)
])

// Import the geojson data and add it to the data source.
let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")!
source.importData(fromURL: url)

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

// Create a bubble layer for rendering clustered data points.
map.layers.addLayer(
    BubbleLayer(
        source: source,
        options: [
            // Scale the size of the clustered bubble based on the number of points in the cluster.
            .bubbleRadius(
                from: NSExpression(
                    forAZMStepping: NSExpression(forKeyPath: "point_count"),
                    // Default of 20 point radius.
                    from: NSExpression(forConstantValue: 20),
                    stops: NSExpression(forConstantValue: [

                        // If point_count >= 100, radius is 30 points.
                        100: 30,

                        // If point_count >= 750, radius is 40 points.
                        750: 40
                    ])
                )
            ),

            // Change the color of the cluster based on the value on the point_count property of the cluster.
            .bubbleColor(
                from: NSExpression(
                    forAZMStepping: NSExpression(forKeyPath: "point_count"),
                    // Default to green.
                    from: NSExpression(forConstantValue: UIColor.green),
                    stops: NSExpression(forConstantValue: [

                        // If the point_count >= 100, color is yellow.
                        100: UIColor.yellow,

                        // If the point_count >= 100, color is red.
                        750: UIColor.red
                    ])
                )
            ),
            .bubbleStrokeWidth(0),

            // Only rendered data points which have a point_count property, which clusters do.
            .filter(from: NSPredicate(format: "point_count != NIL"))
        ]
    )
)

// Create a symbol layer to render the count of locations in a cluster.
map.layers.addLayer(
    SymbolLayer(
        source: source,
        options: [
            // Hide the icon image.
            .iconImage(nil),

            // Display the point count as text.
            .textField(from: NSExpression(forKeyPath: "point_count")),
            .textOffset(CGVector(dx: 0, dy: 0.4)),
            .textAllowOverlap(true),

            // Allow clustered points in this layer.
            .filter(from: NSPredicate(format: "point_count != NIL"))
        ]
    )
)

// Create a layer to render the individual locations.
map.layers.addLayer(
    SymbolLayer(
        source: source,
        options: [
            // Filter out clustered points from this layer.
            .filter(from: NSPredicate(format: "point_count = NIL"))
        ]
    )
)

L’illustration suivante montre le code ci-dessus qui affiche les fonctionnalités de point en cluster dans un calque de bulles, mises à l’échelle et colorées en fonction du nombre de points du cluster. Les points non mis en cluster sont affichés à l’aide d’un calque de symboles.

Décomposition des emplacements en cluster sur la carte lors d’un zoom sur celle-ci.

Afficher les clusters à l’aide d’une couche de symboles

Lorsque vous affichez des points de données, le calque de symboles masque automatiquement les symboles qui se chevauchent pour garantir une interface utilisateur plus propre. Ce comportement par défaut peut être indésirable si vous voulez montrer la densité des points de données sur la carte. Ces paramètres peuvent cependant être modifiés. Pour afficher tous les symboles, définissez l’option iconAllowOverlap du calque de symboles sur true.

Utilisez le clustering pour montrer la densité des points de données tout en conservant une interface utilisateur propre. L’exemple suivant montre comment ajouter des symboles personnalisés, et comment représenter des clusters et des points de données individuels en utilisant le calque de symboles.

// Load all the custom image icons into the map resources.
map.images.add(UIImage(named: "earthquake_icon")!, withID: "earthquake_icon")
map.images.add(UIImage(named: "warning-triangle-icon")!, withID: "warning-triangle-icon")

// Create a data source and add it to the map.
let source = DataSource(options: [
    // Tell the data source to cluster point data.
    .cluster(true)
])

// Import the geojson data and add it to the data source.
let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")!
source.importData(fromURL: url)

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

// Create a layer to render the individual locations.
map.layers.addLayer(
    SymbolLayer(
        source: source,
        options: [
            .iconImage("earthquake_icon"),

            // Filter out clustered points from this layer.
            .filter(from: NSPredicate(format: "point_count = NIL"))
        ]
    )
)

// Create a symbol layer to render the clusters.
map.layers.addLayer(
    SymbolLayer(
        source: source,
        options: [
            .iconImage("warning-triangle-icon"),
            .textField(from: NSExpression(forKeyPath: "point_count")),
            .textOffset(CGVector(dx: 0, dy: -0.4)),

            // Allow clustered points in this layer.
            .filter(from: NSPredicate(format: "point_count != NIL"))
        ]
    )
)

Pour cet exemple, l’image suivante a été chargée dans le dossier assets de l’application.

Image d’icône de tremblement de terre Image d’icône météo d’averse
earthquake-icon.png warning-triangle-icon.png

L’illustration suivante montre le code ci-dessus qui restitue les fonctionnalités de point en cluster et non-cluster à l’aide d’icônes personnalisées.

Carte de points en cluster affichés à l’aide d’un calque de symboles.

Clustering et couche de carte thermique

Les cartes thermiques sont un excellent moyen pour afficher la densité des données sur la carte. Cette méthode de visualisation peut gérer par elle-même un grand nombre de points de données. Si les points de données sont en cluster et que la taille du cluster est utilisée comme pondération de la carte thermique, la carte thermique peut traiter encore plus de données. Pour cela, définissez l’option heatmapWeight du calque de la carte thermique sur NSExpression(forKeyPath: "point_count"). Quand le rayon du cluster est faible, la carte thermique ressemble fortement à une carte thermique utilisant des points de données qui ne sont pas mis en cluster, tout en étant beaucoup plus performante. Toutefois, plus le rayon du cluster est petit, plus la carte thermique est précise, mais avec moins de bénéfices en termes de performances.

// Create a data source and enable clustering.
let source = DataSource(options: [
    // Tell the data source to cluster point data.
    .cluster(true),

    // The radius in points to cluster points together.
    .clusterRadius(10)
])

// Import the geojson data and add it to the data source.
let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")!
source.importData(fromURL: url)

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

// Create a heat map and add it to the map.
map.layers.insertLayer(
    HeatMapLayer(
        source: source,
        options: [
            // Set the weight to the point_count property of the data points.
            .heatmapWeight(from: NSExpression(forKeyPath: "point_count")),

            // Optionally adjust the radius of each heat point.
            .heatmapRadius(20)
        ]
    ),
    below: "labels"
)

L’illustration suivante montre le code ci-dessus affichant une carte thermique optimisée à l’aide des fonctionnalités de points en cluster et du nombre de clusters en tant que poids dans la carte thermique.

Carte thermique optimisée en utilisant des points en cluster comme poids.

Événements de pression sur des points de données en cluster

Quand des événements de pression se produisent sur un calque contenant des points de données en cluster, le point de données en cluster est retourné à l’événement en tant qu’objet de fonctionnalité de point GeoJSON. Cette fonctionnalité de point possède les propriétés suivantes :

Nom de la propriété Type Description
cluster boolean Indique si la fonctionnalité représente un cluster.
point_count nombre Le nombre de points que contient le cluster.
point_count_abbreviated string Une chaîne qui abrège la valeur de point_count si elle est trop longue. (par exemple, 4 000 devient 4K)

Cet exemple prend un calque de bulles qui affiche des points de cluster et ajoute un événement de pression. Quand l’événement de pression est déclenché, le code calcule et effectue un zoom de la carte au niveau de zoom suivant, à partir duquel le cluster se décompose. Cette fonctionnalité est implémentée à l’aide de la méthode zoomLevel(forExpanding:) de la classe DataSource.

// Create a data source and enable clustering.
let source = DataSource(options: [
    // Tell the data source to cluster point data.
    .cluster(true),

    // The radius in points to cluster data points together.
    .clusterRadius(45),

    // The maximum zoom level in which clustering occurs.
    // If you zoom in more than this, all points are rendered as symbols.
    .clusterMaxZoom(15)
])

// Set data source to the class property to use in events handling later.
self.source = source

// Import the geojson data and add it to the data source.
let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")!
source.importData(fromURL: url)

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

// Create a bubble layer for rendering clustered data points.
let clusterBubbleLayer = BubbleLayer(
    source: source,
    options: [
        // Scale the size of the clustered bubble based on the number of points in the cluster.
        .bubbleRadius(
            from: NSExpression(
                forAZMStepping: NSExpression(forKeyPath: "point_count"),
                // Default of 20 point radius.
                from: NSExpression(forConstantValue: 20),
                stops: NSExpression(forConstantValue: [
                    // If point_count >= 100, radius is 30 points.
                    100: 30,

                    // If point_count >= 750, radius is 40 points.
                    750: 40
                ])
            )
        ),

        // Change the color of the cluster based on the value on the point_count property of the cluster.
        .bubbleColor(
            from: NSExpression(
                forAZMStepping: NSExpression(forKeyPath: "point_count"),
                // Default to green.
                from: NSExpression(forConstantValue: UIColor.green),
                stops: NSExpression(forConstantValue: [
                    // If the point_count >= 100, color is yellow.
                    100: UIColor.yellow,

                    // If the point_count >= 100, color is red.
                    750: UIColor.red
                ])
            )
        ),
        .bubbleStrokeWidth(0),

        // Only rendered data points which have a point_count property, which clusters do.
        .filter(from: NSPredicate(format: "point_count != NIL"))
    ]
)

// Add the clusterBubbleLayer to the map.
map.layers.addLayer(clusterBubbleLayer)

// Create a symbol layer to render the count of locations in a cluster.
map.layers.addLayer(
    SymbolLayer(
        source: source,
        options: [
            // Hide the icon image.
            .iconImage(nil),

            // Display the point count as text.
            .textField(from: NSExpression(forKeyPath: "point_count_abbreviated")),

            // Offset the text position so that it's centered nicely.
            .textOffset(CGVector(dx: 0, dy: 0.4)),

            // Allow text overlapping so text is visible anyway
            .textAllowOverlap(true),

            // Allow clustered points in this layer.
            .filter(from: NSPredicate(format: "point_count != NIL"))
        ]
    )
)

// Create a layer to render the individual locations.
map.layers.addLayer(
    SymbolLayer(
        source: source,
        options: [
            // Filter out clustered points from this layer.
            .filter(from: NSPredicate(format: "point_count = NIL"))
        ]
    )
)

// Add the delegate to handle taps on the clusterBubbleLayer only.
map.events.addDelegate(self, for: [clusterBubbleLayer.id])
func azureMap(_ map: AzureMap, didTapOn features: [Feature]) {
    guard let source = source, let cluster = features.first else {
        // Data source have been released or no features provided
        return
    }

    // Get the cluster expansion zoom level. This is the zoom level at which the cluster starts to break apart.
    let expansionZoom = source.zoomLevel(forExpanding: cluster)

    // Update the map camera to be centered over the cluster.
    map.setCameraOptions([
        // Center the map over the cluster points location.
        .center(cluster.coordinate),

        // Zoom to the clusters expansion zoom level.
        .zoom(expansionZoom),

        // Animate the movement of the camera to the new position.
        .animationType(.ease),
        .animationDuration(200)
    ])
}

L’illustration suivante montre le code ci-dessus qui affiche des points en cluster sur une carte qui, lorsque vous appuyez dessus, effectue un zoom avant sur le niveau de zoom suivant et commence à décomposer et développer le cluster.

Carte de fonctionnalités en cluster avec zoom avant et décomposition après pression.

Afficher la zone du cluster

Les données de point représentées par un cluster sont réparties sur une zone. Dans cet exemple, lorsqu’un cluster est touché, deux comportements principaux se produisent. D’abord, les points de données individuels contenus dans le cluster sont utilisés pour calculer une enveloppe convexe. Ensuite, l’enveloppe convexe est affichée sur la carte pour montrer une zone. Une enveloppe convexe est un polygone qui entoure un ensemble de points comme un élastique et qui peut être calculé à l’aide de la méthode convexHull(from:). Tous les points contenus dans un cluster peuvent être récupérés à partir de la source de données à l’aide de la méthode leaves(of:offset:limit:).

// Create a data source and enable clustering.
let source = DataSource(options: [
    // Tell the data source to cluster point data.
    .cluster(true)
])

// Set data source to the class property to use in events handling later.
self.source = source

// Import the geojson data and add it to the data source.
let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")!
source.importData(fromURL: url)

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

// Create a data source for the convex hull polygon.
// Since this will be updated frequently it is more efficient to separate this into its own data source.
let polygonDataSource = DataSource()

// Set polygon data source to the class property to use in events handling later.
self.polygonDataSource = polygonDataSource

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

// Add a polygon layer and a line layer to display the convex hull.
map.layers.addLayer(PolygonLayer(source: polygonDataSource))
map.layers.addLayer(LineLayer(source: polygonDataSource))

// Load an icon into the image sprite of the map.
map.images.add(.azm_markerRed, withID: "marker-red")

// Create a symbol layer to render the clusters.
let clusterLayer = SymbolLayer(
    source: source,
    options: [
        .iconImage("marker-red"),
        .textField(from: NSExpression(forKeyPath: "point_count_abbreviated")),
        .textOffset(CGVector(dx: 0, dy: -1.2)),
        .textColor(.white),
        .textSize(14),

        // Only rendered data points which have a point_count property, which clusters do.
        .filter(from: NSPredicate(format: "point_count != NIL"))
    ]
)

// Add the clusterLayer to the map.
map.layers.addLayer(clusterLayer)

// Create a layer to render the individual locations.
map.layers.addLayer(
    SymbolLayer(
        source: source,
        options: [
            // Filter out clustered points from this layer.
            .filter(from: NSPredicate(format: "point_count = NIL"))
        ]
    )
)

// Add the delegate to handle taps on the clusterLayer only
// and then calculate the convex hull of all the points within a cluster.
map.events.addDelegate(self, for: [clusterLayer.id])
func azureMap(_ map: AzureMap, didTapOn features: [Feature]) {
    guard let source = source, let polygonDataSource = polygonDataSource, let cluster = features.first else {
        // Data source have been released or no features provided
        return
    }

    // Get all points in the cluster. Set the offset to 0 and the max int value to return all points.
    let featureLeaves = source.leaves(of: cluster, offset: 0, limit: .max)

    // When only two points in a cluster. Render a line.
    if featureLeaves.count == 2 {

        // Extract the locations from the feature leaves.
        let locations = featureLeaves.map(\.coordinate)

        // Create a line from the points.
        polygonDataSource.set(geometry: Polyline(locations))

        return
    }

    // When more than two points in a cluster. Render a polygon.
    if let hullPolygon = Math.convexHull(from: featureLeaves) {

        // Overwrite all data in the polygon data source with the newly calculated convex hull polygon.
        polygonDataSource.set(geometry: hullPolygon)
    }
}

L’illustration suivante montre le code ci-dessus qui affiche la zone de tous les points figurant dans le cluster qui a fait l’objet d’une pression.

Carte présentant un polygone d’enveloppe convexe de tous les points figurant dans le cluster qui a fait l’objet d’une pression.

Agrégation de données dans des clusters

Souvent, les clusters sont représentés à l’aide d’un symbole avec le nombre de points qui se trouvent dans le cluster. Cependant, il est parfois souhaitable de pouvoir personnaliser le style des clusters avec des métriques supplémentaires. Avec les propriétés de cluster, des propriétés personnalisées peuvent être créées et égales à un calcul basé sur les propriétés de chaque point avec un cluster. Les propriétés de cluster peuvent être définies dans l’option clusterProperties de DataSource.

Le code suivant calcule un nombre basé sur la propriété du type d’entité de chaque point de données dans un cluster. Quand un utilisateur appuie sur un cluster, une fenêtre contextuelle s’affiche avec des informations supplémentaires sur le cluster.

// Create a popup and add it to the map.
let popup = Popup()
map.popups.add(popup)

// Set popup to the class property to use in events handling later.
self.popup = popup

// Close the popup initially.
popup.close()

// Create a data source and enable clustering.
let source = DataSource(options: [
    // Tell the data source to cluster point data.
    .cluster(true),

    // The radius in points to cluster data points together.
    .clusterRadius(50),

    // Calculate counts for each entity type in a cluster as custom aggregate properties.
    .clusterProperties(self.entityTypes.map { entityType in
        ClusterProperty(
            name: entityType,
            operator: NSExpression(
                forFunction: "sum:",
                arguments: [
                    NSExpression.featureAccumulatedAZMVariable,
                    NSExpression(forKeyPath: entityType)
                ]
            ),
            map: NSExpression(
                forConditional: NSPredicate(format: "EntityType = '\(entityType)'"),
                trueExpression: NSExpression(forConstantValue: 1),
                falseExpression: NSExpression(forConstantValue: 0)
            )
        )
    })
])

// Import the geojson data and add it to the data source.
let url = URL(string: "https://samples.azuremaps.com/data/geojson/SamplePoiDataSet.json")!
source.importData(fromURL: url)

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

// Create a bubble layer for rendering clustered data points.
let clusterBubbleLayer = BubbleLayer(
    source: source,
    options: [
        .bubbleRadius(20),
        .bubbleColor(.purple),
        .bubbleStrokeWidth(0),

        // Only rendered data points which have a point_count property, which clusters do.
        .filter(from: NSPredicate(format: "point_count != NIL"))
    ]
)

// Add the clusterBubbleLayer to the map.
map.layers.addLayer(clusterBubbleLayer)

// Create a symbol layer to render the count of locations in a cluster.
map.layers.addLayer(
    SymbolLayer(
        source: source,
        options: [
            // Hide the icon image.
            .iconImage(nil),

            // Display the 'point_count_abbreviated' property value.
            .textField(from: NSExpression(forKeyPath: "point_count_abbreviated")),

            .textColor(.white),
            .textOffset(CGVector(dx: 0, dy: 0.4)),

            // Allow text overlapping so text is visible anyway
            .textAllowOverlap(true),

            // Only rendered data points which have a point_count property, which clusters do.
            .filter(from: NSPredicate(format: "point_count != NIL"))
        ]
    )
)

// Create a layer to render the individual locations.
map.layers.addLayer(
    SymbolLayer(
        source: source,
        options: [
            // Filter out clustered points from this layer.
            SymbolLayerOptions.filter(from: NSPredicate(format: "point_count = NIL"))
        ]
    )
)

// Add the delegate to handle taps on the clusterBubbleLayer only
// and display the aggregate details of the cluster.
map.events.addDelegate(self, for: [clusterBubbleLayer.id])
func azureMap(_ map: AzureMap, didTapOn features: [Feature]) {
    guard let popup = popup, let cluster = features.first else {
        // Popup has been released or no features provided
        return
    }

    // Create a number formatter that removes decimal places.
    let nf = NumberFormatter()
    nf.maximumFractionDigits = 0

    // Create the popup's content.
    var text = ""

    let pointCount = cluster.properties["point_count"] as! Int
    let pointCountString = nf.string(from: pointCount as NSNumber)!

    text.append("Cluster size: \(pointCountString) entities\n")

    entityTypes.forEach { entityType in
        text.append("\n")
        text.append("\(entityType): ")

        // Get the aggregated entity type count from the properties of the cluster by name.
        let aggregatedCount = cluster.properties[entityType] as! Int
        let aggregatedCountString = nf.string(from: aggregatedCount as NSNumber)!

        text.append(aggregatedCountString)
    }

    // Create the custom view for the popup.
    let customView = PopupTextView()

    // Set the text to the custom view.
    customView.setText(text)

    // Get the position of the cluster.
    let position = Math.positions(from: cluster).first!

    // Set the options on the popup.
    popup.setOptions([
        // Set the popups position.
        .position(position),

        // Set the anchor point of the popup content.
        .anchor(.bottom),

        // Set the content of the popup.
        .content(customView)
    ])

    // Open the popup.
    popup.open()
}

La fenêtre contextuelle suit les étapes décrites dans le document Afficher une fenêtre contextuelle.

L’image suivante montre le code ci-dessus qui affiche une fenêtre contextuelle avec des nombres agrégés de chaque type de valeur d’entité pour tous les points du point de cluster qui a fait l’objet d’une pression.

Carte affichant une fenêtre contextuelle des nombres agrégés des types d’entité de tous les points d’un cluster.

Informations supplémentaires

Pour ajouter des données à votre carte :