diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index f5be363af5..cf8dad720b 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -68,7 +68,7 @@ * Object literal with config options for the Proj4js projection. * @typedef {Object} ol.Proj4jsProjectionOptions * @property {string} code The SRS identifier code, e.g. 'EPSG:31256'. - * @property {ol.Extent} extent The validity extent for the SRS. + * @property {ol.Extent|undefined} extent The validity extent for the SRS. * @property {boolean|undefined} global Whether the projection is valid for the * whole globe. Default is false. */ @@ -78,7 +78,7 @@ * @typedef {Object} ol.ProjectionOptions * @property {string} code The SRS identifier code, e.g. 'EPSG:4326'. * @property {ol.ProjectionUnits} units Units. - * @property {ol.Extent} extent The validity extent for the SRS. + * @property {ol.Extent|undefined} extent The validity extent for the SRS. * @property {string|undefined} axisOrientation The axis orientation as * specified in Proj4. The default is 'enu'. * @property {boolean|undefined} global Whether the projection is valid for the @@ -89,6 +89,8 @@ * Object literal with config options for the view. * @typedef {Object} ol.View2DOptions * @property {ol.Coordinate|undefined} center The view center in map projection. + * @property {ol.Extent|undefined} maxExtent The maximum extent for the view. + * If configured, the view's center cannot be outside this extent. * @property {number|undefined} maxResolution The maximum resolution in map * units per pixel. * @property {number|undefined} maxZoom The maximum zoom level for this view. diff --git a/src/ol/proj/proj.js b/src/ol/proj/proj.js index f25d59a1aa..21d244f2be 100644 --- a/src/ol/proj/proj.js +++ b/src/ol/proj/proj.js @@ -74,7 +74,7 @@ ol.Projection = function(options) { * @private * @type {ol.Extent} */ - this.extent_ = options.extent; + this.extent_ = goog.isDef(options.extent) ? options.extent : null; /** * @private diff --git a/src/ol/tilegrid/tilegrid.js b/src/ol/tilegrid/tilegrid.js index fabd8db081..5811beebce 100644 --- a/src/ol/tilegrid/tilegrid.js +++ b/src/ol/tilegrid/tilegrid.js @@ -4,6 +4,7 @@ goog.require('goog.array'); goog.require('goog.asserts'); goog.require('ol.Coordinate'); goog.require('ol.Projection'); +goog.require('ol.ProjectionUnits'); goog.require('ol.Size'); goog.require('ol.TileCoord'); goog.require('ol.TileRange'); @@ -410,21 +411,23 @@ ol.tilegrid.getForProjection = function(projection) { ol.tilegrid.createForProjection = function(projection, opt_maxZoom, opt_tileSize) { var projectionExtent = projection.getExtent(); - var size = Math.max( - projectionExtent[1] - projectionExtent[0], - projectionExtent[3] - projectionExtent[2]); + var size = goog.isNull(projectionExtent) ? + 360 * ol.METERS_PER_UNIT[ol.ProjectionUnits.DEGREES] / + ol.METERS_PER_UNIT[projection.getUnits()] : + Math.max(projectionExtent[1] - projectionExtent[0], + projectionExtent[3] - projectionExtent[2]); var maxZoom = goog.isDef(opt_maxZoom) ? opt_maxZoom : ol.DEFAULT_MAX_ZOOM; var tileSize = goog.isDef(opt_tileSize) ? opt_tileSize : [ol.DEFAULT_TILE_SIZE, ol.DEFAULT_TILE_SIZE]; var resolutions = new Array(maxZoom + 1); - goog.asserts.assert(tileSize[0] == tileSize[1]); - size = size / tileSize[0]; + size = size / Math.max(tileSize[0], tileSize[1]); for (var z = 0, zz = resolutions.length; z < zz; ++z) { resolutions[z] = size / Math.pow(2, z); } return new ol.tilegrid.TileGrid({ - origin: ol.extent.getBottomLeft(projectionExtent), + origin: goog.isNull(projectionExtent) ? [0, 0] : + ol.extent.getBottomLeft(projectionExtent), resolutions: resolutions, tileSize: tileSize }); diff --git a/src/ol/view2d.js b/src/ol/view2d.js index 5a52c18931..b807da9ad4 100644 --- a/src/ol/view2d.js +++ b/src/ol/view2d.js @@ -4,10 +4,12 @@ goog.provide('ol.View2D'); goog.provide('ol.View2DProperty'); goog.require('goog.asserts'); +goog.require('goog.math'); goog.require('ol.Constraints'); goog.require('ol.IView2D'); goog.require('ol.IView3D'); goog.require('ol.Projection'); +goog.require('ol.ProjectionUnits'); goog.require('ol.ResolutionConstraint'); goog.require('ol.RotationConstraint'); goog.require('ol.RotationConstraintType'); @@ -57,18 +59,12 @@ ol.View2D = function(opt_options) { options.center : null; values[ol.View2DProperty.PROJECTION] = ol.proj.createProjection( options.projection, 'EPSG:3857'); - if (goog.isDef(options.resolution)) { - values[ol.View2DProperty.RESOLUTION] = options.resolution; - } else if (goog.isDef(options.zoom)) { - var projectionExtent = values[ol.View2DProperty.PROJECTION].getExtent(); - var size = Math.max( - projectionExtent[1] - projectionExtent[0], - projectionExtent[3] - projectionExtent[2]); - values[ol.View2DProperty.RESOLUTION] = - size / (ol.DEFAULT_TILE_SIZE * Math.pow(2, options.zoom)); - } - values[ol.View2DProperty.ROTATION] = options.rotation; - this.setValues(values); + + /** + * @private + * @type {ol.Extent} + */ + this.maxExtent_ = goog.isDef(options.maxExtent) ? options.maxExtent : null; var parts = ol.View2D.createResolutionConstraint_(options); @@ -94,6 +90,14 @@ ol.View2D = function(opt_options) { this.constraints_ = new ol.Constraints(resolutionConstraint, rotationConstraint); + if (goog.isDef(options.resolution)) { + values[ol.View2DProperty.RESOLUTION] = options.resolution; + } else if (goog.isDef(options.zoom)) { + values[ol.View2DProperty.RESOLUTION] = resolutionConstraint( + this.maxResolution_, options.zoom); + } + values[ol.View2DProperty.ROTATION] = options.rotation; + this.setValues(values); }; goog.inherits(ol.View2D, ol.View); @@ -355,7 +359,10 @@ ol.View2D.prototype.isDef = function() { * @param {ol.Coordinate|undefined} center Center. */ ol.View2D.prototype.setCenter = function(center) { - this.set(ol.View2DProperty.CENTER, center); + this.set(ol.View2DProperty.CENTER, goog.isNull(this.maxExtent_) ? center : [ + goog.math.clamp(center[0], this.maxExtent_[0], this.maxExtent_[1]), + goog.math.clamp(center[1], this.maxExtent_[2], this.maxExtent_[3]) + ]); }; goog.exportProperty( ol.View2D.prototype, @@ -421,11 +428,16 @@ ol.View2D.createResolutionConstraint_ = function(options) { } else { maxResolution = options.maxResolution; if (!goog.isDef(maxResolution)) { - var projectionExtent = ol.proj.createProjection( - options.projection, 'EPSG:3857').getExtent(); - maxResolution = Math.max( - projectionExtent[1] - projectionExtent[0], - projectionExtent[3] - projectionExtent[2]) / ol.DEFAULT_TILE_SIZE; + var projection = options.projection; + var projectionExtent = ol.proj.createProjection(projection, 'EPSG:3857') + .getExtent(); + var size = goog.isNull(projectionExtent) ? + // use an extent that can fit the whole world if need be + 360 * ol.METERS_PER_UNIT[ol.ProjectionUnits.DEGREES] / + ol.METERS_PER_UNIT[projection.getUnits()] : + Math.max(projectionExtent[1] - projectionExtent[0], + projectionExtent[3] - projectionExtent[2]); + maxResolution = size / ol.DEFAULT_TILE_SIZE; } var maxZoom = options.maxZoom; if (!goog.isDef(maxZoom)) {