Skip to content

Commit 8443d63

Browse files
committed
make scattermapbox first render faster
- by setting up paint and layout props during the 1st addLayer call and by setting up the source during the 1st addSource call, as opposed to having an blank 'init' and a generic 'update' step.
1 parent 278adec commit 8443d63

File tree

2 files changed

+68
-110
lines changed

2 files changed

+68
-110
lines changed

src/plots/mapbox/mapbox.js

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -458,38 +458,11 @@ proto.toImage = function() {
458458
return this.map.getCanvas().toDataURL();
459459
};
460460

461-
// convenience wrapper to create blank GeoJSON sources
462-
// and avoid 'invalid GeoJSON' errors
463-
proto.initSource = function(idSource) {
464-
var blank = {
465-
type: 'geojson',
466-
data: {
467-
type: 'Feature',
468-
geometry: {
469-
type: 'Point',
470-
coordinates: []
471-
}
472-
}
473-
};
474-
475-
return this.map.addSource(idSource, blank);
476-
};
477-
478-
// convenience wrapper to set data of GeoJSON sources
479-
proto.setSourceData = function(idSource, data) {
480-
this.map.getSource(idSource).setData(data);
481-
};
482-
483461
// convenience wrapper to create set multiple layer
484462
// 'layout' or 'paint options at once.
485463
proto.setOptions = function(id, methodName, opts) {
486-
var map = this.map,
487-
keys = Object.keys(opts);
488-
489-
for(var i = 0; i < keys.length; i++) {
490-
var key = keys[i];
491-
492-
map[methodName](id, key, opts[key]);
464+
for(var k in opts) {
465+
this.map[methodName](id, k, opts[k]);
493466
}
494467
};
495468

src/traces/scattermapbox/plot.js

Lines changed: 66 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -6,56 +6,29 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
109
'use strict';
1110

1211
var convert = require('./convert');
1312

14-
15-
function ScatterMapbox(mapbox, uid) {
16-
this.mapbox = mapbox;
17-
this.map = mapbox.map;
18-
13+
function ScatterMapbox(subplot, uid) {
14+
this.subplot = subplot;
1915
this.uid = uid;
2016

21-
this.idSourceFill = uid + '-source-fill';
22-
this.idSourceLine = uid + '-source-line';
23-
this.idSourceCircle = uid + '-source-circle';
24-
this.idSourceSymbol = uid + '-source-symbol';
25-
26-
this.idLayerFill = uid + '-layer-fill';
27-
this.idLayerLine = uid + '-layer-line';
28-
this.idLayerCircle = uid + '-layer-circle';
29-
this.idLayerSymbol = uid + '-layer-symbol';
30-
31-
this.mapbox.initSource(this.idSourceFill);
32-
this.mapbox.initSource(this.idSourceLine);
33-
this.mapbox.initSource(this.idSourceCircle);
34-
this.mapbox.initSource(this.idSourceSymbol);
35-
36-
this.map.addLayer({
37-
id: this.idLayerFill,
38-
source: this.idSourceFill,
39-
type: 'fill'
40-
});
17+
this.sourceIds = {
18+
fill: uid + '-source-fill',
19+
line: uid + '-source-line',
20+
circle: uid + '-source-circle',
21+
symbol: uid + '-source-symbol'
22+
};
4123

42-
this.map.addLayer({
43-
id: this.idLayerLine,
44-
source: this.idSourceLine,
45-
type: 'line'
46-
});
47-
48-
this.map.addLayer({
49-
id: this.idLayerCircle,
50-
source: this.idSourceCircle,
51-
type: 'circle'
52-
});
24+
this.layerIds = {
25+
fill: uid + '-layer-fill',
26+
line: uid + '-layer-line',
27+
circle: uid + '-layer-circle',
28+
symbol: uid + '-layer-symbol'
29+
};
5330

54-
this.map.addLayer({
55-
id: this.idLayerSymbol,
56-
source: this.idSourceSymbol,
57-
type: 'symbol'
58-
});
31+
this.order = ['fill', 'line', 'circle', 'symbol'];
5932

6033
// We could merge the 'fill' source with the 'line' source and
6134
// the 'circle' source with the 'symbol' source if ever having
@@ -64,62 +37,74 @@ function ScatterMapbox(mapbox, uid) {
6437

6538
var proto = ScatterMapbox.prototype;
6639

67-
proto.update = function update(calcTrace) {
68-
var mapbox = this.mapbox;
69-
var opts = convert(calcTrace);
40+
proto.addSource = function(k, opts) {
41+
this.subplot.map.addSource(this.sourceIds[k], {
42+
type: 'geojson',
43+
data: opts.geojson
44+
});
45+
};
7046

71-
mapbox.setOptions(this.idLayerFill, 'setLayoutProperty', opts.fill.layout);
72-
mapbox.setOptions(this.idLayerLine, 'setLayoutProperty', opts.line.layout);
73-
mapbox.setOptions(this.idLayerCircle, 'setLayoutProperty', opts.circle.layout);
74-
mapbox.setOptions(this.idLayerSymbol, 'setLayoutProperty', opts.symbol.layout);
47+
proto.setSourceData = function(k, opts) {
48+
this.subplot.map
49+
.getSource(this.sourceIds[k])
50+
.setData(opts.geojson);
51+
};
7552

76-
if(isVisible(opts.fill)) {
77-
mapbox.setSourceData(this.idSourceFill, opts.fill.geojson);
78-
mapbox.setOptions(this.idLayerFill, 'setPaintProperty', opts.fill.paint);
79-
}
53+
proto.addLayer = function(k, opts) {
54+
this.subplot.map.addLayer({
55+
type: k,
56+
id: this.layerIds[k],
57+
source: this.sourceIds[k],
58+
layout: opts.layout,
59+
paint: opts.paint
60+
});
61+
};
8062

81-
if(isVisible(opts.line)) {
82-
mapbox.setSourceData(this.idSourceLine, opts.line.geojson);
83-
mapbox.setOptions(this.idLayerLine, 'setPaintProperty', opts.line.paint);
84-
}
63+
proto.update = function update(calcTrace) {
64+
var subplot = this.subplot;
65+
var optsAll = convert(calcTrace);
8566

86-
if(isVisible(opts.circle)) {
87-
mapbox.setSourceData(this.idSourceCircle, opts.circle.geojson);
88-
mapbox.setOptions(this.idLayerCircle, 'setPaintProperty', opts.circle.paint);
89-
}
67+
for(var i = 0; i < this.order.length; i++) {
68+
var k = this.order[i];
69+
var opts = optsAll[k];
9070

91-
if(isVisible(opts.symbol)) {
92-
mapbox.setSourceData(this.idSourceSymbol, opts.symbol.geojson);
93-
mapbox.setOptions(this.idLayerSymbol, 'setPaintProperty', opts.symbol.paint);
71+
subplot.setOptions(this.layerIds[k], 'setLayoutProperty', opts.layout);
72+
73+
if(opts.layout.visibility === 'visible') {
74+
this.setSourceData(k, opts);
75+
subplot.setOptions(this.layerIds[k], 'setPaintProperty', opts.paint);
76+
}
9477
}
9578

9679
// link ref for quick update during selections
9780
calcTrace[0].trace._glTrace = this;
9881
};
9982

10083
proto.dispose = function dispose() {
101-
var map = this.map;
102-
103-
map.removeLayer(this.idLayerFill);
104-
map.removeLayer(this.idLayerLine);
105-
map.removeLayer(this.idLayerCircle);
106-
map.removeLayer(this.idLayerSymbol);
84+
var map = this.subplot.map;
10785

108-
map.removeSource(this.idSourceFill);
109-
map.removeSource(this.idSourceLine);
110-
map.removeSource(this.idSourceCircle);
111-
map.removeSource(this.idSourceSymbol);
86+
for(var i = 0; i < this.order.length; i++) {
87+
var k = this.order[i];
88+
map.removeLayer(this.layerIds[k]);
89+
map.removeSource(this.sourceIds[k]);
90+
}
11291
};
11392

114-
function isVisible(layerOpts) {
115-
return layerOpts.layout.visibility === 'visible';
116-
}
117-
118-
module.exports = function createScatterMapbox(mapbox, calcTrace) {
93+
module.exports = function createScatterMapbox(subplot, calcTrace) {
11994
var trace = calcTrace[0].trace;
95+
var scatterMapbox = new ScatterMapbox(subplot, trace.uid);
96+
var optsAll = convert(calcTrace);
97+
98+
for(var i = 0; i < scatterMapbox.order.length; i++) {
99+
var k = scatterMapbox.order[i];
100+
var opts = optsAll[k];
120101

121-
var scatterMapbox = new ScatterMapbox(mapbox, trace.uid);
122-
scatterMapbox.update(calcTrace);
102+
scatterMapbox.addSource(k, opts);
103+
scatterMapbox.addLayer(k, opts);
104+
}
105+
106+
// link ref for quick update during selections
107+
calcTrace[0].trace._glTrace = scatterMapbox;
123108

124109
return scatterMapbox;
125110
};

0 commit comments

Comments
 (0)