@@ -41,6 +41,7 @@ function Geo(opts) {
41
41
this . topojson = null ;
42
42
43
43
this . projection = null ;
44
+ this . viewInitial = null ;
44
45
this . fitScale = null ;
45
46
this . bounds = null ;
46
47
this . midPt = null ;
@@ -119,6 +120,9 @@ proto.fetchTopojson = function() {
119
120
proto . update = function ( geoCalcData , fullLayout ) {
120
121
var geoLayout = fullLayout [ this . id ] ;
121
122
123
+ var hasInvalidBounds = this . updateProjection ( fullLayout , geoLayout ) ;
124
+ if ( hasInvalidBounds ) return ;
125
+
122
126
// important: maps with choropleth traces have a different layer order
123
127
this . hasChoropleth = false ;
124
128
for ( var i = 0 ; i < geoCalcData . length ; i ++ ) {
@@ -128,9 +132,13 @@ proto.update = function(geoCalcData, fullLayout) {
128
132
}
129
133
}
130
134
131
- this . updateProjection ( fullLayout , geoLayout ) ;
135
+ if ( ! this . viewInitial ) {
136
+ this . saveViewInitial ( geoLayout ) ;
137
+ }
138
+
132
139
this . updateBaseLayers ( fullLayout , geoLayout ) ;
133
140
this . updateDims ( fullLayout , geoLayout ) ;
141
+ this . updateFx ( fullLayout , geoLayout ) ;
134
142
135
143
Plots . generalUpdatePerTraceModule ( this , geoCalcData , geoLayout ) ;
136
144
@@ -142,7 +150,6 @@ proto.update = function(geoCalcData, fullLayout) {
142
150
var choroplethLayer = this . layers . backplot . select ( '.choroplethlayer' ) ;
143
151
this . dataPaths . choropleth = choroplethLayer . selectAll ( 'path' ) ;
144
152
145
- this . updateFx ( fullLayout , geoLayout ) ;
146
153
this . render ( ) ;
147
154
} ;
148
155
@@ -186,9 +193,23 @@ proto.updateProjection = function(fullLayout, geoLayout) {
186
193
! isFinite ( b [ 1 ] [ 0 ] ) || ! isFinite ( b [ 1 ] [ 1 ] ) ||
187
194
isNaN ( t [ 0 ] ) || isNaN ( t [ 0 ] )
188
195
) {
189
- Lib . warn ( 'Invalid geo settings' ) ;
196
+ var gd = this . graphDiv ;
197
+ var attrToUnset = [ 'projection.rotation' , 'center' , 'lonaxis.range' , 'lataxis.range' ] ;
198
+ var msg = 'Invalid geo settings, relayout\'ing to default view.' ;
199
+ var updateObj = { } ;
190
200
191
- // TODO fallback to default ???
201
+ // clear all attribute that could cause invalid bounds,
202
+ // clear viewInitial to update reset-view behavior
203
+
204
+ for ( var i = 0 ; i < attrToUnset . length ; i ++ ) {
205
+ updateObj [ this . id + '.' + attrToUnset [ i ] ] = null ;
206
+ }
207
+
208
+ this . viewInitial = null ;
209
+
210
+ Lib . warn ( msg ) ;
211
+ gd . _promises . push ( Plotly . relayout ( gd , updateObj ) ) ;
212
+ return msg ;
192
213
}
193
214
194
215
// px coordinates of view mid-point,
@@ -472,26 +493,27 @@ proto.makeFramework = function() {
472
493
exponentformat : 'B'
473
494
} ;
474
495
Axes . setConvert ( _this . mockAxis , fullLayout ) ;
496
+ } ;
475
497
476
- var geoLayout = fullLayout [ _this . id ] ;
498
+ proto . saveViewInitial = function ( geoLayout ) {
477
499
var center = geoLayout . center || { } ;
478
500
var projLayout = geoLayout . projection ;
479
501
var rotation = projLayout . rotation || { } ;
480
502
481
503
if ( geoLayout . _isScoped ) {
482
- _this . viewInitial = {
504
+ this . viewInitial = {
483
505
'center.lon' : center . lon ,
484
506
'center.lat' : center . lat ,
485
507
'projection.scale' : projLayout . scale
486
508
} ;
487
509
} else if ( geoLayout . _isClipped ) {
488
- _this . viewInitial = {
510
+ this . viewInitial = {
489
511
'projection.scale' : projLayout . scale ,
490
512
'projection.rotation.lon' : rotation . lon ,
491
513
'projection.rotation.lat' : rotation . lat
492
514
} ;
493
515
} else {
494
- _this . viewInitial = {
516
+ this . viewInitial = {
495
517
'center.lon' : center . lon ,
496
518
'center.lat' : center . lat ,
497
519
'projection.scale' : projLayout . scale ,
@@ -574,7 +596,6 @@ function getProjection(geoLayout) {
574
596
var maxAngle = clipAngle * Math . PI / 180 ;
575
597
return angle > maxAngle ;
576
598
} else {
577
- // TODO does this ever happen??
578
599
return false ;
579
600
}
580
601
} ;
0 commit comments