From 267638ff9ca1343600b63c6e4994035c6da7c2c4 Mon Sep 17 00:00:00 2001 From: kota113 Date: Fri, 1 May 2026 08:40:19 +1000 Subject: [PATCH 1/6] feat: [iOS] add a method `animateCamera` to animate camera positions via GMSCameraPosition --- .../NavAutoModule.mm | 37 +++++++++++++++++ .../NavViewController.h | 3 ++ .../NavViewController.mm | 25 +++++++++++ .../NavViewModule.mm | 41 +++++++++++++++++++ 4 files changed, 106 insertions(+) diff --git a/ios/react-native-navigation-sdk/NavAutoModule.mm b/ios/react-native-navigation-sdk/NavAutoModule.mm index adfd47a8..c45587e2 100644 --- a/ios/react-native-navigation-sdk/NavAutoModule.mm +++ b/ios/react-native-navigation-sdk/NavAutoModule.mm @@ -432,6 +432,43 @@ - (void)moveCamera:(CameraPositionSpec &)cameraPosition } } +- (void)animateCamera:(CameraPositionSpec &)cameraPosition + duration:(double)duration + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + CameraPositionSpec positionCopy(cameraPosition); + if (_viewController) { + dispatch_async(dispatch_get_main_queue(), ^{ + GMSMutableCameraPosition *position = [[GMSMutableCameraPosition alloc] init]; + + if (positionCopy.target().has_value()) { + auto target = positionCopy.target().value(); + position.target = CLLocationCoordinate2DMake(target.lat(), target.lng()); + } + + if (positionCopy.zoom().has_value()) { + position.zoom = positionCopy.zoom().value(); + } + + if (positionCopy.bearing().has_value()) { + position.bearing = positionCopy.bearing().value(); + } + + if (positionCopy.tilt().has_value()) { + position.viewingAngle = positionCopy.tilt().value(); + } + + [self->_viewController animateCameraToPosition:position + duration:duration + result:^(BOOL success) { + resolve(@(success)); + }]; + }); + } else { + reject(@"NO_VIEW_CONTROLLER", @"No view controller found", nil); + } +} + - (void)removeMarker:(NSString *)id resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { diff --git a/ios/react-native-navigation-sdk/NavViewController.h b/ios/react-native-navigation-sdk/NavViewController.h index 3fd222e9..041bc974 100644 --- a/ios/react-native-navigation-sdk/NavViewController.h +++ b/ios/react-native-navigation-sdk/NavViewController.h @@ -72,6 +72,9 @@ typedef void (^OnArrayResult)(NSArray *_Nullable result); - (void)setRecenterButtonEnabled:(BOOL)isEnabled; - (void)resetMinMaxZoomLevel; - (void)animateCamera:(GMSCameraUpdate *)update; +- (void)animateCameraToPosition:(GMSCameraPosition *)position + duration:(double)duration + result:(OnBooleanResult)completionBlock; - (void)setMapStyle:(GMSMapStyle *)mapStyle; - (void)setMapType:(GMSMapViewType)mapType; - (void)clearMapView; diff --git a/ios/react-native-navigation-sdk/NavViewController.mm b/ios/react-native-navigation-sdk/NavViewController.mm index a662276f..fbe81a56 100644 --- a/ios/react-native-navigation-sdk/NavViewController.mm +++ b/ios/react-native-navigation-sdk/NavViewController.mm @@ -16,6 +16,7 @@ #import "NavViewController.h" #import +#import #import #import #import "CustomTypes.h" @@ -975,6 +976,30 @@ - (void)animateCamera:(GMSCameraUpdate *)update result:(OnBooleanResult)completi } } +- (void)animateCameraToPosition:(GMSCameraPosition *)position + duration:(double)duration + result:(OnBooleanResult)completionBlock { + if (_mapView == nil || position == nil) { + if (completionBlock) { + completionBlock(NO); + } + return; + } + + if (duration > 0) { + [CATransaction begin]; + [CATransaction setAnimationDuration:duration / 1000.0]; + [_mapView animateToCameraPosition:position]; + [CATransaction commit]; + } else { + [_mapView animateToCameraPosition:position]; + } + + if (completionBlock) { + completionBlock(YES); + } +} + - (NSArray *)getMarkers { NSMutableArray *result = [[NSMutableArray alloc] init]; for (NSString *key in _markerMap) { diff --git a/ios/react-native-navigation-sdk/NavViewModule.mm b/ios/react-native-navigation-sdk/NavViewModule.mm index b3193875..36a07814 100644 --- a/ios/react-native-navigation-sdk/NavViewModule.mm +++ b/ios/react-native-navigation-sdk/NavViewModule.mm @@ -400,6 +400,47 @@ - (void)moveCamera:(NSString *)nativeID } } +- (void)animateCamera:(NSString *)nativeID + cameraPosition:(CameraPositionSpec &)cameraPosition + duration:(double)duration + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + NavViewController *viewController = [self getViewControllerForNativeID:nativeID]; + CameraPositionSpec positionCopy(cameraPosition); + if (viewController) { + dispatch_async(dispatch_get_main_queue(), ^{ + GMSMutableCameraPosition *position = [[GMSMutableCameraPosition alloc] init]; + + if (positionCopy.target().has_value()) { + auto target = positionCopy.target().value(); + position.target = CLLocationCoordinate2DMake(target.lat(), target.lng()); + } + + if (positionCopy.zoom().has_value()) { + position.zoom = positionCopy.zoom().value(); + } + + if (positionCopy.bearing().has_value()) { + position.bearing = positionCopy.bearing().value(); + } + + if (positionCopy.tilt().has_value()) { + position.viewingAngle = positionCopy.tilt().value(); + } + + [viewController animateCameraToPosition:position + duration:duration + result:^(BOOL success) { + if (resolve) { + resolve(@(success)); + } + }]; + }); + } else { + reject(@"NO_VIEW_CONTROLLER", @"No view controller found for the specified nativeID", nil); + } +} + - (void)getCameraPosition:(NSString *)nativeID resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { From b6a73c2e02500246c79d9161d601d6fd8abf8f38 Mon Sep 17 00:00:00 2001 From: kota113 Date: Fri, 1 May 2026 08:40:54 +1000 Subject: [PATCH 2/6] fix: add a null check --- .../google/android/react/navsdk/MapViewController.java | 10 +++++++++- ios/react-native-navigation-sdk/NavViewController.mm | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/google/android/react/navsdk/MapViewController.java b/android/src/main/java/com/google/android/react/navsdk/MapViewController.java index 9f30f826..4da2dbe7 100644 --- a/android/src/main/java/com/google/android/react/navsdk/MapViewController.java +++ b/android/src/main/java/com/google/android/react/navsdk/MapViewController.java @@ -787,7 +787,15 @@ public void moveCamera(Map map) { return; } - LatLng latLng = ObjectTranslationUtil.getLatLngFromMap((Map) map.get("target")); + Object targetObj = map.get("target"); + if (targetObj == null) { + return; + } + + LatLng latLng = ObjectTranslationUtil.getLatLngFromMap((Map) targetObj); + if (latLng == null) { + return; + } float zoom = (float) CollectionUtil.getDouble("zoom", map, 0); float tilt = (float) CollectionUtil.getDouble("tilt", map, 0); diff --git a/ios/react-native-navigation-sdk/NavViewController.mm b/ios/react-native-navigation-sdk/NavViewController.mm index fbe81a56..e0da82d5 100644 --- a/ios/react-native-navigation-sdk/NavViewController.mm +++ b/ios/react-native-navigation-sdk/NavViewController.mm @@ -970,6 +970,12 @@ - (void)setMinZoomLevel:(float)minLevel maxZoom:(float)maxLevel { } - (void)animateCamera:(GMSCameraUpdate *)update result:(OnBooleanResult)completionBlock { + if (_mapView == nil || update == nil) { + if (completionBlock) { + completionBlock(NO); + } + return; + } [_mapView animateWithCameraUpdate:update]; if (completionBlock) { completionBlock(YES); From 95db3989e59d35968c8b07bb9e2cebc981c4dbdc Mon Sep 17 00:00:00 2001 From: kota113 Date: Fri, 1 May 2026 08:52:58 +1000 Subject: [PATCH 3/6] feat: [android] add a method `animateCamera` --- .../react/navsdk/MapViewController.java | 44 ++++++++++++------- .../android/react/navsdk/NavAutoModule.java | 19 ++++++++ .../android/react/navsdk/NavViewModule.java | 24 ++++++++++ 3 files changed, 72 insertions(+), 15 deletions(-) diff --git a/android/src/main/java/com/google/android/react/navsdk/MapViewController.java b/android/src/main/java/com/google/android/react/navsdk/MapViewController.java index 4da2dbe7..459ad78b 100644 --- a/android/src/main/java/com/google/android/react/navsdk/MapViewController.java +++ b/android/src/main/java/com/google/android/react/navsdk/MapViewController.java @@ -808,24 +808,38 @@ public void moveCamera(Map map) { } public void animateCamera(Map map) { - if (mGoogleMap != null) { - int zoom = CollectionUtil.getInt("zoom", map, 0); - int tilt = CollectionUtil.getInt("tilt", map, 0); - int bearing = CollectionUtil.getInt("bearing", map, 0); - int animationDuration = CollectionUtil.getInt("duration", map, 0); - - CameraPosition cameraPosition = - new CameraPosition.Builder() - .target( - ObjectTranslationUtil.getLatLngFromMap( - (Map) map.get("target"))) // Set the target location - .zoom(zoom) // Set the desired zoom level - .tilt(tilt) // Set the desired tilt angle (0 for straight down, 90 for straight up) - .bearing(bearing) // Set the desired bearing (rotation angle in degrees) - .build(); + if (mGoogleMap == null) { + return; + } + + Object targetObj = map.get("target"); + if (targetObj == null) { + return; + } + LatLng latLng = ObjectTranslationUtil.getLatLngFromMap((Map) targetObj); + if (latLng == null) { + return; + } + + int zoom = CollectionUtil.getInt("zoom", map, 0); + int tilt = CollectionUtil.getInt("tilt", map, 0); + int bearing = CollectionUtil.getInt("bearing", map, 0); + int animationDuration = CollectionUtil.getInt("duration", map, 0); + + CameraPosition cameraPosition = + new CameraPosition.Builder() + .target(latLng) + .zoom(zoom) // Set the desired zoom level + .tilt(tilt) // Set the desired tilt angle (0 for straight down, 90 for straight up) + .bearing(bearing) // Set the desired bearing (rotation angle in degrees) + .build(); + + if (animationDuration > 0) { mGoogleMap.animateCamera( CameraUpdateFactory.newCameraPosition(cameraPosition), animationDuration, null); + } else { + mGoogleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); } } diff --git a/android/src/main/java/com/google/android/react/navsdk/NavAutoModule.java b/android/src/main/java/com/google/android/react/navsdk/NavAutoModule.java index d9247aee..5801ddfc 100644 --- a/android/src/main/java/com/google/android/react/navsdk/NavAutoModule.java +++ b/android/src/main/java/com/google/android/react/navsdk/NavAutoModule.java @@ -612,6 +612,25 @@ public void moveCamera(ReadableMap cameraPosition, final Promise promise) { }); } + @Override + public void animateCamera( + ReadableMap cameraPosition, @Nullable Double duration, final Promise promise) { + UiThreadUtil.runOnUiThread( + () -> { + if (mMapViewController == null) { + promise.reject(JsErrors.NO_MAP_ERROR_CODE, JsErrors.NO_MAP_ERROR_MESSAGE); + return; + } + + Map map = cameraPosition.toHashMap(); + if (duration != null) { + map.put("duration", duration.doubleValue()); + } + mMapViewController.animateCamera(map); + promise.resolve(null); + }); + } + @Override public void isAutoScreenAvailable(final Promise promise) { promise.resolve(mMapViewController != null); diff --git a/android/src/main/java/com/google/android/react/navsdk/NavViewModule.java b/android/src/main/java/com/google/android/react/navsdk/NavViewModule.java index e4f8570f..fbc2dff0 100644 --- a/android/src/main/java/com/google/android/react/navsdk/NavViewModule.java +++ b/android/src/main/java/com/google/android/react/navsdk/NavViewModule.java @@ -14,6 +14,7 @@ package com.google.android.react.navsdk; import android.location.Location; +import androidx.annotation.Nullable; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; @@ -261,6 +262,29 @@ public void moveCamera(String nativeID, ReadableMap cameraPosition, final Promis }); } + @Override + public void animateCamera( + String nativeID, + ReadableMap cameraPosition, + @Nullable Double duration, + final Promise promise) { + UiThreadUtil.runOnUiThread( + () -> { + IMapViewFragment fragment = mNavViewManager.getFragmentByNativeId(nativeID); + if (fragment == null) { + promise.reject(JsErrors.NO_MAP_ERROR_CODE, JsErrors.NO_MAP_ERROR_MESSAGE); + return; + } + + Map map = cameraPosition.toHashMap(); + if (duration != null) { + map.put("duration", duration.doubleValue()); + } + fragment.getMapController().animateCamera(map); + promise.resolve(null); + }); + } + @Override public void showRouteOverview(String nativeID, final Promise promise) { UiThreadUtil.runOnUiThread( From 223d177ff34e7c99d9c2ff520da33b9db1645076 Mon Sep 17 00:00:00 2001 From: kota113 Date: Fri, 1 May 2026 09:05:04 +1000 Subject: [PATCH 4/6] feat: add typescript `animateCamera` methods and types --- src/auto/useNavigationAuto.ts | 14 ++++++++++++++ src/maps/mapView/mapView.tsx | 2 +- src/maps/mapView/mapViewController.ts | 17 ++++++++++++++++- src/maps/mapView/types.ts | 14 +++++++++++++- src/native/NativeNavAutoModule.ts | 4 ++++ src/native/NativeNavViewModule.ts | 5 +++++ 6 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/auto/useNavigationAuto.ts b/src/auto/useNavigationAuto.ts index 2dd27593..cd2f8e5c 100644 --- a/src/auto/useNavigationAuto.ts +++ b/src/auto/useNavigationAuto.ts @@ -370,6 +370,20 @@ export const useNavigationAuto = (): UseNavigationAutoResult => { return NavAutoModule.moveCamera(cameraPosition); }, + // set default values to transition similar to Google Maps app + animateCamera: ( + cameraPosition: CameraPosition, + duration?: number | null + ) => { + return NavAutoModule.animateCamera( + { + ...cameraPosition, + zoom: cameraPosition.zoom ?? 15, + }, + duration === undefined ? 500 : duration + ); + }, + setPadding: (padding: Padding) => { const { top = 0, left = 0, bottom = 0, right = 0 } = padding; return NavAutoModule.setMapPadding(top, left, bottom, right); diff --git a/src/maps/mapView/mapView.tsx b/src/maps/mapView/mapView.tsx index 3a0d8eca..a6435cbf 100644 --- a/src/maps/mapView/mapView.tsx +++ b/src/maps/mapView/mapView.tsx @@ -52,7 +52,7 @@ export const MapView = (props: MapViewProps): React.JSX.Element => { target: props.initialCameraPosition?.target ?? null, bearing: props.initialCameraPosition?.bearing ?? 0.0, tilt: props.initialCameraPosition?.tilt ?? 0.0, - zoom: props.initialCameraPosition?.zoom ?? 0.0, + zoom: props.initialCameraPosition?.zoom ?? 15, }, }), }; diff --git a/src/maps/mapView/mapViewController.ts b/src/maps/mapView/mapViewController.ts index 04f6e934..f405e719 100644 --- a/src/maps/mapView/mapViewController.ts +++ b/src/maps/mapView/mapViewController.ts @@ -16,7 +16,7 @@ import NavViewModule from '../../native/NativeNavViewModule'; import { processColorValue, colorIntToRGBA } from '../../shared'; -import type { Location } from '../../shared/types'; +import type { Location } from '../../shared'; import type { CameraPosition, Circle, @@ -195,6 +195,21 @@ export const getMapViewController = (nativeID: string): MapViewController => { return await NavViewModule.moveCamera(nativeID, cameraPosition); }, + animateCamera: async ( + cameraPosition: CameraPosition, + duration?: number | null + ) => { + // set default values to transition similar to Google Maps app + return await NavViewModule.animateCamera( + nativeID, + { + ...cameraPosition, + zoom: cameraPosition.zoom ?? 15, + }, + duration === undefined ? 500 : duration + ); + }, + setPadding: async _padding => { console.warn('setPadding should be set via props in new architecture'); }, diff --git a/src/maps/mapView/types.ts b/src/maps/mapView/types.ts index 59ea599d..67b102cf 100644 --- a/src/maps/mapView/types.ts +++ b/src/maps/mapView/types.ts @@ -376,7 +376,19 @@ export interface MapViewController { * * @param cameraPosition - Defines the position the camera will take with the move. */ - moveCamera(cameraPosition: CameraPosition): void; + moveCamera(cameraPosition: CameraPosition): Promise; + + /** + * Animate the camera to a new position based on the object given. + * + * @param cameraPosition - Defines the position the camera will animate to. + * @param duration - Animation duration in milliseconds. Defaults to 500 ms when undefined. + * Pass null to use the native SDK's default animation duration. + */ + animateCamera( + cameraPosition: CameraPosition, + duration?: number | null + ): Promise; /** * Sets padding to the map. diff --git a/src/native/NativeNavAutoModule.ts b/src/native/NativeNavAutoModule.ts index 8f7a0976..e3a37a7c 100644 --- a/src/native/NativeNavAutoModule.ts +++ b/src/native/NativeNavAutoModule.ts @@ -138,6 +138,10 @@ export interface Spec extends TurboModule { addPolygon(options: PolygonOptionsSpec): Promise; addGroundOverlay(options: GroundOverlayOptionsSpec): Promise; moveCamera(cameraPosition: CameraPositionSpec): Promise; + animateCamera( + cameraPosition: CameraPositionSpec, + duration?: WithDefault + ): Promise; removeMarker(id: string): Promise; removePolyline(id: string): Promise; removePolygon(id: string): Promise; diff --git a/src/native/NativeNavViewModule.ts b/src/native/NativeNavViewModule.ts index ae26454a..6c8d6f2b 100644 --- a/src/native/NativeNavViewModule.ts +++ b/src/native/NativeNavViewModule.ts @@ -148,6 +148,11 @@ export interface Spec extends TurboModule { nativeID: string, cameraPosition: CameraPositionSpec ): Promise; + animateCamera( + nativeID: string, + cameraPosition: CameraPositionSpec, + duration?: WithDefault + ): Promise; getCameraPosition(nativeID: string): Promise; getMyLocation(nativeID: string): Promise; getUiSettings(nativeID: string): Promise; From 7decdadb43a3ab6d50f47c28523ba67240ac2e9d Mon Sep 17 00:00:00 2001 From: kota113 Date: Fri, 1 May 2026 09:05:24 +1000 Subject: [PATCH 5/6] feat: add `animateCamera` tests --- example/e2e/map.test.js | 23 ++++++--- example/src/controls/mapsControls.tsx | 10 ++++ .../src/screens/IntegrationTestsScreen.tsx | 11 +++++ .../integration_tests/integration_test.ts | 49 +++++++++++++++++++ 4 files changed, 85 insertions(+), 8 deletions(-) diff --git a/example/e2e/map.test.js b/example/e2e/map.test.js index e3814007..98328135 100644 --- a/example/e2e/map.test.js +++ b/example/e2e/map.test.js @@ -41,56 +41,63 @@ describe('Map view tests', () => { await expectSuccess(); }); - it('MT03 - initialize map and test camera tilt bearing zoom', async () => { + it('MT03 - initialize map and test animate camera', async () => { + await selectTestByName('testAnimateCamera'); + await waitForTestToFinish(); + await expectNoErrors(); + await expectSuccess(); + }); + + it('MT04 - initialize map and test camera tilt bearing zoom', async () => { await selectTestByName('testTiltZoomBearingCamera'); await waitForTestToFinish(); await expectNoErrors(); await expectSuccess(); }); - it('MT04 - test adding and removing markers', async () => { + it('MT05 - test adding and removing markers', async () => { await selectTestByName('testMapMarkers'); await waitForTestToFinish(); await expectNoErrors(); await expectSuccess(); }); - it('MT05 - test adding and removing circles', async () => { + it('MT06 - test adding and removing circles', async () => { await selectTestByName('testMapCircles'); await waitForTestToFinish(); await expectNoErrors(); await expectSuccess(); }); - it('MT06 - test adding and removing polylines', async () => { + it('MT07 - test adding and removing polylines', async () => { await selectTestByName('testMapPolylines'); await waitForTestToFinish(); await expectNoErrors(); await expectSuccess(); }); - it('MT07 - test adding and removing polygons', async () => { + it('MT08 - test adding and removing polygons', async () => { await selectTestByName('testMapPolygons'); await waitForTestToFinish(); await expectNoErrors(); await expectSuccess(); }); - it('MT08 - test adding and removing ground overlays', async () => { + it('MT09 - test adding and removing ground overlays', async () => { await selectTestByName('testMapGroundOverlays'); await waitForTestToFinish(); await expectNoErrors(); await expectSuccess(); }); - it('MT09 - test setting map style via JSON', async () => { + it('MT10 - test setting map style via JSON', async () => { await selectTestByName('testMapStyle'); await waitForTestToFinish(); await expectNoErrors(); await expectSuccess(); }); - it('MT10 - test min and max zoom level constraints', async () => { + it('MT11 - test min and max zoom level constraints', async () => { await selectTestByName('testMinMaxZoomLevels'); await waitForTestToFinish(); await expectNoErrors(); diff --git a/example/src/controls/mapsControls.tsx b/example/src/controls/mapsControls.tsx index 56807757..15b6da1f 100644 --- a/example/src/controls/mapsControls.tsx +++ b/example/src/controls/mapsControls.tsx @@ -142,6 +142,15 @@ const MapsControls: React.FC = ({ }); }; + const animateCamera = () => { + mapViewController.animateCamera({ + target: { lat: Number(latitude), lng: Number(longitude) }, + zoom: 1, + bearing: 60, + tilt: 60, + }); + }; + const setMapType = (newMapType: MapType) => { onMapTypeChange?.(newMapType); }; @@ -410,6 +419,7 @@ const MapsControls: React.FC = ({ keyboardType="numeric" /> + { diff --git a/example/src/screens/IntegrationTestsScreen.tsx b/example/src/screens/IntegrationTestsScreen.tsx index 292bd34e..c7260c89 100644 --- a/example/src/screens/IntegrationTestsScreen.tsx +++ b/example/src/screens/IntegrationTestsScreen.tsx @@ -42,6 +42,7 @@ import { testRouteSegments, testGetCurrentTimeAndDistance, testMoveCamera, + testAnimateCamera, testTiltZoomBearingCamera, testMapMarkers, testMapCircles, @@ -279,6 +280,9 @@ const IntegrationTestsScreen = () => { case 'testMoveCamera': await testMoveCamera(getTestTools()); break; + case 'testAnimateCamera': + await testAnimateCamera(getTestTools()); + break; case 'testTiltZoomBearingCamera': await testTiltZoomBearingCamera(getTestTools()); break; @@ -451,6 +455,13 @@ const IntegrationTestsScreen = () => { }} testID="testMoveCamera" /> + { + runTest('testAnimateCamera'); + }} + testID="testAnimateCamera" + /> { diff --git a/example/src/screens/integration_tests/integration_test.ts b/example/src/screens/integration_tests/integration_test.ts index 4987e770..10a5314d 100644 --- a/example/src/screens/integration_tests/integration_test.ts +++ b/example/src/screens/integration_tests/integration_test.ts @@ -814,6 +814,55 @@ export const testMoveCamera = async (testTools: TestTools) => { passTest(); }; +export const testAnimateCamera = async (testTools: TestTools) => { + const { mapViewController, passTest, failTest, expectFalseError } = testTools; + if (!mapViewController) { + return failTest('mapViewController was expected to exist'); + } + + // Animate camera to Hong Kong + await mapViewController.animateCamera({ + target: { + lat: 22.2987849, + lng: 114.1719271, + }, + }); + + const hongKongPosition = await waitForCondition( + () => mapViewController.getCameraPosition(), + position => + roundDown(position.target.lat) === 22 && + roundDown(position.target.lng) === 114 + ); + if (!hongKongPosition) { + expectFalseError( + 'roundDown(hongKongPosition.target.lat) !== 22 || roundDown(hongKongPosition.target.lng) !== 114' + ); + } + + // Animate camera to Tokyo + await mapViewController.animateCamera({ + target: { + lat: 35.6805707, + lng: 139.7658596, + }, + }); + + const tokyoPosition = await waitForCondition( + () => mapViewController.getCameraPosition(), + position => + roundDown(position.target.lat) === 35 && + roundDown(position.target.lng) === 139 + ); + if (!tokyoPosition) { + expectFalseError( + 'roundDown(tokyoPosition.target.lat) !== 35 || roundDown(tokyoPosition.target.lng) !== 139' + ); + } + + passTest(); +}; + export const testTiltZoomBearingCamera = async (testTools: TestTools) => { const { mapViewController, passTest, failTest, expectFalseError } = testTools; if (!mapViewController) { From 947b3d0d6a13e050e06e335abb0017b42b2a2a74 Mon Sep 17 00:00:00 2001 From: kota113 Date: Wed, 6 May 2026 23:15:03 +1000 Subject: [PATCH 6/6] docs: document animateCamera --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a05753a0..ec24bcbe 100644 --- a/README.md +++ b/README.md @@ -571,6 +571,7 @@ The `MapViewController` is provided via the `onMapViewControllerCreated` callbac | `removeCircle(id: string)` | `void` | Remove a circle by its ID | | `removeGroundOverlay(id: string)` | `void` | Remove a ground overlay by its ID | | `moveCamera(position: CameraPosition)` | `void` | Move camera to a new position | +| `animateCamera(position: CameraPosition, duration?: number \| null)` | `Promise` | Animate camera to a new position. Defaults to 500 ms when duration is omitted | | `setZoomLevel(level: number)` | `void` | Set the map zoom level | | `setPadding(padding: Padding)` | `void` | Set padding on the map | | `getCameraPosition()` | `Promise` | Get the current camera position |