238 lines
8.0 KiB
Vue
238 lines
8.0 KiB
Vue
<template>
|
|
<div
|
|
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] md:text-[1.69vw] text-[#383E43] mt-24"
|
|
>
|
|
نقشه راه از تولید به مصرف محصولات شینان
|
|
</h2>
|
|
<div ref="main" class="relative mt-[10vw] md:mt-0 flex justify-center">
|
|
<svg
|
|
id="motionSVG"
|
|
class="hidden md:block box z-[1] absolute mt-[8vw] md:mt-[2.4vw] h-[15.385vw] w-[15.385vw] md:h-[5.625vw] md:w-[5.625vw]"
|
|
viewBox="0 0 108 108"
|
|
fill="none"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
>
|
|
<circle
|
|
cx="54"
|
|
cy="54"
|
|
r="53"
|
|
stroke="#383E43"
|
|
stroke-width="2"
|
|
stroke-dasharray="10 10"
|
|
/>
|
|
<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"
|
|
/>
|
|
<path
|
|
d="M58.0125 56.5L49.9751 56.5C49.4876 56.5 49.1876 57.025 49.4376 57.4375L50.2376 58.8125C52.3001 62.4 55.7001 62.4 57.7626 58.8125L58.5625 57.4375C58.8 57.025 58.5 56.5 58.0125 56.5Z"
|
|
fill="#383E43"
|
|
/>
|
|
</svg>
|
|
|
|
<svg
|
|
class="motionPath hidden md:block absolute mt-[8vw] w-[81.146vw] h-[107.604vw]"
|
|
viewBox="0 0 1558 2066"
|
|
fill="none"
|
|
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="mobileMotionPath block absolute md:hidden mt-[20vw] w-[98vw] h-[359.487vw]"
|
|
viewBox="0 0 390 1402"
|
|
fill="none"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
>
|
|
<path
|
|
id="mobileMotionPath"
|
|
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"
|
|
/>
|
|
</svg>
|
|
|
|
<svg
|
|
class="block md:hidden mobilBox z-[1] absolute mt-[8vw] h-[15.385vw] w-[15.385vw]"
|
|
id="mobileMotionSVG"
|
|
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>
|
|
</div>
|
|
<home-page-road-map-componentsBanner />
|
|
<home-page-road-map-componentsProductionStage />
|
|
<home-page-road-map-componentsShopNavigator />
|
|
</div>
|
|
</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(".motionPath #motionPath", {
|
|
strokeDashoffset: -300,
|
|
repeat: -1,
|
|
ease: "none",
|
|
duration: 5,
|
|
});
|
|
gsap.to("#motionSVG", {
|
|
scrollTrigger: {
|
|
trigger: "#motionSVG",
|
|
start: "top 10%",
|
|
end: () =>
|
|
"+=" +
|
|
document.querySelector("#motionPath").getBoundingClientRect().height,
|
|
scrub: 1,
|
|
},
|
|
ease: "slow(0.7,0.7,false)",
|
|
y: document.querySelector("#motionPath").getBoundingClientRect().height,
|
|
motionPath: {
|
|
path: "#motionPath",
|
|
align: "#motionPath",
|
|
alignOrigin: [0.5, 0.5],
|
|
autoRotate: -90,
|
|
},
|
|
});
|
|
gsap.to(".mobileMotionPath #mobileMotionPath", {
|
|
strokeDashoffset: -300,
|
|
repeat: -1,
|
|
ease: "none",
|
|
duration: 5,
|
|
});
|
|
gsap.to("#mobileMotionSVG", {
|
|
scrollTrigger: {
|
|
trigger: "#mobileMotionSVG",
|
|
start: "top 20%",
|
|
end: () =>
|
|
"+=" +
|
|
document.querySelector("#mobileMotionPath").getBoundingClientRect().height,
|
|
scrub: 1,
|
|
},
|
|
ease: "slow(0.7,0.7,false)", // the ease of the snap animation ("power3" by default)
|
|
// y: 700,
|
|
y: document.querySelector("#mobileMotionPath").getBoundingClientRect().height,
|
|
// immediateRender: true,
|
|
motionPath: {
|
|
path: "#mobileMotionPath",
|
|
align: "#mobileMotionPath",
|
|
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!
|
|
|
|
onUnmounted(() => {
|
|
ctx.revert(); // <- Easy Cleanup!
|
|
});
|
|
</script> |