Gunakan GSAP untuk membuat animasi jalur kurva yang responsif dan dipicu oleh scroll – Beragampengetahuan
Salah satu desain utama yang kami usulkan untuk situs web baru pembalap Formula 1 Lando Norris menghadapi tantangan yang menarik: menganimasikan elemen di sepanjang jalur melengkung mulus antara beberapa posisi tetap yang dapat berfungsi pada ukuran perangkat apa pun. Meskipun plugin MotionPath GSAP membuat animasi berbasis jalur menjadi mudah, kami memerlukan sesuatu yang lebih dinamis. Kami membutuhkan sistem yang dapat menghitung ulang kurvanya secara responsif, beradaptasi dengan tata letak yang berbeda, dan memberi kami kontrol yang tepat terhadap bentuk jalur selama pengembangan.
Dalam tutorial ini, kita akan membahas pembuatan animasi jalur melengkung yang dipicu gulir menggunakan alat Visual Configurator, yang memungkinkan Anda membuat kurva sempurna dengan menyeret titik kontrol secara real-time.
Alat yang digunakan:
Demo jalur dan titik kontrol↗
Contents
tantangan desain
Konsepnya sederhana: saat pengguna men-scroll, elemen harus bergerak mulus di sepanjang jalur melengkung antara tiga lokasi tertentu pada halaman, mengubah ukurannya seiring pergerakannya. Bagian yang sulit? Setiap lokasi memiliki ukuran yang berbeda, jalurnya harus terasa alami dan mulus, dan semuanya harus dihitung ulang dengan sempurna saat jendela browser diubah ukurannya.
Jalur SVG statis tidak akan berhasil. Mereka mogok pada ukuran layar yang berbeda dan gagal beradaptasi dengan tata letak responsif kami. Kita memerlukan kurva yang dihitung secara dinamis berdasarkan posisi elemen sebenarnya.
Pelajari tentang kurva Bezier
Sebelum kita mendalami kodenya, mari kita bahas dasar-dasarnya: kurva Bezier kubik. Kurva ini ditentukan oleh empat titik:
- titik awal (jangkar)
- titik kontrol pertama (CP1) – “menarik” kurva menjauh dari titik awal
- titik kontrol kedua (CP2) – “tarik” kurva ke arah akhir
- akhir (jangkar)
Dalam sintaks jalur SVG, ini terlihat seperti:
M x1,y1 C cpx1,cpy1 cpx2,cpy2 x2,y2
Di mana M Pindah ke titik awal, C menggambar kurva Bezier kubik menggunakan dua titik kontrol.
Untuk animasi antara tiga posisi, kita memerlukan dua segmen kurva, yang berarti total empat titik kontrol:
- CP1 dan CP2 kurva pertama (posisi 1 → posisi 2)
- CP3 dan CP4 kurva kedua (posisi 2 → posisi 3)
Tetapkan struktur HTML
Kami sengaja menjaga markup kami seminimal mungkin. Kami mendefinisikan tiga penanda posisi dan elemen animasi:
<div class="hero-section" data-section="hero">
<div class="position pos1" data-pos="1">Position 1</div>
<div class="position pos2" data-pos="2">Position 2</div>
<div class="position pos3" data-pos="3">Position 3</div>
<div class="animated-image" data-image="animated"></div>
</div>
Elemen posisi bertindak sebagai jangkar yang tidak terlihat. Kami akan mengukur titik pusatnya untuk menghitung jalur kami. Dalam produksi, elemen ini mungkin disembunyikan atau dihapus seluruhnya, dengan pemosisian CSS yang menentukan ke mana elemen animasi harus dipindahkan.
Hitung titik kontrol dinamis
Pertama, kita perlu mengukur di mana sebenarnya posisi jangkar pada halaman:
function getPositions()
const section = document.querySelector('[data-section="hero"]');
const pos1 = document.querySelector('[data-pos="1"]');
const pos2 = document.querySelector('[data-pos="2"]');
const pos3 = document.querySelector('[data-pos="3"]');
const rectSection = section.getBoundingClientRect();
return [pos1, pos2, pos3].map((el) =>
const r = el.getBoundingClientRect();
return
x: r.left - rectSection.left + r.width / 2,
y: r.top - rectSection.top + r.height / 2,
width: r.width,
height: r.height,
;
);
Fungsi ini mengembalikan titik pusat dan dimensinya relatif terhadap setiap posisi bagian yang digulir. Kita akan membutuhkannya nanti untuk interpolasi ukuran.
Kini sampai pada bagian yang menyenangkan: secara otomatis menghitung titik kontrol yang menghasilkan kurva S yang mulus. Inilah pendekatan kami:
function calculateDefaultControlPoints(positions)
return [
// CP1: Extends from position 1 toward position 2
x: positions[0].x,
y: positions[0].y + (positions[1].y - positions[0].y) * 0.8,
,
// CP2: Approaches position 2 from above
x: positions[1].x,
y: positions[1].y - Math.min(800, (positions[1].y - positions[0].y) * 0.3),
,
// CP3: Extends from position 2 toward position 3
x: positions[1].x,
y: positions[1].y + Math.min(80, (positions[2].y - positions[1].y) * 0.3),
,
// CP4: Approaches position 3 from above
x: positions[1].x + (positions[2].x - positions[1].x) * 0.6,
y: positions[2].y - (positions[2].y - positions[1].y) * 0.2,
];
Keajaibannya ada pada pengganda ini (0,8, 0,3, 0,6, 0,2). Mereka mengontrol seberapa besar kurva tersebut “ditarik”:
- CP1 Perpanjang 80% secara vertikal dari posisi 1, pertahankan secara horizontal di tengah untuk membuat busur ke bawah
- CP2 Terletak di atas posisi 2, memastikan pendekatan vertikal yang mulus
- CP3 dan CP4 Segmen kurva kedua bekerja dengan cara yang sama
ini Math.min() Batasan mencegah titik kontrol meluas terlalu jauh pada layar yang sangat besar.
Bangun string jalur SVG
Setelah kita mendapatkan posisi dan titik kontrol, kita membangun jalur SVG:
function buildPathString(positions, controlPoints)
return `M$positions[0].x,$positions[0].y ` +
`C$controlPoints[0].x,$controlPoints[0].y ` +
`$controlPoints[1].x,$controlPoints[1].y ` +
`$positions[1].x,$positions[1].y ` +
`C$controlPoints[2].x,$controlPoints[2].y ` +
`$controlPoints[3].x,$controlPoints[3].y ` +
`$positions[2].x,$positions[2].y`;
Ini akan membuat jalur kontinu dengan dua kurva Bezier kubik, membentuk bentuk S kita.
Animasi menggunakan MotionPath GSAP
Sekarang kami memberikan jalur ini ke GSAP. Plug-in MotionPath bertanggung jawab untuk menghitung posisi pada kurva:
const pathString = buildPathString(positions, controlPoints);
gsap.set(img,
x: positions[0].x,
y: positions[0].y,
width: positions[0].width,
height: positions[0].height,
);
const tl = gsap.timeline(
scrollTrigger:
trigger: section,
start: 'top top',
end: 'bottom bottom',
scrub: true,
invalidateOnRefresh: true,
,
);
tl.to(img,
duration: 1.5,
motionPath:
path: pathString,
autoRotate: false,
,
ease: 'none',
onUpdate: function ()
// Size interpolation logic here
,
);
Poin-poin penting:
- Menggosok: Nyata: Mengikat kemajuan animasi secara langsung ke posisi gulir
- Penyegaran tidak valid: benar: Pastikan jalur dihitung ulang ketika ukuran jendela diubah
- Mudah: “Tidak ada”: Perkembangan linier memberi kita pemetaan gulir ke posisi yang dapat diprediksi
- Sumber transformasi: ‘50% 50%’: Pusatkan elemen pada jalur
Masukan alternatif: jalur berbasis array
Plug-in MotionPath GSAP juga dapat membuat jalur langsung dari data titik, bukan string jalur SVG lengkap. Anda dapat meneruskan array titik jangkar dan koordinat titik kontrol dan meminta GSAP menghasilkan kurva Bezier kubik secara internal.
Anda dapat melihat demo minimal yang menunjukkan pendekatan ini di sini:
Dalam kasus kami, kami membuat jalur SVG secara eksplisit sehingga kami dapat memvisualisasikan dan men-debugnya di konfigurator, namun untuk pengaturan yang lebih sederhana, sintaksis berbasis array ini dapat menjadi alternatif yang ringan.
Interpolasi dimensi di sepanjang jalur
Saat elemen kita berjalan di sepanjang jalur, kita ingin elemen tersebut bertransisi dengan lancar dari dimensi setiap posisi ke dimensi posisi berikutnya. kita onUpdate menelepon kembali:
onUpdate: function ()
const progress = this.progress();
// First half: interpolate between position 1 and position 2
if (progress <= 0.5)
const normalizedProgress = progress * 2;
const width = positions[0].width +
(positions[1].width - positions[0].width) * normalizedProgress;
const height = positions[0].height +
(positions[1].height - positions[0].height) * normalizedProgress;
img.style.width = `$widthpx`;
img.style.height = `$heightpx`;
// Second half: interpolate between position 2 and position 3
else
const normalizedProgress = (progress - 0.5) * 2;
const width = positions[1].width +
(positions[2].width - positions[1].width) * normalizedProgress;
const height = positions[1].height +
(positions[2].height - positions[1].height) * normalizedProgress;
img.style.width = `$widthpx`;
img.style.height = `$heightpx`;
Kami membagi animasi pada tanda 50% (saat posisi 2 tercapai) dan kemudian menormalkan kemajuan setiap segmen (0-1 untuk setiap setengahnya), memberi kami transisi ukuran mulus yang selaras dengan jalurnya.
Bangun konfigurator visual
Di sinilah alur kerja pengembangan menjadi menarik. Titik kontrol yang dihitung secara otomatis adalah titik awal yang baik, namun setiap desain berbeda. Kita perlu menyempurnakan kurva ini, tetapi menyesuaikan pengganda dalam kode dan menyegarkan browser dengan cepat menjadi hal yang membosankan.
Sebagai gantinya, kami membuat konfigurator visual yang memungkinkan kami menyeret titik kontrol dan melihat hasilnya secara real time.
Buat cakupan debug
Kami membuat overlay SVG yang berada di atas elemen animasi:
const debugSvg = document.createElementNS(' 'svg');
debugSvg.style.position = 'absolute';
debugSvg.style.top = 0;
debugSvg.style.left = 0;
debugSvg.style.width = '100%';
debugSvg.style.height = '100%';
debugSvg.style.pointerEvents = 'none';
debugSvg.style.zIndex = 15;
section.appendChild(debugSvg);
Kemudian kami menambahkan elemen visual:
// The path itself (red line)
const debugPath = document.createElementNS(' 'path');
debugPath.setAttribute('stroke', '#ff0040');
debugPath.setAttribute('stroke-width', '3');
debugPath.setAttribute('fill', 'none');
debugSvg.appendChild(debugPath);
// Anchor points (red circles at positions 1, 2, 3)
for (let i = 0; i < 3; i++)
const circle = document.createElementNS(' 'circle');
circle.setAttribute('r', '8');
circle.setAttribute('fill', '#ff0040');
debugSvg.appendChild(circle);
anchorPoints.push(circle);
// Control points (green circles - these are draggable)
for (let i = 0; i < 4; i++)
const circle = document.createElementNS(' 'circle');
circle.setAttribute('r', '8');
circle.setAttribute('fill', '#00ff88');
circle.setAttribute('class', 'svg-control-point');
circle.style.pointerEvents = 'all'; // Enable interaction
circle.dataset.index = i;
debugSvg.appendChild(circle);
controlPointElements.push(circle);
// Handle lines (dashed lines connecting controls to anchors)
for (let i = 0; i < 4; i++)
const line = document.createElementNS(' 'line');
line.setAttribute('stroke', '#00ff88');
line.setAttribute('stroke-dasharray', '4,4');
debugSvg.appendChild(line);
handleLines.push(line);
Ini memberi kita representasi visual lengkap dari struktur kurva Bezier, seperti yang Anda lihat di perangkat lunak pengeditan vektor seperti Illustrator atau Figma.
Jadikan titik kontrol dapat diseret
Interaksi tariknya sederhana: lacak posisi mouse/sentuh dan perbarui koordinat titik kontrol:
let isDragging = false;
let currentDragIndex = -1;
function startDrag(e)
const target = e.target;
if (target.classList.contains('svg-control-point'))
isDragging = true;
currentDragIndex = parseInt(target.dataset.index);
target.classList.add('dragging');
e.preventDefault();
function drag(e)
if (!isDragging
function endDrag()
if (isDragging)
const circles = debugSvg.querySelectorAll('.svg-control-point');
circles.forEach(c => c.classList.remove('dragging'));
isDragging = false;
currentDragIndex = -1;
debugSvg.addEventListener('mousedown', startDrag);
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', endDrag);
Saat Anda menyeret titik kontrol, kami:
- Perbarui posisinya di array CurrentControlPoints
- Bangun kembali string jalur
- Bunuh dan buat ulang animasi GSAP dengan jalur baru
- Perbarui semua elemen visual
Ini memberikan umpan balik visual instan saat Anda menyesuaikan kurva.
nilai akhir ekspor
Setelah Anda memasukkan kurva yang sempurna, Anda memerlukan nilai titik kontrol berikut untuk produksi:
function copyValues()
const valuesText = currentControlPoints.map((cp, i) =>
`const controlPoint$i + 1 = \n x: $Math.round(cp.x),\n y: $Math.round(cp.y)\n;`
).join('\n\n');
navigator.clipboard.writeText(valuesText);
Ini akan memformat koordinat menjadi konstanta JavaScript yang dapat Anda tempelkan langsung ke kode produksi.
responsivitas pemrosesan
Di sinilah pendekatan dinamis kami membuahkan hasil. Saat jendela diubah ukurannya:
let resizeTimeout;
window.addEventListener('resize', () =>
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() =>
positions = getPositions();
updateVisualization();
buildAnimation();
, 200);
);
Kami menghitung ulang posisinya, membangun kembali jalur, dan membuat ulang animasi. Koordinat titik kontrol tetap tidak berubah (sudah berada dalam ruang koordinat bagian yang di-scroll), sehingga bentuk kurva beradaptasi secara proporsional dengan tata letak baru.
Ini penting untuk desain responsif. Baik Anda menggunakan ponsel, tablet, atau monitor ultra lebar, struktur lengkung yang sama juga berlaku.
Deskripsi MotionPathHelper GSAP
Perlu disebutkan bahwa GSAP menyertakan plugin bernama MotionPathHelper, yang menyediakan kemampuan pengeditan visual serupa untuk animasi MotionPath. Jika Anda sedang mengerjakan adegan jalur yang lebih kompleks atau memerlukan fitur seperti pengeditan jalur menggunakan beberapa kurva, MotionPathHelper layak untuk dijelajahi.
Untuk kasus penggunaan kami, kami menginginkan integrasi yang erat dengan animasi yang dipicu gulir dan alur kerja yang secara khusus disesuaikan dengan pengaturan tiga posisi kami, itulah sebabnya kami membuat solusi khusus. Namun jika Anda mencari editor jalur siap pakai dengan fungsionalitas yang lebih luas, MotionPathHelper adalah pilihan yang tepat.
Aksesibilitas
Bagi pengguna yang memilih lebih sedikit pergerakan, kami harus menghormati preferensi sistem mereka. Meskipun kita bisa menggunakan JavaScript asli matchMedia API, GSAP menyediakannya sendiri matchMedia Utilitas yang terintegrasi secara mulus dengan sistem animasinya:
// Using GSAP's matchMedia
gsap.matchMedia().add("(prefers-reduced-motion: reduce)", () =>
// Skip the curved path animation entirely
gsap.set(img,
x: positions[2].x, // Jump to final position
y: positions[2].y,
width: positions[2].width,
height: positions[2].height,
);
return () =>
// Cleanup function (optional)
;
);
gsap.matchMedia().add("(prefers-reduced-motion: no-preference)", () =>
// Run the full animation
buildAnimation();
return () =>
// Cleanup function (optional)
;
);
GSAP matchMedia Memberikan keunggulan dibandingkan API asli: secara otomatis mengelola pembersihan ketika kueri media berubah, terintegrasi lebih baik dengan siklus hidup animasi GSAP, dan menyediakan API yang konsisten untuk semua perilaku respons. Bagi mereka yang telah menyatakan preferensi untuk lebih sedikit gerakan, ini akan segera menempatkan elemen pada posisi akhirnya sambil menjalankan animasi penuh untuk yang lain.
*(Catatan: Kami belum menerapkan fitur ini di situs langsung Lando Norris 😬, tapi ini jelas merupakan praktik terbaik yang patut diikuti.)*
Proses produksi
Proses pengembangan kami terlihat seperti ini:
- Pengaturan awal: Gunakan CSS untuk menempatkan elemen jangkar di tempat yang Anda inginkan
- Perhitungan otomatis: Biarkan titik kontrol default memberi Anda kurva awal
- penyesuaian: Buka konfigurator dan seret titik kontrol hingga kurva dirasa sesuai.
- KELUAR: Salin nilai titik kontrol akhir
- menyebarkan: Ganti titik kontrol yang dihitung secara otomatis dengan nilai khusus Anda
- membersihkan: Hapus kode konfigurator dan debug visualisasi produksi
Dalam produksi, Anda biasanya melakukan hardcode pada titik kontrol dan menghapus semua UI konfigurator:
const controlPoints = [
x: 150, y: 450 ,
x: 800, y: 800 ,
x: 850, y: 1200 ,
x: 650, y: 1400
];
// Use these directly instead of calculateDefaultControlPoints()
Meringkaskan
Membuat animasi jalur melengkung yang dipicu gulir ini memberi kami pelajaran berharga tentang menyeimbangkan otomatisasi dan kontrol. Titik kontrol yang dihitung secara otomatis memberi Anda titik awal yang baik, namun kemampuan menyempurnakannya secara visual dapat membuat perbedaan besar dalam mencapai kurva yang sempurna.
Kombinasi plugin MotionPath GSAP yang canggih, ScrollTrigger untuk sinkronisasi gulir, dan konfigurator visual khusus memberi kami apa yang kami butuhkan: sistem animasi responsif yang tampak hebat di perangkat apa pun dan alur kerja pengembangan yang tidak melibatkan tebakan koordinat.
Untuk situs web Lando Norris, pendekatan ini memungkinkan kami membuat animasi pahlawan yang terasa lancar, disengaja, dan sesuai dengan desain dengan sempurna namun tetap responsif sepenuhnya di seluruh perangkat.
rencana pengembangan website
metode pengembangan website
jelaskan beberapa rencana untuk pengembangan website, proses pengembangan website, kekuatan dan kelemahan bisnis pengembangan website
, jasa pengembangan website, tahap pengembangan website, biaya pengembangan website
#Gunakan #GSAP #untuk #membuat #animasi #jalur #kurva #yang #responsif #dan #dipicu #oleh #scroll
