¿Con qué frecuencia llegas a 404 páginas? Por lo general, no tienen estilo y permanecen por defecto. Recientemente encontré
test.do.am, cuyo carácter interactivo atrae la atención y anima la página de error.
Probablemente, solo había una foto de un gato, luego pensaron en el movimiento de los ojos y el desarrollador implementó la idea.

Ahora el usuario visita la página y comprueba el efecto. Es una característica pequeña y agradable, atrapa, luego el usuario la discute con colegas o amigos e incluso repite la función. Podría ser así de fácil, si no:
- El punto central no se renueva cuando el usuario cambia el tamaño de la ventana. Abra la ventana del navegador con una ventana gráfica de pequeño ancho y cambie el tamaño a pantalla completa, el gato no mira el cursor.
- El punto central se coloca en el ojo izquierdo, no en el centro binocular del círculo.
- Cuando el usuario pasa el cursor entre los ojos, las manzanas de los ojos no se juntan y no se enfocan. Los ojos miran al infinito, por eso el gato no mira al usuario, lo mira a través de él.
- Los movimientos de los ojos son inmediatos, deben ser suaves.
- Los movimientos de las manzanas ocurren debido al cambio de margen izquierdo / margen superior. Es incorrecto, encuentre la explicación a continuación.
- Los ojos no se mueven si el cursor está debajo del pie de página.
Lo que sugieroPara empezar, implementemos un movimiento de ojos perfecto.
1. Preparar marcado
<div class="cat"> <div class="cat__eye _left"></div> <div class="cat__eye _right"></div> </div>
2. Obtenga enlaces a los elementos de los ojos
const cat = document.querySelector('.cat'); const eyes = cat.querySelectorAll('.cat__eye'); const eye_left = eyes[0]; const eye_right = eyes[1];
3. Registre el detector de eventos mousemove y obtenga las coordenadas del cursor:
let mouseX; let mouseY; window.addEventListener('mousemove', e => { mouseX = e.clientX; mouseY = e.clientY; })
Agrego mousemove listener en el objeto de la ventana, no en el cuerpo del documento, porque necesito usar toda la pantalla para obtener las coordenadas del mouse.
4. movimiento
Como voy a suavizar los movimientos, no puedo administrarlos en el controlador de movimiento del mouse.
Agregue un método de actualización que será solicitado por requestAnimationFrame, que se sincroniza con la renovación del navegador. Por lo general, las renovaciones ocurren 60 veces por segundo, por lo tanto, vemos 60 fotos por segundo cada 16.6 ms.
Si el desarrollador supone que el navegador del usuario no puede soportar requestAnimationFrame, el desarrollador puede usar setTimeout fallback o
polyfill listo para usar
window.requestAnimationFrame = (function () { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60); }; })();
Para renovar o recuperar de forma estable la actualización a tiempo, registro la variable iniciada
let started = false; let mouseX; let mouseY; window.addEventListener('mousemove', e => { mouseX = e.clientX; mouseY = e.clientY; if(!started){ started = true; update(); } }) function update(){
De esta manera, obtuve constantemente el método de actualización y las coordenadas del cursor. Entonces necesito obtener valores de los movimientos de manzanas dentro de los ojos.
Intento mover ambos ojos como un solo elemento
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)';
Bastante simple: encuentre dx y dy, que son la diferencia de coordenadas entre el centro de los ojos y el mouse, encuentre el ángulo del centro al cursor, usando los métodos Math.cos y Math.sin, obtenga el valor de movimiento para horizontal y vertical. Use un
operador ternario y limite el área de movimiento de los ojos.
El valor Y se da primero para el método Math.atan2, luego el valor x. Como resultado, el usuario nota la falta de naturalidad de los movimientos de los ojos y no enfoca.
Haga que cada ojo se mueva y mire sin referencia el uno al otro.
Interesante pero peor que el resultado anterior, los ojos se mueven hacia arriba y hacia abajo independientemente. Así que usé la primera demostración como una mecánica básica de movimiento y hago que las manzanas de los ojos se junten cuando el cursor está sobre el centro del personaje.
No describiré el código completo, encuentre aquí un resultado:
Por prueba y error, he igualado los parámetros necesarios para el movimiento y el enfoque de los ojos. Entonces ahora necesito suavizar.
Suavizado¿Enlace la
biblioteca TweenMax y codifique algo como esto?
TweenMax.to( eye, 0.15, {x: x, y: y});
Vincular la biblioteca completa para una tarea simple no tiene sentido, por lo tanto, hago el alisado desde cero.
Ponga el caso de que solo hay un elemento de ojo en la página y su área de desplazamiento no está limitada en absoluto. Para suavizar los valores de coordenadas del mouse, utilizo esta mecánica:
const SMOOTHING = 10; x += (needX - x) / SMOOTHING; y += (needY - y) / SMOOTHING; eye.style.transform = 'translate3d(' + x + 'px,' + y + 'px,0)';
Utilizo translate3d para separar los ojos de otra secuencia de representación y acelerarlos.
El truco es que cada 16,6ms (60 fotos por segundo) variable x e y tienden a los valores necesarios. Cada renovación cierra el valor al necesario por 1/10 de diferencia.
let x = 0; let needX = 100; let SMOOTHING = 2; function update(){ x += (needX - x) / SMOOTHING; console.log(x); }
Luego, cada 16.6 ms de renovación obtenemos un suavizado simple y los siguientes valores de x (aprox.):
50 75 87.5 93.75 96.875 98.4375 99.21875 99.609375 100
Un par de trucos más obvios:
- Comience este examen para optimizar la carga de trabajo
if(x != needX || y != needY){ eye.style.transform = 'translate3d(' + x + 'px,' + y + 'px,0)'; }
Pero debe igualar x con needX cuando se acercan tanto como las posiciones de los ojos son casi iguales
if(Math.abs(x - needX) < 0.25){ x = needX; } if(Math.abs(y - needY) < 0.25){ y = needY; }
De lo contrario, los valores x e y llegarán a needX y needY demasiado tiempo; no habrá diferencias visuales, pero cada cambio de pantalla afectará los estilos de ojos. Por cierto, puedes jugar con él tú mismo.
let x = 0; let needX = 100; let smoothing = 2; function update(){ x += (needX - x) / smoothing; if( Math.abs(x - needX) > 0.25 ){
- Si la mecánica anterior es clara, puede crear efectos más complejos, por ejemplo, primavera. El suavizado más simple y la aproximación al cursor se ven así:
x += (mouseX - x) / smoothing; y += (mouseY - y) / smoothing;
Agregue suavizar una diferencia entre los valores de coordenadas necesarios y actuales.
A veces, la limitación de aproximación tiene sentido. Hay un ejemplo anterior donde el valor cambia de 0 a 100, por lo que en el valor de la primera iteración llega a "50", es una cifra bastante grande para 1 paso. Esta mecánica recuerda un poco la
paradoja de Aquiles y la tortuga
GuiñoEsconda y muestre manzanas de ojos cada 2-3 segundos. El método más trivial es "display: none;", "transform: scaleY (N)" con el valor dinámico de la escala y es un poco más complejo.
Crea 2 concursos
const BLINK_COUNTER_LIMIT = 180; - número de renovaciones antes del inicio del parpadeo,
const BLINKED_COUNTER_LIMIT = 6; - número de renovaciones durante un guiño.
Y 2 variables, cuyos valores cambiarán cada renovación.
let blinkCounter = 0; let blinkedCounter = 0;
Código de guiño
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 es una variable de trazo que tiene un valor vacío entre los guiños y los siguientes durante el guiño
' scaleY(0.17)' ' scaleY(0.33)' ' scaleY(0.50)' ' scaleY(0.67)' ' scaleY(0.83)' ' scaleY(1.00)'
Todos los cálculos proporcionan Transformación de parpadeo variable, cuyo valor debe agregarse al código CSS de la transformación de la posición de los ojos. Por lo tanto, se agrega una cadena vacía en el caso de un tiempo de inactividad de 3 segundos y no afecta la escala de los ojos, el valor css se agrega durante el parpadeo.
eye_left.style.transform = 'translate(' + xLeft + 'px,' + y + 'px)' + blinkTransform; eye_right.style.transform = 'translate(' + xRight + 'px,' + y + 'px)' + blinkTransform;
Leccion de la historiaTodos los días nos encontramos con cosas que parecen simples y obvias e incluso no entendemos que esta simplicidad externa esconde una cantidad colosal de preguntas y mejoras. En mi opinión, el diablo está en los detalles que forman el resultado final completo. Muhammad Ali, el mejor boxeador del siglo XX, levantó el talón del pie trasero en el momento del golpe recto. Esta maniobra aumentó la distancia efectiva de golpe y le dio más oportunidades de ganar. Siempre funcionó.
PD: No tengo nada que ver con el sitio web y espero que sus propietarios no se ofendan por mis comentarios. Por conveniencia, llamé manzana del ojo = ojo en código.