diff --git a/README.md b/README.md
index 36ad8a1..5215d7a 100755
--- a/README.md
+++ b/README.md
@@ -574,6 +574,11 @@ The map will continuously move along with the last known location.
https://docs.mapbox.com/mapbox-gl-js/api/#map#addsource
+Supported source types:
+ - Vector
+ - GeoJson
+ - Raster
+
Adds a vector to GeoJSON source to the map.
```js
@@ -614,6 +619,7 @@ Supported layer types:
- Circle
- Fill
- Symbol
+ - Raster
To add a line:
diff --git a/demo/app/main-page.xml b/demo/app/main-page.xml
index a0aea12..88dac0e 100644
--- a/demo/app/main-page.xml
+++ b/demo/app/main-page.xml
@@ -152,6 +152,8 @@
+
+
diff --git a/demo/app/main-view-model.ts b/demo/app/main-view-model.ts
index 7ba77a3..1fffe57 100644
--- a/demo/app/main-view-model.ts
+++ b/demo/app/main-view-model.ts
@@ -1005,4 +1005,27 @@ export class HelloWorldModel extends Observable {
});
});
}
+
+ public doAddRasterLayer(): void {
+ this.mapbox
+ .addLayer({
+ id: 'raster-layer',
+ type: 'raster',
+ source: {
+ type: 'raster',
+ tiles: ['https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg'],
+ tileSize: 256
+ }
+ })
+ .then(() => {
+ console.log('raster layer added');
+ });
+ }
+
+ public doRemoveRasterLayer(): void {
+ this.mapbox.removeLayer('raster-layer').then(() => {
+ this.mapbox.removeSource('raster-layer_source');
+ console.log('layer removed');
+ });
+ }
}
diff --git a/src/layers/layer-factory.android.ts b/src/layers/layer-factory.android.ts
index 7a19cc7..7bc1d1e 100644
--- a/src/layers/layer-factory.android.ts
+++ b/src/layers/layer-factory.android.ts
@@ -3,7 +3,7 @@ import { LayerCommon } from '../mapbox.common';
export class LayerFactory {
static async createLayer(style, source): Promise {
- const layerProperties = this.parseProperties(style.type, Object.assign(style.paint, style.layout)); // TODO: handle defaults
+ const layerProperties = this.parseProperties(style.type, Object.assign(style.paint || {}, style.layout || {})); // TODO: handle defaults
const sourceId = source.getId();
let nativeLayer: com.mapbox.mapboxsdk.style.layers.Layer;
@@ -21,11 +21,14 @@ export class LayerFactory {
case 'symbol':
nativeLayer = new com.mapbox.mapboxsdk.style.layers.SymbolLayer(style.id, sourceId).withProperties(layerProperties);
break;
+ case 'raster':
+ nativeLayer = new com.mapbox.mapboxsdk.style.layers.RasterLayer(style.id, sourceId).withProperties(layerProperties);
+ break;
default:
throw new Error(`Unknown layer type: ${style.type}`);
}
- var layer = new Layer(nativeLayer);
+ const layer = new Layer(nativeLayer);
return layer;
}
@@ -40,6 +43,8 @@ export class LayerFactory {
return this.parsePropertiesForFillLayer(propertiesObject);
case 'symbol':
return this.parsePropertiesForSymbolLayer(propertiesObject);
+ case 'raster':
+ return this.parsePropertiesForRasterLayer(propertiesObject);
default:
throw new Error(`Unknown layer type: ${layerType}`);
}
@@ -246,15 +251,7 @@ export class LayerFactory {
base = propertiesObject['circle-radius'].stops.base;
}
- circleProperties.push(
- PropertyFactory.circleRadius(
- Expression.interpolate(
- Expression.exponential(new java.lang.Float(base)),
- Expression.zoom(),
- stopArgs
- )
- )
- );
+ circleProperties.push(PropertyFactory.circleRadius(Expression.interpolate(Expression.exponential(new java.lang.Float(base)), Expression.zoom(), stopArgs)));
}
}
@@ -443,7 +440,76 @@ export class LayerFactory {
if (propertiesObject['visibility']) {
symbolProperties.push(PropertyFactory.visibility(propertiesObject['visibility']));
}
-
+
return symbolProperties;
}
+
+ private static parsePropertiesForRasterLayer(propertiesObject) {
+ const rasterProperties = [];
+
+ if (!propertiesObject) {
+ return rasterProperties;
+ }
+
+ /*
+ raster-brightness-max ✓
+ raster-brightness-min ✓
+ raster-contrast ✓
+ raster-fade-duration ✓
+ raster-hue-rotate ✓
+ raster-opacity ✓
+ raster-resampling ✓
+ raster-saturation ✓
+ visibility ✓
+ */
+
+ const PropertyFactory = com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+
+ if (propertiesObject['raster-brightness-max']) {
+ rasterProperties.push(PropertyFactory.rasterBrightnessMax(new java.lang.Float(propertiesObject['raster-brightness-max'])));
+ }
+
+ if (propertiesObject['raster-brightness-min']) {
+ rasterProperties.push(PropertyFactory.rasterBrightnessMin(new java.lang.Float(propertiesObject['raster-brightness-min'])));
+ }
+
+ if (propertiesObject['raster-contrast']) {
+ rasterProperties.push(PropertyFactory.rasterContrast(new java.lang.Float(propertiesObject['raster-contrast'])));
+ }
+
+ if (propertiesObject['raster-fade-duration']) {
+ rasterProperties.push(PropertyFactory.rasterFadeDuration(new java.lang.Float(propertiesObject['raster-fade-duration'])));
+ }
+
+ if (propertiesObject['raster-hue-rotate']) {
+ rasterProperties.push(PropertyFactory.rasterHueRotate(new java.lang.Float(propertiesObject['raster-hue-rotate'])));
+ }
+
+ if (propertiesObject['raster-opacity']) {
+ rasterProperties.push(PropertyFactory.rasterOpacity(new java.lang.Float(propertiesObject['raster-opacity'])));
+ }
+
+ if (propertiesObject['raster-resampling']) {
+ switch (propertiesObject['raster-resampling']) {
+ case 'linear':
+ rasterProperties.push(com.mapbox.mapboxsdk.style.layers.Property.RASTER_RESAMPLING_LINEAR);
+ break;
+ case 'nearest':
+ rasterProperties.push(com.mapbox.mapboxsdk.style.layers.Property.RASTER_RESAMPLING_NEAREST);
+ break;
+ default:
+ throw new Error('Unknown raster resampling value.');
+ }
+ }
+
+ if (propertiesObject['raster-saturation']) {
+ rasterProperties.push(PropertyFactory.rasterSaturation(new java.lang.Float(propertiesObject['raster-saturation'])));
+ }
+
+ if (propertiesObject['visibility']) {
+ rasterProperties.push(PropertyFactory.visibility(propertiesObject['visibility']));
+ }
+
+ return rasterProperties;
+ }
}
diff --git a/src/layers/layer-factory.ios.ts b/src/layers/layer-factory.ios.ts
index 344ee42..63e2a46 100644
--- a/src/layers/layer-factory.ios.ts
+++ b/src/layers/layer-factory.ios.ts
@@ -19,11 +19,14 @@ export class LayerFactory {
case 'symbol':
nativeLayer = MGLSymbolStyleLayer.alloc().initWithIdentifierSource(style.id, source);
break;
+ case 'raster':
+ nativeLayer = MGLRasterStyleLayer.alloc().initWithIdentifierSource(style.id, source);
+ break;
default:
throw new Error(`Unknown layer type: ${style.type}`);
}
- const layerProperties = this.parseProperties(style.type, Object.assign(style.paint, style.layout)); // TODO: handle defaults
+ const layerProperties = this.parseProperties(style.type, Object.assign(style.paint || {}, style.layout || {})); // TODO: handle defaults
for (const propKey in layerProperties) {
if (Object.prototype.hasOwnProperty.call(layerProperties, propKey)) {
@@ -31,12 +34,12 @@ export class LayerFactory {
}
}
- var layer = new Layer(nativeLayer);
+ const layer = new Layer(nativeLayer);
return layer;
}
- private static parseProperties(layerType, propertiesObject) {
+ private static parseProperties(layerType, propertiesObject): any {
switch (layerType) {
case 'line':
return this.parsePropertiesForLineLayer(propertiesObject);
@@ -46,6 +49,8 @@ export class LayerFactory {
return this.parsePropertiesForFillLayer(propertiesObject);
case 'symbol':
return this.parsePropertiesForSymbolLayer(propertiesObject);
+ case 'raster':
+ return this.parsePropertiesForRasterLayer(propertiesObject);
default:
throw new Error(`Unknown layer type: ${layerType}`);
}
@@ -360,4 +365,71 @@ export class LayerFactory {
return symbolProperties;
}
+
+ private static parsePropertiesForRasterLayer(propertiesObject) {
+ const rasterProperties = {};
+
+ if (!propertiesObject) {
+ return rasterProperties;
+ }
+
+ /*
+ raster-brightness-max ✓
+ raster-brightness-min ✓
+ raster-contrast ✓
+ raster-fade-duration ✓
+ raster-hue-rotate ✓
+ raster-opacity ✓
+ raster-resampling ✓
+ raster-saturation ✓
+ visibility ✓
+ */
+
+ if (propertiesObject['raster-brightness-max']) {
+ rasterProperties['maximumRasterBrightness'] = NSExpression.expressionForConstantValue(propertiesObject['raster-brightness-max']);
+ }
+
+ if (propertiesObject['raster-brightness-min']) {
+ rasterProperties['minimumRasterBrightness'] = NSExpression.expressionForConstantValue(propertiesObject['raster-brightness-min']);
+ }
+
+ if (propertiesObject['raster-contrast']) {
+ rasterProperties['rasterContrast'] = NSExpression.expressionForConstantValue(propertiesObject['raster-contrast']);
+ }
+
+ if (propertiesObject['raster-fade-duration']) {
+ rasterProperties['rasterFadeDuration'] = NSExpression.expressionForConstantValue(propertiesObject['raster-fade-duration']);
+ }
+
+ if (propertiesObject['raster-hue-rotate']) {
+ rasterProperties['rasterHueRotation'] = NSExpression.expressionForConstantValue(propertiesObject['raster-hue-rotate']);
+ }
+
+ if (propertiesObject['raster-opacity']) {
+ rasterProperties['rasterOpacity'] = NSExpression.expressionForConstantValue(propertiesObject['raster-opacity']);
+ }
+
+ if (propertiesObject['raster-resampling']) {
+ switch (propertiesObject['raster-resampling']) {
+ case 'linear':
+ rasterProperties['rasterResamplingMode'] = MGLRasterResamplingMode.Linear;
+ break;
+ case 'nearest':
+ rasterProperties['rasterResamplingMode'] = MGLRasterResamplingMode.Nearest;
+ break;
+ default:
+ throw new Error('Unknown raster resampling value.');
+ }
+ }
+
+ if (propertiesObject['raster-saturation']) {
+ rasterProperties['rasterSaturation'] = NSExpression.expressionForConstantValue(propertiesObject['raster-saturation']);
+ }
+
+ if (propertiesObject['visibility']) {
+ rasterProperties['visibility'] = NSExpression.expressionForConstantValue(propertiesObject['visibility']);
+ }
+
+ return rasterProperties;
+ }
}
diff --git a/src/mapbox.android.ts b/src/mapbox.android.ts
index 9652938..f36df53 100755
--- a/src/mapbox.android.ts
+++ b/src/mapbox.android.ts
@@ -2627,7 +2627,6 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
addSource(id: string, options: AddSourceOptions, nativeMap?): Promise {
return new Promise((resolve, reject) => {
try {
- const { url, type } = options;
const theMap = nativeMap || this._mapboxMapInstance;
let source;
@@ -2641,9 +2640,9 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
return;
}
- switch (type) {
+ switch (options.type) {
case 'vector':
- source = new com.mapbox.mapboxsdk.style.sources.VectorSource(id, url);
+ source = new com.mapbox.mapboxsdk.style.sources.VectorSource(id, options.url);
break;
case 'geojson':
@@ -2659,8 +2658,33 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
break;
+ case 'raster':
+ // use Array.create because a marshal error throws on TileSet if options.tiles directly passed.
+ const tiles = Array.create(java.lang.String, options.tiles.length);
+ options.tiles.forEach((val, i) => tiles[i] = val);
+
+ const tileSet = new com.mapbox.mapboxsdk.style.sources.TileSet('tileset', tiles);
+
+ if (options.minzoom) {
+ tileSet.setMinZoom(options.minzoom);
+ }
+
+ if (options.maxzoom) {
+ tileSet.setMaxZoom(options.maxzoom);
+ }
+
+ if (options.scheme) {
+ tileSet.setScheme(options.scheme);
+ }
+
+ if (options.bounds) {
+ tileSet.setBounds(options.bounds.map((val) => new java.lang.Float(val)));
+ }
+
+ source = new com.mapbox.mapboxsdk.style.sources.RasterSource(id, tileSet, options.tileSize);
+ break;
default:
- reject('Invalid source type: ' + type);
+ reject('Invalid source type: ' + options['type']);
return;
}
@@ -2739,17 +2763,14 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
let source = null;
if (typeof style.source != 'string') {
- this.addSource(style.id + '_source', style.source);
+ await this.addSource(style.id + '_source', style.source);
source = theMap.getStyle().getSource(style.id + '_source');
} else {
- source = style.source;
+ source = theMap.getStyle().getSource(style.source);
}
-
- const layer = await LayerFactory.createLayer(style, source);
+ const layer = await LayerFactory.createLayer(style, source);
this._mapboxMapInstance.getStyle().addLayer(layer.getNativeInstance());
-
- return Promise.resolve();
}
/**
diff --git a/src/mapbox.common.ts b/src/mapbox.common.ts
index 4fa270d..f1ec25c 100755
--- a/src/mapbox.common.ts
+++ b/src/mapbox.common.ts
@@ -1,4 +1,4 @@
-import { Color, ContentView, Property, Trace, booleanConverter, ImageSource } from '@nativescript/core';
+import { Color, ContentView, Property, Trace, booleanConverter } from '@nativescript/core';
export const MapboxTraceCategory = 'NativescriptMapbox';
export enum CLogTypes {
@@ -285,9 +285,37 @@ export type UserTrackingMode = 'NONE' | 'FOLLOW' | 'FOLLOW_WITH_HEADING' | 'FOLL
// -------------------------------------------------------------
-export interface AddSourceOptions {
+export type AddSourceOptions = VectorSource | GeoJSONSource | RasterSource;
+
+// -------------------------------------------------------------
+
+export interface Source {
+ type: 'vector' | 'raster' | 'geojson';
+}
+
+// -------------------------------------------------------------
+
+export interface RasterSource extends Source {
+ type: 'raster';
+ tiles: string[];
+ bounds?: number[];
+ minzoom?: number;
+ maxzoom?: number;
+ tileSize?: number;
+ scheme?: 'xyz' | 'tms';
+}
+
+// -------------------------------------------------------------
+
+export interface VectorSource extends Source {
+ type: 'vector';
url: string;
- type: string;
+}
+
+// -------------------------------------------------------------
+
+export interface GeoJSONSource extends Source {
+ type: 'geojson';
data?: any;
}
diff --git a/src/mapbox.ios.ts b/src/mapbox.ios.ts
index e59bd49..8ff7126 100755
--- a/src/mapbox.ios.ts
+++ b/src/mapbox.ios.ts
@@ -2110,7 +2110,6 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
addSource(id: string, options: AddSourceOptions, nativeMap?): Promise {
return new Promise((resolve, reject) => {
try {
- const { url, type } = options;
const theMap: MGLMapView = nativeMap || this._mapboxViewInstance;
let source;
@@ -2124,9 +2123,9 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
return;
}
- switch (type) {
+ switch (options.type) {
case 'vector':
- source = MGLVectorTileSource.alloc().initWithIdentifierConfigurationURL(id, NSURL.URLWithString(url));
+ source = MGLVectorTileSource.alloc().initWithIdentifierConfigurationURL(id, NSURL.URLWithString(options.url));
break;
case 'geojson':
@@ -2138,13 +2137,42 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
const content: NSString = NSString.stringWithString(JSON.stringify(options.data));
const nsData: NSData = content.dataUsingEncoding(NSUTF8StringEncoding);
const geoJsonShape = MGLShape.shapeWithDataEncodingError(nsData, NSUTF8StringEncoding);
-
+
source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(id, geoJsonShape, null);
break;
+ case 'raster':
+ const sourceOptions: any = {
+ [MGLTileSourceOptionMinimumZoomLevel]: options.minzoom,
+ [MGLTileSourceOptionMaximumZoomLevel]: options.maxzoom,
+ [MGLTileSourceOptionTileSize]: options.tileSize
+ };
+
+ if (options.scheme) {
+ switch (options.scheme || 'xyz') {
+ case 'xyz':
+ sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = MGLTileCoordinateSystem.XYZ;
+ break;
+ case 'tms':
+ sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = MGLTileCoordinateSystem.TMS;
+ break;
+ default:
+ throw new Error('Unknown raster tile scheme.');
+ }
+ }
+
+ if (options.bounds) {
+ sourceOptions[MGLTileSourceOptionCoordinateBounds] = {
+ sw: CLLocationCoordinate2DMake(options.bounds[1], options.bounds[0]),
+ ne: CLLocationCoordinate2DMake(options.bounds[3], options.bounds[2])
+ } as MGLCoordinateBounds;
+ }
+ source = MGLRasterTileSource.alloc().initWithIdentifierTileURLTemplatesOptions(id, options.tiles, sourceOptions);
+
+ break;
default:
- reject('Invalid source type: ' + type);
+ reject('Invalid source type: ' + options['type']);
return;
}
@@ -2224,16 +2252,14 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
let source = null;
if (typeof style.source != 'string') {
- this.addSource(style.id + '_source', style.source);
+ await this.addSource(style.id + '_source', style.source);
source = theMap.style.sourceWithIdentifier(style.id + '_source');
} else {
- source = style.source;
+ source = theMap.style.sourceWithIdentifier(style.source);
}
const layer = await LayerFactory.createLayer(style, source);
theMap.style.addLayer(layer.getNativeInstance());
-
- return Promise.resolve();
}
/**