You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to #3818 as requested there. #3818 is closed by #4040, but a related failure is still present on 10.3.5: the initial camera keeps the longitude and ends up at latitude 0 whenever the Mapbox style cache is cold.
The camera lands at [137.350, 0.000] instead of [137.350, 35.200] — right longitude, latitude exactly 0, so the map opens on the ocean.
Install the app fresh (adb uninstall <pkg> first — this is what clears the Mapbox style cache).
Launch it. The Camera has no props other than defaultSettings, so after stop & defaultStop race stop #4040 no empty stop is sent (nativeStop === null).
Read the center from onMapIdle / the overlay.
Only the first launch after an install is wrong; every later launch of the same install is correct, which is why this looks flaky in the wild.
build
defaultSettings
fresh installs
landed at latitude 0
10.3.5
{ bounds }
4
4
10.3.5 + patch below
{ bounds }
4
0
10.3.5
{ centerCoordinate, zoomLevel }
8
6
10.3.5 + patch below
{ centerCoordinate, zoomLevel }
4
0
10.3.5, warm relaunch (no reinstall)
{ bounds }
1
0
So bounds fails every time and centerCoordinate fails most of the time — #4213 (onCameraChanged firing [0, 0] / [lng, 0] on launch) looks like the same root cause seen through the event stream.
Reproduced on a physical OnePlus NE2213 (Android 16, API 36) and on the Medium_Phone_API_36.0 AVD, both New Architecture, debug builds.
Unpatched (emulator, fresh install) vs. patched:
I ReactNativeJS: [repro +681ms] onDidFinishLoadingStyle
I ReactNativeJS: [repro +730ms] onDidFinishLoadingMap
I ReactNativeJS: [repro +1018ms] onMapIdle center=[137.350, 0.000] zoom=7.85
Expected behavior
<Camera defaultSettings={{ bounds }} /> should put the initial camera inside the requested bounds on the first launch too, as it does on every subsequent launch.
Notes / preliminary analysis
RNMBXCamera declares requiresStyleLoad = false, so RNMBXMapView.addFeature adds it immediately and addToMap() → setInitialCamera() runs before the style is loaded. setInitialCamera applies the stop through a zero-duration flyTo (CameraUpdateItem.run()); applied that early the latitude does not stick while the longitude does. This matches @Elter71's observation in #3818 that "during the first flyTo method call, Mapbox doesn't center the map on the latitude".
Instrumenting RNMBXCamera in our production app (with Log.e — Logger.w is level-gated below WARN and silently dropped the output) showed:
the map view is already fully laid out (1080×2412) — not a layout-size race;
CameraStop.cameraForCoordinateBounds(...) returns the correct camera (center = 35.205, 137.357, zoom = 8.87);
setInitialCamera runs ~270 ms beforeonDidFinishLoadingMap on a cold start; on a warm start the cached style is loaded before the camera is added, which is exactly the difference between a failing and a passing launch.
Deferring the default stop until the style is loaded fixes it in all configurations I measured. getStyle invokes the callback immediately when the style is already loaded, so the warm path is unchanged and only the cold-start initial camera is delayed by one style load (~150–200 ms):
private fun setInitialCamera(mapView: RNMBXMapView) {
- mDefaultStop?.let {- val map = mapView.getMapboxMap()-- it.setDuration(0)- it.setMode(CameraMode.NONE)- val item = it.toCameraUpdate(mapView)- item.run()- }+ val defaultStop = mDefaultStop ?: return+ mapView.getMapboxMap().getStyle(object : Style.OnStyleLoaded {+ override fun onStyleLoaded(style: Style) {+ defaultStop.setDuration(0)+ defaultStop.setMode(CameraMode.NONE)+ defaultStop.toCameraUpdate(mapView).run()+ }+ })
}
We have been running this patch in production for a while with no side effects. I don't know whether the deferral or requiresStyleLoad = true is the direction you'd prefer (the latter looked riskier to me).
Follow-up to #3818 as requested there. #3818 is closed by #4040, but a related failure is still present on 10.3.5: the initial camera keeps the longitude and ends up at latitude 0 whenever the Mapbox style cache is cold.
Reproducer, evidence and the patch I am running: https://github.com/krisgerhard/rnmapbox-bounds-initial-camera-repro
Mapbox Version
11.24.2
React Native Version
0.86.2
Platform
Android
@rnmapbox/mapsversion10.3.5
Standalone component to reproduce
BugReportExample.js
Observed behavior and steps to reproduce
The camera lands at
[137.350, 0.000]instead of[137.350, 35.200]— right longitude, latitude exactly 0, so the map opens on the ocean.adb uninstall <pkg>first — this is what clears the Mapbox style cache).Camerahas no props other thandefaultSettings, so after stop & defaultStop race stop #4040 no empty stop is sent (nativeStop === null).onMapIdle/ the overlay.Only the first launch after an install is wrong; every later launch of the same install is correct, which is why this looks flaky in the wild.
defaultSettings{ bounds }{ bounds }{ centerCoordinate, zoomLevel }{ centerCoordinate, zoomLevel }{ bounds }So
boundsfails every time andcenterCoordinatefails most of the time — #4213 (onCameraChangedfiring[0, 0]/[lng, 0]on launch) looks like the same root cause seen through the event stream.Reproduced on a physical OnePlus NE2213 (Android 16, API 36) and on the
Medium_Phone_API_36.0AVD, both New Architecture, debug builds.Unpatched (emulator, fresh install) vs. patched:
Expected behavior
<Camera defaultSettings={{ bounds }} />should put the initial camera inside the requested bounds on the first launch too, as it does on every subsequent launch.Notes / preliminary analysis
RNMBXCameradeclaresrequiresStyleLoad = false, soRNMBXMapView.addFeatureadds it immediately andaddToMap()→setInitialCamera()runs before the style is loaded.setInitialCameraapplies the stop through a zero-durationflyTo(CameraUpdateItem.run()); applied that early the latitude does not stick while the longitude does. This matches @Elter71's observation in #3818 that "during the first flyTo method call, Mapbox doesn't center the map on the latitude".Instrumenting
RNMBXCamerain our production app (withLog.e—Logger.wis level-gated below WARN and silently dropped the output) showed:1080×2412) — not a layout-size race;CameraStop.cameraForCoordinateBounds(...)returns the correct camera (center = 35.205, 137.357,zoom = 8.87);setInitialCameraruns ~270 ms beforeonDidFinishLoadingMapon a cold start; on a warm start the cached style is loaded before the camera is added, which is exactly the difference between a failing and a passing launch.Deferring the default stop until the style is loaded fixes it in all configurations I measured.
getStyleinvokes the callback immediately when the style is already loaded, so the warm path is unchanged and only the cold-start initial camera is delayed by one style load (~150–200 ms):private fun setInitialCamera(mapView: RNMBXMapView) { - mDefaultStop?.let { - val map = mapView.getMapboxMap() - - it.setDuration(0) - it.setMode(CameraMode.NONE) - val item = it.toCameraUpdate(mapView) - item.run() - } + val defaultStop = mDefaultStop ?: return + mapView.getMapboxMap().getStyle(object : Style.OnStyleLoaded { + override fun onStyleLoaded(style: Style) { + defaultStop.setDuration(0) + defaultStop.setMode(CameraMode.NONE) + defaultStop.toCameraUpdate(mapView).run() + } + }) }We have been running this patch in production for a while with no side effects. I don't know whether the deferral or
requiresStyleLoad = trueis the direction you'd prefer (the latter looked riskier to me).Additional links and references
defaultStoppart)onCameraChangedfiring[0, 0]on launch, likely the same root cause