Proyecto 1: Líneas heladas
Primero, nuestras líneas son blancas, así que vayamos a nuestro CSS y demos al lienzo un fondo oscuro:
canvas {
background: linear-gradient(45deg, #0d1011 0% 20%, #163486);
}
Constructor de líneas
Ahora volvamos a canvas.js
. Vamos a crear una nueva clase Line
:
class Line {
constructor(x, y, offset) {
this.x = x;
this.y = y;
this.offset = offset;
this.radians = 0;
this.velocity = 0.01;
}
Aparte de determinar la posición de cada línea x
y y
, tenemos algunas otras propiedades para hacer nuestros visuales más interesantes:
- Podemos utilizar la propiedad
offset
para renderizar las líneas a diferentes distancias entre sí. - También vamos a utilizar el movimiento circular en nuestro ejemplo. Podemos utilizar la propiedad
radians
para definir el ángulo de movimiento y la propiedadvelocity
para determinar la velocidad del movimiento.
Método de dibujo de líneas
A continuación, querremos dibujar nuestras líneas. Hay un pequeño círculo en la parte inferior de cada línea, que podemos definir usando la función arc
, y luego la línea sale disparada hacia la parte superior de la pantalla:
class Line {
constructor(x, y, offset) {
this.x = x;
this.y = y;
this.offset = offset;
this.radians = 0;
this.velocity = 0.01;
} draw = () => {
c.strokeStyle = 'rgba(255, 255, 255, 0.5)';
c.fillStyle = 'rgba(255, 255, 255, 0.3)'; c.beginPath();
c.arc(this.x, this.y, 1, 0, Math.PI * 2, false);
c.fill();
c.moveTo(this.x, this.y);
c.lineTo(this.x + 300, this.y - 1000);
c.stroke();
c.closePath(); this.update();
} update = () => {
// this is where we control movement and interactivity
}
}
Para probar que funciona, puedes crear una línea de ejemplo:
const line = new Line(250, 800, 0);
line.draw();
Generación de 100 líneas
Pero queremos que las líneas llenen la pantalla, así que necesitaremos una forma de crear una matriz de 100 líneas. Aquí tenemos una versión sencilla:
const lineArray = ;for (let i = 0; i < 100; i++) { const start = { x: -250, y: 800 };
const unit = 25; lineArray.push(
new Line(
start.x + unit * i,
start.y + i * -3,
0.1 + (1 * i)
)
);
};
Para ver estas líneas, necesitaremos activar sus métodos draw
. Como pronto las animaremos, el mejor lugar para hacerlo es en la función animate
:
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, window.innerWidth, window.innerHeight);
lineArray.forEach(line => {
line.draw();
});
};animate();
¡Ahora tenemos 100 líneas! Pero podemos hacer que nuestra posición inicial sea más interesante: en el código siguiente, la variable random
ayuda a proporcionar una sutil variación que da al efecto general un aspecto más natural. (También estoy usando Math.sin(i)
para añadir un poco de ondulación en las posiciones iniciales. Esto no es necesario, pero es un buen toque.)
const lineArray = ;for (let i = 0; i < 100; i++) { const start = { x: -250, y: 800 };
const random = Math.random() - 0.5;
const unit = 25; lineArray.push(
new Line(
start.x + ((unit + random) * i),
start.y + (i + random) * -3 + Math.sin(i) * unit,
0.1 + (1 * i)
)
);
};
¡Juega con los números hasta que tengas un patrón de inicio que te guste!
Animación
A partir de aquí, es muy sencillo añadir la animación que queremos. Volvemos a nuestra clase Line
y añadimos lo siguiente en el método update
:
this.radians += this.velocity;
this.y = this.y + Math.cos(this.radians + this.offset);
Con cada fotograma de animación, this.radians
aumentará en this.velocity
. A continuación, utilizaremos this.radians
para crear un movimiento circular, a través de Math.cos
.
Si no has encontrado Math.sin
o Math.cos
antes (¡o tu trigonometría está un poco oxidada!), eso no debería impedirte seguir adelante. Sólo tienes que saber que Math.cos
nos permite crear un movimiento de ida y vuelta, en un patrón idéntico a la línea púrpura en el gráfico de abajo:
![](https://miro.medium.com/max/60/1*8c-LoOZCA3PNUD1EgnPVoA.png?q=20)
Por último, añadiendo this.offset
, las líneas comenzarán a hacer un bucle en diferentes ángulos.
Creo que este es un efecto bastante bonito. Pero para darle un toque final, vamos a añadir algo de interactividad. Cuando el usuario pase por encima de las líneas, hagamos que cambien de color.
Interactividad
La forma más sencilla de ver si el ratón del usuario está sobre una de las líneas es utilizar el método isPointInPath
incorporado en el lienzo.
Pero, sin más ajustes, esto no va a ser muy útil. Las líneas son de sólo 1 píxel de ancho, por lo que la posibilidad de desencadenar cualquier cambio será demasiado baja para ser interesante!
Una gran solución a este problema es crear líneas invisibles detrás de cada una de nuestras líneas. Las líneas invisibles deben ser más anchas, y podemos usarlas para disparar isPointInPath.
isPointInPath
Dentro de nuestro método draw
, vamos a crear una función llamada drawLinePath
. Debería tomar un width
para nuestras líneas invisibles, y un color
(en el que se convertirán nuestras líneas visibles, cuando las líneas invisibles estén en contacto):
const drawLinePath = (width = 0, color) => {
c.beginPath();
c.moveTo(this.x - (width / 2), this.y + (width / 2));
c.lineTo(this.x - (width / 2) + 300, this.y - (width / 2) - 1000);
c.lineTo(this.x + (width / 2) + 300, this.y - (width / 2) - 1000);
c.lineTo(this.x + (width / 2), this.y - (width / 2));
c.closePath();
if (c.isPointInPath(mouse.x, mouse.y) && color) {
c.strokeStyle = color;
};
};
(Ten en cuenta que el uso de las funciones de flecha anteriores vincula implícitamente el contexto correcto para this
).
Podemos entonces añadir fácilmente diferentes anchos de líneas invisibles para desencadenar diferentes cambios de color. El siguiente código debería dejar claro lo que está pasando:
drawLinePath(150, 'red');
drawLinePath(50, 'yellow');
Pero, para un efecto más sutil, prueba:
drawLinePath(150, '#baf2ef');
drawLinePath(50, '#dcf3ff');
¡Y eso es todo!
Para el código JavaScript completo, echa un vistazo a este gist.