Files
drupal-mathallo/web_main/themes/custom/mathallo/assets/js/main.js
2026-02-20 11:09:55 +01:00

381 lines
12 KiB
JavaScript

import { createApp } from 'vue'
import '../scss/main.scss'
import Content from './vuejs/Content.vue'
import REST from './api/rest-axios'
// import LocomotiveScroll from 'locomotive-scroll';
// const scroll = new LocomotiveScroll();
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { ScrollSmoother } from "gsap/ScrollSmoother";
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);
// /**
// * @file
// * reha behaviors.
// * https://www.drupal.org/docs/drupal-apis/javascript-api/javascript-api-overview
// */
// (function (Drupal) {
// 'use strict';
// Drupal.behaviors.reha = {
// attach: function (context, settings) {
// console.log('It works!');
// }
// };
// } (Drupal));
(function (Drupal, drupalSettings) {
const MathalloTheme = function () {
const _is_front = drupalSettings.path.isFront
console.log('drupalSettings', drupalSettings)
// liste forme file names
const formesclasses = [
'pyramide',
'prct',
'infinite',
'pi',
'supeg',
'cone',
'croissant',
'cube',
'diamant',
'cylindre'
]
let sizes = [];
// ___ _ _
// |_ _|_ _ (_) |_
// | || ' \| | _|
// |___|_||_|_|\__|
function init () {
console.log('MathalloTheme init()')
initBurgerMenu();
initPartieFrontBackCardSwitch();
initBgFormes();
initBgAnime();
// initVues()
}
function initBurgerMenu() {
let header_right = document.getElementById('burger-btn');
header_right.parentElement.addEventListener('click', function(e){
// console.log('click header_right', this);
this.firstElementChild.toggleAttribute('opened');
this.firstElementChild.nextElementSibling.toggleAttribute('opened');
})
}
function initPartieFrontBackCardSwitch() {
let principes_pratique = document.getElementById('partie-principes-pratique');
if (principes_pratique) {
let cards = principes_pratique.getElementsByClassName('field-card');
// console.log('cards', cards);
for (const card of cards) {
card.addEventListener('mousemove', function (e) {
// console.log(this, e);
for (const child of this.parentElement.children){
child.classList.add('back-card')
child.classList.remove('front-card');
}
this.classList.add('front-card')
this.classList.remove('back-card')
})
}
}
}
async function initBgFormes(){
const container = document.querySelector('main[role="main"] > .layout-content > .wrapper');
// console.log('container', container);
// listes all available sizes
// let min = 150;
// let increment = Math.round((350 / (formesclasses.length -1)));
// for (let i = 0; i < formesclasses.length; i++) {
// sizes.push( min + increment * i)
// }
// console.log('sizes', sizes);
let cards = document.querySelectorAll('article[role="home-presentation"], .field-card, .node-type-chapitre, .node-type-partie');
// console.log('cards', cards);
let used_n = [];
let oddeven=1;
for (const card of cards) {
// console.log('card', card);
// random forme
// avoid duplicated formes
let n = Math.round(Math.random() * (formesclasses.length -1));
while (used_n.includes(n)) {
n = Math.round(Math.random() * (formesclasses.length -1));
}
used_n.push(n);
// console.log('n',n, 'class', formesclasses[n]);
let forme = await createForme(card, n);
container.prepend(forme);
// Snap au centre de la fenêtre pour la card en utilisant le plugin Snap de GSAP
// ScrollTrigger.create({
// trigger: document.querySelector('.partie-principes-pratique'),
// start: "top 60%",
// end: "bottom 40%",
// snap: {
// snapTo: "top", // Snap au centre de la fenêtre
// duration: {min: 0.2, max: 0.5}, // Durée de l'animation de snap
// delay: 0, // Pas de délai
// ease: "power3.out" // Type d'easing pour l'animation
// }
// });
// Animation des cards au scroll
gsap.timeline({
scrollTrigger: {
trigger: card,
start: "top bottom",
end: "bottom top",
scrub: true,
ease: "power4.out",
snap: false,
// markers: true,
// onToggle: (self) => {
// console.log('card scroll toggled, self:', self)
// },
}
})
// cards opacity
.from(card.children, {
opacity: 0.4,
}, 0)
.to(card.children, {
opacity: 1,
}, 0.5)
.to(card.children, {
opacity: 0.4,
}, 0.7)
// cards mvmt
.from(card, {
translateX: `${200 * oddeven}px`,
translateY: `${100 * oddeven}px`
}, 0)
.to(card, {
translateX: "0",
translateY: "0"
}, 0.5);
// .to(card, {
// translateX: `${200 * oddeven}px`,
// }, 0.9);
// Animation des formes continue de rotation + skew pendant tout le scroll
gsap.to(forme.querySelector('svg'), {
scrollTrigger: {
trigger: forme,
start: "top bottom",
end: "bottom top",
scrub: true,
ease: "power4.out"
},
rotation: Math.random() > 0.5 ? 45 : -45,
skewX: Math.random() > 0.5 ? 10 : -10
});
// Animation de couleur des formes uniquement au centre de l'écran
gsap.timeline({
scrollTrigger: {
trigger: card,
start: "top center", // Commence quand le haut de l'élément atteint le centre
end: "bottom center", // Termine quand le bas de l'élément passe le centre
scrub: true,
markers: false // Désactivez les marqueurs en production
}
})
.to(forme.querySelector('svg'), {
stroke: "#f661e2", // Passage au rose
duration: 0.1
}, 0.3) // Au milieu de la timeline (centre de l'écran)
.to(forme.querySelector('svg'), {
stroke: "#1642bc", // Retour au bleu
duration: 0.1
}, 0.7); // Juste après le centre
// inverse oddeven
oddeven*=-1;
}
}
async function createForme(card, n){
let forme = document.createElement('div');
forme.classList.add('bg-forme');
// forme.classList.add(formesclasses[n]);
// inject svg from file
const response = await fetch(`/themes/custom/mathallo/assets/img/formes/${formesclasses[n]}.svg`)
const svgText = await response.text();
forme.innerHTML = svgText;
// get the svg ode
const svgNode = forme.querySelector('svg');
// random size
let wh = 200 + Math.random()*300;
// OR
// pic a size
// let wh = sizes.splice(Math.floor(Math.random() * sizes.length), 1)[0];
// record the original scale for stroke width rescalling
const init_wh = svgNode.getAttribute('width');
// set the new size
forme.style.width = forme.style.height = `${wh}px`;
svgNode.setAttribute('width', wh);
svgNode.setAttribute('height', wh);
// // keep stroke width to visualy 1px
// let scale = wh / init_wh;
// const paths = svgNode.querySelectorAll('path, line, rect, circle, ellipse, polygon, polyline');
// // console.log('paths', paths);
// paths.forEach(path => {
// const init_SW = parseFloat(path.getAttribute('stroke-width')) || 1;
// let new_SW = init_SW / scale;
// path.setAttribute('stroke-width', `${new_SW}px`);
// path.style.strokeWidth = `${new_SW}px`;
// });
// random position
// top
let top = card.offsetTop + card.clientHeight/2 - wh/2;
if (card.clientHeight < 300) {
top = Math.random() > 0.5
? card.offsetTop - wh/2 // on top
: card.offsetTop + card.clientHeight - wh/2; // on bottom
}
forme.style.top = `${top}px`;
let randoffset = 20 + Math.random() * 20;
// left right
if (card.classList.contains('field-principes-reflexion')) {
// left
forme.style.left = `${card.offsetLeft - wh + randoffset}px`;
} else if(card.classList.contains('field-en-pratique')) {
// right
forme.style.left = `${card.offsetLeft + card.clientWidth - randoffset}px`;
} else {
// random
forme.style.left = Math.random() > 0.5
? `${card.offsetLeft - wh + randoffset}px`
: `${card.offsetLeft + card.clientWidth - randoffset}px`;
}
return forme;
}
function initBgAnime(){
gsap.to('body', {
scrollTrigger: 'main[role="main"]', // start animation when ".box" enters the viewport
backgroundPositionY: 10
});
ScrollSmoother.create({
smooth: 3, // how long (in seconds) it takes to "catch up" to the native scroll position
effects: true, // looks for data-speed and data-lag attributes on elements
smoothTouch: 0.1, // much shorter smoothing time on touch devices (default is NO smoothing on touch devices)
wrapper: 'main[role="main"]',
content: 'main[role="main"]>.layout-content'
});
gsap.to('#parallax-bg', {
y: (i, target) => -(ScrollTrigger.maxScroll(window) * 1.2),
ease: "none",
scrollTrigger: {
trigger: 'main[role="main"] > .layout-content > .wrapper',
start: "top bottom",
end: "bottom top",
scrub: true,
invalidateOnRefresh: true
}
});
}
// function initVues(){
// console.log('initVues');
// // initVueContent();
// }
// function initVueContent(){
// createApp(Content).mount('main[role="main"]');
// // processEtapeLinks();
// }
// function onClickEtapeLink(e){
// e.preventDefault();
// let a = e.currentTarget;
// let nid = a.dataset.nodeNid;
// console.log(nid);
// getNodeData(nid);
// return null;
// }
// function processEtapeLinks(){
// let etape_link_fields = document.querySelectorAll('#etapes-liste div.views-field-title');
// etape_link_fields.forEach((field, index) => {
// let nid = null;
// let classList = field.classList;
// classList.forEach((classe) => {
// let reg = /data-node-(\d+)/;
// let result = classe.match(reg);
// if (result) {
// nid = result[1];
// console.log(nid);
// }
// })
// if (nid) {
// let a = field.querySelector('a');
// a.setAttribute('data-node-nid', nid);
// a.addEventListener('click', onClickEtapeLink);
// }
// })
// }
// function getNodeData(nid){
// const params = {
// }
// REST.get(`/node/${nid}?_format=json`, params)
// .then((data) => {
// console.log('user REST getUser data', data)
// })
// .catch(error => {
// console.warn('Issue with getNodedata', error)
// Promise.reject(error)
// })
// }
init()
} // end MathalloTheme()
MathalloTheme()
})(Drupal, drupalSettings)