Hi, first, I'm very happy with the Mapbox products in general!
I'm just implementing the new Android library and I was wondering if there is a way to add a listener to clicks on Polylines. I know this is posible in de js API, but I can't find how to do this in Android.
This would be to change their style and show more information on them.
Is this possible?
Thank you!
@buzoherbert
Thank you reaching out and requesting this feature, currently we do not expose this as an API but is something we are thinking about adding in future releases.
@bleege @zugaldia:
Google maps SDK exposes:

To make this possible we should refactor SingleTapConfirmed, it now only takes Markers in account:
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// Open / Close InfoWindow
PointF tapPoint = new PointF(e.getX(), e.getY());
final float toleranceSides = 15 * mScreenDensity;
final float toleranceTop = 20 * mScreenDensity;
final float toleranceBottom = 5 * mScreenDensity;
RectF tapRect = new RectF(tapPoint.x - toleranceSides, tapPoint.y + toleranceTop,
tapPoint.x + toleranceSides, tapPoint.y - toleranceBottom);
List<LatLng> corners = Arrays.asList(
fromScreenLocation(new PointF(tapRect.left, tapRect.bottom)),
fromScreenLocation(new PointF(tapRect.left, tapRect.top)),
fromScreenLocation(new PointF(tapRect.right, tapRect.top)),
fromScreenLocation(new PointF(tapRect.right, tapRect.bottom))
);
BoundingBox tapBounds = BoundingBox.fromLatLngs(corners);
List<Marker> nearbyMarkers = getMarkersInBounds(tapBounds);
long newSelectedMarkerId = -1;
if (nearbyMarkers!=null && nearbyMarkers.size() > 0) {
Collections.sort(nearbyMarkers);
for (Marker nearbyMarker : nearbyMarkers) {
boolean found = false;
for (Marker selectedMarker : mSelectedMarkers) {
if(selectedMarker.equals(nearbyMarker)){
found = true;
}
}
if(!found){
newSelectedMarkerId = nearbyMarker.getId();
break;
}
}
mMarkersNearLastTap = nearbyMarkers;
}
if (newSelectedMarkerId >= 0) {
int count = mAnnotations.size();
for (int i = 0; i < count; i++) {
Annotation annotation = mAnnotations.get(i);
if (annotation instanceof Marker) {
if (annotation.getId() == newSelectedMarkerId) {
if (mSelectedMarkers.isEmpty() || !mSelectedMarkers.contains(annotation)) {
selectMarker((Marker) annotation);
}
break;
}
}
}
} else {
// deselect any selected marker
deselectMarkers();
// notify app of map click
if (mOnMapClickListener != null) {
LatLng point = fromScreenLocation(tapPoint);
mOnMapClickListener.onMapClick(point);
}
}
return true;
}
And change the way the following method is called and interacted with. This method should be generalised in handling all types of annotations and the underlying native method should only be called once.
private List<Marker> getMarkersInBounds(@NonNull BoundingBox bbox) {
if (bbox == null) {
Log.w(TAG, "bbox was null, so just returning null");
return null;
}
// TODO: filter in JNI using C++ parameter to getAnnotationsInBounds
long[] ids = mNativeMapView.getAnnotationsInBounds(bbox);
List<Long> idsList = new ArrayList<>(ids.length);
for (int i = 0; i < ids.length; i++) {
idsList.add(ids[i]);
}
List<Marker> annotations = new ArrayList<>(ids.length);
int count = mAnnotations.size();
for (int i = 0; i < count; i++) {
Annotation annotation = mAnnotations.get(i);
if (annotation instanceof Marker && idsList.contains(annotation.getId())) {
annotations.add((Marker) annotation);
}
}
return new ArrayList<>(annotations);
}
As indicated in the TODO we should consider moving some things into C++
@tobrun Thank you so much for being so responsive. I'll keep an eye on this thread!
I'm currently looking at implementing this but it seems that our native method getAnnotationsInBounds is not working for polylines. Need to check for polygon.
update neither for polygons
For example, getAnnotationsInBounds is returning 0 in following cases:
https://www.dropbox.com/s/ueuef0nixp8p2ou/device-2016-02-17-150551.mp4?dl=0
Digging a bit deeper, I'm noticing that getAnnotationInBounds is calling a native method called getPointAnnotationsInBounds so this means getAnnotationInBounds will not work for Shape annotations..
I will have to postpone further integration until #3990 has been resolved.
Going to comment the interface definitions because I want to PR the progress made for #3176.
Hi, are there any news about the OnPolygonClickListener? Or does somebody has any other solution? Thank you :)
Waiting on this. I need this. Any update?
Is this close to being implemented?
(If not, I will need to implement a custom solution)
With https://github.com/mapbox/mapbox-gl-native/pull/5165 now merged, we can think again of bringing this feature to the Android SDK (the iOS equivalent ticket is tracked in https://github.com/mapbox/mapbox-gl-native/issues/2082).
At this point we're strongly focused on shipping v4.2 of the SDK (we're getting close) so I don't think this feature will make it on time, but we'll update this ticket as soon as we make any progress.
I solved this with a little workaround:
public class PointPolygonComparator {
/**
* @param coordsOfPoint
* @param pol
* @return
*/
public boolean isPointInPolygon(LatLng coordsOfPoint, Polygon pol) {
List<LatLng> latlngsOfPolygon = extractPolygonToPoints(pol);
int i;
int j;
boolean contains = false;
for (i = 0, j = latlngsOfPolygon.size() - 1; i < latlngsOfPolygon.size(); j = i++) {
if ((latlngsOfPolygon.get(i).getLongitude() > coordsOfPoint.getLongitude()) != (latlngsOfPolygon.get(j).getLongitude() > coordsOfPoint.getLongitude()) &&
(coordsOfPoint.getLatitude() < (latlngsOfPolygon.get(j).getLatitude() - latlngsOfPolygon.get(i).getLatitude()) * (coordsOfPoint.getLongitude() - latlngsOfPolygon.get(i).getLongitude()) / (latlngsOfPolygon.get(j).getLongitude() - latlngsOfPolygon.get(i).getLongitude()) + latlngsOfPolygon.get(i).getLatitude())) {
contains = !contains;
}
}
return contains;
}
/**
*
* @param p
* @return
*/
public List<LatLng> extractPolygonToPoints(Polygon p) {
List <LatLng> latlngsOfPolygon = new ArrayList<>();
for (int x = 0; x < p.getPoints().size(); ++x) {
LatLng coords = new LatLng(p.getPoints().get(x).getLatitude(), p.getPoints().get(x).getLongitude());
latlngsOfPolygon.add(coords);
}
return latlngsOfPolygon;
}
}
You can use this class in any activity together with the onMapClickedListener, for example like this:
mapboxMap.setOnMapClickListener(new MapboxMap.OnMapClickListener() {
@Override
public void onMapClick(@NonNull LatLng point) {
for (Polygon pol : allPolygonsOnMap) {
if (comparator.isPointInPolygon(new LatLng(point.getLatitude(), point.getLongitude()), pol.getPolygon())) {
Toast.makeText(MainActivity.this, pol.getId(), Toast.LENGTH_SHORT).show();
}
}
}
});
Hi folks, does anyone know got any news on this?
@igor-nm this is implemented and available in 5.1.5 and 5.2.0-beta.3
Thanks a lot @tobrun , I am new to mapbox and am developing a map with multiple polygons, and have lots of info in properties and are these properties I need to get, with setOnPolygonClickListener I can not get this information, what can you suggest me?
For that you can better use a geojson source with a filllayer. To react to clicks, you override onmapclicklistener and call into mapboxmap#queryRenderedFeatures with the Id of your layer.
HI @tobrun,
I am adding multiple polygons and also I need the clicklistner for the same.
As you suggested earlier to @igor-nm I have created filllayer for multiple polygons. Code shown below :
public void addPolygonToMap(List> polygonsPosition, String layerName, int color) {
Feature polygonFeature = Feature.fromGeometry(com.mapbox.services.commons.geojson.Polygon.fromCoordinates(polygonsPosition));
final GeoJsonSource source = new GeoJsonSource(layerName,
FeatureCollection.fromFeatures(new Feature[]{polygonFeature}), new GeoJsonOptions());
mMapboxMap.addSource(source);
FillLayer fillLayer = new FillLayer(layerName, layerName);
fillLayer.setProperties(
PropertyFactory.fillColor(color)
);
mMapboxMap.addLayer(fillLayer);
}
While in OnMapclickListner (code shown below) I am getting all the coordinates of that layer. While I need the only polygon which user has clicked. Please suggest me how should I do it.
mMapboxMap.setOnMapClickListener(new MapboxMap.OnMapClickListener() {
@Override
public void onMapClick(@NonNull LatLng point) {
PointF pointf = mMapboxMap.getProjection().toScreenLocation(point);
List<com.mapbox.services.commons.geojson.Feature> featureList = mMapboxMap.queryRenderedFeatures(pointf, "FieldPolygons" );
Log.e("point clicked", "onMapClick: " );
for (com.mapbox.services.commons.geojson.Feature feature : featureList) {
Log.e("pointdedcfede clicked", "onMapClick: " + feature.toJson());
}
}
});
@viveksaruk you can add an unique id as feature property to your features and reference that later in your code to make a distinction to determine which one was clicked.
Thanks @tobrun for quick reply.It worked for me. But How could I group multiple Features with unique ID in one Layer?
Most helpful comment
Waiting on this. I need this. Any update?