Refactor code structure for improved readability and maintainability

This commit is contained in:
susovan sarkar 2026-08-24 12:08:35 +05:30
parent cc6249db24
commit 253d6a0c5f
4 changed files with 140 additions and 58 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -17,7 +17,7 @@ document.addEventListener('DOMContentLoaded', () => {
/* /*
Reusable Car Animation Setup Reusable Car Animation Setup
*/ */
function setupRoadAnimation(svgId, pathId, carId, mainAreaSelector, screenId, speed = 0.00016) { function setupRoadAnimation(svgId, pathId, carId, mainAreaSelector, screenId, speed = 0.00016, pointNames = null) {
const svgEl = document.getElementById(svgId); const svgEl = document.getElementById(svgId);
const pathEl = document.getElementById(pathId); const pathEl = document.getElementById(pathId);
const car = document.getElementById(carId); const car = document.getElementById(carId);
@ -45,6 +45,71 @@ document.addEventListener('DOMContentLoaded', () => {
return { scale, offsetX, offsetY, rect }; return { scale, offsetX, offsetY, rect };
} }
/* Arrival-triggered "point" reveal
Each named point is the marker + leader line + label that's
already baked into the road SVG (circle, icon, connector tick and
title/desc text paths tagged with ids/`.road-point` in the HTML)
we animate that existing artwork in place rather than
positioning a separate HTML copy. It fades in the first time the
car's progress along the road reaches it. */
let points = [];
if (Array.isArray(pointNames) && pointNames.length) {
points = pointNames.map(name => {
const markerEl = document.getElementById(`point-${name}`);
const circleEl = markerEl ? markerEl.querySelector('circle') : null;
const extraEls = [
document.getElementById(`text-${name}-1`),
document.getElementById(`text-${name}-2`),
document.getElementById(`tick-${name}`)
].filter(Boolean);
if (!markerEl || !circleEl) return null;
const svgX = parseFloat(circleEl.getAttribute('cx'));
const svgY = parseFloat(circleEl.getAttribute('cy'));
// Find the point on the road path nearest to the marker so
// "arrival" lines up with where the car visually meets it.
let t = 0, bestDist = Infinity;
const SAMPLES = 400;
for (let i = 0; i <= SAMPLES; i++) {
const sampleT = i / SAMPLES;
const p = pathEl.getPointAtLength(sampleT * TOTAL_LEN);
const dist = (p.x - svgX) ** 2 + (p.y - svgY) ** 2;
if (dist < bestDist) { bestDist = dist; t = sampleT; }
}
return { name, t, markerEl, extraEls, revealed: false };
}).filter(Boolean).sort((a, b) => a.t - b.t);
if (typeof gsap !== 'undefined') {
points.forEach(p => {
gsap.set(p.markerEl, { opacity: 0, scale: 0.5, transformOrigin: '50% 50%' });
if (p.extraEls.length) gsap.set(p.extraEls, { opacity: 0 });
});
}
}
function revealPoint(p) {
if (p.revealed) return;
p.revealed = true;
if (typeof gsap === 'undefined') {
p.markerEl.style.opacity = '1';
p.extraEls.forEach(el => { el.style.opacity = '1'; });
return;
}
gsap.to(p.markerEl, { opacity: 1, scale: 1, duration: 0.4, ease: 'back.out(1.7)' });
if (p.extraEls.length) {
gsap.to(p.extraEls, { opacity: 1, duration: 0.4, ease: 'power2.out', delay: 0.1 });
}
}
function checkPointArrivals(t) {
for (const p of points) {
if (!p.revealed && t >= p.t) revealPoint(p);
}
}
let progress = 0; let progress = 0;
const SPEED = speed; const SPEED = speed;
let lastTime = null; let lastTime = null;
@ -104,12 +169,14 @@ document.addEventListener('DOMContentLoaded', () => {
if (progress >= 1) { if (progress >= 1) {
progress = 1; progress = 1;
placeCar(1); placeCar(1);
checkPointArrivals(progress);
cancelAnimationFrame(rafId); cancelAnimationFrame(rafId);
doLoop(); doLoop();
return; return;
} }
placeCar(progress); placeCar(progress);
checkPointArrivals(progress);
rafId = requestAnimationFrame(animateCar); rafId = requestAnimationFrame(animateCar);
} }
@ -128,7 +195,9 @@ document.addEventListener('DOMContentLoaded', () => {
}, 420); }, 420);
} }
const ro = new ResizeObserver(() => {}); const ro = new ResizeObserver(() => {
placeCar(progress);
});
ro.observe(mainArea); ro.observe(mainArea);
@ -155,7 +224,11 @@ document.addEventListener('DOMContentLoaded', () => {
} }
); );
// 2. Stagger fade-in for SVG pointers (navy circles and white icons) // 2. Stagger fade-in for SVG pointers (navy circles and white icons).
// Screens with arrival-triggered points (pointNames) reveal each
// marker individually as the car reaches it instead — see
// revealPoint()/checkPointArrivals() above.
if (!points.length) {
const pointers = Array.from(document.querySelectorAll('#' + screenId + ' svg circle, #' + screenId + ' svg path')).filter(el => { const pointers = Array.from(document.querySelectorAll('#' + screenId + ' svg circle, #' + screenId + ' svg path')).filter(el => {
const fill = el.getAttribute('fill'); const fill = el.getAttribute('fill');
if (!fill) return false; if (!fill) return false;
@ -179,6 +252,7 @@ document.addEventListener('DOMContentLoaded', () => {
} }
} }
); );
}
// 3. Start car animation when screen is in view // 3. Start car animation when screen is in view
ScrollTrigger.create({ ScrollTrigger.create({
@ -191,10 +265,12 @@ document.addEventListener('DOMContentLoaded', () => {
} }
// Initialize Screen 1 // Initialize Screen 1
setupRoadAnimation('road-svg', 'road-path', 'road-car', '.main-area--prob1', 'screen-prob1', 0.00008); setupRoadAnimation('road-svg', 'road-path', 'road-car', '.main-area--prob1', 'screen-prob1', 0.00008,
['receive', 'sort', 'inspect', 'hold', 'route']);
// Initialize Screen 2 // Initialize Screen 2
setupRoadAnimation('road-svg-2', 'road-path-2', 'road-car-2', '.main-area--prob2', 'screen-prob2', 0.00016); setupRoadAnimation('road-svg-2', 'road-path-2', 'road-car-2', '.main-area--prob2', 'screen-prob2', 0.00016,
['scan', 'decision']);

View File

@ -260,6 +260,12 @@ body {
filter: drop-shadow(0 4px 12px rgba(100, 140, 200, 0.3)); filter: drop-shadow(0 4px 12px rgba(100, 140, 200, 0.3));
} }
/* Baked-in road markers (circle + icon) hidden until the car
reaches them for the first time; see checkPointArrivals() in JS. */
.road-point {
opacity: 0;
}
.road-dashes { .road-dashes {
animation: dashFlow 2s linear infinite; animation: dashFlow 2s linear infinite;
} }

File diff suppressed because one or more lines are too long