Source: map/tools/ProjectionSwitcher.js

import { UiElement } from '../../ui/UiElement.js';

/**
 * Dropdown button to switch the map projection.
 *
 * @extends UiElement
 * @memberof vef.map.tools
 */
class ProjectionSwitcher extends UiElement {

    /**
     * Constructs a new ProjectionSwitcher instance.
     *
     * @param {Map} map - The map object.
     * @param {string} [position="top-left"] - The position of the switcher on the map.
     * @param {Object} [baseLayers] - The base layers for different projections.
     * @param {Object} [projections] - The available projections.
     */
    constructor(map, position, baseLayers, projections) {
        super();

        this.map = map;
        this.position = position || "top-left";
        this.baseLayers = baseLayers;
        this.class = ["vef-tool", "tool-dropdown"];
        this.html = `
            <i class="fas fa-globe-europe"></i>
            <div class="tool-dropdown-content"></div>
        `;

        this.getElement().title = "Projection Switcher";
        this.setClass(this.class);
        this.setHtml(this.html);

        this.setProjections_(projections || {
            "EPSG:4326": '<i class="vef vef-globe"></i><span>Global</span>',
            "EPSG:3995": '<i class="vef vef-globe-north"></i><span>Arctic</span>',
            "EPSG:3031": '<i class="vef vef-globe-south"></i><span>Antarctic</span>',
        });
        this.initEvents_();

        this.map.on("projection_change", () => this.update());
        this.map.on("baselayer_change", () => this.update());
        this.map.addTool(this, this.position);

        this.update();
    }

    /**
     * Sets the available projections.
     *
     * @private
     * @param {Object} projections - The available projections.
     */
    setProjections_(projections) {
        const list = this.query(".tool-dropdown-content");
        for (let code in projections) {
            list.insertAdjacentHTML("beforeend", `
                <button data-crs="${code}">${projections[code]}</button>
            `);
        }
    }

    /**
     * Initializes the event listeners for the switcher buttons.
     *
     * @private
     */
    initEvents_() {
        const buttons = this.queryAll(".tool-dropdown-content button");
        for (let i = 0; i < buttons.length; ++i) {
            buttons[i].addEventListener("click", e => {
                const key = this.map.options.baseLayer;
                const crs = e.currentTarget.dataset.crs;
                if (crs in this.baseLayers[key]) {
                    this.map.setBaseLayer(this.baseLayers[key][crs], crs);
                }
            });
        }
    }

    /**
     * Updates the state of the switcher buttons based on the current map state.
     */
    update() {
        const key = this.map.options.baseLayer;
        const crs = this.map.options.crs;

        const buttons = this.queryAll(".tool-dropdown-content button");
        for (let i = 0; i < buttons.length; ++i) {
            buttons[i].classList.remove("active");
            if (!(buttons[i].dataset.crs in this.baseLayers[key])) {
                buttons[i].disabled = true;
                buttons[i].title = "Projection is unsupported by the active baselayer.";
            } else if (buttons[i].dataset.crs == crs) {
                buttons[i].disabled = true;
                buttons[i].classList.add("active");
                buttons[i].title = "Projection is already selected.";
            } else {
                buttons[i].disabled = false;
                buttons[i].title = "";
            }
        }
    }

}

export { ProjectionSwitcher };