@@ -41,6 +41,7 @@ function Geo(opts) {
4141 this . topojson = null ;
4242
4343 this . projection = null ;
44+ this . viewInitial = null ;
4445 this . fitScale = null ;
4546 this . bounds = null ;
4647 this . midPt = null ;
@@ -119,6 +120,9 @@ proto.fetchTopojson = function() {
119120proto . update = function ( geoCalcData , fullLayout ) {
120121 var geoLayout = fullLayout [ this . id ] ;
121122
123+ var hasInvalidBounds = this . updateProjection ( fullLayout , geoLayout ) ;
124+ if ( hasInvalidBounds ) return ;
125+
122126 // important: maps with choropleth traces have a different layer order
123127 this . hasChoropleth = false ;
124128 for ( var i = 0 ; i < geoCalcData . length ; i ++ ) {
@@ -128,9 +132,13 @@ proto.update = function(geoCalcData, fullLayout) {
128132 }
129133 }
130134
131- this . updateProjection ( fullLayout , geoLayout ) ;
135+ if ( ! this . viewInitial ) {
136+ this . saveViewInitial ( geoLayout ) ;
137+ }
138+
132139 this . updateBaseLayers ( fullLayout , geoLayout ) ;
133140 this . updateDims ( fullLayout , geoLayout ) ;
141+ this . updateFx ( fullLayout , geoLayout ) ;
134142
135143 Plots . generalUpdatePerTraceModule ( this , geoCalcData , geoLayout ) ;
136144
@@ -142,7 +150,6 @@ proto.update = function(geoCalcData, fullLayout) {
142150 var choroplethLayer = this . layers . backplot . select ( '.choroplethlayer' ) ;
143151 this . dataPaths . choropleth = choroplethLayer . selectAll ( 'path' ) ;
144152
145- this . updateFx ( fullLayout , geoLayout ) ;
146153 this . render ( ) ;
147154} ;
148155
@@ -186,9 +193,23 @@ proto.updateProjection = function(fullLayout, geoLayout) {
186193 ! isFinite ( b [ 1 ] [ 0 ] ) || ! isFinite ( b [ 1 ] [ 1 ] ) ||
187194 isNaN ( t [ 0 ] ) || isNaN ( t [ 0 ] )
188195 ) {
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 = { } ;
190200
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 ;
192213 }
193214
194215 // px coordinates of view mid-point,
@@ -472,26 +493,27 @@ proto.makeFramework = function() {
472493 exponentformat : 'B'
473494 } ;
474495 Axes . setConvert ( _this . mockAxis , fullLayout ) ;
496+ } ;
475497
476- var geoLayout = fullLayout [ _this . id ] ;
498+ proto . saveViewInitial = function ( geoLayout ) {
477499 var center = geoLayout . center || { } ;
478500 var projLayout = geoLayout . projection ;
479501 var rotation = projLayout . rotation || { } ;
480502
481503 if ( geoLayout . _isScoped ) {
482- _this . viewInitial = {
504+ this . viewInitial = {
483505 'center.lon' : center . lon ,
484506 'center.lat' : center . lat ,
485507 'projection.scale' : projLayout . scale
486508 } ;
487509 } else if ( geoLayout . _isClipped ) {
488- _this . viewInitial = {
510+ this . viewInitial = {
489511 'projection.scale' : projLayout . scale ,
490512 'projection.rotation.lon' : rotation . lon ,
491513 'projection.rotation.lat' : rotation . lat
492514 } ;
493515 } else {
494- _this . viewInitial = {
516+ this . viewInitial = {
495517 'center.lon' : center . lon ,
496518 'center.lat' : center . lat ,
497519 'projection.scale' : projLayout . scale ,
@@ -574,7 +596,6 @@ function getProjection(geoLayout) {
574596 var maxAngle = clipAngle * Math . PI / 180 ;
575597 return angle > maxAngle ;
576598 } else {
577- // TODO does this ever happen??
578599 return false ;
579600 }
580601 } ;
0 commit comments