Untitled
unknown
plain_text
2 years ago
12 kB
8
Indexable
<template> <div class="l__marquee" v-show="isItMobile === false" ref="el"> <div ref="fullscreenBackground" class="fullscreen-background"></div> <div class="marquee home__marquee noimagemarquee"> <div ref="marquee" class="marquee__inner"> <div class="home__project marquee--item" v-for="(project, index) in filteredProjects" :key="project.project.uid" > <div draggable="false" class="title--container" ref="titleItems" :data-index="index" :data-to="'/project/' + project.project.uid" :data-thumbnail="project?.project?.data?.project_visual?.url || ''" :data-projectid="project?.project?.uid" :data-projectName="project?.project?.data?.project_name" data-section-slider > <h1 ref="titleItem" class="title"> {{ project.project.data.client_name }} </h1> </div> </div> </div> </div> <div ref="mouseleave" class="mouseleave"></div> </div> </template> <script setup> import { nextTick, onMounted, ref } from "vue"; import { gsap } from "gsap"; import Marquee from "@/librairies/Marquee.js"; import { useFirstLoaded } from "../composables/state"; import { isItMobile } from "../composables/useMobile"; import { SplitText } from "gsap/SplitText"; const { $bus } = useNuxtApp(); const el = ref(null); const marquee = ref(null); const mouseleave = ref(null); const titleItem = ref([]); const titleItems = ref(null); const fullscreenBackground = ref(null); let elements, mouse, font, scroll, marqueeInstance, baseFontHeight, isRunning = false; const { client } = usePrismic(); const { data: homepage } = await useAsyncData("Homepage", () => client.getSingle("homepage_projects", { fetchLinks: [ "project.project_name", "project.client_name", "project.uid", "project.project_visual", ], }) ); const filteredProjects = computed(() => { return homepage.value.data.featured_projects.filter( (project) => project.project.uid !== currentRoute ); }); const router = useRouter(); const currentRoute = router.currentRoute.value.params.id; onMounted(() => { watch( isItMobile, async (value) => { if (!value && isRunning === false) { await nextTick(); preloadImages(); initVariables(); mouse = window.mouse; initPageAnimations(); if (useFirstLoaded().value === true) { initPageEntrance(); } if (marqueeInstance === undefined) { marqueeInstance = new Marquee(marquee.value); } else { marqueeInstance.reset(); } setTimeout(() => { onResize(); }, 150); initListeners(); isRunning = true; document.body.classList.add("--homepage-modifier"); document .querySelector(".l__layout") .classList.add("--homepage-modifier"); } else if (value) { removeListeners(); isRunning = false; document.body.classList.remove("--homepage-modifier"); document .querySelector(".l__layout") .classList.remove("--homepage-modifier"); } }, { immediate: true } ); }); $bus.$on("loaded", () => { initPageEntrance(); }); const preloadImages = () => { titleItems.value.forEach((element) => { const type = checkFileType(element.dataset.thumbnail); if (type === "image") { const img = new Image(); img.src = element.dataset.thumbnail; } else if (type === "video") { let mediaElement = document.createElement("video"); mediaElement.preload = "auto"; mediaElement.src = element.dataset.thumbnail; mediaElement.load(); } }); }; const checkFileType = (url) => { url = url.split("?")[0]; const imageRegex = /\.(jpeg|jpg|gif|png)$/; const videoRegex = /\.(mp4)$/; if (url.match(imageRegex)) { return "image"; } else if (url.match(videoRegex)) { return "video"; } else { return "unknown"; } }; const initVariables = () => { elements = []; font = { height: 1, }; scroll = { ease: 0.05, current: 0, target: 0, }; baseFontHeight = window.innerWidth < 1024 ? 35 : 1; }; const initPageAnimations = () => { splitText(); }; const splitText = () => { titleItem.value.forEach((element) => { new SplitText(element, { type: "words, lines, chars", wordsClass: "SplitTextJS-wrapper", charsClass: "SplitTextJS-char", }); }); elements = el.value.querySelectorAll(".SplitTextJS-char"); }; const initPageEntrance = () => { titleItems.value.forEach((title, index) => { gsap.to(title, { y: 0, opacity: 1, ease: "expo.inOut", duration: 2.5, delay: -0.8 + index * 0.05, overwrite: true, }); }); }; const onTitleClick = async (e) => { if (window.isDragging) return; const link = e.target.dataset.to; titleItem.value.forEach((element) => { gsap.set(element, { color: "white", opacity: 0.25, }); }); const transitionTL = gsap.timeline({ defaults: { ease: "expo.inOut", duration: 1.5, }, }); transitionTL.to( ".SplitTextJS-wrapper", { y: 500, opacity: 0, duration: 1.2, ease: "expo.inOut", }, 0 ); await navigateTo(link); }; const initListeners = () => { window.addEventListener("resize", () => { marqueeInstance.onResize(); }); mouseleave.value.addEventListener("mouseenter", onContainerEnter); marquee.value.addEventListener("mouseover", onMarqueeMouseOver); marquee.value.addEventListener("mouseenter", onMarqueeMouseEnter); marquee.value.addEventListener("mouseleave", onMarqueeMouseLeave); document.addEventListener("mouseleave", onDocumentLeave); titleItems.value.forEach((element, index) => { element.addEventListener("mouseenter", () => { onTitleMouseEnter(element); }); element.addEventListener("mouseover", () => { onTitleMouseOver(element, index); }); element.addEventListener("mouseleave", () => { onTitleMouseLeave(); }); element.addEventListener("click", onTitleClick); }); }; const removeListeners = () => { // window.removeEventListener("resize", marqueeInstance.onResize); marquee.value.removeEventListener("mouseover", onMarqueeMouseOver); marquee.value.removeEventListener("mouseleave", onMarqueeMouseLeave); mouseleave.value.removeEventListener("mouseenter", onContainerEnter); document.removeEventListener("mouseleave", onDocumentLeave); window.removeEventListener("mousemove", onTitleMouseMove); titleItems.value.forEach((element) => { element.removeEventListener("mouseover", onTitleMouseOver); element.removeEventListener("mouseleave", onTitleMouseLeave); element.removeEventListener("mouseenter", onTitleMouseEnter); element.removeEventListener("click", onTitleClick); }); }; const onDocumentLeave = () => { resetLetters(); }; const resetLetters = () => { const titleCharacters = el.value.querySelectorAll(".SplitTextJS-char"); titleCharacters.forEach((letter) => { const fontPerLetter = { height: letter.style.getPropertyValue("--fontHeight") || baseFontHeight, }; gsap.to(letter, { fontSize: "19rem", duration: 0.2, }); gsap.to(fontPerLetter, { height: 1, duration: 0.2, onUpdate: () => { letter.style.setProperty( "--fontHeight", fontPerLetter.height || baseFontHeight ); }, }); }); }; const onContainerEnter = () => { resetLetters(); }; const onTitleMouseEnter = (element) => { const media = element.dataset.thumbnail; const fileType = checkFileType(media); let mediaElement; if (fileType === "video") { mediaElement = document.createElement("video"); mediaElement.playsInline = true; mediaElement.loop = true; mediaElement.muted = true; mediaElement.controls = false; mediaElement.classList.add("fullscreen-background--media"); mediaElement.src = media; mediaElement.load(); mediaElement.play(); } else if (fileType === "image") { mediaElement = document.createElement("img"); mediaElement.classList.add("fullscreen-background--media"); mediaElement.src = media; } fullscreenBackground.value.append(mediaElement); const existingVideo = document.querySelector(".fullscreen-background--media"); if (existingVideo) { gsap.to(existingVideo, { opacity: 0, duration: 0.2, onComplete: () => existingVideo.remove(), }); } gsap.to(mediaElement, { opacity: 1, scale: 1, duration: 0.3, overwrite: "auto", }); }; const onTitleMouseOver = (element, index) => { // CHARACTERS ANIMATION ON MOUSEMOVE window.addEventListener("mousemove", onTitleMouseMove); marqueeInstance.isHovering = 0; // STOP AUTOSCROLL }; const onTitleMouseLeave = (event) => { marqueeInstance.isHovering = 1; // STOP AUTOSCROLL scroll.target = 0; scroll.current = 0; }; const onTitleMouseMove = (element) => { const index = Number(element.target.dataset.index); const elements = [ el.value.querySelector( `[data-index='${index <= 0 ? titleItems.value.length - 1 : index - 1}']` ), el.value.querySelector(`[data-index='${index}']`), el.value.querySelector( `[data-index='${ index + 1 > titleItems.value.length - 1 ? 0 : index + 1 }']` ), ]; if (elements[0] === null) return; const titleCharacters = []; elements.forEach((element) => { const characters = element.querySelectorAll(".SplitTextJS-char"); titleCharacters.push(...characters); }); titleCharacters.forEach((elem) => { if (elem.innerHTML === " ") return; adjustImage(elem, mouse?.position?.x, mouse?.position?.y); }); }; const onMarqueeMouseOver = () => { marqueeInstance.marqueeSpeed = 0; }; const onMarqueeMouseEnter = () => { gsap.to(".cursor__drag", { opacity: 1, duration: 0.3 }); }; const onMarqueeMouseLeave = () => { marqueeInstance.marqueeSpeed = 0.5; const allVideos = document.querySelectorAll(".fullscreen-background--media"); gsap.to(allVideos, { opacity: 0, duration: 0.3, onComplete: () => { allVideos.forEach((video) => video.remove()); }, }); gsap.to(".cursor__drag", { opacity: 0, duration: 0.3 }); }; const calculateCenter = (elem) => { var rect1 = elem.getBoundingClientRect(); var x = rect1.left + rect1.width * 0.5; var y = rect1.top + rect1.height * 0.99; return { x: x, y: y }; }; const getDistance = (x1, y1, x2, y2) => { let y = x2 - x1; let x = y2 - y1; return Math.sqrt(x * x + y * y); }; const distanceFromCenter = (image, mouseX, mouseY) => { var imageCenter = calculateCenter(image); return getDistance(imageCenter.x, imageCenter.y, mouseX, mouseY); }; const adjustImage = (image, mX, mY) => { var distance = distanceFromCenter(image, mX, mY); const baseScale = 1; const maxScaling = 1.2; const scalingFactor = 1; const adjustedScaling = maxScaling - (distance / 1500) * scalingFactor; let scaling = adjustedScaling >= baseScale ? adjustedScaling : baseScale; scaling = Math.max(1, scaling); gsap.set(image, { fontSize: 19 + (scaling - 1) * scaling * 15 + "rem", }); gsap.set(font, { height: 1 + (scaling - 1) * scaling * 250, duration: 0.5, onUpdate: () => { image.style.setProperty("--fontHeight", font.height); }, }); }; const onResize = () => { marqueeInstance.onResize(); }; onBeforeUnmount(() => { if (isItMobile === true) return; document.body.classList.remove("--homepage-modifier"); document.querySelector(".l__layout").classList.remove("--homepage-modifier"); gsap.to(".cursor__drag", { opacity: 0, duration: 0.3 }); removeListeners(); elements = []; mouse = { x: null, y: null, }; mouse = null; font = { height: null, }; }); </script> <style lang="scss"> @import "@/assets/css/pages/home.scss"; </style>
Editor is loading...