Search code examples
androidmapboxmapbox-android

How to control the z axis of individual Mapbox features inside the same layer?


I'm using the Mapbox Maps SDK for Android to display pins with custom icons in a map on my app. More specifically, I'm using the SymbolLayer API. When the user clicks on a pin, its appearance changes to show it is selected. However, that clicked pin is often behind other pins, like in this image: enter image description here

All those pins are Features from the same Source, added to the same SymbolLayer.

I want to be able to make the selected pin appear above the other pins, and for that I'm trying to control its z axis. I'm playing around with the PropertyFactory.symbolZOrder(value) method and it seems that neither Property.SYMBOL_Z_ORDER_VIEWPORT_Y nor Property.SYMBOL_Z_ORDER_SOURCE will be of help. I'm hopeful that I will be able to achieve that with an Expression but I have no idea on how to use it.

Any thoughts?


Solution

  • here's an example with explanations. You should set the properties symbolZOrder and symbolSortKey when defining the symbol layer.

    symbolZOrder accept one of the following as argument:

      // SYMBOL_Z_ORDER: Controls the order in which overlapping symbols in the same layer are rendered
    
      /**
       * If symbol sort key is set, sort based on that. Otherwise sort symbols by their y-position relative to the viewport.
       */
      public static final String SYMBOL_Z_ORDER_AUTO = "auto";
      /**
       * Symbols will be sorted by their y-position relative to the viewport.
       */
      public static final String SYMBOL_Z_ORDER_VIEWPORT_Y = "viewport-y";
      /**
       * Symbols will be rendered in the same order as the source data with no sorting applied.
       */
      public static final String SYMBOL_Z_ORDER_SOURCE = "source";
    

    so if you wish to control the symbols based on some logic you should use the SYMBOL_Z_ORDER_AUTO value.

    then you can set the symbolSortKey to some float value.

            Style.OnStyleLoaded onStyleLoaded = style -> {
                style.addLayer(new SymbolLayer(SYMBOLS_LAYER, SYMBOLS_SOURCE)
                        .withProperties(
                                iconImage(step(zoom(),
                                        literal("marker_public_base"),
                                        stop(6, get("icon")))),
                                iconIgnorePlacement(true),
                                iconAllowOverlap(true),
                                iconSize(interpolate(
                                        linear(), zoom(),
                                        stop(0, MARKER_SYMBOL_SIZE * .13),
                                        stop(5, MARKER_SYMBOL_SIZE * .33),
                                        stop(9, MARKER_SYMBOL_SIZE))),
                                iconAnchor(ICON_ANCHOR_BOTTOM),
                                textField(get("title")),
                                textSize(interpolate(
                                        linear(), zoom(),
                                        stop(5.9, 0),
                                        stop(6, SYMBOL_TEXT_SIZE * .4),
                                        stop(7, SYMBOL_TEXT_SIZE * .7),
                                        stop(11, SYMBOL_TEXT_SIZE))),
                                textOptional(true),
                                textHaloColor("#ffffff"),
                                textHaloWidth(1f),
                                textHaloBlur(1f),
                                textAnchor(TEXT_ANCHOR_TOP),
                                symbolZOrder(SYMBOL_Z_ORDER_AUTO),
                                symbolSortKey(get("zIndex"))
                        ));
    

    where

    
                points.forEach(point -> {
                    Feature feature = Feature.fromGeometry(com.mapbox.geojson.Point.fromLngLat(point.lon, point.lat));
                    feature.addStringProperty("id", point.id);
                    feature.addNumberProperty("zIndex", point.isPublic? 0f :  point.isSearchResult? 2f : 1f);
                    feature.addStringProperty("title", point.name);
                    feature.addStringProperty("icon", getIconImageID(point.category, point.isPublic, point.visited));
    
                    symbolsFeatures.add(feature);
                });