1 /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2 * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3 * full text of the license. */
7 * @requires OpenLayers/Map.js
8 * @requires OpenLayers/Projection.js
12 * Class: OpenLayers.Layer
14 OpenLayers.Layer = OpenLayers.Class({
36 * {Float} The layer's opacity. Float number between 0.0 and 1.0.
41 * APIProperty: alwaysInRange
42 * {Boolean} If a layer's display should not be scale-based, this should
43 * be set to true. This will cause the layer, as an overlay, to always
44 * be 'active', by always returning true from the calculateInRange()
47 * If not explicitly specified for a layer, its value will be
48 * determined on startup in initResolutions() based on whether or not
49 * any scale-specific properties have been set as options on the
50 * layer. If no scale-specific options have been set on the layer, we
51 * assume that it should always be in range.
53 * See #987 for more info.
58 * Constant: EVENT_TYPES
59 * {Array(String)} Supported application event types. Register a listener
60 * for a particular event with the following syntax:
62 * layer.events.register(type, obj, listener);
65 * Listeners will be called with a reference to an event object. The
66 * properties of this event depends on exactly what happened.
68 * All event objects have at least the following properties:
69 * object - {Object} A reference to layer.events.object.
70 * element - {DOMElement} A reference to layer.events.element.
72 * Supported map event types:
73 * loadstart - Triggered when layer loading starts.
74 * loadend - Triggered when layer loading ends.
75 * loadcancel - Triggered when layer loading is canceled.
76 * visibilitychanged - Triggered when layer visibility is changed.
77 * move - Triggered when layer moves (triggered with every mousemove
79 * moveend - Triggered when layer is done moving, object passed as
80 * argument has a zoomChanged boolean property which tells that the
83 EVENT_TYPES: ["loadstart", "loadend", "loadcancel", "visibilitychanged",
88 * {<OpenLayers.Events>}
94 * {<OpenLayers.Map>} This variable is set when the layer is added to
95 * the map, via the accessor function setMap().
100 * APIProperty: isBaseLayer
101 * {Boolean} Whether or not the layer is a base layer. This should be set
102 * individually by all subclasses. Default is false
108 * {Boolean} The layer's images have an alpha channel. Default is false.
113 * APIProperty: displayInLayerSwitcher
114 * {Boolean} Display the layer's name in the layer switcher. Default is
117 displayInLayerSwitcher: true,
120 * APIProperty: visibility
121 * {Boolean} The layer should be displayed in the map. Default is true.
126 * APIProperty: attribution
127 * {String} Attribution string, displayed when an
128 * <OpenLayers.Control.Attribution> has been added to the map.
134 * {Boolean} The current map resolution is within the layer's min/max
135 * range. This is set in <OpenLayers.Map.setCenter> whenever the zoom
142 * {<OpenLayers.Size>} For layers with a gutter, the image is larger than
143 * the tile by twice the gutter in each dimension.
148 * Property: imageOffset
149 * {<OpenLayers.Pixel>} For layers with a gutter, the image offset
150 * represents displacement due to the gutter.
158 * {Object} An optional object whose properties will be set on the layer.
159 * Any of the layer properties can be set as a property of the options
160 * object and sent to the constructor when the layer is created.
165 * APIProperty: eventListeners
166 * {Object} If set as an option at construction, the eventListeners
167 * object will be registered with <OpenLayers.Events.on>. Object
168 * structure must be a listeners object as shown in the example for
169 * the events.on method.
171 eventListeners: null,
174 * APIProperty: gutter
175 * {Integer} Determines the width (in pixels) of the gutter around image
176 * tiles to ignore. By setting this property to a non-zero value,
177 * images will be requested that are wider and taller than the tile
178 * size by a value of 2 x gutter. This allows artifacts of rendering
179 * at tile edges to be ignored. Set a gutter value that is equal to
180 * half the size of the widest symbol that needs to be displayed.
181 * Defaults to zero. Non-tiled layers always have zero gutter.
186 * APIProperty: projection
187 * {<OpenLayers.Projection>} or {<String>} Set in the layer options to
188 * override the default projection string this layer - also set maxExtent,
189 * maxResolution, and units if appropriate. Can be either a string or
190 * an <OpenLayers.Projection> object when created -- will be converted
191 * to an object when setMap is called if a string is passed.
197 * {String} The layer map units. Defaults to 'degrees'. Possible values
198 * are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
203 * APIProperty: scales
204 * {Array} An array of map scales in descending order. The values in the
205 * array correspond to the map scale denominator. Note that these
206 * values only make sense if the display (monitor) resolution of the
207 * client is correctly guessed by whomever is configuring the
208 * application. In addition, the units property must also be set.
209 * Use <resolutions> instead wherever possible.
214 * APIProperty: resolutions
215 * {Array} A list of map resolutions (map units per pixel) in descending
216 * order. If this is not set in the layer constructor, it will be set
217 * based on other resolution related properties (maxExtent,
218 * maxResolution, maxScale, etc.).
223 * APIProperty: maxExtent
224 * {<OpenLayers.Bounds>} The center of these bounds will not stray outside
225 * of the viewport extent during panning. In addition, if
226 * <displayOutsideMaxExtent> is set to false, data will not be
227 * requested that falls completely outside of these bounds.
232 * APIProperty: minExtent
233 * {<OpenLayers.Bounds>}
238 * APIProperty: maxResolution
239 * {Float} Default max is 360 deg / 256 px, which corresponds to
240 * zoom level 0 on gmaps. Specify a different value in the layer
241 * options if you are not using a geographic projection and
242 * displaying the whole world.
247 * APIProperty: minResolution
253 * APIProperty: numZoomLevels
259 * APIProperty: minScale
265 * APIProperty: maxScale
271 * APIProperty: displayOutsideMaxExtent
272 * {Boolean} Request map tiles that are completely outside of the max
273 * extent for this layer. Defaults to false.
275 displayOutsideMaxExtent: false,
278 * APIProperty: wrapDateLine
279 * {Boolean} #487 for more info.
284 * APIProperty: transitionEffect
285 * {String} The transition effect to use when the map is panned or
288 * There are currently two supported values:
289 * - *null* No transition effect (the default).
290 * - *resize* Existing tiles are resized on zoom to provide a visual
291 * effect of the zoom having taken place immediately. As the
292 * new tiles become available, they are drawn over top of the
295 transitionEffect: null,
298 * Property: SUPPORTED_TRANSITIONS
299 * {Array} An immutable (that means don't change it!) list of supported
300 * transitionEffect values.
302 SUPPORTED_TRANSITIONS: ['resize'],
305 * Constructor: OpenLayers.Layer
308 * name - {String} The layer name
309 * options - {Object} Hashtable of extra options to tag onto the layer
311 initialize: function(name, options) {
313 this.addOptions(options);
317 if (this.id == null) {
319 this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
321 this.div = OpenLayers.Util.createDiv(this.id);
322 this.div.style.width = "100%";
323 this.div.style.height = "100%";
324 this.div.dir = "ltr";
326 this.events = new OpenLayers.Events(this, this.div,
328 if(this.eventListeners instanceof Object) {
329 this.events.on(this.eventListeners);
334 if (this.wrapDateLine) {
335 this.displayOutsideMaxExtent = true;
341 * Destroy is a destructor: this is to alleviate cyclic references which
342 * the Javascript garbage cleaner can not take care of on its own.
345 * setNewBaseLayer - {Boolean} Set a new base layer when this layer has
346 * been destroyed. Default is true.
348 destroy: function(setNewBaseLayer) {
349 if (setNewBaseLayer == null) {
350 setNewBaseLayer = true;
352 if (this.map != null) {
353 this.map.removeLayer(this, setNewBaseLayer);
355 this.projection = null;
362 if(this.eventListeners) {
363 this.events.un(this.eventListeners);
365 this.events.destroy();
367 this.eventListeners = null;
375 * obj - {<OpenLayers.Layer>} The layer to be cloned
378 * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer>
380 clone: function (obj) {
383 obj = new OpenLayers.Layer(this.name, this.options);
386 // catch any randomly tagged-on properties
387 OpenLayers.Util.applyDefaults(obj, this);
389 // a cloned layer should never have its map property set
390 // because it has not been added to a map yet.
398 * Sets the new layer name for this layer. Can trigger a changelayer event
402 * newName - {String} The new name.
404 setName: function(newName) {
405 if (newName != this.name) {
407 if (this.map != null) {
408 this.map.events.triggerEvent("changelayer", {
417 * APIMethod: addOptions
420 * newOptions - {Object}
422 addOptions: function (newOptions) {
424 if (this.options == null) {
428 // update our copy for clone
429 OpenLayers.Util.extend(this.options, newOptions);
431 // add new options to this
432 OpenLayers.Util.extend(this, newOptions);
436 * APIMethod: onMapResize
437 * This function can be implemented by subclasses
439 onMapResize: function() {
440 //this function can be implemented by subclasses
445 * Redraws the layer. Returns true if the layer was redrawn, false if not.
448 * {Boolean} The layer was redrawn.
454 // min/max Range may have changed
455 this.inRange = this.calculateInRange();
457 // map's center might not yet be set
458 var extent = this.getExtent();
460 if (extent && this.inRange && this.visibility) {
461 var zoomChanged = true;
462 this.moveTo(extent, zoomChanged, false);
463 this.events.triggerEvent("moveend",
464 {"zoomChanged": zoomChanged});
475 * bound - {<OpenLayers.Bounds>}
476 * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
477 * do some init work in that case.
478 * dragging - {Boolean}
480 moveTo:function(bounds, zoomChanged, dragging) {
481 var display = this.visibility;
482 if (!this.isBaseLayer) {
483 display = display && this.inRange;
485 this.display(display);
490 * Set the map property for the layer. This is done through an accessor
491 * so that subclasses can override this and take special action once
492 * they have their map variable set.
494 * Here we take care to bring over any of the necessary default
495 * properties from the map.
498 * map - {<OpenLayers.Map>}
500 setMap: function(map) {
501 if (this.map == null) {
505 // grab some essential layer data from the map if it hasn't already
507 this.maxExtent = this.maxExtent || this.map.maxExtent;
508 this.projection = this.projection || this.map.projection;
510 if (this.projection && typeof this.projection == "string") {
511 this.projection = new OpenLayers.Projection(this.projection);
514 // Check the projection to see if we can get units -- if not, refer
516 this.units = this.projection.getUnits() ||
517 this.units || this.map.units;
519 this.initResolutions();
521 if (!this.isBaseLayer) {
522 this.inRange = this.calculateInRange();
523 var show = ((this.visibility) && (this.inRange));
524 this.div.style.display = show ? "" : "none";
534 * Called at the end of the map.addLayer sequence. At this point, the map
535 * will have a base layer. To be overridden by subclasses.
537 afterAdd: function() {
541 * APIMethod: removeMap
542 * Just as setMap() allows each layer the possibility to take a
543 * personalized action on being added to the map, removeMap() allows
544 * each layer to take a personalized action on being removed from it.
545 * For now, this will be mostly unused, except for the EventPane layer,
546 * which needs this hook so that it can remove the special invisible
550 * map - {<OpenLayers.Map>}
552 removeMap: function(map) {
553 //to be overridden by subclasses
557 * APIMethod: getImageSize
560 * {<OpenLayers.Size>} The size that the image should be, taking into
563 getImageSize: function() {
564 return (this.imageSize || this.tileSize);
568 * APIMethod: setTileSize
569 * Set the tile size based on the map size. This also sets layer.imageSize
570 * and layer.imageOffset for use by Tile.Image.
573 * size - {<OpenLayers.Size>}
575 setTileSize: function(size) {
576 var tileSize = (size) ? size :
577 ((this.tileSize) ? this.tileSize :
578 this.map.getTileSize());
579 this.tileSize = tileSize;
581 // layers with gutters need non-null tile sizes
582 //if(tileSize == null) {
583 // OpenLayers.console.error("Error in layer.setMap() for " +
584 // this.name + ": layers with " +
585 // "gutters need non-null tile sizes");
587 this.imageOffset = new OpenLayers.Pixel(-this.gutter,
589 this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter),
590 tileSize.h + (2*this.gutter));
595 * APIMethod: getVisibility
598 * {Boolean} The layer should be displayed (if in range).
600 getVisibility: function() {
601 return this.visibility;
605 * APIMethod: setVisibility
606 * Set the visibility flag for the layer and hide/show & redraw
607 * accordingly. Fire event unless otherwise specified
609 * Note that visibility is no longer simply whether or not the layer's
610 * style.display is set to "block". Now we store a 'visibility' state
611 * property on the layer class, this allows us to remember whether or
612 * not we *desire* for a layer to be visible. In the case where the
613 * map's resolution is out of the layer's range, this desire may be
617 * visible - {Boolean} Whether or not to display the layer (if in range)
619 setVisibility: function(visibility) {
620 if (visibility != this.visibility) {
621 this.visibility = visibility;
622 this.display(visibility);
624 if (this.map != null) {
625 this.map.events.triggerEvent("changelayer", {
627 property: "visibility"
630 this.events.triggerEvent("visibilitychanged");
636 * Hide or show the Layer
639 * display - {Boolean}
641 display: function(display) {
642 var inRange = this.calculateInRange();
643 if (display != (this.div.style.display != "none")) {
644 this.div.style.display = (display && inRange) ? "block" : "none";
649 * APIMethod: calculateInRange
652 * {Boolean} The layer is displayable at the current map's current
653 * resolution. Note that if 'alwaysInRange' is true for the layer,
654 * this function will always return true.
656 calculateInRange: function() {
659 if (this.alwaysInRange) {
663 var resolution = this.map.getResolution();
664 inRange = ( (resolution >= this.minResolution) &&
665 (resolution <= this.maxResolution) );
672 * APIMethod: setIsBaseLayer
675 * isBaseLayer - {Boolean}
677 setIsBaseLayer: function(isBaseLayer) {
678 if (isBaseLayer != this.isBaseLayer) {
679 this.isBaseLayer = isBaseLayer;
680 if (this.map != null) {
681 this.map.events.triggerEvent("changebaselayer", {
688 /********************************************************/
690 /* Baselayer Functions */
692 /********************************************************/
695 * Method: initResolutions
696 * This method's responsibility is to set up the 'resolutions' array
697 * for the layer -- this array is what the layer will use to interface
698 * between the zoom levels of the map and the resolution display
701 * The user has several options that determine how the array is set up.
703 * For a detailed explanation, see the following wiki from the
704 * openlayers.org homepage:
705 * http://trac.openlayers.org/wiki/SettingZoomLevels
707 initResolutions: function() {
709 // These are the relevant options which are used for calculating
710 // resolutions information.
712 var props = new Array(
713 'projection', 'units',
714 'scales', 'resolutions',
715 'maxScale', 'minScale',
716 'maxResolution', 'minResolution',
717 'minExtent', 'maxExtent',
718 'numZoomLevels', 'maxZoomLevel'
721 //these are the properties which do *not* imply that user wishes
722 // this layer to be scale-dependant
723 var notScaleProps = ['projection', 'units'];
725 //should the layer be scale-dependant? default is false -- this will
726 // only be set true if we find that the user has specified a property
727 // from the 'props' array that is not in 'notScaleProps'
728 var useInRange = false;
730 // First we create a new object where we will store all of the
731 // resolution-related properties that we find in either the layer's
732 // 'options' array or from the map.
735 for(var i=0, len=props.length; i<len; i++) {
736 var property = props[i];
738 // If the layer had one of these properties set *and* it is
739 // a scale property (is not a non-scale property), then we assume
740 // the user did intend to use scale-dependant display (useInRange).
741 if (this.options[property] &&
742 OpenLayers.Util.indexOf(notScaleProps, property) == -1) {
746 confProps[property] = this.options[property] || this.map[property];
749 //only automatically set 'alwaysInRange' if the user hasn't already
750 // set it (to true or false, since the default is null). If user did
751 // not intend to use scale-dependant display then we set they layer
752 // as alwaysInRange. This means calculateInRange() will always return
753 // true and the layer will never be turned off due to scale changes.
755 if (this.alwaysInRange == null) {
756 this.alwaysInRange = !useInRange;
759 // Do not use the scales array set at the map level if
760 // either minScale or maxScale or both are set at the
762 if ((this.options.minScale != null ||
763 this.options.maxScale != null) &&
764 this.options.scales == null) {
766 confProps.scales = null;
768 // Do not use the resolutions array set at the map level if
769 // either minResolution or maxResolution or both are set at the
771 if ((this.options.minResolution != null ||
772 this.options.maxResolution != null) &&
773 this.options.resolutions == null) {
775 confProps.resolutions = null;
778 // If numZoomLevels hasn't been set and the maxZoomLevel *has*,
779 // then use maxZoomLevel to calculate numZoomLevels
781 if ( (!confProps.numZoomLevels) && (confProps.maxZoomLevel) ) {
782 confProps.numZoomLevels = confProps.maxZoomLevel + 1;
785 // First off, we take whatever hodge-podge of values we have and
786 // calculate/distill them down into a resolutions[] array
788 if ((confProps.scales != null) || (confProps.resolutions != null)) {
790 if (confProps.scales != null) {
791 confProps.resolutions = [];
792 for(var i=0, len=confProps.scales.length; i<len; i++) {
793 var scale = confProps.scales[i];
794 confProps.resolutions[i] =
795 OpenLayers.Util.getResolutionFromScale(scale,
799 confProps.numZoomLevels = confProps.resolutions.length;
802 //maxResolution and numZoomLevels based calculation
804 // determine maxResolution
805 if (confProps.minScale) {
806 confProps.maxResolution =
807 OpenLayers.Util.getResolutionFromScale(confProps.minScale,
809 } else if (confProps.maxResolution == "auto") {
810 var viewSize = this.map.getSize();
811 var wRes = confProps.maxExtent.getWidth() / viewSize.w;
812 var hRes = confProps.maxExtent.getHeight()/ viewSize.h;
813 confProps.maxResolution = Math.max(wRes, hRes);
816 // determine minResolution
817 if (confProps.maxScale != null) {
818 confProps.minResolution =
819 OpenLayers.Util.getResolutionFromScale(confProps.maxScale,
821 } else if ( (confProps.minResolution == "auto") &&
822 (confProps.minExtent != null) ) {
823 var viewSize = this.map.getSize();
824 var wRes = confProps.minExtent.getWidth() / viewSize.w;
825 var hRes = confProps.minExtent.getHeight()/ viewSize.h;
826 confProps.minResolution = Math.max(wRes, hRes);
829 // determine numZoomLevels if not already set on the layer
830 // this gives numZoomLevels assuming approximately base 2 scaling
831 if (confProps.minResolution != null &&
832 this.options.numZoomLevels == undefined) {
833 var ratio = confProps.maxResolution / confProps.minResolution;
834 confProps.numZoomLevels =
835 Math.floor(Math.log(ratio) / Math.log(2)) + 1;
838 // now we have numZoomLevels and maxResolution,
839 // we can populate the resolutions array
840 confProps.resolutions = new Array(confProps.numZoomLevels);
842 if(typeof confProps.minResolution == "number" &&
843 confProps.numZoomLevels > 1) {
845 * If maxResolution and minResolution are set (or related
846 * scale properties), we calculate the base for exponential
847 * scaling that starts at maxResolution and ends at
848 * minResolution in numZoomLevels steps.
851 (confProps.maxResolution / confProps.minResolution),
852 (1 / (confProps.numZoomLevels - 1))
855 for (var i=0; i < confProps.numZoomLevels; i++) {
856 var res = confProps.maxResolution / Math.pow(base, i);
857 confProps.resolutions[i] = res;
861 //sort resolutions array ascendingly
863 confProps.resolutions.sort( function(a, b) { return(b-a); } );
865 // now set our newly calculated values back to the layer
866 // Note: We specifically do *not* set them to layer.options, which we
867 // will preserve as it was when we added this layer to the map.
868 // this way cloned layers reset themselves to new map div
872 this.resolutions = confProps.resolutions;
873 this.maxResolution = confProps.resolutions[0];
874 var lastIndex = confProps.resolutions.length - 1;
875 this.minResolution = confProps.resolutions[lastIndex];
878 for(var i=0, len=confProps.resolutions.length; i<len; i++) {
880 OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i],
883 this.minScale = this.scales[0];
884 this.maxScale = this.scales[this.scales.length - 1];
886 this.numZoomLevels = confProps.numZoomLevels;
890 * APIMethod: getResolution
893 * {Float} The currently selected resolution of the map, taken from the
894 * resolutions array, indexed by current zoom level.
896 getResolution: function() {
897 var zoom = this.map.getZoom();
898 return this.getResolutionForZoom(zoom);
902 * APIMethod: getExtent
905 * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
906 * bounds of the current viewPort.
908 getExtent: function() {
909 // just use stock map calculateBounds function -- passing no arguments
910 // means it will user map's current center & resolution
912 return this.map.calculateBounds();
916 * APIMethod: getZoomForExtent
919 * bounds - {<OpenLayers.Bounds>}
920 * closest - {Boolean} Find the zoom level that most closely fits the
921 * specified bounds. Note that this may result in a zoom that does
922 * not exactly contain the entire extent.
926 * {Integer} The index of the zoomLevel (entry in the resolutions array)
927 * for the passed-in extent. We do this by calculating the ideal
928 * resolution for the given extent (based on the map size) and then
929 * calling getZoomForResolution(), passing along the 'closest'
932 getZoomForExtent: function(extent, closest) {
933 var viewSize = this.map.getSize();
934 var idealResolution = Math.max( extent.getWidth() / viewSize.w,
935 extent.getHeight() / viewSize.h );
937 return this.getZoomForResolution(idealResolution, closest);
941 * Method: getDataExtent
942 * Calculates the max extent which includes all of the data for the layer.
943 * This function is to be implemented by subclasses.
946 * {<OpenLayers.Bounds>}
948 getDataExtent: function () {
949 //to be implemented by subclasses
953 * APIMethod: getResolutionForZoom
959 * {Float} A suitable resolution for the specified zoom.
961 getResolutionForZoom: function(zoom) {
962 zoom = Math.max(0, Math.min(zoom, this.resolutions.length - 1));
964 if(this.map.fractionalZoom) {
965 var low = Math.floor(zoom);
966 var high = Math.ceil(zoom);
967 resolution = this.resolutions[low] -
968 ((zoom-low) * (this.resolutions[low]-this.resolutions[high]));
970 resolution = this.resolutions[Math.round(zoom)];
976 * APIMethod: getZoomForResolution
979 * resolution - {Float}
980 * closest - {Boolean} Find the zoom level that corresponds to the absolute
981 * closest resolution, which may result in a zoom whose corresponding
982 * resolution is actually smaller than we would have desired (if this
983 * is being called from a getZoomForExtent() call, then this means that
984 * the returned zoom index might not actually contain the entire
985 * extent specified... but it'll be close).
989 * {Integer} The index of the zoomLevel (entry in the resolutions array)
990 * that corresponds to the best fit resolution given the passed in
991 * value and the 'closest' specification.
993 getZoomForResolution: function(resolution, closest) {
995 if(this.map.fractionalZoom) {
997 var highZoom = this.resolutions.length - 1;
998 var highRes = this.resolutions[lowZoom];
999 var lowRes = this.resolutions[highZoom];
1001 for(var i=0, len=this.resolutions.length; i<len; ++i) {
1002 res = this.resolutions[i];
1003 if(res >= resolution) {
1007 if(res <= resolution) {
1013 var dRes = highRes - lowRes;
1015 zoom = lowZoom + ((highRes - resolution) / dRes);
1021 var minDiff = Number.POSITIVE_INFINITY;
1022 for(var i=0, len=this.resolutions.length; i<len; i++) {
1024 diff = Math.abs(this.resolutions[i] - resolution);
1025 if (diff > minDiff) {
1030 if (this.resolutions[i] < resolution) {
1035 zoom = Math.max(0, i-1);
1041 * APIMethod: getLonLatFromViewPortPx
1044 * viewPortPx - {<OpenLayers.Pixel>}
1047 * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in
1048 * view port <OpenLayers.Pixel>, translated into lon/lat by the layer.
1050 getLonLatFromViewPortPx: function (viewPortPx) {
1052 if (viewPortPx != null) {
1053 var size = this.map.getSize();
1054 var center = this.map.getCenter();
1056 var res = this.map.getResolution();
1058 var delta_x = viewPortPx.x - (size.w / 2);
1059 var delta_y = viewPortPx.y - (size.h / 2);
1061 lonlat = new OpenLayers.LonLat(center.lon + delta_x * res ,
1062 center.lat - delta_y * res);
1064 if (this.wrapDateLine) {
1065 lonlat = lonlat.wrapDateLine(this.maxExtent);
1067 } // else { DEBUG STATEMENT }
1073 * APIMethod: getViewPortPxFromLonLat
1074 * Returns a pixel location given a map location. This method will return
1075 * fractional pixel values.
1078 * lonlat - {<OpenLayers.LonLat>}
1081 * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in
1082 * <OpenLayers.LonLat>,translated into view port pixels.
1084 getViewPortPxFromLonLat: function (lonlat) {
1086 if (lonlat != null) {
1087 var resolution = this.map.getResolution();
1088 var extent = this.map.getExtent();
1089 px = new OpenLayers.Pixel(
1090 (1/resolution * (lonlat.lon - extent.left)),
1091 (1/resolution * (extent.top - lonlat.lat))
1098 * APIMethod: setOpacity
1099 * Sets the opacity for the entire layer (all images)
1104 setOpacity: function(opacity) {
1105 if (opacity != this.opacity) {
1106 this.opacity = opacity;
1107 for(var i=0, len=this.div.childNodes.length; i<len; ++i) {
1108 var element = this.div.childNodes[i].firstChild;
1109 OpenLayers.Util.modifyDOMElement(element, null, null, null,
1110 null, null, null, opacity);
1119 * {Integer} the z-index of this layer
1121 getZIndex: function () {
1122 return this.div.style.zIndex;
1129 * zIndex - {Integer}
1131 setZIndex: function (zIndex) {
1132 this.div.style.zIndex = zIndex;
1136 * Method: adjustBounds
1137 * This function will take a bounds, and if wrapDateLine option is set
1138 * on the layer, it will return a bounds which is wrapped around the
1139 * world. We do not wrap for bounds which *cross* the
1140 * maxExtent.left/right, only bounds which are entirely to the left
1141 * or entirely to the right.
1144 * bounds - {<OpenLayers.Bounds>}
1146 adjustBounds: function (bounds) {
1149 // Adjust the extent of a bounds in map units by the
1150 // layer's gutter in pixels.
1151 var mapGutter = this.gutter * this.map.getResolution();
1152 bounds = new OpenLayers.Bounds(bounds.left - mapGutter,
1153 bounds.bottom - mapGutter,
1154 bounds.right + mapGutter,
1155 bounds.top + mapGutter);
1158 if (this.wrapDateLine) {
1159 // wrap around the date line, within the limits of rounding error
1160 var wrappingOptions = {
1161 'rightTolerance':this.getResolution()
1163 bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
1169 CLASS_NAME: "OpenLayers.Layer"