diff --git a/.idea/misc.xml b/.idea/misc.xml
index 6ab96c3..5a3f2a5 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,8 @@
+
+
+
@@ -34,5 +37,5 @@
-
+
\ No newline at end of file
diff --git a/.idea/react-native-gmaps.iml b/.idea/react-native-gmaps.iml
index d6ebd48..3a3afd8 100644
--- a/.idea/react-native-gmaps.iml
+++ b/.idea/react-native-gmaps.iml
@@ -1,7 +1,6 @@
-
-
+
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index ee96105..0f2597e 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -2,11 +2,11 @@
-
-
+
+
@@ -23,15 +23,33 @@
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -56,15 +74,20 @@
+
-
-
+
+
+
+ true
+
-
-
+
+
+
@@ -87,10 +110,23 @@
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -234,100 +270,18 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -361,30 +315,31 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -403,24 +358,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index 3771546..7c16018 100644
--- a/README.md
+++ b/README.md
@@ -16,12 +16,30 @@ let RNGMap = require('react-native-gmaps');
style={ { height: 500, width: 500 } }
markers={ [
{ coordinates: {lng: 0.1, lat: 51.0} },
- { coordinates: {lng: -0.1, lat: 51.0}, title: "Click marker to see this title!" }
+ {
+ coordinates: {lng: -0.1, lat: 51.0},
+ title: "Click marker to see this title!",
+ snippet: "Subtitle",
+ id: 0,
+ /*
+ * Able to use "my_icon" or {uri: 'my_icon', width: 100, height: 100 } here as well
+ */
+ icon: require('image!my_icon'),
+ /*
+ * color is only working with default icon
+ */
+ color: 120,
+ }
] }
zoomLevel={10}
onMapChange={(e) => console.log(e)}
onMapError={(e) => console.log('Map error --> ', e)}
- center={ { lng: 0.1, lat: 51.0 } } />
+ center={ { lng: 0.1, lat: 51.0 } }
+ /*
+ * clickMarker shows Info Window of Marker with id: 0,
+ * hides Info Window if given null
+ */
+ clickMarker={0}/>
```
##### onMapChange
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 852bf0e..f913fe4 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -10,6 +10,12 @@ android {
versionCode 1
versionName "1.0"
}
+ buildTypes {
+ release {
+ minifyEnabled false // Set this to true to enable Proguard
+ proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
+ }
+ }
lintOptions {
abortOnError false
}
@@ -22,7 +28,7 @@ repositories {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
- compile 'com.android.support:appcompat-v7:23.1.0'
- compile 'com.facebook.react:react-native:0.12.0'
- compile 'com.google.android.gms:play-services:8.1.0'
+ compile 'com.android.support:appcompat-v7:23.1.1'
+ compile 'com.facebook.react:react-native:0.16.+'
+ compile 'com.google.android.gms:play-services-maps:8.1.0'
}
diff --git a/android/app/src/main/java/com/rota/rngmaps/RNGMapsModule.java b/android/app/src/main/java/com/rota/rngmaps/RNGMapsModule.java
index a9cba92..221e19f 100644
--- a/android/app/src/main/java/com/rota/rngmaps/RNGMapsModule.java
+++ b/android/app/src/main/java/com/rota/rngmaps/RNGMapsModule.java
@@ -1,52 +1,113 @@
package com.rota.rngmaps;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import javax.annotation.Nullable;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
-import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactContext;
-import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
-import com.facebook.react.uimanager.CatalystStylesDiffMap;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.UIProp;
+import com.facebook.react.uimanager.ReactProp;
import com.google.android.gms.maps.*;
-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 com.google.android.gms.maps.model.Marker;
-import com.google.android.gms.maps.model.MarkerOptions;
+import com.google.android.gms.maps.model.*;
import java.util.ArrayList;
-import java.util.Map;
+import java.util.HashMap;
-/**
- * Created by Henry on 08/10/2015.
- */
public class RNGMapsModule extends SimpleViewManager {
public static final String REACT_CLASS = "RNGMaps";
+ // Unique Name for Log TAG
+ public static final String TAG = RNGMapsModule.class.getSimpleName();
private MapView mView;
private GoogleMap map;
private ReactContext reactContext;
private ArrayList mapMarkers = new ArrayList();
+ private HashMap markerLookup = new HashMap();
+ private WritableMap properties = Arguments.createMap();
+
+ public static final String[] markerProps = {
+ "title",
+ "coordinates",
+ "color",
+ "snippet",
+ "icon",
+ "id"
+ };
- @UIProp(UIProp.Type.MAP)
public static final String PROP_CENTER = "center";
-
- @UIProp(UIProp.Type.NUMBER)
public static final String PROP_ZOOM_LEVEL = "zoomLevel";
-
- @UIProp(UIProp.Type.ARRAY)
public static final String PROP_MARKERS = "markers";
-
- @UIProp(UIProp.Type.BOOLEAN)
public static final String PROP_ZOOM_ON_MARKERS = "zoomOnMarkers";
+ public static final String PROP_CLICK_MARKER = "clickMarker";
+
+ @ReactProp(name = PROP_CENTER)
+ public void setPropCenter(MapView view, @Nullable ReadableMap center) {
+ if (center != null) {
+ WritableMap centerLatLng = Arguments.createMap();
+ WritableMap centerMap = Arguments.createMap();
+ centerLatLng.putDouble("lat", center.getDouble("lat"));
+ centerLatLng.putDouble("lng", center.getDouble("lng"));
+
+ centerMap.putMap("center", centerLatLng);
+ properties.merge(centerMap);
+ updateCenter();
+ }
+ }
+
+ @ReactProp(name = PROP_ZOOM_LEVEL, defaultInt = 10)
+ public void setPropZoomLevel(MapView view, int zoomLevel) {
+ properties.putInt(PROP_ZOOM_LEVEL, zoomLevel);
+ updateCenter();
+ }
+
+ @ReactProp(name = PROP_MARKERS)
+ public void setPropMarkers(MapView view, @Nullable ReadableArray markersArray) {
+ if (markersArray != null) {
+ updateMarkers(markersArray);
+ }
+ }
+
+ @ReactProp(name = PROP_ZOOM_ON_MARKERS, defaultBoolean = false)
+ public void setPropZoomOnMarkers(MapView view, Boolean shallZoomOnMarkers) {
+ properties.putBoolean(PROP_ZOOM_ON_MARKERS, shallZoomOnMarkers);
+ if (shallZoomOnMarkers) {
+ zoomOnMarkers();
+ }
+ }
+
+ @ReactProp(name = PROP_CLICK_MARKER)
+ public void setPropClickMarker(MapView view, @Nullable Integer clickMarker) {
+ String key = String.valueOf(clickMarker);
+ Log.i(TAG, key);
+ if (clickMarker == null) {
+ if (properties.hasKey(PROP_CLICK_MARKER)) {
+ if (markerLookup.containsKey(String.valueOf(properties.getInt(PROP_CLICK_MARKER)))) {
+ Marker marker = mapMarkers.get(Integer.parseInt(markerLookup.get(String.valueOf(properties.getInt(PROP_CLICK_MARKER)))) );
+ marker.hideInfoWindow();
+ Log.i(TAG, "hideInfoWindow");
+ }
+ }
+ } else {
+ properties.putInt(PROP_CLICK_MARKER, clickMarker);
+ if (markerLookup.containsKey(key)) {
+ Marker marker = mapMarkers.get( Integer.parseInt(markerLookup.get(key)) );
+ marker.showInfoWindow();
+ Log.i(TAG, "showInfoWindow" + String.valueOf(marker));
+ }
+ }
+ }
+
+ protected int mlastZoom = 10;
@Override
public String getName() {
@@ -54,7 +115,7 @@ public String getName() {
}
@Override
- protected MapView createViewInstance(ThemedReactContext context) {
+ public MapView createViewInstance(ThemedReactContext context) {
reactContext = context;
mView = new MapView(context);
mView.onCreate(null);
@@ -62,31 +123,41 @@ protected MapView createViewInstance(ThemedReactContext context) {
map = mView.getMap();
if (map == null) {
- sendMapError("Map is null", "map_null");
+ sendMapError("Map is null", "map_null");
} else {
- map.getUiSettings().setMyLocationButtonEnabled(false);
- map.setMyLocationEnabled(true);
-
- try {
- MapsInitializer.initialize(context.getApplicationContext());
- map.setOnCameraChangeListener(getCameraChangeListener());
- } catch (Exception e) {
- e.printStackTrace();
- sendMapError("Map initialize error", "map_init_error");
- }
+ map.getUiSettings().setMyLocationButtonEnabled(true);
+ map.setMyLocationEnabled(true);
+
+ try {
+ MapsInitializer.initialize(context.getApplicationContext());
+ map.setOnCameraChangeListener(getCameraChangeListener());
+ map.setOnMarkerClickListener(getMarkerClickListener());
+ //add location button click listener
+ map.setOnMyLocationButtonClickListener(new GoogleMap.OnMyLocationButtonClickListener() {
+ @Override
+ public boolean onMyLocationButtonClick() {
+ CameraPosition position = map.getCameraPosition();
+ mlastZoom = (int) position.zoom;
+ return false;
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ sendMapError("Map initialize error", "map_init_error");
+ }
}
return mView;
}
private void sendMapError (String message, String type) {
- WritableMap error = Arguments.createMap();
- error.putString("message", message);
- error.putString("type", type);
+ WritableMap error = Arguments.createMap();
+ error.putString("message", message);
+ error.putString("type", type);
- reactContext
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
- .emit("mapError", error);
+ reactContext
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
+ .emit("mapError", error);
}
private GoogleMap.OnCameraChangeListener getCameraChangeListener() {
@@ -99,7 +170,8 @@ public void onCameraChange(CameraPosition position) {
latLng.putDouble("lng", position.target.longitude);
params.putMap("latLng", latLng);
- params.putDouble("zoomLevel", position.zoom);
+ params.putInt("zoomLevel",(int) position.zoom);
+ mlastZoom = (int) position.zoom;
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
@@ -108,34 +180,72 @@ public void onCameraChange(CameraPosition position) {
};
}
- private Boolean updateCenter (CatalystStylesDiffMap props) {
- try {
- CameraUpdate cameraUpdate;
- Double lng = props.getMap(PROP_CENTER).getDouble("lng");
- Double lat = props.getMap(PROP_CENTER).getDouble("lat");
-
- if(props.hasKey(PROP_ZOOM_LEVEL)) {
- int zoomLevel = props.getInt(PROP_ZOOM_LEVEL, 10);
- cameraUpdate = CameraUpdateFactory
- .newLatLngZoom(
- new LatLng(lat, lng),
- props.getInt(PROP_ZOOM_LEVEL, 10)
- );
- } else {
- cameraUpdate = CameraUpdateFactory.newLatLng(new LatLng(lat, lng));
+ private GoogleMap.OnMarkerClickListener getMarkerClickListener() {
+ return new GoogleMap.OnMarkerClickListener() {
+ @Override
+ public boolean onMarkerClick(Marker marker) {
+ String id = marker.getId();
+ Log.i(TAG, "onMarkerClick " + id);
+ if (markerLookup.containsKey(id)) {
+ WritableMap event = Arguments.createMap();
+ event.putString("id", markerLookup.get(id));
+
+ reactContext
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
+ .emit("markerClick", event);
+ }
+
+ return false;
}
+ };
+ }
- map.animateCamera(cameraUpdate);
-
- return true;
- } catch (Exception e) {
- // ERROR!
- e.printStackTrace();
+ private Boolean updateCenter () {
+ if (properties.hasKey(PROP_CENTER)) {
+ try {
+ CameraUpdate cameraUpdate;
+
+ Double lng = properties.getMap(PROP_CENTER).getDouble("lng");
+ Double lat = properties.getMap(PROP_CENTER).getDouble("lat");
+
+ if (properties.hasKey(PROP_ZOOM_LEVEL)) {
+ int zoomLevel = properties.getInt(PROP_ZOOM_LEVEL);
+ mlastZoom = zoomLevel;
+ Log.i(TAG, "Zoom: " + Integer.toString(properties.getInt(PROP_ZOOM_LEVEL)));
+ cameraUpdate = CameraUpdateFactory
+ .newLatLngZoom(
+ new LatLng(lat, lng),
+ zoomLevel
+ );
+ } else {
+ Log.i(TAG, "Default Zoom.");
+ /*
+ * Changed from cameraUpdate = CameraUpdateFactory.newLatLng(new LatLng(lat, lng));
+ * as it gave me "zoom" Bugs (defaulted to zoom factor 2) as soon as I put in
+ * "real" LNG and LAT values...
+ */
+ cameraUpdate = CameraUpdateFactory
+ .newLatLngZoom(
+ new LatLng(lat, lng),
+ mlastZoom
+ );
+ }
+
+
+ map.animateCamera(cameraUpdate);
+
+ return true;
+ } catch (Exception e) {
+ // ERROR!
+ e.printStackTrace();
+ return false;
+ }
+ } else {
return false;
}
}
- private Boolean updateMarkers (CatalystStylesDiffMap props) {
+ private Boolean updateMarkers (ReadableArray markerArray) {
try {
// First clear all markers from the map
@@ -143,23 +253,64 @@ private Boolean updateMarkers (CatalystStylesDiffMap props) {
marker.remove();
}
mapMarkers.clear();
+ markerLookup.clear();
// All markers to map
- for (int i = 0; i < props.getArray(PROP_MARKERS).size(); i++) {
+ for (int i = 0; i < markerArray.size(); i++) {
MarkerOptions options = new MarkerOptions();
- ReadableMap marker = props.getArray(PROP_MARKERS).getMap(i);
- if(marker.hasKey("coordinates")) {
+ ReadableMap markerJson = markerArray.getMap(i);
+ if(markerJson.hasKey("coordinates")) {
options.position(new LatLng(
- marker.getMap("coordinates").getDouble("lat"),
- marker.getMap("coordinates").getDouble("lng")
+ markerJson.getMap("coordinates").getDouble("lat"),
+ markerJson.getMap("coordinates").getDouble("lng")
)
);
- if(marker.hasKey("title")) {
- options.title(marker.getString("title"));
+ if(markerJson.hasKey("title")) {
+ options.title(markerJson.getString("title"));
+ }
+ if(markerJson.hasKey("color")) {
+ options.icon(BitmapDescriptorFactory.defaultMarker((float) markerJson.getDouble("color")));
+ }
+ if (markerJson.hasKey("snippet")) {
+ options.snippet(markerJson.getString("snippet"));
+ }
+ if(markerJson.hasKey("icon")) {
+ String varName = "";
+ ReadableType iconType = markerJson.getType("icon");
+ if (iconType.compareTo(ReadableType.Map) >= 0) {
+ ReadableMap icon = markerJson.getMap("icon");
+ try {
+ int resId = getResourceDrawableId(icon.getString("uri"));
+ Bitmap image = BitmapFactory.decodeResource(reactContext.getResources(), resId);
+
+ options.icon(BitmapDescriptorFactory.fromBitmap(
+ Bitmap.createScaledBitmap(image, icon.getInt("width"), icon.getInt("height"), true)
+ ));
+ } catch (Exception e) {
+ varName = icon.getString("uri");
+ }
+ } else if (iconType.compareTo(ReadableType.String) >= 0) {
+ varName = markerJson.getString("icon");
+ }
+ if (!varName.equals("")) {
+ // Changing marker icon to use resource
+ int resourceValue = getResourceDrawableId(varName);
+ Log.i(TAG, varName + markerJson.toString());
+ options.icon(BitmapDescriptorFactory.fromResource(resourceValue));
+ }
+ }
+
+ Marker marker = map.addMarker(options);
+
+ if (markerJson.hasKey("id")) {
+ // As we have to lookup it either way, switch it around
+ markerLookup.put(marker.getId(), markerJson.getString("id"));
+ markerLookup.put(markerJson.getString("id"), marker.getId().replace("m",""));
}
- mapMarkers.add(map.addMarker(options));
+
+ mapMarkers.add(marker);
} else break;
}
@@ -191,15 +342,18 @@ private Boolean zoomOnMarkers () {
}
}
- @Override
- public void updateView(MapView view, CatalystStylesDiffMap props) {
- super.updateView(view, props);
- if (props.hasKey(PROP_CENTER)) updateCenter(props);
- if (props.hasKey(PROP_ZOOM_LEVEL)) updateCenter(props);
- if (props.hasKey(PROP_MARKERS)) updateMarkers(props);
- if (props.hasKey(PROP_ZOOM_ON_MARKERS)&&props.getBoolean(PROP_ZOOM_ON_MARKERS, false)) {
- zoomOnMarkers();
+ private int getResourceDrawableId(String name) {
+ try {
+ return reactContext.getResources().getIdentifier(
+ name.toLowerCase().replace("-", "_"),
+ "drawable",
+ reactContext.getPackageName()
+ );
+ } catch (Exception e) {
+ Log.e(TAG, "Failure to get drawable id.", e);
+ return 0;
}
-
}
+
+
}
diff --git a/index.android.js b/index.android.js
index f6d449e..258d165 100644
--- a/index.android.js
+++ b/index.android.js
@@ -15,10 +15,12 @@ let {
var gmaps = {
name: 'RNGMaps',
propTypes: {
+ ...View.propTypes,
center: PropTypes.object,
zoomLevel: PropTypes.number,
markers: PropTypes.array,
zoomOnMarkers: PropTypes.bool,
+ clickMarker: PropTypes.number,
/* Hackedy hack hack hack */
scaleX: React.PropTypes.number,
@@ -34,31 +36,46 @@ let MapView = requireNativeComponent('RNGMaps', gmaps);
class RNGMaps extends Component {
constructor (props) {
super(props);
- this._event = null;
+
+ this._listeners = {
+ mapError: null,
+ mapChange: null,
+ markerClick: null,
+ };
+
+ // Look up markers by id
+ this._markersLookup = {};
this.state = {
zoomOnMarkers: false,
markers: []
}
}
- componentDidMount () {
- this._event = DeviceEventEmitter.addListener('mapChange', (e: Event) => {
- this.props.onMapChange&&this.props.onMapChange(e);
+componentDidMount () {
+ this._listeners.mapError = DeviceEventEmitter.addListener('mapError', (e: Event) => {
+ console.log(`[GMAP_ERROR]: ${e.message}`);
+ this.props.onMapError && this.props.onMapError(e);
});
- this._error = DeviceEventEmitter.addListener('mapError', (e: Event) => {
- console.log(`[GMAP_ERROR]: ${e.message}`);
- this.props.onMapError&&this.props.onMapError(e);
+ this._listeners.mapChange = DeviceEventEmitter.addListener('mapChange', (e: Event) => {
+ this.props.onMapChange && this.props.onMapChange(e);
+ });
+
+ this._listeners.markerClick = DeviceEventEmitter.addListener('markerClick', (e: Event) => {
+ let marker = this._markersLookup[e.id];
+ marker && this.props.onMarkerClick && this.props.onMarkerClick(marker);
});
this.updateMarkers(this.props.markers);
}
componentWillUnmount () {
- this._event&&this._event.remove();
- this._error&&this._error.remove();
+ this._listeners.mapError && this._listeners.mapError.remove();
+ this._listeners.mapChange && this._listeners.mapChange.remove();
+ this._listeners.markerClick && this._listeners.markerClick.remove();
}
+
zoomOnMarkers (bool) {
// HACK: Bleurgh, forcing the change on zoomOnMarkers.
this.setState({ zoomOnMarkers: null }, () => {
@@ -68,7 +85,11 @@ class RNGMaps extends Component {
updateMarkers (markers) {
let newMarkers = [];
- for (var i = 0; i < markers.length; i++) newMarkers.push(markers[i]);
+ for (var i = 0; i < markers.length; i++) {
+ let marker = markers[i];
+ this._markersLookup[marker.id] = marker;
+ newMarkers.push(marker);
+ }
this.setState({ markers: newMarkers });
}
@@ -88,6 +109,7 @@ class RNGMaps extends Component {
if(this._diffMarkers(nextProps.markers, this.state.markers)) {
this.updateMarkers(nextProps.markers);
}
+ console.log('clickMarker:' + nextProps.clickMarker);
}
render () {
diff --git a/package.json b/package.json
index dd8ec20..9f2acc7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-native-gmaps",
- "version": "1.0.4",
+ "version": "1.0.5",
"description": "React Native Android Google Maps implementation.",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"