Skip to content

Commit

Permalink
Implements animateToRegion to Google Maps iOS (react-native-maps#779)
Browse files Browse the repository at this point in the history
  • Loading branch information
btoueg authored and Exilz committed Dec 9, 2016
1 parent 545ab58 commit d0a6e6a
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 39 deletions.
3 changes: 3 additions & 0 deletions ios/AirGoogleMaps/AIRGoogleMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,7 @@
- (void)didChangeCameraPosition:(GMSCameraPosition *)position;
- (void)idleAtCameraPosition:(GMSCameraPosition *)position;

+ (MKCoordinateRegion)makeGMSCameraPositionFromMap:(GMSMapView *)map andGMSCameraPosition:(GMSCameraPosition *)position;
+ (GMSCameraPosition*)makeGMSCameraPositionFromMap:(GMSMapView *)map andMKCoordinateRegion:(MKCoordinateRegion)region;

@end
78 changes: 39 additions & 39 deletions ios/AirGoogleMaps/AIRGoogleMap.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,41 +24,6 @@ id regionAsJSON(MKCoordinateRegion region) {
};
}

MKCoordinateRegion makeMKCoordinateRegionFromGMSCameraPositionOfMap(GMSMapView *map, GMSCameraPosition *position) {
// solution from here: http://stackoverflow.com/a/16587735/1102215
GMSVisibleRegion visibleRegion = map.projection.visibleRegion;
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithRegion: visibleRegion];
CLLocationCoordinate2D center;
CLLocationDegrees longitudeDelta;
CLLocationDegrees latitudeDelta = bounds.northEast.latitude - bounds.southWest.latitude;

if(bounds.northEast.longitude >= bounds.southWest.longitude) {
//Standard case
center = CLLocationCoordinate2DMake((bounds.southWest.latitude + bounds.northEast.latitude) / 2,
(bounds.southWest.longitude + bounds.northEast.longitude) / 2);
longitudeDelta = bounds.northEast.longitude - bounds.southWest.longitude;
} else {
//Region spans the international dateline
center = CLLocationCoordinate2DMake((bounds.southWest.latitude + bounds.northEast.latitude) / 2,
(bounds.southWest.longitude + bounds.northEast.longitude + 360) / 2);
longitudeDelta = bounds.northEast.longitude + 360 - bounds.southWest.longitude;
}
MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
return MKCoordinateRegionMake(center, span);
}

GMSCameraPosition* makeGMSCameraPositionFromMKCoordinateRegionOfMap(GMSMapView *map, MKCoordinateRegion region) {
float latitudeDelta = region.span.latitudeDelta * 0.5;
float longitudeDelta = region.span.longitudeDelta * 0.5;

CLLocationCoordinate2D a = CLLocationCoordinate2DMake(region.center.latitude + latitudeDelta,
region.center.longitude + longitudeDelta);
CLLocationCoordinate2D b = CLLocationCoordinate2DMake(region.center.latitude - latitudeDelta,
region.center.longitude - longitudeDelta);
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:a coordinate:b];
return [map cameraForBounds:bounds insets:UIEdgeInsetsZero];
}

@interface AIRGoogleMap ()

- (id)eventFromCoordinate:(CLLocationCoordinate2D)coordinate;
Expand Down Expand Up @@ -162,12 +127,12 @@ - (void)removeReactSubview:(id<RCTComponent>)subview {
- (void)setInitialRegion:(MKCoordinateRegion)initialRegion {
if (_initialRegionSet) return;
_initialRegionSet = true;
self.camera = makeGMSCameraPositionFromMKCoordinateRegionOfMap(self, initialRegion);
self.camera = [AIRGoogleMap makeGMSCameraPositionFromMap:self andMKCoordinateRegion:initialRegion];
}

- (void)setRegion:(MKCoordinateRegion)region {
// TODO: The JS component is repeatedly setting region unnecessarily. We might want to deal with that in here.
self.camera = makeGMSCameraPositionFromMKCoordinateRegionOfMap(self, region);
self.camera = [AIRGoogleMap makeGMSCameraPositionFromMap:self andMKCoordinateRegion:region];
}

- (BOOL)didTapMarker:(GMSMarker *)marker {
Expand Down Expand Up @@ -197,15 +162,15 @@ - (void)didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate {

- (void)didChangeCameraPosition:(GMSCameraPosition *)position {
id event = @{@"continuous": @YES,
@"region": regionAsJSON(makeMKCoordinateRegionFromGMSCameraPositionOfMap(self, position)),
@"region": regionAsJSON([AIRGoogleMap makeGMSCameraPositionFromMap:self andGMSCameraPosition:position]),
};

if (self.onChange) self.onChange(event);
}

- (void)idleAtCameraPosition:(GMSCameraPosition *)position {
id event = @{@"continuous": @NO,
@"region": regionAsJSON(makeMKCoordinateRegionFromGMSCameraPositionOfMap(self, position)),
@"region": regionAsJSON([AIRGoogleMap makeGMSCameraPositionFromMap:self andGMSCameraPosition:position]),
};
if (self.onChange) self.onChange(event); // complete
}
Expand Down Expand Up @@ -275,4 +240,39 @@ - (BOOL)showsUserLocation {
return self.myLocationEnabled;
}

+ (MKCoordinateRegion) makeGMSCameraPositionFromMap:(GMSMapView *)map andGMSCameraPosition:(GMSCameraPosition *)position {
// solution from here: http://stackoverflow.com/a/16587735/1102215
GMSVisibleRegion visibleRegion = map.projection.visibleRegion;
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithRegion: visibleRegion];
CLLocationCoordinate2D center;
CLLocationDegrees longitudeDelta;
CLLocationDegrees latitudeDelta = bounds.northEast.latitude - bounds.southWest.latitude;

if(bounds.northEast.longitude >= bounds.southWest.longitude) {
//Standard case
center = CLLocationCoordinate2DMake((bounds.southWest.latitude + bounds.northEast.latitude) / 2,
(bounds.southWest.longitude + bounds.northEast.longitude) / 2);
longitudeDelta = bounds.northEast.longitude - bounds.southWest.longitude;
} else {
//Region spans the international dateline
center = CLLocationCoordinate2DMake((bounds.southWest.latitude + bounds.northEast.latitude) / 2,
(bounds.southWest.longitude + bounds.northEast.longitude + 360) / 2);
longitudeDelta = bounds.northEast.longitude + 360 - bounds.southWest.longitude;
}
MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
return MKCoordinateRegionMake(center, span);
}

+ (GMSCameraPosition*) makeGMSCameraPositionFromMap:(GMSMapView *)map andMKCoordinateRegion:(MKCoordinateRegion)region {
float latitudeDelta = region.span.latitudeDelta * 0.5;
float longitudeDelta = region.span.longitudeDelta * 0.5;

CLLocationCoordinate2D a = CLLocationCoordinate2DMake(region.center.latitude + latitudeDelta,
region.center.longitude + longitudeDelta);
CLLocationCoordinate2D b = CLLocationCoordinate2DMake(region.center.latitude - latitudeDelta,
region.center.longitude - longitudeDelta);
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:a coordinate:b];
return [map cameraForBounds:bounds insets:UIEdgeInsetsZero];
}

@end
17 changes: 17 additions & 0 deletions ios/AirGoogleMaps/AIRGoogleMapManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,23 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(onRegionChangeComplete, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(mapType, GMSMapViewType)

RCT_EXPORT_METHOD(animateToRegion:(nonnull NSNumber *)reactTag
withRegion:(MKCoordinateRegion)region
withDuration:(CGFloat)duration)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
[AIRGoogleMap animateWithDuration:duration/1000 animations:^{
GMSCameraPosition* camera = [AIRGoogleMap makeGMSCameraPositionFromMap:(AIRGoogleMap *)view andMKCoordinateRegion:region];
[(AIRGoogleMap *)view animateToCameraPosition:camera];
}];
}
}];
}

RCT_EXPORT_METHOD(fitToElements:(nonnull NSNumber *)reactTag
animated:(BOOL)animated)
{
Expand Down

0 comments on commit d0a6e6a

Please sign in to comment.