¿Cómo puedo animar el dibujo de texto en una página web?

229

Quiero tener una página web que tenga una palabra centrada.

Quiero que esta palabra se dibuje con una animación, de modo que la página "escriba" la palabra de la misma manera que lo haríamos, es decir, comienza en un punto y dibuja líneas y curvas con el tiempo de modo que el resultado final sea un glifo.

No me importa si esto se hace con <canvas>DOM o no, y no me importa si se hace con JavaScript o CSS. La ausencia de jQuery sería agradable, pero no es obligatorio.

¿Cómo puedo hacer esto? He buscado exhaustivamente sin suerte.

Strugee
fuente
2
Pensé en cómo "escribir a mano" los personajes y
publiqué
Hay algo realmente similar en un artículo de codrops (con una demostración en tímpano )
Francisco Presencia
1
En aquellos días, estaba haciendo esta animación en Flash usando máscaras de sprites animadas. Lo que necesita es animar una máscara, lo que significa que revele texto progresivamente. La animación estaría hecha de marcos de máscara.
Tiberiu-Ionuț Stan
Por supuesto, tendría la ventaja de poder dividir el texto en curvas. Tendría que hacer esto usando antes de usar SVGs manuales y algún editor de SVG (Illustrator, o cualquier otra cosa que pueda crear un SVG de su texto). No sé si los SVG admiten máscaras, pero si lo hacen, esto sería mucho más fácil de animar.
Tiberiu-Ionuț Stan
Use SVG y manipule el código SVG con JavaScript para hacer la animación.
The Demz

Respuestas:

264

Quiero que esta palabra se dibuje con una animación, de modo que la página "escriba" la palabra de la misma manera que lo haríamos

Versión de lona

Esto dibujará caracteres individuales más como uno escribiría a mano. Utiliza un patrón de guión largo donde el orden de encendido / apagado se intercambia con el tiempo por char. También tiene un parámetro de velocidad.

Instantánea
Ejemplo de animación (ver demo a continuación)

Para aumentar el realismo y la sensación orgánica, agregué un espaciado aleatorio de letras, un desplazamiento y delta, transparencia, una rotación muy sutil y finalmente uso una fuente ya "escrita a mano". Estos pueden envolverse como parámetros dinámicos para proporcionar una amplia gama de "estilos de escritura".

Para una apariencia aún más realista, se requerirían los datos de ruta que no son por defecto. Pero este es un código corto y eficiente que se aproxima al comportamiento escrito a mano y fácil de implementar.

Cómo funciona

Al definir un patrón de guión, podemos crear hormigas marchantes, líneas punteadas, etc. Aprovechando esto definiendo un punto muy largo para el punto "apagado" y aumentando gradualmente el punto "encendido", dará la ilusión de dibujar la línea cuando se acaricia mientras se anima la longitud del punto.

Dado que el punto de desconexión es tan largo, el patrón repetitivo no será visible (la longitud variará con el tamaño y las características del tipo de letra utilizado). La ruta de la letra tendrá una longitud, por lo que debemos asegurarnos de que cada punto cubra al menos esta longitud.

Para las letras que consisten en más de una ruta (por ejemplo, O, R, P, etc.) como una es para el contorno, una es para la parte hueca, las líneas aparecerán dibujadas simultáneamente. No podemos hacer mucho al respecto con esta técnica, ya que requeriría el acceso a cada segmento de ruta para ser trazado por separado.

Compatibilidad

Para los navegadores que no admiten el elemento de lienzo, se puede colocar una forma alternativa de mostrar el texto entre las etiquetas, por ejemplo, un texto con estilo:

<canvas ...>
    <div class="txtStyle">STROKE-ON CANVAS</div>
</canvas>

Manifestación

Esto produce el trazo animado en vivo ( sin dependencias ):

var ctx = document.querySelector("canvas").getContext("2d"),
    dashLen = 220, dashOffset = dashLen, speed = 5,
    txt = "STROKE-ON CANVAS", x = 30, i = 0;

ctx.font = "50px Comic Sans MS, cursive, TSCu_Comic, sans-serif"; 
ctx.lineWidth = 5; ctx.lineJoin = "round"; ctx.globalAlpha = 2/3;
ctx.strokeStyle = ctx.fillStyle = "#1f2f90";

(function loop() {
  ctx.clearRect(x, 0, 60, 150);
  ctx.setLineDash([dashLen - dashOffset, dashOffset - speed]); // create a long dash mask
  dashOffset -= speed;                                         // reduce dash length
  ctx.strokeText(txt[i], x, 90);                               // stroke letter

  if (dashOffset > 0) requestAnimationFrame(loop);             // animate
  else {
    ctx.fillText(txt[i], x, 90);                               // fill final letter
    dashOffset = dashLen;                                      // prep next char
    x += ctx.measureText(txt[i++]).width + ctx.lineWidth * Math.random();
    ctx.setTransform(1, 0, 0, 1, 0, 3 * Math.random());        // random y-delta
    ctx.rotate(Math.random() * 0.005);                         // random rotation
    if (i < txt.length) requestAnimationFrame(loop);
  }
})();
canvas {background:url(http://i.imgur.com/5RIXWIE.png)}
<canvas width=630></canvas>


fuente
21
¿Soy el único que se está volviendo loco por esto? Parece tan real, al menos, mucho mejor que la primera respuesta, y más cercano a la pregunta del interlocutor.
KhoPhi
55
Terminé usando la otra respuesta, porque la necesitaba de inmediato como un truco rápido y sucio que usé al día siguiente y luego nunca volví a tocar, pero acepto esta porque está mucho más cerca de lo que estaba buscando. para.
Strugee
¿Cómo podemos hacerlo para varias líneas y un bloque de texto largo?
Saad Farooq
1
@ K3N Sí, en realidad fue un buen toque: p Gran trabajo.
keyser
1
@ AliAl-arnous puede establecer x en el extremo opuesto, restar ancho de caracteres en lugar de sumar, transformar con espacio negativo negado y cambiar clearRect para borrar en el otro lado del carácter.
216

Editar 2019


Creé una biblioteca de JavaScript que puede crear animaciones realistas. Es fácil de usar y requiere un archivo JSON especial que actúe como fuente.

var vara = new Vara("#container", "https://rawcdn.githack.com/akzhy/Vara/ed6ab92fdf196596266ae76867c415fa659eb348/fonts/Satisfy/SatisfySL.json", [{
  text: "Hello World!!",
  fontSize: 48,
  y:10
}, {
  text: "Realistic Animations",
  fontSize: 34,
  color:"#f44336"
}], {
  strokeWidth: 2,
  textAlign:"center"
});
#container {
  padding: 30px;
}
<script src="https://rawcdn.githack.com/akzhy/Vara/16e30acca2872212e28735cfdbaba696a355c780/src/vara.min.js"></script>
<div id="container"></div>

Pedido de la página de Github para la documentación y ejemplos. Y Codepen


Respuesta anterior

El siguiente ejemplo usa snap.js para crear dinámicamente tspan elementos y luego animar cada uno de ellos stroke-dashoffset.

Respuesta anterior


Puedes hacer algo como esto usando svg's stroke-dasharray

Sin keyframes animación puedes hacer algo como esto

Y para el soporte de IE puede usar jquery / javascript

Akshay
fuente
44
Wow, eso es realmente interesante. Tomé su fragmento de código original y lo mejoré un poco eliminando propiedades CSS duplicadas, usando compensaciones basadas en porcentajes y valores de dasharray, y cambiando el ancho del trazo para que sea más evidente cómo funciona el código: jsfiddle.net/Ajedi32/gdc4azLn / 1 Siéntase libre de editar cualquiera de esas mejoras en su respuesta si lo desea.
Ajedi32
2
Esta es una solución épica para esta pregunta, SVG es mejor que el lienzo (+1) en la medida en que en caso de que el navegador no lo admita, mostrará el texto en su lugar.
Jeffery ThaGintoki
3
@JefferyThaGintoki, también puede hacer esto con el lienzo, simplemente coloque el texto entre las etiquetas del lienzo, si el lienzo no es compatible, aparecerá el texto (o gif animado como se muestra en la otra respuesta en el texto del cuerpo). Si el navegador no es compatible con el lienzo, probablemente tampoco sea compatible con svg.
torox
1
Creo que el uso del texto SVG es excelente, sin embargo, me pregunto, ¿es posible agregar el relleno en algún momento? solo el contorno de las letras no se ve bien en todos los proyectos, ¡salud! y, por supuesto, +1 a esta respuesta
randomguy04
1
@ randomguy04 Verifique el primer fragmento, lo he editado para agregar un efecto de relleno. Se realiza agregando $(this).css('fill', 'red')como una devolución de llamada a la animación
Akshay
2

Solo CSS:

@keyframes fadein_left {
  from {
    left: 0;
  }
  to {
    left: 100%;
  }
}

#start:before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0%;
  opacity: 0.7;
  height: 25px;
  background: #fff;
  animation: fadein_left 3s;
}
<div id="start">
  some text some text some text some text some text
</div>

zloctb
fuente
0

Después de muchas pruebas, aquí hay algunas notas. El objetivo es mostrar datos de texto rápidos de la forma menos bloqueante, en páginas pesadas DOM que requieren interacciones de los usuarios.

Por supuesto, hay muchas formas de lograr lo mismo. En este ejemplo, las diferencias pueden no ser obvias, realmente se aplican a interfaces complejas.

Más lento : innerHTMLy estilo en línea. El DOM se recalcula en cada iteración. El navegador está trabajando duro para mantener el tren. Fallará rápidamente, causando pérdidas de memoria y congelaciones:

setInterval(function(){
  out.innerHTML = `<span style="position:fixed;top:${~~(Math.random() * 220)}px">${Math.random() * 1000}<span>`
},1)
<h1 id="out"></h1>

Mucho mejor : El uso textContent, requestAnimationFramey la API de animación web. Esto va mucho más suave, es obvio en páginas pesadas DOM. Las interacciones del usuario no bloquearán los repintes. Se pueden omitir algunas reparaciones para mantener la interfaz bien receptiva.

let job
const paint = () => {
  job = requestAnimationFrame(paint)
  out.textContent = Math.random() * 1000
  out.animate([{top: ~~(Math.random() * 220)+"px"},{top:0}],{duration: 1,iterations: 1})
}

/* Start looping -----------------------------------------*/
requestAnimationFrame(paint)
#out{
position: fixed}
<h1 id="out"></h1>

En el ejemplo anterior, el DOM todavía se está recalculando para el desbordamiento de texto. Podemos ver que el depurador parpadea con fuerza. ¡Esto realmente importa en los elementos en cascada! Esto todavía puede ralentizar javascript y los desplazamientos de los usuarios.

ingrese la descripción de la imagen aquí

Potencia total : es posible usar css solo para actualizar los datos con la contentregla css y las variables css. El texto no será seleccionable.

let job
const paint = () => {
  job = requestAnimationFrame(paint)
  out.setAttribute('data-before', Math.random() * 1000)
  out.animate([{top: ~~(Math.random() * 220)+"px"},{top:0}],{duration: 1,iterations: 1})
}

/* Start looping -----------------------------------------*/
requestAnimationFrame(paint)
#out{
  position: fixed
  
  }
#out:before {
   content: attr(data-before)
 }
<h1 id="out"></h1>

ingrese la descripción de la imagen aquí

Mis pruebas muestran grandes mejoras, el motor de JavaScript se salta rápidamente en otras tareas. A veces puede comenzar un poco más lento que el ejemplo anterior. Pero además de eso, esto no bloquea los desplazamientos de los usuarios, y al depurador también le gusta, no más saltos.

NVRM
fuente