getMaxExtent(), getMaxResolution(), and getNumZoomLevels(). They were just wrapping around the properties. better to just access the property directly. Needed to update for these removals in many different files. - Improved initResolutions() functionality. It is now I believe both thorough and complete. The only exception is that we should maybe allow a way for the user to set up resolutions[] array using only minResolution and numZoomLevels instead of only maxResolution and numZoomLevels... but I'm not really sure anyone would ever really want to use that. And at any rate, I don't know the math for how to do it. I'm sure schuyler or Dr. 5 would. Oh. for a summary of how initResolutions works, see: http://trac.openlayers.org/wiki/SettingZoomLevels - Move getResolution(), initResolutions() out of HTTPRequest and into Layer. On thinking this through (and trying to write documentation), I realized that the real, true, GENERIC case for a layer will be using this awesome resolutions[] array that allows for setting number of zoom levels, default max resolutions, special scale arrays, etc. - Updated code for getZoomForExtent() to work with resolutions[] array, instead of using the the log 2 equation. - Move standard getZoomForExtent() and getExtent() out of Grid and into Layer. Like above, there is no reason for these methods to be found so far down in the food chain. They are part of the generic calculations for generic layers, so they belong in Layer. git-svn-id: http://svn.openlayers.org/trunk/openlayers@1379 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
425 lines
13 KiB
JavaScript
425 lines
13 KiB
JavaScript
/* Copyright (c) 2006 MetaCarta, Inc., published under the BSD license.
|
|
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the full
|
|
* text of the license. */
|
|
|
|
/**
|
|
* @class
|
|
*/
|
|
OpenLayers.Layer = Class.create();
|
|
OpenLayers.Layer.prototype = {
|
|
|
|
/** @type String */
|
|
id: null,
|
|
|
|
/** @type String */
|
|
name: null,
|
|
|
|
/** @type DOMElement */
|
|
div: null,
|
|
|
|
/** This variable is set when the layer is added to the map, via the
|
|
* accessor function setMap()
|
|
*
|
|
* @type OpenLayers.Map */
|
|
map: null,
|
|
|
|
/** Whether or not the layer is a base layer. This should be set
|
|
* individually by all subclasses.
|
|
* Default is false
|
|
*
|
|
* @type Boolean
|
|
*/
|
|
isBaseLayer: false,
|
|
|
|
/** asserts whether or not the layer's images have an alpha channel
|
|
*
|
|
* @type boolean */
|
|
alpha: false,
|
|
|
|
// OPTIONS
|
|
|
|
/** @type Array */
|
|
options: null,
|
|
|
|
/** @type String */
|
|
projection: null,
|
|
|
|
/** @type String */
|
|
units: null,
|
|
|
|
/** @type Array */
|
|
scales: null,
|
|
|
|
/** @type Array */
|
|
resolutions: null,
|
|
|
|
/** @type OpenLayers.Bounds */
|
|
maxExtent: null,
|
|
|
|
/** @type OpenLayers.Bounds */
|
|
minExtent: null,
|
|
|
|
/** @type float */
|
|
maxResolution: null,
|
|
|
|
/** @type float */
|
|
minResolution: null,
|
|
|
|
/** @type int */
|
|
numZoomLevels: null,
|
|
|
|
/** @type float */
|
|
minScale: null,
|
|
|
|
/** @type float */
|
|
maxScale: null,
|
|
|
|
|
|
/**
|
|
* @constructor
|
|
*
|
|
* @param {String} name
|
|
* @param {Object} options Hashtable of extra options to tag onto the layer
|
|
*/
|
|
initialize: function(name, options) {
|
|
if (arguments.length > 0) {
|
|
|
|
//store a copy of the custom options for later cloning
|
|
this.options = Object.extend(new Object(), options);
|
|
|
|
//add options to layer
|
|
Object.extend(this, this.options);
|
|
|
|
this.name = name;
|
|
|
|
//generate unique id based on name
|
|
this.id = OpenLayers.Util.createUniqueID("Layer_");
|
|
|
|
if (this.div == null) {
|
|
this.div = OpenLayers.Util.createDiv();
|
|
this.div.style.width = "100%";
|
|
this.div.style.height = "100%";
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Destroy is a destructor: this is to alleviate cyclic references which
|
|
* the Javascript garbage cleaner can not take care of on its own.
|
|
*/
|
|
destroy: function() {
|
|
if (this.map != null) {
|
|
this.map.removeLayer(this);
|
|
}
|
|
this.map = null;
|
|
this.name = null;
|
|
this.div = null;
|
|
this.options = null;
|
|
},
|
|
|
|
/**
|
|
* @returns An exact clone of this OpenLayers.Layer
|
|
* @type OpenLayers.Layer
|
|
*/
|
|
clone: function (obj) {
|
|
|
|
if (obj == null) {
|
|
obj = new OpenLayers.Layer(this.name, this.options);
|
|
}
|
|
|
|
// catch any randomly tagged-on properties
|
|
OpenLayers.Util.applyDefaults(obj, this);
|
|
|
|
// a cloned layer should never have its map property set
|
|
// because it has not been added to a map yet.
|
|
obj.map = null;
|
|
|
|
return obj;
|
|
},
|
|
|
|
/**
|
|
* @param {String} newName
|
|
*/
|
|
setName: function(newName) {
|
|
this.name = newName;
|
|
if (this.map != null)
|
|
this.map.events.triggerEvent("changelayer");
|
|
},
|
|
|
|
/**
|
|
* @param {Object} newOptions
|
|
*/
|
|
addOptions: function (newOptions) {
|
|
|
|
// update our copy for clone
|
|
Object.extend(this.options, newOptions);
|
|
|
|
// add new options to this
|
|
Object.extend(this, this.options);
|
|
},
|
|
|
|
/**
|
|
*
|
|
*/
|
|
onMapResize: function() {
|
|
//this function can be implemented by subclasses
|
|
},
|
|
|
|
/**
|
|
* @param {OpenLayers.Bounds} bound
|
|
* @param {Boolean} zoomChanged tells when zoom has changed, as layers
|
|
* have to do some init work in that case.
|
|
* @param {Boolean} minor
|
|
*/
|
|
moveTo:function(bounds, zoomChanged, minor) {
|
|
//this function can be implemented by subclasses.
|
|
},
|
|
|
|
/** Set the map property for the layer. This is done through an accessor
|
|
* so that subclasses can override this and take special action once
|
|
* they have their map variable set.
|
|
*
|
|
* Here we take care to bring over any of the necessary default properties
|
|
* from the map.
|
|
*
|
|
* @param {OpenLayers.Map} map
|
|
*/
|
|
setMap: function(map) {
|
|
this.map = map;
|
|
|
|
var properties = new Array(
|
|
'projection', 'units',
|
|
'scales', 'resolutions',
|
|
'maxScale', 'minScale',
|
|
'maxResolution', 'minResolution',
|
|
'minExtent', 'maxExtent',
|
|
'numZoomLevels'
|
|
);
|
|
if (this.map.maxZoomLevel && !this.numZoomLevels) {
|
|
this.numZoomLevels = this.map.maxZoomLevel + 1;
|
|
}
|
|
for(var i=0; i < properties.length; i++) {
|
|
if (this[properties[i]] == null) {
|
|
this[properties[i]] = this.map[properties[i]];
|
|
}
|
|
}
|
|
if (this.isBaseLayer) {
|
|
this.initResolutions();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @returns Whether or not the layer is visible
|
|
* @type Boolean
|
|
*/
|
|
getVisibility: function() {
|
|
return (this.div.style.display != "none");
|
|
},
|
|
|
|
/**
|
|
* @param {Boolean} visible
|
|
* @param {Boolean} noEvent
|
|
*/
|
|
setVisibility: function(visible, noEvent) {
|
|
if (visible != this.getVisibility()) {
|
|
this.div.style.display = (visible) ? "block" : "none";
|
|
if ((visible) && (this.map != null)) {
|
|
var extent = this.map.getExtent();
|
|
if (extent != null) {
|
|
this.moveTo(this.map.getExtent());
|
|
}
|
|
}
|
|
if ((this.map != null) &&
|
|
((noEvent == null) || (noEvent == false))) {
|
|
this.map.events.triggerEvent("changelayer");
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @param {Boolean} isBaseLayer
|
|
*/
|
|
setIsBaseLayer: function(isBaseLayer) {
|
|
this.isBaseLayer = isBaseLayer;
|
|
if (this.map != null) {
|
|
this.map.events.triggerEvent("changelayer");
|
|
}
|
|
},
|
|
|
|
/********************************************************/
|
|
/* */
|
|
/* Baselayer Functions */
|
|
/* */
|
|
/********************************************************/
|
|
|
|
/** This method's responsibility is to set up the 'resolutions' array
|
|
* for the layer -- this array is what the layer will use to interface
|
|
* between the zoom levels of the map and the resolution display of the
|
|
* layer.
|
|
*
|
|
* The user has several options that determine how the array is set up.
|
|
*
|
|
* For a detailed explanation, see the following wiki from the
|
|
* openlayers.org homepage:
|
|
*
|
|
* http://trac.openlayers.org/wiki/SettingZoomLevels
|
|
*
|
|
* @private
|
|
*/
|
|
initResolutions: function() {
|
|
|
|
if ((this.scales != null) || (this.resolutions != null)) {
|
|
//preset levels
|
|
if (this.scales != null) {
|
|
this.resolutions = new Array();
|
|
for(var i = 0; i < this.scales.length; i++) {
|
|
this.resolutions[i] =
|
|
OpenLayers.Util.getResolutionFromScale(this.scales[i],
|
|
this.units);
|
|
}
|
|
}
|
|
this.numZoomLevels = this.resolutions.length;
|
|
|
|
} else {
|
|
//maxResolution and numZoomLevels
|
|
|
|
this.resolutions = new Array();
|
|
|
|
// determine maxResolution
|
|
if (this.minScale) {
|
|
this.maxResolution =
|
|
OpenLayers.Util.getResolutionFromScale(this.minScale,
|
|
this.units);
|
|
} else if (this.maxResolution == "auto") {
|
|
var viewSize = this.map.getSize();
|
|
var wRes = this.maxExtent.getWidth() / viewSize.w;
|
|
var hRes = this.maxExtent.getHeight()/ viewSize.h;
|
|
this.maxResolution = Math.max(wRes, hRes);
|
|
}
|
|
|
|
// determine minResolution
|
|
if (this.maxScale != null) {
|
|
this.minResolution =
|
|
OpenLayers.Util.getResolutionFromScale(this.maxScale);
|
|
} else if ((this.minResolution == "auto") &&
|
|
(this.minExtent != null)){
|
|
var viewSize = this.map.getSize();
|
|
var wRes = this.minExtent.getWidth() / viewSize.w;
|
|
var hRes = this.minExtent.getHeight()/ viewSize.h;
|
|
this.minResolution = Math.max(wRes, hRes);
|
|
}
|
|
|
|
// determine numZoomLevels
|
|
if (this.minResolution != null) {
|
|
var ratio = this.maxResolution / this.minResolution;
|
|
this.numZoomLevels =
|
|
Math.floor(Math.log(ratio) / Math.log(2)) + 1;
|
|
}
|
|
|
|
// now we have numZoomLevels and maxResolution,
|
|
// we can populate the resolutions array
|
|
for (var i=0; i < this.numZoomLevels; i++) {
|
|
this.resolutions.push(this.maxResolution / Math.pow(2, i));
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @returns The currently selected resolution of the map, taken from the
|
|
* resolutions array, indexed by current zoom level.
|
|
* @type float
|
|
*/
|
|
getResolution: function() {
|
|
var zoom = this.map.getZoom();
|
|
return this.resolutions[zoom];
|
|
},
|
|
|
|
/** Calculates based on resolution, center, and mapsize
|
|
*
|
|
* @returns A Bounds object which represents the lon/lat bounds of the
|
|
* current viewPort.
|
|
* @type OpenLayers.Bounds
|
|
*/
|
|
getExtent: function () {
|
|
var extent = null;
|
|
|
|
var center = this.map.getCenter();
|
|
if (center != null) {
|
|
|
|
var res = this.getResolution();
|
|
var size = this.map.getSize();
|
|
var w_deg = size.w * res;
|
|
var h_deg = size.h * res;
|
|
|
|
extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
|
|
center.lat - h_deg / 2,
|
|
center.lon + w_deg / 2,
|
|
center.lat + h_deg / 2);
|
|
|
|
}
|
|
|
|
return extent;
|
|
},
|
|
|
|
/**
|
|
* @param {OpenLayers.Bounds} bounds
|
|
*
|
|
* @returns The index of the zoomLevel (entry in the resolutions array)
|
|
* that still contains the passed-in extent. We do this by
|
|
* calculating the ideal resolution for the given exteng (based
|
|
* on the map size) and then find the smallest resolution that
|
|
* is greater than this ideal resolution.
|
|
* @type int
|
|
*/
|
|
getZoomForExtent: function(extent) {
|
|
var viewSize = this.map.getSize();
|
|
var idealResolution = Math.max( extent.getWidth() / viewSize.w,
|
|
extent.getHeight() / viewSize.h );
|
|
|
|
for(var i=1; i <= this.resolutions.length; i++) {
|
|
if ( this.resolutions[i] < idealResolution) {
|
|
break;
|
|
}
|
|
}
|
|
return (i - 1);
|
|
},
|
|
|
|
/**
|
|
* @param {OpenLayers.Pixel} viewPortPx
|
|
*
|
|
* @returns An OpenLayers.LonLat which is the passed-in view port
|
|
* OpenLayers.Pixel, translated into lon/lat by the layer
|
|
* @type OpenLayers.LonLat
|
|
*/
|
|
getLonLatFromViewPortPx: function (viewPortPx) {
|
|
var size = this.map.getSize();
|
|
var center = this.map.getCenter();
|
|
var res = this.map.getResolution();
|
|
|
|
var delta_x = viewPortPx.x - (size.w / 2);
|
|
var delta_y = viewPortPx.y - (size.h / 2);
|
|
|
|
return new OpenLayers.LonLat(center.lon + delta_x * res ,
|
|
center.lat - delta_y * res);
|
|
},
|
|
|
|
/**
|
|
* @param {OpenLayers.LonLat} lonlat
|
|
*
|
|
* @returns An OpenLayers.Pixel which is the passed-in OpenLayers.LonLat,
|
|
* translated into view port pixels
|
|
* @type OpenLayers.Pixel
|
|
*/
|
|
getViewPortPxFromLonLat: function (lonlat) {
|
|
var resolution = this.map.getResolution();
|
|
var extent = this.map.getExtent();
|
|
return new OpenLayers.Pixel(
|
|
Math.round(1/resolution * (lonlat.lon - extent.left)),
|
|
Math.round(1/resolution * (extent.top - lonlat.lat))
|
|
);
|
|
},
|
|
|
|
/** @final @type String */
|
|
CLASS_NAME: "OpenLayers.Layer"
|
|
};
|