Describe the bug
I was trying to find drop-pins wrapped in a certain bounding box, in specified layerIds and null filter using MapView method queryRenderedFeaturesInRect. Each drop-pin is implemented with the combination of ShapeSource & SymbolLayer.
It worked fine on iOS, even iOS 14 but on Android, it sucked. The result only contains an empty array typed FeatureCollection.
However, method queryRenderedFeaturesInRect works with LineLayer both on Android and iOS.
To Reproduce
Below is the implementation for handling selecting a Marker which is obscured by MapboxGL.UserLocation
Example:
// Marker
import React from 'react';
import {
MapView,
ShapeSource,
SymbolLayer,
Camera,
} from '@react-native-mapbox-gl/maps';
import {
Platform,
NativeModules,
NativeEventEmitter,
} from 'react-native';
const Marker = ({ id, onPress, coordinate, properties = {} }) => (
<ShapeSource
onPress={onPress}
id={id}
shape={{
type: 'Feature',
properties,
geometry: {
type: 'Point',
coordinates: coordinate,
},
}}
>
<SymbolLayer
id={`${id}-symbol`}
style={{
iconImage: 'https://s1.imghub.io/uzvBS.png',
iconAnchor: 'bottom',
iconAllowOverlap: true,
}}
/>
</ShapeSource>
)
// MapView
// -- get current user location (iOS)
const MyLocationDataManagerEmmiter = new NativeEventEmitter(NativeModules.MyLocationDataManager)
const getLocationManager = () => new Promise((resolve) => {
const list = MyLocationDataManagerEmmiter.addListener(
'significantLocationChange',
(data) => {
const { longitude, latitude } = data.location.coords
resolve({
longitude,
latitude,
})
list.remove()
},
(err) => console.log('err: ', err),
)
})
// -- get current user location (Android)
let _userLocationAndroid = null;
const handleUserLocationChange = (e) => {
if (e && Platform.OS === 'android' ) {
_userLocationAndroid = e.coords
}
}
// -- get bounding box for point{x, y}
export const calcBoundingBox = (point, boxEdgeHalfSize) => {
const nX = Number(point.x);
const nY = Number(point.y);
const halfSize = Number(boxEdgeHalfSize);
return [
nY - halfSize, // top
nX + halfSize, // right
nY + halfSize, // bottom
nX - halfSize, // left
]
}
<MapboxGL.MapView
ref={(ref) => { _map = ref || _map }}
>
<MapboxGL.Camera
ref={(ref) => {
if (ref) {
_camera = ref
}
}}
zoomLevel={7}
minZoomLevel={0}
maxZoomLevel={18}
followZoomLevel={18}
/>
<MapboxGL.UserLocation
showsUserHeadingIndicator
onUpdate={handleUserLocationChange}
onPress={async () => {
let lng
let lat
if (Platform.OS === 'ios') {
const { longitude, latitude } = await getLocationManager()
lng = longitude
lat = latitude
} else {
if (!_userLocationAndroid) return
const { latitude, longitude } = _userLocationAndroid
lng = longitude
lat = latitude
}
if (Number.isNaN(lng) || Number.isNaN(lat)) {
return
}
const point = await _map.getPointInView([lng, lat])
console.log('_DEBUG_: point', point)
const bbox = calcBoundingBox({ x: point[0], y: point[1] }, 10)
console.log('_DEBUG_: bbox', bbox)
const layerIds = pins.map((pin) => `${pin.identifier}-symbol`)
console.log('_DEBUG_: layerIds', layerIds)
const featureCollections = await _map.queryRenderedFeaturesInRect(bbox, null, layerIds)
console.log('_DEBUG_: featureCollections', JSON.stringify(featureCollections, null, 2))
}}
/>
</MapboxGL.MapView>
Expected behavior
featureCollections should be exactly the same on both Android & iOS.queryRenderedFeaturesInRect to find all SymbolLayer in provided bounding box.Screenshots
Result after clicking on UserLocation
iOS

Android

Versions (please complete the following information):
I'm getting a similar issue with queryRenderedFeaturesAtPoint on Android. Code works fine on iOS, but doesn't work on Android:
const onPress = useCallback(
async (feature: Feature) => {
if (__DEV__) {
console.log(feature);
}
if (feature.geometry.type !== 'Point') {
return;
}
const point = await mapRef.current?.getPointInView(
feature.geometry.coordinates,
);
console.log(point);
if (!point) {
return;
}
const featureQuery = await mapRef.current?.queryRenderedFeaturesAtPoint(
point,
);
console.log(featureQuery);
if (!featureQuery) {
return;
}
const tappedFeature = featureQuery.features.filter(
(f): f is Feature => f.id && f.properties?.name,
)[0];
if (tappedFeature) {
onSelectFeature?.(tappedFeature);
}
},
[onSelectFeature],
);
The logs are interesting, because if I do this exactly the same side-by-side in an iOS simulator and an Android emulator, these are the logs:
iOS: {"geometry": {"coordinates": [-0.1278433227608673, 51.50767608808047], "type": "Point"}, "properties": {"screenPointX": 199, "screenPointY": 431}, "type": "Feature"}
iOS: [198.9999997594527, 430.99999959695907]
iOS: {"features": [{"geometry": [Object], "id": 957821391, "properties": [Object], "type": "Feature"}], "type": "FeatureCollection"}
Android: {"geometry": {"coordinates": [-0.12793794265280667, 51.507698148552066], "type": "Point"}, "properties": {"screenPointX": 513.96240234375, "screenPointY": 850.95703125}, "type": "Feature"}
Android: [195.79519653320312, 324.1741027832031]
Android: {"features": [], "type": "FeatureCollection"}
On iOS getPointInView returns virtually the same numbers as the feature's screenPoint[X/Y] values, whereas on Android they are quite different. Could that be the issue?
Is #639 related to this? Also, getting this issue both on @react-native-mapbox-gl/[email protected] and rc.7
@jun-nguyen-goldenowl, can you please create an example within the /example app.
Preferably in the BugReportTemplate - make sure it runs afterwards.
Less time we spend setting up and debugging code samples is more time fixing the issue.
Thanks in advance 馃檱
I can also confirm that the following snippet was necessary to make queryRenderedFeaturesAtPoint work with the result of getPointInView:
if (Platform.OS == 'android') {
point[0] *= PixelRatio.get();
point[1] *= PixelRatio.get();
}
Would it perhaps make sense to add a method queryRenderedFeaturesAtLocation that handles this internally? (In addition to fixing the underlying bug with getPointInView).
PRs appreciated :)
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Should we keep this open, even if nobody has had the time to fix it so far?
Should we keep this open, even if nobody has had the time to fix it so far?
Definitely, I'll at an appropriate label to the ticket.
Maybe someone stumbles upon it and actually has time :D
@ferdicus could it be that fixing this bug is as simple as removing these two lines here?
https://github.com/react-native-mapbox-gl/maps/blob/963a77b7ce716d1f5b8b64fd5a45c0fcf90aac61/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.java#L922
I couldn't see any similar logic on the iOS counterpart here:
https://github.com/react-native-mapbox-gl/maps/blob/9103f2db5a5600f6a29db1644b2a09e5979da58d/ios/RCTMGL/RCTMGLMapViewManager.m#L116
It could be that iOS works in device pixels, but it doesn't seem so.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
not stale
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Not stale
@ferdicus could it be that fixing this bug is as simple as removing these two lines here?
I couldn't see any similar logic on the iOS counterpart here:
It could be that iOS works in device pixels, but it doesn't seem so.
@savv , not sure - you can check the PR for the reasoning behind this addition: https://github.com/react-native-mapbox-gl/maps/pull/639
Maybe that'll give a hint
Most helpful comment
I can also confirm that the following snippet was necessary to make
queryRenderedFeaturesAtPointwork with the result ofgetPointInView:Would it perhaps make sense to add a method queryRenderedFeaturesAtLocation that handles this internally? (In addition to fixing the underlying bug with
getPointInView).