¿Cómo crear un efecto de onda con Canvas y JavaScript?g

- 👤 Andrés Cruz

🇺🇸 In english

¿Cómo crear un efecto de onda con Canvas y JavaScript?g

Ver ejemplo

En esta entrada veremos cómo crear una onda. Para esto usaremos el elemento Canvas provista por HTML5 y la función llamada Window.requestAnimationFrame() introducida en una entrega anterior llamada: EL SECRETO DE LAS ANIMACIONES EN JAVASCRIPT (REQUESTANIMATIONFRAME()); recordando un poco el uso de la función Window.requestAnimationFrame(), permite animar figuras dibujadas en un elemento Canvas; en otras palabras:

Con la función requestAnimationFrame() se obtienen transiciones o cambios suaves a través de una API que se encuentra optimizado para trabajar con el Canvas.

Para más información, vea el enlace anterior.

Qué es un efecto onda en JavaScript y por qué usar Canvas

Un efecto onda es una animación que simula el comportamiento de una ola u oscilación. Puede usarse para:

  • Visualizaciones
  • Fondos animados
  • Efectos futuristas
  • Representaciones matemáticas

Aunque existen efectos “onda” hechos solo con CSS (como los botones ripple), Canvas permite control total sobre cada píxel y cada frame.

Cuando trabajas con Canvas:

  • Dibujas directamente en un lienzo.
  • Controlas coordenadas, formas y colores.
  • Puedes aplicar matemáticas reales al movimiento.

Por eso es ideal para ondas sinusoidales y animaciones complejas.

Por qué requestAnimationFrame es clave para animaciones fluidas

Uno de los errores más comunes es usar setInterval o setTimeout para animar. Yo mismo lo hice al principio… hasta que vi tirones, consumo excesivo y animaciones poco naturales.

requestAnimationFrame:

  • Se sincroniza con el refresco del navegador.
  • Pausa automáticamente si la pestaña no está activa.
  • Produce transiciones mucho más suaves.

En animaciones de onda, donde cada frame importa, la diferencia es enorme.

Construyendo la onda (JavaScript)

El JavaScript es en realidad corto y sencillo; pero a su vez puede resultar algo enredado debido a las operaciones matemáticas de sumas y divisiones pero trataré de explicarlo de la manera más sencilla.

Antes de mostrar el código es necesario recordar la función seno o coseno que seguramente viste en el colegio y universidad; estas funciones son como olas que vienen y van:

función Coseno

Imagen obtenida de: Coseno.

Las funciones seno y coseno aplicadas a animaciones

Cómo se comporta una onda sinusoidal

La función coseno o seno nos viene de maravilla para realizar este experimento y esto es debido a su efecto de ola u onda que poseen; si no recuerdas que son estas funciones en Internet conseguirás bastante material al respecto.

Volviendo a la aplicación de estas funciones en JavaScript tenemos que:

  • Math.cos(n) es empleada para aplicar el coseno.
  • Math.sin(n) es empleada para aplicar el seno.

Las funciones trigonométricas como Math.sin() y Math.cos() generan curvas periódicas que suben y bajan suavemente. Justo lo que necesitamos para simular una ola.

y = amplitud * Math.sin(frecuencia * x + fase);

Donde:

  • Amplitud controla la altura de la onda.
  • Frecuencia define cuántas oscilaciones hay.
  • Fase permite animar el movimiento.

Finalmente les presento el código JavaScript completo:

    var c = document.getElementById('canv');
    var $ = c.getContext('2d');
    var w = c.width = window.innerWidth;
    var h = c.height = window.innerHeight;
    var draw = function(t) {
      $.lineWidth = 1;
      $.fillStyle = 'rgb(0, 0, 0)';
      $.fillRect(0, 0, w, h);
      for (var i = -60; i < 60; i += 1) {
        $.strokeStyle = 'rgb(255, 255, 255)';
        $.beginPath();
        $.moveTo(0, h / 2);
        for (var j = 0; j < w; j += 10) {
          $.lineTo(10 * Math.cos(i) +
            j + (0.008 * j * j),
            Math.floor(h / 2 + j / 2 *
              Math.cos(j / 50 - t / 50 - i / 118) +
              (i * 0.9) * Math.cos(j / 25 - (i + t) / 65)));
        };
        $.stroke();
      }
    }
    var t = 0;
    window.addEventListener('resize', function() {
      c.width = w = window.innerWidth;
      c.height = h = window.innerHeight;
    }, false);
    var run = function() {
      window.requestAnimationFrame(run);
      t += 5;
      draw(t);
    };
    run();

Como podrás imaginar, el HTML consisten en una simple etiqueta Canvas.

Algunas consideraciones sobre el JavaScript anterior

Primero Inicializamos algunas variables globales para obtener acceso al elemento Canvas, su contexto y dimensiones:

var c = document.getElementById('canv');    var $ = c.getContext('2d');    var w = c.width = window.innerWidth;    var h = c.height = window.innerHeight;

Dentro de la función draw()

Definimos algunos estilos a las líneas que vamos a pintar:

$.lineWidth = 1;
$.fillStyle = 'rgb(0, 0, 0)';
$.fillRect(0, 0, w, h);
$.strokeStyle = 'rgb(255, 255, 255)';

Este primer for permite dibujar un conjunto de líneas en paralelo; al variar la cota inferior y superior podemos crear ondas más o menos anchas; además este for se encarga de inicializar componentes necesarios para pintar líneas.

    for (var i = -60; i < 60; i += 1) {
              $.beginPath();
              $.moveTo(0, h / 2);
                       /*For anidado*/
              $.stroke();
            }

En otras palabras, si este for no estuviera, nuestra onda se vería como un látigo:

Onda látigo

Por qué una sola onda se ve artificial

Aquí viene algo que aprendí probando:
cuando usas una sola función seno, la animación se vuelve demasiado perfecta… y por lo tanto, poco real.

Al combinar varias funciones coseno con ligeros desfases y ajustes, la onda empieza a verse más orgánica. Ese fue el punto en el que mi animación dejó de parecer “matemática” y empezó a verse viva.

El siguiente código es un for anidado que pinta w líneas por vez; en donde w es el ancho de la pantalla:

    for (var j = 0; j < w; j += 10) {
      $.lineTo(10 * Math.cos(i) +
        j + (0.008 * j * j),
        Math.floor(h / 2 + j / 2 *
          Math.cos(j / 50 - t / 50 - i / 118) +
          (i * 0.9) * Math.cos(j / 25 - (i + t) / 65)));
    };

Como podrás ver, empleamos múltiples funciones cosenos (Math.cos) para crear un variado efecto onda (y no tan constante como el coseno).

Las divisiones y multiplicaciones por números bajos es para mantener los valores lo más "constantes" posibles y que la onda no vaya a variar de tamaño radicalmente a medida que los valores de los fors (var j y var i) aumenten.

Para tener una animación variada, cada vez que se ejecuta recursivamente la función draw() a través de la función window.requestAnimationFrame(run); se varía el valor de la variable t para tal fin.

Finalmente creamos la función run() la cual es invocada al cargar la página web.

var run = function() {
      window.requestAnimationFrame(run);
      t += 5;
     draw(t);
};

Dibujando la onda paso a paso

function draw(t) {
 ctx.lineWidth = 1;
 ctx.fillStyle = 'rgb(0, 0, 0)';
 ctx.fillRect(0, 0, w, h);
 for (var i = -60; i < 60; i++) {
   ctx.strokeStyle = 'rgb(255,255,255)';
   ctx.beginPath();
   ctx.moveTo(0, h / 2);
   for (var j = 0; j < w; j += 10) {
     ctx.lineTo(
       10 * Math.cos(i) + j + (0.008 * j * j),
       Math.floor(
         h / 2 +
         j / 2 * Math.cos(j / 50 - t / 50 - i / 118) +
         (i * 0.9) * Math.cos(j / 25 - (i + t) / 65)
       )
     );
   }
   ctx.stroke();
 }
}
  • El primer for crea múltiples líneas paralelas.
  • El segundo for dibuja cada línea a lo largo del ancho.
  • Se combinan varios cosenos para romper la simetría perfecta.

Cuando eliminé ese primer for, la onda parecía un látigo. Al añadirlo, el efecto ganó profundidad.

Superposición de ondas para un efecto más orgánico

Este enfoque genera:

  • Variación visual
  • Sensación de volumen
  • Movimiento no repetitivo

Es justo lo que no ofrecen los ejemplos simples de una sola onda seno.

Controlando amplitud, frecuencia y movimiento de la onda

  • Evitar deformaciones extremas
    • Un error típico es no limitar valores. Si no controlas las divisiones y multiplicaciones, la onda empieza a crecer sin control.
    • Por experiencia, usar valores pequeños y progresivos mantiene la animación estable.
  • Ajustes que marcan la diferencia visual
    • Pequeños cambios producen efectos enormes:
      • Incrementar lentamente la fase
      • Variar ligeramente la amplitud
      • Introducir offsets mínimos
  • En animaciones de este tipo, menos es más.

Optimización y rendimiento en animaciones Canvas

Errores comunes al animar ondas

  • Redibujar sin limpiar el canvas
  • Usar demasiados cálculos por frame
  • No adaptar el canvas al resize

Yo siempre escucho el evento resize:

window.addEventListener('resize', function () {
 c.width = w = window.innerWidth;
 c.height = h = window.innerHeight;
});

Consejos prácticos para animaciones estables

  • Usa requestAnimationFrame
  • Evita bucles innecesarios
  • Controla bien las constantes matemáticas
  • Prueba en pantallas grandes y pequeñas

Variaciones del efecto onda y posibles mejoras

Una vez dominas la base, puedes:

  • Añadir color dinámico
  • Introducir ruido aleatorio
  • Crear ondas reactivas al mouse
  • Sincronizar varias capas de ondas

Aquí es donde Canvas realmente brilla frente a CSS.

Preguntas frecuentes sobre efectos de onda en JavaScript

  • ¿Es mejor Canvas que CSS para este efecto?
    • Sí, cuando necesitas ondas reales y control matemático.
  • ¿Puedo usar seno o coseno indistintamente?
    • Sí, la diferencia principal es el desfase inicial.
  • ¿Consume muchos recursos?
    • Bien optimizado, no. requestAnimationFrame ayuda mucho.
  • ¿Funciona en móviles?
    • Sí, siempre que ajustes resolución y cálculos.

Conclusión

Crear un efecto onda en JavaScript va mucho más allá de un truco visual. Cuando combinas Canvas, requestAnimationFrame y trigonometría, puedes construir animaciones fluidas, orgánicas y totalmente personalizables.

En mi experiencia, el salto de usar una onda simple a superponer varias funciones fue lo que realmente transformó el resultado final. A partir de ahí, las posibilidades son enormes.

Ver ejemplo

Acepto recibir anuncios de interes sobre este Blog.

Crea ondas sinusoidales dinámicas con HTML5 Canvas y JavaScript. Tutorial que explora requestAnimationFrame y funciones trigonométricas para animaciones web fluidas.

| 👤 Andrés Cruz

🇺🇸 In english