From df81ca44d6e3f5ed864366eb3e2c6921c0691029 Mon Sep 17 00:00:00 2001 From: Gerardo Date: Wed, 3 May 2017 13:09:46 +0200 Subject: [PATCH 01/22] Wip: Android tiles --- example/examples/CustomTiles.js | 10 +- .../react/maps/AirMapCanvasUrlTile.java | 164 ++++++++++++++++++ .../maps/AirMapCanvasUrlTileManager.java | 50 ++++++ .../airbnb/android/react/maps/AirMapView.java | 6 + .../android/react/maps/MapsPackage.java | 4 +- lib/components/MapCanvasUrlTile.js | 52 ++++++ lib/components/MapView.js | 2 + 7 files changed, 282 insertions(+), 6 deletions(-) create mode 100644 lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java create mode 100644 lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java create mode 100644 lib/components/MapCanvasUrlTile.js diff --git a/example/examples/CustomTiles.js b/example/examples/CustomTiles.js index 3d6e11d7f..5299ac14b 100644 --- a/example/examples/CustomTiles.js +++ b/example/examples/CustomTiles.js @@ -11,9 +11,9 @@ import MapView, { MAP_TYPES, PROVIDER_DEFAULT } from 'react-native-maps'; const { width, height } = Dimensions.get('window'); const ASPECT_RATIO = width / height; -const LATITUDE = 37.78825; -const LONGITUDE = -122.4324; -const LATITUDE_DELTA = 0.0922; +const LATITUDE = -9.020726; +const LONGITUDE = -52.467347; +const LATITUDE_DELTA = 40.1922; const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO; class CustomTiles extends React.Component { @@ -46,8 +46,8 @@ class CustomTiles extends React.Component { style={styles.map} initialRegion={region} > - diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java new file mode 100644 index 000000000..8223b0468 --- /dev/null +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -0,0 +1,164 @@ +package com.airbnb.android.react.maps; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.AsyncTask; +import android.util.Log; +import android.widget.ImageView; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.model.Tile; +import com.google.android.gms.maps.model.TileOverlay; +import com.google.android.gms.maps.model.TileOverlayOptions; +import com.google.android.gms.maps.model.TileProvider; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; + +public class AirMapCanvasUrlTile extends AirMapFeature { + + class AIRMapCanvasUrlTileProvider implements TileProvider { + public AIRMapCanvasUrlTileProvider(int width, int height) { + super(); + } + @Override + public Tile getTile(int x, int y, int zoom) { + int w = 256, h = 256; + + Bitmap.Config conf = Bitmap.Config.ARGB_8888; + Bitmap coordTile = Bitmap.createBitmap(w, h, conf); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + //coordTile.compress(Bitmap.CompressFormat.PNG, 100, stream); + byte[] bitmapData = stream.toByteArray(); + Uri.Builder builder = new Uri.Builder(); + builder.scheme("http") + .authority("wri-tiles.s3.amazonaws.com") + .appendPath("glad_prod") + .appendPath("tiles") + .appendPath(String.valueOf(zoom)) + .appendPath(String.valueOf(x)) + .appendPath(String.valueOf(y)); + String providerUrl = builder.build().toString() + ".png"; + + Log.d("Tiles", providerUrl); + + + //new DownloadTile(bitmapData) + // .execute(providerUrl); + + URL url = null; + try { + url = new URL(providerUrl); + Bitmap image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); + + int width, height, r,g, b, c; + height = image.getHeight(); + width = image.getWidth(); + + Bitmap bmpSephia = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + /*Canvas canvas = new Canvas(bmpSephia); + Paint paint = new Paint(); + paint.setAntiAlias(true); + + canvas.drawBitmap(image, 0, 0, paint);*/ + /* + for(int e=0; e < width; e++) { + for(int f=0; f < height; f++) { + c = image.getPixel(e, f); + int day = Color.red(c) * 255 + Color.green(c); + + if (day > 0 ) { + r = 220; + g = 102; + b = 153; + + bmpSephia.setPixel(e, f, Color.rgb(r, g, b)); + } else { + bmpSephia.setPixel(e, f, Color.argb(0, 0, 0 ,0)); + } + } + }*/ + + + stream = new ByteArrayOutputStream(); + image.compress(Bitmap.CompressFormat.PNG, 0, stream); + bitmapData = stream.toByteArray(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return new Tile(256, 256, bitmapData); + } + } + + + private TileOverlayOptions tileOverlayOptions; + private TileOverlay tileOverlay; + + private String urlTemplate; + private float zIndex; + + public AirMapCanvasUrlTile(Context context) { + super(context); + } + + public void setZIndex(float zIndex) { + this.zIndex = zIndex; + if (tileOverlay != null) { + tileOverlay.setZIndex(zIndex); + } + } + + private class DownloadTile extends AsyncTask { + private byte[] tile; + + public DownloadTile(byte[] tile) { + this.tile = tile; + } + + protected Bitmap doInBackground(String... urls) { + String imageURL = urls[0]; + Bitmap bimage = null; + try { + InputStream in = new java.net.URL(imageURL).openStream(); + bimage = BitmapFactory.decodeStream(in); + + } catch (Exception e) { + Log.e("Error Message", e.getMessage()); + e.printStackTrace(); + } + return bimage; + } + + protected void onPostExecute(Bitmap result) { + Log.d("Title", String.valueOf(result)); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + result.compress(Bitmap.CompressFormat.PNG, 0, stream); + this.tile = stream.toByteArray(); + Tile newTile = new Tile(256, 256, this.tile); + } + } + + @Override + public Object getFeature() { + return tileOverlay; + } + + @Override + public void addToMap(GoogleMap map) { + Log.d("Map", "Add to map"); + this.tileOverlay = map.addTileOverlay(new TileOverlayOptions().tileProvider(new AIRMapCanvasUrlTileProvider(256, 256))); + } + + @Override + public void removeFromMap(GoogleMap map) { + tileOverlay.remove(); + } +} diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java new file mode 100644 index 000000000..6632ea99c --- /dev/null +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java @@ -0,0 +1,50 @@ +package com.airbnb.android.react.maps; + +import android.content.Context; +import android.os.Build; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.WindowManager; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.ViewGroupManager; +import com.facebook.react.uimanager.annotations.ReactProp; + +public class AirMapCanvasUrlTileManager extends ViewGroupManager { + private DisplayMetrics metrics; + + public AirMapCanvasUrlTileManager(ReactApplicationContext reactContext) { + super(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + metrics = new DisplayMetrics(); + ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay() + .getRealMetrics(metrics); + } else { + metrics = reactContext.getResources().getDisplayMetrics(); + } + } + + @Override + public String getName() { + Log.d("Map", "Get name"); + return "AIRMapCanvasUrlTile"; + } + + @Override + public AirMapCanvasUrlTile createViewInstance(ThemedReactContext context) { + return new AirMapCanvasUrlTile(context); + } + + @ReactProp(name = "urlTemplate") + public void setUrlTemplate(AirMapCanvasUrlTile view, String urlTemplate) { + /*view.setUrlTemplate(urlTemplate);*/ + } + + @ReactProp(name = "zIndex", defaultFloat = -1.0f) + public void setZIndex(AirMapCanvasUrlTile view, float zIndex) { + view.setZIndex(zIndex); + } + +} diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java index 0c8604f26..b2b1631b5 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java @@ -10,6 +10,7 @@ import android.os.Handler; import android.support.v4.view.GestureDetectorCompat; import android.support.v4.view.MotionEventCompat; +import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ScaleGestureDetector; @@ -428,6 +429,7 @@ public void setHandlePanDrag(boolean handlePanDrag) { public void addFeature(View child, int index) { // Our desired API is to pass up annotations/overlays as children to the mapview component. // This is where we intercept them and do the appropriate underlying mapview action. + if (child instanceof AirMapMarker) { AirMapMarker annotation = (AirMapMarker) child; annotation.addToMap(map); @@ -454,6 +456,10 @@ public void addFeature(View child, int index) { AirMapUrlTile urlTileView = (AirMapUrlTile) child; urlTileView.addToMap(map); features.add(index, urlTileView); + } else if (child instanceof AirMapCanvasUrlTile) { + AirMapCanvasUrlTile canvasUrlTileView = (AirMapCanvasUrlTile) child; + canvasUrlTileView.addToMap(map); + features.add(index, canvasUrlTileView); } else { ViewGroup children = (ViewGroup) child; for (int i = 0; i < children.getChildCount(); i++) { diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java b/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java index e76f63aa2..5dea52f14 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java @@ -39,6 +39,7 @@ public List createViewManagers(ReactApplicationContext reactContext AirMapManager mapManager = new AirMapManager(reactContext); AirMapLiteManager mapLiteManager = new AirMapLiteManager(reactContext); AirMapUrlTileManager tileManager = new AirMapUrlTileManager(reactContext); + AirMapCanvasUrlTileManager canvasTileManager = new AirMapCanvasUrlTileManager(reactContext); return Arrays.asList( calloutManager, @@ -48,6 +49,7 @@ public List createViewManagers(ReactApplicationContext reactContext circleManager, mapManager, mapLiteManager, - tileManager); + tileManager, + canvasTileManager); } } diff --git a/lib/components/MapCanvasUrlTile.js b/lib/components/MapCanvasUrlTile.js new file mode 100644 index 000000000..77dd18579 --- /dev/null +++ b/lib/components/MapCanvasUrlTile.js @@ -0,0 +1,52 @@ +import React, { PropTypes } from 'react'; + +import { + View, +} from 'react-native'; + +import decorateMapComponent, { + USES_DEFAULT_IMPLEMENTATION, + SUPPORTED, +} from './decorateMapComponent'; + +const propTypes = { + ...View.propTypes, + + /** + * The url template of the tile server. The patterns {x} {y} {z} will be replaced at runtime + * For example, http://c.tile.openstreetmap.org/{z}/{x}/{y}.png + */ + urlTemplate: PropTypes.string.isRequired, + + /** + * The order in which this tile overlay is drawn with respect to other overlays. An overlay + * with a larger z-index is drawn over overlays with smaller z-indices. The order of overlays + * with the same z-index is arbitrary. The default zIndex is -1. + * + * @platform android + */ + zIndex: PropTypes.number, +}; + +class MapUrlTile extends React.Component { + render() { + const AIRMapUrlTile = this.getAirComponent(); + return ( + + ); + } +} + +MapUrlTile.propTypes = propTypes; + +module.exports = decorateMapComponent(MapUrlTile, { + componentType: 'CanvasUrlTile', + providers: { + google: { + ios: SUPPORTED, + android: USES_DEFAULT_IMPLEMENTATION, + }, + }, +}); diff --git a/lib/components/MapView.js b/lib/components/MapView.js index 5eb2284a5..ee89d5e84 100644 --- a/lib/components/MapView.js +++ b/lib/components/MapView.js @@ -15,6 +15,7 @@ import MapPolygon from './MapPolygon'; import MapCircle from './MapCircle'; import MapCallout from './MapCallout'; import MapUrlTile from './MapUrlTile'; +import MapCanvasUrlTile from './MapCanvasUrlTile'; import AnimatedRegion from './AnimatedRegion'; import { contextTypes as childContextTypes, @@ -680,6 +681,7 @@ MapView.Polyline = MapPolyline; MapView.Polygon = MapPolygon; MapView.Circle = MapCircle; MapView.UrlTile = MapUrlTile; +MapView.CanvasUrlTile = MapCanvasUrlTile; MapView.Callout = MapCallout; Object.assign(MapView, ProviderConstants); MapView.ProviderPropType = PropTypes.oneOf(Object.values(ProviderConstants)); From b529b89f336dafcbe07b3334ab85567df4ab9442 Mon Sep 17 00:00:00 2001 From: Alvaro Leal Date: Wed, 3 May 2017 18:02:28 +0200 Subject: [PATCH 02/22] Create intermediateBitmap with appropriate color and alpha and paints it --- .../react/maps/AirMapCanvasUrlTile.java | 57 +++++++++++-------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index 8223b0468..bd83dc9b3 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -3,6 +3,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Color; import android.net.Uri; import android.os.AsyncTask; import android.util.Log; @@ -60,33 +61,39 @@ public Tile getTile(int x, int y, int zoom) { height = image.getHeight(); width = image.getWidth(); - Bitmap bmpSephia = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - /*Canvas canvas = new Canvas(bmpSephia); - Paint paint = new Paint(); - paint.setAntiAlias(true); - - canvas.drawBitmap(image, 0, 0, paint);*/ - /* - for(int e=0; e < width; e++) { - for(int f=0; f < height; f++) { - c = image.getPixel(e, f); - int day = Color.red(c) * 255 + Color.green(c); - - if (day > 0 ) { - r = 220; - g = 102; - b = 153; - - bmpSephia.setPixel(e, f, Color.rgb(r, g, b)); - } else { - bmpSephia.setPixel(e, f, Color.argb(0, 0, 0 ,0)); - } + Bitmap intermediateBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + int red, green, blue, pixel, alpha; + int[] pixels = new int[width * height]; + image.getPixels(pixels, 0, width, 0, 0, width, height); + for (int i = 0; i < pixels.length; i++) { + pixel = pixels[i]; + + red = (pixel >> 16) & 0xFF; + green = (pixel >> 8) & 0xFF; + blue = pixel & 0xFF; + + int day = red * 255 + green; + + if (red > 255) + red = 255; + if (green > 255) + green = 255; + + if (day > 0) { + red = 220; + green = 102; + blue = 153; + alpha = 255; + } else { + alpha = 0; } - }*/ - - + + pixels[i] = Color.argb(alpha, red, green, blue); + } + intermediateBitmap.setPixels(pixels, 0, width, 0, 0, width, height); + stream = new ByteArrayOutputStream(); - image.compress(Bitmap.CompressFormat.PNG, 0, stream); + intermediateBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); bitmapData = stream.toByteArray(); } catch (MalformedURLException e) { e.printStackTrace(); From 29df5cbfdaa256693061f68b45536793fca2a016 Mon Sep 17 00:00:00 2001 From: Alvaro Leal Date: Thu, 4 May 2017 13:43:49 +0200 Subject: [PATCH 03/22] Limit zoom and rescale after that level --- .../react/maps/AirMapCanvasUrlTile.java | 50 +++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index bd83dc9b3..dd90d5c87 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -20,6 +20,8 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; +import java.lang.Math; + public class AirMapCanvasUrlTile extends AirMapFeature { @@ -30,6 +32,18 @@ public AIRMapCanvasUrlTileProvider(int width, int height) { @Override public Tile getTile(int x, int y, int zoom) { int w = 256, h = 256; + int maxZoom = 12; + int xCord = x; + int yCord = y; + int zoomCord = zoom; + + if (zoom > maxZoom) { + xCord = (int)(x / (Math.pow(2, zoom - maxZoom))); + yCord = (int)(y / (Math.pow(2, zoom - maxZoom))); + zoomCord = maxZoom; + } + + Bitmap.Config conf = Bitmap.Config.ARGB_8888; Bitmap coordTile = Bitmap.createBitmap(w, h, conf); @@ -41,13 +55,27 @@ public Tile getTile(int x, int y, int zoom) { .authority("wri-tiles.s3.amazonaws.com") .appendPath("glad_prod") .appendPath("tiles") - .appendPath(String.valueOf(zoom)) - .appendPath(String.valueOf(x)) - .appendPath(String.valueOf(y)); + .appendPath(String.valueOf(zoomCord)) + .appendPath(String.valueOf(xCord)) + .appendPath(String.valueOf(yCord)); String providerUrl = builder.build().toString() + ".png"; Log.d("Tiles", providerUrl); + int srcX = 0; + int srcY = 0; + int srcW = w; + int srcH = h; + + if (zoom > maxZoom) { + int zsteps = zoom - maxZoom; + int relation = (int) Math.pow(2, zsteps) ; + int size = (int) (256 / relation); + srcX = (int) size * (x % relation); + srcY = (int) size * (y % relation); + srcW = (int) size; + srcH = (int) size; + } //new DownloadTile(bitmapData) // .execute(providerUrl); @@ -57,14 +85,16 @@ public Tile getTile(int x, int y, int zoom) { url = new URL(providerUrl); Bitmap image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); - int width, height, r,g, b, c; - height = image.getHeight(); - width = image.getWidth(); + Bitmap resizedBitmap = Bitmap.createBitmap(image , srcX , srcY, srcW, srcH); + + int width, height, r, g, b, c; + height = resizedBitmap.getHeight(); + width = resizedBitmap.getWidth(); - Bitmap intermediateBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Bitmap finalBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); int red, green, blue, pixel, alpha; int[] pixels = new int[width * height]; - image.getPixels(pixels, 0, width, 0, 0, width, height); + resizedBitmap.getPixels(pixels, 0, width, 0, 0, width, height); for (int i = 0; i < pixels.length; i++) { pixel = pixels[i]; @@ -90,10 +120,10 @@ public Tile getTile(int x, int y, int zoom) { pixels[i] = Color.argb(alpha, red, green, blue); } - intermediateBitmap.setPixels(pixels, 0, width, 0, 0, width, height); + finalBitmap.setPixels(pixels, 0, width, 0, 0, width, height); stream = new ByteArrayOutputStream(); - intermediateBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); + finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); bitmapData = stream.toByteArray(); } catch (MalformedURLException e) { e.printStackTrace(); From b8546096bd95078ed4d9ccdaee6f5d055a7756e4 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Thu, 4 May 2017 17:34:15 +0200 Subject: [PATCH 04/22] Get local tiles --- .project | 17 ++ .settings/org.eclipse.buildship.core.prefs | 3 + example/App.js | 2 +- example/android/app/.classpath | 6 + example/android/app/.project | 23 +++ .../org.eclipse.buildship.core.prefs | 3 + .../android/app/src/main/AndroidManifest.xml | 3 + example/examples/CustomTiles.js | 16 +- lib/android/.classpath | 6 + lib/android/.project | 23 +++ .../org.eclipse.buildship.core.prefs | 3 + .../react/maps/AirMapCanvasUrlTile.java | 154 ++++++++++-------- 12 files changed, 190 insertions(+), 69 deletions(-) create mode 100644 .project create mode 100644 .settings/org.eclipse.buildship.core.prefs create mode 100644 example/android/app/.classpath create mode 100644 example/android/app/.project create mode 100644 example/android/app/.settings/org.eclipse.buildship.core.prefs create mode 100644 lib/android/.classpath create mode 100644 lib/android/.project create mode 100644 lib/android/.settings/org.eclipse.buildship.core.prefs diff --git a/.project b/.project new file mode 100644 index 000000000..f564041e5 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + react-native-maps + Project react-native-maps created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..03931c0c1 --- /dev/null +++ b/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,3 @@ +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir= +eclipse.preferences.version=1 diff --git a/example/App.js b/example/App.js index dadbea056..793a0f809 100644 --- a/example/App.js +++ b/example/App.js @@ -123,6 +123,7 @@ class App extends React.Component { render() { return this.renderExamples([ // [, , , ] + [CustomTiles, 'Custom Tiles', true], [StaticMap, 'StaticMap', true], [DisplayLatLng, 'Tracking Position', true, '(incomplete)'], [ViewsAsMarkers, 'Arbitrary Views as Markers', true], @@ -143,7 +144,6 @@ class App extends React.Component { [FitToSuppliedMarkers, 'Focus Map On Markers', true], [FitToCoordinates, 'Fit Map To Coordinates', true], [LiteMapView, 'Android Lite MapView'], - [CustomTiles, 'Custom Tiles', true], [ZIndexMarkers, 'Position Markers with Z-index', true], [MapStyle, 'Customize the style of the map', true], [LegalLabel, 'Reposition the legal label', true], diff --git a/example/android/app/.classpath b/example/android/app/.classpath new file mode 100644 index 000000000..8d8d85f14 --- /dev/null +++ b/example/android/app/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/example/android/app/.project b/example/android/app/.project new file mode 100644 index 000000000..ca3856c62 --- /dev/null +++ b/example/android/app/.project @@ -0,0 +1,23 @@ + + + example-android + Project example-android created by Buildship. + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/example/android/app/.settings/org.eclipse.buildship.core.prefs b/example/android/app/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..0d766b113 --- /dev/null +++ b/example/android/app/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,3 @@ +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir=../../.. +eclipse.preferences.version=1 diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index b111eef4a..659a1fcdc 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -3,6 +3,9 @@ + + + + + + + + diff --git a/lib/android/.project b/lib/android/.project new file mode 100644 index 000000000..2a84911fc --- /dev/null +++ b/lib/android/.project @@ -0,0 +1,23 @@ + + + react-native-maps-lib + Project react-native-maps-lib created by Buildship. + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/lib/android/.settings/org.eclipse.buildship.core.prefs b/lib/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..abb1f3437 --- /dev/null +++ b/lib/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,3 @@ +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir=../.. +eclipse.preferences.version=1 diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index dd90d5c87..6ada9d8c2 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -6,8 +6,8 @@ import android.graphics.Color; import android.net.Uri; import android.os.AsyncTask; +import android.os.Environment; import android.util.Log; -import android.widget.ImageView; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.Tile; @@ -16,9 +16,8 @@ import com.google.android.gms.maps.model.TileProvider; import java.io.ByteArrayOutputStream; -import java.io.IOException; +import java.io.File; import java.io.InputStream; -import java.net.MalformedURLException; import java.net.URL; import java.lang.Math; @@ -36,13 +35,14 @@ public Tile getTile(int x, int y, int zoom) { int xCord = x; int yCord = y; int zoomCord = zoom; - + if (zoom > maxZoom) { xCord = (int)(x / (Math.pow(2, zoom - maxZoom))); yCord = (int)(y / (Math.pow(2, zoom - maxZoom))); zoomCord = maxZoom; } + boolean online = false; Bitmap.Config conf = Bitmap.Config.ARGB_8888; @@ -51,16 +51,42 @@ public Tile getTile(int x, int y, int zoom) { //coordTile.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] bitmapData = stream.toByteArray(); Uri.Builder builder = new Uri.Builder(); - builder.scheme("http") - .authority("wri-tiles.s3.amazonaws.com") - .appendPath("glad_prod") - .appendPath("tiles") - .appendPath(String.valueOf(zoomCord)) - .appendPath(String.valueOf(xCord)) - .appendPath(String.valueOf(yCord)); - String providerUrl = builder.build().toString() + ".png"; + Bitmap image; + + if (online) { + + builder.scheme("http") + .authority("wri-tiles.s3.amazonaws.com") + .appendPath("glad_prod") + .appendPath("tiles") + .appendPath(String.valueOf(zoomCord)) + .appendPath(String.valueOf(xCord)) + .appendPath(String.valueOf(yCord)); + String providerUrl = builder.build().toString() + ".png"; + + URL url = null; + try { + url = new URL(providerUrl); + image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); + } catch (Exception e) { + e.printStackTrace(); + return NO_TILE; + } + + } else { - Log.d("Tiles", providerUrl); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + File dir = Environment.getExternalStorageDirectory(); + File yourFile = new File(dir, "Download/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); + + try { + image = BitmapFactory.decodeFile(yourFile.getAbsolutePath(), options); + } catch (Exception e) { + e.printStackTrace(); + return NO_TILE; + } + } int srcX = 0; int srcY = 0; @@ -80,62 +106,60 @@ public Tile getTile(int x, int y, int zoom) { //new DownloadTile(bitmapData) // .execute(providerUrl); - URL url = null; - try { - url = new URL(providerUrl); - Bitmap image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); - - Bitmap resizedBitmap = Bitmap.createBitmap(image , srcX , srcY, srcW, srcH); - - int width, height, r, g, b, c; - height = resizedBitmap.getHeight(); - width = resizedBitmap.getWidth(); - - Bitmap finalBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - int red, green, blue, pixel, alpha; - int[] pixels = new int[width * height]; - resizedBitmap.getPixels(pixels, 0, width, 0, 0, width, height); - for (int i = 0; i < pixels.length; i++) { - pixel = pixels[i]; - - red = (pixel >> 16) & 0xFF; - green = (pixel >> 8) & 0xFF; - blue = pixel & 0xFF; - - int day = red * 255 + green; - - if (red > 255) - red = 255; - if (green > 255) - green = 255; - - if (day > 0) { - red = 220; - green = 102; - blue = 153; - alpha = 255; - } else { - alpha = 0; - } - - pixels[i] = Color.argb(alpha, red, green, blue); - } - finalBitmap.setPixels(pixels, 0, width, 0, 0, width, height); - - stream = new ByteArrayOutputStream(); - finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); - bitmapData = stream.toByteArray(); - } catch (MalformedURLException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + if (image != null) { + try { + + Bitmap resizedBitmap = Bitmap.createBitmap(image , srcX , srcY, srcW, srcH); + + int width, height, r, g, b, c; + height = resizedBitmap.getHeight(); + width = resizedBitmap.getWidth(); + + Bitmap finalBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + int red, green, blue, pixel, alpha; + int[] pixels = new int[width * height]; + resizedBitmap.getPixels(pixels, 0, width, 0, 0, width, height); + for (int i = 0; i < pixels.length; i++) { + pixel = pixels[i]; + + red = (pixel >> 16) & 0xFF; + green = (pixel >> 8) & 0xFF; + blue = pixel & 0xFF; + + int day = red * 255 + green; + + if (red > 255) + red = 255; + if (green > 255) + green = 255; + + if (day > 0) { + red = 220; + green = 102; + blue = 153; + alpha = 255; + } else { + alpha = 0; + } + + pixels[i] = Color.argb(alpha, red, green, blue); + } + finalBitmap.setPixels(pixels, 0, width, 0, 0, width, height); + + stream = new ByteArrayOutputStream(); + finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); + + bitmapData = stream.toByteArray(); + } catch (Exception e) { + e.printStackTrace(); + } + return new Tile(256, 256, bitmapData); + } else { + return NO_TILE; } - - return new Tile(256, 256, bitmapData); } } - private TileOverlayOptions tileOverlayOptions; private TileOverlay tileOverlay; From aebcc55536fab0a1c48531a84f81bb28e1295dcd Mon Sep 17 00:00:00 2001 From: Alvaro Leal Date: Thu, 4 May 2017 19:12:56 +0200 Subject: [PATCH 05/22] Remove unneeded logs and code --- .../com/airbnb/android/react/maps/AirMapCanvasUrlTile.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index dd90d5c87..06555b8c5 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -43,14 +43,11 @@ public Tile getTile(int x, int y, int zoom) { zoomCord = maxZoom; } - - Bitmap.Config conf = Bitmap.Config.ARGB_8888; - Bitmap coordTile = Bitmap.createBitmap(w, h, conf); ByteArrayOutputStream stream = new ByteArrayOutputStream(); - //coordTile.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] bitmapData = stream.toByteArray(); Uri.Builder builder = new Uri.Builder(); + builder.scheme("http") .authority("wri-tiles.s3.amazonaws.com") .appendPath("glad_prod") @@ -60,8 +57,6 @@ public Tile getTile(int x, int y, int zoom) { .appendPath(String.valueOf(yCord)); String providerUrl = builder.build().toString() + ".png"; - Log.d("Tiles", providerUrl); - int srcX = 0; int srcY = 0; int srcW = w; From d300083689f7417679ad7fd6522edd7fc8835bb7 Mon Sep 17 00:00:00 2001 From: Alvaro Leal Date: Thu, 4 May 2017 19:17:07 +0200 Subject: [PATCH 06/22] Scales the map to render the tiles without aliasing --- .../react/maps/AirMapCanvasUrlTile.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index 06555b8c5..b4ce475ff 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -31,6 +31,7 @@ public AIRMapCanvasUrlTileProvider(int width, int height) { } @Override public Tile getTile(int x, int y, int zoom) { + int TILE_SIZE = 256; int w = 256, h = 256; int maxZoom = 12; int xCord = x; @@ -61,11 +62,14 @@ public Tile getTile(int x, int y, int zoom) { int srcY = 0; int srcW = w; int srcH = h; + int scaleSize = 1; if (zoom > maxZoom) { int zsteps = zoom - maxZoom; int relation = (int) Math.pow(2, zsteps) ; - int size = (int) (256 / relation); + int size = (int) (TILE_SIZE / relation); + // we scale the map to keep the tiles sharp + scaleSize = (int) (TILE_SIZE * 2); srcX = (int) size * (x % relation); srcY = (int) size * (y % relation); srcW = (int) size; @@ -79,17 +83,21 @@ public Tile getTile(int x, int y, int zoom) { try { url = new URL(providerUrl); Bitmap image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); - - Bitmap resizedBitmap = Bitmap.createBitmap(image , srcX , srcY, srcW, srcH); + Bitmap croppedBitmap = Bitmap.createBitmap(image , srcX , srcY, srcW, srcH); + Bitmap scaledBitmap = croppedBitmap; + if (zoom > maxZoom) { + // The last false is for filter anti-aliasing + scaledBitmap = Bitmap.createScaledBitmap (croppedBitmap, scaleSize, scaleSize, false); + } int width, height, r, g, b, c; - height = resizedBitmap.getHeight(); - width = resizedBitmap.getWidth(); + height = scaledBitmap.getHeight(); + width = scaledBitmap.getWidth(); Bitmap finalBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); int red, green, blue, pixel, alpha; int[] pixels = new int[width * height]; - resizedBitmap.getPixels(pixels, 0, width, 0, 0, width, height); + scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height); for (int i = 0; i < pixels.length; i++) { pixel = pixels[i]; @@ -126,7 +134,7 @@ public Tile getTile(int x, int y, int zoom) { e.printStackTrace(); } - return new Tile(256, 256, bitmapData); + return new Tile(TILE_SIZE, TILE_SIZE, bitmapData); } } From 8155426357a6cb2ba20e59f123b3d55561e530ab Mon Sep 17 00:00:00 2001 From: j8seangel Date: Fri, 5 May 2017 11:30:00 +0200 Subject: [PATCH 07/22] Pass params from RN --- example/examples/CustomTiles.js | 6 + .../react/maps/AirMapCanvasUrlTile.java | 173 ++++++++++++------ .../maps/AirMapCanvasUrlTileManager.java | 27 ++- lib/components/MapCanvasUrlTile.js | 30 ++- 4 files changed, 171 insertions(+), 65 deletions(-) diff --git a/example/examples/CustomTiles.js b/example/examples/CustomTiles.js index a0f7991e1..97bfaf208 100644 --- a/example/examples/CustomTiles.js +++ b/example/examples/CustomTiles.js @@ -54,11 +54,17 @@ class CustomTiles extends React.Component { provider={this.props.provider} mapType={this.mapType} style={styles.map} + mapType="hybrid" initialRegion={region} > diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index c43cab6c6..299565b88 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -5,7 +5,6 @@ import android.graphics.BitmapFactory; import android.graphics.Color; import android.net.Uri; -import android.os.AsyncTask; import android.os.Environment; import android.util.Log; @@ -17,7 +16,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.InputStream; import java.net.URL; import java.lang.Math; @@ -25,48 +23,53 @@ public class AirMapCanvasUrlTile extends AirMapFeature { class AIRMapCanvasUrlTileProvider implements TileProvider { - public AIRMapCanvasUrlTileProvider(int width, int height) { + private String urlTemplate; + private int width; + private int height; + private int maxZoom; + private String areaName; + private boolean isConnected; + public AIRMapCanvasUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaName, boolean isConnected) { super(); + this.width = width; + this.height = height; + this.urlTemplate = urlTemplate; + this.maxZoom = maxZoom; + this.areaName = areaName; + this.isConnected = isConnected; } @Override public Tile getTile(int x, int y, int zoom) { - int TILE_SIZE = 256; - int w = 256, h = 256; + int TILE_SIZE = this.width; int maxZoom = 12; int xCord = x; int yCord = y; int zoomCord = zoom; int srcX = 0; int srcY = 0; - int srcW = w; - int srcH = h; + int srcW = this.width; + int srcH = this.height; int scaleSize = 1; - boolean online = true; - if (zoom > maxZoom) { - xCord = (int)(x / (Math.pow(2, zoom - maxZoom))); - yCord = (int)(y / (Math.pow(2, zoom - maxZoom))); - zoomCord = maxZoom; + if (zoom > this.maxZoom) { + xCord = (int)(x / (Math.pow(2, zoom - this.maxZoom))); + yCord = (int)(y / (Math.pow(2, zoom - this.maxZoom))); + zoomCord = this.maxZoom; } - Bitmap.Config conf = Bitmap.Config.ARGB_8888; ByteArrayOutputStream stream = new ByteArrayOutputStream(); byte[] bitmapData = stream.toByteArray(); Uri.Builder builder = new Uri.Builder(); Bitmap image; - if (online) { - builder.scheme("http") - .authority("wri-tiles.s3.amazonaws.com") - .appendPath("glad_prod") - .appendPath("tiles") - .appendPath(String.valueOf(zoomCord)) - .appendPath(String.valueOf(xCord)) - .appendPath(String.valueOf(yCord)); - String providerUrl = builder.build().toString() + ".png"; - - URL url = null; + if (this.isConnected) { + String providerUrl = this.urlTemplate + .replace("{x}", Integer.toString(xCord)) + .replace("{y}", Integer.toString(yCord)) + .replace("{z}", Integer.toString(zoomCord)); + + URL url; try { url = new URL(providerUrl); image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); @@ -79,18 +82,18 @@ public Tile getTile(int x, int y, int zoom) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_8888; File dir = Environment.getExternalStorageDirectory(); - File yourFile = new File(dir, "Download/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); + File myFile = new File(dir, areaName + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); try { - image = BitmapFactory.decodeFile(yourFile.getAbsolutePath(), options); + image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); } catch (Exception e) { e.printStackTrace(); return NO_TILE; } } - if (zoom > maxZoom) { - int zsteps = zoom - maxZoom; + if (zoom > this.maxZoom) { + int zsteps = zoom - this.maxZoom; int relation = (int) Math.pow(2, zsteps) ; int size = (int) (TILE_SIZE / relation); // we scale the map to keep the tiles sharp @@ -101,8 +104,6 @@ public Tile getTile(int x, int y, int zoom) { srcH = (int) size; } - URL url = null; - if (image != null) { Bitmap croppedBitmap = Bitmap.createBitmap(image , srcX , srcY, srcW, srcH); Bitmap scaledBitmap = croppedBitmap; @@ -141,11 +142,11 @@ public Tile getTile(int x, int y, int zoom) { } else { alpha = 0; } - + pixels[i] = Color.argb(alpha, red, green, blue); } - finalBitmap.setPixels(pixels, 0, width, 0, 0, width, height); - + finalBitmap.setPixels(pixels, 0, width, 0, 0, width, height); + stream = new ByteArrayOutputStream(); finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); bitmapData = stream.toByteArray(); @@ -154,53 +155,108 @@ public Tile getTile(int x, int y, int zoom) { return NO_TILE; } } + + public void setUrlTemplate(String urlTemplate) { + this.urlTemplate = urlTemplate; + } + + public void setMaxZoom(int maxZoom) { + this.maxZoom = maxZoom; + } + + public void setAreaName(String areaName) { + this.areaName = areaName; + } + + public void setIsConnected(boolean isConnected) { + this.isConnected = isConnected; + } } private TileOverlayOptions tileOverlayOptions; private TileOverlay tileOverlay; + private AIRMapCanvasUrlTileProvider tileProvider; private String urlTemplate; + private int maxZoom; + private String areaName; + private String minDate; + private String maxDate; + private boolean isConnected; private float zIndex; public AirMapCanvasUrlTile(Context context) { super(context); } - public void setZIndex(float zIndex) { - this.zIndex = zIndex; + public void setUrlTemplate(String urlTemplate) { + this.urlTemplate = urlTemplate; + if (tileProvider != null) { + tileProvider.setUrlTemplate(urlTemplate); + } if (tileOverlay != null) { - tileOverlay.setZIndex(zIndex); + tileOverlay.clearTileCache(); + } + } + + public void setMaxZoom(int maxZoom) { + this.maxZoom = maxZoom; + if (tileProvider != null) { + tileProvider.setMaxZoom(maxZoom); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); } } - private class DownloadTile extends AsyncTask { - private byte[] tile; + public void setAreaName(String areaName) { + this.areaName = areaName; + if (tileProvider != null) { + tileProvider.setAreaName(areaName); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } - public DownloadTile(byte[] tile) { - this.tile = tile; + public void setIsConnected(boolean isConnected) { + this.isConnected = isConnected; + if (tileProvider != null) { + tileProvider.setIsConnected(isConnected); } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } - protected Bitmap doInBackground(String... urls) { - String imageURL = urls[0]; - Bitmap bimage = null; - try { - InputStream in = new java.net.URL(imageURL).openStream(); - bimage = BitmapFactory.decodeStream(in); + public void setMinDate(String minDate) { + this.minDate = minDate; + } - } catch (Exception e) { - Log.e("Error Message", e.getMessage()); - e.printStackTrace(); - } - return bimage; + public void setMaxDate(String maxDate) { + this.minDate = maxDate; + } + + public void setZIndex(float zIndex) { + this.zIndex = zIndex; + if (tileOverlay != null) { + tileOverlay.setZIndex(zIndex); } + } - protected void onPostExecute(Bitmap result) { - Log.d("Title", String.valueOf(result)); - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - result.compress(Bitmap.CompressFormat.PNG, 0, stream); - this.tile = stream.toByteArray(); - Tile newTile = new Tile(256, 256, this.tile); + public TileOverlayOptions getTileOverlayOptions() { + if (tileOverlayOptions == null) { + tileOverlayOptions = createTileOverlayOptions(); } + return tileOverlayOptions; + } + + private TileOverlayOptions createTileOverlayOptions() { + TileOverlayOptions options = new TileOverlayOptions(); + options.zIndex(zIndex); + this.tileProvider = new AIRMapCanvasUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaName, this.isConnected); + options.tileProvider(this.tileProvider); + return options; } @Override @@ -210,8 +266,7 @@ public Object getFeature() { @Override public void addToMap(GoogleMap map) { - Log.d("Map", "Add to map"); - this.tileOverlay = map.addTileOverlay(new TileOverlayOptions().tileProvider(new AIRMapCanvasUrlTileProvider(256, 256))); + this.tileOverlay = map.addTileOverlay(getTileOverlayOptions()); } @Override diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java index 6632ea99c..46c5af3ee 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java @@ -39,7 +39,32 @@ public AirMapCanvasUrlTile createViewInstance(ThemedReactContext context) { @ReactProp(name = "urlTemplate") public void setUrlTemplate(AirMapCanvasUrlTile view, String urlTemplate) { - /*view.setUrlTemplate(urlTemplate);*/ + view.setUrlTemplate(urlTemplate); + } + + @ReactProp(name = "maxZoom", defaultInt = 12) + public void setMaxZoom(AirMapCanvasUrlTile view, int maxZoom) { + view.setMaxZoom(maxZoom); + } + + @ReactProp(name = "areaName") + public void setAreaName(AirMapCanvasUrlTile view, String areaName) { + view.setAreaName(areaName); + } + + @ReactProp(name = "isConnected", defaultBoolean = true) + public void setIsConnected(AirMapCanvasUrlTile view, boolean isConnected) { + view.setIsConnected(isConnected); + } + + @ReactProp(name = "minDate") + public void setMinDate(AirMapCanvasUrlTile view, String minDate) { + view.setMinDate(minDate); + } + + @ReactProp(name = "maxDate") + public void setMaxDate(AirMapCanvasUrlTile view, String maxDate) { + view.setMaxDate(maxDate); } @ReactProp(name = "zIndex", defaultFloat = -1.0f) diff --git a/lib/components/MapCanvasUrlTile.js b/lib/components/MapCanvasUrlTile.js index 77dd18579..a3c7f6e46 100644 --- a/lib/components/MapCanvasUrlTile.js +++ b/lib/components/MapCanvasUrlTile.js @@ -26,22 +26,42 @@ const propTypes = { * @platform android */ zIndex: PropTypes.number, + /** + * Flag to use the offline tiles instead of the url version + */ + isConnected: PropTypes.bool, + /** + * Area name to get the tiles from the corrent folder + */ + areaName: PropTypes.string, + /** + * Min date to get tiles + */ + minDate: PropTypes.string, + /** + * Max date to get tiles + */ + maxDate: PropTypes.string, + /** + * Max zoom when the tiles have data + */ + maxZoom: PropTypes.number, }; -class MapUrlTile extends React.Component { +class CanvasUrlTile extends React.Component { render() { - const AIRMapUrlTile = this.getAirComponent(); + const AIRMapCanvasUrlTile = this.getAirComponent(); return ( - ); } } -MapUrlTile.propTypes = propTypes; +CanvasUrlTile.propTypes = propTypes; -module.exports = decorateMapComponent(MapUrlTile, { +module.exports = decorateMapComponent(CanvasUrlTile, { componentType: 'CanvasUrlTile', providers: { google: { From 67c1acfcc21de26f7335be9fd6fa458e18612497 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Mon, 8 May 2017 16:49:31 +0200 Subject: [PATCH 08/22] Default props and view params --- lib/components/MapCanvasUrlTile.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/components/MapCanvasUrlTile.js b/lib/components/MapCanvasUrlTile.js index a3c7f6e46..bf3777941 100644 --- a/lib/components/MapCanvasUrlTile.js +++ b/lib/components/MapCanvasUrlTile.js @@ -9,6 +9,13 @@ import decorateMapComponent, { SUPPORTED, } from './decorateMapComponent'; +const viewConfig = { + uiViewClassName: 'AIRCanvasUrlTile', + validAttributes: { + coordinate: true, + }, +}; + const propTypes = { ...View.propTypes, @@ -48,6 +55,11 @@ const propTypes = { maxZoom: PropTypes.number, }; +const defaultProps = { + maxZoom: 12, + isConnected: true, +}; + class CanvasUrlTile extends React.Component { render() { const AIRMapCanvasUrlTile = this.getAirComponent(); @@ -59,7 +71,9 @@ class CanvasUrlTile extends React.Component { } } +CanvasUrlTile.viewConfig = viewConfig; CanvasUrlTile.propTypes = propTypes; +CanvasUrlTile.defaultProps = defaultProps; module.exports = decorateMapComponent(CanvasUrlTile, { componentType: 'CanvasUrlTile', From a7b6ff20c52c24007cc73e2286878a6b6217be44 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Mon, 8 May 2017 18:12:33 +0200 Subject: [PATCH 09/22] Remove unvalid attribute --- lib/components/MapCanvasUrlTile.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/components/MapCanvasUrlTile.js b/lib/components/MapCanvasUrlTile.js index bf3777941..9d18498ab 100644 --- a/lib/components/MapCanvasUrlTile.js +++ b/lib/components/MapCanvasUrlTile.js @@ -11,9 +11,6 @@ import decorateMapComponent, { const viewConfig = { uiViewClassName: 'AIRCanvasUrlTile', - validAttributes: { - coordinate: true, - }, }; const propTypes = { From 4bc67864ae7e7fde3018a5f0737927c727a5f49f Mon Sep 17 00:00:00 2001 From: j8seangel Date: Tue, 9 May 2017 09:53:59 +0200 Subject: [PATCH 10/22] Area id and app document folder --- .../react/maps/AirMapCanvasUrlTile.java | 26 ++++++++++--------- .../maps/AirMapCanvasUrlTileManager.java | 6 ++--- .../airbnb/android/react/maps/AirMapView.java | 6 ++--- lib/components/MapCanvasUrlTile.js | 4 +-- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index 299565b88..c14f1701a 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -27,15 +27,15 @@ class AIRMapCanvasUrlTileProvider implements TileProvider { private int width; private int height; private int maxZoom; - private String areaName; + private String areaId; private boolean isConnected; - public AIRMapCanvasUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaName, boolean isConnected) { + public AIRMapCanvasUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, boolean isConnected) { super(); this.width = width; this.height = height; this.urlTemplate = urlTemplate; this.maxZoom = maxZoom; - this.areaName = areaName; + this.areaId = areaId; this.isConnected = isConnected; } @Override @@ -51,6 +51,8 @@ public Tile getTile(int x, int y, int zoom) { int srcH = this.height; int scaleSize = 1; + // Log.d("Position", String.valueOf(x) + "x" + String.valueOf(y) + "x" + String.valueOf(zoom)); + if (zoom > this.maxZoom) { xCord = (int)(x / (Math.pow(2, zoom - this.maxZoom))); yCord = (int)(y / (Math.pow(2, zoom - this.maxZoom))); @@ -81,8 +83,8 @@ public Tile getTile(int x, int y, int zoom) { } else { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_8888; - File dir = Environment.getExternalStorageDirectory(); - File myFile = new File(dir, areaName + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); + File dir = getContext().getFilesDir(); + File myFile = new File(dir, "tiles/" + areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); try { image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); @@ -164,8 +166,8 @@ public void setMaxZoom(int maxZoom) { this.maxZoom = maxZoom; } - public void setAreaName(String areaName) { - this.areaName = areaName; + public void setAreaId(String areaId) { + this.areaId = areaId; } public void setIsConnected(boolean isConnected) { @@ -179,7 +181,7 @@ public void setIsConnected(boolean isConnected) { private String urlTemplate; private int maxZoom; - private String areaName; + private String areaId; private String minDate; private String maxDate; private boolean isConnected; @@ -209,10 +211,10 @@ public void setMaxZoom(int maxZoom) { } } - public void setAreaName(String areaName) { - this.areaName = areaName; + public void setAreaId(String areaId) { + this.areaId = areaId; if (tileProvider != null) { - tileProvider.setAreaName(areaName); + tileProvider.setAreaId(areaId); } if (tileOverlay != null) { tileOverlay.clearTileCache(); @@ -254,7 +256,7 @@ public TileOverlayOptions getTileOverlayOptions() { private TileOverlayOptions createTileOverlayOptions() { TileOverlayOptions options = new TileOverlayOptions(); options.zIndex(zIndex); - this.tileProvider = new AIRMapCanvasUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaName, this.isConnected); + this.tileProvider = new AIRMapCanvasUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected); options.tileProvider(this.tileProvider); return options; } diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java index 46c5af3ee..da771c0e9 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java @@ -47,9 +47,9 @@ public void setMaxZoom(AirMapCanvasUrlTile view, int maxZoom) { view.setMaxZoom(maxZoom); } - @ReactProp(name = "areaName") - public void setAreaName(AirMapCanvasUrlTile view, String areaName) { - view.setAreaName(areaName); + @ReactProp(name = "areaId") + public void setAreaId(AirMapCanvasUrlTile view, String areaId) { + view.setAreaId(areaId); } @ReactProp(name = "isConnected", defaultBoolean = true) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java index b2b1631b5..2b7fb31ef 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java @@ -457,9 +457,9 @@ public void addFeature(View child, int index) { urlTileView.addToMap(map); features.add(index, urlTileView); } else if (child instanceof AirMapCanvasUrlTile) { - AirMapCanvasUrlTile canvasUrlTileView = (AirMapCanvasUrlTile) child; - canvasUrlTileView.addToMap(map); - features.add(index, canvasUrlTileView); + AirMapCanvasUrlTile canvasUrlTileView = (AirMapCanvasUrlTile) child; + canvasUrlTileView.addToMap(map); + features.add(index, canvasUrlTileView); } else { ViewGroup children = (ViewGroup) child; for (int i = 0; i < children.getChildCount(); i++) { diff --git a/lib/components/MapCanvasUrlTile.js b/lib/components/MapCanvasUrlTile.js index 9d18498ab..1fbe6f753 100644 --- a/lib/components/MapCanvasUrlTile.js +++ b/lib/components/MapCanvasUrlTile.js @@ -35,9 +35,9 @@ const propTypes = { */ isConnected: PropTypes.bool, /** - * Area name to get the tiles from the corrent folder + * Area id to get the tiles from the corrent folder */ - areaName: PropTypes.string, + areaId: PropTypes.string, /** * Min date to get tiles */ From 9faaadb6bee8321a4c2e71ced37bd5f342a542c3 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Tue, 9 May 2017 10:13:00 +0200 Subject: [PATCH 11/22] Fix android path --- build.gradle | 2 +- .../java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index f89d2c594..8a3e2453e 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.android.tools.build:gradle:2.3.1' } } diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index c14f1701a..0edca1f19 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -84,7 +84,7 @@ public Tile getTile(int x, int y, int zoom) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_8888; File dir = getContext().getFilesDir(); - File myFile = new File(dir, "tiles/" + areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); + File myFile = new File(dir + "/tiles", areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); try { image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); From fd0152a3230e451c1f7489df329875d1dac8281c Mon Sep 17 00:00:00 2001 From: Alvaro Leal Date: Tue, 9 May 2017 12:56:38 +0200 Subject: [PATCH 12/22] Filter alerts by min and max days since the start date in the tileProvider --- .../react/maps/AirMapCanvasUrlTile.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index 0edca1f19..13d1a15ae 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -28,8 +28,10 @@ class AIRMapCanvasUrlTileProvider implements TileProvider { private int height; private int maxZoom; private String areaId; + private String minDate; + private String maxDate; private boolean isConnected; - public AIRMapCanvasUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, boolean isConnected) { + public AIRMapCanvasUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, boolean isConnected, String minDate, String maxDate) { super(); this.width = width; this.height = height; @@ -37,6 +39,8 @@ public AIRMapCanvasUrlTileProvider(int width, int height, String urlTemplate, in this.maxZoom = maxZoom; this.areaId = areaId; this.isConnected = isConnected; + this.minDate = minDate; + this.maxDate = maxDate; } @Override public Tile getTile(int x, int y, int zoom) { @@ -50,7 +54,8 @@ public Tile getTile(int x, int y, int zoom) { int srcW = this.width; int srcH = this.height; int scaleSize = 1; - + int minDate = Integer.valueOf(this.minDate); + int maxDate = Integer.valueOf(this.maxDate); // Log.d("Position", String.valueOf(x) + "x" + String.valueOf(y) + "x" + String.valueOf(zoom)); if (zoom > this.maxZoom) { @@ -129,14 +134,14 @@ public Tile getTile(int x, int y, int zoom) { green = (pixel >> 8) & 0xFF; blue = pixel & 0xFF; - int day = red * 255 + green; - if (red > 255) red = 255; if (green > 255) green = 255; - if (day > 0) { + int day = red * 255 + green; + + if (day > 0 && day >= minDate && day <= maxDate) { red = 220; green = 102; blue = 153; @@ -236,7 +241,7 @@ public void setMinDate(String minDate) { } public void setMaxDate(String maxDate) { - this.minDate = maxDate; + this.maxDate = maxDate; } public void setZIndex(float zIndex) { @@ -256,7 +261,7 @@ public TileOverlayOptions getTileOverlayOptions() { private TileOverlayOptions createTileOverlayOptions() { TileOverlayOptions options = new TileOverlayOptions(); options.zIndex(zIndex); - this.tileProvider = new AIRMapCanvasUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected); + this.tileProvider = new AIRMapCanvasUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected, this.minDate, this.maxDate); options.tileProvider(this.tileProvider); return options; } From 09350da0ecb17e1b7d71094abe88bf4e45e26326 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Wed, 10 May 2017 17:38:00 +0200 Subject: [PATCH 13/22] Add interaction canvas layer --- example/examples/CustomTiles.js | 56 +++- .../maps/AirMapCanvasInteractionUrlTile.java | 315 ++++++++++++++++++ ...AirMapCanvasInteractionUrlTileManager.java | 84 +++++ .../airbnb/android/react/maps/AirMapView.java | 4 + .../android/react/maps/MapsPackage.java | 4 +- lib/components/MapCanvasInteractionUrlTile.js | 91 +++++ lib/components/MapView.js | 2 + package.json | 4 + 8 files changed, 557 insertions(+), 3 deletions(-) create mode 100644 lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java create mode 100644 lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java create mode 100644 lib/components/MapCanvasInteractionUrlTile.js diff --git a/example/examples/CustomTiles.js b/example/examples/CustomTiles.js index 97bfaf208..86b9f6fb8 100644 --- a/example/examples/CustomTiles.js +++ b/example/examples/CustomTiles.js @@ -10,6 +10,9 @@ import { import MapView, { MAP_TYPES, PROVIDER_DEFAULT } from 'react-native-maps'; +const geoViewport = require('@mapbox/geo-viewport'); +const tilebelt = require('@mapbox/tilebelt'); + const { width, height } = Dimensions.get('window'); const ASPECT_RATIO = width / height; @@ -23,6 +26,11 @@ class CustomTiles extends React.Component { super(props, context); this.state = { + coordinates: { + latitude: null, + longitude: null, + tile: [], // tile coordinates x, y, z + }, region: { latitude: LATITUDE, longitude: LONGITUDE, @@ -45,9 +53,39 @@ class CustomTiles extends React.Component { } } + getMapZoom() { + const position = this.state.region; + + const bounds = [ + position.longitude - (position.longitudeDelta / 2), + position.latitude - (position.latitudeDelta / 2), + position.longitude + (position.longitudeDelta / 2), + position.latitude + (position.latitudeDelta / 2), + ]; + + return geoViewport.viewport(bounds, [height, width]).zoom || null; + } + + onRegionChange = (region) => { + this.setState({ region }); + } + + onMapPress = (e) => { + const coordinates = e.nativeEvent.coordinate; + const zoom = this.getMapZoom(); + const tile = tilebelt.pointToTile(coordinates.longitude, coordinates.latitude, zoom); + this.setState({ + coordinates: { + ...coordinates, + tile, + }, + }); + } render() { - const { region } = this.state; + const { region, coordinates } = this.state; + const hasCoordinates = (coordinates.latitude && coordinates.longitude && coordinates.tile !== null) || false; + return ( + {hasCoordinates && + + } diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java new file mode 100644 index 000000000..390d1027e --- /dev/null +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java @@ -0,0 +1,315 @@ +package com.airbnb.android.react.maps; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.net.Uri; +import android.os.Environment; +import android.util.Log; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.model.Tile; +import com.google.android.gms.maps.model.TileOverlay; +import com.google.android.gms.maps.model.TileOverlayOptions; +import com.google.android.gms.maps.model.TileProvider; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.net.URL; +import java.lang.Math; + +public class AirMapCanvasInteractionUrlTile extends AirMapFeature { + private class Coordinates { + private double lat; + private double lng; + private int[] tile; + + public Coordinates(double lat, double lng, int[] tile) { + this.lat = lat; + this.lng = lng; + this.tile = tile; + } + + public double getLat() { + return lat; + } + + public double getLng() { + return lng; + } + + public int[] getTile() { + return tile; + } + } + + + class AIRMapCanvasInteractionUrlTileProvider implements TileProvider { + private String urlTemplate; + private int width; + private int height; + private int maxZoom; + private String areaId; + private boolean isConnected; + private Coordinates coordinates; + public AIRMapCanvasInteractionUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, boolean isConnected, Coordinates coordinates) { + super(); + this.width = width; + this.height = height; + this.urlTemplate = urlTemplate; + this.maxZoom = maxZoom; + this.areaId = areaId; + this.isConnected = isConnected; + this.coordinates = coordinates; + } + @Override + public Tile getTile(int x, int y, int zoom) { + int TILE_SIZE = this.width; + int maxZoom = 12; + int xCord = x; + int yCord = y; + int zoomCord = zoom; + int srcX = 0; + int srcY = 0; + int srcW = this.width; + int srcH = this.height; + int scaleSize = 1; + + int[] tile = coordinates.getTile(); + Log.d("tile Position: ", x + "-" + y + "-" + zoom); + Log.d("tile given: ", tile[0] + "-" + tile[1] + "-" + tile[2]); + + if (tile[0] == x && tile[1] == y && tile[2] == zoom) { + + if (zoom > this.maxZoom) { + xCord = (int)(x / (Math.pow(2, zoom - this.maxZoom))); + yCord = (int)(y / (Math.pow(2, zoom - this.maxZoom))); + zoomCord = this.maxZoom; + } + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + byte[] bitmapData = stream.toByteArray(); + + Bitmap image; + + if (this.isConnected) { + String providerUrl = this.urlTemplate + .replace("{x}", Integer.toString(xCord)) + .replace("{y}", Integer.toString(yCord)) + .replace("{z}", Integer.toString(zoomCord)); + + URL url; + try { + url = new URL(providerUrl); + image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); + } catch (Exception e) { + e.printStackTrace(); + return NO_TILE; + } + + } else { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + File dir = getContext().getFilesDir(); + File myFile = new File(dir + "/tiles", areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); + + try { + image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); + } catch (Exception e) { + e.printStackTrace(); + return NO_TILE; + } + } + + if (zoom > this.maxZoom) { + int zsteps = zoom - this.maxZoom; + int relation = (int) Math.pow(2, zsteps) ; + int size = (int) (TILE_SIZE / relation); + // we scale the map to keep the tiles sharp + scaleSize = (int) (TILE_SIZE * 2); + srcX = (int) size * (x % relation); + srcY = (int) size * (y % relation); + srcW = (int) size; + srcH = (int) size; + } + + if (image != null) { + Bitmap croppedBitmap = Bitmap.createBitmap(image , srcX , srcY, srcW, srcH); + Bitmap scaledBitmap = croppedBitmap; + if (zoom > maxZoom) { + // The last false is for filter anti-aliasing + scaledBitmap = Bitmap.createScaledBitmap (croppedBitmap, scaleSize, scaleSize, false); + } + + int width, height, r, g, b, c; + height = scaledBitmap.getHeight(); + width = scaledBitmap.getWidth(); + + Bitmap finalBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + int red, green, blue, pixel, alpha; + int[] pixels = new int[width * height]; + scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height); + for (int i = 0; i < pixels.length; i++) { + pixel = pixels[i]; + + red = (pixel >> 16) & 0xFF; + green = (pixel >> 8) & 0xFF; + blue = pixel & 0xFF; + + int day = red * 255 + green; + + red = 255; + green = 255; + blue = 255; + alpha = 100; + + pixels[i] = Color.argb(alpha, red, green, blue); + } + finalBitmap.setPixels(pixels, 0, width, 0, 0, width, height); + + stream = new ByteArrayOutputStream(); + finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); + bitmapData = stream.toByteArray(); + return new Tile(TILE_SIZE, TILE_SIZE, bitmapData); + } else { + return NO_TILE; + } + } else { + return NO_TILE; + } + } + + public void setUrlTemplate(String urlTemplate) { + this.urlTemplate = urlTemplate; + } + + public void setMaxZoom(int maxZoom) { + this.maxZoom = maxZoom; + } + + public void setAreaId(String areaId) { + this.areaId = areaId; + } + + public void setIsConnected(boolean isConnected) { + this.isConnected = isConnected; + } + + public void setCoordinates(Coordinates coordinates) { + this.coordinates = coordinates; + } + } + + private TileOverlayOptions tileOverlayOptions; + private TileOverlay tileOverlay; + private AIRMapCanvasInteractionUrlTileProvider tileProvider; + + private String urlTemplate; + private int maxZoom; + private String areaId; + private String minDate; + private String maxDate; + private boolean isConnected; + private float zIndex; + private Coordinates coordinates; + + public AirMapCanvasInteractionUrlTile(Context context) { + super(context); + } + + public void setUrlTemplate(String urlTemplate) { + this.urlTemplate = urlTemplate; + if (tileProvider != null) { + tileProvider.setUrlTemplate(urlTemplate); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + + public void setMaxZoom(int maxZoom) { + this.maxZoom = maxZoom; + if (tileProvider != null) { + tileProvider.setMaxZoom(maxZoom); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + + public void setAreaId(String areaId) { + this.areaId = areaId; + if (tileProvider != null) { + tileProvider.setAreaId(areaId); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + + public void setIsConnected(boolean isConnected) { + this.isConnected = isConnected; + if (tileProvider != null) { + tileProvider.setIsConnected(isConnected); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + + public void setMinDate(String minDate) { + this.minDate = minDate; + } + + public void setMaxDate(String maxDate) { + this.minDate = maxDate; + } + + public void setZIndex(float zIndex) { + this.zIndex = zIndex; + if (tileOverlay != null) { + tileOverlay.setZIndex(zIndex); + } + } + + public void setCoordinates(double lat, double lng, int[] tile) { + this.coordinates = new Coordinates(lat, lng, tile); + if (tileProvider != null) { + tileProvider.setCoordinates(coordinates); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + + public TileOverlayOptions getTileOverlayOptions() { + if (tileOverlayOptions == null) { + tileOverlayOptions = createTileOverlayOptions(); + } + return tileOverlayOptions; + } + + private TileOverlayOptions createTileOverlayOptions() { + TileOverlayOptions options = new TileOverlayOptions(); + options.zIndex(zIndex); + this.tileProvider = new AIRMapCanvasInteractionUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected, this.coordinates); + options.tileProvider(this.tileProvider); + return options; + } + + @Override + public Object getFeature() { + return tileOverlay; + } + + @Override + public void addToMap(GoogleMap map) { + this.tileOverlay = map.addTileOverlay(getTileOverlayOptions()); + } + + @Override + public void removeFromMap(GoogleMap map) { + tileOverlay.remove(); + } +} diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java new file mode 100644 index 000000000..97862d1f1 --- /dev/null +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java @@ -0,0 +1,84 @@ +package com.airbnb.android.react.maps; + +import android.content.Context; +import android.os.Build; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.WindowManager; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.ViewGroupManager; +import com.facebook.react.uimanager.annotations.ReactProp; + +public class AirMapCanvasInteractionUrlTileManager extends ViewGroupManager { + private DisplayMetrics metrics; + + public AirMapCanvasInteractionUrlTileManager(ReactApplicationContext reactContext) { + super(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + metrics = new DisplayMetrics(); + ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay() + .getRealMetrics(metrics); + } else { + metrics = reactContext.getResources().getDisplayMetrics(); + } + } + + @Override + public String getName() { + Log.d("Map", "Get name"); + return "AIRMapCanvasInteractionUrlTile"; + } + + @Override + public AirMapCanvasInteractionUrlTile createViewInstance(ThemedReactContext context) { + return new AirMapCanvasInteractionUrlTile(context); + } + + @ReactProp(name = "urlTemplate") + public void setUrlTemplate(AirMapCanvasInteractionUrlTile view, String urlTemplate) { + view.setUrlTemplate(urlTemplate); + } + + @ReactProp(name = "maxZoom", defaultInt = 12) + public void setMaxZoom(AirMapCanvasInteractionUrlTile view, int maxZoom) { + view.setMaxZoom(maxZoom); + } + + @ReactProp(name = "areaId") + public void setAreaId(AirMapCanvasInteractionUrlTile view, String areaId) { + view.setAreaId(areaId); + } + + @ReactProp(name = "isConnected", defaultBoolean = true) + public void setIsConnected(AirMapCanvasInteractionUrlTile view, boolean isConnected) { + view.setIsConnected(isConnected); + } + + @ReactProp(name = "minDate") + public void setMinDate(AirMapCanvasInteractionUrlTile view, String minDate) { + view.setMinDate(minDate); + } + + @ReactProp(name = "maxDate") + public void setMaxDate(AirMapCanvasInteractionUrlTile view, String maxDate) { + view.setMaxDate(maxDate); + } + + @ReactProp(name = "zIndex", defaultFloat = -1.0f) + public void setZIndex(AirMapCanvasInteractionUrlTile view, float zIndex) { + view.setZIndex(zIndex); + } + + @ReactProp(name = "coordinates") + public void setCoordinates(AirMapCanvasInteractionUrlTile view, ReadableMap coordinates) { + if (coordinates != null) { + int[] tile = new int[]{coordinates.getArray("tile").getInt(0), coordinates.getArray("tile").getInt(1), coordinates.getArray("tile").getInt(2)}; + view.setCoordinates(coordinates.getDouble("latitude"), coordinates.getDouble("longitude"), tile); + } + } + +} diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java index 2b7fb31ef..5594cc46d 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java @@ -460,6 +460,10 @@ public void addFeature(View child, int index) { AirMapCanvasUrlTile canvasUrlTileView = (AirMapCanvasUrlTile) child; canvasUrlTileView.addToMap(map); features.add(index, canvasUrlTileView); + } else if (child instanceof AirMapCanvasInteractionUrlTile) { + AirMapCanvasInteractionUrlTile canvasInteractionUrlTileView = (AirMapCanvasInteractionUrlTile) child; + canvasInteractionUrlTileView.addToMap(map); + features.add(index, canvasInteractionUrlTileView); } else { ViewGroup children = (ViewGroup) child; for (int i = 0; i < children.getChildCount(); i++) { diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java b/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java index 5dea52f14..5284e1581 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java @@ -40,6 +40,7 @@ public List createViewManagers(ReactApplicationContext reactContext AirMapLiteManager mapLiteManager = new AirMapLiteManager(reactContext); AirMapUrlTileManager tileManager = new AirMapUrlTileManager(reactContext); AirMapCanvasUrlTileManager canvasTileManager = new AirMapCanvasUrlTileManager(reactContext); + AirMapCanvasInteractionUrlTileManager canvasInteractionTileManager = new AirMapCanvasInteractionUrlTileManager(reactContext); return Arrays.asList( calloutManager, @@ -50,6 +51,7 @@ public List createViewManagers(ReactApplicationContext reactContext mapManager, mapLiteManager, tileManager, - canvasTileManager); + canvasTileManager, + canvasInteractionTileManager); } } diff --git a/lib/components/MapCanvasInteractionUrlTile.js b/lib/components/MapCanvasInteractionUrlTile.js new file mode 100644 index 000000000..a708a2445 --- /dev/null +++ b/lib/components/MapCanvasInteractionUrlTile.js @@ -0,0 +1,91 @@ +import React, { PropTypes } from 'react'; + +import { + View, +} from 'react-native'; + +import decorateMapComponent, { + USES_DEFAULT_IMPLEMENTATION, + SUPPORTED, +} from './decorateMapComponent'; + +const viewConfig = { + uiViewClassName: 'AIRCanvasInteractionUrlTile', +}; + +const propTypes = { + ...View.propTypes, + + /** + * The url template of the tile server. The patterns {x} {y} {z} will be replaced at runtime + * For example, http://c.tile.openstreetmap.org/{z}/{x}/{y}.png + */ + urlTemplate: PropTypes.string.isRequired, + + /** + * The order in which this tile overlay is drawn with respect to other overlays. An overlay + * with a larger z-index is drawn over overlays with smaller z-indices. The order of overlays + * with the same z-index is arbitrary. The default zIndex is -1. + * + * @platform android + */ + zIndex: PropTypes.number, + /** + * Flag to use the offline tiles instead of the url version + */ + isConnected: PropTypes.bool, + /** + * Area id to get the tiles from the corrent folder + */ + areaId: PropTypes.string, + /** + * Min date to get tiles + */ + minDate: PropTypes.string, + /** + * Max date to get tiles + */ + maxDate: PropTypes.string, + /** + * Max zoom when the tiles have data + */ + maxZoom: PropTypes.number, + /** + * Max zoom when the tiles have data + */ + coordinates: PropTypes.shape({ + latitud: PropTypes.number, + longitud: PropTypes.number, + tile: PropTypes.arrayOf(React.PropTypes.number), + }), +}; + +const defaultProps = { + maxZoom: 12, + isConnected: true, +}; + +class CanvasInteractionUrlTile extends React.Component { + render() { + const AIRMapCanvasInteractionUrlTile = this.getAirComponent(); + return ( + + ); + } +} + +CanvasInteractionUrlTile.viewConfig = viewConfig; +CanvasInteractionUrlTile.propTypes = propTypes; +CanvasInteractionUrlTile.defaultProps = defaultProps; + +module.exports = decorateMapComponent(CanvasInteractionUrlTile, { + componentType: 'CanvasInteractionUrlTile', + providers: { + google: { + ios: SUPPORTED, + android: USES_DEFAULT_IMPLEMENTATION, + }, + }, +}); diff --git a/lib/components/MapView.js b/lib/components/MapView.js index ee89d5e84..1b416687b 100644 --- a/lib/components/MapView.js +++ b/lib/components/MapView.js @@ -16,6 +16,7 @@ import MapCircle from './MapCircle'; import MapCallout from './MapCallout'; import MapUrlTile from './MapUrlTile'; import MapCanvasUrlTile from './MapCanvasUrlTile'; +import MapCanvasInteractionUrlTile from './MapCanvasInteractionUrlTile'; import AnimatedRegion from './AnimatedRegion'; import { contextTypes as childContextTypes, @@ -682,6 +683,7 @@ MapView.Polygon = MapPolygon; MapView.Circle = MapCircle; MapView.UrlTile = MapUrlTile; MapView.CanvasUrlTile = MapCanvasUrlTile; +MapView.CanvasInteractionUrlTile = MapCanvasInteractionUrlTile; MapView.Callout = MapCallout; Object.assign(MapView, ProviderConstants); MapView.ProviderPropType = PropTypes.oneOf(Object.values(ProviderConstants)); diff --git a/package.json b/package.json index 70224da44..a072b8950 100644 --- a/package.json +++ b/package.json @@ -55,5 +55,9 @@ "android": { "sourceDir": "./android" } + }, + "dependencies": { + "@mapbox/geo-viewport": "^0.2.2", + "@mapbox/tilebelt": "^1.0.1" } } From 7f62ccd4afbc415a5b3910994f513d51ce4fc8b5 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Thu, 11 May 2017 14:03:23 +0200 Subject: [PATCH 14/22] Add interaction custom urltile layer --- example/examples/CustomTiles.js | 20 +-- lib/android/gradle.properties | 1 + .../maps/AirMapCanvasInteractionUrlTile.java | 147 ++++++++++-------- ...AirMapCanvasInteractionUrlTileManager.java | 3 +- lib/components/MapCanvasInteractionUrlTile.js | 3 +- 5 files changed, 92 insertions(+), 82 deletions(-) diff --git a/example/examples/CustomTiles.js b/example/examples/CustomTiles.js index 86b9f6fb8..1f2f4f55f 100644 --- a/example/examples/CustomTiles.js +++ b/example/examples/CustomTiles.js @@ -27,9 +27,8 @@ class CustomTiles extends React.Component { this.state = { coordinates: { - latitude: null, - longitude: null, - tile: [], // tile coordinates x, y, z + tile: [], // tile coordinates x, y, z + precision x, y + precision: [], // tile precision x, y }, region: { latitude: LATITUDE, @@ -73,19 +72,20 @@ class CustomTiles extends React.Component { onMapPress = (e) => { const coordinates = e.nativeEvent.coordinate; const zoom = this.getMapZoom(); - const tile = tilebelt.pointToTile(coordinates.longitude, coordinates.latitude, zoom); + const tile = tilebelt.pointToTile(coordinates.longitude, coordinates.latitude, zoom, true); + this.setState({ coordinates: { - ...coordinates, - tile, + tile: [tile[0], tile[1], tile[2]], + precision: [tile[3], tile[4]], }, }); } render() { const { region, coordinates } = this.state; - const hasCoordinates = (coordinates.latitude && coordinates.longitude && coordinates.tile !== null) || false; - + const hasCoordinates = (coordinates.tile && coordinates.tile.length > 0) || false; + console.log(coordinates); return ( this.maxZoom) { - xCord = (int)(x / (Math.pow(2, zoom - this.maxZoom))); - yCord = (int)(y / (Math.pow(2, zoom - this.maxZoom))); - zoomCord = this.maxZoom; + xCord = (int)(x / (Math.pow(2, zoom - this.maxZoom))); + yCord = (int)(y / (Math.pow(2, zoom - this.maxZoom))); + zoomCord = this.maxZoom; } ByteArrayOutputStream stream = new ByteArrayOutputStream(); @@ -94,44 +86,44 @@ public Tile getTile(int x, int y, int zoom) { Bitmap image; if (this.isConnected) { - String providerUrl = this.urlTemplate - .replace("{x}", Integer.toString(xCord)) - .replace("{y}", Integer.toString(yCord)) - .replace("{z}", Integer.toString(zoomCord)); - - URL url; - try { - url = new URL(providerUrl); - image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); - } catch (Exception e) { - e.printStackTrace(); - return NO_TILE; - } + String providerUrl = this.urlTemplate + .replace("{x}", Integer.toString(xCord)) + .replace("{y}", Integer.toString(yCord)) + .replace("{z}", Integer.toString(zoomCord)); + + URL url; + try { + url = new URL(providerUrl); + image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); + } catch (Exception e) { + e.printStackTrace(); + return NO_TILE; + } } else { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - File dir = getContext().getFilesDir(); - File myFile = new File(dir + "/tiles", areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); - - try { - image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); - } catch (Exception e) { - e.printStackTrace(); - return NO_TILE; - } + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + File dir = getContext().getFilesDir(); + File myFile = new File(dir + "/tiles", areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); + + try { + image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); + } catch (Exception e) { + e.printStackTrace(); + return NO_TILE; + } } if (zoom > this.maxZoom) { - int zsteps = zoom - this.maxZoom; - int relation = (int) Math.pow(2, zsteps) ; - int size = (int) (TILE_SIZE / relation); - // we scale the map to keep the tiles sharp - scaleSize = (int) (TILE_SIZE * 2); - srcX = (int) size * (x % relation); - srcY = (int) size * (y % relation); - srcW = (int) size; - srcH = (int) size; + int zsteps = zoom - this.maxZoom; + int relation = (int) Math.pow(2, zsteps) ; + int size = (int) (TILE_SIZE / relation); + // we scale the map to keep the tiles sharp + scaleSize = (int) (TILE_SIZE * 2); + srcX = (int) size * (x % relation); + srcY = (int) size * (y % relation); + srcW = (int) size; + srcH = (int) size; } if (image != null) { @@ -150,30 +142,46 @@ public Tile getTile(int x, int y, int zoom) { int red, green, blue, pixel, alpha; int[] pixels = new int[width * height]; scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height); - for (int i = 0; i < pixels.length; i++) { - pixel = pixels[i]; - red = (pixel >> 16) & 0xFF; - green = (pixel >> 8) & 0xFF; - blue = pixel & 0xFF; + double[] precision = coordinates.getPrecision(); + int xFilter = (int)(precision[0] * width); + int yFilter = (int)(precision[1] * height); - int day = red * 255 + green; + for(int xPoint=0; xPoint < width; xPoint++) { + for(int yPoint=0; yPoint < height; yPoint++) { + c = scaledBitmap.getPixel(xPoint, yPoint); - red = 255; - green = 255; - blue = 255; - alpha = 100; + red = Color.red(c); + green = Color.green(c); + blue = Color.blue(c); + + if (red > 255) + red = 255; + if (green > 255) + green = 255; + + int day = red * 255 + green; - pixels[i] = Color.argb(alpha, red, green, blue); + // if (day > 0 && day >= minDate && day <= maxDate) { + if (xPoint == xFilter && yPoint == yFilter) { + red = 255; + green = 255; + blue = 255; + alpha = 255; + } else { + alpha = 0; + } + + finalBitmap.setPixel(xPoint, yPoint, Color.argb(alpha, red, green, blue)); + } } - finalBitmap.setPixels(pixels, 0, width, 0, 0, width, height); - stream = new ByteArrayOutputStream(); - finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); - bitmapData = stream.toByteArray(); - return new Tile(TILE_SIZE, TILE_SIZE, bitmapData); + stream = new ByteArrayOutputStream(); + finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); + bitmapData = stream.toByteArray(); + return new Tile(TILE_SIZE, TILE_SIZE, bitmapData); } else { - return NO_TILE; + return NO_TILE; } } else { return NO_TILE; @@ -273,8 +281,8 @@ public void setZIndex(float zIndex) { } } - public void setCoordinates(double lat, double lng, int[] tile) { - this.coordinates = new Coordinates(lat, lng, tile); + public void setCoordinates(int[] tile, double[] precision) { + this.coordinates = new Coordinates(tile, precision); if (tileProvider != null) { tileProvider.setCoordinates(coordinates); } @@ -295,6 +303,7 @@ private TileOverlayOptions createTileOverlayOptions() { options.zIndex(zIndex); this.tileProvider = new AIRMapCanvasInteractionUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected, this.coordinates); options.tileProvider(this.tileProvider); + // options.fadeIn(false); return options; } diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java index 97862d1f1..e629b2fe8 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java @@ -77,7 +77,8 @@ public void setZIndex(AirMapCanvasInteractionUrlTile view, float zIndex) { public void setCoordinates(AirMapCanvasInteractionUrlTile view, ReadableMap coordinates) { if (coordinates != null) { int[] tile = new int[]{coordinates.getArray("tile").getInt(0), coordinates.getArray("tile").getInt(1), coordinates.getArray("tile").getInt(2)}; - view.setCoordinates(coordinates.getDouble("latitude"), coordinates.getDouble("longitude"), tile); + double[] precision = new double[]{coordinates.getArray("precision").getDouble(0), coordinates.getArray("precision").getDouble(1)}; + view.setCoordinates(tile, precision); } } diff --git a/lib/components/MapCanvasInteractionUrlTile.js b/lib/components/MapCanvasInteractionUrlTile.js index a708a2445..cafddfa06 100644 --- a/lib/components/MapCanvasInteractionUrlTile.js +++ b/lib/components/MapCanvasInteractionUrlTile.js @@ -54,9 +54,8 @@ const propTypes = { * Max zoom when the tiles have data */ coordinates: PropTypes.shape({ - latitud: PropTypes.number, - longitud: PropTypes.number, tile: PropTypes.arrayOf(React.PropTypes.number), + precision: PropTypes.arrayOf(React.PropTypes.number), }), }; From df857238cfb1989e76b88202ed52d8aa51a71bb2 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Thu, 11 May 2017 16:39:11 +0200 Subject: [PATCH 15/22] New library for tile float part and fix zoom --- example/examples/CustomTiles.js | 22 ++++++++++++++++++---- package.json | 2 +- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/example/examples/CustomTiles.js b/example/examples/CustomTiles.js index 1f2f4f55f..1e8306110 100644 --- a/example/examples/CustomTiles.js +++ b/example/examples/CustomTiles.js @@ -62,11 +62,20 @@ class CustomTiles extends React.Component { position.latitude + (position.latitudeDelta / 2), ]; - return geoViewport.viewport(bounds, [height, width]).zoom || null; + return geoViewport.viewport(bounds, [width, height], 0, 21, 256).zoom || 0; + } + + onRegionChangeComplete = (region) => { + this.updateRegion(region); } onRegionChange = (region) => { - this.setState({ region }); + if (this.onRegionChangeTimer) { + clearTimeout(this.onRegionChangeTimer); + } + this.onRegionChangeTimer = setTimeout(() => { + this.updateRegion(region); + }, 200); } onMapPress = (e) => { @@ -82,9 +91,13 @@ class CustomTiles extends React.Component { }); } + updateRegion = (region) => { + this.setState({ region }); + } + render() { const { region, coordinates } = this.state; - const hasCoordinates = (coordinates.tile && coordinates.tile.length > 0) || false; + const hasCoordinates = (coordinates.tile && coordinates.tile.length === 3) || false; console.log(coordinates); return ( @@ -95,7 +108,8 @@ class CustomTiles extends React.Component { mapType="hybrid" onPress={this.onMapPress} initialRegion={region} - onRegionChangeComplete={this.onRegionChange} + onRegionChange={this.onRegionChange} + onRegionChangeComplete={this.onRegionChangeComplete} > Date: Thu, 11 May 2017 18:03:22 +0200 Subject: [PATCH 16/22] Show pixel only within data --- .../maps/AirMapCanvasInteractionUrlTile.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java index c2d9b05f0..b325c429e 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java @@ -44,15 +44,19 @@ class AIRMapCanvasInteractionUrlTileProvider implements TileProvider { private int height; private int maxZoom; private String areaId; + private String minDate; + private String maxDate; private boolean isConnected; private Coordinates coordinates; - public AIRMapCanvasInteractionUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, boolean isConnected, Coordinates coordinates) { + public AIRMapCanvasInteractionUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, boolean isConnected, String minDate, String maxDate, Coordinates coordinates) { super(); this.width = width; this.height = height; this.urlTemplate = urlTemplate; this.maxZoom = maxZoom; this.areaId = areaId; + this.minDate = minDate; + this.maxDate = maxDate; this.isConnected = isConnected; this.coordinates = coordinates; } @@ -68,6 +72,10 @@ public Tile getTile(int x, int y, int zoom) { int srcW = this.width; int srcH = this.height; int scaleSize = 1; + + int minDate = Integer.valueOf(this.minDate); + int maxDate = Integer.valueOf(this.maxDate); + int[] tile = coordinates.getTile(); Log.d("tile Position: ", x + "-" + y + "-" + zoom); Log.d("tile given: ", tile[0] + "-" + tile[1] + "-" + tile[2]); @@ -161,9 +169,10 @@ public Tile getTile(int x, int y, int zoom) { green = 255; int day = red * 255 + green; + boolean inDay = day > 0 && day >= minDate && day <= maxDate; + boolean inPoint = xPoint == xFilter && yPoint == yFilter; - // if (day > 0 && day >= minDate && day <= maxDate) { - if (xPoint == xFilter && yPoint == yFilter) { + if (inDay && inPoint) { red = 255; green = 255; blue = 255; @@ -271,7 +280,7 @@ public void setMinDate(String minDate) { } public void setMaxDate(String maxDate) { - this.minDate = maxDate; + this.maxDate = maxDate; } public void setZIndex(float zIndex) { @@ -301,7 +310,7 @@ public TileOverlayOptions getTileOverlayOptions() { private TileOverlayOptions createTileOverlayOptions() { TileOverlayOptions options = new TileOverlayOptions(); options.zIndex(zIndex); - this.tileProvider = new AIRMapCanvasInteractionUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected, this.coordinates); + this.tileProvider = new AIRMapCanvasInteractionUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected, this.minDate, this.maxDate, this.coordinates); options.tileProvider(this.tileProvider); // options.fadeIn(false); return options; From 9c96c70f74fa22082092ba52275aeefb456a2c3e Mon Sep 17 00:00:00 2001 From: j8seangel Date: Fri, 12 May 2017 15:30:49 +0200 Subject: [PATCH 17/22] Disable fade and add tile size depends on zoom --- .../maps/AirMapCanvasInteractionUrlTile.java | 141 +++++++++--------- 1 file changed, 72 insertions(+), 69 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java index b325c429e..c6c9f728c 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java @@ -83,9 +83,9 @@ public Tile getTile(int x, int y, int zoom) { if (tile[0] == x && tile[1] == y && tile[2] == zoom) { if (zoom > this.maxZoom) { - xCord = (int)(x / (Math.pow(2, zoom - this.maxZoom))); - yCord = (int)(y / (Math.pow(2, zoom - this.maxZoom))); - zoomCord = this.maxZoom; + xCord = (int)(x / (Math.pow(2, zoom - this.maxZoom))); + yCord = (int)(y / (Math.pow(2, zoom - this.maxZoom))); + zoomCord = this.maxZoom; } ByteArrayOutputStream stream = new ByteArrayOutputStream(); @@ -94,44 +94,45 @@ public Tile getTile(int x, int y, int zoom) { Bitmap image; if (this.isConnected) { - String providerUrl = this.urlTemplate - .replace("{x}", Integer.toString(xCord)) - .replace("{y}", Integer.toString(yCord)) - .replace("{z}", Integer.toString(zoomCord)); - - URL url; - try { - url = new URL(providerUrl); - image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); - } catch (Exception e) { - e.printStackTrace(); - return NO_TILE; - } + String providerUrl = this.urlTemplate + .replace("{x}", Integer.toString(xCord)) + .replace("{y}", Integer.toString(yCord)) + .replace("{z}", Integer.toString(zoomCord)); + + URL url; + try { + url = new URL(providerUrl); + image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); + } catch (Exception e) { + e.printStackTrace(); + return NO_TILE; + } } else { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - File dir = getContext().getFilesDir(); - File myFile = new File(dir + "/tiles", areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); - - try { - image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); - } catch (Exception e) { - e.printStackTrace(); - return NO_TILE; - } + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + File dir = getContext().getFilesDir(); + File myFile = new File(dir + "/tiles", areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); + + try { + image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); + } catch (Exception e) { + e.printStackTrace(); + return NO_TILE; + } } + int zsteps = 1; if (zoom > this.maxZoom) { - int zsteps = zoom - this.maxZoom; - int relation = (int) Math.pow(2, zsteps) ; - int size = (int) (TILE_SIZE / relation); - // we scale the map to keep the tiles sharp - scaleSize = (int) (TILE_SIZE * 2); - srcX = (int) size * (x % relation); - srcY = (int) size * (y % relation); - srcW = (int) size; - srcH = (int) size; + zsteps = zoom - this.maxZoom; + int relation = (int) Math.pow(2, zsteps) ; + int size = (int) (TILE_SIZE / relation); + // we scale the map to keep the tiles sharp + scaleSize = (int) (TILE_SIZE * 2); + srcX = (int) size * (x % relation); + srcY = (int) size * (y % relation); + srcW = (int) size; + srcH = (int) size; } if (image != null) { @@ -154,46 +155,48 @@ public Tile getTile(int x, int y, int zoom) { double[] precision = coordinates.getPrecision(); int xFilter = (int)(precision[0] * width); int yFilter = (int)(precision[1] * height); + double THRESHOLD = zoom * 0.5 * zsteps; for(int xPoint=0; xPoint < width; xPoint++) { - for(int yPoint=0; yPoint < height; yPoint++) { - c = scaledBitmap.getPixel(xPoint, yPoint); - - red = Color.red(c); - green = Color.green(c); - blue = Color.blue(c); - - if (red > 255) - red = 255; - if (green > 255) - green = 255; - - int day = red * 255 + green; - boolean inDay = day > 0 && day >= minDate && day <= maxDate; - boolean inPoint = xPoint == xFilter && yPoint == yFilter; - - if (inDay && inPoint) { - red = 255; - green = 255; - blue = 255; - alpha = 255; - } else { - alpha = 0; + for(int yPoint=0; yPoint < height; yPoint++) { + c = scaledBitmap.getPixel(xPoint, yPoint); + + red = Color.red(c); + green = Color.green(c); + blue = Color.blue(c); + + if (red > 255) + red = 255; + if (green > 255) + green = 255; + + int day = red * 255 + green; + boolean inDay = day > 0 && day >= minDate && day <= maxDate; + boolean inXPoint = xPoint >= (xFilter - THRESHOLD) && (xPoint <= xFilter + THRESHOLD); + boolean inYPoint = yPoint >= (yFilter - THRESHOLD) && (yPoint <= yFilter + THRESHOLD); + + if (inDay && inXPoint && inYPoint) { + red = 255; + green = 255; + blue = 255; + alpha = 150; + } else { + alpha = 0; + } + + finalBitmap.setPixel(xPoint, yPoint, Color.argb(alpha, red, green, blue)); } - - finalBitmap.setPixel(xPoint, yPoint, Color.argb(alpha, red, green, blue)); - } } - stream = new ByteArrayOutputStream(); - finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); - bitmapData = stream.toByteArray(); - return new Tile(TILE_SIZE, TILE_SIZE, bitmapData); + stream = new ByteArrayOutputStream(); + finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); + bitmapData = stream.toByteArray(); + return new Tile(TILE_SIZE, TILE_SIZE, bitmapData); } else { - return NO_TILE; + return NO_TILE; } } else { - return NO_TILE; + return NO_TILE; } } @@ -312,7 +315,7 @@ private TileOverlayOptions createTileOverlayOptions() { options.zIndex(zIndex); this.tileProvider = new AIRMapCanvasInteractionUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected, this.minDate, this.maxDate, this.coordinates); options.tileProvider(this.tileProvider); - // options.fadeIn(false); + options.fadeIn(false); return options; } From b3b2eb8d6fc519d556fd7d4c7659ae35ecf7e7c6 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Fri, 19 May 2017 15:57:12 +0200 Subject: [PATCH 18/22] Add alerts type to support viirs visualization --- .../react/maps/AirMapCanvasUrlTile.java | 40 +++++++++++++++---- .../maps/AirMapCanvasUrlTileManager.java | 5 +++ lib/components/MapCanvasUrlTile.js | 4 ++ 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index 13d1a15ae..388aacfae 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -28,16 +28,18 @@ class AIRMapCanvasUrlTileProvider implements TileProvider { private int height; private int maxZoom; private String areaId; + private String alertType; private String minDate; private String maxDate; private boolean isConnected; - public AIRMapCanvasUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, boolean isConnected, String minDate, String maxDate) { + public AIRMapCanvasUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, String alertType, boolean isConnected, String minDate, String maxDate) { super(); this.width = width; this.height = height; this.urlTemplate = urlTemplate; this.maxZoom = maxZoom; this.areaId = areaId; + this.alertType = alertType; this.isConnected = isConnected; this.minDate = minDate; this.maxDate = maxDate; @@ -89,7 +91,7 @@ public Tile getTile(int x, int y, int zoom) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_8888; File dir = getContext().getFilesDir(); - File myFile = new File(dir + "/tiles", areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); + File myFile = new File(dir + "/tiles", areaId + "/" + this.alertType + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); try { image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); @@ -119,7 +121,7 @@ public Tile getTile(int x, int y, int zoom) { scaledBitmap = Bitmap.createScaledBitmap (croppedBitmap, scaleSize, scaleSize, false); } - int width, height, r, g, b, c; + int width, height; height = scaledBitmap.getHeight(); width = scaledBitmap.getWidth(); @@ -142,10 +144,17 @@ public Tile getTile(int x, int y, int zoom) { int day = red * 255 + green; if (day > 0 && day >= minDate && day <= maxDate) { - red = 220; - green = 102; - blue = 153; - alpha = 255; + if (this.alertType.equals("viirs")) { + red = 244; + green = 66; + blue = 66; + alpha = 255; + } else { + red = 220; + green = 102; + blue = 153; + alpha = 255; + } } else { alpha = 0; } @@ -178,6 +187,10 @@ public void setAreaId(String areaId) { public void setIsConnected(boolean isConnected) { this.isConnected = isConnected; } + public void setAlertType(String alertType) { + this.alertType = alertType; + } + } private TileOverlayOptions tileOverlayOptions; @@ -187,6 +200,7 @@ public void setIsConnected(boolean isConnected) { private String urlTemplate; private int maxZoom; private String areaId; + private String alertType; private String minDate; private String maxDate; private boolean isConnected; @@ -236,6 +250,16 @@ public void setIsConnected(boolean isConnected) { } } + public void setAlertType(String alertType) { + this.alertType = alertType; + if (tileProvider != null) { + tileProvider.setAlertType(alertType); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + public void setMinDate(String minDate) { this.minDate = minDate; } @@ -261,7 +285,7 @@ public TileOverlayOptions getTileOverlayOptions() { private TileOverlayOptions createTileOverlayOptions() { TileOverlayOptions options = new TileOverlayOptions(); options.zIndex(zIndex); - this.tileProvider = new AIRMapCanvasUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected, this.minDate, this.maxDate); + this.tileProvider = new AIRMapCanvasUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.alertType, this.isConnected, this.minDate, this.maxDate); options.tileProvider(this.tileProvider); return options; } diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java index da771c0e9..14e23bc1a 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTileManager.java @@ -47,6 +47,11 @@ public void setMaxZoom(AirMapCanvasUrlTile view, int maxZoom) { view.setMaxZoom(maxZoom); } + @ReactProp(name = "alertType") + public void setAlertType(AirMapCanvasUrlTile view, String alertType) { + view.setAlertType(alertType); + } + @ReactProp(name = "areaId") public void setAreaId(AirMapCanvasUrlTile view, String areaId) { view.setAreaId(areaId); diff --git a/lib/components/MapCanvasUrlTile.js b/lib/components/MapCanvasUrlTile.js index 1fbe6f753..49a5509c8 100644 --- a/lib/components/MapCanvasUrlTile.js +++ b/lib/components/MapCanvasUrlTile.js @@ -38,6 +38,10 @@ const propTypes = { * Area id to get the tiles from the corrent folder */ areaId: PropTypes.string, + /** + * Alert type supported umd_as_it_happens OR viirs + */ + alertType: PropTypes.string, /** * Min date to get tiles */ From 06cfd121ca6876db2828e4a616e3ce87de066ed5 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Mon, 22 May 2017 17:14:28 +0200 Subject: [PATCH 19/22] Show VIIRS alerts --- .../react/maps/AirMapCanvasUrlTile.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index 388aacfae..8f0a11202 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -91,12 +91,14 @@ public Tile getTile(int x, int y, int zoom) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_8888; File dir = getContext().getFilesDir(); - File myFile = new File(dir + "/tiles", areaId + "/" + this.alertType + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); + File myFile = new File(dir + "/tiles" + "/" + this.alertType, areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); try { image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); } catch (Exception e) { e.printStackTrace(); + + return NO_TILE; } } @@ -141,20 +143,27 @@ public Tile getTile(int x, int y, int zoom) { if (green > 255) green = 255; - int day = red * 255 + green; + int day; + if (this.alertType.equals("viirs")) { + day = blue; + } else { + day = red * 255 + green; + } - if (day > 0 && day >= minDate && day <= maxDate) { - if (this.alertType.equals("viirs")) { + if(this.alertType.equals("viirs")) { + if (day > 0) { red = 244; green = 66; blue = 66; alpha = 255; } else { - red = 220; - green = 102; - blue = 153; - alpha = 255; + alpha = 0; } + } else if (day > 0 && day >= minDate && day <= maxDate) { + red = 220; + green = 102; + blue = 153; + alpha = 255; } else { alpha = 0; } From d1a3ce15f139b8d256f6377c689148625555dcec Mon Sep 17 00:00:00 2001 From: j8seangel Date: Thu, 25 May 2017 17:49:49 +0200 Subject: [PATCH 20/22] Refactor to use custom canvas tile base --- build.gradle | 2 +- example/examples/CustomTiles.js | 10 +- .../react/maps/AirMapCanvasFeature.java | 131 +++++++ .../maps/AirMapCanvasInteractionUrlTile.java | 339 +++--------------- ...AirMapCanvasInteractionUrlTileManager.java | 2 +- .../react/maps/AirMapCanvasTileProvider.java | 182 ++++++++++ .../react/maps/AirMapCanvasUrlTile.java | 323 +++-------------- .../android/react/maps/Coordinates.java | 22 ++ 8 files changed, 428 insertions(+), 583 deletions(-) create mode 100644 lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasFeature.java create mode 100644 lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasTileProvider.java create mode 100644 lib/android/src/main/java/com/airbnb/android/react/maps/Coordinates.java diff --git a/build.gradle b/build.gradle index 8a3e2453e..588e5cb99 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' + classpath 'com.android.tools.build:gradle:2.3.2' } } diff --git a/example/examples/CustomTiles.js b/example/examples/CustomTiles.js index 1e8306110..7906ff6db 100644 --- a/example/examples/CustomTiles.js +++ b/example/examples/CustomTiles.js @@ -116,9 +116,10 @@ class CustomTiles extends React.Component { zIndex={-1} maxZoom={12} areaId="Download" + alertType="umd_as_it_happen" isConnected - minDate="2017/01/01" - maxDate="2017/03/01" + minDate="0" + maxDate="3000" /> {hasCoordinates && } diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasFeature.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasFeature.java new file mode 100644 index 000000000..ba1b877dc --- /dev/null +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasFeature.java @@ -0,0 +1,131 @@ +package com.airbnb.android.react.maps; + +import android.content.Context; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.model.TileOverlay; +import com.google.android.gms.maps.model.TileOverlayOptions; + +/** + * Created by joseangel.parreno@vizzuality.com on 25/05/2017. + */ + +public abstract class AirMapCanvasFeature extends AirMapFeature { + protected TileOverlayOptions tileOverlayOptions; + protected TileOverlay tileOverlay; + protected AirMapCanvasTileProvider tileProvider; + + protected String urlTemplate; + protected int maxZoom; + protected String areaId; + protected String alertType; + protected String minDate; + protected String maxDate; + protected boolean isConnected; + protected float zIndex; + protected Coordinates coordinates; + + public AirMapCanvasFeature(Context context) { + super(context); + } + + public void setUrlTemplate(String urlTemplate) { + this.urlTemplate = urlTemplate; + if (tileProvider != null) { + tileProvider.setUrlTemplate(urlTemplate); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + + public void setMaxZoom(int maxZoom) { + this.maxZoom = maxZoom; + if (tileProvider != null) { + tileProvider.setMaxZoom(maxZoom); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + + public void setAreaId(String areaId) { + this.areaId = areaId; + if (tileProvider != null) { + tileProvider.setAreaId(areaId); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + + public void setIsConnected(boolean isConnected) { + this.isConnected = isConnected; + if (tileProvider != null) { + tileProvider.setIsConnected(isConnected); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + + public void setAlertType(String alertType) { + this.alertType = alertType; + if (tileProvider != null) { + tileProvider.setAlertType(alertType); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + + public void setMinDate(String minDate) { + this.minDate = minDate; + } + + public void setMaxDate(String maxDate) { + this.maxDate = maxDate; + } + + public void setZIndex(float zIndex) { + this.zIndex = zIndex; + if (tileOverlay != null) { + tileOverlay.setZIndex(zIndex); + } + } + + public void setCoordinates(Coordinates coordinates) { + this.coordinates = coordinates; + if (tileProvider != null) { + tileProvider.setCoordinates(coordinates); + } + if (tileOverlay != null) { + tileOverlay.clearTileCache(); + } + } + + public TileOverlayOptions getTileOverlayOptions() { + if (tileOverlayOptions == null) { + tileOverlayOptions = createTileOverlayOptions(); + } + return tileOverlayOptions; + } + + protected abstract TileOverlayOptions createTileOverlayOptions(); + + + @Override + public Object getFeature() { + return tileOverlay; + } + + @Override + public void addToMap(GoogleMap map) { + this.tileOverlay = map.addTileOverlay(getTileOverlayOptions()); + } + + @Override + public void removeFromMap(GoogleMap map) { + tileOverlay.remove(); + } +} diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java index c6c9f728c..03087a908 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java @@ -2,335 +2,76 @@ import android.content.Context; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.Color; -import android.net.Uri; -import android.os.Environment; -import android.util.Log; - -import com.google.android.gms.maps.GoogleMap; -import com.google.android.gms.maps.model.Tile; -import com.google.android.gms.maps.model.TileOverlay; import com.google.android.gms.maps.model.TileOverlayOptions; -import com.google.android.gms.maps.model.TileProvider; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.net.URL; -import java.lang.Math; -public class AirMapCanvasInteractionUrlTile extends AirMapFeature { - private class Coordinates { - private int[] tile; - private double[] precision; +public class AirMapCanvasInteractionUrlTile extends AirMapCanvasFeature { - public Coordinates(int[] tile, double[] precision) { - this.tile = tile; - this.precision = precision; - } + public AirMapCanvasInteractionUrlTile(Context context){ super(context); } - public int[] getTile() { - return tile; - } - public double[] getPrecision() { - return precision; - } - } + class AIRMapCanvasInteractionTileProvider extends AirMapCanvasTileProvider { - - class AIRMapCanvasInteractionUrlTileProvider implements TileProvider { - private String urlTemplate; - private int width; - private int height; - private int maxZoom; - private String areaId; - private String minDate; - private String maxDate; - private boolean isConnected; - private Coordinates coordinates; - public AIRMapCanvasInteractionUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, boolean isConnected, String minDate, String maxDate, Coordinates coordinates) { - super(); - this.width = width; - this.height = height; - this.urlTemplate = urlTemplate; - this.maxZoom = maxZoom; - this.areaId = areaId; - this.minDate = minDate; - this.maxDate = maxDate; - this.isConnected = isConnected; - this.coordinates = coordinates; + public AIRMapCanvasInteractionTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, boolean isConnected, String minDate, String maxDate, String alertType, Coordinates coordinates) { + super(width, height, urlTemplate, maxZoom, areaId, isConnected, minDate, maxDate, alertType, coordinates); } - @Override - public Tile getTile(int x, int y, int zoom) { - int TILE_SIZE = this.width; - int maxZoom = 12; - int xCord = x; - int yCord = y; - int zoomCord = zoom; - int srcX = 0; - int srcY = 0; - int srcW = this.width; - int srcH = this.height; - int scaleSize = 1; - - int minDate = Integer.valueOf(this.minDate); - int maxDate = Integer.valueOf(this.maxDate); - - int[] tile = coordinates.getTile(); - Log.d("tile Position: ", x + "-" + y + "-" + zoom); - Log.d("tile given: ", tile[0] + "-" + tile[1] + "-" + tile[2]); - - if (tile[0] == x && tile[1] == y && tile[2] == zoom) { - - if (zoom > this.maxZoom) { - xCord = (int)(x / (Math.pow(2, zoom - this.maxZoom))); - yCord = (int)(y / (Math.pow(2, zoom - this.maxZoom))); - zoomCord = this.maxZoom; - } - - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - byte[] bitmapData = stream.toByteArray(); - - Bitmap image; - - if (this.isConnected) { - String providerUrl = this.urlTemplate - .replace("{x}", Integer.toString(xCord)) - .replace("{y}", Integer.toString(yCord)) - .replace("{z}", Integer.toString(zoomCord)); - - URL url; - try { - url = new URL(providerUrl); - image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); - } catch (Exception e) { - e.printStackTrace(); - return NO_TILE; - } - - } else { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - File dir = getContext().getFilesDir(); - File myFile = new File(dir + "/tiles", areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); - - try { - image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); - } catch (Exception e) { - e.printStackTrace(); - return NO_TILE; - } - } - int zsteps = 1; - if (zoom > this.maxZoom) { - zsteps = zoom - this.maxZoom; - int relation = (int) Math.pow(2, zsteps) ; - int size = (int) (TILE_SIZE / relation); - // we scale the map to keep the tiles sharp - scaleSize = (int) (TILE_SIZE * 2); - srcX = (int) size * (x % relation); - srcY = (int) size * (y % relation); - srcW = (int) size; - srcH = (int) size; - } - - if (image != null) { - Bitmap croppedBitmap = Bitmap.createBitmap(image , srcX , srcY, srcW, srcH); - Bitmap scaledBitmap = croppedBitmap; - if (zoom > maxZoom) { - // The last false is for filter anti-aliasing - scaledBitmap = Bitmap.createScaledBitmap (croppedBitmap, scaleSize, scaleSize, false); - } - - int width, height, r, g, b, c; - height = scaledBitmap.getHeight(); - width = scaledBitmap.getWidth(); - - Bitmap finalBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - int red, green, blue, pixel, alpha; - int[] pixels = new int[width * height]; - scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height); + protected Context getParentContext() { + return getContext(); + } - double[] precision = coordinates.getPrecision(); - int xFilter = (int)(precision[0] * width); - int yFilter = (int)(precision[1] * height); - double THRESHOLD = zoom * 0.5 * zsteps; + protected Bitmap paintTile(Bitmap scaledBitmap, int width, int height, int zoom, int zsteps, int minDate, int maxDate) { + Bitmap finalBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + int red, green, blue, alpha, c; + double[] precision = coordinates.getPrecision(); + int xFilter = (int)(precision[0] * width); + int yFilter = (int)(precision[1] * height); + double THRESHOLD = zoom * 0.5 * zsteps; - for(int xPoint=0; xPoint < width; xPoint++) { - for(int yPoint=0; yPoint < height; yPoint++) { - c = scaledBitmap.getPixel(xPoint, yPoint); - red = Color.red(c); - green = Color.green(c); - blue = Color.blue(c); + for(int xPoint=0; xPoint < width; xPoint++) { + for(int yPoint=0; yPoint < height; yPoint++) { + c = scaledBitmap.getPixel(xPoint, yPoint); - if (red > 255) - red = 255; - if (green > 255) - green = 255; + red = Color.red(c); + green = Color.green(c); + blue = Color.blue(c); - int day = red * 255 + green; - boolean inDay = day > 0 && day >= minDate && day <= maxDate; - boolean inXPoint = xPoint >= (xFilter - THRESHOLD) && (xPoint <= xFilter + THRESHOLD); - boolean inYPoint = yPoint >= (yFilter - THRESHOLD) && (yPoint <= yFilter + THRESHOLD); + if (red > 255) + red = 255; + if (green > 255) + green = 255; - if (inDay && inXPoint && inYPoint) { - red = 255; - green = 255; - blue = 255; - alpha = 150; - } else { - alpha = 0; - } + int day = red * 255 + green; + boolean inDay = day > 0 && day >= minDate && day <= maxDate; + boolean inXPoint = xPoint >= (xFilter - THRESHOLD) && (xPoint <= xFilter + THRESHOLD); + boolean inYPoint = yPoint >= (yFilter - THRESHOLD) && (yPoint <= yFilter + THRESHOLD); - finalBitmap.setPixel(xPoint, yPoint, Color.argb(alpha, red, green, blue)); - } + if (inDay && inXPoint && inYPoint) { + red = 255; + green = 255; + blue = 255; + alpha = 150; + } else { + alpha = 0; } - stream = new ByteArrayOutputStream(); - finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); - bitmapData = stream.toByteArray(); - return new Tile(TILE_SIZE, TILE_SIZE, bitmapData); - } else { - return NO_TILE; + finalBitmap.setPixel(xPoint, yPoint, Color.argb(alpha, red, green, blue)); } - } else { - return NO_TILE; } + return finalBitmap; } - public void setUrlTemplate(String urlTemplate) { - this.urlTemplate = urlTemplate; - } - - public void setMaxZoom(int maxZoom) { - this.maxZoom = maxZoom; - } - - public void setAreaId(String areaId) { - this.areaId = areaId; - } - - public void setIsConnected(boolean isConnected) { - this.isConnected = isConnected; - } - - public void setCoordinates(Coordinates coordinates) { - this.coordinates = coordinates; - } - } - - private TileOverlayOptions tileOverlayOptions; - private TileOverlay tileOverlay; - private AIRMapCanvasInteractionUrlTileProvider tileProvider; - - private String urlTemplate; - private int maxZoom; - private String areaId; - private String minDate; - private String maxDate; - private boolean isConnected; - private float zIndex; - private Coordinates coordinates; - - public AirMapCanvasInteractionUrlTile(Context context) { - super(context); - } - - public void setUrlTemplate(String urlTemplate) { - this.urlTemplate = urlTemplate; - if (tileProvider != null) { - tileProvider.setUrlTemplate(urlTemplate); - } - if (tileOverlay != null) { - tileOverlay.clearTileCache(); - } - } - - public void setMaxZoom(int maxZoom) { - this.maxZoom = maxZoom; - if (tileProvider != null) { - tileProvider.setMaxZoom(maxZoom); - } - if (tileOverlay != null) { - tileOverlay.clearTileCache(); - } - } - - public void setAreaId(String areaId) { - this.areaId = areaId; - if (tileProvider != null) { - tileProvider.setAreaId(areaId); - } - if (tileOverlay != null) { - tileOverlay.clearTileCache(); - } - } - - public void setIsConnected(boolean isConnected) { - this.isConnected = isConnected; - if (tileProvider != null) { - tileProvider.setIsConnected(isConnected); - } - if (tileOverlay != null) { - tileOverlay.clearTileCache(); - } - } - - public void setMinDate(String minDate) { - this.minDate = minDate; - } - - public void setMaxDate(String maxDate) { - this.maxDate = maxDate; - } - - public void setZIndex(float zIndex) { - this.zIndex = zIndex; - if (tileOverlay != null) { - tileOverlay.setZIndex(zIndex); - } - } - public void setCoordinates(int[] tile, double[] precision) { - this.coordinates = new Coordinates(tile, precision); - if (tileProvider != null) { - tileProvider.setCoordinates(coordinates); - } - if (tileOverlay != null) { - tileOverlay.clearTileCache(); - } } - public TileOverlayOptions getTileOverlayOptions() { - if (tileOverlayOptions == null) { - tileOverlayOptions = createTileOverlayOptions(); - } - return tileOverlayOptions; - } - private TileOverlayOptions createTileOverlayOptions() { + protected TileOverlayOptions createTileOverlayOptions() { TileOverlayOptions options = new TileOverlayOptions(); options.zIndex(zIndex); - this.tileProvider = new AIRMapCanvasInteractionUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected, this.minDate, this.maxDate, this.coordinates); + this.tileProvider = new AIRMapCanvasInteractionTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected, this.minDate, this.maxDate, this.alertType, this.coordinates); options.tileProvider(this.tileProvider); - options.fadeIn(false); return options; } - @Override - public Object getFeature() { - return tileOverlay; - } - - @Override - public void addToMap(GoogleMap map) { - this.tileOverlay = map.addTileOverlay(getTileOverlayOptions()); - } - - @Override - public void removeFromMap(GoogleMap map) { - tileOverlay.remove(); - } } diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java index e629b2fe8..9799a47ee 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTileManager.java @@ -78,7 +78,7 @@ public void setCoordinates(AirMapCanvasInteractionUrlTile view, ReadableMap coor if (coordinates != null) { int[] tile = new int[]{coordinates.getArray("tile").getInt(0), coordinates.getArray("tile").getInt(1), coordinates.getArray("tile").getInt(2)}; double[] precision = new double[]{coordinates.getArray("precision").getDouble(0), coordinates.getArray("precision").getDouble(1)}; - view.setCoordinates(tile, precision); + view.setCoordinates(new Coordinates(tile, precision)); } } diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasTileProvider.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasTileProvider.java new file mode 100644 index 000000000..5bc395095 --- /dev/null +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasTileProvider.java @@ -0,0 +1,182 @@ +package com.airbnb.android.react.maps; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.util.Log; + +import com.google.android.gms.maps.model.Tile; +import com.google.android.gms.maps.model.TileProvider; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.net.URL; + +/** + * Created by joseangel.parreno@vizzuality.com on 19/05/2017. + */ + + +public abstract class AirMapCanvasTileProvider implements TileProvider { + protected String urlTemplate; + protected int width; + protected int height; + protected int maxZoom; + protected String areaId; + protected String minDate; + protected String maxDate; + protected boolean isConnected; + protected Coordinates coordinates; + protected String alertType; + + public AirMapCanvasTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, boolean isConnected, String minDate, String maxDate, String alertType, Coordinates coordinates) { + super(); + this.width = width; + this.height = height; + this.urlTemplate = urlTemplate; + this.maxZoom = maxZoom; + this.areaId = areaId; + this.minDate = minDate; + this.maxDate = maxDate; + this.alertType = alertType; + this.isConnected = isConnected; + this.coordinates = coordinates; + } + @Override + public Tile getTile(int x, int y, int zoom) { + int TILE_SIZE = this.width; + int maxZoom = 12; + int xCord = x; + int yCord = y; + int zoomCord = zoom; + int srcX = 0; + int srcY = 0; + int srcW = this.width; + int srcH = this.height; + int scaleSize = 1; + + int minDate = Integer.valueOf(this.minDate); + int maxDate = Integer.valueOf(this.maxDate); + + if (this.coordinates != null) { + int[] tile = this.coordinates.getTile(); + Log.d("tile Position: ", x + "-" + y + "-" + zoom); + Log.d("tile given: ", tile[0] + "-" + tile[1] + "-" + tile[2]); + if(!(tile[0] == x && tile[1] == y && tile[2] == zoom)) { + return NO_TILE; + } + } + + if (zoom > this.maxZoom) { + xCord = (int)(x / (Math.pow(2, zoom - this.maxZoom))); + yCord = (int)(y / (Math.pow(2, zoom - this.maxZoom))); + zoomCord = this.maxZoom; + } + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + byte[] bitmapData = stream.toByteArray(); + + Bitmap image; + + if (this.isConnected) { + String providerUrl = this.urlTemplate + .replace("{x}", Integer.toString(xCord)) + .replace("{y}", Integer.toString(yCord)) + .replace("{z}", Integer.toString(zoomCord)); + + URL url; + try { + url = new URL(providerUrl); + image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); + } catch (Exception e) { + e.printStackTrace(); + return NO_TILE; + } + + } else { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + File dir = getParentContext().getFilesDir(); + File myFile = new File(dir + "/tiles", areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); + + try { + image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); + } catch (Exception e) { + e.printStackTrace(); + return NO_TILE; + } + } + int zsteps = 1; + + if (zoom > this.maxZoom) { + zsteps = zoom - this.maxZoom; + int relation = (int) Math.pow(2, zsteps) ; + int size = (int) (TILE_SIZE / relation); + // we scale the map to keep the tiles sharp + scaleSize = (int) (TILE_SIZE * 2); + srcX = (int) size * (x % relation); + srcY = (int) size * (y % relation); + srcW = (int) size; + srcH = (int) size; + } + + if (image != null) { + Bitmap croppedBitmap = Bitmap.createBitmap(image , srcX , srcY, srcW, srcH); + Bitmap scaledBitmap = croppedBitmap; + if (zoom > maxZoom) { + // The last false is for filter anti-aliasing + scaledBitmap = Bitmap.createScaledBitmap (croppedBitmap, scaleSize, scaleSize, false); + } + + int width, height; + height = scaledBitmap.getHeight(); + width = scaledBitmap.getWidth(); + + // + + int[] pixels = new int[width * height]; + scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height); + + + Bitmap finalBitmap = paintTile(scaledBitmap, width, height, zoom, zsteps, minDate, maxDate); + + + + stream = new ByteArrayOutputStream(); + finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); + bitmapData = stream.toByteArray(); + return new Tile(TILE_SIZE, TILE_SIZE, bitmapData); + } else { + return NO_TILE; + } + } + + protected abstract Context getParentContext(); + + protected abstract Bitmap paintTile(Bitmap scaledBitmap, int width, int height, int zoom, int zsteps, int minDate, int maxDate); + + public void setUrlTemplate(String urlTemplate) { + this.urlTemplate = urlTemplate; + } + + public void setMaxZoom(int maxZoom) { + this.maxZoom = maxZoom; + } + + public void setAreaId(String areaId) { + this.areaId = areaId; + } + + public void setAlertType(String alertType) { + this.alertType = alertType; + } + + public void setIsConnected(boolean isConnected) { + this.isConnected = isConnected; + } + + public void setCoordinates(Coordinates coordinates) { + this.coordinates = coordinates; + } +} diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index 8f0a11202..bc74ddad0 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -2,315 +2,82 @@ import android.content.Context; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.Color; -import android.net.Uri; -import android.os.Environment; -import android.util.Log; - -import com.google.android.gms.maps.GoogleMap; -import com.google.android.gms.maps.model.Tile; -import com.google.android.gms.maps.model.TileOverlay; import com.google.android.gms.maps.model.TileOverlayOptions; -import com.google.android.gms.maps.model.TileProvider; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.net.URL; -import java.lang.Math; -public class AirMapCanvasUrlTile extends AirMapFeature { +public class AirMapCanvasUrlTile extends AirMapCanvasFeature { - class AIRMapCanvasUrlTileProvider implements TileProvider { - private String urlTemplate; - private int width; - private int height; - private int maxZoom; - private String areaId; - private String alertType; - private String minDate; - private String maxDate; - private boolean isConnected; - public AIRMapCanvasUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, String alertType, boolean isConnected, String minDate, String maxDate) { - super(); - this.width = width; - this.height = height; - this.urlTemplate = urlTemplate; - this.maxZoom = maxZoom; - this.areaId = areaId; - this.alertType = alertType; - this.isConnected = isConnected; - this.minDate = minDate; - this.maxDate = maxDate; - } - @Override - public Tile getTile(int x, int y, int zoom) { - int TILE_SIZE = this.width; - int maxZoom = 12; - int xCord = x; - int yCord = y; - int zoomCord = zoom; - int srcX = 0; - int srcY = 0; - int srcW = this.width; - int srcH = this.height; - int scaleSize = 1; - int minDate = Integer.valueOf(this.minDate); - int maxDate = Integer.valueOf(this.maxDate); - // Log.d("Position", String.valueOf(x) + "x" + String.valueOf(y) + "x" + String.valueOf(zoom)); - - if (zoom > this.maxZoom) { - xCord = (int)(x / (Math.pow(2, zoom - this.maxZoom))); - yCord = (int)(y / (Math.pow(2, zoom - this.maxZoom))); - zoomCord = this.maxZoom; - } + public AirMapCanvasUrlTile(Context context){ super(context); } - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - byte[] bitmapData = stream.toByteArray(); - Uri.Builder builder = new Uri.Builder(); - - Bitmap image; - - if (this.isConnected) { - String providerUrl = this.urlTemplate - .replace("{x}", Integer.toString(xCord)) - .replace("{y}", Integer.toString(yCord)) - .replace("{z}", Integer.toString(zoomCord)); - - URL url; - try { - url = new URL(providerUrl); - image = BitmapFactory.decodeStream(url.openConnection().getInputStream()); - } catch (Exception e) { - e.printStackTrace(); - return NO_TILE; - } + class AIRMapCanvasUrlTileProvider extends AirMapCanvasTileProvider { - } else { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - File dir = getContext().getFilesDir(); - File myFile = new File(dir + "/tiles" + "/" + this.alertType, areaId + "/" + zoomCord + "x" + xCord + "x" + yCord + ".png"); + public AIRMapCanvasUrlTileProvider(int width, int height, String urlTemplate, int maxZoom, String areaId, boolean isConnected, String minDate, String maxDate, String alertType, Coordinates coordinates) { + super(width, height, urlTemplate, maxZoom, areaId, isConnected, minDate, maxDate, alertType, coordinates); + } - try { - image = BitmapFactory.decodeFile(myFile.getAbsolutePath(), options); - } catch (Exception e) { - e.printStackTrace(); + protected Context getParentContext() { + return getContext(); + } + protected Bitmap paintTile(Bitmap scaledBitmap, int width, int height, int zoom, int zsteps, int minDate, int maxDate) { + Bitmap finalBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + int red, green, blue, pixel, alpha; + int[] pixels = new int[width * height]; + scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height); + for (int i = 0; i < pixels.length; i++) { + pixel = pixels[i]; - return NO_TILE; - } - } + red = (pixel >> 16) & 0xFF; + green = (pixel >> 8) & 0xFF; + blue = pixel & 0xFF; - if (zoom > this.maxZoom) { - int zsteps = zoom - this.maxZoom; - int relation = (int) Math.pow(2, zsteps) ; - int size = (int) (TILE_SIZE / relation); - // we scale the map to keep the tiles sharp - scaleSize = (int) (TILE_SIZE * 2); - srcX = (int) size * (x % relation); - srcY = (int) size * (y % relation); - srcW = (int) size; - srcH = (int) size; - } + if (red > 255) + red = 255; + if (green > 255) + green = 255; - if (image != null) { - Bitmap croppedBitmap = Bitmap.createBitmap(image , srcX , srcY, srcW, srcH); - Bitmap scaledBitmap = croppedBitmap; - if (zoom > maxZoom) { - // The last false is for filter anti-aliasing - scaledBitmap = Bitmap.createScaledBitmap (croppedBitmap, scaleSize, scaleSize, false); + int day; + if (this.alertType != null && this.alertType.equals("viirs")) { + day = blue; + } else { + day = red * 255 + green; } - int width, height; - height = scaledBitmap.getHeight(); - width = scaledBitmap.getWidth(); - - Bitmap finalBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - int red, green, blue, pixel, alpha; - int[] pixels = new int[width * height]; - scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height); - for (int i = 0; i < pixels.length; i++) { - pixel = pixels[i]; - - red = (pixel >> 16) & 0xFF; - green = (pixel >> 8) & 0xFF; - blue = pixel & 0xFF; - - if (red > 255) - red = 255; - if (green > 255) - green = 255; - - int day; - if (this.alertType.equals("viirs")) { - day = blue; - } else { - day = red * 255 + green; - } - - if(this.alertType.equals("viirs")) { - if (day > 0) { - red = 244; - green = 66; - blue = 66; - alpha = 255; - } else { - alpha = 0; - } - } else if (day > 0 && day >= minDate && day <= maxDate) { - red = 220; - green = 102; - blue = 153; + if(this.alertType != null && this.alertType.equals("viirs")) { + if (day > 0) { + red = 244; + green = 66; + blue = 66; alpha = 255; } else { alpha = 0; } - - pixels[i] = Color.argb(alpha, red, green, blue); + } else if (day > 0 && day >= minDate && day <= maxDate) { + red = 220; + green = 102; + blue = 153; + alpha = 255; + } else { + alpha = 0; } - finalBitmap.setPixels(pixels, 0, width, 0, 0, width, height); - stream = new ByteArrayOutputStream(); - finalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); - bitmapData = stream.toByteArray(); - return new Tile(TILE_SIZE, TILE_SIZE, bitmapData); - } else { - return NO_TILE; + pixels[i] = Color.argb(alpha, red, green, blue); } + finalBitmap.setPixels(pixels, 0, width, 0, 0, width, height); + return finalBitmap; } - public void setUrlTemplate(String urlTemplate) { - this.urlTemplate = urlTemplate; - } - - public void setMaxZoom(int maxZoom) { - this.maxZoom = maxZoom; - } - - public void setAreaId(String areaId) { - this.areaId = areaId; - } - - public void setIsConnected(boolean isConnected) { - this.isConnected = isConnected; - } - public void setAlertType(String alertType) { - this.alertType = alertType; - } - - } - - private TileOverlayOptions tileOverlayOptions; - private TileOverlay tileOverlay; - private AIRMapCanvasUrlTileProvider tileProvider; - - private String urlTemplate; - private int maxZoom; - private String areaId; - private String alertType; - private String minDate; - private String maxDate; - private boolean isConnected; - private float zIndex; - - public AirMapCanvasUrlTile(Context context) { - super(context); - } - - public void setUrlTemplate(String urlTemplate) { - this.urlTemplate = urlTemplate; - if (tileProvider != null) { - tileProvider.setUrlTemplate(urlTemplate); - } - if (tileOverlay != null) { - tileOverlay.clearTileCache(); - } - } - - public void setMaxZoom(int maxZoom) { - this.maxZoom = maxZoom; - if (tileProvider != null) { - tileProvider.setMaxZoom(maxZoom); - } - if (tileOverlay != null) { - tileOverlay.clearTileCache(); - } - } - - public void setAreaId(String areaId) { - this.areaId = areaId; - if (tileProvider != null) { - tileProvider.setAreaId(areaId); - } - if (tileOverlay != null) { - tileOverlay.clearTileCache(); - } - } - - public void setIsConnected(boolean isConnected) { - this.isConnected = isConnected; - if (tileProvider != null) { - tileProvider.setIsConnected(isConnected); - } - if (tileOverlay != null) { - tileOverlay.clearTileCache(); - } - } - - public void setAlertType(String alertType) { - this.alertType = alertType; - if (tileProvider != null) { - tileProvider.setAlertType(alertType); - } - if (tileOverlay != null) { - tileOverlay.clearTileCache(); - } - } - public void setMinDate(String minDate) { - this.minDate = minDate; } - public void setMaxDate(String maxDate) { - this.maxDate = maxDate; - } - - public void setZIndex(float zIndex) { - this.zIndex = zIndex; - if (tileOverlay != null) { - tileOverlay.setZIndex(zIndex); - } - } - public TileOverlayOptions getTileOverlayOptions() { - if (tileOverlayOptions == null) { - tileOverlayOptions = createTileOverlayOptions(); - } - return tileOverlayOptions; - } - - private TileOverlayOptions createTileOverlayOptions() { + protected TileOverlayOptions createTileOverlayOptions() { TileOverlayOptions options = new TileOverlayOptions(); options.zIndex(zIndex); - this.tileProvider = new AIRMapCanvasUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.alertType, this.isConnected, this.minDate, this.maxDate); + this.tileProvider = new AIRMapCanvasUrlTileProvider(256, 256, this.urlTemplate, this.maxZoom, this.areaId, this.isConnected, this.minDate, this.maxDate, this.alertType, null); options.tileProvider(this.tileProvider); return options; } - @Override - public Object getFeature() { - return tileOverlay; - } - - @Override - public void addToMap(GoogleMap map) { - this.tileOverlay = map.addTileOverlay(getTileOverlayOptions()); - } - - @Override - public void removeFromMap(GoogleMap map) { - tileOverlay.remove(); - } } diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/Coordinates.java b/lib/android/src/main/java/com/airbnb/android/react/maps/Coordinates.java new file mode 100644 index 000000000..5de7247d7 --- /dev/null +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/Coordinates.java @@ -0,0 +1,22 @@ +package com.airbnb.android.react.maps; + +/** + * Created by joseangel on 25/05/2017. + */ + +public class Coordinates { + private int[] tile; + private double[] precision; + + public Coordinates(int[] tile, double[] precision) { + this.tile = tile; + this.precision = precision; + } + + public int[] getTile() { + return tile; + } + public double[] getPrecision() { + return precision; + } +} From aa624e2314f53cacdcf0bf847a0ff18ed391bc29 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Thu, 25 May 2017 19:13:36 +0200 Subject: [PATCH 21/22] Fix viirs dates --- .../maps/AirMapCanvasInteractionUrlTile.java | 15 ++++++++++----- .../android/react/maps/AirMapCanvasUrlTile.java | 9 ++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java index 03087a908..261bce835 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasInteractionUrlTile.java @@ -37,12 +37,17 @@ protected Bitmap paintTile(Bitmap scaledBitmap, int width, int height, int zoom, green = Color.green(c); blue = Color.blue(c); - if (red > 255) - red = 255; - if (green > 255) - green = 255; + if (red > 255) red = 255; + if (green > 255) green = 255; + if (blue > 255) blue = 255; + + int day; + if (this.alertType != null && this.alertType.equals("viirs")) { + day = blue; + } else { + day = red * 255 + green; + } - int day = red * 255 + green; boolean inDay = day > 0 && day >= minDate && day <= maxDate; boolean inXPoint = xPoint >= (xFilter - THRESHOLD) && (xPoint <= xFilter + THRESHOLD); boolean inYPoint = yPoint >= (yFilter - THRESHOLD) && (yPoint <= yFilter + THRESHOLD); diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java index bc74ddad0..bac7b824f 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCanvasUrlTile.java @@ -32,10 +32,9 @@ protected Bitmap paintTile(Bitmap scaledBitmap, int width, int height, int zoom, green = (pixel >> 8) & 0xFF; blue = pixel & 0xFF; - if (red > 255) - red = 255; - if (green > 255) - green = 255; + if (red > 255) red = 255; + if (green > 255) green = 255; + if (blue > 255) blue = 255; int day; if (this.alertType != null && this.alertType.equals("viirs")) { @@ -45,7 +44,7 @@ protected Bitmap paintTile(Bitmap scaledBitmap, int width, int height, int zoom, } if(this.alertType != null && this.alertType.equals("viirs")) { - if (day > 0) { + if (day > 0 && day >= minDate && day <= maxDate) { red = 244; green = 66; blue = 66; From af13a6ce4dc3abd4090a9e890f9da65ca0c0fdcd Mon Sep 17 00:00:00 2001 From: j8seangel Date: Mon, 29 May 2017 12:36:44 +0200 Subject: [PATCH 22/22] Remove logs --- example/examples/CustomTiles.js | 2 +- .../react/maps/AirMapCanvasInteractionUrlTileManager.java | 1 - .../com/airbnb/android/react/maps/AirMapCanvasTileProvider.java | 2 -- .../airbnb/android/react/maps/AirMapCanvasUrlTileManager.java | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/example/examples/CustomTiles.js b/example/examples/CustomTiles.js index 7906ff6db..59924abba 100644 --- a/example/examples/CustomTiles.js +++ b/example/examples/CustomTiles.js @@ -98,7 +98,7 @@ class CustomTiles extends React.Component { render() { const { region, coordinates } = this.state; const hasCoordinates = (coordinates.tile && coordinates.tile.length === 3) || false; - console.log(coordinates); + return (