1
votes

I'm sure I might be missing something with the Mapbox implementation, since I have been studying so many alternatives (Tangram ES, Mapzen, and other).

I need to display natively on Android thousands (not millions) of interactive points (or markers). I only need to be able to capture which point/marker was clicked.

I succeeded implementing markers on Mapbox for Android. But I dislike the result of having so many markers being displayed when I zoom out the phone.

In Leaflet there's an awesome plugin, called Markercluster, that groups in a circle with a number the hidden markers under it. I found that solution simply perfect.

I couldn't find a similar solution for Mapbox (or other API). So far, the only thing I found that gets closer to what I'm looking for is loading a GeoJSON file on Mapbox. And it's simply nice and easy to do. Easy to hide layers later. But I cannot manage to get to know which Point was clicked so I can load the info related to that point and show it on the screen.

So, briefing, markers lack the look I get with the GeoJSON points (which get hidden as I zoom out or displayed as I zoom in, showing more or less as I do that). However, markers allow me to click over them.

P.S. If anyone knows of an alternative to Mapbox, that allows to display POIs (Points of Interest) as I need, please let me know. I'll more than happy to give it a chance.

1

1 Answers

2
votes

Well, apparently there is a way to do what I intended using the Mapbox for Android SDK. The way is this one:

  1. Load the points (markers) using a GeoJson file (Adding data source)
  2. Include icons for the markers (Mapbox provides a wide range of default markers https://www.mapbox.com/maki-icons/)
  3. Relate the GeoJson points to the icons (so each point is related to at least an icon, could be that you want the same icon for all markers though) (Adding visual representation)
  4. Add an onClick event listener in order to detect which point has been clicked (Adding interactivity)

1.Load the points (markers) using a GeoJson file (Adding data source)

URL geoJsonUrl = new URL("https://your-website.com/list.json");
final GeoJsonSource geoJsonSource = new GeoJsonSource("geojson-source", geoJsonUrl);
mapboxMap.addSource(geoJsonSource);

2.Include icons for the markers (Mapbox provides a wide range of default markers https://www.mapbox.com/maki-icons/) (Adding visual representation)

Bitmap marker_type1_icon = BitmapFactory.decodeResource(getResources(), R.drawable.marker_type1_icon);
mapboxMap.addImage("marker_type1", marker_type1_icon);
Bitmap marker_type2_icon = BitmapFactory.decodeResource(getResources(), R.drawable.marker_type2_icon);
mapboxMap.addImage("marker_type2", marker_type2_icon);

3.Relate the GeoJson points to the icons (so each point is related to at least an icon, could be that you want the same icon for all markers though) (Adding visual representation)

SymbolLayer symbolLayer = new SymbolLayer("layer-id", "geojson-source");
symbolLayer.setProperties(
    // This is the bit that makes the map to display an icon or another. "poi" is a property of a Point in a GeoJSON document.
    // If you enclosed between keys,, it will introduce the value of the poi property.
    // If you want a fixed icon for all markers, change this for "marker_type1", following my example from point 2.
    PropertyFactory.iconImage("{poi}"),
    // With this property we will show which Point was clicked, making the icon look bigger
    PropertyFactory.iconSize(
        Function.property(
            "selected",
            Stops.categorical(
                Stop.stop(true, PropertyFactory.iconSize(2.0f)),
                Stop.stop(false, PropertyFactory.iconSize(1.0f))
            )
        )
    )
);
mapboxMap.addLayer(symbolLayer);

4.Add an onClick event listener in order to detect which point has been clicked (Adding interactivity)

mapboxMap.addOnMapClickListener(new MapboxMap.OnMapClickListener() {
    @Override
    public void onMapClick(LatLng point) {
        PointF screenPoint = mapboxMap.getProjection().toScreenLocation(point);
        List<Feature> features = mapboxMap.queryRenderedFeatures(screenPoint, "layer-id");
        if (!features.isEmpty()) {
            Feature selectedFeature = features.get(0);
            selectedFeature.getProperties().addProperty("selected", true);
            String title = selectedFeature.getStringProperty("title");
            Toast.makeText(MapActivity.this, "You selected " + title, Toast.LENGTH_SHORT).show();

            // This triggers the update of the feature (Point) on the data source so it updates the SymbolLayer and you can see the feature enabled (bigger in this example)
            geoJsonSource.setGeoJson(selectedFeature);
        }
    }
});

The full guide I found is this one https://blog.mapbox.com/a-guide-to-the-android-symbollayer-api-5daac7b66f2c which is pretty awesome, although one or two functions were deprecated and I looked for their replacements. Aside from that, could be a nice way to get even deeper into the SymbolLayer of Mapbox SDK. You can do pretty nice things with it.