diff options
Diffstat (limited to 'src/map/switcher')
-rw-r--r-- | src/map/switcher/switcher.css | 34 | ||||
-rw-r--r-- | src/map/switcher/switcher.js | 123 |
2 files changed, 157 insertions, 0 deletions
diff --git a/src/map/switcher/switcher.css b/src/map/switcher/switcher.css new file mode 100644 index 00000000..afba84d6 --- /dev/null +++ b/src/map/switcher/switcher.css @@ -0,0 +1,34 @@ +.maplibregl-style-list { + display: none; +} + +.maplibregl-ctrl-group .maplibregl-style-list button { + background: none; + border: none; + cursor: pointer; + display: block; + font-size: 14px; + padding: 8px 8px 6px; + text-align: right; + width: 100%; + height: auto; +} + +.maplibregl-style-list button.active { + font-weight: bold; +} + +.maplibregl-style-list button:hover { + background-color: rgba(0, 0, 0, 0.05); +} + +.maplibregl-style-list button + button { + border-top: 1px solid #ddd; +} + +.maplibregl-style-switcher { + background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNTQuODQ5cHgiIGhlaWdodD0iNTQuODQ5cHgiIHZpZXdCb3g9IjAgMCA1NC44NDkgNTQuODQ5IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1NC44NDkgNTQuODQ5OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PGc+PGc+PGc+PHBhdGggZD0iTTU0LjQ5NywzOS42MTRsLTEwLjM2My00LjQ5bC0xNC45MTcsNS45NjhjLTAuNTM3LDAuMjE0LTEuMTY1LDAuMzE5LTEuNzkzLDAuMzE5Yy0wLjYyNywwLTEuMjU0LTAuMTA0LTEuNzktMC4zMThsLTE0LjkyMS01Ljk2OEwwLjM1MSwzOS42MTRjLTAuNDcyLDAuMjAzLTAuNDY3LDAuNTI0LDAuMDEsMC43MTZMMjYuNTYsNTAuODFjMC40NzcsMC4xOTEsMS4yNTEsMC4xOTEsMS43MjksMEw1NC40ODgsNDAuMzNDNTQuOTY0LDQwLjEzOSw1NC45NjksMzkuODE3LDU0LjQ5NywzOS42MTR6Ii8+PHBhdGggZD0iTTU0LjQ5NywyNy41MTJsLTEwLjM2NC00LjQ5MWwtMTQuOTE2LDUuOTY2Yy0wLjUzNiwwLjIxNS0xLjE2NSwwLjMyMS0xLjc5MiwwLjMyMWMtMC42MjgsMC0xLjI1Ni0wLjEwNi0xLjc5My0wLjMyMWwtMTQuOTE4LTUuOTY2TDAuMzUxLDI3LjUxMmMtMC40NzIsMC4yMDMtMC40NjcsMC41MjMsMC4wMSwwLjcxNkwyNi41NiwzOC43MDZjMC40NzcsMC4xOSwxLjI1MSwwLjE5LDEuNzI5LDBsMjYuMTk5LTEwLjQ3OUM1NC45NjQsMjguMDM2LDU0Ljk2OSwyNy43MTYsNTQuNDk3LDI3LjUxMnoiLz48cGF0aCBkPSJNMC4zNjEsMTYuMTI1bDEzLjY2Miw1LjQ2NWwxMi41MzcsNS4wMTVjMC40NzcsMC4xOTEsMS4yNTEsMC4xOTEsMS43MjksMGwxMi41NDEtNS4wMTZsMTMuNjU4LTUuNDYzYzAuNDc3LTAuMTkxLDAuNDgtMC41MTEsMC4wMS0wLjcxNkwyOC4yNzcsNC4wNDhjLTAuNDcxLTAuMjA0LTEuMjM2LTAuMjA0LTEuNzA4LDBMMC4zNTEsMTUuNDFDLTAuMTIxLDE1LjYxNC0wLjExNiwxNS45MzUsMC4zNjEsMTYuMTI1eiIvPjwvZz48L2c+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvc3ZnPg==); + background-position: center; + background-repeat: no-repeat; + background-size: 70%; +} diff --git a/src/map/switcher/switcher.js b/src/map/switcher/switcher.js new file mode 100644 index 00000000..b6c62a6e --- /dev/null +++ b/src/map/switcher/switcher.js @@ -0,0 +1,123 @@ +import './switcher.css'; + +export class SwitcherControl { + + constructor(onBeforeSwitch, onSwitch, onAfterSwitch) { + this.onBeforeSwitch = onBeforeSwitch; + this.onSwitch = onSwitch; + this.onAfterSwitch = onAfterSwitch; + this.onDocumentClick = this.onDocumentClick.bind(this); + this.styles = []; + this.currentStyle = null; + } + + getDefaultPosition() { + return 'top-right'; + } + + updateStyles(updatedStyles, defaultStyle) { + this.styles = updatedStyles; + + let selectedStyle = null; + for (const style of this.styles) { + if (style.id === (this.currentStyle || defaultStyle)) { + selectedStyle = style.id; + break; + } + } + if (!selectedStyle) { + selectedStyle = this.styles[0].id; + } + + while (this.mapStyleContainer.firstChild) { + this.mapStyleContainer.removeChild(this.mapStyleContainer.firstChild); + } + + let selectedStyleElement; + + for (const style of this.styles) { + const styleElement = document.createElement('button'); + styleElement.type = 'button'; + styleElement.innerText = style.title; + styleElement.dataset.id = style.id; + styleElement.dataset.style = JSON.stringify(style.style); + styleElement.addEventListener('click', (event) => { + const { target } = event; + if (!target.classList.contains('active')) { + this.onSelectStyle(target); + } + }); + if (style.id === selectedStyle) { + selectedStyleElement = styleElement; + styleElement.classList.add('active'); + } + this.mapStyleContainer.appendChild(styleElement); + } + + if (this.currentStyle !== selectedStyle) { + this.onSelectStyle(selectedStyleElement); + this.currentStyle = selectedStyle; + } + } + + onSelectStyle(target) { + this.onBeforeSwitch(); + + const style = this.styles.find((it) => it.id === target.dataset.id); + this.map.setStyle(style.style, { diff: false }); + this.map.setTransformRequest(style.transformRequest); + + this.onSwitch(target.dataset.id); + + this.mapStyleContainer.style.display = 'none'; + this.styleButton.style.display = 'block'; + + const elements = this.mapStyleContainer.getElementsByClassName('active'); + while (elements[0]) { + elements[0].classList.remove('active'); + } + target.classList.add('active'); + + this.currentStyle = target.dataset.id; + + this.onAfterSwitch(); + } + + onAdd(map) { + this.map = map; + this.controlContainer = document.createElement('div'); + this.controlContainer.classList.add('maplibregl-ctrl'); + this.controlContainer.classList.add('maplibregl-ctrl-group'); + this.mapStyleContainer = document.createElement('div'); + this.styleButton = document.createElement('button'); + this.styleButton.type = 'button'; + this.mapStyleContainer.classList.add('maplibregl-style-list'); + this.styleButton.classList.add('maplibregl-ctrl-icon'); + this.styleButton.classList.add('maplibregl-style-switcher'); + this.styleButton.addEventListener('click', () => { + this.styleButton.style.display = 'none'; + this.mapStyleContainer.style.display = 'block'; + }); + document.addEventListener('click', this.onDocumentClick); + this.controlContainer.appendChild(this.styleButton); + this.controlContainer.appendChild(this.mapStyleContainer); + return this.controlContainer; + } + + onRemove() { + if (!this.controlContainer || !this.controlContainer.parentNode || !this.map || !this.styleButton) { + return; + } + this.styleButton.removeEventListener('click', this.onDocumentClick); + this.controlContainer.parentNode.removeChild(this.controlContainer); + document.removeEventListener('click', this.onDocumentClick); + this.map = undefined; + } + + onDocumentClick(event) { + if (this.controlContainer && !this.controlContainer.contains(event.target) && this.mapStyleContainer && this.styleButton) { + this.mapStyleContainer.style.display = 'none'; + this.styleButton.style.display = 'block'; + } + } +} |