Seberapa sering Anda mencapai 404 halaman? Biasanya, mereka tidak ditata dan tetap default. Baru-baru ini saya menemukan
test.do.am yang karakter interaktifnya menarik perhatian dan menghidupkan halaman kesalahan.
Mungkin, hanya ada gambar kucing, lalu mereka memikirkan gerakan mata dan pengembang menerapkan ide tersebut.

Sekarang pengguna mengunjungi halaman dan memeriksa efeknya. Ini fitur kecil yang keren dan menyenangkan, menangkap, lalu pengguna mendiskusikannya dengan kolega atau teman dan bahkan mengulangi fitur tersebut. Bisa semudah ini, jika tidak:
- Titik tengah tidak diperbarui saat pengguna mengubah ukuran jendela. Buka jendela browser dengan viewport lebar kecil dan ubah ukuran ke layar penuh, kucing tidak melihat kursor.
- Titik tengah ditempatkan di mata kiri, bukan di tengah teropong lingkaran.
- Saat pengguna mengarahkan kursor di antara mata, apel mata tidak bertemu dan tidak fokus. Mata mencari sampai tak terhingga, itu sebabnya kucing itu tidak memandang penggunanya, itu melaluinya.
- Gerakan mata langsung, mereka harus halus.
- Pergerakan apel terjadi karena perubahan margin-kiri / margin-atas. Itu salah, cari penjelasan di bawah.
- Mata tidak bergerak jika kursor berada di bawah kaki.
Apa yang saya sarankanSebagai permulaan, mari kita lakukan gerakan mata tanpa cacat.
1. Siapkan markup
<div class="cat"> <div class="cat__eye _left"></div> <div class="cat__eye _right"></div> </div>
2. Dapatkan tautan ke elemen mata
const cat = document.querySelector('.cat'); const eyes = cat.querySelectorAll('.cat__eye'); const eye_left = eyes[0]; const eye_right = eyes[1];
3. Daftarkan pendengar acara mousemove dan dapatkan koordinat kursor:
let mouseX; let mouseY; window.addEventListener('mousemove', e => { mouseX = e.clientX; mouseY = e.clientY; })
Saya menambahkan pendengar mousemove pada objek jendela, bukan dokumen tubuh, karena saya perlu menggunakan semua layar untuk mendapatkan koordinat mouse.
4. Gerakan
Karena saya akan memperlancar gerakan, saya tidak bisa mengelolanya dalam handler mousemove.
Tambahkan metode pembaruan yang akan diambil oleh requestAnimationFrame yang disinkronkan dengan pembaruan browser. Biasanya pembaruan terjadi 60 kali per detik, oleh karena itu kami melihat 60 foto per detik setiap 16,6 ms.
Jika pengembang menganggap browser pengguna tidak dapat mendukung requestAnimationFrame, pengembang dapat menggunakan setTimeout mundur atau
polyfill yang sudah jadi window.requestAnimationFrame = (function () { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60); }; })();
Untuk memperbarui atau stabil mengambil pembaruan dalam waktu, saya mendaftar variabel mulai
let started = false; let mouseX; let mouseY; window.addEventListener('mousemove', e => { mouseX = e.clientX; mouseY = e.clientY; if(!started){ started = true; update(); } }) function update(){
Dengan cara ini saya terus mendapatkan metode pembaruan dan koordinat kursor. Maka saya perlu mendapatkan nilai gerakan apel di dalam mata.
Saya mencoba menggerakkan kedua mata sebagai elemen tunggal
let dx = mouseX - eyesCenterX; let dy = mouseY - eyesCenterY; let angle = Math.atan2(dy, dx); let distance = Math.sqrt(dx * dx + dy * dy); distance = distance > EYES_RADIUS ? EYES_RADIUS : distance; let x = Math.cos(angle) * distance; let y = Math.sin(angle) * distance; eye_left.style.transform = 'translate(' + x + 'px,' + y + 'px)'; eye_right.style.transform = 'translate(' + x + 'px,' + y + 'px)';
Cukup sederhana: temukan dx dan dy, yang merupakan koordinat perbedaan antara pusat mata dan mouse, temukan sudut dari pusat ke kursor, menggunakan metode Math.cos dan Math.sin mendapatkan nilai pergerakan untuk horizontal dan vertikal. Gunakan
operator ternary dan batasi area pergerakan mata.
Nilai Y diberikan pertama untuk metode Math.atan2, kemudian nilai x. Akibatnya pengguna memperhatikan gerakan mata yang tidak alami dan tidak ada fokus.
Buat setiap mata bergerak dan menonton tanpa referensi satu sama lain.
Menarik tetapi lebih buruk dari hasil sebelumnya, mata bergerak naik dan turun secara mandiri. Jadi saya menggunakan demo pertama sebagai mekanik gerakan dasar dan membuat apel mata bertemu ketika kursor adalah tentang pusat karakter.
Saya tidak akan menjelaskan seluruh kode, harap temukan hasilnya sebagai berikut:
Dengan coba-coba, saya telah mencocokkan parameter yang diperlukan untuk gerakan mata dan pemfokusan. Jadi sekarang saya perlu perataan.
MenghaluskanTautkan
pustaka TweenMax dan
beri kode sesuatu seperti ini?
TweenMax.to( eye, 0.15, {x: x, y: y});
Menghubungkan seluruh lib untuk tugas sederhana tidak masuk akal, oleh karena itu, saya membuat perataan dari awal.
Letakkan case bahwa hanya ada satu elemen mata pada halaman dan area pemindahannya tidak terbatas sama sekali. Untuk memperlancar nilai koordinat mouse, saya menggunakan mekanisme ini:
const SMOOTHING = 10; x += (needX - x) / SMOOTHING; y += (needY - y) / SMOOTHING; eye.style.transform = 'translate3d(' + x + 'px,' + y + 'px,0)';
Saya menggunakan translate3d untuk memisahkan mata ke aliran rendering lain dan mempercepatnya.
Caranya adalah bahwa setiap 16,6 ms (60 foto per detik) variabel x dan y cenderung nilai yang dibutuhkan. Setiap pembaruan menutup nilai sesuai yang dibutuhkan untuk perbedaan 1/10.
let x = 0; let needX = 100; let SMOOTHING = 2; function update(){ x += (needX - x) / SMOOTHING; console.log(x); }
Kemudian setiap pembaruan 16,6 ms kami mendapatkan smoothing sederhana dan nilai x berikutnya (kira-kira):
50 75 87.5 93.75 96.875 98.4375 99.21875 99.609375 100
Beberapa trik yang tidak terlihat:
- Mulai pemeriksaan ini untuk mengoptimalkan beban kerja
if(x != needX || y != needY){ eye.style.transform = 'translate3d(' + x + 'px,' + y + 'px,0)'; }
Tetapi Anda harus menyamakan x dengan needX ketika mereka sedekat posisi mata hampir sama
if(Math.abs(x - needX) < 0.25){ x = needX; } if(Math.abs(y - needY) < 0.25){ y = needY; }
Kalau tidak, nilai x dan y akan mencapai needX dan needY terlalu lama; tidak akan ada perbedaan visual, tetapi setiap perubahan layar akan memengaruhi gaya mata. Tapi kamu bisa bermain-main dengan itu sendiri.
let x = 0; let needX = 100; let smoothing = 2; function update(){ x += (needX - x) / smoothing; if( Math.abs(x - needX) > 0.25 ){
- Jika mekanika di atas jelas, Anda dapat membuat efek yang lebih kompleks, misalnya pegas. Perkiraan smoothing dan kursor yang paling sederhana terlihat seperti ini:
x += (mouseX - x) / smoothing; y += (mouseY - y) / smoothing;
Tambahkan smoothing perbedaan antara nilai koordinat yang dibutuhkan dan saat ini.
Terkadang keterbatasan perkiraan masuk akal. Ada contoh di atas di mana nilai berubah dari 0 hingga 100, jadi pada nilai iterasi pertama mencapai "50", itu adalah angka yang cukup besar untuk 1 langkah. Mekanik ini agak mengingatkan
paradoks Achilles dan kura-kura
Mengedipkan mataSembunyikan dan perlihatkan apel mata setiap 2-3 detik. Metode yang paling sepele adalah "display: none;", "transform: scaleY (N)" dengan nilai dinamis skala y sedikit lebih kompleks.
Buat 2 konstanta
const BLINK_COUNTER_LIMIT = 180; - jumlah pembaruan sebelum mulai berkedip,
const BLINKED_COUNTER_LIMIT = 6; - Jumlah pembaruan selama satu wink.
Dan 2 variabel, yang nilainya akan mengubah setiap pembaruan.
let blinkCounter = 0; let blinkedCounter = 0;
Kode mengedipkan mata
let blinkTransform = ''; blinkCounter++; if(blinkCounter > BLINK_COUNTER_LIMIT){ blinkedCounter++ if(blinkedCounter > BLINKED_COUNTER_LIMIT){ blinkCounter = 0; } else { blinkTransform = ' scaleY(' + (blinkedCounter / BLINKED_COUNTER_LIMIT) + ')'; } } else { blinkedCounter = 0; }
BlinkTransform adalah variabel stroke yang memiliki nilai kosong antara mengedipkan mata dan mengikutinya selama mengedipkan mata
' scaleY(0.17)' ' scaleY(0.33)' ' scaleY(0.50)' ' scaleY(0.67)' ' scaleY(0.83)' ' scaleY(1.00)'
Semua perhitungan memberikan Transform blink variabel, nilai yang harus ditambahkan ke kode css transformasi posisi mata. Jadi string kosong akan ditambahkan jika turun 3 detik dan tidak berpengaruh pada skala mata, nilai css ditambahkan selama berkedip.
eye_left.style.transform = 'translate(' + xLeft + 'px,' + y + 'px)' + blinkTransform; eye_right.style.transform = 'translate(' + xRight + 'px,' + y + 'px)' + blinkTransform;
Pelajaran dari ceritanyaSetiap hari kita bertemu hal-hal yang tampak sederhana dan jelas dan kita bahkan tidak mengerti bahwa kesederhanaan eksternal ini menyembunyikan sejumlah besar pertanyaan dan perbaikan. Menurut pendapat saya, setan ada dalam perincian yang membentuk seluruh hasil akhir. Muhammad Ali petinju terbaik abad ke-20 mengangkat tumit kaki belakang pada saat pukulan lurus. Manuver ini meningkatkan jarak pukulan efektif dan memberinya lebih banyak peluang untuk menang. Selalu berhasil.
PS Saya tidak memiliki hubungan dengan situs web dan berharap pemiliknya tidak akan tersinggung dengan komentar saya. Untuk kenyamanan saya beri nama apple of the eye = eye dalam kode.