| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622 |
- /* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
- /**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Lang.js
- * @requires Rico/Corner.js
- */
- /**
- * Class: OpenLayers.Control.LayerSwitcher
- * The LayerSwitcher control displays a table of contents for the map. This
- * allows the user interface to switch between BaseLasyers and to show or hide
- * Overlays. By default the switcher is shown minimized on the right edge of
- * the map, the user may expand it by clicking on the handle.
- *
- * To create the LayerSwitcher outside of the map, pass the Id of a html div
- * as the first argument to the constructor.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
- OpenLayers.Control.LayerSwitcher =
- OpenLayers.Class(OpenLayers.Control, {
- /**
- * APIProperty: roundedCorner
- * {Boolean} If true the Rico library is used for rounding the corners
- * of the layer switcher div, defaults to true.
- */
- roundedCorner: true,
- /**
- * APIProperty: roundedCornerColor
- * {String} The color of the rounded corners, only applies if roundedCorner
- * is true, defaults to "darkblue".
- */
- roundedCornerColor: "darkblue",
-
- /**
- * Property: layerStates
- * {Array(Object)} Basically a copy of the "state" of the map's layers
- * the last time the control was drawn. We have this in order to avoid
- * unnecessarily redrawing the control.
- */
- layerStates: null,
-
- // DOM Elements
-
- /**
- * Property: layersDiv
- * {DOMElement}
- */
- layersDiv: null,
-
- /**
- * Property: baseLayersDiv
- * {DOMElement}
- */
- baseLayersDiv: null,
- /**
- * Property: baseLayers
- * {Array(<OpenLayers.Layer>)}
- */
- baseLayers: null,
-
-
- /**
- * Property: dataLbl
- * {DOMElement}
- */
- dataLbl: null,
-
- /**
- * Property: dataLayersDiv
- * {DOMElement}
- */
- dataLayersDiv: null,
- /**
- * Property: dataLayers
- * {Array(<OpenLayers.Layer>)}
- */
- dataLayers: null,
- /**
- * Property: minimizeDiv
- * {DOMElement}
- */
- minimizeDiv: null,
- /**
- * Property: maximizeDiv
- * {DOMElement}
- */
- maximizeDiv: null,
-
- /**
- * APIProperty: ascending
- * {Boolean}
- */
- ascending: true,
-
- /**
- * Constructor: OpenLayers.Control.LayerSwitcher
- *
- * Parameters:
- * options - {Object}
- */
- initialize: function(options) {
- OpenLayers.Control.prototype.initialize.apply(this, arguments);
- this.layerStates = [];
- },
- /**
- * APIMethod: destroy
- */
- destroy: function() {
-
- OpenLayers.Event.stopObservingElement(this.div);
- OpenLayers.Event.stopObservingElement(this.minimizeDiv);
- OpenLayers.Event.stopObservingElement(this.maximizeDiv);
- //clear out layers info and unregister their events
- this.clearLayersArray("base");
- this.clearLayersArray("data");
-
- this.map.events.un({
- "addlayer": this.redraw,
- "changelayer": this.redraw,
- "removelayer": this.redraw,
- "changebaselayer": this.redraw,
- scope: this
- });
-
- OpenLayers.Control.prototype.destroy.apply(this, arguments);
- },
- /**
- * Method: setMap
- *
- * Properties:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- OpenLayers.Control.prototype.setMap.apply(this, arguments);
- this.map.events.on({
- "addlayer": this.redraw,
- "changelayer": this.redraw,
- "removelayer": this.redraw,
- "changebaselayer": this.redraw,
- scope: this
- });
- },
- /**
- * Method: draw
- *
- * Returns:
- * {DOMElement} A reference to the DIV DOMElement containing the
- * switcher tabs.
- */
- draw: function() {
- OpenLayers.Control.prototype.draw.apply(this);
- // create layout divs
- this.loadContents();
- // set mode to minimize
- if(!this.outsideViewport) {
- this.minimizeControl();
- }
- // populate div with current info
- this.redraw();
- return this.div;
- },
- /**
- * Method: clearLayersArray
- * User specifies either "base" or "data". we then clear all the
- * corresponding listeners, the div, and reinitialize a new array.
- *
- * Parameters:
- * layersType - {String}
- */
- clearLayersArray: function(layersType) {
- var layers = this[layersType + "Layers"];
- if (layers) {
- for(var i=0, len=layers.length; i<len ; i++) {
- var layer = layers[i];
- OpenLayers.Event.stopObservingElement(layer.inputElem);
- OpenLayers.Event.stopObservingElement(layer.labelSpan);
- }
- }
- this[layersType + "LayersDiv"].innerHTML = "";
- this[layersType + "Layers"] = [];
- },
- /**
- * Method: checkRedraw
- * Checks if the layer state has changed since the last redraw() call.
- *
- * Returns:
- * {Boolean} The layer state changed since the last redraw() call.
- */
- checkRedraw: function() {
- var redraw = false;
- if ( !this.layerStates.length ||
- (this.map.layers.length != this.layerStates.length) ) {
- redraw = true;
- } else {
- for (var i=0, len=this.layerStates.length; i<len; i++) {
- var layerState = this.layerStates[i];
- var layer = this.map.layers[i];
- if ( (layerState.name != layer.name) ||
- (layerState.inRange != layer.inRange) ||
- (layerState.id != layer.id) ||
- (layerState.visibility != layer.visibility) ) {
- redraw = true;
- break;
- }
- }
- }
- return redraw;
- },
-
- /**
- * Method: redraw
- * Goes through and takes the current state of the Map and rebuilds the
- * control to display that state. Groups base layers into a
- * radio-button group and lists each data layer with a checkbox.
- *
- * Returns:
- * {DOMElement} A reference to the DIV DOMElement containing the control
- */
- redraw: function() {
- //if the state hasn't changed since last redraw, no need
- // to do anything. Just return the existing div.
- if (!this.checkRedraw()) {
- return this.div;
- }
- //clear out previous layers
- this.clearLayersArray("base");
- this.clearLayersArray("data");
-
- var containsOverlays = false;
- var containsBaseLayers = false;
-
- // Save state -- for checking layer if the map state changed.
- // We save this before redrawing, because in the process of redrawing
- // we will trigger more visibility changes, and we want to not redraw
- // and enter an infinite loop.
- var len = this.map.layers.length;
- this.layerStates = new Array(len);
- for (var i=0; i <len; i++) {
- var layer = this.map.layers[i];
- this.layerStates[i] = {
- 'name': layer.name,
- 'visibility': layer.visibility,
- 'inRange': layer.inRange,
- 'id': layer.id
- };
- }
- var layers = this.map.layers.slice();
- if (!this.ascending) { layers.reverse(); }
- for(var i=0, len=layers.length; i<len; i++) {
- var layer = layers[i];
- var baseLayer = layer.isBaseLayer;
- if (layer.displayInLayerSwitcher) {
- if (baseLayer) {
- containsBaseLayers = true;
- } else {
- containsOverlays = true;
- }
- // only check a baselayer if it is *the* baselayer, check data
- // layers if they are visible
- var checked = (baseLayer) ? (layer == this.map.baseLayer)
- : layer.getVisibility();
-
- // create input element
- var inputElem = document.createElement("input");
- inputElem.id = this.id + "_input_" + layer.name;
- inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name;
- inputElem.type = (baseLayer) ? "radio" : "checkbox";
- inputElem.value = layer.name;
- inputElem.checked = checked;
- inputElem.defaultChecked = checked;
- if (!baseLayer && !layer.inRange) {
- inputElem.disabled = true;
- }
- var context = {
- 'inputElem': inputElem,
- 'layer': layer,
- 'layerSwitcher': this
- };
- OpenLayers.Event.observe(inputElem, "mouseup",
- OpenLayers.Function.bindAsEventListener(this.onInputClick,
- context)
- );
-
- // create span
- var labelSpan = document.createElement("span");
- OpenLayers.Element.addClass(labelSpan, "labelSpan");
- if (!baseLayer && !layer.inRange) {
- labelSpan.style.color = "gray";
- }
- labelSpan.innerHTML = layer.name;
- labelSpan.style.verticalAlign = (baseLayer) ? "bottom"
- : "baseline";
- OpenLayers.Event.observe(labelSpan, "click",
- OpenLayers.Function.bindAsEventListener(this.onInputClick,
- context)
- );
- // create line break
- var br = document.createElement("br");
-
-
- var groupArray = (baseLayer) ? this.baseLayers
- : this.dataLayers;
- groupArray.push({
- 'layer': layer,
- 'inputElem': inputElem,
- 'labelSpan': labelSpan
- });
-
-
- var groupDiv = (baseLayer) ? this.baseLayersDiv
- : this.dataLayersDiv;
- groupDiv.appendChild(inputElem);
- groupDiv.appendChild(labelSpan);
- groupDiv.appendChild(br);
- }
- }
- // if no overlays, dont display the overlay label
- this.dataLbl.style.display = (containsOverlays) ? "" : "none";
-
- // if no baselayers, dont display the baselayer label
- this.baseLbl.style.display = (containsBaseLayers) ? "" : "none";
- return this.div;
- },
- /**
- * Method:
- * A label has been clicked, check or uncheck its corresponding input
- *
- * Parameters:
- * e - {Event}
- *
- * Context:
- * - {DOMElement} inputElem
- * - {<OpenLayers.Control.LayerSwitcher>} layerSwitcher
- * - {<OpenLayers.Layer>} layer
- */
- onInputClick: function(e) {
- if (!this.inputElem.disabled) {
- if (this.inputElem.type == "radio") {
- this.inputElem.checked = true;
- this.layer.map.setBaseLayer(this.layer);
- } else {
- this.inputElem.checked = !this.inputElem.checked;
- this.layerSwitcher.updateMap();
- }
- }
- OpenLayers.Event.stop(e);
- },
-
- /**
- * Method: onLayerClick
- * Need to update the map accordingly whenever user clicks in either of
- * the layers.
- *
- * Parameters:
- * e - {Event}
- */
- onLayerClick: function(e) {
- this.updateMap();
- },
- /**
- * Method: updateMap
- * Cycles through the loaded data and base layer input arrays and makes
- * the necessary calls to the Map object such that that the map's
- * visual state corresponds to what the user has selected in
- * the control.
- */
- updateMap: function() {
- // set the newly selected base layer
- for(var i=0, len=this.baseLayers.length; i<len; i++) {
- var layerEntry = this.baseLayers[i];
- if (layerEntry.inputElem.checked) {
- this.map.setBaseLayer(layerEntry.layer, false);
- }
- }
- // set the correct visibilities for the overlays
- for(var i=0, len=this.dataLayers.length; i<len; i++) {
- var layerEntry = this.dataLayers[i];
- layerEntry.layer.setVisibility(layerEntry.inputElem.checked);
- }
- },
- /**
- * Method: maximizeControl
- * Set up the labels and divs for the control
- *
- * Parameters:
- * e - {Event}
- */
- maximizeControl: function(e) {
- // set the div's width and height to empty values, so
- // the div dimensions can be controlled by CSS
- this.div.style.width = "";
- this.div.style.height = "";
- this.showControls(false);
- if (e != null) {
- OpenLayers.Event.stop(e);
- }
- },
-
- /**
- * Method: minimizeControl
- * Hide all the contents of the control, shrink the size,
- * add the maximize icon
- *
- * Parameters:
- * e - {Event}
- */
- minimizeControl: function(e) {
- // to minimize the control we set its div's width
- // and height to 0px, we cannot just set "display"
- // to "none" because it would hide the maximize
- // div
- this.div.style.width = "0px";
- this.div.style.height = "0px";
- this.showControls(true);
- if (e != null) {
- OpenLayers.Event.stop(e);
- }
- },
- /**
- * Method: showControls
- * Hide/Show all LayerSwitcher controls depending on whether we are
- * minimized or not
- *
- * Parameters:
- * minimize - {Boolean}
- */
- showControls: function(minimize) {
- this.maximizeDiv.style.display = minimize ? "" : "none";
- this.minimizeDiv.style.display = minimize ? "none" : "";
- this.layersDiv.style.display = minimize ? "none" : "";
- },
-
- /**
- * Method: loadContents
- * Set up the labels and divs for the control
- */
- loadContents: function() {
- //configure main div
- OpenLayers.Event.observe(this.div, "mouseup",
- OpenLayers.Function.bindAsEventListener(this.mouseUp, this));
- OpenLayers.Event.observe(this.div, "click",
- this.ignoreEvent);
- OpenLayers.Event.observe(this.div, "mousedown",
- OpenLayers.Function.bindAsEventListener(this.mouseDown, this));
- OpenLayers.Event.observe(this.div, "dblclick", this.ignoreEvent);
- // layers list div
- this.layersDiv = document.createElement("div");
- this.layersDiv.id = this.id + "_layersDiv";
- OpenLayers.Element.addClass(this.layersDiv, "layersDiv");
- this.baseLbl = document.createElement("div");
- this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer");
- OpenLayers.Element.addClass(this.baseLbl, "baseLbl");
-
- this.baseLayersDiv = document.createElement("div");
- OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv");
- this.dataLbl = document.createElement("div");
- this.dataLbl.innerHTML = OpenLayers.i18n("Overlays");
- OpenLayers.Element.addClass(this.dataLbl, "dataLbl");
-
- this.dataLayersDiv = document.createElement("div");
- OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv");
- if (this.ascending) {
- this.layersDiv.appendChild(this.baseLbl);
- this.layersDiv.appendChild(this.baseLayersDiv);
- this.layersDiv.appendChild(this.dataLbl);
- this.layersDiv.appendChild(this.dataLayersDiv);
- } else {
- this.layersDiv.appendChild(this.dataLbl);
- this.layersDiv.appendChild(this.dataLayersDiv);
- this.layersDiv.appendChild(this.baseLbl);
- this.layersDiv.appendChild(this.baseLayersDiv);
- }
-
- this.div.appendChild(this.layersDiv);
- if(this.roundedCorner) {
- OpenLayers.Rico.Corner.round(this.div, {
- corners: "tl bl",
- bgColor: "transparent",
- color: this.roundedCornerColor,
- blend: false
- });
- OpenLayers.Rico.Corner.changeOpacity(this.layersDiv, 0.75);
- }
- var imgLocation = OpenLayers.Util.getImagesLocation();
- var sz = new OpenLayers.Size(18,18);
- // maximize button div
- var img = imgLocation + 'layer-switcher-maximize.png';
- this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
- "OpenLayers_Control_MaximizeDiv",
- null,
- sz,
- img,
- "absolute");
- OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv");
- this.maximizeDiv.style.display = "none";
- OpenLayers.Event.observe(this.maximizeDiv, "click",
- OpenLayers.Function.bindAsEventListener(this.maximizeControl, this)
- );
-
- this.div.appendChild(this.maximizeDiv);
- // minimize button div
- var img = imgLocation + 'layer-switcher-minimize.png';
- var sz = new OpenLayers.Size(18,18);
- this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
- "OpenLayers_Control_MinimizeDiv",
- null,
- sz,
- img,
- "absolute");
- OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv");
- this.minimizeDiv.style.display = "none";
- OpenLayers.Event.observe(this.minimizeDiv, "click",
- OpenLayers.Function.bindAsEventListener(this.minimizeControl, this)
- );
- this.div.appendChild(this.minimizeDiv);
- },
-
- /**
- * Method: ignoreEvent
- *
- * Parameters:
- * evt - {Event}
- */
- ignoreEvent: function(evt) {
- OpenLayers.Event.stop(evt);
- },
- /**
- * Method: mouseDown
- * Register a local 'mouseDown' flag so that we'll know whether or not
- * to ignore a mouseUp event
- *
- * Parameters:
- * evt - {Event}
- */
- mouseDown: function(evt) {
- this.isMouseDown = true;
- this.ignoreEvent(evt);
- },
- /**
- * Method: mouseUp
- * If the 'isMouseDown' flag has been set, that means that the drag was
- * started from within the LayerSwitcher control, and thus we can
- * ignore the mouseup. Otherwise, let the Event continue.
- *
- * Parameters:
- * evt - {Event}
- */
- mouseUp: function(evt) {
- if (this.isMouseDown) {
- this.isMouseDown = false;
- this.ignoreEvent(evt);
- }
- },
- CLASS_NAME: "OpenLayers.Control.LayerSwitcher"
- });
|