PMA.UI Documentation by Pathomation

view/controls/layerSwitch.js

import { Control } from 'ol/control';
import { Events } from '../definitions';

/**
 * Creates a control for managing server side annotation layers
 * @param {object} opt_options Options to initialize
 * @param {string} [opt_options.className] The css class to apply to this control
 * @param {string} [opt_options.tipLabel] Label for the button
 * @param {boolean} [opt_options.collapsed] Whether the control starts collapsed
 * @param {string} [opt_options.collapseLabel] The label to show when collapsed
 * @param {Object} [opt_options.stateManager] The state manager to keep settings in sync
 */
export class LayerSwitch extends Control {
    constructor(opt_options) {
        var options = opt_options || {};
        var element = document.createElement('div');
        super({
            element: element,
            target: options.target
        });

        this.pmaViewport = options.pmaViewport;
        this.stateManager = options.stateManager ? options.stateManager : null;
        if (this.stateManager) {
            if (!this.stateManager.layerSwitch) {
                this.stateManager.layerSwitch = {};
                this.stateManager.layerSwitch.collapsed = (options.collapsed) ? options.collapsed : false;
            }

            this.collapsed_ = this.stateManager.layerSwitch.collapsed === true;
        }
        else {
            this.collapsed_ = (options.collapsed) ? options.collapsed : false;
        }

        var className = (options.className) ? options.className : 'ol-layerswitch';
        var tipLabel = (options.tipLabel) ? options.tipLabel : 'Channels';

        var collapseLabel = (options.collapseLabel) ? options.collapseLabel : '\u00BB';
        this.collapseLabel_ = document.createElement('span');
        this.collapseLabel_.innerHTML = collapseLabel;

        var label = (options.label) ? options.label : '\u00AB';
        this.label_ = document.createElement('span');
        this.label_.innerHTML = label;

        var activeLabel = this.collapsed_ ? this.collapseLabel_ : this.label_;

        var button = document.createElement('button');
        button.type = 'button';
        button.title = tipLabel;
        button.appendChild(activeLabel);
        button.className = "collapse-button";
        this.btnEventUsed = 'click';

        if ('ontouchstart' in document.documentElement) {
            this.btnEventUsed = 'touchstart';
        }

        button.addEventListener(this.btnEventUsed, this.buttonClk.bind(this), false);

        var cssClasses = className + ' ' + 'ol-unselectable ol-control ' + (this.collapsed_ ? ' ol-collapsed' : '');
        element.className = cssClasses;
        element.appendChild(button);

        this.panel_ = document.createElement('ul');
        this.panel_.className = 'panel';
        element.appendChild(this.panel_);
    };

    /**
     * Sets the OpenLayers map this control handles. This is automatically called by OpenLayers
     * @param {ol.Map} map 
     */
    setMap(map) {
        super.setMap(map);
        this.drawPanel();
    };

    /**
    * Changes the visibility of the specified layers
    * @param {Object[]} options - An array of options
    * @param {string} options.name - The name of the layer to change the visibility
    * @param {boolean} options.visible - Whether to show or hide the specified layer
    * @param {number} [options.opacity] - A number between 0 and 1 that sets the opacity of the layer
    */
    setLayersVisibility(options) {
        if (!options || options.length == 0) {
            return;
        }

        if (!this.getMap()) {
            return;
        }

        var layers = this.getMap().getLayers().getArray();
        for (var oi = 0; oi < options.length; oi++) {
            var o = options[oi];
            if (!o.name) {
                continue;
            }

            for (var j = layers.length - 1; j >= 0; j--) {
                // only check for groups
                if (layers[j].getLayers) {
                    var groupLayers = layers[j].getLayers().getArray();
                    for (var i = groupLayers.length - 1; i >= 0; i--) {
                        var layer = groupLayers[i];
                        let lName = layer.get("title") || layer.get("name");
                        if (lName == o.name) {
                            layer.setVisible(o.visible);
                            if (!(o.opacity == null)) {
                                layer.setOpacity(o.opacity);
                            }
                        }

                        let li = this.panel_.querySelector(`li[data-name='${lName}']`);
                        if (li) {
                            let checkbox = li.querySelector("input[type=checkbox]");
                            checkbox.checked = layer.getVisible();
                            let range = li.querySelector("input[type=range]");
                            range.value = layer.getOpacity() * 100;
                        }
                    }
                }
            }
        }
    };

    /**
   * Gets the visibility of the specified layers
   * @returns {Object[]} options - An array of options
   * @returns {string} options.name - The name of the layer to change the visibility
   * @returns {boolean} options.visible - Whether to show or hide the specified layer
   */
    getLayersVisibility() {
        if (!this.getMap()) {
            return;
        }

        let result = [];
        let layers = this.getMap().getLayers().getArray();
        for (let j = layers.length - 1; j >= 0; j--) {
            if (layers[j].getLayers) {
                let groupLayers = layers[j].getLayers().getArray();
                for (let i = groupLayers.length - 1; i >= 0; i--) {
                    let layer = groupLayers[i];
                    let lName = layer.get("title") || layer.get("name");
                    result.push({ name: lName, visible: layer.getVisible(), opacity: layer.getOpacity() });
                }
            }
        }

        return result;
    }

    //	Draw the panel control (prevent multiple draw due to layers manipulation on the map with a delay function)
    drawPanel(e) {
        if (!this.getMap()) return;

        var layers = this.getMap().getLayers().getArray();
        this.panel_.innerHTML = '';

        for (var j = layers.length - 1; j >= 0; j--) {
            // only check for groups
            if (layers[j].getLayers) {
                var groupLayers = layers[j].getLayers().getArray();
                for (var i = groupLayers.length - 1; i >= 0; i--) {
                    var layer = groupLayers[i];
                    // var showLayer = layer.get("displayInLayerSwitcher") !== false;
                    // if (!showLayer) {
                    //     continue;
                    // }

                    var li = document.createElement('li');
                    li.setAttribute('data-name', layer.get("title") || layer.get("name"));
                    li.className = layer.getVisible() ? "visible " : " ";
                    this.panel_.appendChild(li);

                    var liHtml = "<input type='checkbox' " + (layer.getVisible() ? "checked='checked' " : "") + "/>";
                    liHtml += "<label title='" + (layer.get("title") || layer.get("name")) + "'>" + (layer.get("title") || layer.get("name")) + "</label>";
                    liHtml += "<input type=\"range\" min=\"0\" max=\"100\" value=\"" + layer.getOpacity() * 100 + "\" name=\"layer-opacity\" >";
                    li.innerHTML = liHtml;

                    let checkbox = li.querySelector("input[type=checkbox]");
                    checkbox.addEventListener('change', switchVisibility.bind(this, layer, checkbox), false);

                    let label = li.querySelector("label");
                    label.addEventListener(this.btnEventUsed, switchVisibility.bind(this, layer, checkbox), false);

                    let range = li.querySelector("input[type=range]");
                    range.addEventListener('change', opacityChange.bind(this, layer, range), false);
                }
            }
        }

        function switchVisibility(layer, checkbox) {
            layer.setVisible(!layer.getVisible());
            checkbox.checked = layer.getVisible();
            if (this.pmaViewport) {
                this.pmaViewport.fireEvent(Events.AnnotationLayerChanged, this.pmaViewport);
            }
        }

        function opacityChange(layer, range) {
            layer.setOpacity(range.value / 100);
            if (this.pmaViewport) {
                this.pmaViewport.fireEvent(Events.AnnotationLayerChanged, this.pmaViewport);
            }
        }
    };

    /** 
     * Gets the collapsed state of the control
     * @return {boolean} True if the control is currently collapsed
    */
    getCollapsed() {
        return (" " + this.element.className + " ").indexOf(' ol-collapsed ') > -1;
    };

    /** 
     * Sets the collapsed state of the control
     * @param {boolean} collapsed - True to collapse the control, otherwise false
    */
    setCollapsed(collapsed) {
        if (this.getCollapsed() != collapsed) {
            this.buttonClk();
        }
    };

    buttonClk(event) {
        if (event) {
            event.preventDefault();
            event.stopPropagation();
        }

        if ((" " + this.element.className + " ").indexOf(' ol-collapsed ') > -1) {
            this.element.className = this.element.className.replace(/ol-collapsed/g, '');
        }
        else {
            this.element.className += ' ol-collapsed';
        }

        if (!this.collapsed_) {
            this.label_.parentNode.replaceChild(this.collapseLabel_, this.label_);
        } else {
            this.collapseLabel_.parentNode.replaceChild(this.label_, this.collapseLabel_);
        }

        this.collapsed_ = !this.collapsed_;
        if (this.stateManager) {
            this.stateManager.layerSwitch.collapsed = this.collapsed_;
        }
    }
}