animations / add GSAP package

This commit is contained in:
HAM!DREZA
2024-05-04 19:55:34 +03:30
parent 10a012ec8e
commit 839a085e55
8 changed files with 606 additions and 96 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
node_modules/
.nuxt/
pages/text.vue
pages/test.vue
+1 -1
View File
@@ -6,7 +6,7 @@
src: url("/public/fonts/IRANSansWebFaNum.woff2");
}
html {
overflow-x: hidden;
overflow-x: hidden !important;
}
body {
direction: rtl;
+17 -3
View File
@@ -19,6 +19,7 @@
>
<g clip-path="url(#clip0_836_14934)">
<path
id="motion"
d="M1556 177.906L1458.57 214.144C1346.1 255.98 1222.32 255.968 1109.86 214.108L772.5 88.5484L643.155 59.2008C567.222 41.9719 488.315 42.7151 412.72 61.3711L236.5 104.86L6.56556 168.432L-22.8608 174.781L-53.8923 177.905L-109 177.905"
stroke="url(#paint0_linear_836_14934)"
stroke-width="2"
@@ -130,9 +131,22 @@
</div>
</template>
<script setup>
import { Swiper, SwiperSlide } from 'swiper/vue';
// Import Swiper styles
import 'swiper/css';
import { onMounted, onUnmounted, ref } from "vue";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { MotionPathPlugin } from "gsap/MotionPathPlugin";
gsap.registerPlugin(ScrollTrigger, MotionPathPlugin);
const main = ref();
let ctx;
onMounted(() => {
ctx = gsap.context((self) => {
gsap.to(".line #motion",
{strokeDashoffset: -300, repeat: -1, ease: "none", duration: 5});
})})
</script>
+53 -4
View File
@@ -1,17 +1,16 @@
<template>
<div
class="header h-[76.923vw] lg:h-[48.802vw] text-white flex flex-col items-center"
class="!max-w-[100vw] transform-bubbles header h-[76.923vw] lg:h-[48.802vw] text-white flex flex-col items-center"
>
<svg
class="animate absolute rotating -top-[59.231vw] lg:-top-[8.8vw] h-[120.513vw] lg:h-[44.688vw] w-[100vw] lg:w-[44.688vw]"
class="hidden lg:flex rotating-bubbles animate absolute rotating -top-[59.231vw] lg:!-top-[8.8vw] h-[120.513vw] lg:h-[44.688vw] w-[95%] !overflow-x-hidden lg:w-[44.688vw]"
viewBox="0 0 858 858"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
id="motion"
cx="429"
cy="429"
r="427.5"
@@ -34,6 +33,23 @@
</defs>
</svg>
<!-- <svg
class="arrow absolute h-[4.167vw] w-[4.167vw] rotate-180 lg:!top-[34vw]"
viewBox="0 0 80 80"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="40" cy="40" r="40" fill="white" />
<path
d="M27.5 34.4375V45.5625C27.5 52.4792 32.3958 55.2917 38.375 51.8542L41.0417 50.3125C41.6875 49.9375 42.0833 49.25 42.0833 48.5V31.5C42.0833 30.75 41.6875 30.0625 41.0417 29.6875L38.375 28.1458C32.3958 24.7083 27.5 27.5208 27.5 34.4375Z"
fill="#383E43"
/>
<path
d="M44.167 33.3125V46.7083C44.167 47.5208 45.042 48.0208 45.7295 47.6042L48.0212 46.2708C54.0003 42.8333 54.0003 37.1667 48.0212 33.7292L45.7295 32.3958C45.042 32 44.167 32.5 44.167 33.3125Z"
fill="#383E43"
/>
</svg> -->
<h1
class="text-[7.277vw] lg:text-[3.718vw] font-[700] mt-[100px] lg:mt-[120px] lg:mt-[9.115vw]"
>
@@ -52,4 +68,37 @@
</template>
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { MotionPathPlugin } from "gsap/MotionPathPlugin";
gsap.registerPlugin(ScrollTrigger, MotionPathPlugin);
const main = ref();
let ctx;
onMounted(() => {
ctx = gsap.context((self) => {
gsap.to(".rotating-bubbles", {
scrollTrigger: {
trigger: ".transform-bubbles",
scrub: 1,
start: "center center",
end: "+=5000",
},
rotation: 500,
duration: 3,
ease: "none",
}),
gsap.to(".animate #motion", {
strokeDashoffset: -300,
repeat: -1,
ease: "none",
duration: 5,
})
});
});
</script>
+131 -43
View File
@@ -1,15 +1,16 @@
<template>
<div
class="flex flex-col items-center border-t-[1px] border-[#E5E5E5] z-[1] min-h-[40vw] bg-[#FAF6F9] mt-8"
class="flex flex-col items-center border-t-[1px] border-[#E5E5E5] z-[1] min-h-[40vw] bg-[#FAF6F9] mt-[8vw]"
>
<h2
class="font-semibold text-[5.11vw] lg:text-[1.69vw] text-[#383E43] mt-24"
>
نقشه راه از تولید به مصرف محصولات شینان
</h2>
<div class="relative mt-[10vw] lg:mt-0 flex justify-center">
<div ref="main" class="relative mt-[10vw] lg:mt-0 flex justify-center">
<svg
class="box absolute mt-[8vw] lg:mt-12 h-[15.385vw] w-[15.385vw] lg:h-[5.625vw] lg:w-[5.625vw]"
id="motionSVG"
class="hidden lg:block box z-[1] absolute mt-[8vw] lg:mt-[2.4vw] h-[15.385vw] w-[15.385vw] lg:h-[5.625vw] lg:w-[5.625vw]"
viewBox="0 0 108 108"
fill="none"
xmlns="http://www.w3.org/2000/svg"
@@ -22,7 +23,7 @@
stroke-width="2"
stroke-dasharray="10 10"
/>
<circle cx="54" cy="54" r="23" fill="white" />
<circle cx="54" cy="54" r="23" fill="white"/>
<path
d="M57.3375 46.5L50.6625 46.5C46.5125 46.5 44.825 49.4375 46.8875 53.025L47.8125 54.625C48.0375 55.0125 48.45 55.25 48.9 55.25L59.1 55.25C59.55 55.25 59.9625 55.0125 60.1875 54.625L61.1125 53.025C63.175 49.4375 61.4875 46.5 57.3375 46.5Z"
fill="#383E43"
@@ -39,14 +40,32 @@
xmlns="http://www.w3.org/2000/svg"
>
<path
id="motionPath"
d="M779.997 -3.39639e-05V-3.39639e-05C779.997 51.3625 738.36 93 686.997 93L100.997 93C45.7681 93 0.996454 137.771 0.996452 193L0.996417 974C0.996415 1029.23 45.768 1074 100.996 1074L1457 1074C1512.23 1074 1557 1118.77 1557 1174L1557 1595C1557 1650.23 1512.22 1695 1457 1695L258.996 1695C203.767 1695 158.996 1739.77 158.996 1795L158.996 2065.5"
stroke="#383E43"
stroke-width="2"
stroke-dasharray="10 10"
/>
</svg>
<svg
class="block absolute lg:hidden mt-[20vw]"
class="box hidden absolute"
id="motionSVG"
width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="30" cy="30" r="29.5" stroke="#383E43" stroke-dasharray="5 5"/>
<circle cx="30" cy="30" r="18" fill="white"/>
<path d="M32.6698 24L27.3298 24C24.0098 24 22.6598 26.35 24.3098 29.22L25.0498 30.5C25.2298 30.81 25.5598 31 25.9198 31L34.0798 31C34.4398 31 34.7698 30.81 34.9498 30.5L35.6898 29.22C37.3398 26.35 35.9898 24 32.6698 24Z" fill="#383E43"/>
<path d="M33.2104 32L26.7804 32C26.3904 32 26.1504 32.42 26.3504 32.75L26.9904 33.85C28.6404 36.72 31.3604 36.72 33.0104 33.85L33.6504 32.75C33.8404 32.42 33.6004 32 33.2104 32Z" fill="#383E43"/>
</svg>
<svg
class="motionPath block absolute lg:hidden mt-[20vw]"
width="98vw"
height="359.487vw"
viewBox="0 0 390 1402"
@@ -54,6 +73,7 @@
xmlns="http://www.w3.org/2000/svg"
>
<path
id="motionPath"
d="M195.25 -8.51273e-06L195.211 9.21222C195.094 36.7434 172.743 59 145.212 59L50 59C22.3858 59 5.86356e-05 81.3858 5.88568e-05 109L6.27834e-05 599C6.30047e-05 626.614 22.3858 649 50.0001 649L339.999 649C367.613 649 389.999 671.386 389.999 699L389.999 1238C389.999 1265.61 367.613 1288 339.999 1288L245 1288C217.386 1288 195 1310.39 195 1338L195 1402"
stroke="#383E43"
stroke-dasharray="5 5"
@@ -66,47 +86,115 @@
</div>
</template>
<script setup>
// onMounted(() => {
// useGsap.to(".box", {
import { onMounted, onUnmounted, ref } from "vue";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
// scrollTrigger: {
// trigger: '.box',
// start: 'center center',
// end: 'bottom 20%',
// scrub: true,
// },
import { MotionPathPlugin } from "gsap/MotionPathPlugin";
gsap.registerPlugin(ScrollTrigger, MotionPathPlugin);
// });
const main = ref();
let ctx;
// let rotateTo = useGsap.quickTo(".box", "rotation");
// let prevDirection = 0;
// useGsap.to(".box", {
// motionPath: {
// path: 'M779.997 -3.39639e-05V-3.39639e-05C779.997 51.3625 738.36 93 686.997 93L100.997 93C45.7681 93 0.996454 137.771 0.996452 193L0.996417 974C0.996415 1029.23 45.768 1074 100.996 1074L1457 1074C1512.23 1074 1557 1118.77 1557 1174L1557 1595C1557 1650.23 1512.22 1695 1457 1695L258.996 1695C203.767 1695 158.996 1739.77 158.996 1795L158.996 2065.5',
onMounted(() => {
ctx = gsap.context((self) => {
gsap.to(".motionPath #motionPath",
{strokeDashoffset: -300, repeat: -1, ease: "none", duration: 5});
gsap.to("#motionSVG", {
scrollTrigger: {
trigger: "#motionSVG",
start: "top 30%",
end: () =>
"+=" +
document.querySelector("#motionPath").getBoundingClientRect().height,
scrub: 1,
},
ease: pathEase("#motionPath"), // the ease of the snap animation ("power3" by default)
// y: 700,
y: document.querySelector("#motionPath").getBoundingClientRect().height,
// immediateRender: true,
motionPath: {
path: "#motionPath",
align: "#motionPath",
alignOrigin: [0.5, 0.5],
autoRotate: -90,
},
});
function pathEase(path, config = {}) {
let axis = config.axis || "y",
precision = config.precision || 1,
rawPath = MotionPathPlugin.cacheRawPathMeasurements(
MotionPathPlugin.getRawPath(gsap.utils.toArray(path)[0]),
Math.round(precision * 12)
),
useX = axis === "x",
start = rawPath[0][useX ? 0 : 1],
end =
rawPath[rawPath.length - 1][
rawPath[rawPath.length - 1].length - (useX ? 2 : 1)
],
range = end - start,
l = Math.round(precision * 200),
inc = 1 / l,
positions = [0],
a = [],
minIndex = 0,
smooth = [0],
minChange = (1 / l) * 0.6,
smoothRange =
config.smooth === true ? 7 : Math.round(config.smooth) || 0,
fullSmoothRange = smoothRange * 2,
getClosest = (p) => {
while (positions[minIndex] <= p && minIndex++ < l) {}
a.push(
((p - positions[minIndex - 1]) /
(positions[minIndex] - positions[minIndex - 1])) *
inc +
minIndex * inc
);
smoothRange &&
a.length > smoothRange &&
a[a.length - 1] - a[a.length - 2] < minChange &&
smooth.push(a.length - smoothRange);
},
i = 1;
for (; i < l; i++) {
positions[i] =
(MotionPathPlugin.getPositionOnPath(rawPath, i / l)[axis] - start) /
range;
}
positions[l] = 1;
for (i = 0; i < l; i++) {
getClosest(i / l);
}
a.push(1); // must end at 1.
if (smoothRange) {
// smooth at the necessary indexes where a small difference was sensed. Make it a linear change over the course of the fullSmoothRange
smooth.push(l - fullSmoothRange + 1);
smooth.forEach((i) => {
let start = a[i],
j = Math.min(i + fullSmoothRange, l),
inc = (a[j] - start) / (j - i),
c = 1;
i++;
for (; i < j; i++) {
a[i] = start + inc * c++;
}
});
}
return (p) => {
let i = p * l,
s = a[i | 0];
return i ? s + (a[Math.ceil(i)] - s) * (i % 1) : 0;
};
}
});
}, main.value); // <- Scope!
// },
// scrollTrigger: {
// trigger: ".motionPath",
// start: "top center",
// end: () =>
// "+=" +
// document.querySelector(".motionPath")?.getBoundingClientRect().height,
// scrub: 0.5,
// markers: true,
// onUpdate: (self) => {
// if (prevDirection !== self.direction) {
// // only run this when we're changing direction
// rotateTo(self.direction === 1 ? 0 : -180);
// prevDirection = self.direction;
// }
// },
// },
// });
// });
onUnmounted(() => {
ctx.revert(); // <- Easy Cleanup!
});
</script>
+150 -20
View File
@@ -1,26 +1,156 @@
<template>
<div class="-z-[1] relative mt-[140vw] lg:mt-[50vw] flex flex-col items-center justify-center">
<div class="relative w-[87.69%] lg:w-[91.82%] flex flex-col items-center justify-center">
<svg class="absolute" width="48.125vw" height="48.125vw" viewBox="0 0 924 924" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="462" cy="462" r="461" stroke="#878787" stroke-width="2" stroke-dasharray="8 8"/>
</svg>
<svg class="absolute" width="75.365vw" height="75.365vw" viewBox="0 0 1447 1447" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="723.5" cy="723.5" r="722.5" stroke="#878787" stroke-width="2" stroke-dasharray="8 8"/>
</svg>
<div
ref="main"
id="flipSection"
class="-z-[1] relative mt-[100vw] lg:mt-[50vw] flex flex-col items-center justify-center"
>
<img
src="/public/images/assal.png"
alt="product-name"
class="z-[10] ax w-[18.205vw] lg:w-[17.292vw] h-[20.521vw]"
/>
<h1
class="font-bold text-[4.038vw] lg:text-[2.21vw] text-[#383E43] my-[2.083vw]"
>
عسل آقای عسل
</h1>
<p
class="text-[3.59vw] lg:text-[1.823vw] text-[#383E43] font-semibold"
dir="rtl"
>
510,000
<span class="text-[2.836vw] lg:text-[0.833vw] font-[400]">تومان</span>
</p>
<img
src="/public/images/assal.png"
alt="product-name"
class="w-[18.205vw] lg:w-[17.292vw] h-[20.521vw]"
/>
<h1 class="font-bold text-[4.038vw] lg:text-[2.21vw] text-[#383E43] my-[2.083vw]">عسل آقای عسل</h1>
<p class="text-[3.59vw] lg:text-[1.823vw] text-[#383E43] font-semibold" dir="rtl">
510,000
<span class="text-[2.836vw] lg:text-[0.833vw] font-[400]">تومان</span>
</p>
</div>
<div class="absolute">
<div
ref="start"
class="start relative w-[87.69%] lg:w-[91.82%] flex flex-col items-center justify-center"
>
<svg
class="small absolute"
width="40.125vw"
height="40.125vw"
viewBox="0 0 924 924"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="462"
cy="462"
r="461"
stroke="#878787"
stroke-width="2"
stroke-dasharray="8 8"
/>
</svg>
<svg
class="big absolute"
width="75.365vw"
height="75.365vw"
viewBox="0 0 1447 1447"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="723.5"
cy="723.5"
r="722.5"
stroke="#878787"
stroke-width="2"
stroke-dasharray="8 8"
/>
</svg>
</div>
</div>
</div>
</template>
<script setup>
// test
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { Flip } from "gsap/Flip";
gsap.registerPlugin(ScrollTrigger, Flip);
import gsap from "gsap";
const main = ref();
const start = ref();
const end = ref();
let ctx;
onMounted(() => {
const anim = gsap.fromTo(
".ax",
{ autoAlpha: 0, y: 50 },
{ duration: 1, autoAlpha: 1, y: 0 }
);
ScrollTrigger.create({
trigger: ".ax",
animation: anim,
repeat: -1,
scrub: true,
toggleActions: "play none none none",
}),
gsap
.timeline({
scrollTrigger: {
trigger: "#flipSection",
scrub: true,
pin: true,
start: "center center",
end: "+=800vw",
},
})
.from(".start", {
scale: 0.1,
}),
gsap.to(".small", {
scrollTrigger: {
trigger: "#flipSection",
scrub: 1,
start: "center center",
end: "+=800",
},
rotation: 500,
duration: 3,
ease: "none",
});
gsap.to(".big", {
scrollTrigger: {
trigger: "#flipSection",
scrub: 1,
start: "center center",
end: "+=800",
},
rotation: -500,
duration: 3,
ease: "none",
});
});
</script>
<style scoped>
.start.active {
visibility: hidden;
}
.start {
visibility: visible;
}
.start.flipping {
visibility: visible;
}
.end {
display: none;
}
.end.active {
display: flex !important;
}
.start,
.start.flipping {
visibility: visible;
}
</style>
+4 -1
View File
@@ -1,5 +1,4 @@
<template>
<div class="flex justify-center py-[20vw] md:py-[10vw]">
<div
class="w-[85%] md:w-[81.04%] flex flex-col md:flex-row justify-between"
@@ -53,3 +52,7 @@
</div>
</div>
</template>
<script setup>
</script>
+245 -19
View File
@@ -1,30 +1,256 @@
<template>
<div class="relative h-[97.436vw] md:h-[45.938vw] flex flex-col items-center">
<Carousel :autoplay="2000" :wrap-around="true" paginationColor="gray" paginationActiveColor="red">>
<Slide v-for="slide in 3" :key="slide">
<div class="carousel__item">{{ slide }}</div>
</Slide>
<div ref="main" class="scroller relative h-[1000px]">
<section class="orange">
<div class="text">This is some text inside of a div block.</div>
</section>
<template #addons>
<Pagination />
</template>
</Carousel>
<section class="black">
<div class="text-wrap">
<div class="panel-text blue-text">Blue</div>
<div class="panel-text red-text">Red</div>
<div class="panel-text orange-text">Orange</div>
<div class="panel-text purple-text">Purple</div>
</div>
<div class="p-wrap">
<div class="panel blue"></div>
<div class="panel red"></div>
<div class="panel orange"></div>
<div class="panel purple"></div>
</div>
</section>
<section class="blue"></section>
</div>
</template>
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import {Scrollbar} from "gsap/Scrollbar"
import { MotionPathPlugin } from "gsap/MotionPathPlugin";
gsap.registerPlugin(ScrollTrigger, Scrollbar);
const main = ref();
let ctx;
onMounted(() => {
let bodyScrollBar = Scrollbar.init(document.body, {
damping: 0.1,
delegateTo: document,
});
ScrollTrigger.scrollerProxy(".scroller", {
scrollTop(value) {
if (arguments.length) {
bodyScrollBar.scrollTop = value;
}
return bodyScrollBar.scrollTop;
},
});
bodyScrollBar.addListener(ScrollTrigger.update);
gsap.set(".panel", { zIndex: (i, target, targets) => targets.length - i });
var images = gsap.utils.toArray(".panel:not(.purple)");
images.forEach((image, i) => {
var tl = gsap.timeline({
scrollTrigger: {
trigger: "section.black",
scroller: ".scroller",
start: () => "top -" + window.innerHeight * (i + 0.5),
end: () => "+=" + window.innerHeight,
scrub: true,
toggleActions: "play none reverse none",
invalidateOnRefresh: true,
},
});
tl.to(image, { height: 0 });
});
gsap.set(".panel-text", {
zIndex: (i, target, targets) => targets.length - i,
});
var texts = gsap.utils.toArray(".panel-text");
texts.forEach((text, i) => {
var tl = gsap.timeline({
scrollTrigger: {
trigger: "section.black",
scroller: ".scroller",
start: () => "top -" + window.innerHeight * i,
end: () => "+=" + window.innerHeight,
scrub: true,
toggleActions: "play none reverse none",
invalidateOnRefresh: true,
},
});
tl.to(text, { duration: 0.33, opacity: 1, y: "50%" }).to(
text,
{ duration: 0.33, opacity: 0, y: "0%" },
0.66
);
});
ScrollTrigger.create({
trigger: "section.black",
scroller: ".scroller",
scrub: true,
markers: true,
pin: true,
start: () => "top top",
end: () => "+=" + (images.length + 1) * window.innerHeight,
invalidateOnRefresh: true,
});
});
</script>
<style scoped>
</style>
body,
html {
margin: 0;
}
.scroller {
height: 100vh;
}
.orange {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
height: 100vh;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
background-color: #753500;
}
.text {
color: #fff;
}
.black {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
height: 100vh;
-webkit-justify-content: space-around;
-ms-flex-pack: distribute;
justify-content: space-around;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
background-color: #070707;
}
.blue {
height: 100vh;
background-color: #00026d;
}
.text-wrap {
position: relative;
overflow: hidden;
width: 450px;
height: 80vh;
}
.panel-text {
position: absolute;
left: 0%;
top: 0%;
right: 0%;
bottom: 0%;
z-index: 1;
width: 100%;
height: 100%;
font-size: 40px;
text-transform: uppercase;
font-weight: 900;
text-align: center;
background-color: #070707;
transform: translateY(100%);
opacity: 0;
}
.panel-text.blue-text {
color: blue;
}
.panel-text.red-text {
color: red;
}
.panel-text.purple-text {
color: purple;
}
.panel-text.orange-text {
color: orange;
}
.p-wrap {
position: relative;
overflow: hidden;
width: 450px;
height: 80vh;
}
.panel {
position: absolute;
left: 0%;
top: 0%;
right: 0%;
bottom: 0%;
z-index: 1;
width: 100%;
height: 100%;
background-image: url("../images/5ed12171d9d512cb2feead83_5.jpg");
background-position: 50% 50%;
background-size: cover;
background-repeat: no-repeat;
}
.panel._2 {
z-index: 1;
background-image: url("../images/5f5a5b3515c4dd0c2c455925_110642301_938622823267359_7859124022958180678_n201.jpg");
}
.panel.blue {
z-index: auto;
}
.panel.red {
z-index: auto;
background-color: red;
background-image: none;
}
.panel.orange {
z-index: auto;
background-color: #cf5d00;
background-image: none;
}
.panel.purple {
z-index: auto;
background-color: #808;
background-image: none;
}
</style>