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};
+}