Details

Wie oft kommen Sie auf 404 Seiten? Normalerweise sind sie nicht gestylt und bleiben Standard. Kürzlich habe ich test.do.am gefunden, welcher interaktive Charakter Aufmerksamkeit erregt und die Fehlerseite belebt .

Wahrscheinlich gab es nur ein Katzenbild, dann haben sie sich Augenbewegungen ausgedacht und der Entwickler hat die Idee umgesetzt. Bild Jetzt besucht der Benutzer die Seite und überprüft den Effekt. Es ist eine coole und angenehme kleine Funktion, die auffängt, dann vom Benutzer mit Kollegen oder Freunden besprochen und sogar wiederholt wird. Es könnte so einfach sein, wenn nicht:

  1. Der Mittelpunkt wird nicht erneuert, wenn der Benutzer die Fenstergröße ändert. Öffnen Sie das Browserfenster mit kleinem Ansichtsfenster und ändern Sie die Größe auf Vollbild. Die Katze schaut nicht auf den Cursor.
  2. Der Mittelpunkt befindet sich auf dem linken Auge und nicht in der binokularen Mitte des Kreises.
  3. Wenn der Benutzer den Cursor zwischen den Augen bewegt, kommen die Äpfel der Augen nicht zusammen und fokussieren nicht. Die Augen schauen ins Unendliche, deshalb schaut die Katze den Benutzer nicht an, sie schaut durch ihn hindurch.
  4. Augenbewegungen sind sofort, sie müssen glatt sein.
  5. Die Bewegungen der Äpfel erfolgen aufgrund von Änderungen am linken Rand / am oberen Rand. Es ist falsch, Erklärung finden Sie unten.
  6. Die Augen bewegen sich nicht, wenn sich der Cursor unter der Fußzeile befindet.

Was ich vorschlage

Lassen Sie uns zunächst eine fehlerfreie Augenbewegung implementieren.

1. Bereiten Sie das Markup vor

<div class="cat"> <div class="cat__eye _left"></div> <div class="cat__eye _right"></div> </div> 

2. Holen Sie sich Links zu den Elementen der Augen

 const cat = document.querySelector('.cat'); const eyes = cat.querySelectorAll('.cat__eye'); const eye_left = eyes[0]; const eye_right = eyes[1]; 

3. Registrieren Sie den Mauszeiger-Ereignis-Listener und erhalten Sie die Cursorkoordinaten:

 let mouseX; let mouseY; window.addEventListener('mousemove', e => { mouseX = e.clientX; mouseY = e.clientY; }) 

Ich füge einen Mausbewegungs-Listener zum Fensterobjekt hinzu, nicht zum Dokumentkörper, da ich den gesamten Bildschirm verwenden muss, um Mauskoordinaten zu erhalten.

4. Bewegung
Da ich Bewegungen glätten werde, kann ich sie im Mausbewegungshandler nicht verwalten.

Fügen Sie eine Aktualisierungsmethode hinzu, die von requestAnimationFrame abgerufen wird, das mit der Browsererneuerung synchronisiert wird. Normalerweise erfolgen Erneuerungen 60 Mal pro Sekunde, daher sehen wir alle 16,6 ms 60 Bilder pro Sekunde.

Wenn der Entwickler annimmt, dass der Browser des Benutzers requestAnimationFrame nicht unterstützt, kann der Entwickler setTimeout-Fallback oder eine vorgefertigte Polyfüllung verwenden

 window.requestAnimationFrame = (function () { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60); }; })(); 

Um das Update rechtzeitig zu erneuern oder stabil abzurufen, registriere ich die Startvariable

 let started = false; let mouseX; let mouseY; window.addEventListener('mousemove', e => { mouseX = e.clientX; mouseY = e.clientY; if(!started){ started = true; update(); } }) function update(){ // Here comes eyes movement magic requestAnimationFrame(update); } 

Auf diese Weise habe ich ständig Aktualisierungsmethoden und Cursorkoordinaten abgerufen. Dann muss ich Werte für die Bewegungen der Äpfel in den Augen ermitteln.

Ich versuche beide Augen als einzelnes Element zu bewegen

 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)'; 

Ziemlich einfach: Finden Sie dx und dy, die Koordinatendifferenzen zwischen Augenmitte und Maus, suchen Sie den Winkel von Mitte zu Cursor, indem Sie die Methoden Math.cos und Math.sin verwenden, um den Bewegungswert für horizontal und vertikal zu erhalten. Verwenden Sie einen ternären Operator und begrenzen Sie den Bewegungsbereich der Augen.


Der Y-Wert wird zuerst für die Math.atan2-Methode angegeben, dann der x-Wert. Infolgedessen bemerkt der Benutzer eine Unnatürlichkeit der Augenbewegungen und keine Fokussierung.

Bewegen Sie jedes Auge und beobachten Sie es ohne Bezug zueinander.

 // left eye let left_dx = mouseX - eyesCenterX + 48; let left_dy = mouseY - eyesCenterY; let left_angle = Math.atan2(left_dy, left_dx); let left_distance = Math.sqrt(left_dx * left_dx + left_dy * left_dy); left_distance = left_distance > EYES_RADIUS ? EYES_RADIUS : left_distance; let left_x = Math.cos(left_angle) * left_distance; let left_y = Math.sin(left_angle) * left_distance; eye_left.style.transform = 'translate(' + left_x + 'px,' + left_y + 'px)'; // right eye let right_dx = mouseX - eyesCenterX - 48; let right_dy = mouseY - eyesCenterY; let right_angle = Math.atan2(right_dy, right_dx); let right_distance = Math.sqrt(right_dx * right_dx + right_dy * right_dy); right_distance = right_distance > EYES_RADIUS ? EYES_RADIUS : right_distance; let right_x = Math.cos(right_angle) * right_distance; let right_y = Math.sin(right_angle) * right_distance; eye_right.style.transform = 'translate(' + right_x + 'px,' + right_y + 'px)'; 


Interessant, aber schlechter als das vorherige Ergebnis. Die Augen bewegen sich unabhängig voneinander auf und ab. Also habe ich die erste Demo als Basis für die Bewegungsmechanik verwendet und Äpfel der Augen zusammengebracht, wenn sich der Cursor in der Mitte des Charakters befindet.

Ich werde nicht den gesamten Code beschreiben, hier finden Sie ein Ergebnis:


Durch Versuch und Irrtum habe ich die benötigten Parameter für die Bewegung und Fokussierung der Augen angepasst. Also muss ich jetzt glätten.

Glätten

TweenMax-Bibliothek verknüpfen und so etwas codieren?

 TweenMax.to( eye, 0.15, {x: x, y: y}); 

Das Verknüpfen der gesamten Bibliothek für einfache Aufgaben macht keinen Sinn, daher mache ich das Glätten von Grund auf neu.

Stellen Sie den Fall ein, dass sich nur ein Augenelement auf der Seite befindet und der Verschiebungsbereich überhaupt nicht begrenzt ist. Um die Werte der Mauskoordinaten zu glätten, verwende ich diese Mechanik:

 const SMOOTHING = 10; x += (needX - x) / SMOOTHING; y += (needY - y) / SMOOTHING; eye.style.transform = 'translate3d(' + x + 'px,' + y + 'px,0)'; 

Ich verwende translate3d, um Augen von einem anderen Rendering-Stream zu trennen und sie zu beschleunigen.

Der Trick ist, dass alle 16,6 ms (60 Bilder pro Sekunde) Variablen x und y zu den erforderlichen Werten tendieren. Jede Erneuerung schließt den Wert für 1/10 der Differenz auf den erforderlichen Wert.

 let x = 0; let needX = 100; let SMOOTHING = 2; function update(){ x += (needX - x) / SMOOTHING; console.log(x); } 

Dann erhalten wir alle 16,6 ms Erneuerung eine einfache Glättung und die nächsten x-Werte (ungefähr):

 50 75 87.5 93.75 96.875 98.4375 99.21875 99.609375 100 

Noch ein paar unauffällige Tricks:

- Starten Sie diese Untersuchung, um die Arbeitsbelastung zu optimieren

 if(x != needX || y != needY){ eye.style.transform = 'translate3d(' + x + 'px,' + y + 'px,0)'; } 

Aber Sie müssen x mit needX gleichsetzen, wenn sie so nahe kommen, wie die Augenpositionen fast gleich sind

 if(Math.abs(x - needX) < 0.25){ x = needX; } if(Math.abs(y - needY) < 0.25){ y = needY; } 

Andernfalls erreichen die x- und y-Werte needX und needY zu lange. Es gibt keine visuellen Unterschiede, aber jede Bildschirmänderung wirkt sich auf die Augenstile aus. Übrigens können Sie selbst damit herumspielen.

 let x = 0; let needX = 100; let smoothing = 2; function update(){ x += (needX - x) / smoothing; if( Math.abs(x - needX) > 0.25 ){ // replace 0.25 with anything else and check number of x renewals. window.requestAnimationFrame(update); } else { x = needX; } console.log( x.toString(10) ); } update(); 

- Wenn die oben genannten Mechanismen klar sind, können Sie komplexere Effekte erzielen, z. B. Feder. Die einfachste Glättung und Annäherung an den Cursor sieht folgendermaßen aus:

 x += (mouseX - x) / smoothing; y += (mouseY - y) / smoothing; 


Fügen Sie eine Glättung der Differenz zwischen den benötigten und den aktuellen Koordinatenwerten hinzu.


Manchmal ist eine Approximationsbeschränkung sinnvoll. Es gibt ein Beispiel oben, in dem sich der Wert von 0 auf 100 ändert. Wenn also der Wert der ersten Iteration „50“ erreicht, ist dies eine ziemlich große Zahl für einen Schritt. Diese Mechanik erinnert irgendwie an Achilles und die Schildkröte


Zwinkert

Verstecke und zeige alle 2-3 Sekunden Äpfel der Augen. Die trivialste Methode ist "display: none;", "transform: scaleY (N)" mit dem dynamischen Wert der y-Skala ist etwas komplexer.

Erstellen Sie 2 Konstanten

const BLINK_COUNTER_LIMIT = 180; - Anzahl der Erneuerungen vor Beginn des Blinkens,
const BLINKED_COUNTER_LIMIT = 6; - Anzahl der Verlängerungen während eines Augenzwinkerns.

Und 2 Variablen, deren Werte sich bei jeder Erneuerung ändern.

 let blinkCounter = 0; let blinkedCounter = 0; 

Code des Zwinkerns

 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 ist eine Strichvariable, deren leerer Wert zwischen dem Zwinkern und den folgenden während des Zwinkerns liegt

 ' scaleY(0.17)' ' scaleY(0.33)' ' scaleY(0.50)' ' scaleY(0.67)' ' scaleY(0.83)' ' scaleY(1.00)' 

Alle Berechnungen ergeben eine variable Blinktransformation, deren Wert zum CSS-Code der Augenpositionstransformation hinzugefügt werden sollte. Daher wird bei einer Ausfallzeit von 3 Sekunden eine leere Zeichenfolge hinzugefügt, die sich nicht auf die Augenskala auswirkt. Der CSS-Wert wird beim Blinken hinzugefügt.

 eye_left.style.transform = 'translate(' + xLeft + 'px,' + y + 'px)' + blinkTransform; eye_right.style.transform = 'translate(' + xRight + 'px,' + y + 'px)' + blinkTransform; 

Lektion der Geschichte

Jeden Tag begegnen wir Dingen, die einfach und offensichtlich erscheinen, und wir verstehen nicht einmal, dass diese äußere Einfachheit eine enorme Menge an Fragen und Verbesserungen verbirgt. Meiner Meinung nach steckt der Teufel in den Details, die das gesamte Endergebnis bilden. Muhammad Ali, der beste Boxer des 20. Jahrhunderts, hob im Moment des geraden Schlags die Ferse des hinteren Fußes. Dieses Manöver erhöhte die effektive Schlagdistanz und gab ihm mehr Gewinnchancen. Es hat immer funktioniert.

PS Ich habe keinen Einfluss auf die Website und hoffe, dass die Eigentümer meine Kommentare nicht beleidigen. Der Einfachheit halber habe ich im Code Apfel des Auges = Auge genannt.

Source: https://habr.com/ru/post/de443720/


All Articles