/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license. * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt * for the full text of the license. */ /** * @requires OpenLayers/Control.js * * Class: OpenLayers.Control.LayerSwitcher * * Inherits from: * - */ OpenLayers.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { /** * Property: activeColor * {String} */ activeColor: "darkblue", // DOM Elements /** * Property: layersDiv * {DOMElement} */ layersDiv: null, /** * Property: baseLayersDiv * {DOMElement} */ baseLayersDiv: null, /** * Property: baseLayers * {Array()} */ baseLayers: null, /** * Property: dataLbl * {DOMElement} */ dataLbl: null, /** * Property: dataLayersDiv * {DOMElement} */ dataLayersDiv: null, /** * Property: dataLayers * {Array()} */ 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); }, /** * 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.unregister("addlayer", this, this.redraw); this.map.events.unregister("changelayer", this, this.redraw); this.map.events.unregister("removelayer", this, this.redraw); this.map.events.unregister("changebaselayer", this, this.redraw); OpenLayers.Control.prototype.destroy.apply(this, arguments); }, /** * Method: setMap * * Properties: * map - {} */ setMap: function(map) { OpenLayers.Control.prototype.setMap.apply(this, arguments); this.map.events.register("addlayer", this, this.redraw); this.map.events.register("changelayer", this, this.redraw); this.map.events.register("removelayer", this, this.redraw); this.map.events.register("changebaselayer", this, this.redraw); }, /** * 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; i < layers.length; i++) { var layer = layers[i]; OpenLayers.Event.stopObservingElement(layer.inputElem); OpenLayers.Event.stopObservingElement(layer.labelSpan); } } this[layersType + "LayersDiv"].innerHTML = ""; this[layersType + "Layers"] = []; }, /** * 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() { //clear out previous layers this.clearLayersArray("base"); this.clearLayersArray("data"); var containsOverlays = false; var containsBaseLayers = false; var layers = this.map.layers.slice(); if (!this.ascending) { layers.reverse(); } for( var i = 0; i < layers.length; 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 = "input_" + layer.name; inputElem.name = (baseLayer) ? "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", this.onInputClick.bindAsEventListener(context)); // create span var labelSpan = document.createElement("span"); if (!baseLayer && !layer.inRange) { labelSpan.style.color = "gray"; } labelSpan.innerHTML = layer.name; labelSpan.style.verticalAlign = (baseLayer) ? "bottom" : "baseline"; OpenLayers.Event.observe(labelSpan, "click", this.onInputClick.bindAsEventListener(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 * - {} layerSwitcher * - {} layer */ onInputClick: function(e) { if (!this.inputElem.disabled) { if (this.inputElem.type == "radio") { this.inputElem.checked = true; this.layer.map.setBaseLayer(this.layer, true); this.layer.map.events.triggerEvent("changebaselayer"); } 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; i < this.baseLayers.length; 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; i < this.dataLayers.length; i++) { var layerEntry = this.dataLayers[i]; layerEntry.layer.setVisibility(layerEntry.inputElem.checked, true); } }, /** * Method: maximizeControl * Set up the labels and divs for the control * * Parameters: * e - {Event} */ maximizeControl: function(e) { //HACK HACK HACK - find a way to auto-size this layerswitcher this.div.style.width = "20em"; 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) { 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 this.div.style.position = "absolute"; this.div.style.top = "25px"; this.div.style.right = "0px"; this.div.style.left = ""; this.div.style.fontFamily = "sans-serif"; this.div.style.fontWeight = "bold"; this.div.style.marginTop = "3px"; this.div.style.marginLeft = "3px"; this.div.style.marginBottom = "3px"; this.div.style.fontSize = "smaller"; this.div.style.color = "white"; this.div.style.backgroundColor = "transparent"; OpenLayers.Event.observe(this.div, "mouseup", this.mouseUp.bindAsEventListener(this)); OpenLayers.Event.observe(this.div, "click", this.ignoreEvent); OpenLayers.Event.observe(this.div, "mousedown", this.mouseDown.bindAsEventListener(this)); OpenLayers.Event.observe(this.div, "dblclick", this.ignoreEvent); // layers list div this.layersDiv = document.createElement("div"); this.layersDiv.id = "layersDiv"; this.layersDiv.style.paddingTop = "5px"; this.layersDiv.style.paddingLeft = "10px"; this.layersDiv.style.paddingBottom = "5px"; this.layersDiv.style.paddingRight = "75px"; this.layersDiv.style.backgroundColor = this.activeColor; // had to set width/height to get transparency in IE to work. // thanks -- http://jszen.blogspot.com/2005/04/ie6-opacity-filter-caveat.html // this.layersDiv.style.width = "100%"; this.layersDiv.style.height = "100%"; this.baseLbl = document.createElement("div"); this.baseLbl.innerHTML = "Base Layer"; this.baseLbl.style.marginTop = "3px"; this.baseLbl.style.marginLeft = "3px"; this.baseLbl.style.marginBottom = "3px"; this.baseLayersDiv = document.createElement("div"); this.baseLayersDiv.style.paddingLeft = "10px"; /*OpenLayers.Event.observe(this.baseLayersDiv, "click", this.onLayerClick.bindAsEventListener(this)); */ this.dataLbl = document.createElement("div"); this.dataLbl.innerHTML = "Overlays"; this.dataLbl.style.marginTop = "3px"; this.dataLbl.style.marginLeft = "3px"; this.dataLbl.style.marginBottom = "3px"; this.dataLayersDiv = document.createElement("div"); this.dataLayersDiv.style.paddingLeft = "10px"; 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); OpenLayers.Rico.Corner.round(this.div, {corners: "tl bl", bgColor: "transparent", color: this.activeColor, 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"); this.maximizeDiv.style.top = "5px"; this.maximizeDiv.style.right = "0px"; this.maximizeDiv.style.left = ""; this.maximizeDiv.style.display = "none"; OpenLayers.Event.observe(this.maximizeDiv, "click", this.maximizeControl.bindAsEventListener(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"); this.minimizeDiv.style.top = "5px"; this.minimizeDiv.style.right = "0px"; this.minimizeDiv.style.left = ""; this.minimizeDiv.style.display = "none"; OpenLayers.Event.observe(this.minimizeDiv, "click", this.minimizeControl.bindAsEventListener(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" });