Refactor code structure for improved readability and maintainability
This commit is contained in:
parent
cc6249db24
commit
253d6a0c5f
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
@ -17,7 +17,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
/* ═══════════════════════════════════════════
|
||||
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 pathEl = document.getElementById(pathId);
|
||||
const car = document.getElementById(carId);
|
||||
@ -45,6 +45,71 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
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;
|
||||
const SPEED = speed;
|
||||
let lastTime = null;
|
||||
@ -104,12 +169,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (progress >= 1) {
|
||||
progress = 1;
|
||||
placeCar(1);
|
||||
checkPointArrivals(progress);
|
||||
cancelAnimationFrame(rafId);
|
||||
doLoop();
|
||||
return;
|
||||
}
|
||||
|
||||
placeCar(progress);
|
||||
checkPointArrivals(progress);
|
||||
rafId = requestAnimationFrame(animateCar);
|
||||
}
|
||||
|
||||
@ -128,7 +195,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}, 420);
|
||||
}
|
||||
|
||||
const ro = new ResizeObserver(() => {});
|
||||
const ro = new ResizeObserver(() => {
|
||||
placeCar(progress);
|
||||
});
|
||||
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 fill = el.getAttribute('fill');
|
||||
if (!fill) return false;
|
||||
@ -179,6 +252,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// 3. Start car animation when screen is in view
|
||||
ScrollTrigger.create({
|
||||
@ -191,10 +265,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
// 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
|
||||
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']);
|
||||
|
||||
|
||||
|
||||
|
||||
@ -260,6 +260,12 @@ body {
|
||||
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 {
|
||||
animation: dashFlow 2s linear infinite;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user