Skip to content

Commit fb52c8c

Browse files
authored
Merge pull request #729 from plotly/mapbox-access-token
Make mapbox access token configurable via layout attribute
2 parents cc9c0d3 + faf79b5 commit fb52c8c

File tree

6 files changed

+98
-14
lines changed

6 files changed

+98
-14
lines changed

src/plot_api/plot_api.js

+4
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,10 @@ Plotly.plot = function(gd, data, layout, config) {
326326
// so that the caller doesn't care which route we took
327327
return Promise.all(gd._promises).then(function() {
328328
return gd;
329+
}, function() {
330+
// clear the promise queue if one of them got rejected
331+
Lib.log('Clearing previous rejected promises from queue.');
332+
gd._promises = [];
329333
});
330334
};
331335

src/plots/mapbox/index.js

+32-9
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,21 @@ exports.layoutAttributes = require('./layout_attributes');
4747
exports.supplyLayoutDefaults = require('./layout_defaults');
4848

4949
exports.plot = function plotMapbox(gd) {
50-
51-
if(!gd._context.mapboxAccessToken) {
52-
throw new Error(constants.noAccessTokenErrorMsg);
53-
}
54-
else {
55-
mapboxgl.accessToken = gd._context.mapboxAccessToken;
56-
}
57-
5850
var fullLayout = gd._fullLayout,
5951
calcData = gd.calcdata,
6052
mapboxIds = Plots.getSubplotIds(fullLayout, 'mapbox');
6153

54+
var accessToken = findAccessToken(gd, mapboxIds);
55+
mapboxgl.accessToken = accessToken;
56+
6257
for(var i = 0; i < mapboxIds.length; i++) {
6358
var id = mapboxIds[i],
6459
subplotCalcData = getSubplotCalcData(calcData, id),
65-
mapbox = fullLayout[id]._subplot;
60+
opts = fullLayout[id],
61+
mapbox = opts._subplot;
62+
63+
// copy access token to fullLayout (to handle the context case)
64+
opts.accesstoken = accessToken;
6665

6766
if(!mapbox) {
6867
mapbox = createMapbox({
@@ -131,3 +130,27 @@ function getSubplotCalcData(calcData, id) {
131130

132131
return subplotCalcData;
133132
}
133+
134+
function findAccessToken(gd, mapboxIds) {
135+
var fullLayout = gd._fullLayout,
136+
context = gd._context;
137+
138+
// first look for access token in context
139+
var accessToken = context.mapboxAccessToken;
140+
141+
// allow mapbox layout options to override it
142+
for(var i = 0; i < mapboxIds.length; i++) {
143+
var opts = fullLayout[mapboxIds[i]];
144+
145+
if(opts.accesstoken) {
146+
accessToken = opts.accesstoken;
147+
break;
148+
}
149+
}
150+
151+
if(!accessToken) {
152+
throw new Error(constants.noAccessTokenErrorMsg);
153+
}
154+
155+
return accessToken;
156+
}

src/plots/mapbox/layout_attributes.js

+12
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ module.exports = {
4545
}
4646
},
4747

48+
accesstoken: {
49+
valType: 'string',
50+
noBlank: true,
51+
strict: true,
52+
role: 'info',
53+
description: [
54+
'Sets the mapbox access token to be used for this mapbox map.',
55+
'Alternatively, the mapbox access token can be set in the',
56+
'configuration options under `mapboxAccessToken`.'
57+
].join(' ')
58+
},
4859
style: {
4960
valType: 'string',
5061
values: ['basic', 'streets', 'outdoors', 'light', 'dark', 'satellite', 'satellite-streets'],
@@ -55,6 +66,7 @@ module.exports = {
5566
'Either input the defaults Mapbox names or the URL to a custom style.'
5667
].join(' ')
5768
},
69+
5870
center: {
5971
lon: {
6072
valType: 'number',

src/plots/mapbox/layout_defaults.js

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
2525
};
2626

2727
function handleDefaults(containerIn, containerOut, coerce) {
28+
coerce('accesstoken');
2829
coerce('style');
2930
coerce('center.lon');
3031
coerce('center.lat');

src/plots/mapbox/mapbox.js

+15-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ function Mapbox(opts) {
4040

4141
// state variables used to infer how and what to update
4242
this.map = null;
43+
this.accessToken = null;
4344
this.styleUrl = null;
4445
this.traceHash = {};
4546
this.layerList = [];
@@ -57,7 +58,16 @@ proto.plot = function(calcData, fullLayout, promises) {
5758
var self = this;
5859

5960
// feed in new mapbox options
60-
self.opts = fullLayout[this.id];
61+
var opts = self.opts = fullLayout[this.id];
62+
63+
// remove map and create a new map if access token has change
64+
if(self.map && (opts.accesstoken !== self.accessToken)) {
65+
self.map.remove();
66+
self.map = null;
67+
self.styleUrl = null;
68+
self.traceHash = [];
69+
self.layerList = {};
70+
}
6171

6272
var promise;
6373

@@ -83,6 +93,9 @@ proto.createMap = function(calcData, fullLayout, resolve, reject) {
8393
// mapbox doesn't have a way to get the current style URL; do it ourselves
8494
var styleUrl = self.styleUrl = convertStyleUrl(opts.style);
8595

96+
// store access token associated with this map
97+
self.accessToken = opts.accesstoken;
98+
8699
var map = self.map = new mapboxgl.Map({
87100
container: self.div,
88101

@@ -334,7 +347,7 @@ proto.updateLayers = function() {
334347
};
335348

336349
proto.destroy = function() {
337-
this.map.remove();
350+
if(this.map) this.map.remove();
338351
this.container.removeChild(this.div);
339352
};
340353

test/jasmine/tests/mapbox_test.js

+34-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var customMatchers = require('../assets/custom_matchers');
1313

1414
var MAPBOX_ACCESS_TOKEN = require('@build/credentials.json').MAPBOX_ACCESS_TOKEN;
1515
var TRANSITION_DELAY = 500;
16+
var MOUSE_DELAY = 100;
1617

1718
var noop = function() {};
1819

@@ -187,6 +188,22 @@ describe('mapbox credentials', function() {
187188
mapboxAccessToken: dummyToken
188189
}).catch(function(err) {
189190
expect(err).toEqual(new Error(constants.mapOnErrorMsg));
191+
}).then(done);
192+
});
193+
194+
it('should use access token in mapbox layout options if present', function(done) {
195+
Plotly.plot(gd, [{
196+
type: 'scattermapbox',
197+
lon: [10, 20, 30],
198+
lat: [10, 20, 30]
199+
}], {
200+
mapbox: {
201+
accesstoken: MAPBOX_ACCESS_TOKEN
202+
}
203+
}, {
204+
mapboxAccessToken: dummyToken
205+
}).then(function() {
206+
expect(gd._fullLayout.mapbox.accesstoken).toEqual(MAPBOX_ACCESS_TOKEN);
190207
done();
191208
});
192209
});
@@ -475,6 +492,22 @@ describe('mapbox plots', function() {
475492
});
476493
});
477494

495+
it('should be able to update the access token', function(done) {
496+
var promise = Plotly.relayout(gd, 'mapbox.accesstoken', 'wont-work');
497+
498+
promise.catch(function(err) {
499+
expect(gd._fullLayout.mapbox.accesstoken).toEqual('wont-work');
500+
expect(err).toEqual(new Error(constants.mapOnErrorMsg));
501+
});
502+
503+
promise.then(function() {
504+
return Plotly.relayout(gd, 'mapbox.accesstoken', MAPBOX_ACCESS_TOKEN);
505+
}).then(function() {
506+
expect(gd._fullLayout.mapbox.accesstoken).toEqual(MAPBOX_ACCESS_TOKEN);
507+
}).then(done);
508+
});
509+
510+
478511
it('should be able to update traces', function(done) {
479512
function assertDataPts(lengths) {
480513
var lines = getGeoJsonData(gd, 'lines'),
@@ -763,15 +796,13 @@ describe('mapbox plots', function() {
763796
}
764797

765798
function _mouseEvent(type, pos, cb) {
766-
var DELAY = 100;
767-
768799
return new Promise(function(resolve) {
769800
mouseEvent(type, pos[0], pos[1]);
770801

771802
setTimeout(function() {
772803
cb();
773804
resolve();
774-
}, DELAY);
805+
}, MOUSE_DELAY);
775806
});
776807
}
777808

0 commit comments

Comments
 (0)