Skip to content

Commit c485595

Browse files
authored
feat: raster source & layer support (#11)
feat: add raster source & layer
1 parent 908dbd4 commit c485595

8 files changed

+281
-37
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,11 @@ The map will continuously move along with the last known location.
574574

575575
https://docs.mapbox.com/mapbox-gl-js/api/#map#addsource
576576

577+
Supported source types:
578+
- Vector
579+
- GeoJson
580+
- Raster
581+
577582
Adds a vector to GeoJSON source to the map.
578583

579584
```js
@@ -614,6 +619,7 @@ Supported layer types:
614619
- Circle
615620
- Fill
616621
- Symbol
622+
- Raster
617623

618624
To add a line:
619625

demo/app/main-page.xml

+2
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@
152152

153153
<Button row="12" col="0" text="get layers" tap="{{ doGetLayers }}" class="button" />
154154
<Button row="12" col="1" text="toggle all layers" tap="{{ doToggleLayers }}" class="button" />
155+
<Button row="12" col="2" text="+ raster" tap="{{ doAddRasterLayer }}" class="button" />
156+
<Button row="12" col="3" text="- raster" tap="{{ doRemoveRasterLayer }}" class="button" />
155157

156158
<StackLayout row="13" col="0" colSpan="4">
157159
<ContentView with="100%" height="100%" id="mapContainer" />

demo/app/main-view-model.ts

+23
Original file line numberDiff line numberDiff line change
@@ -1005,4 +1005,27 @@ export class HelloWorldModel extends Observable {
10051005
});
10061006
});
10071007
}
1008+
1009+
public doAddRasterLayer(): void {
1010+
this.mapbox
1011+
.addLayer({
1012+
id: 'raster-layer',
1013+
type: 'raster',
1014+
source: {
1015+
type: 'raster',
1016+
tiles: ['https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg'],
1017+
tileSize: 256
1018+
}
1019+
})
1020+
.then(() => {
1021+
console.log('raster layer added');
1022+
});
1023+
}
1024+
1025+
public doRemoveRasterLayer(): void {
1026+
this.mapbox.removeLayer('raster-layer').then(() => {
1027+
this.mapbox.removeSource('raster-layer_source');
1028+
console.log('layer removed');
1029+
});
1030+
}
10081031
}

src/layers/layer-factory.android.ts

+78-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { LayerCommon } from '../mapbox.common';
33

44
export class LayerFactory {
55
static async createLayer(style, source): Promise<LayerCommon> {
6-
const layerProperties = this.parseProperties(style.type, Object.assign(style.paint, style.layout)); // TODO: handle defaults
6+
const layerProperties = this.parseProperties(style.type, Object.assign(style.paint || {}, style.layout || {})); // TODO: handle defaults
77

88
const sourceId = source.getId();
99
let nativeLayer: com.mapbox.mapboxsdk.style.layers.Layer;
@@ -21,11 +21,14 @@ export class LayerFactory {
2121
case 'symbol':
2222
nativeLayer = new com.mapbox.mapboxsdk.style.layers.SymbolLayer(style.id, sourceId).withProperties(layerProperties);
2323
break;
24+
case 'raster':
25+
nativeLayer = new com.mapbox.mapboxsdk.style.layers.RasterLayer(style.id, sourceId).withProperties(layerProperties);
26+
break;
2427
default:
2528
throw new Error(`Unknown layer type: ${style.type}`);
2629
}
2730

28-
var layer = new Layer(nativeLayer);
31+
const layer = new Layer(nativeLayer);
2932

3033
return layer;
3134
}
@@ -40,6 +43,8 @@ export class LayerFactory {
4043
return this.parsePropertiesForFillLayer(propertiesObject);
4144
case 'symbol':
4245
return this.parsePropertiesForSymbolLayer(propertiesObject);
46+
case 'raster':
47+
return this.parsePropertiesForRasterLayer(propertiesObject);
4348
default:
4449
throw new Error(`Unknown layer type: ${layerType}`);
4550
}
@@ -246,15 +251,7 @@ export class LayerFactory {
246251
base = propertiesObject['circle-radius'].stops.base;
247252
}
248253

249-
circleProperties.push(
250-
PropertyFactory.circleRadius(
251-
Expression.interpolate(
252-
Expression.exponential(new java.lang.Float(base)),
253-
Expression.zoom(),
254-
stopArgs
255-
)
256-
)
257-
);
254+
circleProperties.push(PropertyFactory.circleRadius(Expression.interpolate(Expression.exponential(new java.lang.Float(base)), Expression.zoom(), stopArgs)));
258255
}
259256
}
260257

@@ -443,7 +440,76 @@ export class LayerFactory {
443440
if (propertiesObject['visibility']) {
444441
symbolProperties.push(PropertyFactory.visibility(propertiesObject['visibility']));
445442
}
446-
443+
447444
return symbolProperties;
448445
}
446+
447+
private static parsePropertiesForRasterLayer(propertiesObject) {
448+
const rasterProperties = [];
449+
450+
if (!propertiesObject) {
451+
return rasterProperties;
452+
}
453+
454+
/*
455+
raster-brightness-max ✓
456+
raster-brightness-min ✓
457+
raster-contrast ✓
458+
raster-fade-duration ✓
459+
raster-hue-rotate ✓
460+
raster-opacity ✓
461+
raster-resampling ✓
462+
raster-saturation ✓
463+
visibility ✓
464+
*/
465+
466+
const PropertyFactory = com.mapbox.mapboxsdk.style.layers.PropertyFactory;
467+
468+
if (propertiesObject['raster-brightness-max']) {
469+
rasterProperties.push(PropertyFactory.rasterBrightnessMax(new java.lang.Float(propertiesObject['raster-brightness-max'])));
470+
}
471+
472+
if (propertiesObject['raster-brightness-min']) {
473+
rasterProperties.push(PropertyFactory.rasterBrightnessMin(new java.lang.Float(propertiesObject['raster-brightness-min'])));
474+
}
475+
476+
if (propertiesObject['raster-contrast']) {
477+
rasterProperties.push(PropertyFactory.rasterContrast(new java.lang.Float(propertiesObject['raster-contrast'])));
478+
}
479+
480+
if (propertiesObject['raster-fade-duration']) {
481+
rasterProperties.push(PropertyFactory.rasterFadeDuration(new java.lang.Float(propertiesObject['raster-fade-duration'])));
482+
}
483+
484+
if (propertiesObject['raster-hue-rotate']) {
485+
rasterProperties.push(PropertyFactory.rasterHueRotate(new java.lang.Float(propertiesObject['raster-hue-rotate'])));
486+
}
487+
488+
if (propertiesObject['raster-opacity']) {
489+
rasterProperties.push(PropertyFactory.rasterOpacity(new java.lang.Float(propertiesObject['raster-opacity'])));
490+
}
491+
492+
if (propertiesObject['raster-resampling']) {
493+
switch (propertiesObject['raster-resampling']) {
494+
case 'linear':
495+
rasterProperties.push(com.mapbox.mapboxsdk.style.layers.Property.RASTER_RESAMPLING_LINEAR);
496+
break;
497+
case 'nearest':
498+
rasterProperties.push(com.mapbox.mapboxsdk.style.layers.Property.RASTER_RESAMPLING_NEAREST);
499+
break;
500+
default:
501+
throw new Error('Unknown raster resampling value.');
502+
}
503+
}
504+
505+
if (propertiesObject['raster-saturation']) {
506+
rasterProperties.push(PropertyFactory.rasterSaturation(new java.lang.Float(propertiesObject['raster-saturation'])));
507+
}
508+
509+
if (propertiesObject['visibility']) {
510+
rasterProperties.push(PropertyFactory.visibility(propertiesObject['visibility']));
511+
}
512+
513+
return rasterProperties;
514+
}
449515
}

src/layers/layer-factory.ios.ts

+75-3
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,27 @@ export class LayerFactory {
1919
case 'symbol':
2020
nativeLayer = MGLSymbolStyleLayer.alloc().initWithIdentifierSource(style.id, source);
2121
break;
22+
case 'raster':
23+
nativeLayer = MGLRasterStyleLayer.alloc().initWithIdentifierSource(style.id, source);
24+
break;
2225
default:
2326
throw new Error(`Unknown layer type: ${style.type}`);
2427
}
2528

26-
const layerProperties = this.parseProperties(style.type, Object.assign(style.paint, style.layout)); // TODO: handle defaults
29+
const layerProperties = this.parseProperties(style.type, Object.assign(style.paint || {}, style.layout || {})); // TODO: handle defaults
2730

2831
for (const propKey in layerProperties) {
2932
if (Object.prototype.hasOwnProperty.call(layerProperties, propKey)) {
3033
nativeLayer[propKey] = layerProperties[propKey];
3134
}
3235
}
3336

34-
var layer = new Layer(nativeLayer);
37+
const layer = new Layer(nativeLayer);
3538

3639
return layer;
3740
}
3841

39-
private static parseProperties(layerType, propertiesObject) {
42+
private static parseProperties(layerType, propertiesObject): any {
4043
switch (layerType) {
4144
case 'line':
4245
return this.parsePropertiesForLineLayer(propertiesObject);
@@ -46,6 +49,8 @@ export class LayerFactory {
4649
return this.parsePropertiesForFillLayer(propertiesObject);
4750
case 'symbol':
4851
return this.parsePropertiesForSymbolLayer(propertiesObject);
52+
case 'raster':
53+
return this.parsePropertiesForRasterLayer(propertiesObject);
4954
default:
5055
throw new Error(`Unknown layer type: ${layerType}`);
5156
}
@@ -360,4 +365,71 @@ export class LayerFactory {
360365

361366
return symbolProperties;
362367
}
368+
369+
private static parsePropertiesForRasterLayer(propertiesObject) {
370+
const rasterProperties = {};
371+
372+
if (!propertiesObject) {
373+
return rasterProperties;
374+
}
375+
376+
/*
377+
raster-brightness-max ✓
378+
raster-brightness-min ✓
379+
raster-contrast ✓
380+
raster-fade-duration ✓
381+
raster-hue-rotate ✓
382+
raster-opacity ✓
383+
raster-resampling ✓
384+
raster-saturation ✓
385+
visibility ✓
386+
*/
387+
388+
if (propertiesObject['raster-brightness-max']) {
389+
rasterProperties['maximumRasterBrightness'] = NSExpression.expressionForConstantValue(propertiesObject['raster-brightness-max']);
390+
}
391+
392+
if (propertiesObject['raster-brightness-min']) {
393+
rasterProperties['minimumRasterBrightness'] = NSExpression.expressionForConstantValue(propertiesObject['raster-brightness-min']);
394+
}
395+
396+
if (propertiesObject['raster-contrast']) {
397+
rasterProperties['rasterContrast'] = NSExpression.expressionForConstantValue(propertiesObject['raster-contrast']);
398+
}
399+
400+
if (propertiesObject['raster-fade-duration']) {
401+
rasterProperties['rasterFadeDuration'] = NSExpression.expressionForConstantValue(propertiesObject['raster-fade-duration']);
402+
}
403+
404+
if (propertiesObject['raster-hue-rotate']) {
405+
rasterProperties['rasterHueRotation'] = NSExpression.expressionForConstantValue(propertiesObject['raster-hue-rotate']);
406+
}
407+
408+
if (propertiesObject['raster-opacity']) {
409+
rasterProperties['rasterOpacity'] = NSExpression.expressionForConstantValue(propertiesObject['raster-opacity']);
410+
}
411+
412+
if (propertiesObject['raster-resampling']) {
413+
switch (propertiesObject['raster-resampling']) {
414+
case 'linear':
415+
rasterProperties['rasterResamplingMode'] = MGLRasterResamplingMode.Linear;
416+
break;
417+
case 'nearest':
418+
rasterProperties['rasterResamplingMode'] = MGLRasterResamplingMode.Nearest;
419+
break;
420+
default:
421+
throw new Error('Unknown raster resampling value.');
422+
}
423+
}
424+
425+
if (propertiesObject['raster-saturation']) {
426+
rasterProperties['rasterSaturation'] = NSExpression.expressionForConstantValue(propertiesObject['raster-saturation']);
427+
}
428+
429+
if (propertiesObject['visibility']) {
430+
rasterProperties['visibility'] = NSExpression.expressionForConstantValue(propertiesObject['visibility']);
431+
}
432+
433+
return rasterProperties;
434+
}
363435
}

src/mapbox.android.ts

+31-10
Original file line numberDiff line numberDiff line change
@@ -2627,7 +2627,6 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
26272627
addSource(id: string, options: AddSourceOptions, nativeMap?): Promise<void> {
26282628
return new Promise((resolve, reject) => {
26292629
try {
2630-
const { url, type } = options;
26312630
const theMap = nativeMap || this._mapboxMapInstance;
26322631
let source;
26332632

@@ -2641,9 +2640,9 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
26412640
return;
26422641
}
26432642

2644-
switch (type) {
2643+
switch (options.type) {
26452644
case 'vector':
2646-
source = new com.mapbox.mapboxsdk.style.sources.VectorSource(id, url);
2645+
source = new com.mapbox.mapboxsdk.style.sources.VectorSource(id, options.url);
26472646
break;
26482647

26492648
case 'geojson':
@@ -2659,8 +2658,33 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
26592658

26602659
break;
26612660

2661+
case 'raster':
2662+
// use Array.create because a marshal error throws on TileSet if options.tiles directly passed.
2663+
const tiles = Array.create(java.lang.String, options.tiles.length);
2664+
options.tiles.forEach((val, i) => tiles[i] = val);
2665+
2666+
const tileSet = new com.mapbox.mapboxsdk.style.sources.TileSet('tileset', tiles);
2667+
2668+
if (options.minzoom) {
2669+
tileSet.setMinZoom(options.minzoom);
2670+
}
2671+
2672+
if (options.maxzoom) {
2673+
tileSet.setMaxZoom(options.maxzoom);
2674+
}
2675+
2676+
if (options.scheme) {
2677+
tileSet.setScheme(options.scheme);
2678+
}
2679+
2680+
if (options.bounds) {
2681+
tileSet.setBounds(options.bounds.map((val) => new java.lang.Float(val)));
2682+
}
2683+
2684+
source = new com.mapbox.mapboxsdk.style.sources.RasterSource(id, tileSet, options.tileSize);
2685+
break;
26622686
default:
2663-
reject('Invalid source type: ' + type);
2687+
reject('Invalid source type: ' + options['type']);
26642688
return;
26652689
}
26662690

@@ -2739,17 +2763,14 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
27392763

27402764
let source = null;
27412765
if (typeof style.source != 'string') {
2742-
this.addSource(style.id + '_source', style.source);
2766+
await this.addSource(style.id + '_source', style.source);
27432767
source = theMap.getStyle().getSource(style.id + '_source');
27442768
} else {
2745-
source = style.source;
2769+
source = theMap.getStyle().getSource(style.source);
27462770
}
2747-
2748-
const layer = await LayerFactory.createLayer(style, source);
27492771

2772+
const layer = await LayerFactory.createLayer(style, source);
27502773
this._mapboxMapInstance.getStyle().addLayer(layer.getNativeInstance());
2751-
2752-
return Promise.resolve();
27532774
}
27542775

27552776
/**

0 commit comments

Comments
 (0)