diff --git a/web/themes/custom/caravane/assets/js/main.js b/web/themes/custom/caravane/assets/js/main.js index cd38854..3a8cc7e 100644 --- a/web/themes/custom/caravane/assets/js/main.js +++ b/web/themes/custom/caravane/assets/js/main.js @@ -7,6 +7,7 @@ import VueImageZoomer from 'vue-image-zoomer' import 'vue-image-zoomer/dist/style.css'; import { useContentStore } from './stores/content'; +import { useMapStore } from './stores/mapState'; import router from './router/router'; // Working with the history API @@ -31,19 +32,13 @@ import router from './router/router'; (function ($, Drupal, drupalSettings) { const CaravaneTheme = function () { - const _is_front = drupalSettings.path.isFront - console.log('drupalSettings', drupalSettings) + const _is_front = drupalSettings.path.isFront; + console.log('drupalSettings', drupalSettings); - // let _I18n - - // ___ _ _ - // |_ _|_ _ (_) |_ - // | || ' \| | _| - // |___|_||_|_|\__| function init () { - console.log('CaravaneTheme init()') - initVues() - toggleMenu() + console.log('CaravaneTheme init()'); + initVues(); + toggleMenu(); } function initVues(){ @@ -55,45 +50,67 @@ import router from './router/router'; .use(createPinia()).use(router) .use(VueImageZoomer); const store = useContentStore(); + const mapStore = useMapStore(); app.mount('#content-modale'); - processEtapeLinks(store); - processStaticLinks(store); - - setupEtapeMapPopup(store); + Drupal.behaviors.customLeafletInteraction = { + attach: function(context, settings) { + $(context).on('leafletMapInit', function (e, settings, map, mapid, markers) { + mapStore.defaultMapCenter = map.getCenter(); + mapStore.maxZoom = settings.settings.maxZoom; + mapStore.defaultZoom = settings.settings.minZoom; + + processEtapeLinks(store, map); + processStaticLinks(store, map); + processHeaderLogo(store, map); + setupEtapeMapPopup(store, map); + }); + } + } } - - function onClickContentLink(e, store, category){ + function onClickContentLink(e, store, map, category){ e.preventDefault(); let a; - - const li = e.target.closest('li'); - a = li.querySelector('a'); + + if (e.target.tagName !== 'IMG') { + const li = e.target.closest('li'); + a = li.querySelector('a'); + } else { + a = e.target.closest('a'); + } let nid = a.dataset.nodeNid; if (category === 'etape') { - store.fetchEtapeData(nid); + store.fetchEtapeData(nid, map); } else if (category === 'static') { - store.fetchStaticData(nid); + if (nid) { + store.fetchStaticData(nid, map); + } else { + store.emptyAll(null, map); + } } return null; } - function processStaticLinks(store){ - let general_link_fields = document.querySelectorAll('#menu > ul > li:not(:first-of-type) > a'); + function processStaticLinks(store, map) { + let general_link_fields = document.querySelectorAll('#menu > ul > li > a'); for (let field of general_link_fields) { let general_link_href = field.getAttribute('href'); const nid = general_link_href.charAt(general_link_href.length-1); - field.setAttribute('data-node-nid', nid); - field.addEventListener('click', (e) => onClickContentLink(e, store, 'static')); + field.setAttribute('data-node-nid', parseInt(nid)); + field.addEventListener('click', (e) => onClickContentLink(e, store, map, 'static')); } } + function processHeaderLogo(store, map) { + const logo = document.querySelector('#block-caravane-logocaravane a'); + logo.addEventListener('click', (e) => onClickContentLink(e, store, map, 'static')); + } - function processEtapeLinks(store){ + function processEtapeLinks(store, map) { let etape_li = document.querySelectorAll('#etapes-liste li'); etape_li.forEach((li) => { let field = li.querySelector('div.views-field-title'); @@ -110,7 +127,7 @@ import router from './router/router'; if (nid) { let a = field.querySelector('a'); a.setAttribute('data-node-nid', nid); - li.addEventListener('click', (e) => onClickContentLink(e, store, 'etape')); + li.addEventListener('click', (e) => onClickContentLink(e, store, map, 'etape')); } let couleur = li.querySelector('.views-field-field-couleur .snippets-description').innerText; let iconElements = li.querySelectorAll('.icone-arret > div'); @@ -145,52 +162,43 @@ import router from './router/router'; }) } - function setupEtapeMapPopup(store) { - Drupal.behaviors.customLeafletInteraction = { - attach: function(context, settings) { - $(context).on('leafletMapInit', function (e, settings, map, mapid, markers) { - const icons = document.querySelectorAll('.leaflet-map-divicon'); - for (let icon of icons) { - const colorContainer = icon.querySelector('.couleur'); - let colorDivs = colorContainer.querySelectorAll('.separated-content'); - let color; - colorDivs.forEach((div) => { - if (div.innerText.startsWith('
')) { - color = div.innerText; - } - }); - color = color.substring(color.indexOf('>') + 1, color.indexOf('<', color.indexOf('>') + 1)).trim(); + function setupEtapeMapPopup(store, map) { + const icons = document.querySelectorAll('.leaflet-map-divicon'); + for (let icon of icons) { + const colorContainer = icon.querySelector('.couleur'); + let colorDivs = colorContainer.querySelectorAll('.separated-content'); + let color; + colorDivs.forEach((div) => { + if (div.innerText.startsWith('
')) { + color = div.innerText; + } + }); + color = color.substring(color.indexOf('>') + 1, color.indexOf('<', color.indexOf('>') + 1)).trim(); - const nid = icon.querySelector('.nid'); - const nidValue = nid.querySelector('.separated-content').innerText; + const nid = icon.querySelector('.nid'); + const nidValue = nid.querySelector('.separated-content').innerText; - icon.addEventListener('click', function(event) { - store.fetchEtapeData(nidValue); - }); - - //colorContainer.remove(); - //nid.remove(); - colorContainer.style.display = "none"; - nid.style.display = "none"; - const iconElements = icon.querySelectorAll('div'); - for (let iconElement of iconElements) { - iconElement.style.backgroundColor = color; - } - icon.removeAttribute('title'); - - icon.addEventListener('mouseenter', function (event) { - icon.style.transform = `${icon.style.transform} scale(1.1)`; - const popup = document.querySelector('.leaflet-tooltip-center > div'); - popup.style.opacity = "1"; - }); - - icon.addEventListener('mouseleave', function (event) { - icon.style.transform = icon.style.transform.split(' ')[0] + icon.style.transform.split(' ')[1] + icon.style.transform.split(' ')[2]; - }) - } - - }); + icon.addEventListener('click', function(event) { + store.fetchEtapeData(nidValue, map); + }); + + colorContainer.style.display = "none"; + nid.style.display = "none"; + const iconElements = icon.querySelectorAll('div'); + for (let iconElement of iconElements) { + iconElement.style.backgroundColor = color; } + icon.removeAttribute('title'); + + icon.addEventListener('mouseenter', function (event) { + icon.style.transform = `${icon.style.transform} scale(1.1)`; + const popup = document.querySelector('.leaflet-tooltip-center > div'); + popup.style.opacity = "1"; + }); + + icon.addEventListener('mouseleave', function (event) { + icon.style.transform = icon.style.transform.split(' ')[0] + icon.style.transform.split(' ')[1] + icon.style.transform.split(' ')[2]; + }) } } diff --git a/web/themes/custom/caravane/assets/js/stores/content.js b/web/themes/custom/caravane/assets/js/stores/content.js index dcc38a5..302b8ad 100644 --- a/web/themes/custom/caravane/assets/js/stores/content.js +++ b/web/themes/custom/caravane/assets/js/stores/content.js @@ -6,9 +6,11 @@ import REST from '../api/rest-axios'; export const useContentStore = defineStore('content', { state: () => ({ href: '', + map: {}, etape: { title: '', adresse: {}, + coordinates: {}, etape_number: '', vignette: {}, couleur: '', @@ -37,8 +39,9 @@ export const useContentStore = defineStore('content', { error: null, }), actions: { - async fetchEtapeData(nid) { + async fetchEtapeData(nid, map) { this.resetStore(); + this.map = map; try { const response = await REST.get(`/jsonapi/node/etape/`); for (let etape of response.data.data) { @@ -48,6 +51,10 @@ export const useContentStore = defineStore('content', { this.href = metatag.attributes.href; } } + this.etape.coordinates = { + lat: etape.attributes.field_geofield.lat, + lon: etape.attributes.field_geofield.lon, + }; this.etape.title = etape.attributes.title; this.etape.adresse = etape.attributes.field_adresse; this.etape.etape_number = etape.attributes.field_arret_numero; @@ -205,8 +212,9 @@ export const useContentStore = defineStore('content', { this.loading = false; } }, - async fetchStaticData(nid) { + async fetchStaticData(nid, map) { this.resetStore(); + this.map = map; try { const response = await REST.get(`/jsonapi/node/static/`); for (let page of response.data.data) { @@ -285,7 +293,9 @@ export const useContentStore = defineStore('content', { } } }, - emptyAll(nid) { + emptyAll(nid, map) { + this.href = ''; + this.map = map; this.etape = {}; this.page = {}; this.setActiveItemInMenu(nid); @@ -328,7 +338,6 @@ export const useContentStore = defineStore('content', { resetStore() { this.loading = true; this.error = null; - this.href = ''; this.etape = {}; this.page = {}; }, diff --git a/web/themes/custom/caravane/assets/js/stores/mapState.js b/web/themes/custom/caravane/assets/js/stores/mapState.js new file mode 100644 index 0000000..e8e9a2b --- /dev/null +++ b/web/themes/custom/caravane/assets/js/stores/mapState.js @@ -0,0 +1,46 @@ +import { defineStore } from 'pinia'; + +export const useMapStore = defineStore('mapState', { + state: () => ({ + defaultZoom: Number, + defaultMapCenter: Object, + currentPlace: Object, + maxZoom: Number, + currentZoom: Number, + duration: 3, + }), + actions: { + zoomToPlace(map, lat, long) { + map.flyTo([lat, long], this.maxZoom, { duration: this.duration }); + this.currentZoom = this.maxZoom; + }, + resetMap(map) { + map.flyTo(this.defaultMapCenter, this.defaultZoom, { duration: this.duration }); + this.currentZoom = this.defaultZoom; + }, + lockMap(map) { + setTimeout(() => { + map.options.minZoom = this.currentZoom; + map.options.maxZoom = this.currentZoom; + }, this.duration * 1000 + 100); + map.dragging.disable(); + map.touchZoom.disable(); + map.doubleClickZoom.disable(); + map.scrollWheelZoom.disable(); + map.boxZoom.disable(); + map.keyboard.disable(); + // map.tap.disable(); + }, + unlockMap(map) { + map.options.minZoom = this.defaultZoom; + map.options.maxZoom = this.maxZoom; + map.dragging.enable(); + map.touchZoom.enable(); + map.doubleClickZoom.enable(); + map.scrollWheelZoom.enable(); + map.boxZoom.enable(); + map.keyboard.enable(); + // map.tap.enable(); + }, + }, +}); \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/Modale.vue b/web/themes/custom/caravane/assets/js/vuejs/Modale.vue index 4d8305d..eac815d 100644 --- a/web/themes/custom/caravane/assets/js/vuejs/Modale.vue +++ b/web/themes/custom/caravane/assets/js/vuejs/Modale.vue @@ -20,7 +20,8 @@ :couleur="etape.couleur || brandColor" /> + :partie="partie" + :couleur="etape.couleur || brandColor" /> + :couleur="etape.couleur || brandColor" + :map="map" />
@@ -46,6 +48,7 @@ import { computed, watch, onMounted } from 'vue'; import { storeToRefs } from 'pinia'; import { useContentStore } from '../stores/content'; +import { useMapStore } from '../stores/mapState'; import { useRoute, useRouter } from 'vue-router'; import ModaleHeader from './components/ModaleHeader.vue'; @@ -64,13 +67,17 @@ const { isObjectEmpty, scrollTop } = useUtils(); const router = useRouter(); const store = useContentStore(); +const mapState = useMapStore(); const route = useRoute(); -const { loading, error, href, etape, page } = storeToRefs(store); +const { loading, error, href, map, etape, page } = storeToRefs(store); +const { duration } = storeToRefs(mapState); const isEtapeValid = computed(() => !error.value && !loading.value && etape.value && !isObjectEmpty(etape.value)); const isPageValid = computed(() => !error.value && !loading.value && page.value && !isObjectEmpty(page.value)); +let isModaleEtape, wasModaleEtape; + const brandColor = "#80c8bf"; let isProgrammaticNavigation = false; @@ -78,18 +85,18 @@ let isProgrammaticNavigation = false; const handleRouteChange = () => { watch( () => route.params.id, - (newId) => { + (newId) => { if (isProgrammaticNavigation) { isProgrammaticNavigation = false; return; } if (!newId) { - store.emptyAll(); + store.emptyAll(map.value); } else { - store.fetchEtapeData(newId); + store.fetchEtapeData(newId, map.value); if (!etape.value?.data) { - store.fetchStaticData(newId); + store.fetchStaticData(newId, map.value); } scrollTop(); } @@ -112,36 +119,82 @@ const handleHrefChange = () => { () => href.value, (newHref) => { const relativePath = newHref.split('.fr')[1]; - if (relativePath && relativePath !== '' && relativePath !== '/') { - isProgrammaticNavigation = true; - router.push(relativePath); - scrollTop(); + isProgrammaticNavigation = true; + if (newHref == '') { + router.push('/'); + mapState.unlockMap(map.value) + } else { + if (relativePath && relativePath !== '' && relativePath !== '/') { + mapState.lockMap(map.value); + router.push(relativePath); + scrollTop(); + } } } ); }; +const handleMapMovement = () => { + watch( + () => href.value, + () => { + console.log("NEW HREF"); + console.log(href.value); + + isModaleEtape = !isObjectEmpty(etape.value); + + console.log("CAS 1", !wasModaleEtape && isModaleEtape); + console.log("CAS 2", wasModaleEtape && isModaleEtape); + console.log("CAS 3", wasModaleEtape && !isModaleEtape); + + if (!wasModaleEtape && isModaleEtape) { + document.documentElement.style.setProperty('--modale-enter-delay', `${duration.value}s`); + mapState.zoomToPlace(map.value, etape.value.coordinates.lat, etape.value.coordinates.lon); + + } else if (wasModaleEtape && isModaleEtape) { + document.documentElement.style.setProperty('--modale-leave-delay', 0); + document.documentElement.style.setProperty('--modale-enter-delay', `${duration.value * 2}s`); + mapState.resetMap(map.value); + setTimeout(() => { + mapState.zoomToPlace(map.value, etape.value.coordinates.lat, etape.value.coordinates.lon); + }, duration.value * 1000); + + } else if (wasModaleEtape && !isModaleEtape) { + document.documentElement.style.setProperty('--modale-leave-delay', 0); + mapState.resetMap(map.value); + } + + wasModaleEtape = isModaleEtape; + }, + ); +}; + onMounted(() => { + isModaleEtape = !isObjectEmpty(etape.value); + wasModaleEtape = isModaleEtape; handleRouteChange(); handleColorChange(); handleHrefChange(); + handleMapMovement(); }); \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/components/ModaleFooter.vue b/web/themes/custom/caravane/assets/js/vuejs/components/ModaleFooter.vue index ec8e280..c7c3cf5 100644 --- a/web/themes/custom/caravane/assets/js/vuejs/components/ModaleFooter.vue +++ b/web/themes/custom/caravane/assets/js/vuejs/components/ModaleFooter.vue @@ -5,7 +5,7 @@