aboutsummaryrefslogtreecommitdiff
path: root/src/map/switcher
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/switcher')
-rw-r--r--src/map/switcher/switcher.css34
-rw-r--r--src/map/switcher/switcher.js123
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';
+ }
+ }
+}