From e07a721adb27ad55d9f6bef65651dbab0591b6a7 Mon Sep 17 00:00:00 2001 From: dakur Date: Tue, 4 Feb 2025 06:37:32 +0100 Subject: [PATCH] wip --- scripts/administrativeUnitsMap.js | 252 +++++++++++++++++++++++++++++- 1 file changed, 244 insertions(+), 8 deletions(-) diff --git a/scripts/administrativeUnitsMap.js b/scripts/administrativeUnitsMap.js index a812775..6aee242 100644 --- a/scripts/administrativeUnitsMap.js +++ b/scripts/administrativeUnitsMap.js @@ -18,38 +18,141 @@ } */ +/* TODO: tohle skoro mám až na to že nejsem schopen rozjet přepínání vrstev */ + document.addEventListener('DOMContentLoaded', async function () { - const { Map } = await google.maps.importLibrary("maps"); + const map = await initializeMap(); + const filters = initializeFilters(map); + + // custom behavior for hnuti-brontosaurus page + // ideally, administrativeUnitsMap should export API, but there's no time play with it now + const unitBaseLinkEl = document.getElementById('about-structure-unit-base-link'); + if (unitBaseLinkEl !== null) { + unitBaseLinkEl.addEventListener('click', () => // listen to base unit link as well + filters.displayLayer(document.getElementById('mapa-zakladni-clanky'))); + } + + window.addEventListener('load', () => { // finally once the page is loaded, check if a layer filter should be activated + const hash = window.location.hash.substring(1); + + const selectedFilterLinkEl = hash !== '' + ? document.querySelector(`.administrativeUnitsMap__filters #${hash}`) + : null; + + if (selectedFilterLinkEl !== null) { // no filtering element with given hash found => do not filter + filters.displayLayer(selectedFilterLinkEl); + + } else { + filters.displayAll(); + } + }); +}); + + +/* MAP */ + +async function initializeMap() +{ + const { Map, Data } = await google.maps.importLibrary("maps"); const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker"); const mapEl = document.getElementById("map"); const administrativeUnits = JSON.parse(mapEl.getAttribute('data-administrativeUnits')); const map = new Map(mapEl, { - center: { lat: 49.000, lng: 16.000 }, - zoom: 8, + center: { lat: 49.7437572, lng: 15.3386383 }, // Czechia geographic center, see https://en.mapy.cz/s/gupehogeha + zoom: 7, mapId: "b80d048e42b74f71", }); + const bounds = new google.maps.LatLngBounds(); + let currentInfoWindow; + + const markers = []; + const slugs = []; + const layers = new google.maps.MVCObject(); + const layersObj = {}; - // todo bulk add? for (const unit of administrativeUnits) { + + // collect slugs + const slug = resolveUnitTypeSlug(unit); + if ( !! slug && ! slugs.includes(slug)) { + slugs.push(slug); + } + + // customize pin style const color = resolveColor(unit); const pinEl = new PinElement({ background: color, glyphColor: color, }); + + // set marker + const coords = { lat: unit.lat, lng: unit.lng }; const marker = new AdvancedMarkerElement({ map: map, - position: { lat: unit.lat, lng: unit.lng }, + position: coords, title: unit.name, content: pinEl.element, }); + bounds.extend(new google.maps.LatLng(unit.lat, unit.lng)); + + // create info window + const infoWindow = new google.maps.InfoWindow({ + content: buildInfoWindow(unit).outerHTML, + ariaLabel: unit.name, + }); + marker.addListener('click', () => { + currentInfoWindow?.close(); + currentInfoWindow = infoWindow; + + infoWindow.open({ + anchor: marker, + map, + }) + }); + + // add to layer + if ( ! layersObj.hasOwnProperty(slug)) { + layersObj[slug] = []; + } + layersObj[slug].push(marker); + continue; + const markerVisibility = new google.maps.MVCObject(); + markerVisibility.set("visible", true); // Default to visible + markerVisibility.bindTo("visible", layers, slug); // Sync with model + /*dataLayer.add({ + geometry: coords, + properties: { type: resolveUnitTypeSlug(unit) } + });*/ + //marker.bindTo('map', layers, slug); + /* console.log(slugs, layers.get('base')); + layers.bindTo(slug, marker);*/ + //markers.push(marker); + markerVisibility.bindTo(slug, markerVisibility, "visible"); // Sync marker with markerVisibility } - map.centerAndZoom(); -}); + map.fitBounds(bounds); -function resolveColor(unit) { + return { + displayLayer(filterSlug) { + /*const allVisible = typeof filterSlug === 'undefined'; + markers.forEach(marker => { + const isVisible = allVisible || marker.type === filterSlug; + markers.set("visible_" + marker.type, isVisible); + }); + return;*/ + const allVisible = typeof filterSlug === 'undefined'; + slugs.forEach(slug => { + //layers.set(slug, slug === filterSlug || allVisible/* ? map : null*/)); + layersObj[slug].forEach(marker => marker.setMap(allVisible || slug === filterSlug ? map : null)); + }); + }, + }; +} + +function resolveColor(unit) +{ // todo true colors if (unit.isOfTypeClub) return "violet"; if (unit.isOfTypeBase) return "orange"; @@ -58,3 +161,136 @@ function resolveColor(unit) { if (unit.isOfTypeChildren) return "pink"; throw new Error("Unsupported unit type"); } + + +function buildInfoWindow(unit) +{ + const containerEl = document.createElement('div'); + containerEl.id = 'infowindow'; + containerEl.classList.add('administrativeUnitsMap__infoWindow') + + if (unit.image !== null) { + const imageContainerEl = containerEl.appendChild(document.createElement('div')); + imageContainerEl.classList.add('administrativeUnitsMap__infoWindowImageContainer'); + const imageEl = imageContainerEl.appendChild(document.createElement('img')); + imageEl.classList.add('administrativeUnitsMap__infoWindowImage'); + imageEl.src = unit.image; + } + + const contentEl = containerEl.appendChild(document.createElement('div')); + const metaEl = contentEl.appendChild(document.createElement('div')); + + metaEl.innerHTML = resolveUnitTitle(unit); + metaEl.innerHTML += `
Adresa: ${unit.address}`; + + if (unit.chairman !== null) { + metaEl.innerHTML += `
Předseda: ${unit.chairman}`; + } + + if (unit.website !== null ) { + metaEl.innerHTML += `
Web: ${unit.website}` + } + + if (unit.email !== null) { + metaEl.innerHTML += `
E-mail: ${unit.email}`; + } + + if (unit.description !== null) { + const descriptionEl = contentEl.appendChild(document.createElement('p')); + descriptionEl.classList.add('administrativeUnitsMap__infoWindowDescription') + descriptionEl.innerHTML += unit.description; + } + + return containerEl; +} + +function resolveUnitTitle(unit) +{ + const type = resolveUnitTypeLabel(unit); + if (type === null) { + return unit.name; + } + + return `${unit.name} – ${type}`; +} + +function resolveUnitTypeLabel(unit) +{ + switch (true) { + case unit.isOfTypeClub: + return 'klub'; + + case unit.isOfTypeBase: + return 'základní článek'; + + case unit.isOfTypeRegional: + return 'regionální centrum'; + + case unit.isOfTypeOffice: + return 'ústředí'; + + case unit.isOfTypeChildren: + return 'dětský oddíl'; + } + + return null; +} + +function resolveUnitTypeSlug(unit) +{ + if (unit.isOfTypeClub) { + return 'club'; + + } else if (unit.isOfTypeBase) { + return 'base'; + + } else if (unit.isOfTypeRegional) { + return 'regional'; + + } else if (unit.isOfTypeOffice) { + return 'office'; + + } else if (unit.isOfTypeChildren) { + return 'children'; + + } else { // no option selected, fall back to Google Maps default marker + return; + } +} + + +/* FILTERS */ + +function initializeFilters({displayLayer: mapDisplayLayer}) +{ + const ActiveFilterSelector = 'administrativeUnitsMap__filter--active'; + + const filters = document.querySelectorAll('.administrativeUnitsMap__filter'); + + const updateFilterActiveState = (active) => { + filters.forEach(filterEl => + filterEl.classList.remove(ActiveFilterSelector)); + + active.classList.add(ActiveFilterSelector); + } + + const displayAll = () => { + updateFilterActiveState(document.getElementById('mapa-vse')); + mapDisplayLayer(); + } + const displayLayer = (filterEl) => { + updateFilterActiveState(filterEl); + mapDisplayLayer(filterEl.dataset.slug); + }; + + // initialize filters (listen to click events) + filters.forEach(filterEl => + filterEl.addEventListener('click', ev => { + window.history.pushState(null, '', filterEl.children[0].getAttribute('href')); + ev.preventDefault(); + + displayLayer(filterEl); + })); + + return {displayAll, displayLayer}; +}