@@ -19,6 +19,7 @@ var Drawing = require('../../components/drawing');
19
19
var Fx = require ( '../../components/fx' ) ;
20
20
var Plots = require ( '../plots' ) ;
21
21
var Axes = require ( '../cartesian/axes' ) ;
22
+ var getAutoRange = require ( '../cartesian/autorange' ) . getAutoRange ;
22
23
var dragElement = require ( '../../components/dragelement' ) ;
23
24
var prepSelect = require ( '../cartesian/select' ) . prepSelect ;
24
25
var selectOnClick = require ( '../cartesian/select' ) . selectOnClick ;
@@ -143,18 +144,24 @@ proto.fetchTopojson = function() {
143
144
proto . update = function ( geoCalcData , fullLayout ) {
144
145
var geoLayout = fullLayout [ this . id ] ;
145
146
146
- var hasInvalidBounds = this . updateProjection ( fullLayout , geoLayout ) ;
147
- if ( hasInvalidBounds ) return ;
148
-
149
147
// important: maps with choropleth traces have a different layer order
150
148
this . hasChoropleth = false ;
149
+
151
150
for ( var i = 0 ; i < geoCalcData . length ; i ++ ) {
152
- if ( geoCalcData [ i ] [ 0 ] . trace . type === 'choropleth' ) {
151
+ var calcTrace = geoCalcData [ i ] ;
152
+ var trace = calcTrace [ 0 ] . trace ;
153
+
154
+ if ( trace . type === 'choropleth' ) {
153
155
this . hasChoropleth = true ;
154
- break ;
156
+ }
157
+ if ( trace . visible === true && trace . _length > 0 ) {
158
+ trace . _module . calcGeoJSON ( calcTrace , fullLayout ) ;
155
159
}
156
160
}
157
161
162
+ var hasInvalidBounds = this . updateProjection ( geoCalcData , fullLayout ) ;
163
+ if ( hasInvalidBounds ) return ;
164
+
158
165
if ( ! this . viewInitial || this . scope !== geoLayout . scope ) {
159
166
this . saveViewInitial ( geoLayout ) ;
160
167
}
@@ -177,20 +184,19 @@ proto.update = function(geoCalcData, fullLayout) {
177
184
this . render ( ) ;
178
185
} ;
179
186
180
- proto . updateProjection = function ( fullLayout , geoLayout ) {
187
+ proto . updateProjection = function ( geoCalcData , fullLayout ) {
188
+ var gd = this . graphDiv ;
189
+ var geoLayout = fullLayout [ this . id ] ;
181
190
var gs = fullLayout . _size ;
182
191
var domain = geoLayout . domain ;
183
192
var projLayout = geoLayout . projection ;
184
- var rotation = projLayout . rotation || { } ;
185
- var center = geoLayout . center || { } ;
186
193
187
- var projection = this . projection = getProjection ( geoLayout ) ;
194
+ var lonaxis = geoLayout . lonaxis ;
195
+ var lataxis = geoLayout . lataxis ;
196
+ var axLon = lonaxis . _ax ;
197
+ var axLat = lataxis . _ax ;
188
198
189
- // set 'pre-fit' projection
190
- projection
191
- . center ( [ center . lon - rotation . lon , center . lat - rotation . lat ] )
192
- . rotate ( [ - rotation . lon , - rotation . lat , rotation . roll ] )
193
- . parallels ( projLayout . parallels ) ;
199
+ var projection = this . projection = getProjection ( geoLayout ) ;
194
200
195
201
// setup subplot extent [[x0,y0], [x1,y1]]
196
202
var extent = [ [
@@ -201,11 +207,46 @@ proto.updateProjection = function(fullLayout, geoLayout) {
201
207
gs . t + gs . h * ( 1 - domain . y [ 0 ] )
202
208
] ] ;
203
209
204
- var lonaxis = geoLayout . lonaxis ;
205
- var lataxis = geoLayout . lataxis ;
206
- var rangeBox = makeRangeBox ( lonaxis . range , lataxis . range ) ;
210
+ var center = geoLayout . center || { } ;
211
+ var rotation = projLayout . rotation || { } ;
212
+ var lonaxisRange = lonaxis . range || [ ] ;
213
+ var lataxisRange = lataxis . range || [ ] ;
214
+
215
+ if ( geoLayout . fitbounds ) {
216
+ axLon . _length = extent [ 1 ] [ 0 ] - extent [ 0 ] [ 0 ] ;
217
+ axLat . _length = extent [ 1 ] [ 1 ] - extent [ 0 ] [ 1 ] ;
218
+ axLon . range = getAutoRange ( gd , axLon ) ;
219
+ axLat . range = getAutoRange ( gd , axLat ) ;
220
+
221
+ var midLon = ( axLon . range [ 0 ] + axLon . range [ 1 ] ) / 2 ;
222
+ var midLat = ( axLat . range [ 0 ] + axLat . range [ 1 ] ) / 2 ;
223
+
224
+ if ( geoLayout . _isScoped ) {
225
+ center = { lon : midLon , lat : midLat } ;
226
+ } else if ( geoLayout . _isClipped ) {
227
+ center = { lon : midLon , lat : midLat } ;
228
+ rotation = { lon : midLon , lat : midLat , roll : rotation . roll } ;
229
+
230
+ var projType = projLayout . type ;
231
+ var lonHalfSpan = ( constants . lonaxisSpan [ projType ] / 2 ) || 180 ;
232
+ var latHalfSpan = ( constants . lataxisSpan [ projType ] / 2 ) || 180 ;
233
+
234
+ lonaxisRange = [ midLon - lonHalfSpan , midLon + lonHalfSpan ] ;
235
+ lataxisRange = [ midLat - latHalfSpan , midLat + latHalfSpan ] ;
236
+ } else {
237
+ center = { lon : midLon , lat : midLat } ;
238
+ rotation = { lon : midLon , lat : rotation . lat , roll : rotation . roll } ;
239
+ }
240
+ }
241
+
242
+ // set 'pre-fit' projection
243
+ projection
244
+ . center ( [ center . lon - rotation . lon , center . lat - rotation . lat ] )
245
+ . rotate ( [ - rotation . lon , - rotation . lat , rotation . roll ] )
246
+ . parallels ( projLayout . parallels ) ;
207
247
208
248
// fit projection 'scale' and 'translate' to set lon/lat ranges
249
+ var rangeBox = makeRangeBox ( lonaxisRange , lataxisRange ) ;
209
250
projection . fitExtent ( extent , rangeBox ) ;
210
251
211
252
var b = this . bounds = projection . getBounds ( rangeBox ) ;
@@ -217,12 +258,11 @@ proto.updateProjection = function(fullLayout, geoLayout) {
217
258
! isFinite ( b [ 1 ] [ 0 ] ) || ! isFinite ( b [ 1 ] [ 1 ] ) ||
218
259
isNaN ( t [ 0 ] ) || isNaN ( t [ 0 ] )
219
260
) {
220
- var gd = this . graphDiv ;
221
- var attrToUnset = [ 'projection.rotation' , 'center' , 'lonaxis.range' , 'lataxis.range' ] ;
261
+ var attrToUnset = [ 'fitbounds' , 'projection.rotation' , 'center' , 'lonaxis.range' , 'lataxis.range' ] ;
222
262
var msg = 'Invalid geo settings, relayout\'ing to default view.' ;
223
263
var updateObj = { } ;
224
264
225
- // clear all attribute that could cause invalid bounds,
265
+ // clear all attributes that could cause invalid bounds,
226
266
// clear viewInitial to update reset-view behavior
227
267
228
268
for ( var i = 0 ; i < attrToUnset . length ; i ++ ) {
@@ -236,16 +276,26 @@ proto.updateProjection = function(fullLayout, geoLayout) {
236
276
return msg ;
237
277
}
238
278
279
+ if ( geoLayout . fitbounds ) {
280
+ var b2 = projection . getBounds ( makeRangeBox ( axLon . range , axLat . range ) ) ;
281
+ var k2 = Math . min (
282
+ ( b [ 1 ] [ 0 ] - b [ 0 ] [ 0 ] ) / ( b2 [ 1 ] [ 0 ] - b2 [ 0 ] [ 0 ] ) ,
283
+ ( b [ 1 ] [ 1 ] - b [ 0 ] [ 1 ] ) / ( b2 [ 1 ] [ 1 ] - b2 [ 0 ] [ 1 ] )
284
+ ) ;
285
+ projection . scale ( k2 * s ) ;
286
+ } else {
287
+ // adjust projection to user setting
288
+ projection . scale ( projLayout . scale * s ) ;
289
+ }
290
+
239
291
// px coordinates of view mid-point,
240
292
// useful to update `geo.center` after interactions
241
293
var midPt = this . midPt = [
242
294
( b [ 0 ] [ 0 ] + b [ 1 ] [ 0 ] ) / 2 ,
243
295
( b [ 0 ] [ 1 ] + b [ 1 ] [ 1 ] ) / 2
244
296
] ;
245
297
246
- // adjust projection to user setting
247
298
projection
248
- . scale ( projLayout . scale * s )
249
299
. translate ( [ t [ 0 ] + ( midPt [ 0 ] - t [ 0 ] ) , t [ 1 ] + ( midPt [ 1 ] - t [ 1 ] ) ] )
250
300
. clipExtent ( b ) ;
251
301
@@ -540,26 +590,31 @@ proto.saveViewInitial = function(geoLayout) {
540
590
var projLayout = geoLayout . projection ;
541
591
var rotation = projLayout . rotation || { } ;
542
592
593
+ this . viewInitial = {
594
+ 'fitbounds' : geoLayout . fitbounds ,
595
+ 'projection.scale' : projLayout . scale
596
+ } ;
597
+
598
+ var extra ;
543
599
if ( geoLayout . _isScoped ) {
544
- this . viewInitial = {
600
+ extra = {
545
601
'center.lon' : center . lon ,
546
602
'center.lat' : center . lat ,
547
- 'projection.scale' : projLayout . scale
548
603
} ;
549
604
} else if ( geoLayout . _isClipped ) {
550
- this . viewInitial = {
551
- 'projection.scale' : projLayout . scale ,
605
+ extra = {
552
606
'projection.rotation.lon' : rotation . lon ,
553
607
'projection.rotation.lat' : rotation . lat
554
608
} ;
555
609
} else {
556
- this . viewInitial = {
610
+ extra = {
557
611
'center.lon' : center . lon ,
558
612
'center.lat' : center . lat ,
559
- 'projection.scale' : projLayout . scale ,
560
613
'projection.rotation.lon' : rotation . lon
561
614
} ;
562
615
}
616
+
617
+ Lib . extendFlat ( this . viewInitial , extra ) ;
563
618
} ;
564
619
565
620
// [hot code path] (re)draw all paths which depend on the projection
0 commit comments