Skip to content

Commit 908171c

Browse files
committed
add minscale and maxscale to geo subplots
1 parent f7c4692 commit 908171c

File tree

5 files changed

+69
-13
lines changed

5 files changed

+69
-13
lines changed

src/plots/geo/geo.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,22 @@ proto.updateProjection = function(geoCalcData, fullLayout) {
213213

214214
var projection = this.projection = getProjection(geoLayout);
215215

216+
projection.getScale = function() {
217+
return projection.scale();
218+
};
219+
220+
projection.setScale = function(scale) {
221+
this._initalScale = this._initalScale || projection.scale();
222+
223+
var minscale = projLayout.minscale;
224+
var maxscale = projLayout.maxscale;
225+
console.log(minscale, maxscale)
226+
if(minscale !== undefined) scale = Math.max(minscale, scale / this._initalScale) * this._initalScale;
227+
if(maxscale !== undefined) scale = Math.min(maxscale, scale / this._initalScale) * this._initalScale;
228+
229+
return projection.scale(scale);
230+
};
231+
216232
// setup subplot extent [[x0,y0], [x1,y1]]
217233
var extent = [[
218234
gs.l + gs.w * domain.x[0],
@@ -265,7 +281,7 @@ proto.updateProjection = function(geoCalcData, fullLayout) {
265281
projection.fitExtent(extent, rangeBox);
266282

267283
var b = this.bounds = projection.getBounds(rangeBox);
268-
var s = this.fitScale = projection.scale();
284+
var s = this.fitScale = projection.getScale();
269285
var t = projection.translate();
270286

271287
if(geoLayout.fitbounds) {
@@ -276,13 +292,13 @@ proto.updateProjection = function(geoCalcData, fullLayout) {
276292
);
277293

278294
if(isFinite(k2)) {
279-
projection.scale(k2 * s);
295+
projection.setScale(k2 * s);
280296
} else {
281297
Lib.warn('Something went wrong during' + this.id + 'fitbounds computations.');
282298
}
283299
} else {
284300
// adjust projection to user setting
285-
projection.scale(projLayout.scale * s);
301+
projection.setScale(projLayout.scale * s);
286302
}
287303

288304
// px coordinates of view mid-point,

src/plots/geo/layout_attributes.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,24 @@ var attrs = module.exports = overrideAll({
177177
'that fits the map\'s lon and lat ranges. '
178178
].join(' ')
179179
},
180+
minscale: {
181+
valType: 'number',
182+
min: 0,
183+
description: [
184+
'Minimal zoom level of the map view.',
185+
'A minscale of *0.5* (50%) corresponds to a zoom level',
186+
'where the map has half the size of base zoom level.'
187+
].join(' ')
188+
},
189+
maxscale: {
190+
valType: 'number',
191+
min: 0,
192+
description: [
193+
'Maximal zoom level of the map view.',
194+
'A maxscale of *2* (200%) corresponds to a zoom level',
195+
'where the map is twice as big as the base layer.'
196+
].join(' ')
197+
},
180198
},
181199
center: {
182200
lon: {

src/plots/geo/layout_defaults.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,16 @@ function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
160160
coerce('projection.parallels', dfltProjParallels);
161161
}
162162

163-
coerce('projection.scale');
163+
var minscale = coerce('projection.minscale');
164+
var maxscale = coerce('projection.maxscale');
165+
if(minscale !== undefined && maxscale !== undefined && minscale > maxscale) {
166+
geoLayoutOut.projection.minscale = minscale = undefined;
167+
geoLayoutOut.projection.maxscale = maxscale = undefined;
168+
}
169+
170+
var scale = coerce('projection.scale');
171+
if(minscale !== undefined) geoLayoutOut.projection.scale = scale = Math.max(minscale, scale);
172+
if(maxscale !== undefined) geoLayoutOut.projection.scale = scale = Math.min(maxscale, scale);
164173

165174
show = coerce('showland', !visible ? false : undefined);
166175
if(show) coerce('landcolor');

src/plots/geo/zoom.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ module.exports = createGeoZoom;
3232
function initZoom(geo, projection) {
3333
return d3.behavior.zoom()
3434
.translate(projection.translate())
35-
.scale(projection.scale());
35+
.scale(projection.getScale());
3636
}
3737

3838
// sync zoom updates with user & full layout
@@ -60,7 +60,7 @@ function sync(geo, projection, cb) {
6060
}
6161

6262
cb(set);
63-
set('projection.scale', projection.scale() / geo.fitScale);
63+
set('projection.scale', projection.getScale() / geo.fitScale);
6464
set('fitbounds', false);
6565
gd.emit('plotly_relayout', eventData);
6666
}
@@ -81,7 +81,7 @@ function zoomScoped(geo, projection) {
8181

8282
var center = projection.invert(geo.midPt);
8383
geo.graphDiv.emit('plotly_relayouting', {
84-
'geo.projection.scale': projection.scale() / geo.fitScale,
84+
'geo.projection.scale': projection.getScale() / geo.fitScale,
8585
'geo.center.lon': center[0],
8686
'geo.center.lat': center[1]
8787
});
@@ -143,12 +143,12 @@ function zoomNonClipped(geo, projection) {
143143
mouse1 = d3.mouse(this);
144144

145145
if(outside(mouse0)) {
146-
zoom.scale(projection.scale());
146+
zoom.scale(projection.getScale());
147147
zoom.translate(projection.translate());
148148
return;
149149
}
150150

151-
projection.scale(d3.event.scale);
151+
projection.setScale(d3.event.scale);
152152
projection.translate([translate0[0], d3.event.translate[1]]);
153153

154154
if(!zoomPoint) {
@@ -167,7 +167,7 @@ function zoomNonClipped(geo, projection) {
167167
var rotate = projection.rotate();
168168
var center = projection.invert(geo.midPt);
169169
geo.graphDiv.emit('plotly_relayouting', {
170-
'geo.projection.scale': projection.scale() / geo.fitScale,
170+
'geo.projection.scale': projection.getScale() / geo.fitScale,
171171
'geo.center.lon': center[0],
172172
'geo.center.lat': center[1],
173173
'geo.projection.rotation.lon': -rotate[0]
@@ -199,7 +199,7 @@ function zoomNonClipped(geo, projection) {
199199
// zoom for clipped projections
200200
// inspired by https://www.jasondavies.com/maps/d3.geo.zoom.js
201201
function zoomClipped(geo, projection) {
202-
var view = {r: projection.rotate(), k: projection.scale()};
202+
var view = {r: projection.rotate(), k: projection.getScale()};
203203
var zoom = initZoom(geo, projection);
204204
var event = d3eventDispatch(zoom, 'zoomstart', 'zoom', 'zoomend');
205205
var zooming = 0;
@@ -221,7 +221,8 @@ function zoomClipped(geo, projection) {
221221
zoomOn.call(zoom, 'zoom', function() {
222222
var mouse1 = d3.mouse(this);
223223

224-
projection.scale(view.k = d3.event.scale);
224+
projection.setScale(d3.event.scale);
225+
view.k = projection.getScale();
225226

226227
if(!zoomPoint) {
227228
// if no zoomPoint, the mouse wasn't over the actual geography yet
@@ -272,7 +273,7 @@ function zoomClipped(geo, projection) {
272273

273274
var _rotate = projection.rotate();
274275
geo.graphDiv.emit('plotly_relayouting', {
275-
'geo.projection.scale': projection.scale() / geo.fitScale,
276+
'geo.projection.scale': projection.getScale() / geo.fitScale,
276277
'geo.projection.rotation.lon': -_rotate[0],
277278
'geo.projection.rotation.lat': -_rotate[1]
278279
});

test/plot-schema.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2373,6 +2373,18 @@
23732373
"valType": "number"
23742374
},
23752375
"editType": "plot",
2376+
"maxscale": {
2377+
"description": "Maximal zoom level of the map view. A maxscale of *2* (200%) corresponds to a zoom level where the map is twice as big as the base layer.",
2378+
"editType": "plot",
2379+
"min": 0,
2380+
"valType": "number"
2381+
},
2382+
"minscale": {
2383+
"description": "Minimal zoom level of the map view. A minscale of *0.5* (50%) corresponds to a zoom level where the map has half the size of base zoom level.",
2384+
"editType": "plot",
2385+
"min": 0,
2386+
"valType": "number"
2387+
},
23762388
"parallels": {
23772389
"description": "For conic projection types only. Sets the parallels (tangent, secant) where the cone intersects the sphere.",
23782390
"editType": "plot",

0 commit comments

Comments
 (0)