toggle animations
This commit is contained in:
parent
f2680fc65a
commit
9bf84290ac
|
@ -10,23 +10,32 @@ export const useMapStore = defineStore('mapState', {
|
||||||
currentPlace: Object,
|
currentPlace: Object,
|
||||||
maxZoom: Number,
|
maxZoom: Number,
|
||||||
currentZoom: Number,
|
currentZoom: Number,
|
||||||
duration: 3,
|
animationsAreEnabled: true,
|
||||||
|
animationDuration: 3,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
zoomToPlace(lat, long) {
|
zoomToPlace(lat, long) {
|
||||||
if (useLayoutStore().isDesktop) long = long - 0.03;
|
if (useLayoutStore().isDesktop) long = long - 0.03;
|
||||||
this.map.flyTo([lat, long], this.maxZoom, { duration: this.duration });
|
this.map.flyTo(
|
||||||
|
[lat, long],
|
||||||
|
this.maxZoom,
|
||||||
|
{ animate: this.animationsAreEnabled, animationDuration: this.animationDuration });
|
||||||
this.currentZoom = this.maxZoom;
|
this.currentZoom = this.maxZoom;
|
||||||
},
|
},
|
||||||
resetMap() {
|
resetMap() {
|
||||||
this.map.flyTo(this.defaultMapCenter, useLayoutStore().isDesktop ? this.defaultZoomDesktop : this.defaultZoomMobile, { duration: this.duration });
|
console.log(this.defaultMapCenter);
|
||||||
|
|
||||||
|
this.map.flyTo(
|
||||||
|
this.defaultMapCenter,
|
||||||
|
useLayoutStore().isDesktop ? this.defaultZoomDesktop : this.defaultZoomMobile,
|
||||||
|
{ animate: this.animationsAreEnabled, animationDuration: this.animationDuration });
|
||||||
this.currentZoom = useLayoutStore().isDesktop ? this.defaultZoomDesktop : this.defaultZoomMobile;
|
this.currentZoom = useLayoutStore().isDesktop ? this.defaultZoomDesktop : this.defaultZoomMobile;
|
||||||
},
|
},
|
||||||
lockMap() {
|
lockMap() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.map.options.minZoom = this.currentZoom;
|
this.map.options.minZoom = this.currentZoom;
|
||||||
this.map.options.maxZoom = this.currentZoom;
|
this.map.options.maxZoom = this.currentZoom;
|
||||||
}, this.duration * 1000 + 100);
|
}, this.animationDuration * 1000 + 100);
|
||||||
this.map.dragging.disable();
|
this.map.dragging.disable();
|
||||||
this.map.touchZoom.disable();
|
this.map.touchZoom.disable();
|
||||||
this.map.doubleClickZoom.disable();
|
this.map.doubleClickZoom.disable();
|
||||||
|
@ -34,17 +43,28 @@ export const useMapStore = defineStore('mapState', {
|
||||||
this.map.boxZoom.disable();
|
this.map.boxZoom.disable();
|
||||||
this.map.keyboard.disable();
|
this.map.keyboard.disable();
|
||||||
// map.tap.disable();
|
// map.tap.disable();
|
||||||
},
|
},
|
||||||
unlockMap() {
|
unlockMap() {
|
||||||
this.map.options.minZoom = useLayoutStore().isDesktop ? this.defaultZoomDesktop : this.defaultZoomMobile;
|
this.map.options.minZoom = useLayoutStore().isDesktop ? this.defaultZoomDesktop : this.defaultZoomMobile;
|
||||||
this.map.options.maxZoom = this.maxZoom;
|
this.map.options.maxZoom = this.maxZoom;
|
||||||
this.map.dragging.enable();
|
this.map.dragging.enable();
|
||||||
this.map.touchZoom.enable();
|
this.map.touchZoom.enable();
|
||||||
this.map.doubleClickZoom.enable();
|
this.map.doubleClickZoom.enable();
|
||||||
this.map.scrollWheelZoom.enable();
|
this.map.scrollWheelZoom.enable();
|
||||||
this.map.boxZoom.enable();
|
this.map.boxZoom.enable();
|
||||||
this.map.keyboard.enable();
|
this.map.keyboard.enable();
|
||||||
// map.tap.enable();
|
// map.tap.enable();
|
||||||
},
|
},
|
||||||
|
toggleAnimation() {
|
||||||
|
this.animationsAreEnabled = !this.animationsAreEnabled;
|
||||||
|
},
|
||||||
|
checkReducedMotion() {
|
||||||
|
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||||
|
this.animationsAreEnabled = !mediaQuery.matches;
|
||||||
|
|
||||||
|
mediaQuery.addEventListener('change', (event) => {
|
||||||
|
this.animationsAreEnabled = !event.matches;
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
|
@ -2,6 +2,7 @@ import { createApp } from 'vue';
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
import router from '../router/router';
|
import router from '../router/router';
|
||||||
import Modale from '../vuejs/Modale.vue';
|
import Modale from '../vuejs/Modale.vue';
|
||||||
|
import AnimationToggle from '../vuejs/AnimationToggle.vue';
|
||||||
import VueImageZoomer from 'vue-image-zoomer';
|
import VueImageZoomer from 'vue-image-zoomer';
|
||||||
import 'vue-image-zoomer/dist/style.css';
|
import 'vue-image-zoomer/dist/style.css';
|
||||||
|
|
||||||
|
@ -9,14 +10,20 @@ import { useContentStore } from '../stores/content';
|
||||||
import { useMapStore } from '../stores/map';
|
import { useMapStore } from '../stores/map';
|
||||||
|
|
||||||
export function initVueContentModale() {
|
export function initVueContentModale() {
|
||||||
|
const pinia = createPinia();
|
||||||
|
|
||||||
const app = createApp(Modale)
|
const app = createApp(Modale)
|
||||||
.use(createPinia())
|
.use(pinia)
|
||||||
.use(router)
|
.use(router)
|
||||||
.use(VueImageZoomer);
|
.use(VueImageZoomer);
|
||||||
|
|
||||||
const store = useContentStore();
|
const store = useContentStore();
|
||||||
const mapStore = useMapStore();
|
const mapStore = useMapStore();
|
||||||
app.mount('#content-modale');
|
app.mount('#content-modale');
|
||||||
|
|
||||||
|
const animationToggle = createApp(AnimationToggle)
|
||||||
|
.use(pinia)
|
||||||
|
.mount('#animation-toggle');
|
||||||
|
|
||||||
return { store, mapStore, router };
|
return { store, mapStore, router };
|
||||||
}
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
<template>
|
||||||
|
<div @click="handleClick" class="animation-toggle-container">
|
||||||
|
<div><p>Activer les animations</p></div>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" v-model="animationsAreEnabled" @click.stop @change="toggleAnimation" />
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { useMapStore } from '../stores/map';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const mapStore = useMapStore();
|
||||||
|
|
||||||
|
const { animationsAreEnabled } = storeToRefs(mapStore);
|
||||||
|
|
||||||
|
const toggleAnimation = () => {
|
||||||
|
mapStore.toggleAnimation();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
toggleAnimation();
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleClick,
|
||||||
|
toggleAnimation,
|
||||||
|
animationsAreEnabled,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -1,5 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<Transition>
|
<Transition
|
||||||
|
:enter-active-class="animationsAreEnabled ? 'v-enter-active' : 'no-transition'"
|
||||||
|
:leave-active-class="animationsAreEnabled ? 'v-leave-active' : 'no-transition'"
|
||||||
|
>
|
||||||
<div v-if="!loading && (contentType === 'etape' || contentType === 'static')">
|
<div v-if="!loading && (contentType === 'etape' || contentType === 'static')">
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
<ModaleHeader
|
<ModaleHeader
|
||||||
|
@ -81,7 +84,7 @@ const {
|
||||||
error,
|
error,
|
||||||
} = storeToRefs(store);
|
} = storeToRefs(store);
|
||||||
|
|
||||||
const { map, duration } = storeToRefs(mapState);
|
const { defaultMapCenter, animationDuration, animationsAreEnabled } = storeToRefs(mapState);
|
||||||
|
|
||||||
let isModaleEtape, wasModaleEtape;
|
let isModaleEtape, wasModaleEtape;
|
||||||
|
|
||||||
|
@ -105,30 +108,56 @@ const handleMapMovement = () => {
|
||||||
if (!loading.value) {
|
if (!loading.value) {
|
||||||
isModaleEtape = contentType.value === 'etape';
|
isModaleEtape = contentType.value === 'etape';
|
||||||
|
|
||||||
if (!wasModaleEtape && isModaleEtape) {
|
// Define helper functions in variables
|
||||||
// national -> détail
|
const disableModaleTransition = () => {
|
||||||
document.documentElement.style.setProperty('--modale-enter-delay', `${duration.value}s`);
|
document.documentElement.style.setProperty('margin-top', '0');
|
||||||
mapState.zoomToPlace(content.value.coordinates.lat, content.value.coordinates.lon);
|
document.documentElement.style.setProperty('transition', 'none');
|
||||||
} else if (wasModaleEtape && isModaleEtape) {
|
|
||||||
// détail -> détail
|
|
||||||
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(content.value.coordinates.lat, content.value.coordinates.lon);
|
|
||||||
}, duration.value * 1000);
|
|
||||||
|
|
||||||
} else if (wasModaleEtape && !isModaleEtape) {
|
|
||||||
// détail -> national
|
|
||||||
document.documentElement.style.setProperty('--modale-leave-delay', 0);
|
|
||||||
document.documentElement.style.setProperty('--modale-enter-delay', `${duration.value}s`);
|
|
||||||
mapState.resetMap();
|
|
||||||
} else if (!wasModaleEtape && !isModaleEtape) {
|
|
||||||
// national -> national
|
|
||||||
console.log('national -> national');
|
|
||||||
document.documentElement.style.setProperty('--modale-leave-delay', 0);
|
|
||||||
document.documentElement.style.setProperty('--modale-enter-delay', '0.5s');
|
|
||||||
}
|
}
|
||||||
|
const setModaleTransition = (enterDelay) => {
|
||||||
|
document.documentElement.style.setProperty('--modale-enter-delay', `${enterDelay}s`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const zoomToContentPlace = () => {
|
||||||
|
mapState.zoomToPlace(
|
||||||
|
content.value.coordinates.lat ? content.value.coordinates.lat : defaultMapCenter.value.lat,
|
||||||
|
content.value.coordinates.lon ? content.value.coordinates.lon : defaultMapCenter.value.lng
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (animationsAreEnabled.value) {
|
||||||
|
|
||||||
|
if (isModaleEtape) {
|
||||||
|
if (!wasModaleEtape) {
|
||||||
|
console.log('national -> détail');
|
||||||
|
setModaleTransition(animationDuration.value);
|
||||||
|
zoomToContentPlace();
|
||||||
|
} else {
|
||||||
|
console.log('détail -> détail');
|
||||||
|
setModaleTransition(animationDuration.value);
|
||||||
|
//mapState.resetMap();
|
||||||
|
zoomToContentPlace();
|
||||||
|
//setTimeout(zoomToContentPlace, animationDuration.value * 1000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (wasModaleEtape) {
|
||||||
|
console.log('détail -> national');
|
||||||
|
setModaleTransition(animationDuration.value);
|
||||||
|
mapState.resetMap();
|
||||||
|
} else {
|
||||||
|
console.log('national -> national');
|
||||||
|
setModaleTransition(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isModaleEtape) {
|
||||||
|
zoomToContentPlace();
|
||||||
|
} else {
|
||||||
|
mapState.resetMap();
|
||||||
|
}
|
||||||
|
disableModaleTransition();
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollTo(0, 0);
|
||||||
|
|
||||||
wasModaleEtape = isModaleEtape;
|
wasModaleEtape = isModaleEtape;
|
||||||
}
|
}
|
||||||
|
@ -150,7 +179,7 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.v-leave-active {
|
.v-leave-active {
|
||||||
transition: margin-top 0.5s ease-in var(--modale-leave-delay);
|
transition: margin-top 0.5s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
.v-enter-from,
|
.v-enter-from,
|
||||||
|
@ -160,6 +189,12 @@ onMounted(() => {
|
||||||
|
|
||||||
.v-enter-to,
|
.v-enter-to,
|
||||||
.v-leave-from {
|
.v-leave-from {
|
||||||
margin-top: 0vh;
|
margin-top: 0vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This class will disable transitions */
|
||||||
|
.no-transition {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
transition: none !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -5,7 +5,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="contentType === 'etape' && (content.previous || content.next)" class="related-etape-links">
|
<div v-if="contentType === 'etape' && (content.previous || content.next)" class="related-etape-links">
|
||||||
<div v-if="content.previous" class="card previous" @click="displayRelatedElement(content.previous.url)">
|
<div v-if="content.previous" class="card previous" @click="clickRelatedElement(content.previous.url)">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<div :style="{ backgroundColor: content.previous.couleur }"></div>
|
<div :style="{ backgroundColor: content.previous.couleur }"></div>
|
||||||
<div :style="{ backgroundColor: content.previous.couleur }"></div>
|
<div :style="{ backgroundColor: content.previous.couleur }"></div>
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="content.next" class="card next" @click="displayRelatedElement(content.next.url)">
|
<div v-if="content.next" class="card next" @click="clickRelatedElement(content.next.url)">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<div :style="{ backgroundColor: content.next.couleur }"></div>
|
<div :style="{ backgroundColor: content.next.couleur }"></div>
|
||||||
<div :style="{ backgroundColor: content.next.couleur }"></div>
|
<div :style="{ backgroundColor: content.next.couleur }"></div>
|
||||||
|
@ -63,4 +63,13 @@ async function displayRelatedElement(href) {
|
||||||
await store.fetchContentData(baseUrl + href);
|
await store.fetchContentData(baseUrl + href);
|
||||||
document.title = store.pageTitle;
|
document.title = store.pageTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import { setActiveNavItem } from '../../utils/set-active-nav-item.js';
|
||||||
|
|
||||||
|
function clickRelatedElement(href) {
|
||||||
|
const baseUrl = window.location.protocol + "//" + window.location.host;
|
||||||
|
if (href.startsWith(baseUrl)) href = href.replace(baseUrl, '');
|
||||||
|
setActiveNavItem('etape', href);
|
||||||
|
displayRelatedElement(href);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
|
@ -597,6 +597,7 @@ body{
|
||||||
margin: 30px 0;
|
margin: 30px 0;
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
padding-right: 0.5rem;
|
||||||
transition: transform 0.3s ease-out, opacity 0.3s ease-out;
|
transition: transform 0.3s ease-out, opacity 0.3s ease-out;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
> .infos-arret {
|
> .infos-arret {
|
||||||
|
@ -1178,6 +1179,75 @@ body{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
> #animation-toggle > div {
|
||||||
|
cursor: pointer;
|
||||||
|
position: fixed;
|
||||||
|
bottom: $body-margin-bottom;
|
||||||
|
right: $body-margin-x;
|
||||||
|
z-index: 999;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.4rem 1.2rem;
|
||||||
|
border-radius: 10rem;
|
||||||
|
background-color: white;
|
||||||
|
transition: background-color 0.3s ease-out;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
margin-right: 1rem;
|
||||||
|
> p {
|
||||||
|
font-size: $sm-font-size-mobile;
|
||||||
|
@media screen and (min-width: $desktop-min-width) {
|
||||||
|
font-size: $sm-font-size-desktop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 2.2rem;
|
||||||
|
height: 1.2rem;
|
||||||
|
> input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
&:checked + .slider {
|
||||||
|
background-color: $brand-color;
|
||||||
|
}
|
||||||
|
&:focus + .slider {
|
||||||
|
box-shadow: 0 0 1px $brand-color;
|
||||||
|
}
|
||||||
|
&:checked + .slider::before {
|
||||||
|
-webkit-transform: translateX(1rem);
|
||||||
|
-ms-transform: translateX(1rem);
|
||||||
|
transform: translateX(1rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border-radius: 34px;
|
||||||
|
background-color: $main-color-light;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 1rem;
|
||||||
|
width: 1rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
left: 0.1rem;
|
||||||
|
bottom: 0.1rem;
|
||||||
|
background-color: $light-color;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
> .user-login-form {
|
> .user-login-form {
|
||||||
height: 90vh;
|
height: 90vh;
|
||||||
|
|
|
@ -52,5 +52,6 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div id="content-modale"></div>
|
<div id="content-modale"></div>
|
||||||
|
<div id="animation-toggle"></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
Loading…
Reference in New Issue