Skip to content

Commit 4b8a05b

Browse files
committed
fix uirevision behavior on mapbox subplots
... and remove `self.opts` use `self.gd._fullLayout[self.id]` instead, which always points to the correct container even on redraw-less updates
1 parent 8151197 commit 4b8a05b

File tree

2 files changed

+111
-37
lines changed

2 files changed

+111
-37
lines changed

src/plots/mapbox/mapbox.js

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@ function Mapbox(opts) {
3232
// unique id for this Mapbox instance
3333
this.uid = fullLayout._uid + '-' + this.id;
3434

35-
// full mapbox options (N.B. needs to be updated on every updates)
36-
this.opts = fullLayout[this.id];
37-
3835
// create framework on instantiation for a smoother first plot call
3936
this.div = null;
4037
this.xaxis = null;
@@ -57,9 +54,7 @@ module.exports = function createMapbox(opts) {
5754

5855
proto.plot = function(calcData, fullLayout, promises) {
5956
var self = this;
60-
61-
// feed in new mapbox options
62-
var opts = self.opts = fullLayout[this.id];
57+
var opts = fullLayout[self.id];
6358

6459
// remove map and create a new map if access token has change
6560
if(self.map && (opts.accesstoken !== self.accessToken)) {
@@ -88,7 +83,7 @@ proto.plot = function(calcData, fullLayout, promises) {
8883
proto.createMap = function(calcData, fullLayout, resolve, reject) {
8984
var self = this;
9085
var gd = self.gd;
91-
var opts = self.opts;
86+
var opts = fullLayout[self.id];
9287

9388
// store style id and URL or object
9489
var styleObj = self.styleObj = getStyleObj(opts.style);
@@ -147,14 +142,16 @@ proto.createMap = function(calcData, fullLayout, resolve, reject) {
147142
// duplicate 'plotly_relayout' events.
148143

149144
if(eventData.originalEvent || wheeling) {
150-
var view = self.getView();
145+
var optsNow = gd._fullLayout[self.id];
146+
Registry.call('_storeDirectGUIEdit', gd.layout, gd._fullLayout._preGUI, self.getViewEdits(optsNow));
151147

152-
opts._input.center = opts.center = view.center;
153-
opts._input.zoom = opts.zoom = view.zoom;
154-
opts._input.bearing = opts.bearing = view.bearing;
155-
opts._input.pitch = opts.pitch = view.pitch;
148+
var viewNow = self.getView();
149+
optsNow._input.center = optsNow.center = viewNow.center;
150+
optsNow._input.zoom = optsNow.zoom = viewNow.zoom;
151+
optsNow._input.bearing = optsNow.bearing = viewNow.bearing;
152+
optsNow._input.pitch = optsNow.pitch = viewNow.pitch;
156153

157-
emitRelayoutFromView(view);
154+
gd.emit('plotly_relayout', self.getViewEdits(viewNow));
158155
}
159156
wheeling = false;
160157
});
@@ -186,35 +183,25 @@ proto.createMap = function(calcData, fullLayout, resolve, reject) {
186183
map.on('zoomstart', unhover);
187184

188185
map.on('dblclick', function() {
189-
gd.emit('plotly_doubleclick', null);
186+
var optsNow = gd._fullLayout[self.id];
187+
Registry.call('_storeDirectGUIEdit', gd.layout, gd._fullLayout._preGUI, self.getViewEdits(optsNow));
190188

191189
var viewInitial = self.viewInitial;
192-
193190
map.setCenter(convertCenter(viewInitial.center));
194191
map.setZoom(viewInitial.zoom);
195192
map.setBearing(viewInitial.bearing);
196193
map.setPitch(viewInitial.pitch);
197194

198195
var viewNow = self.getView();
196+
optsNow._input.center = optsNow.center = viewNow.center;
197+
optsNow._input.zoom = optsNow.zoom = viewNow.zoom;
198+
optsNow._input.bearing = optsNow.bearing = viewNow.bearing;
199+
optsNow._input.pitch = optsNow.pitch = viewNow.pitch;
199200

200-
opts._input.center = opts.center = viewNow.center;
201-
opts._input.zoom = opts.zoom = viewNow.zoom;
202-
opts._input.bearing = opts.bearing = viewNow.bearing;
203-
opts._input.pitch = opts.pitch = viewNow.pitch;
204-
205-
emitRelayoutFromView(viewNow);
201+
gd.emit('plotly_doubleclick', null);
202+
gd.emit('plotly_relayout', self.getViewEdits(viewNow));
206203
});
207204

208-
function emitRelayoutFromView(view) {
209-
var id = self.id;
210-
var evtData = {};
211-
for(var k in view) {
212-
evtData[id + '.' + k] = view[k];
213-
}
214-
Registry.call('_storeDirectGUIEdit', gd.layout, gd._fullLayout._preGUI, evtData);
215-
gd.emit('plotly_relayout', evtData);
216-
}
217-
218205
// define event handlers on map creation, to keep one ref per map,
219206
// so that map.on / map.off in updateFx works as expected
220207
self.clearSelect = function() {
@@ -248,10 +235,11 @@ proto.createMap = function(calcData, fullLayout, resolve, reject) {
248235
proto.updateMap = function(calcData, fullLayout, resolve, reject) {
249236
var self = this;
250237
var map = self.map;
238+
var opts = fullLayout[this.id];
251239

252240
self.rejectOnError(reject);
253241

254-
var styleObj = getStyleObj(self.opts.style);
242+
var styleObj = getStyleObj(opts.style);
255243

256244
if(self.styleObj.id !== styleObj.id) {
257245
self.styleObj = styleObj;
@@ -309,14 +297,14 @@ proto.updateData = function(calcData) {
309297

310298
proto.updateLayout = function(fullLayout) {
311299
var map = this.map;
312-
var opts = this.opts;
300+
var opts = fullLayout[this.id];
313301

314302
map.setCenter(convertCenter(opts.center));
315303
map.setZoom(opts.zoom);
316304
map.setBearing(opts.bearing);
317305
map.setPitch(opts.pitch);
318306

319-
this.updateLayers();
307+
this.updateLayers(fullLayout);
320308
this.updateFramework(fullLayout);
321309
this.updateFx(fullLayout);
322310
this.map.resize();
@@ -463,8 +451,8 @@ proto.updateFramework = function(fullLayout) {
463451
this.yaxis._length = size.h * (domain.y[1] - domain.y[0]);
464452
};
465453

466-
proto.updateLayers = function() {
467-
var opts = this.opts;
454+
proto.updateLayers = function(fullLayout) {
455+
var opts = fullLayout[this.id];
468456
var layers = opts.layers;
469457
var layerList = this.layerList;
470458
var i;
@@ -519,7 +507,6 @@ proto.project = function(v) {
519507
// get map's current view values in plotly.js notation
520508
proto.getView = function() {
521509
var map = this.map;
522-
523510
var mapCenter = map.getCenter();
524511
var center = { lon: mapCenter.lng, lat: mapCenter.lat };
525512

@@ -531,6 +518,19 @@ proto.getView = function() {
531518
};
532519
};
533520

521+
proto.getViewEdits = function(cont) {
522+
var id = this.id;
523+
var keys = ['center', 'zoom', 'bearing', 'pitch'];
524+
var obj = {};
525+
526+
for(var i = 0; i < keys.length; i++) {
527+
var k = keys[i];
528+
obj[id + '.' + k] = cont[k];
529+
}
530+
531+
return obj;
532+
};
533+
534534
function getStyleObj(val) {
535535
var styleValues = layoutAttributes.style.values;
536536
var styleDflt = layoutAttributes.style.dflt;

test/jasmine/tests/plot_api_react_test.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,4 +1930,78 @@ describe('Test Plotly.react + interactions under uirevision:', function() {
19301930
.catch(failTest)
19311931
.then(done);
19321932
});
1933+
1934+
it('@gl mapbox subplots should preserve viewport changes after panning', function(done) {
1935+
Plotly.setPlotConfig({
1936+
mapboxAccessToken: MAPBOX_ACCESS_TOKEN
1937+
});
1938+
1939+
function _react() {
1940+
return Plotly.react(gd, [{
1941+
type: 'scattermapbox',
1942+
lon: [3, 1, 2],
1943+
lat: [2, 3, 1]
1944+
}], {
1945+
width: 500,
1946+
height: 500,
1947+
uirevision: true
1948+
});
1949+
}
1950+
1951+
// see mapbox_test.js for rationale
1952+
function _mouseEvent(type, pos) {
1953+
return new Promise(function(resolve) {
1954+
mouseEvent(type, pos[0], pos[1]);
1955+
setTimeout(resolve, 100);
1956+
});
1957+
}
1958+
1959+
// see mapbox_test.js for rationale
1960+
function _drag(p0, p1) {
1961+
return _mouseEvent('mousemove', p0)
1962+
.then(function() { return _mouseEvent('mousedown', p0); })
1963+
.then(function() { return _mouseEvent('mousemove', p1); })
1964+
.then(function() { return _mouseEvent('mousemove', p1); })
1965+
.then(function() { return _mouseEvent('mouseup', p1); })
1966+
.then(function() { return _mouseEvent('mouseup', p1); });
1967+
}
1968+
1969+
// should be same before & after 2nd react()
1970+
function _assertGUI(msg) {
1971+
var TOL = 2;
1972+
1973+
var mapbox = gd.layout.mapbox || {};
1974+
expect((mapbox.center || {}).lon).toBeCloseTo(-17.578, TOL, msg);
1975+
expect((mapbox.center || {}).lat).toBeCloseTo(17.308, TOL, msg);
1976+
expect(mapbox.zoom).toBe(1);
1977+
1978+
var fullMapbox = gd._fullLayout.mapbox || {};
1979+
expect(fullMapbox.center.lon).toBeCloseTo(-17.578, TOL, msg);
1980+
expect(fullMapbox.center.lat).toBeCloseTo(17.308, TOL, msg);
1981+
expect(fullMapbox.zoom).toBe(1);
1982+
1983+
var preGUI = gd._fullLayout._preGUI;
1984+
expect(preGUI['mapbox.center.lon']).toBe(null, msg);
1985+
expect(preGUI['mapbox.center.lat']).toBe(null, msg);
1986+
expect(preGUI['mapbox.zoom']).toBe(null, msg);
1987+
}
1988+
1989+
_react()
1990+
.then(function() {
1991+
expect(gd.layout.mapbox).toEqual({});
1992+
1993+
var fullMapbox = gd._fullLayout.mapbox;
1994+
expect(fullMapbox.center.lon).toBe(0);
1995+
expect(fullMapbox.center.lat).toBe(0);
1996+
expect(fullMapbox.zoom).toBe(1);
1997+
1998+
expect(gd._fullLayout._preGUI).toEqual({});
1999+
})
2000+
.then(function() { return _drag([200, 200], [250, 250]); })
2001+
.then(function() { _assertGUI('before'); })
2002+
.then(_react)
2003+
.then(function() { _assertGUI('after'); })
2004+
.catch(failTest)
2005+
.then(done);
2006+
});
19332007
});

0 commit comments

Comments
 (0)