diff --git a/src/plots/mapbox/layers.js b/src/plots/mapbox/layers.js index d6a896c605b..45a85ff819e 100644 --- a/src/plots/mapbox/layers.js +++ b/src/plots/mapbox/layers.js @@ -131,7 +131,7 @@ function isVisible(opts) { return opts.visible && ( Lib.isPlainObject(source) || - (typeof source === 'string' && source.length > 0) + ((typeof source === 'string' || Array.isArray(source)) && source.length > 0) ); } @@ -193,7 +193,10 @@ function convertOpts(opts) { break; } - return { layout: layout, paint: paint }; + return { + layout: layout, + paint: paint + }; } function convertSourceOpts(opts) { @@ -206,9 +209,16 @@ function convertSourceOpts(opts) { field = 'data'; } else if(sourceType === 'vector') { field = typeof source === 'string' ? 'url' : 'tiles'; + } else if(sourceType === 'raster') { + field = 'tiles'; + sourceOpts.tileSize = 256; + } else if(sourceType === 'image') { + field = 'url'; + sourceOpts.coordinates = opts.coordinates; } sourceOpts[field] = source; + return sourceOpts; } diff --git a/src/plots/mapbox/layout_attributes.js b/src/plots/mapbox/layout_attributes.js index 2b39202f6f0..e8be572252c 100644 --- a/src/plots/mapbox/layout_attributes.js +++ b/src/plots/mapbox/layout_attributes.js @@ -102,12 +102,11 @@ var attrs = module.exports = overrideAll({ }, sourcetype: { valType: 'enumerated', - values: ['geojson', 'vector'], + values: ['geojson', 'vector', 'raster', 'image'], dflt: 'geojson', role: 'info', description: [ - 'Sets the source type for this layer.', - 'Support for *raster*, *image* and *video* source types is coming soon.' + 'Sets the source type for this layer.' ].join(' ') }, @@ -134,7 +133,7 @@ var attrs = module.exports = overrideAll({ type: { valType: 'enumerated', - values: ['circle', 'line', 'fill', 'symbol'], + values: ['circle', 'line', 'fill', 'symbol', 'raster'], dflt: 'circle', role: 'info', description: [ @@ -145,6 +144,17 @@ var attrs = module.exports = overrideAll({ ].join(' ') }, + coordinates: { + valType: 'any', + role: 'info', + description: [ + 'Sets the coordinates array contains [longitude, latitude] pairs', + 'for the image corners listed in clockwise order:', + 'top left, top right, bottom right, bottom left.', + 'Only has an effect for *image* `sourcetype`.' + ].join(' ') + }, + // attributes shared between all types below: { valType: 'string', diff --git a/src/plots/mapbox/layout_defaults.js b/src/plots/mapbox/layout_defaults.js index b9651e06ba5..ee1e77c8964 100644 --- a/src/plots/mapbox/layout_defaults.js +++ b/src/plots/mapbox/layout_defaults.js @@ -6,7 +6,6 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var Lib = require('../../lib'); @@ -52,12 +51,27 @@ function handleLayerDefaults(layerIn, layerOut) { var visible = coerce('visible'); if(visible) { var sourceType = coerce('sourcetype'); + var mustBeRasterLayer = sourceType === 'raster' || sourceType === 'image'; + coerce('source'); - if(sourceType === 'vector') coerce('sourcelayer'); + if(sourceType === 'vector') { + coerce('sourcelayer'); + } + + if(sourceType === 'image') { + coerce('coordinates'); + } + + var typeDflt; + if(mustBeRasterLayer) typeDflt = 'raster'; - // maybe add smart default based off GeoJSON geometry? - var type = coerce('type'); + var type = coerce('type', typeDflt); + + if(mustBeRasterLayer && type !== 'raster') { + type = layerOut.type = 'raster'; + Lib.log('Source types *raster* and *image* must drawn *raster* layer type.'); + } coerce('below'); coerce('color'); diff --git a/test/image/baselines/mapbox_layers.png b/test/image/baselines/mapbox_layers.png index e6d4621e425..71dd1c2c619 100644 Binary files a/test/image/baselines/mapbox_layers.png and b/test/image/baselines/mapbox_layers.png differ diff --git a/test/image/mocks/mapbox_layers.json b/test/image/mocks/mapbox_layers.json index 9edb823de66..cee6f59e0d5 100644 --- a/test/image/mocks/mapbox_layers.json +++ b/test/image/mocks/mapbox_layers.json @@ -21,10 +21,15 @@ "#7570b3" ] } + }, + { + "type": "scattermapbox", + "subplot": "mapbox2" } ], "layout": { "mapbox": { + "domain": {"x": [0, 0.48], "y": [0, 1]}, "style": "light", "center": { "lon": -73.59194521800514, @@ -547,8 +552,33 @@ } ] }, + + "mapbox2": { + "domain": {"x": [0.52, 1], "y": [0, 1]}, + "style": "mapbox://styles/mapbox/light-v10", + "zoom": 4.5, + "center": {"lon": -74.5, "lat": 42}, + "layers": [ + { + "sourcetype": "raster", + "source": [ + "https://img.nj.gov/imagerywms/Natural2015?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:3857&transparent=true&width=256&height=256&layers=Natural2015" + ], + "below": "aeroway-line" + }, + { + "sourcetype": "image", + "coordinates": [ + [-80.425, 46.437], + [-71.516, 46.437], + [-71.516, 37.936], + [-80.425, 37.936] + ], + "source": "https://docs.mapbox.com/mapbox-gl-js/assets/radar.gif" + } + ] + }, "height": 450, - "width": 1100, - "autosize": true + "width": 900 } } diff --git a/test/jasmine/tests/mapbox_test.js b/test/jasmine/tests/mapbox_test.js index 831bc8e8896..bbbb86521b2 100644 --- a/test/jasmine/tests/mapbox_test.js +++ b/test/jasmine/tests/mapbox_test.js @@ -184,6 +184,52 @@ describe('mapbox defaults', function() { expect(layoutOut.mapbox.layers[3].circle).toBeUndefined(); }); + it('should not allow to set layer type other than *raster* for sourcetype value *raster* and *image*', function() { + spyOn(Lib, 'log'); + + layoutIn = { + mapbox: { + layers: [{ + sourcetype: 'raster', + source: 'url', + type: 'circle' + }, { + sourcetype: 'image', + source: 'url', + type: 'fill' + }] + } + }; + supplyLayoutDefaults(layoutIn, layoutOut, fullData); + + expect(Lib.log).toHaveBeenCalledTimes(2); + expect(Lib.log).toHaveBeenCalledWith('Source types *raster* and *image* must drawn *raster* layer type.'); + + expect(layoutOut.mapbox.layers[0].type).toBe('raster'); + expect(layoutOut.mapbox.layers[1].type).toBe('raster'); + }); + + it('should default layer with sourcetype *raster* and *image* to type *raster', function() { + spyOn(Lib, 'log'); + + layoutIn = { + mapbox: { + layers: [{ + sourcetype: 'raster', + source: 'url' + }, { + sourcetype: 'image', + source: 'url' + }] + } + }; + supplyLayoutDefaults(layoutIn, layoutOut, fullData); + + expect(Lib.log).toHaveBeenCalledTimes(0); + expect(layoutOut.mapbox.layers[0].type).toBe('raster'); + expect(layoutOut.mapbox.layers[1].type).toBe('raster'); + }); + it('should set *layout.dragmode* to pan while zoom is not available', function() { var gd = { data: fullData,