diff --git a/index.ios.js b/index.ios.js index 89adacd..97c4764 100644 --- a/index.ios.js +++ b/index.ios.js @@ -8,6 +8,10 @@ import { findNodeHandle } from 'react-native'; +import cloneDeep from 'lodash/cloneDeep'; +import clone from 'lodash/clone'; +import isEqual from 'lodash/isEqual'; + const { MapboxGLManager } = NativeModules; const { mapStyles, userTrackingMode, userLocationVerticalAlignment, unknownResourceCount } = MapboxGLManager; @@ -206,9 +210,6 @@ class MapView extends Component { onTap: PropTypes.func, contentInset: PropTypes.array, userLocationVerticalAlignment: PropTypes.number, - onOfflineProgressDidChange: PropTypes.func, - onOfflineMaxAllowedMapboxTiles: PropTypes.func, - onOfflineDidRecieveError: PropTypes.func, onChangeUserTrackingMode: PropTypes.func }; @@ -231,10 +232,59 @@ class MapView extends Component { compassIsHidden: false }; + componentWillReceiveProps(newProps) { + const oldKeys = clone(this._annotations); + const itemsToAdd = []; + const itemsToRemove = []; + + newProps.annotations.forEach(annotation => { + const id = annotation.id; + if (!isEqual(this._annotations[id], annotation)) { + this._annotations[id] = cloneDeep(annotation); + itemsToAdd.push(annotation); + } + oldKeys[id] = null; + }); + + for (let key in oldKeys) { + if (oldKeys[key]) { + delete this._annotations[key]; + itemsToRemove.push(key); + } + } + + MapboxGLManager.spliceAnnotations(findNodeHandle(this), false, itemsToRemove, itemsToAdd); + } + + _native = null; + + onNativeComponentMount = (ref) => { + if (this._native === ref) { return; } + this._native = ref; + + MapboxGLManager.spliceAnnotations(findNodeHandle(this), true, [], this.props.annotations); + + let annotations = this.props.annotations.reduce((acc, annotation) => { + acc[annotation.id] = cloneDeep(annotation); + return acc; + }, {}); + + this._annotations = annotations; + }; + + setNativeProps(nativeProps) { + this._native && this._native.setNativeProps(nativeProps); + } + + componentWillUnmount() { + this._native = null; + } + render() { return ( + onChangeUserTrackingMode={this._onChangeUserTrackingMode} + /> ); } } diff --git a/ios/RCTMapboxGL/RCTMapboxGL.h b/ios/RCTMapboxGL/RCTMapboxGL.h index 84a0e7c..a484bfc 100644 --- a/ios/RCTMapboxGL/RCTMapboxGL.h +++ b/ios/RCTMapboxGL/RCTMapboxGL.h @@ -40,7 +40,7 @@ - (void)selectAnnotation:(NSString*)selectedId animated:(BOOL)animated; // Annotation management -- (void)addAnnotation:(NSObject *)annotation; +- (void)upsertAnnotation:(NSObject *)annotation; - (void)removeAnnotation:(NSString*)selectedIdentifier; - (void)removeAllAnnotations; diff --git a/ios/RCTMapboxGL/RCTMapboxGL.m b/ios/RCTMapboxGL/RCTMapboxGL.m index 2a71392..035fff3 100644 --- a/ios/RCTMapboxGL/RCTMapboxGL.m +++ b/ios/RCTMapboxGL/RCTMapboxGL.m @@ -101,7 +101,9 @@ _isChangingUserTracking = YES; _map.userTrackingMode = _userTrackingMode; _isChangingUserTracking = NO; - [_map addAnnotations:[_annotations allValues]]; + for (NSString * annotationId in _annotations) { + [_map addAnnotation:_annotations[annotationId]]; + } [self addSubview:_map]; [self layoutSubviews]; @@ -122,14 +124,19 @@ // Annotation management -- (void)addAnnotation:(RCTMGLAnnotation *) annotation { +- (void)upsertAnnotation:(RCTMGLAnnotation *) annotation { NSString * identifier = [annotation id]; if (!identifier || [identifier length] == 0) { RCTLogError(@"field `id` is required on all annotations"); return; } + + RCTMGLAnnotation * oldAnnotation = [_annotations objectForKey:identifier]; [_annotations setObject:annotation forKey:identifier]; [_map addAnnotation:annotation]; + if (oldAnnotation) { + [_map removeAnnotation:oldAnnotation]; + } } - (void)removeAnnotation:(NSString*)selectedIdentifier diff --git a/ios/RCTMapboxGL/RCTMapboxGLManager.m b/ios/RCTMapboxGL/RCTMapboxGLManager.m index da5dde9..b7dac2b 100644 --- a/ios/RCTMapboxGL/RCTMapboxGLManager.m +++ b/ios/RCTMapboxGL/RCTMapboxGLManager.m @@ -73,23 +73,6 @@ RCT_CUSTOM_VIEW_PROPERTY(contentInset, UIEdgeInsetsMake, RCTMapboxGL) view.contentInset = inset; } -RCT_CUSTOM_VIEW_PROPERTY(annotations, CLLocationCoordinate2D, RCTMapboxGL) -{ - if ([json isKindOfClass:[NSArray class]]) { - [view removeAllAnnotations]; - - id annotationObject; - NSEnumerator *enumerator = [json objectEnumerator]; - - while (annotationObject = [enumerator nextObject]) { - CLLocationCoordinate2D coordinate = [RCTConvert CLLocationCoordinate2D:annotationObject]; - if (CLLocationCoordinate2DIsValid(coordinate)){ - [view addAnnotation:convertToMGLAnnotation(annotationObject)]; - } - } - } -} - // Constants - (NSDictionary *)constantsToExport @@ -306,6 +289,28 @@ RCT_EXPORT_METHOD(removePack:(NSString*)packName // View methods +RCT_EXPORT_METHOD(spliceAnnotations:(nonnull NSNumber *)reactTag + deleteAll:(BOOL)deleteAll + toDelete:(nonnull NSArray *)toDelete + toAdd:(nonnull NSArray *)toAdd) +{ + [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + RCTMapboxGL *mapView = viewRegistry[reactTag]; + + if (deleteAll) { + [mapView removeAllAnnotations]; + } else { + for (NSString * key in toDelete) { + [mapView removeAnnotation:key]; + } + } + + for (NSObject * annotationObject in toAdd) { + [mapView upsertAnnotation:convertToMGLAnnotation(annotationObject)]; + } + }]; +} + RCT_EXPORT_METHOD(getCenterCoordinateZoomLevel:(nonnull NSNumber *)reactTag callback:(RCTResponseSenderBlock)callback) { diff --git a/package.json b/package.json index 6535881..e06b8a8 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "eslint-plugin-react": "^3.11.3" }, "dependencies": { - "babel-eslint": "^4.1.6" + "babel-eslint": "^4.1.6", + "lodash": "^4.13.1" } }