@@ -594,6 +594,8 @@ modeBarButtons.hoverClosestGeo = {
594594 click : toggleHover
595595} ;
596596
597+ const ZOOM_STEP_GEO = 2 ;
598+
597599function handleGeo ( gd , ev ) {
598600 const button = ev . currentTarget ;
599601 const attr = button . getAttribute ( 'data-attr' ) ;
@@ -603,30 +605,36 @@ function handleGeo(gd, ev) {
603605
604606 for ( const id of geoIds ) {
605607 const geoLayout = fullLayout [ id ] ;
608+ const geoSubplot = geoLayout . _subplot ;
606609
607610 if ( attr === 'zoom' ) {
608- const { minscale, scale } = geoLayout . projection ;
611+ // Under fitbounds, geoLayout.projection.scale is undefined; read the
612+ // effective view from the D3 projection state instead
613+ const projection = geoSubplot . projection ;
614+ const effectiveScale = projection . scale ( ) / geoSubplot . fitScale ; // Convert to schema format (multiples of original scale)
615+ const [ rotationLon , rotationLat ] = projection . rotate ( ) . map ( ( d ) => - d ) ; // Flip sign because D3 rotation is opposite of ours
616+ const [ centerLon , centerLat ] = projection . invert ( geoSubplot . midPt ) ;
617+
618+ const { minscale } = geoLayout . projection ;
609619 const maxscale = geoLayout . projection . maxscale ?? Infinity ;
610620 // swap if user supplied min > max so clamping is well-defined
611621 const min = Math . min ( minscale , maxscale ) ;
612622 const max = Math . max ( minscale , maxscale ) ;
613- let newScale = val === 'in' ? 2 * scale : 0.5 * scale ;
623+ let newScale = val === 'in' ? ZOOM_STEP_GEO * effectiveScale : ( 1 / ZOOM_STEP_GEO ) * effectiveScale ;
614624
615625 // clamp to [min, max]
616626 if ( newScale > max ) newScale = max ;
617627 else if ( newScale < min ) newScale = min ;
618628
619- if ( newScale !== scale ) {
629+ if ( newScale !== effectiveScale ) {
620630 // Persist the currently-effective view attrs with the new scale; turn
621631 // off fitbounds so auto-fit doesn't overwrite them on the ensuing replot
622- const { rotation } = geoLayout . projection ;
623- const { center } = geoLayout ;
624632 Registry . call ( '_guiRelayout' , gd , {
625633 [ id + '.projection.scale' ] : newScale ,
626- [ id + '.projection.rotation.lon' ] : rotation . lon ,
627- [ id + '.projection.rotation.lat' ] : rotation . lat ,
628- [ id + '.center.lon' ] : center . lon ,
629- [ id + '.center.lat' ] : center . lat ,
634+ [ id + '.projection.rotation.lon' ] : rotationLon ,
635+ [ id + '.projection.rotation.lat' ] : rotationLat ,
636+ [ id + '.center.lon' ] : centerLon ,
637+ [ id + '.center.lat' ] : centerLat ,
630638 [ id + '.fitbounds' ] : false
631639 } ) ;
632640 }
0 commit comments