// 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 = []; let _cardsForms = []; let smoother = null; let fn_modale; let mouse_pos = {x:0,y:0}; // ___ _ _ // |_ _|_ _ (_) |_ // | || ' \| | _| // |___|_||_|_|\__| function init () { console.log('MathalloTheme init()') initBurgerMenu(); initPartieFrontBackCardSwitch(); initHome(); initBgFormes(); initBgAnime(); initFootnotes(); // 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') }) } } } function onWindowResize() { _cardsForms.forEach(({card, forme, formepos}) => { // console.log(`card`, card, 'forme', forme, 'formepos', formepos); forme.style.top = `${card.offsetTop + formepos.top}px`; forme.style.left = `${card.offsetLeft + formepos.left}px`; }) } function initHome(){ let ps = document.querySelectorAll('article[role="home-presentation"] p'); let used_n = []; for (const p of ps) { 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); p.classList.add(`forme-${_formesclasses[n]}`); } } 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); let cardFormObject = { 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); // register forme cardFormObject.forme = forme; // register relative position of forme against card cardFormObject.formepos = { left: forme.offsetLeft - card.offsetLeft, top: forme.offsetTop - card.offsetTop } // register cards and formes _cardsForms.push(cardFormObject); // console.log('_cardsForms', _cardsForms); // create GSAP animations createGsapAnims(card, forme, oddeven); // inverse oddeven oddeven*=-1; } window.addEventListener('resize', onWindowResize); } function createGsapAnims(card, forme, oddeven){ // 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 } 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 response = await fetch(`/themes/custom/mathallo/assets/img/formes/bordure/${_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') || card.classList.contains('field-ressources')) { // left forme.style.left = `${card.offsetLeft - wh + randoffset}px`; } else if(card.classList.contains('field-en-pratique') || card.classList.contains('field-plus-loin')) { // 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 // }); smoother = 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', onUpdate: onUpdateSmoother }); console.log('smoother', smoother); 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 onUpdateSmoother(sm){ // console.log('onUpdateSmoother', sm); // let content = sm.content(); updateFnModalePos(); } function initFootnotes(){ // let container = document.querySelector('main[role="main"]>div.layout-content>.wrapper'); let container = document.body; fn_modale = document.createElement('div'); fn_modale.classList.add('fn-modale'); container.append(fn_modale); let fns = document.querySelectorAll('.footnote__citation'); // console.log('fns', fns); let used_n = []; for (const fn of fns) { console.log('fn', fn); // set a random class for icone 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); fn.querySelector('span.footnote-link').classList.add(`forme-${_formesclasses[n]}`); // events fn.addEventListener('mouseenter', onMouseEnterFN); fn.addEventListener('mouseleave', onMouseLeaveFN); // fn.addEventListener('mousemove', onMouseMove); } window.addEventListener('mousemove', onMouseMove); } function onMouseEnterFN(event){ console.log('onMouseEnterFN, event:', event); fn_modale.innerHTML = event.target.querySelector('.footnote-content').innerHTML; fn_modale.classList.add('visible'); // fn_modale.style.left = `${event.clientX}px`; // fn_modale.style.top = `${event.clientY}px`; } function onMouseLeaveFN(event){ console.log('onMouseLeaveFN, event:', event); fn_modale.classList.remove('visible'); setTimeout(function(){ fn_modale.innerHTML = ""; }, 1000); // fn_modale.style.left = `${event.clientX}px`; // fn_modale.style.top = `${event.clientY}px`; } function onMouseMove(event){ // console.log('onMouseMove, event:', event); mouse_pos = { x:event.clientX, y:event.clientY } updateFnModalePos(); } function updateFnModalePos(){ if (smoother) { let cont = smoother.content(); console.log('cont', cont); let rect = cont.getBoundingClientRect(); // console.log(`mouse_pos.x=${mouse_pos.x} | window.innerWidth/2=${window.innerWidth/2}`); let compensed_mouse_pos = { x: mouse_pos.x - rect.left, y: mouse_pos.y - rect.top + cont.offsetTop } let decalage = 20; if (mouse_pos.x < window.innerWidth/2) { fn_modale.style.left = `${compensed_mouse_pos.x + decalage}px`; }else{ fn_modale.style.left = `${compensed_mouse_pos.x - fn_modale.clientWidth - decalage}px`; } // let componsed_mouse_posy = mouse_pos.y - rect.top + 370; if (mouse_pos.y < window.innerHeight / 2) { // fn_modale.style.top = `${componsed_mouse_posy - fn_modale.clientHeight + 60}px`; fn_modale.style.top = `${compensed_mouse_pos.y + decalage}px` } else{ // fn_modale.style.top = `${componsed_mouse_posy - 60}px`; fn_modale.style.top = `${compensed_mouse_pos.y - fn_modale.clientHeight - decalage}px` } console.log('window', window); } else{ console.warn('no smoother'); } } // 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)