Files
hesu-JT/js/about-us.js
T
2026-08-27 11:54:26 +08:00

120 lines
4.7 KiB
JavaScript

/* ============================================================
About Us — CSS sticky pin + rAF scroll-linked (no GSAP)
Smoothest approach: CSS position:sticky handles the pin
(native GPU compositing), rAF drives the cross-fade timeline.
Stage 1 (au-1): intro(screen1) -> slogan(screen2)
Stage 2 (au-3): Strong Resources(screen3) -> zoom+logo(screen4)
============================================================ */
(function () {
var s1 = document.querySelector('#au-1');
var s3 = document.querySelector('#au-3');
if (!s1) return;
var bg = s1.querySelector('.au-bg');
var intro = s1.querySelector('.au-inner');
var corner = s1.querySelector('.au-corner-img');
var mask = s1.querySelector('.au-mask');
var layer = s1.querySelector('.au-slogan-layer');
var sl = s1.querySelector('.au-slogan');
var cn = s1.querySelector('.au-slogan-cn');
var head = s3 ? s3.querySelector('.au-sec-head') : null;
var zoom = s3 ? s3.querySelector('.au-zoom-img') : null;
var zoomMask = s3 ? s3.querySelector('.au-zoom-mask') : null;
var reveal = s3 ? s3.querySelector('.au-reveal') : null;
function clamp(v, a, b) { return Math.max(a, Math.min(b, v)); }
function lerp(a, b, t) { return a + (b - a) * clamp(t, 0, 1); }
var start1 = 0, start3 = 0;
function measure() {
function dt(el) { var r = el.getBoundingClientRect(); return r.top + window.scrollY; }
start1 = dt(s1);
if (s3) start3 = dt(s3);
}
function update() {
var vh = window.innerHeight;
/* ---- au-1 (pin 2vh): intro held -> cross-fade to slogan ---- */
var p = clamp((window.scrollY - start1) / vh, 0, 2); // 0 -> 2
// bg: subtle cinematic scale throughout
if (bg) bg.style.transform = 'scale(' + lerp(1.04, 1, p / 2).toFixed(4) + ')';
// intro (screen 1): held 0-0.3, fades up 0.3-0.6
var introT = clamp((p - 0.3) / 0.3, 0, 1);
if (intro) { intro.style.opacity = String(1 - introT); intro.style.transform = 'translateY(' + (-introT * 30).toFixed(1) + 'px)'; }
if (corner) corner.style.opacity = String(1 - introT);
// mask: darkens 0.3-0.6
if (mask) mask.style.opacity = String(introT);
// slogan (screen 2): triggered CSS transition at threshold (NIO-style auto rise-up)
if (layer) layer.classList.toggle('is-current', p >= 0.5);
/* ---- au-3 (pin 2vh): Strong Resources -> zoom + logo ---- */
if (s3) {
var q = clamp((window.scrollY - start3) / vh, 0, 2);
var t = clamp((q - 1.0) / 1.0, 0, 1);
// head (screen 3): held first screen, fades second
if (head) head.style.opacity = String(clamp(1 - (q - 0.6) / 0.3, 0, 1));
// zoom: scale to fullscreen; photo opacity stays 1 — a black veil fades in over it
if (zoom) {
zoom.style.transform = 'translate(-50%, -50%) scale(' + lerp(1, 2.2, t).toFixed(3) + ')';
}
if (zoomMask) zoomMask.style.opacity = String(lerp(0, 0.8, t).toFixed(3));
// reveal (screen 4): logo+text in second screen
if (reveal) reveal.style.opacity = String(clamp((q - 1.1) / 0.4, 0, 1));
}
}
var ticking = false;
function onScroll() {
if (ticking) return;
ticking = true;
requestAnimationFrame(function () { update(); ticking = false; });
}
window.addEventListener('scroll', onScroll, { passive: true });
window.addEventListener('resize', function () { measure(); onScroll(); });
measure();
update();
})();
/* ============================================================
GPS data carousel — auto-rotate + dot navigation
============================================================ */
(function () {
var track = document.querySelector('.au-gps__track');
var dotsWrap = document.querySelector('.au-gps__dots');
if (!track || !dotsWrap) return;
var cards = Array.prototype.slice.call(track.children);
if (cards.length < 2) return;
var idx = 0, timer = null;
cards.forEach(function (_, i) {
var b = document.createElement('button');
b.setAttribute('aria-label', 'Slide ' + (i + 1));
b.addEventListener('click', function () { goTo(i); restart(); });
dotsWrap.appendChild(b);
});
var dots = Array.prototype.slice.call(dotsWrap.children);
function render() {
track.style.transform = 'translateX(' + (-idx * 100) + '%)';
dots.forEach(function (d, i) { d.classList.toggle('active', i === idx); });
}
function goTo(i) { idx = ((i % cards.length) + cards.length) % cards.length; render(); }
function next() { goTo(idx + 1); }
function start() { timer = setInterval(next, 4000); }
function restart() { clearInterval(timer); start(); }
render();
start();
// pause auto-rotate while hovering
track.addEventListener('mouseenter', function () { clearInterval(timer); });
track.addEventListener('mouseleave', start);
})();