Skip to content

Commit 071e21b

Browse files
committed
feat(geo): support min/max scale limits
fixes #5191
1 parent 6583929 commit 071e21b

File tree

5 files changed

+47
-3
lines changed

5 files changed

+47
-3
lines changed

Diff for: src/components/modebar/buttons.js

+10
Original file line numberDiff line numberDiff line change
@@ -533,8 +533,18 @@ function handleGeo(gd, ev) {
533533

534534
if(attr === 'zoom') {
535535
var scale = geoLayout.projection.scale;
536+
var minScale = geoLayout.projection.minScale;
537+
var maxScale = geoLayout.projection.maxScale;
538+
536539
var newScale = (val === 'in') ? 2 * scale : 0.5 * scale;
537540

541+
// make sure the scale is within the min/max bounds
542+
if (newScale > maxScale) {
543+
newScale = maxScale;
544+
} else if (newScale < minScale) {
545+
newScale = minScale;
546+
}
547+
538548
Registry.call('_guiRelayout', gd, id + '.projection.scale', newScale);
539549
}
540550
}

Diff for: src/plots/geo/geo.js

+7
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,13 @@ function getProjection(geoLayout) {
709709
return projection.getPath().bounds(object);
710710
};
711711

712+
// https://github.com/d3/d3-zoom/blob/master/README.md#zoom_scaleExtent
713+
projection.scaleExtent = function() {
714+
var minScale = projLayout.minScale * 100;
715+
var maxScale = projLayout.maxScale * 100;
716+
return [ minScale, maxScale ];
717+
};
718+
712719
// adapted from d3 v4:
713720
// https://github.com/d3/d3-geo/blob/master/src/projection/fit.js
714721
projection.fitExtent = function(extent, object) {

Diff for: src/plots/geo/layout_attributes.js

+25-3
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,31 @@ var attrs = module.exports = overrideAll({
174174
min: 0,
175175
dflt: 1,
176176
description: [
177-
'Zooms in or out on the map view.',
178-
'A scale of *1* corresponds to the largest zoom level',
179-
'that fits the map\'s lon and lat ranges. '
177+
'Initial zoom level of the map view.',
178+
'A scale of *1* (100%) corresponds to the base zoom level',
179+
'that fits the map\'s lon and lat ranges.'
180+
].join(' ')
181+
},
182+
minScale: {
183+
valType: 'number',
184+
role: 'info',
185+
min: 0,
186+
dflt: 0,
187+
description: [
188+
'Minimal zoom level of the map view.',
189+
'A minScale of *0.5* (50%) corresponds to a zoom level',
190+
'where the map has half the size of base zoom level.'
191+
].join(' ')
192+
},
193+
maxScale: {
194+
valType: 'number',
195+
role: 'info',
196+
min: 0,
197+
dflt: Infinity,
198+
description: [
199+
'Maximal zoom level of the map view.',
200+
'A maxScale of *2* (200%) corresponds to a zoom level',
201+
'where the map is twice as big as the base layer.'
180202
].join(' ')
181203
},
182204
},

Diff for: src/plots/geo/layout_defaults.js

+4
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
162162
}
163163

164164
coerce('projection.scale');
165+
coerce('projection.minScale');
166+
coerce('projection.maxScale');
165167

166168
show = coerce('showland', !visible ? false : undefined);
167169
if(show) coerce('landcolor');
@@ -206,6 +208,8 @@ function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
206208
// clear attributes that will get auto-filled later
207209
if(fitBounds) {
208210
delete geoLayoutOut.projection.scale;
211+
delete geoLayoutOut.projection.minScale;
212+
delete geoLayoutOut.projection.maxScale;
209213

210214
if(isScoped) {
211215
delete geoLayoutOut.center.lon;

Diff for: src/plots/geo/zoom.js

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ module.exports = createGeoZoom;
4141
function initZoom(geo, projection) {
4242
return d3.behavior.zoom()
4343
.translate(projection.translate())
44+
.scaleExtent(projection.scaleExtent())
4445
.scale(projection.scale());
4546
}
4647

0 commit comments

Comments
 (0)