120 lines
4.7 KiB
JavaScript
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);
|
|
})();
|