mirror of
https://github.com/status-im/react-native-mapbox-gl.git
synced 2026-09-02 05:51:12 +00:00
Removed old android and ios projects
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.Annotation;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
|
||||
public interface RNMGLAnnotationOptions {
|
||||
public abstract Annotation addToMap(MapboxMap map);
|
||||
}
|
||||
-244
@@ -1,244 +0,0 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.mapbox.mapboxsdk.annotations.Annotation;
|
||||
import com.mapbox.mapboxsdk.annotations.Icon;
|
||||
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class RNMGLMarkerOptions implements RNMGLAnnotationOptions {
|
||||
protected MarkerOptions _options;
|
||||
|
||||
public RNMGLMarkerOptions(MarkerOptions options) {
|
||||
_options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation addToMap(MapboxMap map) {
|
||||
return map.addMarker(_options);
|
||||
}
|
||||
}
|
||||
|
||||
class RNMGLPolylineOptions implements RNMGLAnnotationOptions {
|
||||
protected PolylineOptions _options;
|
||||
|
||||
public RNMGLPolylineOptions(PolylineOptions options) {
|
||||
_options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation addToMap(MapboxMap map) {
|
||||
return map.addPolyline(_options);
|
||||
}
|
||||
}
|
||||
|
||||
class RNMGLPolygonOptions implements RNMGLAnnotationOptions {
|
||||
protected PolygonOptions _options;
|
||||
|
||||
public RNMGLPolygonOptions(PolygonOptions options) {
|
||||
_options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation addToMap(MapboxMap map) {
|
||||
return map.addPolygon(_options);
|
||||
}
|
||||
}
|
||||
|
||||
public class RNMGLAnnotationOptionsFactory {
|
||||
|
||||
public static RNMGLAnnotationOptions annotationOptionsFromJS(ReadableMap annotation, Context context) {
|
||||
String type = annotation.getString("type");
|
||||
|
||||
if (type.equals("point")) {
|
||||
return markerOptionsFromJS(annotation, context);
|
||||
} else if (type.equals("polyline")) {
|
||||
return polylineOptionsFromJS(annotation);
|
||||
} else if (type.equals("polygon")) {
|
||||
return polygonOptionsFromJS(annotation);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Drawable drawableFromDrawableName(Context context, String drawableName) {
|
||||
int resID = context.getResources().getIdentifier(drawableName, "drawable", context.getApplicationContext().getPackageName());
|
||||
return ContextCompat.getDrawable(context, resID);
|
||||
}
|
||||
|
||||
static Drawable drawableFromUrl(Context context, String url) throws IOException {
|
||||
// This doesn't currently work, as it throws NetworkOnMainThreadException
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||
connection.connect();
|
||||
InputStream input = connection.getInputStream();
|
||||
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(input);
|
||||
return new BitmapDrawable(context.getResources(), bitmap);
|
||||
}
|
||||
|
||||
static Map<String, Icon> iconCache = new HashMap();
|
||||
|
||||
static Icon iconFromSourceAndSize(Context context, ReadableMap source, int width, int height) throws IOException {
|
||||
String path = source.getString("uri");
|
||||
String cacheKey = path + "||" + width + "||" + height;
|
||||
Icon icon = iconCache.get(cacheKey);
|
||||
if (icon != null) { return icon; }
|
||||
|
||||
Drawable drawable;
|
||||
try {
|
||||
drawable = drawableFromUrl(context, path);
|
||||
} catch (MalformedURLException ex) {
|
||||
drawable = drawableFromDrawableName(context, path);
|
||||
}
|
||||
|
||||
IconFactory iconFactory = IconFactory.getInstance(context);
|
||||
|
||||
int intrinsicWidth = drawable.getIntrinsicWidth();
|
||||
int intrinsicHeight = drawable.getIntrinsicHeight();
|
||||
|
||||
if (width < 0) { width = intrinsicWidth; }
|
||||
if (height < 0) { height = intrinsicHeight; }
|
||||
|
||||
// Check if a rescale would be superfluous
|
||||
if ((drawable instanceof BitmapDrawable) && width == intrinsicWidth && height == intrinsicHeight) {
|
||||
icon = iconFactory.fromBitmap(((BitmapDrawable)drawable).getBitmap());
|
||||
} else {
|
||||
// Conversion taken from mapbox-gl-native/issues/7897#issuecomment-277302450
|
||||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
|
||||
drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
//DrawableCompat.setTint(drawable, colorRes);
|
||||
drawable.draw(canvas);
|
||||
icon = iconFactory.fromBitmap(bitmap);
|
||||
}
|
||||
|
||||
iconCache.put(cacheKey, icon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
static RNMGLAnnotationOptions markerOptionsFromJS(ReadableMap annotation, Context context) {
|
||||
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");
|
||||
ReadableMap annotationSource = annotationImage.getMap("source");
|
||||
try {
|
||||
int width = -1;
|
||||
int height = -1;
|
||||
|
||||
if (annotationImage.hasKey("height") && annotationImage.hasKey("width")) {
|
||||
float scale = context.getResources().getDisplayMetrics().density;
|
||||
height = Math.round((float)annotationImage.getInt("height") * scale);
|
||||
width = Math.round((float)annotationImage.getInt("width") * scale);
|
||||
}
|
||||
|
||||
marker.icon(iconFromSourceAndSize(context, annotationSource, width, height));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return new RNMGLMarkerOptions(marker);
|
||||
}
|
||||
|
||||
static RNMGLAnnotationOptions polylineOptionsFromJS(ReadableMap annotation) {
|
||||
PolylineOptions polyline = new PolylineOptions();
|
||||
|
||||
ReadableArray coordinates = annotation.getArray("coordinates");
|
||||
int coordinatesSize = coordinates.size();
|
||||
if (coordinatesSize > 0) {
|
||||
LatLng[] points = new LatLng[coordinatesSize];
|
||||
ReadableArray coordinate;
|
||||
for (int p = 0; p < coordinatesSize; p++) {
|
||||
coordinate = coordinates.getArray(p);
|
||||
points[p] = new LatLng(
|
||||
coordinate.getDouble(0),
|
||||
coordinate.getDouble(1)
|
||||
);
|
||||
}
|
||||
polyline.add(points);
|
||||
}
|
||||
|
||||
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 new RNMGLPolylineOptions(polyline);
|
||||
}
|
||||
|
||||
static RNMGLAnnotationOptions polygonOptionsFromJS(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 new RNMGLPolygonOptions(polygon);
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.facebook.react.views.view.ReactViewGroup;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class RNMGLAnnotationView extends ReactViewGroup {
|
||||
|
||||
private Set<PropertyListener> propertyListeners;
|
||||
private String annotationId;
|
||||
private LatLng coordinate;
|
||||
private float layoutWidth;
|
||||
private float layoutHeight;
|
||||
|
||||
public RNMGLAnnotationView(Context context) {
|
||||
super(context);
|
||||
this.propertyListeners = new HashSet<>();
|
||||
}
|
||||
|
||||
// Properties
|
||||
|
||||
public String getAnnotationId() {
|
||||
return annotationId;
|
||||
}
|
||||
|
||||
public void setAnnotationId(String annotationId) {
|
||||
this.annotationId = annotationId;
|
||||
}
|
||||
|
||||
public LatLng getCoordinate() {
|
||||
return coordinate;
|
||||
}
|
||||
|
||||
public void setCoordinate(LatLng coordinate) {
|
||||
this.coordinate = coordinate;
|
||||
fireUpdateEvent();
|
||||
}
|
||||
|
||||
// React layout
|
||||
|
||||
public void setLayoutDimensions(float layoutWidth, float layoutHeight) {
|
||||
this.layoutWidth = layoutWidth;
|
||||
this.layoutHeight = layoutHeight;
|
||||
}
|
||||
|
||||
public float getLayoutWidth() {
|
||||
return layoutWidth;
|
||||
}
|
||||
|
||||
public float getLayoutHeight() {
|
||||
return layoutHeight;
|
||||
}
|
||||
|
||||
// Listeners
|
||||
|
||||
public void addPropertyListener(PropertyListener propertyListener) {
|
||||
propertyListeners.add(propertyListener);
|
||||
}
|
||||
|
||||
public void removePropertyListener(PropertyListener propertyListener) {
|
||||
propertyListeners.remove(propertyListener);
|
||||
}
|
||||
|
||||
private void fireUpdateEvent() {
|
||||
for (PropertyListener listener : propertyListeners) {
|
||||
listener.propertiesUpdated(this);
|
||||
}
|
||||
}
|
||||
|
||||
public interface PropertyListener {
|
||||
void propertiesUpdated(RNMGLAnnotationView view);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class RNMGLAnnotationViewManager extends ViewGroupManager<RNMGLAnnotationView> {
|
||||
|
||||
private static final String NAME = "RCTMapboxAnnotation";
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RNMGLAnnotationView createViewInstance(ThemedReactContext reactContext) {
|
||||
return new RNMGLAnnotationView(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends LayoutShadowNode> getShadowNodeClass() {
|
||||
return SizeReportingShadowNode.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutShadowNode createShadowNodeInstance() {
|
||||
return new SizeReportingShadowNode();
|
||||
}
|
||||
|
||||
// Props
|
||||
|
||||
@ReactProp(name = "id")
|
||||
public void setAnnotationId(RNMGLAnnotationView view, String value) {
|
||||
view.setAnnotationId(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "coordinate")
|
||||
public void setCoordinate(RNMGLAnnotationView view, ReadableMap map) {
|
||||
LatLng coordinate = new LatLng();
|
||||
coordinate.setLatitude(map.getDouble("latitude"));
|
||||
coordinate.setLongitude(map.getDouble("longitude"));
|
||||
view.setCoordinate(coordinate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateExtraData(RNMGLAnnotationView view, Object extraData) {
|
||||
// This is called from the {@link SizeReportingShadowNode}. We cache
|
||||
// the width and height so that we can set the correct size on the marker
|
||||
// view annotations in ReactNativeMapboxGLView RNMGLCustomMarkerViewAdapter.
|
||||
HashMap<String, Float> data = (HashMap<String, Float>) extraData;
|
||||
float width = data.get("width");
|
||||
float height = data.get("height");
|
||||
view.setLayoutDimensions(width, height);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerView;
|
||||
|
||||
public class RNMGLCustomMarkerView extends MarkerView {
|
||||
|
||||
private String annotationId;
|
||||
|
||||
public RNMGLCustomMarkerView(BaseMarkerViewOptions baseMarkerViewOptions, String annotationId) {
|
||||
super(baseMarkerViewOptions);
|
||||
this.annotationId = annotationId;
|
||||
}
|
||||
|
||||
public String getAnnotationId() {
|
||||
return annotationId;
|
||||
}
|
||||
}
|
||||
-90
@@ -1,90 +0,0 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.Icon;
|
||||
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
|
||||
public class RNMGLCustomMarkerViewOptions extends BaseMarkerViewOptions<RNMGLCustomMarkerView, RNMGLCustomMarkerViewOptions> {
|
||||
private String annotationId;
|
||||
|
||||
public RNMGLCustomMarkerViewOptions() {}
|
||||
|
||||
protected RNMGLCustomMarkerViewOptions(Parcel in) {
|
||||
position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
|
||||
snippet(in.readString());
|
||||
title(in.readString());
|
||||
flat(in.readByte() != 0);
|
||||
anchor(in.readFloat(), in.readFloat());
|
||||
infoWindowAnchor(in.readFloat(), in.readFloat());
|
||||
rotation(in.readFloat());
|
||||
visible(in.readByte() != 0);
|
||||
alpha(in.readFloat());
|
||||
if (in.readByte() != 0) {
|
||||
// this means we have an icon
|
||||
String iconId = in.readString();
|
||||
Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
|
||||
Icon icon = IconFactory.recreate(iconId, iconBitmap);
|
||||
icon(icon);
|
||||
}
|
||||
annotationId(in.readString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RNMGLCustomMarkerViewOptions getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RNMGLCustomMarkerView getMarker() {
|
||||
return new RNMGLCustomMarkerView(this, annotationId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeParcelable(getPosition(), flags);
|
||||
out.writeString(getSnippet());
|
||||
out.writeString(getTitle());
|
||||
out.writeByte((byte) (isFlat() ? 1 : 0));
|
||||
out.writeFloat(getAnchorU());
|
||||
out.writeFloat(getAnchorV());
|
||||
out.writeFloat(getInfoWindowAnchorU());
|
||||
out.writeFloat(getInfoWindowAnchorV());
|
||||
out.writeFloat(getRotation());
|
||||
out.writeByte((byte) (isVisible() ? 1 : 0));
|
||||
out.writeFloat(getAlpha());
|
||||
Icon icon = getIcon();
|
||||
out.writeByte((byte) (icon != null ? 1 : 0));
|
||||
if (icon != null) {
|
||||
out.writeString(getIcon().getId());
|
||||
out.writeParcelable(getIcon().getBitmap(), flags);
|
||||
}
|
||||
out.writeString(annotationId);
|
||||
}
|
||||
|
||||
public RNMGLCustomMarkerViewOptions annotationId(String annotationId) {
|
||||
this.annotationId = annotationId;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<RNMGLCustomMarkerViewOptions> CREATOR
|
||||
= new Parcelable.Creator<RNMGLCustomMarkerViewOptions>() {
|
||||
public RNMGLCustomMarkerViewOptions createFromParcel(Parcel in) {
|
||||
return new RNMGLCustomMarkerViewOptions(in);
|
||||
}
|
||||
|
||||
public RNMGLCustomMarkerViewOptions[] newArray(int size) {
|
||||
return new RNMGLCustomMarkerViewOptions[size];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
|
||||
/**
|
||||
* Prefix all the internal event names with mapbox so that they don't clobber or get clobbered
|
||||
* by events with the same name in other libraries. None of this will be visible to the user.
|
||||
* The callback names will remain normal.
|
||||
*/
|
||||
public class ReactNativeMapboxGLEventTypes {
|
||||
public static String ON_REGION_DID_CHANGE = "mapbox.onRegionDidChange";
|
||||
public static String ON_REGION_WILL_CHANGE = "mapbox.onRegionWillChange";
|
||||
public static String ON_OPEN_ANNOTATION = "mapbox.onOpenAnnotation";
|
||||
public static String ON_RIGHT_ANNOTATION_TAPPED = "mapbox.onRightAnnotationTapped";
|
||||
public static String ON_CHANGE_USER_TRACKING_MODE = "mapbox.onChangeUserTrackingMode";
|
||||
public static String ON_UPDATE_USER_LOCATION = "mapbox.onUpdateUserLocation";
|
||||
public static String ON_LONG_PRESS = "mapbox.onLongPress";
|
||||
public static String ON_TAP = "mapbox.onTap";
|
||||
public static String ON_FINISH_LOADING_MAP = "mapbox.onFinishLoadingMap";
|
||||
public static String ON_START_LOADING_MAP = "mapbox.onStartLoadingMap";
|
||||
public static String ON_LOCATE_USER_FAILED = "mapbox.onLocateUserFailed";
|
||||
|
||||
private ReactNativeMapboxGLEventTypes() {}
|
||||
}
|
||||
@@ -1,489 +0,0 @@
|
||||
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.modules.core.RCTNativeAppEventEmitter;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdate;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
import com.mapbox.mapboxsdk.constants.MapboxConstants;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ReactNativeMapboxGLManager extends ViewGroupManager<ReactNativeMapboxGLView> {
|
||||
|
||||
private static final String REACT_CLASS = "RCTMapboxGL";
|
||||
|
||||
private ReactApplicationContext _context;
|
||||
private Map<ReactNativeMapboxGLView, List<View>> _childViews;
|
||||
private Set<ChildListener> _childListeners;
|
||||
|
||||
public ReactNativeMapboxGLManager(ReactApplicationContext context) {
|
||||
super();
|
||||
_context = context;
|
||||
_childViews = new HashMap<>();
|
||||
_childListeners = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return REACT_CLASS;
|
||||
}
|
||||
|
||||
public ReactApplicationContext getContext() {
|
||||
return _context;
|
||||
}
|
||||
|
||||
public List<RNMGLAnnotationView> getAnnotationViews(ReactNativeMapboxGLView parent) {
|
||||
List<RNMGLAnnotationView> annotationViews = new ArrayList<>();
|
||||
for (View view : _childViews.get(parent)) {
|
||||
if (RNMGLAnnotationView.class.equals(view.getClass())) {
|
||||
annotationViews.add((RNMGLAnnotationView) view);
|
||||
}
|
||||
}
|
||||
return annotationViews;
|
||||
}
|
||||
|
||||
// Lifecycle methods
|
||||
|
||||
@Override
|
||||
public ReactNativeMapboxGLView createViewInstance(ThemedReactContext context) {
|
||||
return new ReactNativeMapboxGLView(context, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAfterUpdateTransaction(ReactNativeMapboxGLView view) {
|
||||
super.onAfterUpdateTransaction(view);
|
||||
view.onAfterUpdateTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDropViewInstance(ReactNativeMapboxGLView view) {
|
||||
view.onDrop();
|
||||
}
|
||||
|
||||
// Event types
|
||||
@Override
|
||||
public @Nullable Map<String, Object> getExportedCustomDirectEventTypeConstants() {
|
||||
return MapBuilder.<String,Object>builder()
|
||||
.put(ReactNativeMapboxGLEventTypes.ON_REGION_DID_CHANGE, MapBuilder.of("registrationName", "onRegionDidChange"))
|
||||
.put(ReactNativeMapboxGLEventTypes.ON_REGION_WILL_CHANGE, MapBuilder.of("registrationName", "onRegionWillChange"))
|
||||
.put(ReactNativeMapboxGLEventTypes.ON_OPEN_ANNOTATION, MapBuilder.of("registrationName", "onOpenAnnotation"))
|
||||
.put(ReactNativeMapboxGLEventTypes.ON_RIGHT_ANNOTATION_TAPPED, MapBuilder.of("registrationName", "onRightAnnotationTapped"))
|
||||
.put(ReactNativeMapboxGLEventTypes.ON_CHANGE_USER_TRACKING_MODE, MapBuilder.of("registrationName", "onChangeUserTrackingMode"))
|
||||
.put(ReactNativeMapboxGLEventTypes.ON_UPDATE_USER_LOCATION, MapBuilder.of("registrationName", "onUpdateUserLocation"))
|
||||
.put(ReactNativeMapboxGLEventTypes.ON_LONG_PRESS, MapBuilder.of("registrationName", "onLongPress"))
|
||||
.put(ReactNativeMapboxGLEventTypes.ON_TAP, MapBuilder.of("registrationName", "onTap"))
|
||||
.put(ReactNativeMapboxGLEventTypes.ON_FINISH_LOADING_MAP, MapBuilder.of("registrationName", "onFinishLoadingMap"))
|
||||
.put(ReactNativeMapboxGLEventTypes.ON_START_LOADING_MAP, MapBuilder.of("registrationName", "onStartLoadingMap"))
|
||||
.put(ReactNativeMapboxGLEventTypes.ON_LOCATE_USER_FAILED, MapBuilder.of("registrationName", "onLocateUserFailed"))
|
||||
.build();
|
||||
}
|
||||
|
||||
// Children
|
||||
|
||||
public interface ChildListener {
|
||||
void childAdded(View child);
|
||||
void childRemoved(View child);
|
||||
}
|
||||
|
||||
public void addChildListener(ChildListener listener) {
|
||||
_childListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeChildListener(ChildListener listener) {
|
||||
_childListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(ReactNativeMapboxGLView parent, View child, int index) {
|
||||
if (!_childViews.containsKey(parent)) {
|
||||
_childViews.put(parent, new ArrayList<View>());
|
||||
}
|
||||
_childViews.get(parent).add(index, child);
|
||||
if (!RNMGLAnnotationView.class.equals(child.getClass())) {
|
||||
super.addView(parent, child, getRealIndex(parent, index));
|
||||
}
|
||||
for (ChildListener listener : _childListeners) {
|
||||
listener.childAdded(child);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount(ReactNativeMapboxGLView parent) {
|
||||
return _childViews.get(parent).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildAt(ReactNativeMapboxGLView parent, int index) {
|
||||
return _childViews.get(parent).get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewAt(ReactNativeMapboxGLView parent, int index) {
|
||||
int realIndex = getRealIndex(parent, index);
|
||||
View child = _childViews.get(parent).remove(index);
|
||||
if (!RNMGLAnnotationView.class.equals(child.getClass())) {
|
||||
super.removeViewAt(parent, realIndex);
|
||||
}
|
||||
for (ChildListener listener : _childListeners) {
|
||||
listener.childRemoved(child);
|
||||
}
|
||||
if (_childViews.get(parent).isEmpty()) {
|
||||
_childViews.remove(parent);
|
||||
}
|
||||
}
|
||||
|
||||
private int getRealIndex(ReactNativeMapboxGLView parent, int index) {
|
||||
int annotationViews = 0;
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (RNMGLAnnotationView.class.equals(getChildAt(parent, i).getClass())) {
|
||||
annotationViews++;
|
||||
}
|
||||
}
|
||||
return index - annotationViews;
|
||||
}
|
||||
|
||||
// Props
|
||||
|
||||
@ReactProp(name = "initialZoomLevel")
|
||||
public void setInitialZoomLevel(ReactNativeMapboxGLView view, double value) {
|
||||
view.setInitialZoomLevel(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "minimumZoomLevel")
|
||||
public void setMinumumZoomLevel(ReactNativeMapboxGLView view, double value) {
|
||||
view.setMinimumZoomLevel(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "maximumZoomLevel")
|
||||
public void setMaxumumZoomLevel(ReactNativeMapboxGLView view, double value) {
|
||||
view.setMaximumZoomLevel(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "initialDirection")
|
||||
public void setInitialDirection(ReactNativeMapboxGLView view, double value) {
|
||||
view.setInitialDirection(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "initialCenterCoordinate")
|
||||
public void setInitialCenterCoordinate(ReactNativeMapboxGLView view, ReadableMap coord) {
|
||||
double lat = coord.getDouble("latitude");
|
||||
double lon = coord.getDouble("longitude");
|
||||
view.setInitialCenterCoordinate(lat, lon);
|
||||
}
|
||||
|
||||
@ReactProp(name = "enableOnRegionDidChange")
|
||||
public void setEnableOnRegionDidChange(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setEnableOnRegionDidChange(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "enableOnRegionWillChange")
|
||||
public void setEnableOnRegionWillChange(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setEnableOnRegionWillChange(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "debugActive")
|
||||
public void setDebugActive(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setDebugActive(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "rotateEnabled")
|
||||
public void setRotateEnabled(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setRotateEnabled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "scrollEnabled")
|
||||
public void setScrollEnabled(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setScrollEnabled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "zoomEnabled")
|
||||
public void setZoomEnabled(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setZoomEnabled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "pitchEnabled")
|
||||
public void setPitchEnabled(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setPitchEnabled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "annotationsPopUpEnabled")
|
||||
public void setAnnotationsPopUpEnabled(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setAnnotationsPopUpEnabled(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "showsUserLocation")
|
||||
public void setShowsUserLocation(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setShowsUserLocation(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "styleURL")
|
||||
public void setStyleUrl(ReactNativeMapboxGLView view, @Nonnull String styleURL) {
|
||||
view.setStyleURL(styleURL);
|
||||
}
|
||||
|
||||
@ReactProp(name = "userTrackingMode")
|
||||
public void setUserTrackingMode(ReactNativeMapboxGLView view, int mode) {
|
||||
view.setLocationTracking(ReactNativeMapboxGLModule.locationTrackingModes[mode]);
|
||||
view.setBearingTracking(ReactNativeMapboxGLModule.bearingTrackingModes[mode]);
|
||||
}
|
||||
|
||||
@ReactProp(name = "attributionButtonIsHidden")
|
||||
public void setAttributionButtonIsHidden(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setAttributionButtonIsHidden(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "logoIsHidden")
|
||||
public void setLogoIsHidden(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setLogoIsHidden(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "compassIsHidden")
|
||||
public void setCompassIsHidden(ReactNativeMapboxGLView view, boolean value) {
|
||||
view.setCompassIsHidden(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "contentInset")
|
||||
public void setContentInset(ReactNativeMapboxGLView view, ReadableArray inset) {
|
||||
view.setContentInset(inset.getInt(0), inset.getInt(1), inset.getInt(2), inset.getInt(3));
|
||||
}
|
||||
|
||||
// Commands
|
||||
|
||||
public static final int COMMAND_GET_DIRECTION = 0;
|
||||
public static final int COMMAND_GET_PITCH = 1;
|
||||
public static final int COMMAND_GET_CENTER_COORDINATE_ZOOM_LEVEL = 2;
|
||||
public static final int COMMAND_GET_BOUNDS = 3;
|
||||
public static final int COMMAND_EASE_TO = 4;
|
||||
public static final int COMMAND_SET_VISIBLE_COORDINATE_BOUNDS = 6;
|
||||
public static final int COMMAND_SELECT_ANNOTATION = 7;
|
||||
public static final int COMMAND_SPLICE_ANNOTATIONS = 8;
|
||||
public static final int COMMAND_DESELECT_ANNOTATION = 9;
|
||||
|
||||
@Override
|
||||
public
|
||||
@Nullable
|
||||
Map<String, Integer> getCommandsMap() {
|
||||
return MapBuilder.<String, Integer>builder()
|
||||
.put("getDirection", COMMAND_GET_DIRECTION)
|
||||
.put("getPitch", COMMAND_GET_PITCH)
|
||||
.put("getCenterCoordinateZoomLevel", COMMAND_GET_CENTER_COORDINATE_ZOOM_LEVEL)
|
||||
.put("getBounds", COMMAND_GET_BOUNDS)
|
||||
.put("easeTo", COMMAND_EASE_TO)
|
||||
.put("setVisibleCoordinateBounds", COMMAND_SET_VISIBLE_COORDINATE_BOUNDS)
|
||||
.put("selectAnnotation", COMMAND_SELECT_ANNOTATION)
|
||||
.put("spliceAnnotations", COMMAND_SPLICE_ANNOTATIONS)
|
||||
.put("deselectAnnotation", COMMAND_DESELECT_ANNOTATION)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void fireCallback(int callbackId, WritableArray args) {
|
||||
WritableArray event = Arguments.createArray();
|
||||
event.pushInt(callbackId);
|
||||
event.pushArray(args);
|
||||
|
||||
_context.getJSModule(RCTNativeAppEventEmitter.class)
|
||||
.emit("MapboxAndroidCallback", event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveCommand(ReactNativeMapboxGLView view, int commandId, @Nullable ReadableArray args) {
|
||||
Assertions.assertNotNull(args);
|
||||
switch (commandId) {
|
||||
case COMMAND_GET_DIRECTION:
|
||||
getDirection(view, args.getInt(0));
|
||||
break;
|
||||
case COMMAND_GET_PITCH:
|
||||
getPitch(view, args.getInt(0));
|
||||
break;
|
||||
case COMMAND_GET_CENTER_COORDINATE_ZOOM_LEVEL:
|
||||
getCenterCoordinateZoomLevel(view, args.getInt(0));
|
||||
break;
|
||||
case COMMAND_GET_BOUNDS:
|
||||
getBounds(view, args.getInt(0));
|
||||
break;
|
||||
case COMMAND_EASE_TO:
|
||||
easeTo(view, args.getMap(0), args.getBoolean(1), args.getInt(2));
|
||||
break;
|
||||
case COMMAND_SET_VISIBLE_COORDINATE_BOUNDS:
|
||||
setVisibleCoordinateBounds(view,
|
||||
args.getDouble(0), args.getDouble(1), args.getDouble(2), args.getDouble(3),
|
||||
args.getDouble(4), args.getDouble(5), args.getDouble(6), args.getDouble(7),
|
||||
args.getBoolean(8)
|
||||
);
|
||||
break;
|
||||
case COMMAND_SELECT_ANNOTATION:
|
||||
selectAnnotation(view, args.getString(0), args.getBoolean(1));
|
||||
break;
|
||||
case COMMAND_SPLICE_ANNOTATIONS:
|
||||
spliceAnnotations(view, args.getBoolean(0), args.getArray(1), args.getArray(2));
|
||||
break;
|
||||
case COMMAND_DESELECT_ANNOTATION:
|
||||
deselectAnnotation(view);
|
||||
break;
|
||||
default:
|
||||
throw new JSApplicationIllegalArgumentException("Invalid commandId " + commandId + " sent to " + getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
private void getDirection(ReactNativeMapboxGLView view, int callbackId) {
|
||||
WritableArray result = Arguments.createArray();
|
||||
result.pushDouble(view.getCameraPosition().bearing);
|
||||
fireCallback(callbackId, result);
|
||||
}
|
||||
|
||||
private void getPitch(ReactNativeMapboxGLView view, int callbackId) {
|
||||
WritableArray result = Arguments.createArray();
|
||||
result.pushDouble(view.getCameraPosition().tilt);
|
||||
fireCallback(callbackId, result);
|
||||
}
|
||||
|
||||
private void getCenterCoordinateZoomLevel(ReactNativeMapboxGLView view, int callbackId) {
|
||||
CameraPosition camera = view.getCameraPosition();
|
||||
|
||||
WritableArray args = Arguments.createArray();
|
||||
WritableMap result = Arguments.createMap();
|
||||
result.putDouble("latitude", camera.target.getLatitude());
|
||||
result.putDouble("longitude", camera.target.getLongitude());
|
||||
result.putDouble("zoomLevel", camera.zoom);
|
||||
args.pushMap(result);
|
||||
|
||||
fireCallback(callbackId, args);
|
||||
}
|
||||
|
||||
private void getBounds(ReactNativeMapboxGLView view, int callbackId) {
|
||||
LatLngBounds bounds = view.getBounds();
|
||||
|
||||
WritableArray args = Arguments.createArray();
|
||||
WritableArray result = Arguments.createArray();
|
||||
result.pushDouble(bounds.getLatSouth());
|
||||
result.pushDouble(bounds.getLonWest());
|
||||
result.pushDouble(bounds.getLatNorth());
|
||||
result.pushDouble(bounds.getLonEast());
|
||||
args.pushArray(result);
|
||||
|
||||
fireCallback(callbackId, args);
|
||||
}
|
||||
|
||||
// Setters
|
||||
|
||||
private void easeTo(ReactNativeMapboxGLView view, ReadableMap updates, boolean animated, int callbackId) {
|
||||
CameraPosition oldPosition = view.getCameraPosition();
|
||||
CameraPosition.Builder cameraBuilder = new CameraPosition.Builder(oldPosition);
|
||||
|
||||
if (updates.hasKey("latitude") && updates.hasKey("longitude")) {
|
||||
cameraBuilder.target(new LatLng(updates.getDouble("latitude"), updates.getDouble("longitude")));
|
||||
}
|
||||
if (updates.hasKey("zoomLevel")) {
|
||||
cameraBuilder.zoom(updates.getDouble("zoomLevel"));
|
||||
}
|
||||
if (updates.hasKey("direction")) {
|
||||
cameraBuilder.bearing(updates.getDouble("direction"));
|
||||
}
|
||||
if (updates.hasKey("pitch")) {
|
||||
cameraBuilder.tilt(updates.getDouble("pitch"));
|
||||
}
|
||||
|
||||
// I want lambdas :(
|
||||
class CallbackRunnable implements Runnable {
|
||||
int callbackId;
|
||||
ReactNativeMapboxGLManager manager;
|
||||
|
||||
CallbackRunnable(ReactNativeMapboxGLManager manager, int callbackId) {
|
||||
this.callbackId = callbackId;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
manager.fireCallback(callbackId, Arguments.createArray());
|
||||
}
|
||||
}
|
||||
|
||||
int duration = animated ? MapboxConstants.ANIMATION_DURATION : 0;
|
||||
view.setCameraPosition(cameraBuilder.build(), duration, new CallbackRunnable(this, callbackId));
|
||||
}
|
||||
|
||||
public void setCamera(
|
||||
ReactNativeMapboxGLView view,
|
||||
double latitude, double longitude,
|
||||
double altitude, double pitch, double direction,
|
||||
double duration) {
|
||||
throw new JSApplicationIllegalArgumentException("MapView.setCamera() is not supported on Android. If you're trying to change pitch, use MapView.easeTo()");
|
||||
}
|
||||
|
||||
public void setVisibleCoordinateBounds(
|
||||
ReactNativeMapboxGLView view,
|
||||
double latS, double lonW, double latN, double lonE,
|
||||
double paddingTop, double paddingRight, double paddingBottom, double paddingLeft,
|
||||
boolean animated) {
|
||||
CameraUpdate update = CameraUpdateFactory.newLatLngBounds(
|
||||
new LatLngBounds.Builder()
|
||||
.include(new LatLng(latS, lonW))
|
||||
.include(new LatLng(latN, lonE))
|
||||
.build(),
|
||||
(int) paddingLeft,
|
||||
(int) paddingTop,
|
||||
(int) paddingRight,
|
||||
(int) paddingBottom
|
||||
);
|
||||
view.setCameraUpdate(update, animated ? MapboxConstants.ANIMATION_DURATION : 0, null);
|
||||
}
|
||||
|
||||
// Annotations
|
||||
|
||||
public void spliceAnnotations(ReactNativeMapboxGLView view, boolean removeAll, ReadableArray itemsToRemove, ReadableArray itemsToAdd) {
|
||||
if (removeAll) {
|
||||
view.removeAllAnnotations();
|
||||
} else {
|
||||
int removeCount = itemsToRemove.size();
|
||||
for (int i = 0; i < removeCount; i++) {
|
||||
view.removeAnnotation(itemsToRemove.getString(i));
|
||||
}
|
||||
}
|
||||
|
||||
int addCount = itemsToAdd.size();
|
||||
for (int i = 0; i < addCount; i++) {
|
||||
ReadableMap annotation = itemsToAdd.getMap(i);
|
||||
RNMGLAnnotationOptions annotationOptions = RNMGLAnnotationOptionsFactory.annotationOptionsFromJS(annotation, view.getContext());
|
||||
|
||||
String name = annotation.getString("id");
|
||||
view.setAnnotation(name, annotationOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public void selectAnnotation(ReactNativeMapboxGLView view, String annotationId, boolean animated) {
|
||||
view.selectAnnotation(annotationId, animated);
|
||||
}
|
||||
|
||||
public void deselectAnnotation(ReactNativeMapboxGLView view) {
|
||||
view.deselectAnnotation();
|
||||
}
|
||||
}
|
||||
@@ -1,835 +0,0 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.hardware.GeomagneticField;
|
||||
import android.location.Location;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.LifecycleEventListener;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.touch.OnInterceptTouchEventListener;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
import com.mapbox.mapboxsdk.annotations.Annotation;
|
||||
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerView;
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdate;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
|
||||
import com.mapbox.mapboxsdk.maps.MapView;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
|
||||
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
|
||||
import com.mapbox.mapboxsdk.maps.UiSettings;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ReactNativeMapboxGLView extends RelativeLayout implements
|
||||
OnMapReadyCallback, LifecycleEventListener,
|
||||
MapboxMap.OnMapClickListener, MapboxMap.OnMapLongClickListener,
|
||||
MapboxMap.OnMyBearingTrackingModeChangeListener, MapboxMap.OnMyLocationTrackingModeChangeListener,
|
||||
MapboxMap.OnMyLocationChangeListener,
|
||||
MapboxMap.OnMarkerClickListener, MapboxMap.OnInfoWindowClickListener,
|
||||
MapView.OnMapChangedListener, ReactNativeMapboxGLManager.ChildListener
|
||||
{
|
||||
|
||||
private MapboxMap _map = null;
|
||||
private MapView _mapView = null;
|
||||
private ReactNativeMapboxGLManager _manager;
|
||||
private boolean _paused = false;
|
||||
|
||||
private CameraPosition.Builder _initialCamera = new CameraPosition.Builder();
|
||||
private MapboxMapOptions _mapOptions;
|
||||
private int _locationTrackingMode;
|
||||
private int _bearingTrackingMode;
|
||||
private boolean _trackingModeUpdateScheduled = false;
|
||||
private boolean _showsUserLocation;
|
||||
private boolean _annotationsPopUpEnabled = true;
|
||||
private boolean _zoomEnabled = true;
|
||||
private double _minimumZoomLevel = 0;
|
||||
private double _maximumZoomLevel = 20;
|
||||
private boolean _pitchEnabled = true;
|
||||
private boolean _scrollEnabled = true;
|
||||
private boolean _rotateEnabled = true;
|
||||
private boolean _enableOnRegionWillChange = false;
|
||||
private boolean _enableOnRegionDidChange = false;
|
||||
private int _paddingTop, _paddingRight, _paddingBottom, _paddingLeft;
|
||||
private boolean _recentlyChanged = false;
|
||||
private boolean _willChangeThrottled = false;
|
||||
private boolean _didChangeThrottled = false;
|
||||
private boolean _changeWasAnimated = false;
|
||||
|
||||
private Map<String, Annotation> _annotations = new HashMap<>();
|
||||
private Map<Long, String> _annotationIdsToName = new HashMap<>();
|
||||
private Map<String, RNMGLAnnotationOptions> _annotationOptions = new HashMap<>();
|
||||
private Map<String, MarkerView> _customAnnodationIds = new HashMap<>();
|
||||
private Map<String, RNMGLAnnotationView> _customAnnotationViewMap = new HashMap<>();
|
||||
private Map<RNMGLAnnotationView, RNMGLAnnotationView.PropertyListener> _propertyListeners = new HashMap<>();
|
||||
|
||||
private Handler _handler;
|
||||
|
||||
|
||||
@UiThread
|
||||
public ReactNativeMapboxGLView(Context context, ReactNativeMapboxGLManager manager) {
|
||||
super(context);
|
||||
_handler = new android.os.Handler();
|
||||
_manager = manager;
|
||||
_mapOptions = MapboxMapOptions.createFromAttributes(context, null);
|
||||
_mapOptions.zoomGesturesEnabled(true);
|
||||
_mapOptions.rotateGesturesEnabled(true);
|
||||
_mapOptions.scrollGesturesEnabled(true);
|
||||
_mapOptions.tiltGesturesEnabled(true);
|
||||
}
|
||||
|
||||
// Lifecycle methods
|
||||
|
||||
public void onAfterUpdateTransaction() {
|
||||
if (_mapView != null) { return; }
|
||||
setupMapView();
|
||||
_paused = false;
|
||||
_mapView.onStart();
|
||||
_mapView.onResume();
|
||||
_manager.getContext().addLifecycleEventListener(this);
|
||||
}
|
||||
|
||||
public void onDrop() {
|
||||
if (_mapView == null) { return; }
|
||||
_manager.getContext().removeLifecycleEventListener(this);
|
||||
_manager.removeChildListener(this);
|
||||
if (!_paused) {
|
||||
_paused = true;
|
||||
_mapView.onPause();
|
||||
_mapView.onStop();
|
||||
}
|
||||
destroyMapView();
|
||||
_mapView = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostResume() {
|
||||
_paused = false;
|
||||
_mapView.onStart();
|
||||
_mapView.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostPause() {
|
||||
_paused = true;
|
||||
_mapView.onPause();
|
||||
_mapView.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostDestroy() {
|
||||
onDrop();
|
||||
}
|
||||
|
||||
// Initialization
|
||||
|
||||
private void setupMapView() {
|
||||
_mapOptions.camera(_initialCamera.build());
|
||||
_mapView = new MapView(this.getContext(), _mapOptions);
|
||||
_manager.addView(this, _mapView, 0);
|
||||
_mapView.addOnMapChangedListener(this);
|
||||
_mapView.onCreate(null);
|
||||
_mapView.getMapAsync(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMapReady(MapboxMap mapboxMap) {
|
||||
if (_mapView == null) { return; }
|
||||
_map = mapboxMap;
|
||||
|
||||
// Configure map
|
||||
_map.setMyLocationEnabled(_showsUserLocation);
|
||||
_map.getTrackingSettings().setMyLocationTrackingMode(_locationTrackingMode);
|
||||
_map.getTrackingSettings().setMyBearingTrackingMode(_bearingTrackingMode);
|
||||
_map.setPadding(_paddingLeft, _paddingTop, _paddingRight, _paddingBottom);
|
||||
_map.setMinZoomPreference(_minimumZoomLevel);
|
||||
_map.setMaxZoomPreference(_maximumZoomLevel);
|
||||
|
||||
UiSettings uiSettings = _map.getUiSettings();
|
||||
uiSettings.setZoomGesturesEnabled(_zoomEnabled);
|
||||
uiSettings.setScrollGesturesEnabled(_scrollEnabled);
|
||||
uiSettings.setRotateGesturesEnabled(_rotateEnabled);
|
||||
uiSettings.setTiltGesturesEnabled(_pitchEnabled);
|
||||
|
||||
// If these settings changed between setupMapView() and onMapReady(), coerce them to their right values
|
||||
// This doesn't happen in the current implementation of MapView, but let's be future proof
|
||||
if (_map.isDebugActive() != _mapOptions.getDebugActive()) {
|
||||
_map.setDebugActive(_mapOptions.getDebugActive());
|
||||
}
|
||||
if (!_map.getStyleUrl().equals(_mapOptions.getStyle())) {
|
||||
_map.setStyleUrl(_mapOptions.getStyle());
|
||||
}
|
||||
if (uiSettings.isLogoEnabled() != _mapOptions.getLogoEnabled()) {
|
||||
uiSettings.setLogoEnabled(_mapOptions.getLogoEnabled());
|
||||
}
|
||||
if (uiSettings.isAttributionEnabled() != _mapOptions.getAttributionEnabled()) {
|
||||
uiSettings.setAttributionEnabled(_mapOptions.getAttributionEnabled());
|
||||
}
|
||||
if (uiSettings.isCompassEnabled() != _mapOptions.getCompassEnabled()) {
|
||||
uiSettings.setCompassEnabled(_mapOptions.getCompassEnabled());
|
||||
}
|
||||
|
||||
// Attach listeners
|
||||
_map.setOnMapClickListener(this);
|
||||
_map.setOnMapLongClickListener(this);
|
||||
_map.setOnMyLocationTrackingModeChangeListener(this);
|
||||
_map.setOnMyBearingTrackingModeChangeListener(this);
|
||||
_map.setOnMyLocationChangeListener(this);
|
||||
_map.setOnMarkerClickListener(this);
|
||||
_map.setOnInfoWindowClickListener(this);
|
||||
|
||||
// Create annotations
|
||||
for (Map.Entry<String, RNMGLAnnotationOptions> entry : _annotationOptions.entrySet()) {
|
||||
Annotation annotation = entry.getValue().addToMap(_map);
|
||||
_annotations.put(entry.getKey(), annotation);
|
||||
_annotationIdsToName.put(annotation.getId(), entry.getKey());
|
||||
}
|
||||
|
||||
_annotationOptions.clear();
|
||||
|
||||
_map.getMarkerViewManager().addMarkerViewAdapter(
|
||||
new RNMGLCustomMarkerViewAdapter(getContext()));
|
||||
}
|
||||
|
||||
private void destroyMapView() {
|
||||
_mapView.removeOnMapChangedListener(this);
|
||||
if (_map != null) {
|
||||
_map.setOnMapClickListener(null);
|
||||
_map.setOnMapLongClickListener(null);
|
||||
_map.setOnMyLocationTrackingModeChangeListener(null);
|
||||
_map.setOnMyBearingTrackingModeChangeListener(null);
|
||||
_map.setOnMyLocationChangeListener(null);
|
||||
_map.setOnMarkerClickListener(null);
|
||||
_map.setOnInfoWindowClickListener(null);
|
||||
_map = null;
|
||||
}
|
||||
_mapView.onDestroy();
|
||||
}
|
||||
|
||||
// Children
|
||||
|
||||
@Override
|
||||
public void childAdded(View child) {
|
||||
if (child instanceof RNMGLAnnotationView) {
|
||||
updateMarkerAnnotations();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childRemoved(View child) {
|
||||
if (child instanceof RNMGLAnnotationView) {
|
||||
updateMarkerAnnotations();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateMarkerAnnotations() {
|
||||
Set<RNMGLAnnotationView> newAnnotationViews = new HashSet<>(_manager.getAnnotationViews(this));
|
||||
Set<RNMGLAnnotationView> currentViews = new HashSet<>(_customAnnotationViewMap.values());
|
||||
Collection<RNMGLAnnotationView> addedChildren = Utils.difference(newAnnotationViews, currentViews);
|
||||
Collection<RNMGLAnnotationView> removedChildren = Utils.difference(currentViews, newAnnotationViews);
|
||||
|
||||
for (RNMGLAnnotationView annotationView : removedChildren) {
|
||||
annotationView.removePropertyListener(_propertyListeners.get(annotationView));
|
||||
_customAnnotationViewMap.remove(annotationView.getAnnotationId());
|
||||
MarkerView markerView = _customAnnodationIds.remove(annotationView.getAnnotationId());
|
||||
_map.removeMarker(markerView);
|
||||
}
|
||||
|
||||
for (RNMGLAnnotationView annotationView : addedChildren) {
|
||||
_customAnnotationViewMap.put(annotationView.getAnnotationId(), annotationView);
|
||||
RNMGLCustomMarkerViewOptions options = new RNMGLCustomMarkerViewOptions()
|
||||
.annotationId(annotationView.getAnnotationId())
|
||||
.position(annotationView.getCoordinate())
|
||||
.anchor(0.5f, 0.5f)
|
||||
.flat(true);
|
||||
final MarkerView markerView = _map.addMarker(options);
|
||||
_customAnnodationIds.put(annotationView.getAnnotationId(), markerView);
|
||||
_annotationIdsToName.put(markerView.getId(), annotationView.getAnnotationId());
|
||||
RNMGLAnnotationView.PropertyListener propertyListener = new RNMGLAnnotationView.PropertyListener() {
|
||||
@Override
|
||||
public void propertiesUpdated(RNMGLAnnotationView view) {
|
||||
markerView.setPosition(view.getCoordinate());
|
||||
}
|
||||
};
|
||||
annotationView.addPropertyListener(propertyListener);
|
||||
_propertyListeners.put(annotationView, propertyListener);
|
||||
}
|
||||
|
||||
relayout();
|
||||
}
|
||||
|
||||
private void relayout() {
|
||||
// Need a relayout to show custom marker views
|
||||
_handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(_mapView != null) {
|
||||
_mapView.measure(
|
||||
View.MeasureSpec.makeMeasureSpec(_mapView.getMeasuredWidth(), View.MeasureSpec.EXACTLY),
|
||||
View.MeasureSpec.makeMeasureSpec(_mapView.getMeasuredHeight(), View.MeasureSpec.EXACTLY));
|
||||
_mapView.layout(_mapView.getLeft(), _mapView.getTop(), _mapView.getRight(), _mapView.getBottom());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Props
|
||||
|
||||
public void setInitialZoomLevel(double value) {
|
||||
_initialCamera.zoom(value);
|
||||
}
|
||||
|
||||
public void setInitialDirection(double value) {
|
||||
_initialCamera.bearing(value);
|
||||
}
|
||||
|
||||
public void setInitialCenterCoordinate(double lat, double lon) {
|
||||
_initialCamera.target(new LatLng(lat, lon));
|
||||
}
|
||||
|
||||
public void setEnableOnRegionDidChange(boolean value) {
|
||||
_enableOnRegionDidChange = value;
|
||||
}
|
||||
|
||||
public void setEnableOnRegionWillChange(boolean value) {
|
||||
_enableOnRegionWillChange = value;
|
||||
}
|
||||
|
||||
public void setShowsUserLocation(boolean value) {
|
||||
if (_showsUserLocation == value) { return; }
|
||||
_showsUserLocation = value;
|
||||
if (_map != null) { _map.setMyLocationEnabled(value); }
|
||||
}
|
||||
|
||||
public void setRotateEnabled(boolean value) {
|
||||
if (_rotateEnabled == value) { return; }
|
||||
_rotateEnabled = value;
|
||||
if (_map != null) {
|
||||
_map.getUiSettings().setRotateGesturesEnabled(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setScrollEnabled(boolean value) {
|
||||
if (_scrollEnabled == value) { return; }
|
||||
_scrollEnabled = value;
|
||||
if (_map != null) {
|
||||
_map.getUiSettings().setScrollGesturesEnabled(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setZoomEnabled(boolean value) {
|
||||
if (_zoomEnabled == value) { return; }
|
||||
_zoomEnabled = value;
|
||||
if (_map != null) {
|
||||
_map.getUiSettings().setZoomGesturesEnabled(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMinimumZoomLevel(double value) {
|
||||
if (_minimumZoomLevel == value) { return; }
|
||||
_minimumZoomLevel = value;
|
||||
if (_map != null) {
|
||||
_map.setMinZoomPreference(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMaximumZoomLevel(double value) {
|
||||
if (_maximumZoomLevel == value) { return; }
|
||||
_maximumZoomLevel = value;
|
||||
if (_map != null) {
|
||||
_map.setMaxZoomPreference(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPitchEnabled(boolean value) {
|
||||
if (_pitchEnabled == value) { return; }
|
||||
_pitchEnabled = value;
|
||||
if (_map != null) {
|
||||
_map.getUiSettings().setTiltGesturesEnabled(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAnnotationsPopUpEnabled(boolean value) {
|
||||
_annotationsPopUpEnabled = value;
|
||||
}
|
||||
|
||||
public void setStyleURL(String styleURL) {
|
||||
if (styleURL.equals(_mapOptions.getStyle())) { return; }
|
||||
_mapOptions.styleUrl(styleURL);
|
||||
if (_map != null) { _map.setStyleUrl(styleURL); }
|
||||
}
|
||||
|
||||
public void setDebugActive(boolean value) {
|
||||
if (_mapOptions.getDebugActive() == value) { return; }
|
||||
_mapOptions.debugActive(value);
|
||||
if (_map != null) { _map.setDebugActive(value); }
|
||||
}
|
||||
|
||||
public void setLocationTracking(int value) {
|
||||
if (_locationTrackingMode == value) { return; }
|
||||
_locationTrackingMode = value;
|
||||
if (_map != null) { _map.getTrackingSettings().setMyLocationTrackingMode(value); }
|
||||
}
|
||||
|
||||
public void setBearingTracking(int value) {
|
||||
if (_bearingTrackingMode == value) { return; }
|
||||
_bearingTrackingMode = value;
|
||||
if (_map != null) { _map.getTrackingSettings().setMyBearingTrackingMode(value); }
|
||||
}
|
||||
|
||||
public void setAttributionButtonIsHidden(boolean value) {
|
||||
if (_mapOptions.getAttributionEnabled() == !value) { return; }
|
||||
_mapOptions.attributionEnabled(!value);
|
||||
if (_map != null) {
|
||||
_map.getUiSettings().setAttributionEnabled(!value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLogoIsHidden(boolean value) {
|
||||
if (_mapOptions.getLogoEnabled() == !value) { return; }
|
||||
_mapOptions.logoEnabled(!value);
|
||||
if (_map != null) {
|
||||
_map.getUiSettings().setLogoEnabled(!value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCompassIsHidden(boolean value) {
|
||||
if (_mapOptions.getCompassEnabled() == !value) { return; }
|
||||
_mapOptions.compassEnabled(!value);
|
||||
if (_map != null) {
|
||||
_map.getUiSettings().setCompassEnabled(!value);
|
||||
}
|
||||
}
|
||||
|
||||
public void setContentInset(int top, int right, int bottom, int left) {
|
||||
if (top == _paddingTop &&
|
||||
bottom == _paddingBottom &&
|
||||
left == _paddingLeft &&
|
||||
right == _paddingRight) { return; }
|
||||
_paddingTop = top;
|
||||
_paddingRight = right;
|
||||
_paddingBottom = bottom;
|
||||
_paddingLeft = left;
|
||||
if (_map != null) { _map.setPadding(left, top, right, bottom); }
|
||||
}
|
||||
|
||||
// Events
|
||||
|
||||
void emitEvent(String name, @Nullable WritableMap event) {
|
||||
if (event == null) {
|
||||
event = Arguments.createMap();
|
||||
}
|
||||
((ReactContext)getContext())
|
||||
.getJSModule(RCTEventEmitter.class)
|
||||
.receiveEvent(getId(), name, event);
|
||||
}
|
||||
|
||||
WritableMap serializePoint(LatLng point) {
|
||||
PointF screenCoords = _map.getProjection().toScreenLocation(point);
|
||||
|
||||
WritableMap event = Arguments.createMap();
|
||||
WritableMap src = Arguments.createMap();
|
||||
src.putDouble("latitude", point.getLatitude());
|
||||
src.putDouble("longitude", point.getLongitude());
|
||||
src.putDouble("screenCoordX", screenCoords.x);
|
||||
src.putDouble("screenCoordY", screenCoords.y);
|
||||
event.putMap("src", src);
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMapClick(LatLng point) {
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_TAP, serializePoint(point));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMapLongClick(@NonNull LatLng point) {
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_LONG_PRESS, serializePoint(point));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMyLocationChange(@Nullable Location location) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
WritableMap src = Arguments.createMap();
|
||||
|
||||
if (location == null) {
|
||||
src.putString("message", "Could not get user location");
|
||||
event.putMap("src", src);
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_LOCATE_USER_FAILED, event);
|
||||
return;
|
||||
}
|
||||
|
||||
src.putDouble("latitude", location.getLatitude());
|
||||
src.putDouble("longitude", location.getLongitude());
|
||||
|
||||
if (location.hasAccuracy()) {
|
||||
src.putDouble("verticalAccuracy", location.getAccuracy());
|
||||
src.putDouble("horizontalAccuracy", location.getAccuracy());
|
||||
}
|
||||
|
||||
GeomagneticField geoField = new GeomagneticField(
|
||||
(float)location.getLatitude(),
|
||||
(float)location.getLongitude(),
|
||||
location.hasAltitude() ? (float)location.getAltitude() : 0.0f,
|
||||
System.currentTimeMillis()
|
||||
);
|
||||
|
||||
src.putDouble("magneticHeading", location.getBearing());
|
||||
src.putDouble("trueHeading", location.getBearing() + geoField.getDeclination());
|
||||
|
||||
event.putMap("src", src);
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_UPDATE_USER_LOCATION, event);
|
||||
}
|
||||
|
||||
class TrackingModeChangeRunnable implements Runnable {
|
||||
ReactNativeMapboxGLView target;
|
||||
TrackingModeChangeRunnable(ReactNativeMapboxGLView target) {
|
||||
this.target = target;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
target.onTrackingModeChange();
|
||||
}
|
||||
}
|
||||
|
||||
public void onTrackingModeChange() {
|
||||
if (!_trackingModeUpdateScheduled) { return; }
|
||||
_trackingModeUpdateScheduled = false;
|
||||
|
||||
for (int mode = 0; mode < ReactNativeMapboxGLModule.locationTrackingModes.length; mode++) {
|
||||
if (_locationTrackingMode == ReactNativeMapboxGLModule.locationTrackingModes[mode] &&
|
||||
_bearingTrackingMode == ReactNativeMapboxGLModule.bearingTrackingModes[mode]) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
event.putInt("src", mode);
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_CHANGE_USER_TRACKING_MODE, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void onMyBearingTrackingModeChange(int myBearingTrackingMode) {
|
||||
if (_bearingTrackingMode == myBearingTrackingMode) { return; }
|
||||
_bearingTrackingMode = myBearingTrackingMode;
|
||||
_trackingModeUpdateScheduled = true;
|
||||
_handler.post(new TrackingModeChangeRunnable(this));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@UiThread
|
||||
public void onMyLocationTrackingModeChange(int myLocationTrackingMode) {
|
||||
if (_locationTrackingMode == myLocationTrackingMode) { return; }
|
||||
_locationTrackingMode = myLocationTrackingMode;
|
||||
_trackingModeUpdateScheduled = true;
|
||||
_handler.post(new TrackingModeChangeRunnable(this));
|
||||
}
|
||||
|
||||
WritableMap serializeCurrentRegion(boolean animated) {
|
||||
CameraPosition camera = _map == null
|
||||
? _initialCamera.build()
|
||||
: _map.getCameraPosition();
|
||||
|
||||
WritableMap event = Arguments.createMap();
|
||||
WritableMap src = Arguments.createMap();
|
||||
src.putDouble("longitude", camera.target.getLongitude());
|
||||
src.putDouble("latitude", camera.target.getLatitude());
|
||||
src.putDouble("zoomLevel", camera.zoom);
|
||||
src.putDouble("direction", camera.bearing);
|
||||
src.putDouble("pitch", camera.tilt);
|
||||
src.putBoolean("animated", animated);
|
||||
event.putMap("src", src);
|
||||
return event;
|
||||
}
|
||||
|
||||
class RegionChangedThrottleRunnable implements Runnable {
|
||||
ReactNativeMapboxGLView target;
|
||||
RegionChangedThrottleRunnable(ReactNativeMapboxGLView target) {
|
||||
this.target = target;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
target.flushRegionChangedThrottle(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void flushRegionChangedThrottle(boolean fireAgain) {
|
||||
_recentlyChanged = false;
|
||||
if (_willChangeThrottled) {
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_REGION_WILL_CHANGE, serializeCurrentRegion(_changeWasAnimated));
|
||||
}
|
||||
if (_didChangeThrottled) {
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_REGION_DID_CHANGE, serializeCurrentRegion(_changeWasAnimated));
|
||||
}
|
||||
|
||||
if (fireAgain && _didChangeThrottled) {
|
||||
_recentlyChanged = true;
|
||||
_handler.postDelayed(new RegionChangedThrottleRunnable(this), 100);
|
||||
}
|
||||
_willChangeThrottled = false;
|
||||
_didChangeThrottled = false;
|
||||
}
|
||||
|
||||
private void onRegionWillChange(boolean animated) {
|
||||
if (animated) {
|
||||
flushRegionChangedThrottle(false);
|
||||
}
|
||||
|
||||
if (_recentlyChanged) {
|
||||
_willChangeThrottled = true;
|
||||
_changeWasAnimated = animated;
|
||||
} else {
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_REGION_WILL_CHANGE, serializeCurrentRegion(animated));
|
||||
}
|
||||
}
|
||||
|
||||
private void onRegionDidChange(boolean animated) {
|
||||
if (animated) {
|
||||
flushRegionChangedThrottle(false);
|
||||
}
|
||||
|
||||
if (_recentlyChanged) {
|
||||
_didChangeThrottled = true;
|
||||
_changeWasAnimated = animated;
|
||||
} else {
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_REGION_DID_CHANGE, serializeCurrentRegion(animated));
|
||||
_recentlyChanged = true;
|
||||
_handler.postDelayed(new RegionChangedThrottleRunnable(this), 100);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMapChanged(int change) {
|
||||
switch (change) {
|
||||
case MapView.REGION_WILL_CHANGE:
|
||||
case MapView.REGION_WILL_CHANGE_ANIMATED:
|
||||
if (_enableOnRegionWillChange) {
|
||||
onRegionWillChange(change == MapView.REGION_WILL_CHANGE_ANIMATED);
|
||||
}
|
||||
break;
|
||||
case MapView.REGION_DID_CHANGE:
|
||||
case MapView.REGION_DID_CHANGE_ANIMATED:
|
||||
if (_enableOnRegionDidChange) {
|
||||
onRegionDidChange(change == MapView.REGION_DID_CHANGE_ANIMATED);
|
||||
}
|
||||
break;
|
||||
case MapView.WILL_START_LOADING_MAP:
|
||||
_manager.removeChildListener(this);
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_START_LOADING_MAP, null);
|
||||
break;
|
||||
case MapView.DID_FINISH_LOADING_MAP:
|
||||
_manager.addChildListener(this);
|
||||
updateMarkerAnnotations();
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_FINISH_LOADING_MAP, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WritableMap serializeMarker(Marker marker) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
WritableMap src = Arguments.createMap();
|
||||
|
||||
src.putString("id", _annotationIdsToName.get(marker.getId()));
|
||||
src.putDouble("longitude", marker.getPosition().getLongitude());
|
||||
src.putDouble("latitude", marker.getPosition().getLatitude());
|
||||
src.putString("title", marker.getTitle());
|
||||
src.putString("subtitle", marker.getSnippet());
|
||||
|
||||
event.putMap("src", src);
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInfoWindowClick(@NonNull Marker marker) {
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_RIGHT_ANNOTATION_TAPPED, serializeMarker(marker));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMarkerClick(@NonNull Marker marker) {
|
||||
emitEvent(ReactNativeMapboxGLEventTypes.ON_OPEN_ANNOTATION, serializeMarker(marker));
|
||||
|
||||
if (_annotationsPopUpEnabled == false) { return true; }
|
||||
|
||||
relayout();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
public CameraPosition getCameraPosition() {
|
||||
if (_map == null) { return _initialCamera.build(); }
|
||||
return _map.getCameraPosition();
|
||||
}
|
||||
|
||||
public LatLngBounds getBounds() {
|
||||
if (_map == null) { return new LatLngBounds.Builder().build(); }
|
||||
return _map.getProjection().getVisibleRegion().latLngBounds;
|
||||
}
|
||||
|
||||
// Camera setters
|
||||
|
||||
public void setCameraPosition(CameraPosition position, int duration, @Nullable Runnable callback) {
|
||||
if (_map == null) {
|
||||
_initialCamera = new CameraPosition.Builder(position);
|
||||
if (callback != null) { callback.run(); }
|
||||
return;
|
||||
}
|
||||
|
||||
CameraUpdate update = CameraUpdateFactory.newCameraPosition(position);
|
||||
setCameraUpdate(update, duration, callback);
|
||||
}
|
||||
|
||||
public void setCameraUpdate(CameraUpdate update, int duration, @Nullable Runnable callback) {
|
||||
if (_map == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (duration == 0) {
|
||||
_map.moveCamera(update);
|
||||
if (callback != null) { callback.run(); }
|
||||
} else {
|
||||
// Ugh... Java callbacks suck
|
||||
class CameraCallback implements MapboxMap.CancelableCallback {
|
||||
Runnable callback;
|
||||
CameraCallback(Runnable callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
@Override
|
||||
public void onCancel() {
|
||||
if (callback != null) { callback.run(); }
|
||||
}
|
||||
@Override
|
||||
public void onFinish() {
|
||||
if (callback != null) { callback.run(); }
|
||||
}
|
||||
}
|
||||
|
||||
_map.animateCamera(update, duration, new CameraCallback(callback));
|
||||
}
|
||||
}
|
||||
|
||||
// Annotations
|
||||
|
||||
@Nullable Annotation _removeAnnotation(String name, boolean keep) {
|
||||
if (_map == null) {
|
||||
_annotationOptions.remove(name);
|
||||
return null;
|
||||
}
|
||||
Annotation annotation = _annotations.remove(name);
|
||||
if (annotation == null) { return null; }
|
||||
_annotationIdsToName.remove(annotation.getId());
|
||||
|
||||
if (keep) { return annotation; }
|
||||
_map.removeAnnotation(annotation);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeAnnotation(String name) {
|
||||
_removeAnnotation(name, false);
|
||||
}
|
||||
|
||||
public void removeAllAnnotations() {
|
||||
_annotationOptions.clear();
|
||||
_annotations.clear();
|
||||
_annotationIdsToName.clear();
|
||||
if (_map != null) {
|
||||
_map.removeAnnotations();
|
||||
}
|
||||
}
|
||||
|
||||
public void setAnnotation(String name, RNMGLAnnotationOptions options) {
|
||||
Annotation removed = _removeAnnotation(name, true);
|
||||
|
||||
if (_map == null) {
|
||||
_annotationOptions.put(name, options);
|
||||
} else {
|
||||
Annotation annotation = options.addToMap(_map);
|
||||
_annotations.put(name, annotation);
|
||||
_annotationIdsToName.put(annotation.getId(), name);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public void deselectAnnotation() {
|
||||
if (_map == null) { return; }
|
||||
_map.deselectMarkers();
|
||||
}
|
||||
|
||||
// Custom Marker View Adapter - Adapts a MarkerView to display an custom react native view.
|
||||
|
||||
private class RNMGLCustomMarkerViewAdapter extends MapboxMap.MarkerViewAdapter<RNMGLCustomMarkerView> {
|
||||
|
||||
RNMGLCustomMarkerViewAdapter(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View getView(@NonNull final RNMGLCustomMarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
RNMGLAnnotationView reactView = _customAnnotationViewMap.get(marker.getAnnotationId());
|
||||
if (reactView.getParent() != null) {
|
||||
ViewGroup group = (ViewGroup) reactView.getParent();
|
||||
group.removeView(reactView);
|
||||
}
|
||||
int width = (int)reactView.getLayoutWidth();
|
||||
int height = (int)reactView.getLayoutHeight();
|
||||
ViewGroup.LayoutParams frameLayoutMeasurements = new FrameLayout.LayoutParams(width, height);
|
||||
ViewGroup.LayoutParams viewGroupMeasurements = new ViewGroup.LayoutParams(width, height);
|
||||
|
||||
FrameLayout layout;
|
||||
if (convertView == null) {
|
||||
layout = new FrameLayout(getContext());
|
||||
} else {
|
||||
layout = (FrameLayout) convertView;
|
||||
layout.removeAllViews();
|
||||
}
|
||||
reactView.setLayoutParams(viewGroupMeasurements);
|
||||
reactView.setOnInterceptTouchEventListener(new OnInterceptTouchEventListener() {
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(ViewGroup v, MotionEvent event) {
|
||||
onMarkerClick(marker);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
layout.setLayoutParams(frameLayoutMeasurements);
|
||||
layout.addView(reactView);
|
||||
|
||||
relayout();
|
||||
|
||||
return layout;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.mapbox.reactnativemapboxgl;
|
||||
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.uimanager.UIViewOperationQueue;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SizeReportingShadowNode extends LayoutShadowNode {
|
||||
|
||||
@Override
|
||||
public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
|
||||
super.onCollectExtraUpdates(uiViewOperationQueue);
|
||||
|
||||
Map<String, Float> data = new HashMap<>();
|
||||
data.put("width", getLayoutWidth());
|
||||
data.put("height", getLayoutHeight());
|
||||
|
||||
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), data);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user