Last active
September 26, 2023 10:32
-
-
Save zhenguet/fcd566e31af4eda4a2e7ddb161306e2d to your computer and use it in GitHub Desktop.
add isMarkerWithinScreen to react-native-maps@1.7.1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.rnmaps.maps; | |
import android.app.Activity; | |
import android.graphics.Bitmap; | |
import android.graphics.Point; | |
import android.location.Address; | |
import android.location.Geocoder; | |
import android.net.Uri; | |
import android.util.Base64; | |
import android.util.DisplayMetrics; | |
import android.util.Log; | |
import androidx.annotation.NonNull; | |
import androidx.annotation.Nullable; | |
import com.facebook.react.bridge.Promise; | |
import com.facebook.react.bridge.ReactApplicationContext; | |
import com.facebook.react.bridge.ReactContextBaseJavaModule; | |
import com.facebook.react.bridge.ReactMethod; | |
import com.facebook.react.bridge.ReadableMap; | |
import com.facebook.react.bridge.WritableMap; | |
import com.facebook.react.bridge.WritableNativeMap; | |
import com.facebook.react.module.annotations.ReactModule; | |
import com.facebook.react.uimanager.NativeViewHierarchyManager; | |
import com.facebook.react.uimanager.UIBlock; | |
import com.facebook.react.uimanager.UIManagerModule; | |
import com.google.android.gms.maps.GoogleMap; | |
import com.google.android.gms.maps.MapsInitializer; | |
import com.google.android.gms.maps.OnMapsSdkInitializedCallback; | |
import com.google.android.gms.maps.model.CameraPosition; | |
import com.google.android.gms.maps.model.LatLng; | |
import com.google.android.gms.maps.model.LatLngBounds; | |
import java.io.ByteArrayOutputStream; | |
import java.io.Closeable; | |
import java.io.File; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
@ReactModule(name = MapModule.NAME) | |
public class MapModule extends ReactContextBaseJavaModule { | |
public static final String NAME = "AirMapModule"; | |
private static final String SNAPSHOT_RESULT_FILE = "file"; | |
private static final String SNAPSHOT_RESULT_BASE64 = "base64"; | |
private static final String SNAPSHOT_FORMAT_PNG = "png"; | |
private static final String SNAPSHOT_FORMAT_JPG = "jpg"; | |
public MapModule(ReactApplicationContext reactContext) { | |
super(reactContext); | |
} | |
@Override | |
public String getName() { | |
return NAME; | |
} | |
@Override | |
public Map<String, Object> getConstants() { | |
final Map<String, Object> constants = new HashMap<>(); | |
constants.put( | |
"legalNotice", | |
"This license information is displayed in Settings > Google > Open Source on any device running Google Play services." | |
); | |
return constants; | |
} | |
public Activity getActivity() { | |
return getCurrentActivity(); | |
} | |
public static void closeQuietly(Closeable closeable) { | |
if (closeable == null) return; | |
try { | |
closeable.close(); | |
} catch (IOException ignored) {} | |
} | |
@ReactMethod | |
public void takeSnapshot( | |
final int tag, | |
final ReadableMap options, | |
final Promise promise | |
) { | |
// Parse and verity options | |
final ReactApplicationContext context = getReactApplicationContext(); | |
final String format = options.hasKey("format") | |
? options.getString("format") | |
: "png"; | |
final Bitmap.CompressFormat compressFormat = format.equals( | |
SNAPSHOT_FORMAT_PNG | |
) | |
? Bitmap.CompressFormat.PNG | |
: format.equals(SNAPSHOT_FORMAT_JPG) ? Bitmap.CompressFormat.JPEG : null; | |
final double quality = options.hasKey("quality") | |
? options.getDouble("quality") | |
: 1.0; | |
final DisplayMetrics displayMetrics = context | |
.getResources() | |
.getDisplayMetrics(); | |
final Integer width = options.hasKey("width") | |
? (int) (displayMetrics.density * options.getDouble("width")) | |
: 0; | |
final Integer height = options.hasKey("height") | |
? (int) (displayMetrics.density * options.getDouble("height")) | |
: 0; | |
final String result = options.hasKey("result") | |
? options.getString("result") | |
: "file"; | |
// Add UI-block so we can get a valid reference to the map-view | |
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class); | |
uiManager.addUIBlock( | |
new UIBlock() { | |
public void execute(NativeViewHierarchyManager nvhm) { | |
MapView view = (MapView) nvhm.resolveView(tag); | |
if (view == null) { | |
promise.reject("AirMapView not found"); | |
return; | |
} | |
if (view.map == null) { | |
promise.reject("AirMapView.map is not valid"); | |
return; | |
} | |
view.map.snapshot( | |
new GoogleMap.SnapshotReadyCallback() { | |
public void onSnapshotReady(@Nullable Bitmap snapshot) { | |
// Convert image to requested width/height if necessary | |
if (snapshot == null) { | |
promise.reject("Failed to generate bitmap, snapshot = null"); | |
return; | |
} | |
if ( | |
(width != 0) && | |
(height != 0) && | |
( | |
width != snapshot.getWidth() || | |
height != snapshot.getHeight() | |
) | |
) { | |
snapshot = | |
Bitmap.createScaledBitmap(snapshot, width, height, true); | |
} | |
// Save the snapshot to disk | |
if (result.equals(SNAPSHOT_RESULT_FILE)) { | |
File tempFile; | |
FileOutputStream outputStream; | |
try { | |
tempFile = | |
File.createTempFile( | |
"AirMapSnapshot", | |
"." + format, | |
context.getCacheDir() | |
); | |
outputStream = new FileOutputStream(tempFile); | |
} catch (Exception e) { | |
promise.reject(e); | |
return; | |
} | |
snapshot.compress( | |
compressFormat, | |
(int) (100.0 * quality), | |
outputStream | |
); | |
closeQuietly(outputStream); | |
String uri = Uri.fromFile(tempFile).toString(); | |
promise.resolve(uri); | |
} else if (result.equals(SNAPSHOT_RESULT_BASE64)) { | |
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | |
snapshot.compress( | |
compressFormat, | |
(int) (100.0 * quality), | |
outputStream | |
); | |
closeQuietly(outputStream); | |
byte[] bytes = outputStream.toByteArray(); | |
String data = Base64.encodeToString(bytes, Base64.NO_WRAP); | |
promise.resolve(data); | |
} | |
} | |
} | |
); | |
} | |
} | |
); | |
} | |
@ReactMethod | |
public void isMarkerWithinScreen( | |
final int tag, | |
ReadableMap coordinate, | |
final Promise promise | |
) { | |
final ReactApplicationContext context = getReactApplicationContext(); | |
final double lat = coordinate.getDouble("latitude"); | |
final double lng = coordinate.getDouble("longitude"); | |
final LatLng position = new LatLng(lat, lng); | |
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class); | |
uiManager.addUIBlock( | |
new UIBlock() { | |
@Override | |
public void execute(NativeViewHierarchyManager nvhm) { | |
MapView view = (MapView) nvhm.resolveView(tag); | |
if (view == null) { | |
promise.reject("AirMapView not found"); | |
return; | |
} | |
if (view.map == null) { | |
promise.reject("AirMapView.map is not valid"); | |
return; | |
} | |
LatLngBounds currentScreen = view.map | |
.getProjection() | |
.getVisibleRegion() | |
.latLngBounds; | |
boolean onScreen = currentScreen.contains(position); | |
WritableMap visibleJson = new WritableNativeMap(); | |
visibleJson.putBoolean("visible", onScreen); | |
promise.resolve(visibleJson); | |
} | |
} | |
); | |
} | |
@ReactMethod | |
public void getCamera(final int tag, final Promise promise) { | |
final ReactApplicationContext context = getReactApplicationContext(); | |
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class); | |
uiManager.addUIBlock( | |
new UIBlock() { | |
@Override | |
public void execute(NativeViewHierarchyManager nvhm) { | |
MapView view = (MapView) nvhm.resolveView(tag); | |
if (view == null) { | |
promise.reject("AirMapView not found"); | |
return; | |
} | |
if (view.map == null) { | |
promise.reject("AirMapView.map is not valid"); | |
return; | |
} | |
CameraPosition position = view.map.getCameraPosition(); | |
WritableMap centerJson = new WritableNativeMap(); | |
centerJson.putDouble("latitude", position.target.latitude); | |
centerJson.putDouble("longitude", position.target.longitude); | |
WritableMap cameraJson = new WritableNativeMap(); | |
cameraJson.putMap("center", centerJson); | |
cameraJson.putDouble("heading", (double) position.bearing); | |
cameraJson.putDouble("zoom", (double) position.zoom); | |
cameraJson.putDouble("pitch", (double) position.tilt); | |
promise.resolve(cameraJson); | |
} | |
} | |
); | |
} | |
@ReactMethod | |
public void getAddressFromCoordinates( | |
final int tag, | |
final ReadableMap coordinate, | |
final Promise promise | |
) { | |
final ReactApplicationContext context = getReactApplicationContext(); | |
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class); | |
uiManager.addUIBlock( | |
new UIBlock() { | |
@Override | |
public void execute(NativeViewHierarchyManager nvhm) { | |
MapView view = (MapView) nvhm.resolveView(tag); | |
if (view == null) { | |
promise.reject("AirMapView not found"); | |
return; | |
} | |
if (view.map == null) { | |
promise.reject("AirMapView.map is not valid"); | |
return; | |
} | |
if ( | |
coordinate == null || | |
!coordinate.hasKey("latitude") || | |
!coordinate.hasKey("longitude") | |
) { | |
promise.reject("Invalid coordinate format"); | |
return; | |
} | |
Geocoder geocoder = new Geocoder(context); | |
try { | |
List<Address> list = geocoder.getFromLocation( | |
coordinate.getDouble("latitude"), | |
coordinate.getDouble("longitude"), | |
1 | |
); | |
if (list.isEmpty()) { | |
promise.reject("Can not get address location"); | |
return; | |
} | |
Address address = list.get(0); | |
WritableMap addressJson = new WritableNativeMap(); | |
addressJson.putString("name", address.getFeatureName()); | |
addressJson.putString("locality", address.getLocality()); | |
addressJson.putString("thoroughfare", address.getThoroughfare()); | |
addressJson.putString( | |
"subThoroughfare", | |
address.getSubThoroughfare() | |
); | |
addressJson.putString("subLocality", address.getSubLocality()); | |
addressJson.putString("administrativeArea", address.getAdminArea()); | |
addressJson.putString( | |
"subAdministrativeArea", | |
address.getSubAdminArea() | |
); | |
addressJson.putString("postalCode", address.getPostalCode()); | |
addressJson.putString("countryCode", address.getCountryCode()); | |
addressJson.putString("country", address.getCountryName()); | |
promise.resolve(addressJson); | |
} catch (IOException e) { | |
promise.reject("Can not get address location"); | |
} | |
} | |
} | |
); | |
} | |
@ReactMethod | |
public void pointForCoordinate( | |
final int tag, | |
ReadableMap coordinate, | |
final Promise promise | |
) { | |
final ReactApplicationContext context = getReactApplicationContext(); | |
final double density = (double) context | |
.getResources() | |
.getDisplayMetrics() | |
.density; | |
final LatLng coord = new LatLng( | |
coordinate.hasKey("latitude") ? coordinate.getDouble("latitude") : 0.0, | |
coordinate.hasKey("longitude") ? coordinate.getDouble("longitude") : 0.0 | |
); | |
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class); | |
uiManager.addUIBlock( | |
new UIBlock() { | |
@Override | |
public void execute(NativeViewHierarchyManager nvhm) { | |
MapView view = (MapView) nvhm.resolveView(tag); | |
if (view == null) { | |
promise.reject("AirMapView not found"); | |
return; | |
} | |
if (view.map == null) { | |
promise.reject("AirMapView.map is not valid"); | |
return; | |
} | |
Point pt = view.map.getProjection().toScreenLocation(coord); | |
WritableMap ptJson = new WritableNativeMap(); | |
ptJson.putDouble("x", (double) pt.x / density); | |
ptJson.putDouble("y", (double) pt.y / density); | |
promise.resolve(ptJson); | |
} | |
} | |
); | |
} | |
@ReactMethod | |
public void coordinateForPoint( | |
final int tag, | |
ReadableMap point, | |
final Promise promise | |
) { | |
final ReactApplicationContext context = getReactApplicationContext(); | |
final double density = (double) context | |
.getResources() | |
.getDisplayMetrics() | |
.density; | |
final Point pt = new Point( | |
point.hasKey("x") ? (int) (point.getDouble("x") * density) : 0, | |
point.hasKey("y") ? (int) (point.getDouble("y") * density) : 0 | |
); | |
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class); | |
uiManager.addUIBlock( | |
new UIBlock() { | |
@Override | |
public void execute(NativeViewHierarchyManager nvhm) { | |
MapView view = (MapView) nvhm.resolveView(tag); | |
if (view == null) { | |
promise.reject("AirMapView not found"); | |
return; | |
} | |
if (view.map == null) { | |
promise.reject("AirMapView.map is not valid"); | |
return; | |
} | |
LatLng coord = view.map.getProjection().fromScreenLocation(pt); | |
WritableMap coordJson = new WritableNativeMap(); | |
coordJson.putDouble("latitude", coord.latitude); | |
coordJson.putDouble("longitude", coord.longitude); | |
promise.resolve(coordJson); | |
} | |
} | |
); | |
} | |
@ReactMethod | |
public void getMapBoundaries(final int tag, final Promise promise) { | |
final ReactApplicationContext context = getReactApplicationContext(); | |
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class); | |
uiManager.addUIBlock( | |
new UIBlock() { | |
@Override | |
public void execute(NativeViewHierarchyManager nvhm) { | |
MapView view = (MapView) nvhm.resolveView(tag); | |
if (view == null) { | |
promise.reject("AirMapView not found"); | |
return; | |
} | |
if (view.map == null) { | |
promise.reject("AirMapView.map is not valid"); | |
return; | |
} | |
double[][] boundaries = view.getMapBoundaries(); | |
WritableMap coordinates = new WritableNativeMap(); | |
WritableMap northEastHash = new WritableNativeMap(); | |
WritableMap southWestHash = new WritableNativeMap(); | |
northEastHash.putDouble("longitude", boundaries[0][0]); | |
northEastHash.putDouble("latitude", boundaries[0][1]); | |
southWestHash.putDouble("longitude", boundaries[1][0]); | |
southWestHash.putDouble("latitude", boundaries[1][1]); | |
coordinates.putMap("northEast", northEastHash); | |
coordinates.putMap("southWest", southWestHash); | |
promise.resolve(coordinates); | |
} | |
} | |
); | |
} | |
@ReactMethod | |
public void enableLatestRenderer(final Promise promise) { | |
final ReactApplicationContext context = getReactApplicationContext(); | |
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class); | |
uiManager.addUIBlock( | |
new UIBlock() { | |
@Override | |
public void execute(NativeViewHierarchyManager nvhm) { | |
MapsInitializer.initialize( | |
context, | |
MapsInitializer.Renderer.LATEST, | |
new OnMapsSdkInitializedCallback() { | |
@Override | |
public void onMapsSdkInitialized( | |
@NonNull MapsInitializer.Renderer renderer | |
) { | |
Log.d("AirMapRenderer", renderer.toString()); | |
promise.resolve(renderer.toString()); | |
} | |
} | |
); | |
} | |
} | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// AIRGoogleMapManager.m | |
// AirMaps | |
// | |
// Created by Gil Birman on 9/1/16. | |
// | |
#ifdef HAVE_GOOGLE_MAPS | |
#import "AIRGoogleMapManager.h" | |
#import <React/RCTViewManager.h> | |
#import <React/RCTBridge.h> | |
#import <React/RCTUIManager.h> | |
#import <React/RCTConvert+CoreLocation.h> | |
#import <React/RCTEventDispatcher.h> | |
#import <React/RCTViewManager.h> | |
#import <React/RCTConvert.h> | |
#import <React/UIView+React.h> | |
#import "RCTConvert+GMSMapViewType.h" | |
#import "AIRGoogleMap.h" | |
#import "AIRMapMarker.h" | |
#import "AIRMapPolyline.h" | |
#import "AIRMapPolygon.h" | |
#import "AIRMapCircle.h" | |
#import "SMCalloutView.h" | |
#import "AIRGoogleMapMarker.h" | |
#import "RCTConvert+AirMap.h" | |
#import <MapKit/MapKit.h> | |
#import <QuartzCore/QuartzCore.h> | |
static NSString *const RCTMapViewKey = @"MapView"; | |
@interface AIRGoogleMapManager() <GMSMapViewDelegate> | |
{ | |
BOOL didCallOnMapReady; | |
} | |
@end | |
@implementation AIRGoogleMapManager | |
RCT_EXPORT_MODULE() | |
- (UIView *)view | |
{ | |
[GMSServices setMetalRendererEnabled:YES]; | |
AIRGoogleMap *map = [AIRGoogleMap new]; | |
map.bridge = self.bridge; | |
map.delegate = self; | |
map.isAccessibilityElement = NO; | |
map.accessibilityElementsHidden = NO; | |
map.settings.consumesGesturesInView = NO; | |
UIPanGestureRecognizer *drag = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapDrag:)]; | |
[drag setMinimumNumberOfTouches:1]; | |
[drag setMaximumNumberOfTouches:1]; | |
[map addGestureRecognizer:drag]; | |
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapDrag:)]; | |
[map addGestureRecognizer:pinch]; | |
return map; | |
} | |
RCT_EXPORT_VIEW_PROPERTY(isAccessibilityElement, BOOL) | |
RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier, NSString) | |
RCT_EXPORT_VIEW_PROPERTY(initialCamera, GMSCameraPosition) | |
RCT_REMAP_VIEW_PROPERTY(camera, cameraProp, GMSCameraPosition) | |
RCT_EXPORT_VIEW_PROPERTY(initialRegion, MKCoordinateRegion) | |
RCT_EXPORT_VIEW_PROPERTY(region, MKCoordinateRegion) | |
RCT_EXPORT_VIEW_PROPERTY(showsBuildings, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(showsCompass, BOOL) | |
//RCT_EXPORT_VIEW_PROPERTY(showsScale, BOOL) // Not supported by GoogleMaps | |
RCT_EXPORT_VIEW_PROPERTY(showsTraffic, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(zoomEnabled, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(rotateEnabled, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(scrollEnabled, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(scrollDuringRotateOrZoomEnabled, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(zoomTapEnabled, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(showsUserLocation, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(showsMyLocationButton, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(showsIndoors, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(showsIndoorLevelPicker, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(customMapStyleString, NSString) | |
RCT_EXPORT_VIEW_PROPERTY(mapPadding, UIEdgeInsets) | |
RCT_REMAP_VIEW_PROPERTY(paddingAdjustmentBehavior, paddingAdjustmentBehaviorString, NSString) | |
RCT_EXPORT_VIEW_PROPERTY(onMapReady, RCTBubblingEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onMapLoaded, RCTBubblingEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onKmlReady, RCTBubblingEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onLongPress, RCTBubblingEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onPanDrag, RCTBubblingEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onUserLocationChange, RCTBubblingEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onMarkerPress, RCTDirectEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onRegionChange, RCTDirectEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onRegionChangeComplete, RCTDirectEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onPoiClick, RCTDirectEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onIndoorLevelActivated, RCTDirectEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onIndoorBuildingFocused, RCTDirectEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(mapType, GMSMapViewType) | |
RCT_EXPORT_VIEW_PROPERTY(minZoomLevel, CGFloat) | |
RCT_EXPORT_VIEW_PROPERTY(maxZoomLevel, CGFloat) | |
RCT_EXPORT_VIEW_PROPERTY(kmlSrc, NSString) | |
RCT_EXPORT_METHOD(isMarkerWithinScreen:(nonnull NSNumber *)reactTag | |
position:(CLLocationCoordinate2D)position | |
resolver: (RCTPromiseResolveBlock)resolve | |
rejecter:(RCTPromiseRejectBlock)reject) | |
{ | |
[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 AIRMap, got: %@", view); | |
} else { | |
AIRGoogleMap *mapView = (AIRGoogleMap *)view; | |
GMSVisibleRegion region = [mapView.projection visibleRegion]; | |
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithRegion:region]; | |
resolve(@{@"visible": @([bounds containsCoordinate:position])}); | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(getCamera:(nonnull NSNumber *)reactTag | |
resolver: (RCTPromiseResolveBlock)resolve | |
rejecter:(RCTPromiseRejectBlock)reject) | |
{ | |
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) { | |
id view = viewRegistry[reactTag]; | |
if (![view isKindOfClass:[AIRGoogleMap class]]) { | |
reject(@"Invalid argument", [NSString stringWithFormat:@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view], NULL); | |
} else { | |
AIRGoogleMap *mapView = (AIRGoogleMap *)view; | |
resolve(@{ | |
@"center": @{ | |
@"latitude": @(mapView.camera.target.latitude), | |
@"longitude": @(mapView.camera.target.longitude), | |
}, | |
@"pitch": @(mapView.camera.viewingAngle), | |
@"heading": @(mapView.camera.bearing), | |
@"zoom": @(mapView.camera.zoom), | |
}); | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(setCamera:(nonnull NSNumber *)reactTag | |
camera:(id)json) | |
{ | |
[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 *mapView = (AIRGoogleMap *)view; | |
GMSCameraPosition *camera = [RCTConvert GMSCameraPositionWithDefaults:json existingCamera:[mapView camera]]; | |
[mapView setCamera:camera]; | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(animateCamera:(nonnull NSNumber *)reactTag | |
withCamera:(id)json | |
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 { | |
[CATransaction begin]; | |
[CATransaction setAnimationDuration:duration/1000]; | |
AIRGoogleMap *mapView = (AIRGoogleMap *)view; | |
GMSCameraPosition *camera = [RCTConvert GMSCameraPositionWithDefaults:json existingCamera:[mapView camera]]; | |
[mapView animateToCameraPosition:camera]; | |
[CATransaction commit]; | |
} | |
}]; | |
} | |
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 { | |
// Core Animation must be used to control the animation's duration | |
// See http://stackoverflow.com/a/15663039/171744 | |
[CATransaction begin]; | |
[CATransaction setAnimationDuration:duration/1000]; | |
AIRGoogleMap *mapView = (AIRGoogleMap *)view; | |
GMSCameraPosition *camera = [AIRGoogleMap makeGMSCameraPositionFromMap:mapView andMKCoordinateRegion:region]; | |
[mapView animateToCameraPosition:camera]; | |
[CATransaction commit]; | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(fitToElements:(nonnull NSNumber *)reactTag | |
edgePadding:(nonnull NSDictionary *)edgePadding | |
animated:(BOOL)animated) | |
{ | |
[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 *mapView = (AIRGoogleMap *)view; | |
CLLocationCoordinate2D myLocation = ((AIRGoogleMapMarker *)(mapView.markers.firstObject)).realMarker.position; | |
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:myLocation coordinate:myLocation]; | |
for (AIRGoogleMapMarker *marker in mapView.markers) | |
bounds = [bounds includingCoordinate:marker.realMarker.position]; | |
GMSCameraUpdate* cameraUpdate; | |
if ([edgePadding count] != 0) { | |
// Set Map viewport | |
CGFloat top = [RCTConvert CGFloat:edgePadding[@"top"]]; | |
CGFloat right = [RCTConvert CGFloat:edgePadding[@"right"]]; | |
CGFloat bottom = [RCTConvert CGFloat:edgePadding[@"bottom"]]; | |
CGFloat left = [RCTConvert CGFloat:edgePadding[@"left"]]; | |
cameraUpdate = [GMSCameraUpdate fitBounds:bounds withEdgeInsets:UIEdgeInsetsMake(top, left, bottom, right)]; | |
} else { | |
cameraUpdate = [GMSCameraUpdate fitBounds:bounds withPadding:55.0f]; | |
} | |
if (animated) { | |
[mapView animateWithCameraUpdate: cameraUpdate]; | |
} else { | |
[mapView moveCamera: cameraUpdate]; | |
} | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(fitToSuppliedMarkers:(nonnull NSNumber *)reactTag | |
markers:(nonnull NSArray *)markers | |
edgePadding:(nonnull NSDictionary *)edgePadding | |
animated:(BOOL)animated) | |
{ | |
[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 *mapView = (AIRGoogleMap *)view; | |
NSPredicate *filterMarkers = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { | |
AIRGoogleMapMarker *marker = (AIRGoogleMapMarker *)evaluatedObject; | |
return [marker isKindOfClass:[AIRGoogleMapMarker class]] && [markers containsObject:marker.identifier]; | |
}]; | |
NSArray *filteredMarkers = [mapView.markers filteredArrayUsingPredicate:filterMarkers]; | |
CLLocationCoordinate2D myLocation = ((AIRGoogleMapMarker *)(filteredMarkers.firstObject)).realMarker.position; | |
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:myLocation coordinate:myLocation]; | |
for (AIRGoogleMapMarker *marker in filteredMarkers) | |
bounds = [bounds includingCoordinate:marker.realMarker.position]; | |
// Set Map viewport | |
CGFloat top = [RCTConvert CGFloat:edgePadding[@"top"]]; | |
CGFloat right = [RCTConvert CGFloat:edgePadding[@"right"]]; | |
CGFloat bottom = [RCTConvert CGFloat:edgePadding[@"bottom"]]; | |
CGFloat left = [RCTConvert CGFloat:edgePadding[@"left"]]; | |
GMSCameraUpdate* cameraUpdate = [GMSCameraUpdate fitBounds:bounds withEdgeInsets:UIEdgeInsetsMake(top, left, bottom, right)]; | |
if (animated) { | |
[mapView animateWithCameraUpdate:cameraUpdate | |
]; | |
} else { | |
[mapView moveCamera: cameraUpdate]; | |
} | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(fitToCoordinates:(nonnull NSNumber *)reactTag | |
coordinates:(nonnull NSArray<AIRMapCoordinate *> *)coordinates | |
edgePadding:(nonnull NSDictionary *)edgePadding | |
animated:(BOOL)animated) | |
{ | |
[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 *mapView = (AIRGoogleMap *)view; | |
CLLocationCoordinate2D myLocation = coordinates.firstObject.coordinate; | |
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:myLocation coordinate:myLocation]; | |
for (AIRMapCoordinate *coordinate in coordinates) | |
bounds = [bounds includingCoordinate:coordinate.coordinate]; | |
// Set Map viewport | |
CGFloat top = [RCTConvert CGFloat:edgePadding[@"top"]]; | |
CGFloat right = [RCTConvert CGFloat:edgePadding[@"right"]]; | |
CGFloat bottom = [RCTConvert CGFloat:edgePadding[@"bottom"]]; | |
CGFloat left = [RCTConvert CGFloat:edgePadding[@"left"]]; | |
GMSCameraUpdate *cameraUpdate = [GMSCameraUpdate fitBounds:bounds withEdgeInsets:UIEdgeInsetsMake(top, left, bottom, right)]; | |
if (animated) { | |
[mapView animateWithCameraUpdate: cameraUpdate]; | |
} else { | |
[mapView moveCamera: cameraUpdate]; | |
} | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(takeSnapshot:(nonnull NSNumber *)reactTag | |
withWidth:(nonnull NSNumber *)width | |
withHeight:(nonnull NSNumber *)height | |
withRegion:(MKCoordinateRegion)region | |
format:(nonnull NSString *)format | |
quality:(nonnull NSNumber *)quality | |
result:(nonnull NSString *)result | |
withCallback:(RCTResponseSenderBlock)callback) | |
{ | |
NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970]; | |
NSString *pathComponent = [NSString stringWithFormat:@"Documents/snapshot-%.20lf.%@", timeStamp, format]; | |
NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent: pathComponent]; | |
[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 AIRMap, got: %@", view); | |
} else { | |
AIRGoogleMap *mapView = (AIRGoogleMap *)view; | |
// TODO: currently we are ignoring width, height, region | |
UIGraphicsBeginImageContextWithOptions(mapView.frame.size, YES, 0.0f); | |
[mapView.layer renderInContext:UIGraphicsGetCurrentContext()]; | |
UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); | |
NSData *data; | |
if ([format isEqualToString:@"png"]) { | |
data = UIImagePNGRepresentation(image); | |
} | |
else if([format isEqualToString:@"jpg"]) { | |
data = UIImageJPEGRepresentation(image, quality.floatValue); | |
} | |
if ([result isEqualToString:@"file"]) { | |
[data writeToFile:filePath atomically:YES]; | |
callback(@[[NSNull null], filePath]); | |
} | |
else if ([result isEqualToString:@"base64"]) { | |
callback(@[[NSNull null], [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]]); | |
} | |
} | |
UIGraphicsEndImageContext(); | |
}]; | |
} | |
RCT_EXPORT_METHOD(pointForCoordinate:(nonnull NSNumber *)reactTag | |
coordinate:(NSDictionary *)coordinate | |
resolver: (RCTPromiseResolveBlock)resolve | |
rejecter:(RCTPromiseRejectBlock)reject) | |
{ | |
CLLocationCoordinate2D coord = | |
CLLocationCoordinate2DMake( | |
[coordinate[@"latitude"] doubleValue], | |
[coordinate[@"longitude"] doubleValue] | |
); | |
[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 AIRMap, got: %@", view); | |
} else { | |
AIRGoogleMap *mapView = (AIRGoogleMap *)view; | |
CGPoint touchPoint = [mapView.projection pointForCoordinate:coord]; | |
resolve(@{ | |
@"x": @(touchPoint.x), | |
@"y": @(touchPoint.y), | |
}); | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(coordinateForPoint:(nonnull NSNumber *)reactTag | |
point:(NSDictionary *)point | |
resolver: (RCTPromiseResolveBlock)resolve | |
rejecter:(RCTPromiseRejectBlock)reject) | |
{ | |
CGPoint pt = CGPointMake( | |
[point[@"x"] doubleValue], | |
[point[@"y"] doubleValue] | |
); | |
[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 AIRMap, got: %@", view); | |
} else { | |
AIRGoogleMap *mapView = (AIRGoogleMap *)view; | |
CLLocationCoordinate2D coordinate = [mapView.projection coordinateForPoint:pt]; | |
resolve(@{ | |
@"latitude": @(coordinate.latitude), | |
@"longitude": @(coordinate.longitude), | |
}); | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(getMarkersFrames:(nonnull NSNumber *)reactTag | |
onlyVisible:(BOOL)onlyVisible | |
resolver: (RCTPromiseResolveBlock)resolve | |
rejecter:(RCTPromiseRejectBlock)reject) | |
{ | |
[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 AIRMap, got: %@", view); | |
} else { | |
AIRGoogleMap *mapView = (AIRGoogleMap *)view; | |
resolve([mapView getMarkersFramesWithOnlyVisible:onlyVisible]); | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(getMapBoundaries:(nonnull NSNumber *)reactTag | |
resolver:(RCTPromiseResolveBlock)resolve | |
rejecter:(RCTPromiseRejectBlock)reject) | |
{ | |
[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 { | |
NSArray *boundingBox = [view getMapBoundaries]; | |
resolve(@{ | |
@"northEast" : @{ | |
@"longitude" : boundingBox[0][0], | |
@"latitude" : boundingBox[0][1] | |
}, | |
@"southWest" : @{ | |
@"longitude" : boundingBox[1][0], | |
@"latitude" : boundingBox[1][1] | |
} | |
}); | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(setMapBoundaries:(nonnull NSNumber *)reactTag | |
northEast:(CLLocationCoordinate2D)northEast | |
southWest:(CLLocationCoordinate2D)southWest) | |
{ | |
[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 *mapView = (AIRGoogleMap *)view; | |
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:northEast coordinate:southWest]; | |
mapView.cameraTargetBounds = bounds; | |
} | |
}]; | |
} | |
RCT_EXPORT_METHOD(setIndoorActiveLevelIndex:(nonnull NSNumber *)reactTag | |
levelIndex:(NSInteger) levelIndex) | |
{ | |
[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 *mapView = (AIRGoogleMap *)view; | |
if (!mapView.indoorDisplay) { | |
return; | |
} | |
if ( levelIndex < [mapView.indoorDisplay.activeBuilding.levels count]) { | |
mapView.indoorDisplay.activeLevel = mapView.indoorDisplay.activeBuilding.levels[levelIndex]; | |
} | |
} | |
}]; | |
} | |
+ (BOOL)requiresMainQueueSetup { | |
return YES; | |
} | |
- (NSDictionary *)constantsToExport { | |
return @{ @"legalNotice": [GMSServices openSourceLicenseInfo] }; | |
} | |
- (void)mapView:(GMSMapView *)mapView willMove:(BOOL)gesture{ | |
self.isGesture = gesture; | |
} | |
- (void)mapViewDidStartTileRendering:(GMSMapView *)mapView { | |
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView; | |
[googleMapView didPrepareMap]; | |
} | |
- (void)mapViewDidFinishTileRendering:(GMSMapView *)mapView { | |
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView; | |
[googleMapView mapViewDidFinishTileRendering]; | |
} | |
- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker { | |
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView; | |
return [googleMapView didTapMarker:marker]; | |
} | |
- (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSPolygon *)polygon { | |
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView; | |
[googleMapView didTapPolygon:polygon]; | |
} | |
- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate { | |
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView; | |
[googleMapView didTapAtCoordinate:coordinate]; | |
} | |
- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate { | |
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView; | |
[googleMapView didLongPressAtCoordinate:coordinate]; | |
} | |
- (void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition *)position { | |
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView; | |
[googleMapView didChangeCameraPosition:position isGesture:self.isGesture]; | |
} | |
- (void)mapView:(GMSMapView *)mapView idleAtCameraPosition:(GMSCameraPosition *)position { | |
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView; | |
[googleMapView idleAtCameraPosition:position isGesture:self.isGesture]; | |
} | |
- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker { | |
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker; | |
return [aMarker.fakeMarker markerInfoWindow];} | |
- (UIView *)mapView:(GMSMapView *)mapView markerInfoContents:(GMSMarker *)marker { | |
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker; | |
return [aMarker.fakeMarker markerInfoContents]; | |
} | |
- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker { | |
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker; | |
[aMarker.fakeMarker didTapInfoWindowOfMarker:aMarker]; | |
} | |
- (void)mapView:(GMSMapView *)mapView didBeginDraggingMarker:(GMSMarker *)marker { | |
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker; | |
[aMarker.fakeMarker didBeginDraggingMarker:aMarker]; | |
} | |
- (void)mapView:(GMSMapView *)mapView didEndDraggingMarker:(GMSMarker *)marker { | |
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker; | |
[aMarker.fakeMarker didEndDraggingMarker:aMarker]; | |
} | |
- (void)mapView:(GMSMapView *)mapView didDragMarker:(GMSMarker *)marker { | |
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker; | |
[aMarker.fakeMarker didDragMarker:aMarker]; | |
} | |
- (void)mapView:(GMSMapView *)mapView | |
didTapPOIWithPlaceID:(NSString *)placeID | |
name:(NSString *)name | |
location:(CLLocationCoordinate2D)location { | |
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView; | |
[googleMapView didTapPOIWithPlaceID:placeID name:name location:location]; | |
} | |
#pragma mark Gesture Recognizer Handlers | |
- (void)handleMapDrag:(UIPanGestureRecognizer*)recognizer { | |
AIRGoogleMap *map = (AIRGoogleMap *)recognizer.view; | |
if (!map.onPanDrag) return; | |
CGPoint touchPoint = [recognizer locationInView:map]; | |
CLLocationCoordinate2D coord = [map.projection coordinateForPoint:touchPoint]; | |
map.onPanDrag(@{ | |
@"coordinate": @{ | |
@"latitude": @(coord.latitude), | |
@"longitude": @(coord.longitude), | |
}, | |
@"position": @{ | |
@"x": @(touchPoint.x), | |
@"y": @(touchPoint.y), | |
}, | |
}); | |
} | |
@end | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from "react"; | |
import { | |
Animated as RNAnimated, | |
Animated, | |
NativeSyntheticEvent, | |
ViewProps, | |
} from "react-native"; | |
import { | |
CalloutPressEvent, | |
ClickEvent, | |
Frame, | |
LatLng, | |
MarkerDeselectEvent, | |
MarkerDragEvent, | |
MarkerDragStartEndEvent, | |
MarkerPressEvent, | |
MarkerSelectEvent, | |
Point, | |
Provider, | |
Region, | |
} from "./sharedTypes"; | |
import { | |
Address, | |
BoundingBox, | |
Camera, | |
ChangeEvent, | |
Details, | |
EdgePadding, | |
FitToOptions, | |
IndoorBuildingEvent, | |
IndoorLevelActivatedEvent, | |
KmlMapEvent, | |
LongPressEvent, | |
MapPressEvent, | |
MapStyleElement, | |
MapType, | |
MapTypes, | |
PanDragEvent, | |
PoiClickEvent, | |
SnapshotOptions, | |
UserLocationChangeEvent, | |
} from "./MapView.types"; | |
import { Modify } from "./sharedTypesInternal"; | |
import { MapViewNativeComponentType } from "./MapViewNativeComponent"; | |
export declare const MAP_TYPES: MapTypes; | |
export type MapViewProps = ViewProps & { | |
/** | |
* If `true` map will be cached and displayed as an image instead of being interactable, for performance usage. | |
* | |
* @default false | |
* @platform iOS: Apple maps only | |
* @platform Android: Supported | |
*/ | |
cacheEnabled?: boolean; | |
/** | |
* The camera view the map should display. | |
* | |
* Use the camera system, instead of the region system, if you need control over | |
* the pitch or heading. Using this will ignore the `region` property. | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
camera?: Camera; | |
/** | |
* If set, changes the position of the compass. | |
* | |
* @platform iOS: Apple Maps only | |
* @platform Android: Not supported | |
*/ | |
compassOffset?: Point; | |
/** | |
* Adds custom styling to the map component. | |
* See [README](https://github.com/react-native-maps/react-native-maps#customizing-the-map-style) for more information. | |
* | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
customMapStyle?: MapStyleElement[]; | |
/** | |
* If `true` the map will focus on the user's location. | |
* This only works if `showsUserLocation` is true and the user has shared their location. | |
* | |
* @default false | |
* @platform iOS: Apple Maps only | |
* @platform Android: Not supported | |
*/ | |
followsUserLocation?: boolean; | |
/** | |
* The initial camera view the map should use. Use this prop instead of `camera` | |
* only if you don't want to control the camera of the map besides the initial view. | |
* | |
* Use the camera system, instead of the region system, if you need control over | |
* the pitch or heading. | |
* | |
* Changing this prop after the component has mounted will not result in a camera change. | |
* | |
* This is similar to the `initialValue` prop of a text input. | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
initialCamera?: Camera; | |
/** | |
* The initial region to be displayed by the map. Use this prop instead of `region` | |
* only if you don't want to control the viewport of the map besides the initial region. | |
* | |
* Changing this prop after the component has mounted will not result in a region change. | |
* | |
* This is similar to the `initialValue` prop of a text input. | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
initialRegion?: Region; | |
/** | |
* The URL for KML file. | |
* | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
kmlSrc?: string; | |
/** | |
* If set, changes the position of the "Legal" label link in Apple maps. | |
* | |
* @platform iOS: Apple Maps only | |
* @platform Android: Not supported | |
*/ | |
legalLabelInsets?: EdgePadding; | |
/** | |
* Enables lite mode on Android | |
* | |
* @platform iOS: Not supported | |
* @platform Android: Supported | |
*/ | |
liteMode?: boolean; | |
/** | |
* Sets loading background color. | |
* | |
* @default `#FFFFFF` | |
* @platform iOS: Apple Maps only | |
* @platform Android: Supported | |
*/ | |
loadingBackgroundColor?: string; | |
/** | |
* If `true` a loading indicator will show while the map is loading. | |
* | |
* @default false | |
* @platform iOS: Apple Maps only | |
* @platform Android: Supported | |
*/ | |
loadingEnabled?: boolean; | |
/** | |
* Sets loading indicator color. | |
* | |
* @default `#606060` | |
* @platform iOS: Apple Maps only | |
* @platform Android: Supported | |
*/ | |
loadingIndicatorColor?: string; | |
/** | |
* Adds custom padding to each side of the map. Useful when map elements/markers are obscured. | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
mapPadding?: EdgePadding; | |
/** | |
* The map type to be displayed | |
* | |
* @default `standard` | |
* @platform iOS: hybrid | mutedStandard | sattelite | standard | terrain | |
* @platform Android: hybrid | none | sattelite | standard | terrain | |
*/ | |
mapType?: MapType; | |
/** | |
* TODO: Add documentation | |
* | |
* @platform iOS: Apple Maps only | |
* @platform Android: Not supported | |
*/ | |
maxDelta?: number; | |
/** | |
* Maximum zoom value for the map, must be between 0 and 20 | |
* | |
* @default 20 | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
maxZoomLevel?: number; | |
/** | |
* TODO: Add documentation | |
* | |
* @platform iOS: Apple Maps only | |
* @platform Android: Not supported | |
*/ | |
minDelta?: number; | |
/** | |
* Minimum zoom value for the map, must be between 0 and 20 | |
* | |
* @default 0 | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
minZoomLevel?: number; | |
/** | |
* If `false` the map won't move to the marker when pressed. | |
* | |
* @default true | |
* @platform iOS: Not supported | |
* @platform Android: Supported | |
*/ | |
moveOnMarkerPress?: boolean; | |
/** | |
* Callback that is called when a callout is tapped by the user. | |
* | |
* @platform iOS: Apple Maps only | |
* @platform Android: Supported | |
*/ | |
onCalloutPress?: (event: CalloutPressEvent) => void; | |
/** | |
* Callback that is called when user double taps on the map. | |
* | |
* @platform iOS: Apple Maps only | |
* @platform Android: Supported | |
*/ | |
onDoublePress?: (event: ClickEvent) => void; | |
/** | |
* Callback that is called when an indoor building is focused/unfocused | |
* | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
onIndoorBuildingFocused?: (event: IndoorBuildingEvent) => void; | |
/** | |
* Callback that is called when a level on indoor building is activated | |
* | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
onIndoorLevelActivated?: (event: IndoorLevelActivatedEvent) => void; | |
/** | |
* Callback that is called once the kml is fully loaded. | |
* | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
onKmlReady?: (event: KmlMapEvent) => void; | |
/** | |
* Callback that is called when user makes a "long press" somewhere on the map. | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
onLongPress?: (event: LongPressEvent) => void; | |
/** | |
* Callback that is called when the map has finished rendering all tiles. | |
* | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
onMapLoaded?: (event: NativeSyntheticEvent<{}>) => void; | |
/** | |
* Callback that is called once the map is ready. | |
* | |
* Event is optional, as the first onMapReady callback is intercepted | |
* on Android, and the event is not passed on. | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
onMapReady?: (event?: NativeSyntheticEvent<{}>) => void; | |
/** | |
* Callback that is called when a marker on the map becomes deselected. | |
* This will be called when the callout for that marker is about to be hidden. | |
* | |
* @platform iOS: Apple Maps only | |
* @platform Android: Not supported | |
*/ | |
onMarkerDeselect?: (event: MarkerDeselectEvent) => void; | |
/** | |
* Callback called continuously as a marker is dragged | |
* | |
* @platform iOS: Apple Maps only | |
* @platform Android: Supported | |
*/ | |
onMarkerDrag?: (event: MarkerDragEvent) => void; | |
/** | |
* Callback that is called when a drag on a marker finishes. | |
* This is usually the point you will want to setState on the marker's coordinate again | |
* | |
* @platform iOS: Apple Maps only | |
* @platform Android: Supported | |
*/ | |
onMarkerDragEnd?: (event: MarkerDragStartEndEvent) => void; | |
/** | |
* Callback that is called when the user initiates a drag on a marker (if it is draggable) | |
* | |
* @platform iOS: Apple Maps only | |
* @platform Android: Supported | |
*/ | |
onMarkerDragStart?: (event: MarkerDragStartEndEvent) => void; | |
/** | |
* Callback that is called when a marker on the map is tapped by the user. | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
onMarkerPress?: (event: MarkerPressEvent) => void; | |
/** | |
* Callback that is called when a marker on the map becomes selected. | |
* This will be called when the callout for that marker is about to be shown. | |
* | |
* @platform iOS: Apple Maps only. | |
* @platform Android: Not supported | |
*/ | |
onMarkerSelect?: (event: MarkerSelectEvent) => void; | |
/** | |
* Callback that is called when user presses and drags the map. | |
* **NOTE**: for iOS `scrollEnabled` should be set to false to trigger the event | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
onPanDrag?: (event: PanDragEvent) => void; | |
/** | |
* Callback that is called when user click on a POI. | |
* | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
onPoiClick?: (event: PoiClickEvent) => void; | |
/** | |
* Callback that is called when user taps on the map. | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
onPress?: (event: MapPressEvent) => void; | |
/** | |
* Callback that is called continuously when the region changes, such as when a user is dragging the map. | |
* `isGesture` property indicates if the move was from the user (true) or an animation (false). | |
* **Note**: `isGesture` is supported by Google Maps only. | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
onRegionChange?: (region: Region, details: Details) => void; | |
/** | |
* Callback that is called once when the region changes, such as when the user is done moving the map. | |
* `isGesture` property indicates if the move was from the user (true) or an animation (false). | |
* **Note**: `isGesture` is supported by Google Maps only. | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
onRegionChangeComplete?: (region: Region, details: Details) => void; | |
/** | |
* Callback that is called when the underlying map figures our users current location | |
* (coordinate also includes isFromMockProvider value for Android API 18 and above). | |
* Make sure **showsUserLocation** is set to *true*. | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
onUserLocationChange?: (event: UserLocationChangeEvent) => void; | |
/** | |
* Indicates how/when to affect padding with safe area insets | |
* | |
* @platform iOS: Google Maps only | |
* @platform Android: Not supported | |
*/ | |
paddingAdjustmentBehavior?: "always" | "automatic" | "never"; | |
/** | |
* If `false` the user won't be able to adjust the camera’s pitch angle. | |
* | |
* @default true | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
pitchEnabled?: boolean; | |
/** | |
* The map framework to use. | |
* Either `"google"` for GoogleMaps, otherwise `undefined` to use the native map framework (`MapKit` in iOS and `GoogleMaps` in android). | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
provider?: Provider; | |
/** | |
* The region to be displayed by the map. | |
* The region is defined by the center coordinates and the span of coordinates to display. | |
* | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
region?: Region; | |
/** | |
* If `false` the user won't be able to adjust the camera’s pitch angle. | |
* | |
* @default true | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
rotateEnabled?: boolean; | |
/** | |
* If `false` the map will stay centered while rotating or zooming. | |
* | |
* @default true | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
scrollDuringRotateOrZoomEnabled?: boolean; | |
/** | |
* If `false` the user won't be able to change the map region being displayed. | |
* | |
* @default true | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
scrollEnabled?: boolean; | |
/** | |
* A Boolean indicating whether the map displays extruded building information. | |
* | |
* @default true | |
* @platform iOS: Not supported | |
* @platform Android: Supported | |
*/ | |
showsBuildings?: boolean; | |
/** | |
* If `false` compass won't be displayed on the map. | |
* | |
* @default true | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
showsCompass?: boolean; | |
/** | |
* A Boolean indicating whether indoor level picker should be enabled. | |
* | |
* @default false | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
showsIndoorLevelPicker?: boolean; | |
/** | |
* A Boolean indicating whether indoor maps should be enabled. | |
* | |
* @default true | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
showsIndoors?: boolean; | |
/** | |
* If `false` hide the button to move map to the current user's location. | |
* | |
* @default true | |
* @platform iOS: Google Maps only | |
* @platform Android: Supported | |
*/ | |
showsMyLocationButton?: boolean; | |
/** | |
* If `false` points of interest won't be displayed on the map. | |
* TODO: DEPRECATED? Doesn't seem to do anything | |
* | |
* @default true | |
* @platform iOS: Maybe Apple Maps? | |
* @platform Android: Not supported | |
*/ | |
showsPointsOfInterest?: boolean; | |
/** | |
* A Boolean indicating whether the map shows scale information. | |
* | |
* @default true | |
* @platform iOS: Apple Maps only | |
* @platform Android: Not supported | |
*/ | |
showsScale?: boolean; | |
/** | |
* A Boolean value indicating whether the map displays traffic information. | |
* TODO: Look into android support | |
* | |
* @default false | |
* @platform iOS: Supported | |
* @platform Android: Not supported? | |
*/ | |
showsTraffic?: boolean; | |
/** | |
* If `true` the users location will be displayed on the map. | |
* | |
* This will cause iOS to ask for location permissions. | |
* For iOS see: [DOCS](https://github.com/react-native-maps/react-native-maps/blob/master/docs/installation.md#set-the-usage-description-property) | |
* @default false | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
showsUserLocation?: boolean; | |
/** | |
* Sets the tint color of the map. (Changes the color of the position indicator) | |
* | |
* @default System Blue | |
* @platform iOS: Apple Maps only | |
* @platform Android: Not supported | |
*/ | |
tintColor?: string; | |
/** | |
* If `false` will hide 'Navigate' and 'Open in Maps' buttons on marker press | |
* | |
* @default true | |
* @platform iOS: Not supported | |
* @platform Android: Supported | |
*/ | |
toolbarEnabled?: boolean; | |
/** | |
* Sets the map to the style selected. | |
* | |
* @default System setting | |
* @platform iOS: Apple Maps only (iOS >= 13.0) | |
* @platform Android: Not supported | |
*/ | |
userInterfaceStyle?: "light" | "dark"; | |
/** | |
* The title of the annotation for current user location. | |
* | |
* This only works if `showsUserLocation` is true. | |
* | |
* @default `My Location` | |
* @platform iOS: Apple Maps only | |
* @platform Android: Not supported | |
*/ | |
userLocationAnnotationTitle?: string; | |
/** | |
* If `true` clicking user location will show the default callout for userLocation annotation. | |
* | |
* @default false | |
* @platform iOS: Apple Maps only | |
* @platform Android: Not supported | |
*/ | |
userLocationCalloutEnabled?: boolean; | |
/** | |
* Fastest interval the application will actively acquire locations. | |
* | |
* See [Google APIs documentation](https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html) | |
* | |
* @default 5000 | |
* @platform iOS: Not supported | |
* @platform Android: Supported | |
*/ | |
userLocationFastestInterval?: number; | |
/** | |
* Set power priority of user location tracking. | |
* | |
* See [Google APIs documentation](https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html) | |
* | |
* @default `high` | |
* @platform iOS: Not supported | |
* @platform Android: Supported | |
*/ | |
userLocationPriority?: "balanced" | "high" | "low" | "passive"; | |
/** | |
* Interval of user location updates in milliseconds. | |
* | |
* See [Google APIs documentation](https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html) | |
* | |
* @default 5000 | |
* @platform iOS: Not supported | |
* @platform Android: Supported | |
*/ | |
userLocationUpdateInterval?: number; | |
/** | |
* If `false` the zoom control at the bottom right of the map won't be visible. | |
* | |
* @default true | |
* @platform iOS: Not supported | |
* @platform Android: Supported | |
*/ | |
zoomControlEnabled?: boolean; | |
/** | |
* If `false` the user won't be able to pinch/zoom the map. | |
* | |
* TODO: Why is the Android reactprop defaultvalue set to false? | |
* | |
* @default true | |
* @platform iOS: Supported | |
* @platform Android: Supported | |
*/ | |
zoomEnabled?: boolean; | |
/** | |
* If `false` the user won't be able to double tap to zoom the map. | |
* **Note:** But it will greatly decrease delay of tap gesture recognition. | |
* | |
* @default true | |
* @platform iOS: Google Maps only | |
* @platform Android: Not supported | |
*/ | |
zoomTapEnabled?: boolean; | |
}; | |
type ModifiedProps = Modify< | |
MapViewProps, | |
{ | |
region?: MapViewProps["region"] | null; | |
initialRegion?: MapViewProps["initialRegion"] | null; | |
} | |
>; | |
export type NativeProps = Omit< | |
ModifiedProps, | |
"customMapStyle" | "onRegionChange" | "onRegionChangeComplete" | |
> & { | |
ref: React.RefObject<MapViewNativeComponentType>; | |
customMapStyleString?: string; | |
handlePanDrag?: boolean; | |
onChange?: (e: ChangeEvent) => void; | |
}; | |
type State = { | |
isReady: boolean; | |
}; | |
declare class MapView extends React.Component<MapViewProps, State> { | |
static Animated: Animated.AnimatedComponent<typeof MapView>; | |
private map; | |
constructor(props: MapViewProps); | |
/** | |
* @deprecated Will be removed in v2.0.0, as setNativeProps is not a thing in fabric. | |
* See https://reactnative.dev/docs/new-architecture-library-intro#migrating-off-setnativeprops | |
*/ | |
setNativeProps(props: Partial<NativeProps>): void; | |
private _onMapReady; | |
private _onChange; | |
isMarkerWithinScreen(markers: string[]): void; | |
getCamera(): Promise<Camera>; | |
setCamera(camera: Partial<Camera>): void; | |
animateCamera( | |
camera: Partial<Camera>, | |
opts?: { | |
duration?: number; | |
}, | |
): void; | |
animateToRegion(region: Region, duration?: number): void; | |
fitToElements(options?: FitToOptions): void; | |
fitToSuppliedMarkers(markers: string[], options?: FitToOptions): void; | |
fitToCoordinates(coordinates?: LatLng[], options?: FitToOptions): void; | |
/** | |
* Get visible boudaries | |
* | |
* @return Promise Promise with the bounding box ({ northEast: <LatLng>, southWest: <LatLng> }) | |
*/ | |
getMapBoundaries(): Promise<BoundingBox>; | |
setMapBoundaries(northEast: LatLng, southWest: LatLng): void; | |
setIndoorActiveLevelIndex(activeLevelIndex: number): void; | |
/** | |
* Takes a snapshot of the map and saves it to a picture | |
* file or returns the image as a base64 encoded string. | |
* | |
* @param args Configuration options | |
* @param [args.width] Width of the rendered map-view (when omitted actual view width is used). | |
* @param [args.height] Height of the rendered map-view (when omitted actual height is used). | |
* @param [args.region] Region to render (Only supported on iOS). | |
* @param [args.format] Encoding format ('png', 'jpg') (default: 'png'). | |
* @param [args.quality] Compression quality (only used for jpg) (default: 1.0). | |
* @param [args.result] Result format ('file', 'base64') (default: 'file'). | |
* | |
* @return Promise Promise with either the file-uri or base64 encoded string | |
*/ | |
takeSnapshot(args: SnapshotOptions): Promise<string>; | |
/** | |
* Convert a coordinate to address by using default Geocoder | |
* | |
* @param coordinate Coordinate | |
* @param [coordinate.latitude] Latitude | |
* @param [coordinate.longitude] Longitude | |
* | |
* @return Promise with return type Address | |
*/ | |
addressForCoordinate(coordinate: LatLng): Promise<Address>; | |
/** | |
* Convert a map coordinate to user-space point | |
* | |
* @param coordinate Coordinate | |
* @param [coordinate.latitude] Latitude | |
* @param [coordinate.longitude] Longitude | |
* | |
* @return Promise Promise with the point ({ x: Number, y: Number }) | |
*/ | |
pointForCoordinate(coordinate: LatLng): Promise<Point>; | |
/** | |
* Convert a user-space point to a map coordinate | |
* | |
* @param point Point | |
* @param [point.x] X | |
* @param [point.x] Y | |
* | |
* @return Promise Promise with the coordinate ({ latitude: Number, longitude: Number }) | |
*/ | |
coordinateForPoint(point: Point): Promise<LatLng>; | |
/** | |
* Get markers' centers and frames in user-space coordinates | |
* | |
* @param onlyVisible boolean true to include only visible markers, false to include all | |
* | |
* @return Promise Promise with { <identifier>: { point: Point, frame: Frame } } | |
*/ | |
getMarkersFrames(onlyVisible?: boolean): Promise<{ | |
[key: string]: { | |
point: Point; | |
frame: Frame; | |
}; | |
}>; | |
/** | |
* Get bounding box from region | |
* | |
* @param region Region | |
* | |
* @return Object Object bounding box ({ northEast: <LatLng>, southWest: <LatLng> }) | |
*/ | |
boundingBoxForRegion(region: Region): BoundingBox; | |
private _mapManagerCommand; | |
private _getHandle; | |
private _runCommand; | |
render(): JSX.Element; | |
} | |
export declare const AnimatedMapView: RNAnimated.AnimatedComponent< | |
typeof MapView | |
>; | |
export declare const enableLatestRenderer: () => any; | |
export default MapView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var __createBinding = | |
(this && this.__createBinding) || | |
(Object.create | |
? function (o, m, k, k2) { | |
if (k2 === undefined) k2 = k; | |
var desc = Object.getOwnPropertyDescriptor(m, k); | |
if ( | |
!desc || | |
("get" in desc ? !m.__esModule : desc.writable || desc.configurable) | |
) { | |
desc = { | |
enumerable: true, | |
get: function () { | |
return m[k]; | |
}, | |
}; | |
} | |
Object.defineProperty(o, k2, desc); | |
} | |
: function (o, m, k, k2) { | |
if (k2 === undefined) k2 = k; | |
o[k2] = m[k]; | |
}); | |
var __setModuleDefault = | |
(this && this.__setModuleDefault) || | |
(Object.create | |
? function (o, v) { | |
Object.defineProperty(o, "default", { enumerable: true, value: v }); | |
} | |
: function (o, v) { | |
o["default"] = v; | |
}); | |
var __importStar = | |
(this && this.__importStar) || | |
function (mod) { | |
if (mod && mod.__esModule) return mod; | |
var result = {}; | |
if (mod != null) | |
for (var k in mod) | |
if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) | |
__createBinding(result, mod, k); | |
__setModuleDefault(result, mod); | |
return result; | |
}; | |
Object.defineProperty(exports, "__esModule", { value: true }); | |
exports.enableLatestRenderer = | |
exports.AnimatedMapView = | |
exports.MAP_TYPES = | |
void 0; | |
const React = __importStar(require("react")); | |
const react_native_1 = require("react-native"); | |
const decorateMapComponent_1 = require("./decorateMapComponent"); | |
const ProviderConstants = __importStar(require("./ProviderConstants")); | |
const MapViewNativeComponent_1 = require("./MapViewNativeComponent"); | |
exports.MAP_TYPES = { | |
STANDARD: "standard", | |
SATELLITE: "satellite", | |
HYBRID: "hybrid", | |
TERRAIN: "terrain", | |
NONE: "none", | |
MUTEDSTANDARD: "mutedStandard", | |
}; | |
const GOOGLE_MAPS_ONLY_TYPES = [ | |
exports.MAP_TYPES.TERRAIN, | |
exports.MAP_TYPES.NONE, | |
]; | |
class MapView extends React.Component { | |
static Animated; | |
map; | |
constructor(props) { | |
super(props); | |
this.map = React.createRef(); | |
this.state = { | |
isReady: react_native_1.Platform.OS === "ios", | |
}; | |
this._onMapReady = this._onMapReady.bind(this); | |
this._onChange = this._onChange.bind(this); | |
} | |
/** | |
* @deprecated Will be removed in v2.0.0, as setNativeProps is not a thing in fabric. | |
* See https://reactnative.dev/docs/new-architecture-library-intro#migrating-off-setnativeprops | |
*/ | |
setNativeProps(props) { | |
console.warn( | |
"setNativeProps is deprecated and will be removed in next major release", | |
); | |
// @ts-ignore | |
this.map.current?.setNativeProps(props); | |
} | |
_onMapReady() { | |
const { onMapReady } = this.props; | |
this.setState({ isReady: true }, () => { | |
if (onMapReady) { | |
onMapReady(); | |
} | |
}); | |
} | |
_onChange({ nativeEvent }) { | |
const isGesture = nativeEvent.isGesture; | |
const details = { isGesture }; | |
if (nativeEvent.continuous) { | |
if (this.props.onRegionChange) { | |
this.props.onRegionChange(nativeEvent.region, details); | |
} | |
} else if (this.props.onRegionChangeComplete) { | |
this.props.onRegionChangeComplete(nativeEvent.region, details); | |
} | |
} | |
isMarkerWithinScreen(marker) { | |
if (react_native_1.Platform.OS === "android") { | |
return react_native_1.NativeModules.AirMapModule.isMarkerWithinScreen( | |
this._getHandle(), | |
marker.coordinate, | |
); | |
} else if (react_native_1.Platform.OS === "ios") { | |
return this._runCommand("isMarkerWithinScreen", [marker.coordinate]); | |
} | |
return Promise.reject( | |
"isMarkerWithinScreen not supported on this platform", | |
); | |
} | |
getCamera() { | |
if (react_native_1.Platform.OS === "android") { | |
return react_native_1.NativeModules.AirMapModule.getCamera( | |
this._getHandle(), | |
); | |
} else if (react_native_1.Platform.OS === "ios") { | |
return this._runCommand("getCamera", []); | |
} | |
return Promise.reject("getCamera not supported on this platform"); | |
} | |
setCamera(camera) { | |
if (this.map.current) { | |
MapViewNativeComponent_1.Commands.setCamera(this.map.current, camera); | |
} | |
} | |
animateCamera(camera, opts) { | |
if (this.map.current) { | |
MapViewNativeComponent_1.Commands.animateCamera( | |
this.map.current, | |
camera, | |
opts?.duration ? opts.duration : 500, | |
); | |
} | |
} | |
animateToRegion(region, duration = 500) { | |
if (this.map.current) { | |
MapViewNativeComponent_1.Commands.animateToRegion( | |
this.map.current, | |
region, | |
duration, | |
); | |
} | |
} | |
fitToElements(options = {}) { | |
if (this.map.current) { | |
const { | |
edgePadding = { top: 0, right: 0, bottom: 0, left: 0 }, | |
animated = true, | |
} = options; | |
MapViewNativeComponent_1.Commands.fitToElements( | |
this.map.current, | |
edgePadding, | |
animated, | |
); | |
} | |
} | |
fitToSuppliedMarkers(markers, options = {}) { | |
if (this.map.current) { | |
const { | |
edgePadding = { top: 0, right: 0, bottom: 0, left: 0 }, | |
animated = true, | |
} = options; | |
MapViewNativeComponent_1.Commands.fitToSuppliedMarkers( | |
this.map.current, | |
markers, | |
edgePadding, | |
animated, | |
); | |
} | |
} | |
fitToCoordinates(coordinates = [], options = {}) { | |
if (this.map.current) { | |
const { | |
edgePadding = { top: 0, right: 0, bottom: 0, left: 0 }, | |
animated = true, | |
} = options; | |
MapViewNativeComponent_1.Commands.fitToCoordinates( | |
this.map.current, | |
coordinates, | |
edgePadding, | |
animated, | |
); | |
} | |
} | |
/** | |
* Get visible boudaries | |
* | |
* @return Promise Promise with the bounding box ({ northEast: <LatLng>, southWest: <LatLng> }) | |
*/ | |
async getMapBoundaries() { | |
if (react_native_1.Platform.OS === "android") { | |
return await react_native_1.NativeModules.AirMapModule.getMapBoundaries( | |
this._getHandle(), | |
); | |
} else if (react_native_1.Platform.OS === "ios") { | |
return await this._runCommand("getMapBoundaries", []); | |
} | |
return Promise.reject("getMapBoundaries not supported on this platform"); | |
} | |
setMapBoundaries(northEast, southWest) { | |
if (this.map.current) { | |
MapViewNativeComponent_1.Commands.setMapBoundaries( | |
this.map.current, | |
northEast, | |
southWest, | |
); | |
} | |
} | |
setIndoorActiveLevelIndex(activeLevelIndex) { | |
if (this.map.current) { | |
MapViewNativeComponent_1.Commands.setIndoorActiveLevelIndex( | |
this.map.current, | |
activeLevelIndex, | |
); | |
} | |
} | |
/** | |
* Takes a snapshot of the map and saves it to a picture | |
* file or returns the image as a base64 encoded string. | |
* | |
* @param args Configuration options | |
* @param [args.width] Width of the rendered map-view (when omitted actual view width is used). | |
* @param [args.height] Height of the rendered map-view (when omitted actual height is used). | |
* @param [args.region] Region to render (Only supported on iOS). | |
* @param [args.format] Encoding format ('png', 'jpg') (default: 'png'). | |
* @param [args.quality] Compression quality (only used for jpg) (default: 1.0). | |
* @param [args.result] Result format ('file', 'base64') (default: 'file'). | |
* | |
* @return Promise Promise with either the file-uri or base64 encoded string | |
*/ | |
takeSnapshot(args) { | |
// Sanitize inputs | |
const config = { | |
width: args.width || 0, | |
height: args.height || 0, | |
region: args.region || {}, | |
format: args.format || "png", | |
quality: args.quality || 1.0, | |
result: args.result || "file", | |
}; | |
if (config.format !== "png" && config.format !== "jpg") { | |
throw new Error("Invalid format specified"); | |
} | |
if (config.result !== "file" && config.result !== "base64") { | |
throw new Error("Invalid result specified"); | |
} | |
// Call native function | |
if (react_native_1.Platform.OS === "android") { | |
return react_native_1.NativeModules.AirMapModule.takeSnapshot( | |
this._getHandle(), | |
config, | |
); | |
} else if (react_native_1.Platform.OS === "ios") { | |
return new Promise((resolve, reject) => { | |
this._runCommand("takeSnapshot", [ | |
config.width, | |
config.height, | |
config.region, | |
config.format, | |
config.quality, | |
config.result, | |
(err, snapshot) => { | |
if (err) { | |
reject(err); | |
} else { | |
resolve(snapshot); | |
} | |
}, | |
]); | |
}); | |
} | |
return Promise.reject("takeSnapshot not supported on this platform"); | |
} | |
/** | |
* Convert a coordinate to address by using default Geocoder | |
* | |
* @param coordinate Coordinate | |
* @param [coordinate.latitude] Latitude | |
* @param [coordinate.longitude] Longitude | |
* | |
* @return Promise with return type Address | |
*/ | |
addressForCoordinate(coordinate) { | |
if (react_native_1.Platform.OS === "android") { | |
return react_native_1.NativeModules.AirMapModule.getAddressFromCoordinates( | |
this._getHandle(), | |
coordinate, | |
); | |
} else if (react_native_1.Platform.OS === "ios") { | |
return this._runCommand("getAddressFromCoordinates", [coordinate]); | |
} | |
return Promise.reject("getAddress not supported on this platform"); | |
} | |
/** | |
* Convert a map coordinate to user-space point | |
* | |
* @param coordinate Coordinate | |
* @param [coordinate.latitude] Latitude | |
* @param [coordinate.longitude] Longitude | |
* | |
* @return Promise Promise with the point ({ x: Number, y: Number }) | |
*/ | |
pointForCoordinate(coordinate) { | |
if (react_native_1.Platform.OS === "android") { | |
return react_native_1.NativeModules.AirMapModule.pointForCoordinate( | |
this._getHandle(), | |
coordinate, | |
); | |
} else if (react_native_1.Platform.OS === "ios") { | |
return this._runCommand("pointForCoordinate", [coordinate]); | |
} | |
return Promise.reject("pointForCoordinate not supported on this platform"); | |
} | |
/** | |
* Convert a user-space point to a map coordinate | |
* | |
* @param point Point | |
* @param [point.x] X | |
* @param [point.x] Y | |
* | |
* @return Promise Promise with the coordinate ({ latitude: Number, longitude: Number }) | |
*/ | |
coordinateForPoint(point) { | |
if (react_native_1.Platform.OS === "android") { | |
return react_native_1.NativeModules.AirMapModule.coordinateForPoint( | |
this._getHandle(), | |
point, | |
); | |
} else if (react_native_1.Platform.OS === "ios") { | |
return this._runCommand("coordinateForPoint", [point]); | |
} | |
return Promise.reject("coordinateForPoint not supported on this platform"); | |
} | |
/** | |
* Get markers' centers and frames in user-space coordinates | |
* | |
* @param onlyVisible boolean true to include only visible markers, false to include all | |
* | |
* @return Promise Promise with { <identifier>: { point: Point, frame: Frame } } | |
*/ | |
getMarkersFrames(onlyVisible = false) { | |
if (react_native_1.Platform.OS === "ios") { | |
return this._runCommand("getMarkersFrames", [onlyVisible]); | |
} | |
return Promise.reject("getMarkersFrames not supported on this platform"); | |
} | |
/** | |
* Get bounding box from region | |
* | |
* @param region Region | |
* | |
* @return Object Object bounding box ({ northEast: <LatLng>, southWest: <LatLng> }) | |
*/ | |
boundingBoxForRegion(region) { | |
return { | |
northEast: { | |
latitude: region.latitude + region.latitudeDelta / 2, | |
longitude: region.longitude + region.longitudeDelta / 2, | |
}, | |
southWest: { | |
latitude: region.latitude - region.latitudeDelta / 2, | |
longitude: region.longitude - region.longitudeDelta / 2, | |
}, | |
}; | |
} | |
_mapManagerCommand(name) { | |
return react_native_1.NativeModules[ | |
`${(0, decorateMapComponent_1.getNativeMapName)( | |
this.props.provider, | |
)}Manager` | |
][name]; | |
} | |
_getHandle() { | |
return (0, react_native_1.findNodeHandle)(this.map.current); | |
} | |
_runCommand(name, args) { | |
if (react_native_1.Platform.OS === "ios") { | |
return this._mapManagerCommand(name)(this._getHandle(), ...args); | |
} else { | |
return Promise.reject( | |
`Invalid platform was passed: ${react_native_1.Platform.OS}`, | |
); | |
} | |
} | |
render() { | |
let props; | |
if (this.state.isReady) { | |
props = { | |
region: null, | |
initialRegion: null, | |
onChange: this._onChange, | |
onMapReady: this._onMapReady, | |
ref: this.map, | |
customMapStyleString: this.props.customMapStyle | |
? JSON.stringify(this.props.customMapStyle) | |
: undefined, | |
...this.props, | |
}; | |
if ( | |
react_native_1.Platform.OS === "ios" && | |
props.provider === ProviderConstants.PROVIDER_DEFAULT && | |
props.mapType && | |
GOOGLE_MAPS_ONLY_TYPES.includes(props.mapType) | |
) { | |
props.mapType = exports.MAP_TYPES.STANDARD; | |
} | |
if (props.onPanDrag) { | |
props.handlePanDrag = !!props.onPanDrag; | |
} | |
} else { | |
props = { | |
style: this.props.style, | |
region: null, | |
initialRegion: this.props.initialRegion || null, | |
initialCamera: this.props.initialCamera, | |
ref: this.map, | |
onChange: this._onChange, | |
onMapReady: this._onMapReady, | |
onLayout: this.props.onLayout, | |
customMapStyleString: this.props.customMapStyle | |
? JSON.stringify(this.props.customMapStyle) | |
: undefined, | |
}; | |
} | |
if (react_native_1.Platform.OS === "android" && this.props.liteMode) { | |
return ( | |
<decorateMapComponent_1.ProviderContext.Provider | |
value={this.props.provider} | |
> | |
<AIRMapLite {...props} /> | |
</decorateMapComponent_1.ProviderContext.Provider> | |
); | |
} | |
const AIRMap = getNativeMapComponent(this.props.provider); | |
return ( | |
<decorateMapComponent_1.ProviderContext.Provider | |
value={this.props.provider} | |
> | |
<AIRMap {...props} /> | |
</decorateMapComponent_1.ProviderContext.Provider> | |
); | |
} | |
} | |
const airMaps = { | |
default: (0, react_native_1.requireNativeComponent)("AIRMap"), | |
google: () => null, | |
}; | |
if (react_native_1.Platform.OS === "android") { | |
airMaps.google = airMaps.default; | |
} else { | |
airMaps.google = decorateMapComponent_1.googleMapIsInstalled | |
? (0, react_native_1.requireNativeComponent)("AIRGoogleMap") | |
: (0, decorateMapComponent_1.createNotSupportedComponent)( | |
"react-native-maps: AirGoogleMaps dir must be added to your xCode project to support GoogleMaps on iOS.", | |
); | |
} | |
const getNativeMapComponent = (provider) => airMaps[provider || "default"]; | |
const AIRMapLite = react_native_1.UIManager.getViewManagerConfig("AIRMapLite") | |
? (0, react_native_1.requireNativeComponent)("AIRMapLite") | |
: () => null; | |
exports.AnimatedMapView = | |
react_native_1.Animated.createAnimatedComponent(MapView); | |
const enableLatestRenderer = () => { | |
if (react_native_1.Platform.OS !== "android") { | |
return; | |
} | |
return react_native_1.NativeModules.AirMapModule.enableLatestRenderer(); | |
}; | |
exports.enableLatestRenderer = enableLatestRenderer; | |
MapView.Animated = exports.AnimatedMapView; | |
exports.default = MapView; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment