From ca0cc491ba1fb8783dcf264cd335e0f4eec09f30 Mon Sep 17 00:00:00 2001 From: Marius Petcu Date: Sat, 2 Jul 2016 21:19:03 +0300 Subject: [PATCH] Backport annotations to Android --- .../ReactNativeMapboxGLAnnotationFactory.java | 150 ++++++++++++++++++ .../ReactNativeMapboxGLManager.java | 26 ++- .../ReactNativeMapboxGLView.java | 103 ++++++++++++ index.js | 6 +- 4 files changed, 282 insertions(+), 3 deletions(-) create mode 100644 android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLAnnotationFactory.java diff --git a/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLAnnotationFactory.java b/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLAnnotationFactory.java new file mode 100644 index 0000000..cf6df71 --- /dev/null +++ b/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLAnnotationFactory.java @@ -0,0 +1,150 @@ +package com.mapbox.reactnativemapboxgl; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.support.annotation.RequiresPermission; +import android.view.View; + +import com.facebook.react.bridge.ReadableMap; +import com.mapbox.mapboxsdk.annotations.Icon; +import com.mapbox.mapboxsdk.annotations.IconFactory; +import com.mapbox.mapboxsdk.annotations.Marker; +import com.mapbox.mapboxsdk.annotations.MarkerOptions; +import com.mapbox.mapboxsdk.annotations.Polygon; +import com.mapbox.mapboxsdk.annotations.PolygonOptions; +import com.mapbox.mapboxsdk.annotations.PolylineOptions; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.MapView; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +public class ReactNativeMapboxGLAnnotationFactory { + + static Drawable drawableFromDrawableName(View view, String drawableName) { + Bitmap x; + int resID = view.getResources().getIdentifier(drawableName, "drawable", view.getContext().getApplicationContext().getPackageName()); + x = BitmapFactory.decodeResource(view.getResources(), resID); + return new BitmapDrawable(view.getResources(), x); + } + + public static Drawable drawableFromUrl(View view, String url) throws IOException { + Bitmap x; + + HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); + connection.connect(); + InputStream input = connection.getInputStream(); + + x = BitmapFactory.decodeStream(input); + return new BitmapDrawable(view.getResources(), x); + } + + public static MarkerOptions markerFromJS(ReadableMap annotation, View view) { + MarkerOptions marker = new MarkerOptions(); + + double latitude = annotation.getArray("coordinates").getDouble(0); + double longitude = annotation.getArray("coordinates").getDouble(1); + LatLng markerCenter = new LatLng(latitude, longitude); + marker.position(markerCenter); + + if (annotation.hasKey("title")) { + String title = annotation.getString("title"); + marker.title(title); + } + + if (annotation.hasKey("subtitle")) { + String subtitle = annotation.getString("subtitle"); + marker.snippet(subtitle); + } + + if (annotation.hasKey("annotationImage")) { + ReadableMap annotationImage = annotation.getMap("annotationImage"); + String annotationURL = annotationImage.getString("url"); + try { + Drawable image; + if (annotationURL.startsWith("image!")) { + image = drawableFromDrawableName(view, annotationURL.replace("image!", "")); + } else { + image = drawableFromUrl(view, annotationURL); + } + + IconFactory iconFactory = IconFactory.getInstance(view.getContext()); + Icon icon; + if (annotationImage.hasKey("height") && annotationImage.hasKey("width")) { + float scale = view.getResources().getDisplayMetrics().density; + int height = Math.round((float)annotationImage.getInt("height") * scale); + int width = Math.round((float)annotationImage.getInt("width") * scale); + icon = iconFactory.fromDrawable(image, width, height); + } else { + icon = iconFactory.fromDrawable(image); + } + + marker.icon(icon); + } catch (Exception e) { + e.printStackTrace(); + } + } + return marker; + } + + static PolylineOptions polylineFromJS(ReadableMap annotation) { + PolylineOptions polyline = new PolylineOptions(); + + int coordSize = annotation.getArray("coordinates").size(); + for (int p = 0; p < coordSize; p++) { + double latitude = annotation.getArray("coordinates").getArray(p).getDouble(0); + double longitude = annotation.getArray("coordinates").getArray(p).getDouble(1); + polyline.add(new LatLng(latitude, longitude)); + } + + if (annotation.hasKey("alpha")) { + double strokeAlpha = annotation.getDouble("alpha"); + polyline.alpha((float) strokeAlpha); + } + + if (annotation.hasKey("strokeColor")) { + int strokeColor = Color.parseColor(annotation.getString("strokeColor")); + polyline.color(strokeColor); + } + + if (annotation.hasKey("strokeWidth")) { + float strokeWidth = annotation.getInt("strokeWidth"); + polyline.width(strokeWidth); + } + + return polyline; + } + + static PolygonOptions polygonFromJS(ReadableMap annotation) { + PolygonOptions polygon = new PolygonOptions(); + + int coordSize = annotation.getArray("coordinates").size(); + for (int p = 0; p < coordSize; p++) { + double latitude = annotation.getArray("coordinates").getArray(p).getDouble(0); + double longitude = annotation.getArray("coordinates").getArray(p).getDouble(1); + polygon.add(new LatLng(latitude, longitude)); + } + + if (annotation.hasKey("alpha")) { + double fillAlpha = annotation.getDouble("alpha"); + polygon.alpha((float) fillAlpha); + } + + if (annotation.hasKey("fillColor")) { + int fillColor = Color.parseColor(annotation.getString("fillColor")); + polygon.fillColor(fillColor); + } + + if (annotation.hasKey("strokeColor")) { + int strokeColor = Color.parseColor(annotation.getString("strokeColor")); + polygon.strokeColor(strokeColor); + } + + return polygon; + } +} diff --git a/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLManager.java b/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLManager.java index 6146f47..9797b8b 100644 --- a/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLManager.java +++ b/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLManager.java @@ -358,10 +358,32 @@ public class ReactNativeMapboxGLManager extends SimpleViewManager _annotations = new HashMap(); + private Map _markerOptions = new HashMap(); + private Map _polylineOptions = new HashMap(); + private Map _polygonOptions = new HashMap(); + private android.os.Handler _trackingModeHandler; @UiThread @@ -161,6 +172,20 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements _map.setOnMyLocationTrackingModeChangeListener(this); _map.setOnMyBearingTrackingModeChangeListener(this); _map.setOnMyLocationChangeListener(this); + + // Create annotations + for (Map.Entry entry : _markerOptions.entrySet()) { + _annotations.put(entry.getKey(), _map.addMarker(entry.getValue())); + } + _markerOptions.clear(); + for (Map.Entry entry : _polylineOptions.entrySet()) { + _annotations.put(entry.getKey(), _map.addPolyline(entry.getValue())); + } + _polylineOptions.clear(); + for (Map.Entry entry : _polygonOptions.entrySet()) { + _annotations.put(entry.getKey(), _map.addPolygon(entry.getValue())); + } + _polygonOptions.clear(); } private void destroyMapView() { @@ -490,4 +515,82 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements _map.animateCamera(update, duration, new CameraCallback(callback)); } } + + // Annotations + + @Nullable Annotation _removeAnnotation(String name, boolean keep) { + if (_map == null) { + _markerOptions.remove(name); + _polylineOptions.remove(name); + _polygonOptions.remove(name); + return null; + } + Annotation annotation = _annotations.remove(name); + if (annotation == null) { return null; } + if (keep) { return annotation; } + _map.removeAnnotation(annotation); + return null; + } + + public void removeAnnotation(String name) { + _removeAnnotation(name, false); + } + + public void removeAllAnnotations() { + _markerOptions.clear(); + _polygonOptions.clear(); + _polygonOptions.clear(); + _annotations.clear(); + if (_map != null) { + _map.removeAnnotations(); + } + } + + public void setMarker(String name, MarkerOptions options) { + Annotation removed = _removeAnnotation(name, true); + + if (_map == null) { + _markerOptions.put(name, options); + } else { + Annotation annotation = _map.addMarker(options); + _annotations.put(name, annotation); + } + + if (removed != null) { _map.removeAnnotation(removed); } + } + + public void setPolyline(String name, PolylineOptions options) { + Annotation removed = _removeAnnotation(name, true); + + if (_map == null) { + _polylineOptions.put(name, options); + } else { + Annotation annotation = _map.addPolyline(options); + _annotations.put(name, annotation); + } + + if (removed != null) { _map.removeAnnotation(removed); } + } + + public void setPolygon(String name, PolygonOptions options) { + Annotation removed = _removeAnnotation(name, true); + + if (_map == null) { + _polygonOptions.put(name, options); + } else { + Annotation annotation = _map.addPolygon(options); + _annotations.put(name, annotation); + } + + if (removed != null) { _map.removeAnnotation(removed); } + } + + public void selectAnnotation(String name, boolean animated) { + if (_map == null) { return; } + Annotation annotation = _annotations.get(name); + if (annotation == null) { return; } + if (!(annotation instanceof Marker)) { return; } + Marker marker = (Marker)annotation; + _map.selectMarker(marker); + } } diff --git a/index.js b/index.js index 32290ab..65cb79f 100644 --- a/index.js +++ b/index.js @@ -362,7 +362,11 @@ class MapView extends Component { } const MapboxGLView = requireNativeComponent('RCTMapboxGL', MapView, { - nativeOnly: { onChange: true } + nativeOnly: { + onChange: true, + enableOnRegionDidChange: true, + enableOnRegionWillChange: true + } }); const Mapbox = {