Source: Control/Legend.js

/**
 * Create Legend Control
 * @type function
 * @returns {function} See parameters of return function in {@link CONTROL_FACTORIES_legend}
 */
BKGWebMap.Control.createLegend = function () {
    return function (map, controlName, options, panel) {
        var _this = this;

        var mapId = map.getTarget();
        var elementId = mapId;

        // Check if control should be created
        if (options.active === false) {
            return undefined;
        }

        // If no panel exists and no other div ID is defined, do not create this control
        if (!panel && (!options.div || options.div === '')) {
            window.console.log(BKGWebMap.ERROR.noPanelNoDivForControl + controlName);
            return undefined;
        }

        var target;
        var inPanel = true;
        if (options.div && options.div !== '') {
            target = options.div;
            inPanel = false;
            elementId = target;
        } else {
            target = panel.element.getElementsByClassName('bkgwebmap-panelbar')[0];
        }

        // Control title for panel
        var title = 'Legende';

        // Custom class
        var customClass = '';
        if (options.style && options.style !== '') {
            customClass = ' ' + options.style;
        }

        // Tooltip position
        var tooltipClass = 'bkgwebmap-paneltooltip bkgwebmap-paneltooltipleft';
        var tooltipTextClass = 'bkgwebmap-paneltooltiptext bkgwebmap-paneltooltiptextleft';
        if (inPanel && panel.getPanelPosition() === 'right') {
            tooltipClass = 'bkgwebmap-paneltooltip bkgwebmap-paneltooltipright';
            tooltipTextClass = 'bkgwebmap-paneltooltiptext bkgwebmap-paneltooltiptextright';
        }

        // Create DOM
        var legend = document.createElement('div');
        legend.className = 'bkgwebmap-legend ' + tooltipClass + customClass;

        var parser = new DOMParser();
        var legendIcon = parser.parseFromString(BKGWebMap.PANEL_ICONS.LEGEND, 'text/xml');
        if (inPanel) {
            legendIcon.documentElement.setAttribute('class', 'bkgwebmap-panelicons bkgwebmap-paneliconsopen');
        } else {
            legendIcon.documentElement.setAttribute('class', 'bkgwebmap-panelicons');
        }
        legend.appendChild(legendIcon.documentElement);

        var legendTooltip = document.createElement('span');
        legendTooltip.className = tooltipTextClass;
        legendTooltip.innerHTML = title;
        legend.appendChild(legendTooltip);

        var legendContent = document.createElement('div');
        var legendContentClass = 'bkgwebmap-legendcontent bkgwebmap-selectable';
        legendContent.className = legendContentClass + ' bkgwebmap-panelsinglecontent';
        if (inPanel) {
            panel.addPanelContent(legendContent);
        } else {
            legend.appendChild(legendContent);
            legendContent.style.display = 'none';
        }

        function clickControl() {
            if (inPanel) {
                var activeContent = panel.getActiveContent();
                if (activeContent === '') {
                    panel.openPanel();
                    panel.changePanelContent(title, legendContentClass);
                    _this.activeIcon();
                } else if (activeContent === legendContentClass) {
                    panel.closePanel();
                } else {
                    panel.changePanelContent(title, legendContentClass);
                    _this.activeIcon();
                }
            } else if (legendContent.style.display === 'none') {
                legendContent.style.display = 'block';
            } else {
                legendContent.style.display = 'none';
            }
        }

        this.activeIcon = function () {
            legend.classList.add('bkgwebmap-panelactive');
        };

        function getNewLegendUrl(element, legendInfo, name, newParamsWMS) {
            var styleName;
            for (var i = 0; i < newParamsWMS.LAYERS.length; i++) {
                styleName = '';
                if (name === newParamsWMS.LAYERS[i]) {
                    element.classList.add('bkgwebmap-legendlayeractive');
                    styleName = newParamsWMS.STYLES[i];
                    if (legendInfo && typeof legendInfo[name] === 'object' && legendInfo[name].constructor === Object) {
                        return legendInfo[name][styleName];
                    }
                }
            }
            return undefined;
        }

        function reloadWmsLegend(layer, newParamsWMS) {
            var legendInfo = layer.getLegendInfo();
            var uniqueId = layer.getProperties().uniqueId;
            var wmsLayers = document.getElementById(elementId).querySelectorAll('[data-bkgwebmap-legendlayerid]');

            for (var i = 0; i < wmsLayers.length; i++) {
                var id = wmsLayers[i].getAttribute('data-bkgwebmap-legendlayerid');
                if (uniqueId === id) {
                    var nameElements = wmsLayers[i].querySelectorAll('[data-bkgwebmap-legendlayerwmsname]');
                    for (var k = 0; k < nameElements.length; k++) {
                        nameElements[k].classList.remove('bkgwebmap-legendlayeractive');
                        var name = nameElements[k].getAttribute('data-bkgwebmap-legendlayerwmsname');
                        var newUrl = getNewLegendUrl(nameElements[k], legendInfo, name, newParamsWMS);
                        if (newUrl) {
                            nameElements[k].getElementsByTagName('img')[0].setAttribute('src', newUrl);
                        }
                    }
                }
            }
        }

        /**
         * Add a legend of a new layer
         * @param {object} layer - Layer that should be added
         */
        this.addLayerToLegend = function (layer, inGroup, groupVisibility) {
            if (layer instanceof ol.layer.Group) {
                var groupLayerVisibility = layer.getVisible();
                layer.getLayers().forEach(function (sublayer) {
                    _this.addLayerToLegend(sublayer, true, groupLayerVisibility);
                });
            } else {
                var layerLegendDiv;
                var layerLegendDivTitle;
                var layerLegendDivImgDiv;
                var layerLegendDivImg;
                var url = layer.getProperties().legendUrl;
                var layerActive = false;
                if ((layer instanceof BKGWebMap.Layer.ImageWMS || layer instanceof BKGWebMap.Layer.TileWMS) && !url) {
                    var activateLegend = true;
                    var legendInfo = layer.getLegendInfo();
                    if (!legendInfo) {
                        return;
                    }

                    layerLegendDiv = document.createElement('div');
                    layerLegendDiv.className = 'bkgwebmap-legendlayer';
                    layerLegendDiv.setAttribute('data-bkgwebmap-legendlayerid', layer.getProperties().uniqueId);
                    legendContent.appendChild(layerLegendDiv);

                    layerLegendDivTitle = document.createElement('div');
                    layerLegendDivTitle.className = 'bkgwebmap-legendlayertitle';
                    layerLegendDivTitle.innerHTML = layer.getProperties().name;
                    layerLegendDiv.appendChild(layerLegendDivTitle);

                    var subLayers = layer.getLayers();

                    for (var i = 0; i < subLayers.length; i++) {
                        var legendUrl = '';

                        var layerLegendDivWms = document.createElement('div');
                        if (subLayers[i].visibility && layer.getVisible()) {
                            layerLegendDivWms.className = 'bkgwebmap-legendlayer bkgwebmap-legendlayerwms bkgwebmap-legendlayeractive';
                            layerActive = true;
                        } else {
                            layerLegendDivWms.className = 'bkgwebmap-legendlayer bkgwebmap-legendlayerwms';
                        }
                        layerLegendDivWms.setAttribute('data-bkgwebmap-legendlayerid', subLayers[i].uniqueId);
                        layerLegendDivWms.setAttribute('data-bkgwebmap-legendlayerwmsname', subLayers[i].layer);
                        layerLegendDiv.appendChild(layerLegendDivWms);

                        layerLegendDivTitle = document.createElement('div');
                        layerLegendDivTitle.className = 'bkgwebmap-legendlayertitle bkgwebmap-legendlayertitlewms';
                        layerLegendDivTitle.innerHTML = subLayers[i].name;
                        layerLegendDivWms.appendChild(layerLegendDivTitle);

                        layerLegendDivImgDiv = document.createElement('div');
                        layerLegendDivImgDiv.className = 'bkgwebmap-legendlayerimg';
                        layerLegendDivWms.appendChild(layerLegendDivImgDiv);

                        layerLegendDivImg = document.createElement('img');

                        if (legendInfo && (typeof legendInfo[subLayers[i].layer] === 'string' || legendInfo[subLayers[i].layer] instanceof String)) {
                            legendUrl = legendInfo[subLayers[i].layer];
                        } else if (legendInfo && typeof legendInfo[subLayers[i].layer] === 'object' && legendInfo[subLayers[i].layer].constructor === Object) {
                            if (subLayers[i].style) {
                                legendUrl = legendInfo[subLayers[i].layer][subLayers[i].style];
                            } else {
                                var counter = 0;
                                var defaultUrl = '';
                                for (var styleName in legendInfo[subLayers[i].layer]) {
                                    counter++;
                                    if (counter === 1) {
                                        legendUrl = legendInfo[subLayers[i].layer][styleName];
                                    }
                                    defaultUrl = legendInfo[subLayers[i].layer][styleName];
                                    if (styleName.toLowerCase().indexOf('default') !== -1) {
                                        legendUrl = legendInfo[subLayers[i].layer][styleName];
                                    }
                                }
                                if (counter === 1) {
                                    legendUrl = defaultUrl;
                                }
                            }
                        }
                        if (legendUrl) {
                            layerLegendDivImg.setAttribute('src', legendUrl);
                        } else {
                            activateLegend = false;
                        }

                        layerLegendDivImgDiv.appendChild(layerLegendDivImg);
                    }

                    if (inGroup && !groupVisibility) {
                        layerActive = false;
                    }

                    if (layerActive && legendInfo && activateLegend) {
                        layerLegendDiv.classList.add('bkgwebmap-legendlayeractive');
                    }
                } else if (url) {
                    layerLegendDiv = document.createElement('div');
                    layerActive = layer.getVisible();

                    if (inGroup && !groupVisibility) {
                        layerActive = false;
                    }

                    if (layerActive) {
                        layerLegendDiv.className = 'bkgwebmap-legendlayer bkgwebmap-legendlayeractive';
                    } else {
                        layerLegendDiv.className = 'bkgwebmap-legendlayer';
                    }
                    layerLegendDiv.setAttribute('data-bkgwebmap-legendlayerid', layer.getProperties().uniqueId);
                    legendContent.appendChild(layerLegendDiv);

                    layerLegendDivTitle = document.createElement('div');
                    layerLegendDivTitle.className = 'bkgwebmap-legendlayertitle';
                    layerLegendDivTitle.innerHTML = layer.getProperties().name;
                    layerLegendDiv.appendChild(layerLegendDivTitle);

                    layerLegendDivImgDiv = document.createElement('div');
                    layerLegendDivImgDiv.className = 'bkgwebmap-legendlayerimg';
                    layerLegendDiv.appendChild(layerLegendDivImgDiv);

                    layerLegendDivImg = document.createElement('img');
                    layerLegendDivImg.setAttribute('src', url);
                    layerLegendDivImgDiv.appendChild(layerLegendDivImg);
                }
            }
        };

        /**
         * Remove legend when removing a custom layer
         * @param {object} layer - Layer that should be removed
         */
        this.removeLayerFromLegend = function (layer) {
            var uniqueId = layer.getProperties().uniqueId;
            var legendElements = document.getElementById(elementId).querySelectorAll('[data-bkgwebmap-legendlayerid]');
            for (var k = 0; k < legendElements.length; k++) {
                var legendElementId = legendElements[k].getAttribute('data-bkgwebmap-legendlayerid');
                if (uniqueId === legendElementId) {
                    legendElements[k].parentNode.removeChild(legendElements[k]);
                }
            }
        };

        /**
         * Show/hide legend of a layer
         * @param {object} layer - Layer that should be used
         * @param {boolean} visible - Show or hide legend
         */
        this.changeLegend = function (layer, visible, newParamsWMS, inGroup, groupVisibility) {
            if (layer instanceof ol.layer.Group) {
                layer.getLayers().forEach(function (sublayer) {
                    _this.changeLegend(sublayer, visible, newParamsWMS, true, visible);
                });
            } else {
                var legendLayers = document.getElementById(elementId).getElementsByClassName('bkgwebmap-legendcontent')[0].querySelectorAll('[data-bkgwebmap-legendlayerid]');

                for (var i = 0; i < legendLayers.length; i++) {
                    if (legendLayers[i].getAttribute('data-bkgwebmap-legendlayerid') === layer.getProperties().uniqueId) {
                        if (inGroup) {
                            if (!groupVisibility) {
                                legendLayers[i].classList.remove('bkgwebmap-legendlayeractive');
                            } else if (layer.getVisible()) {
                                legendLayers[i].classList.add('bkgwebmap-legendlayeractive');
                            } else {
                                legendLayers[i].classList.remove('bkgwebmap-legendlayeractive');
                            }
                        } else if (visible) {
                            legendLayers[i].classList.add('bkgwebmap-legendlayeractive');
                        } else {
                            legendLayers[i].classList.remove('bkgwebmap-legendlayeractive');
                        }

                        if (legendLayers[i].getElementsByTagName('img')[0].src === '') {
                            legendLayers[i].classList.remove('bkgwebmap-legendlayeractive');
                        }
                    }
                }

                if (newParamsWMS) {
                    reloadWmsLegend(layer, newParamsWMS);
                }
            }
        };

        // Event listeners
        var elementForEvent = legend;
        if (!inPanel) {
            elementForEvent = legend.querySelector('svg');
        }
        elementForEvent.addEventListener('click', clickControl, { passive: true });
        elementForEvent.addEventListener('mouseenter', function () {
            var allTooltips = document.getElementById(mapId).getElementsByClassName('bkgwebmap-paneltooltiptext');
            for (var i = 0; i < allTooltips.length; i++) {
                allTooltips[i].style.visibility = '';
            }
            legendTooltip.style.visibility = 'visible';
            setTimeout(function () {
                legendTooltip.style.visibility = '';
            }, 1200);
        }, false);

        // Finalize control
        ol.control.Control.call(this, {
            element: legend,
            target: target
        });
    };
};