/*
* Copyright (c) 2013 Bundesamt für Kartographie und Geodäsie.
* See license.txt in the BKG WebMap distribution or repository for the
* full text of the license.
*
* Author: Dirk Thalheim
*/
/**
* @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/BaseTypes/Element.js
* @requires OpenLayers/Util.js
* @requires OpenLayers/Control.js
* @requires OpenLayers/Events.js
* @requires OpenLayers/Layer/WMS.js
* @requires BKGWebMap/Control.js
* @requires BKGWebMap/Util.js
*/
/**
* @classdesc Control zur Anzeige von Layerlegenden.
*
* Sofern ein Layer über ein Attribut legendURL verfügt, wird dieses als Bild
* in den Container eingefügt.
*
* @constructor BKGWebMap.Control.Legend
* @param {object} options - Optionen für das Controlelement
*/
BKGWebMap.Control.Legend = OpenLayers.Class(OpenLayers.Control, {
/**
* Eventhandler
* @memberOf BKGWebMap.Control.Legend
* @type OpenLayers.Events
*/
events: null,
/**
* Legenden-Titel
* @memberOf BKGWebMap.Control.Legend
* @type HTMLElement
*/
legendTitle: null,
/**
* Container für Legenden
* @memberOf BKGWebMap.Control.Legend
* @type HTMLElement
*/
legendsContainer: null,
/**
* Höhe für Legendengrafik. -1 für automatisch vom Server
* @memberOf BKGWebMap.Control.Legend
* @type int
*/
legendHeight: -1,
/**
* Breite für Legendengrafik. -1 für automatisch vom Server
* @memberOf BKGWebMap.Control.Legend
* @type int
*/
legendWidth: -1,
/**
* Texte für Labels
* @memberOf BKGWebMap.Control.Legend
* @type object
*/
labels: {
/** Titel der Legende. */
title : 'Legende',
/** Prefix für Layername in Legende */
layerPrefix: 'Layer: '
},
initialize: function(options) {
OpenLayers.Control.prototype.initialize.apply(this, [options]);
this.layerStates = [];
},
destroy: function() {
this.map.events.un({
buttonclick: this.onButtonClick,
addlayer: this.redraw,
changelayer: this.redraw,
removelayer: this.redraw,
changebaselayer: this.redraw,
scope: this
});
OpenLayers.Control.prototype.destroy.apply(this, arguments);
},
/**
* Registriert Control für Layer-Map-Events
* @param {OpenLayers.Map}map
* @memberOf BKGWebMap.Control.Legend
*/
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
});
},
/**
* Erstellt die Legende für alle Layer in der Karte
*
* @return {HTMLElement} Eine Referenz zum DOMElement welches die Legende beinhaltet.
* @memberOf BKGWebMap.Control.Legend
*/
draw: function() {
var div = OpenLayers.Control.prototype.draw.apply(this);
this.legendTitle = document.createElement('h2');
this.legendTitle.innerHTML = this.labels.title;
OpenLayers.Element.addClass(this.legendTitle, 'closed');
div.appendChild(this.legendTitle);
// Click auf Titel öffnet Legende
OpenLayers.Event.observe(this.legendTitle, "click", OpenLayers.Function.bindAsEventListener(this.toggle, this));
// get legend graphics
this.legendsContainer = document.createElement('dl');
OpenLayers.Element.addClass(this.legendsContainer, this.displayClass + 'Legends');
OpenLayers.Element.addClass(this.legendsContainer, 'hidden');
div.appendChild(this.legendsContainer);
this.redraw();
this.registerEvents();
return div;
},
/**
* Überprüft ob sich der Status der Layer seit dem letzten redraw-Aufruf geändert hat.
*
* @return {boolean} <code>true</code> Bei Änderung des Status.
* @memberOf BKGWebMap.Control.Legend
*/
checkRedraw: function() {
if ( !this.layerStates.length || (this.map.layers.length != this.layerStates.length) ) {
return true;
}
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.id != layer.id) ||
(layerState.visibility != layer.visibility) ) {
return true;
}
}
return false;
},
/**
* Erstellt den dynamischen Inhalt, der abhängig von Layeränderungen, etc. ist.
* @memberOf BKGWebMap.Control.Legend
*/
redraw: function () {
// Sofern sich der Status der Layer nicht geändert hat, ist nichts zu tun.
if (!this.checkRedraw()) {
return;
}
// Ermittle die aktuellen Stati der Layer
this.layerStates = BKGWebMap.Util.map(function(layer) {
return { name: layer.name, id: layer.id, visibility:layer.visibility };
}, this.map.layers);
// Redraw
this.legendsContainer.innerHTML = "";
BKGWebMap.Util.each(this.map.layers, OpenLayers.Function.bind(
function(index, layer) {
if(!layer.legendURL && !(layer instanceof OpenLayers.Layer.WMS))
return;
if(!layer.visibility)
return;
var dt = document.createElement('dt');
dt.innerHTML = layer.name;
this.legendsContainer.appendChild(dt);
var legendWrapper = document.createElement('dd');
this.legendsContainer.appendChild(legendWrapper);
var legendGraphics = this.createLegendGraphics(layer);
BKGWebMap.Util.each(legendGraphics, OpenLayers.Function.bind( function(index, item) { this.appendChild(item); }, legendWrapper) );
}, this
));
},
/**
* Erzeugt die Legendenvisualisierungen für den gegebenen Layer. Dazu muss im Layer legendURL gegeben sein, oder
* es handelt sich um einen WMS-Layer. Dann wird mit GetLegendGraphic gearbeitet.
*
* @param layer
* @return {Array<HTMLElement>} Liste an Legendengraphiken
* @memberOf BKGWebMap.Control.Legend
*/
createLegendGraphics: function(layer) {
var imgSources;
var baseURL = layer.url + '?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&FORMAT=image/png';
if(this.legendHeight > 0)
baseURL += '&HEIGH=' + this.legendHeight;
if(this.legendWidth > 0)
baseURL += '&WIDTH=' + this.legendWidth;
baseURL += '&LAYER=';
if (layer.legendURL) {
// prefer a given legendURL
imgSources = [{url: layer.legendURL, name: layer.name}];
} else if ( layer instanceof BKGWebMap.Layer.WMS ) {
var layers = BKGWebMap.Util.grep( layer.layers, function(item, i) { return item.active } );
imgSources = BKGWebMap.Util.map( function(layer) {
var url = baseURL + layer.name;
if(layer.style)
url = url + '&STYLE=' + layer.style;
return {url: url, name: layer.title, description: layer.title };
}, layers );
} else if ( layer instanceof OpenLayers.Layer.WMS ) {
var layers = layer.params.LAYERS.split(',');
// TODO: add var styles = layer.params.STYLES.split(',');
var layerPrefix = this.labels.layerPrefix;
imgSources = BKGWebMap.Util.map( function(layer) {
return {url: baseURL + layer, name: layer, description: layerPrefix + layer };
}, layers );
}
return BKGWebMap.Util.map( function(source) {
var img = document.createElement('img');
img.src = source.url;
img.alt = source.name;
var imgWrapper = document.createElement('div');
if(source.description) {
var span = document.createElement('span');
span.innerHTML = source.description;
imgWrapper.appendChild(span);
imgWrapper.appendChild(document.createElement('br'));
}
imgWrapper.appendChild(img);
return imgWrapper;
}, imgSources );
},
/**
* Blendet die Legende ein oder aus.
* @memberOf BKGWebMap.Control.Legend
*/
toggle: function (evt) {
// noch nicht erzeugt?
if(this.div === null) return;
var visible = OpenLayers.Element.hasClass(this.legendsContainer, "hidden");
OpenLayers.Element.removeClass(this.legendTitle, visible ? "closed" : "opened");
OpenLayers.Element.addClass(this.legendTitle, visible ? "open" : "closed");
OpenLayers.Element.removeClass(this.legendsContainer, visible ? "hidden" : "visible");
OpenLayers.Element.addClass(this.legendsContainer, visible ? "visible" : "hidden");
},
/**
* Registers events on the div.
* @memberOf BKGWebMap.Control.Legend
*/
registerEvents:function() {
this.events = new OpenLayers.Events(this, this.div, null, true);
function onTouchstart(evt) {
OpenLayers.Event.stop(evt, true);
}
this.events.on({
"mousedown": this.onmousedown,
"mousemove": this.onmousemove,
"mouseup": this.onmouseup,
"click": this.onclick,
"mouseout": this.onmouseout,
"dblclick": this.ondblclick,
"touchstart": onTouchstart,
scope: this
});
},
/**
* @param {Event} evt
* @memberOf BKGWebMap.Control.Legend
*/
onmousedown: function (evt) {
this.mousedown = true;
OpenLayers.Event.stop(evt, true);
},
/**
* @param {Event} evt
* @memberOf BKGWebMap.Control.Legend
*/
onmousemove: function (evt) {
if (this.mousedown) {
OpenLayers.Event.stop(evt, true);
}
},
/**
* @param {Event} evt
* @memberOf BKGWebMap.Control.Legend
*/
onmouseup: function (evt) {
if (this.mousedown) {
this.mousedown = false;
OpenLayers.Event.stop(evt, true);
}
},
/**
* Ignore clicks, but allowing default browser handling
* @param {Event} evt
* @memberOf BKGWebMap.Control.Legend
*/
onclick: function (evt) {
OpenLayers.Event.stop(evt, true);
},
/**
* @param {Event} evt
* @memberOf BKGWebMap.Control.Legend
*/
onmouseout: function (evt) {
this.mousedown = false;
},
/**
* Ignore double-clicks, but allowing default browser handling
* @param {Event} evt
* @memberOf BKGWebMap.Control.Legend
*/
ondblclick: function (evt) {
OpenLayers.Event.stop(evt, true);
},
CLASS_NAME: "BKGWebMap.Control.Legend"
});
/**
* Factory-Funktion zur Generierung eines Legend Steuerelement.
* @param {Array<OpenLayers.Control>} controls - Liste der Steuerelemente, in die die neue erzeugten Steuerelemente
* eingefügt werden sollen.
* @param {boolean} enabled -<code>true</code> wenn Legend erstellt werden soll.
*/
BKGWebMap.Control.FACTORIES['legend'] = function(controls, enabled) {
if (!enabled) return;
controls.push(new BKGWebMap.Control.Legend());
};
/*
FÜR WMS:
function erzeugeLegende() {
var legendDiv = OpenLayers.Util.getElement('legend');
// Legendenelemente entfernen:
if ( legendDiv.hasChildNodes() ) {
while ( legendDiv.childNodes.length >= 1 ) {
legendDiv.removeChild( legendDiv.firstChild );
}
}
// Alle neu erzeugen
for (layer_idx in map.layers) {
var layer = map.layers[layer_idx];
if ( layer instanceof OpenLayers.Layer.WMS && layer.visibility ) {
// Ein WMS-Layer in OpenLayers kann aus
// mehreren kommagetrennten WMS-Layern bestehen
var url_layers_string = layer.params.LAYERS;
var url_layers = url_layers_string.split(',');
for(part_idx in url_layers) {
singlelayer = url_layers[part_idx];
// hole legende
var url = layer.url;
url += ( url.indexOf('?') === -1 ) ? '?' : '';
url += '&SERVICE=WMS';
url += '&VERSION=1.1.1';
url += '&REQUEST=GetLegendGraphic';
url += '&FORMAT=image/png';
url += '&LAYER=' + singlelayer;
var img = document.createElement("img");
img.src = url;
legendDiv.appendChild(img);
}
}
}
}
...
lyr.events.register('visibilitychanged', window, erzeugeLegende);
*/