diff --git a/package-lock.json b/package-lock.json
index a88cd6771aa..b3b66a118b3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -78,9 +78,9 @@
"integrity": "sha1-zlblOfg1UrWNENZy6k1vya3HsjQ="
},
"@mapbox/mapbox-gl-supported": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.4.0.tgz",
- "integrity": "sha512-ZD0Io4XK+/vU/4zpANjOtdWfVszAgnaMPsGR6LKsWh4kLIEv9qoobTVmJPPuwuM+ZI2b3BlZ6DYw1XHVmv6YTA=="
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.4.1.tgz",
+ "integrity": "sha512-yyKza9S6z3ELKuf6w5n6VNUB0Osu6Z93RXPfMHLIlNWohu3KqxewLOq4lMXseYJ92GwkRAxd207Pr/Z98cwmvw=="
},
"@mapbox/point-geometry": {
"version": "0.1.0",
@@ -3126,6 +3126,11 @@
}
}
},
+ "earcut": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.1.5.tgz",
+ "integrity": "sha512-QFWC7ywTVLtvRAJTVp8ugsuuGQ5mVqNmJ1cRYeLrSHgP3nycr2RHTJob9OtM0v8ujuoKN0NY1a93J/omeTL1PA=="
+ },
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -7077,9 +7082,9 @@
}
},
"mapbox-gl": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-1.1.0.tgz",
- "integrity": "sha512-ODwesguQJM7FobmSlv/qGJkmrzUTlIRe92dEBy587RV2k2QGsQDQUCk6/KE+lzVJuyk7WQappNkzhgagaxY5Eg==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-1.1.1.tgz",
+ "integrity": "sha512-i57kASg8J/U/lJzBePyqTP2ImKUcx8FkHyCjb3ssWYaBBXHUeZ4STGXXfU9u1AQU9170PjDIJLubUUB1vLLSBQ==",
"requires": {
"@mapbox/geojson-rewind": "^0.4.0",
"@mapbox/geojson-types": "^1.0.2",
@@ -7107,11 +7112,6 @@
"vt-pbf": "^3.1.1"
},
"dependencies": {
- "earcut": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.1.5.tgz",
- "integrity": "sha512-QFWC7ywTVLtvRAJTVp8ugsuuGQ5mVqNmJ1cRYeLrSHgP3nycr2RHTJob9OtM0v8ujuoKN0NY1a93J/omeTL1PA=="
- },
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
diff --git a/package.json b/package.json
index ec787360bcb..945ae710e3e 100644
--- a/package.json
+++ b/package.json
@@ -91,7 +91,7 @@
"glslify": "^7.0.0",
"has-hover": "^1.0.1",
"has-passive-events": "^1.0.0",
- "mapbox-gl": "1.1.0",
+ "mapbox-gl": "^1.1.1",
"matrix-camera-controller": "^2.1.3",
"mouse-change": "^1.4.0",
"mouse-event-offset": "^3.0.2",
diff --git a/src/plots/mapbox/constants.js b/src/plots/mapbox/constants.js
index 858856223cd..37f0dc8f3c8 100644
--- a/src/plots/mapbox/constants.js
+++ b/src/plots/mapbox/constants.js
@@ -8,149 +8,152 @@
'use strict';
-var requiredVersion = '1.1.0';
-
-module.exports = {
- requiredVersion: requiredVersion,
-
- styleUrlPrefix: 'mapbox://styles/mapbox/',
- styleUrlSuffix: 'v9',
-
- styleValuesMapbox: ['basic', 'streets', 'outdoors', 'light', 'dark', 'satellite', 'satellite-streets'],
- styleValueOSM: 'open-street-map',
- styleValueDflt: 'basic',
-
- styles: {
- 'open-street-map': {
- id: 'osm',
- version: 8,
- sources: {
- 'plotly-osm-tiles': {
- type: 'raster',
- attribution: '© OpenStreetMap',
- tiles: [
- 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png',
- 'https://b.tile.openstreetmap.org/{z}/{x}/{y}.png'
- ],
- tileSize: 256
- }
- },
- layers: [{
- id: 'plotly-osm-tiles',
+var requiredVersion = '1.1.1';
+
+var stylesNonMapbox = {
+ 'open-street-map': {
+ id: 'osm',
+ version: 8,
+ sources: {
+ 'plotly-osm-tiles': {
type: 'raster',
- source: 'plotly-osm-tiles',
- minzoom: 0,
- maxzoom: 22
- }]
+ attribution: '© OpenStreetMap',
+ tiles: [
+ 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png',
+ 'https://b.tile.openstreetmap.org/{z}/{x}/{y}.png'
+ ],
+ tileSize: 256
+ }
},
- 'white-bg': {
+ layers: [{
+ id: 'plotly-osm-tiles',
+ type: 'raster',
+ source: 'plotly-osm-tiles',
+ minzoom: 0,
+ maxzoom: 22
+ }]
+ },
+ 'white-bg': {
+ id: 'white-bg',
+ version: 8,
+ sources: {},
+ layers: [{
id: 'white-bg',
- version: 8,
- sources: {},
- layers: [{
- id: 'white-bg',
- type: 'background',
- paint: {'background-color': '#FFFFFF'},
- minzoom: 0,
- maxzoom: 22
- }]
- },
- 'carto-positron': {
- id: 'carto-positron',
- version: 8,
- sources: {
- 'plotly-carto-positron': {
- type: 'raster',
- attribution: '© CARTO',
- tiles: ['https://cartodb-basemaps-c.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png'],
- tileSize: 256
- }
- },
- layers: [{
- id: 'plotly-carto-positron',
+ type: 'background',
+ paint: {'background-color': '#FFFFFF'},
+ minzoom: 0,
+ maxzoom: 22
+ }]
+ },
+ 'carto-positron': {
+ id: 'carto-positron',
+ version: 8,
+ sources: {
+ 'plotly-carto-positron': {
type: 'raster',
- source: 'plotly-carto-positron',
- minzoom: 0,
- maxzoom: 22
- }]
+ attribution: '© CARTO',
+ tiles: ['https://cartodb-basemaps-c.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png'],
+ tileSize: 256
+ }
},
- 'carto-darkmatter': {
- id: 'carto-darkmatter',
- version: 8,
- sources: {
- 'plotly-carto-darkmatter': {
- type: 'raster',
- attribution: '© CARTO',
- tiles: ['https://cartodb-basemaps-c.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png'],
- tileSize: 256
- }
- },
- layers: [{
- id: 'plotly-carto-darkmatter',
+ layers: [{
+ id: 'plotly-carto-positron',
+ type: 'raster',
+ source: 'plotly-carto-positron',
+ minzoom: 0,
+ maxzoom: 22
+ }]
+ },
+ 'carto-darkmatter': {
+ id: 'carto-darkmatter',
+ version: 8,
+ sources: {
+ 'plotly-carto-darkmatter': {
type: 'raster',
- source: 'plotly-carto-darkmatter',
- minzoom: 0,
- maxzoom: 22
- }]
+ attribution: '© CARTO',
+ tiles: ['https://cartodb-basemaps-c.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png'],
+ tileSize: 256
+ }
},
- 'stamen-terrain': {
- id: 'stamen-terrain',
- version: 8,
- sources: {
- 'plotly-stamen-terrain': {
- type: 'raster',
- attribution: 'Map tiles by Stamen Design, under CC BY 3.0 | Data by OpenStreetMap, under ODbL.',
- tiles: ['https://stamen-tiles.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png'],
- tileSize: 256
- }
- },
- layers: [{
- id: 'plotly-stamen-terrain',
+ layers: [{
+ id: 'plotly-carto-darkmatter',
+ type: 'raster',
+ source: 'plotly-carto-darkmatter',
+ minzoom: 0,
+ maxzoom: 22
+ }]
+ },
+ 'stamen-terrain': {
+ id: 'stamen-terrain',
+ version: 8,
+ sources: {
+ 'plotly-stamen-terrain': {
type: 'raster',
- source: 'plotly-stamen-terrain',
- minzoom: 0,
- maxzoom: 22
- }]
+ attribution: 'Map tiles by Stamen Design, under CC BY 3.0 | Data by OpenStreetMap, under ODbL.',
+ tiles: ['https://stamen-tiles.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png'],
+ tileSize: 256
+ }
},
- 'stamen-toner': {
- id: 'stamen-toner',
- version: 8,
- sources: {
- 'plotly-stamen-toner': {
- type: 'raster',
- attribution: 'Map tiles by Stamen Design, under CC BY 3.0 | Data by OpenStreetMap, under ODbL.',
- tiles: ['https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png'],
- tileSize: 256
- }
- },
- layers: [{
- id: 'plotly-stamen-toner',
+ layers: [{
+ id: 'plotly-stamen-terrain',
+ type: 'raster',
+ source: 'plotly-stamen-terrain',
+ minzoom: 0,
+ maxzoom: 22
+ }]
+ },
+ 'stamen-toner': {
+ id: 'stamen-toner',
+ version: 8,
+ sources: {
+ 'plotly-stamen-toner': {
type: 'raster',
- source: 'plotly-stamen-toner',
- minzoom: 0,
- maxzoom: 22
- }]
+ attribution: 'Map tiles by Stamen Design, under CC BY 3.0 | Data by OpenStreetMap, under ODbL.',
+ tiles: ['https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png'],
+ tileSize: 256
+ }
},
- 'stamen-watercolor': {
- id: 'stamen-watercolor',
- version: 8,
- sources: {
- 'plotly-stamen-watercolor': {
- type: 'raster',
- attribution: 'Map tiles by Stamen Design, under CC BY 3.0 | Data by OpenStreetMap, under CC BY SA.',
- tiles: ['https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png'],
- tileSize: 256
- }
- },
- layers: [{
- id: 'plotly-stamen-watercolor',
- type: 'raster',
- source: 'plotly-stamen-watercolor',
- minzoom: 0,
- maxzoom: 22
- }]
- }
+ layers: [{
+ id: 'plotly-stamen-toner',
+ type: 'raster',
+ source: 'plotly-stamen-toner',
+ minzoom: 0,
+ maxzoom: 22
+ }]
},
+ 'stamen-watercolor': {
+ id: 'stamen-watercolor',
+ version: 8,
+ sources: {
+ 'plotly-stamen-watercolor': {
+ type: 'raster',
+ attribution: 'Map tiles by Stamen Design, under CC BY 3.0 | Data by OpenStreetMap, under CC BY SA.',
+ tiles: ['https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png'],
+ tileSize: 256
+ }
+ },
+ layers: [{
+ id: 'plotly-stamen-watercolor',
+ type: 'raster',
+ source: 'plotly-stamen-watercolor',
+ minzoom: 0,
+ maxzoom: 22
+ }]
+ }
+};
+
+var styleValuesNonMapbox = Object.keys(stylesNonMapbox);
+
+module.exports = {
+ requiredVersion: requiredVersion,
+
+ styleUrlPrefix: 'mapbox://styles/mapbox/',
+ styleUrlSuffix: 'v9',
+
+ styleValuesMapbox: ['basic', 'streets', 'outdoors', 'light', 'dark', 'satellite', 'satellite-streets'],
+ styleValueDflt: 'basic',
+ stylesNonMapbox: stylesNonMapbox,
+ styleValuesNonMapbox: styleValuesNonMapbox,
traceLayerPrefix: 'plotly-trace-layer-',
layoutLayerPrefix: 'plotly-layout-layer-',
@@ -168,6 +171,12 @@ module.exports = {
'More info here: https://www.mapbox.com/help/define-access-token/'
].join('\n'),
+ missingStyleErrorMsg: [
+ 'No valid mapbox style found, please set `mapbox.style` to one of:',
+ styleValuesNonMapbox.join(', '),
+ 'or register a Mapbox access token to use a Mapbox-served style.'
+ ].join('\n'),
+
multipleTokensErrorMsg: [
'Set multiple mapbox access token across different mapbox subplot,',
'using first token found as mapbox-gl does not allow multiple' +
diff --git a/src/plots/mapbox/index.js b/src/plots/mapbox/index.js
index 98643e4186f..8563582efbf 100644
--- a/src/plots/mapbox/index.js
+++ b/src/plots/mapbox/index.js
@@ -220,20 +220,23 @@ function findAccessToken(gd, mapboxIds) {
var tokensUseful = [];
var tokensListed = [];
+ var hasOneSetMapboxStyle = false;
var wontWork = false;
// Take the first token we find in a mapbox subplot.
// These default to the context value but may be overridden.
for(var i = 0; i < mapboxIds.length; i++) {
var opts = fullLayout[mapboxIds[i]];
- var style = opts.style;
var token = opts.accesstoken;
- if(typeof style === 'string' && constants.styleValuesMapbox.indexOf(style) !== -1) {
+ if(isMapboxStyle(opts.style)) {
if(token) {
Lib.pushUnique(tokensUseful, token);
} else {
- Lib.error('Uses Mapbox map style, but did not set an access token.');
+ if(isMapboxStyle(opts._input.style)) {
+ Lib.error('Uses Mapbox map style, but did not set an access token.');
+ hasOneSetMapboxStyle = true;
+ }
wontWork = true;
}
}
@@ -244,7 +247,10 @@ function findAccessToken(gd, mapboxIds) {
}
if(wontWork) {
- throw new Error(constants.noAccessTokenErrorMsg);
+ var msg = hasOneSetMapboxStyle ?
+ constants.noAccessTokenErrorMsg :
+ constants.missingStyleErrorMsg;
+ throw new Error(msg);
}
if(tokensUseful.length) {
@@ -263,6 +269,10 @@ function findAccessToken(gd, mapboxIds) {
}
}
+function isMapboxStyle(s) {
+ return typeof s === 'string' && constants.styleValuesMapbox.indexOf(s) !== -1;
+}
+
exports.updateFx = function(gd) {
var fullLayout = gd._fullLayout;
var subplotIds = fullLayout._subplots[MAPBOX];
diff --git a/src/plots/mapbox/layout_attributes.js b/src/plots/mapbox/layout_attributes.js
index 98afe21c7d3..7cdec7305eb 100644
--- a/src/plots/mapbox/layout_attributes.js
+++ b/src/plots/mapbox/layout_attributes.js
@@ -39,19 +39,38 @@ var attrs = module.exports = overrideAll({
description: [
'Sets the mapbox access token to be used for this mapbox map.',
'Alternatively, the mapbox access token can be set in the',
- 'configuration options under `mapboxAccessToken`.'
+ 'configuration options under `mapboxAccessToken`.',
+ 'Note that accessToken are only required when `style`',
+ '(e.g with values :', constants.styleValuesMapbox.join(', '), ')',
+ 'and/or a layout layer references the Mapbox server.'
].join(' ')
},
style: {
valType: 'any',
- values: constants.styleValuesMapbox.concat(constants.styleValueOSM),
+ values: constants.styleValuesMapbox.concat(Object.keys(constants.styleValuesNonMapbox)),
dflt: constants.styleValueDflt,
role: 'style',
description: [
- 'Sets the Mapbox map style.',
- 'Either input one of the default Mapbox style names or the URL to a custom style',
- 'or a valid Mapbox style JSON.',
- 'From OpenStreetMap raster tiles, use *open-street-map*.'
+ 'Defines the map layers that are rendered by default below the trace layers defined in `data`,',
+ 'which are themselves by default rendered below the layers defined in `layout.mapbox.layers`.',
+ '',
+ 'These layers can be defined either explicitly as a Mapbox Style object which can contain multiple',
+ 'layer definitions that load data from any public or private Tile Map Service (TMS or XYZ) or Web Map Service (WMS)',
+ 'or implicitly by using one of the built-in style objects which use WMSes which do not require any',
+ 'access tokens, or by using a default Mapbox style or custom Mapbox style URL, both of',
+ 'which require a Mapbox access token',
+ '',
+ 'Note that Mapbox access token can be set in the `accesstoken` attribute',
+ 'or in the `mapboxAccessToken` config option.',
+ '',
+ 'Mapbox Style objects are of the form described in the Mapbox GL JS documentation available at',
+ 'https://docs.mapbox.com/mapbox-gl-js/style-spec',
+ '',
+ 'The built-in plotly.js styles objects are:', constants.styleValuesNonMapbox.join(', '),
+ '',
+ 'The built-in Mapbox styles are:', constants.styleValuesMapbox.join(', '),
+ '',
+ 'Mapbox style URLs are of the form: mapbox://mapbox.mapbox--'
].join(' ')
},
@@ -106,7 +125,8 @@ var attrs = module.exports = overrideAll({
dflt: 'geojson',
role: 'info',
description: [
- 'Sets the source type for this layer.'
+ 'Sets the source type for this layer,',
+ 'that is the type of the layer data.'
].join(' ')
},
@@ -115,9 +135,11 @@ var attrs = module.exports = overrideAll({
role: 'info',
description: [
'Sets the source data for this layer (mapbox.layer.source).',
- 'Source can be either a URL,',
- 'a geojson object (with `sourcetype` set to *geojson*)',
- 'or an array of tile URLS (with `sourcetype` set to *vector*).'
+ 'When `sourcetype` is set to *geojson*, `source` can be a URL to a GeoJSON',
+ 'or a GeoJSON object.',
+ 'When `sourcetype` is set to *vector* or *raster*, `source` can be a URL or',
+ 'an array of tile URLs.',
+ 'When `sourcetype` is set to *image*, `source` can be a URL to an image.'
].join(' ')
},
@@ -145,10 +167,15 @@ var attrs = module.exports = overrideAll({
dflt: 'circle',
role: 'info',
description: [
- 'Sets the layer type (mapbox.layer.type).',
- 'Support for *raster*, *background* types is coming soon.',
- 'Note that *line* and *fill* are not compatible with Point',
- 'GeoJSON geometries.'
+ 'Sets the layer type,',
+ 'that is the how the layer data set in `source` will be rendered',
+ 'With `sourcetype` set to *geojson*, the following values are allowed:',
+ '*circle*, *line*, *fill* and *symbol*.',
+ 'but note that *line* and *fill* are not compatible with Point',
+ 'GeoJSON geometries.',
+ 'With `sourcetype` set to *vector*, the following values are allowed:',
+ ' *circle*, *line*, *fill* and *symbol*.',
+ 'With `sourcetype` set to *raster* or `*image*`, only the *raster* value is allowed.'
].join(' ')
},
diff --git a/src/plots/mapbox/mapbox.js b/src/plots/mapbox/mapbox.js
index 8fdc2d55b7d..86e678ca228 100644
--- a/src/plots/mapbox/mapbox.js
+++ b/src/plots/mapbox/mapbox.js
@@ -769,8 +769,8 @@ function getStyleObj(val) {
if(constants.styleValuesMapbox.indexOf(val) !== -1) {
styleObj.style = convertStyleVal(val);
- } else if(constants.styles[val]) {
- styleObj.style = constants.styles[val];
+ } else if(constants.stylesNonMapbox[val]) {
+ styleObj.style = constants.stylesNonMapbox[val];
} else {
styleObj.style = val;
}
diff --git a/test/jasmine/tests/mapbox_test.js b/test/jasmine/tests/mapbox_test.js
index fac5e2ef259..9916cb177b6 100644
--- a/test/jasmine/tests/mapbox_test.js
+++ b/test/jasmine/tests/mapbox_test.js
@@ -283,7 +283,7 @@ describe('mapbox credentials', function() {
});
});
- it('@gl should throw error if token is not registered', function() {
+ it('@gl should throw error when no non-mapbox style is set and missing a mapbox access token token', function() {
spyOn(Lib, 'error');
expect(function() {
@@ -292,6 +292,22 @@ describe('mapbox credentials', function() {
lon: [10, 20, 30],
lat: [10, 20, 30]
}]);
+ }).toThrow(new Error(constants.missingStyleErrorMsg));
+
+ expect(Lib.error).toHaveBeenCalledTimes(0);
+ }, LONG_TIMEOUT_INTERVAL);
+
+ it('@gl should throw error when setting a Mapbox style w/o a registered token', function() {
+ spyOn(Lib, 'error');
+
+ expect(function() {
+ Plotly.plot(gd, [{
+ type: 'scattermapbox',
+ lon: [10, 20, 30],
+ lat: [10, 20, 30]
+ }], {
+ mapbox: {style: 'basic'}
+ });
}).toThrow(new Error(constants.noAccessTokenErrorMsg));
expect(Lib.error).toHaveBeenCalledWith('Uses Mapbox map style, but did not set an access token.');