Como posso animar o desenho de texto em uma página da web?


229

Eu quero ter uma página da web que tenha uma palavra centralizada.

Quero que essa palavra seja desenhada com uma animação, de modo que a página "escreva" da mesma maneira que gostaríamos, ou seja, começa em um ponto e desenha linhas e curvas ao longo do tempo, de modo que o resultado final seja um glifo.

Não me importo se isso é feito com <canvas>ou o DOM, e não me importo se é feito com JavaScript ou CSS. A ausência do jQuery seria boa, mas não necessária.

Como posso fazer isso? Eu procurei exaustivamente sem sorte.


2
Eu pensei um pouco sobre como realmente escrever caracteres à mão e postei meus pensamentos aqui: stackoverflow.com/questions/12700731/…
markE

Há algo de muito semelhante em um artigo codrops (com uma demo em tympanus )
Francisco Presencia

1
Naquela época, eu fazia essa animação no Flash usando máscaras de sprite animadas. O que você precisa é animar uma máscara, o que significa que ela revele progressivamente o texto. A animação seria feita de quadros de máscara.
Tiberiu-Ionuț Stan

Obviamente, você teria o benefício de poder dividir o texto em curvas. Você precisaria fazer isso usando antes a criação de SVGs e algum editor de SVG (Illustrator, ou qualquer outra coisa que possa criar um SVG do seu texto). Não sei se os SVGs suportam máscaras, mas, se o fizerem, isso seria muito mais fácil de animar.
Tiberiu-Ionuț Stan

Use SVG e manipule o código SVG com JavaScript para criar a animação.
The Demz

Respostas:


264

Eu quero que essa palavra seja desenhada com uma animação, de modo que a página "grave" a palavra da mesma maneira que gostaríamos

Versão Canvas

Isso irá desenhar caracteres únicos mais como se fosse escrever à mão. Ele usa um longo padrão de traço em que a ordem on / off é trocada ao longo do tempo por caractere. Também possui um parâmetro de velocidade.

Instantâneo
Exemplo de animação (veja a demonstração abaixo)

Para aumentar o realismo e a sensação orgânica, adicionei espaçamento aleatório de letras, deslocamento y delta, transparência, uma rotação muito sutil e, finalmente, usando uma fonte já "manuscrita". Eles podem ser agrupados como parâmetros dinâmicos para fornecer uma ampla variedade de "estilos de escrita".

Para uma aparência ainda mais realista, os dados do caminho seriam necessários, o que não é por padrão. Mas este é um código curto e eficiente que aproxima o comportamento escrito à mão e fácil de implementar.

Como funciona

Ao definir um padrão de traço, podemos criar formigas marchando, linhas pontilhadas e assim por diante. Aproveitando-se disso, definindo um ponto muito longo para o ponto "desligado" e aumentando gradualmente o ponto "ligado", ele dará a ilusão de desenhar a linha quando pressionada enquanto anima o comprimento do ponto.

Como o ponto desativado é tão longo, o padrão de repetição não será visível (o comprimento varia de acordo com o tamanho e as características do tipo de letra que está sendo usado). O caminho da carta terá um comprimento; portanto, precisamos ter certeza de que cada ponto está cobrindo pelo menos esse comprimento.

Para letras que consistem em mais de um caminho (ex. O, R, P etc.) como um é para o contorno, um é para a parte oca, as linhas parecerão ser desenhadas simultaneamente. Não podemos fazer muito sobre isso com essa técnica, pois exigiria o acesso a cada segmento de caminho a ser traçado separadamente.

Compatibilidade

Para navegadores que não suportam o elemento canvas, uma maneira alternativa de mostrar o texto pode ser colocada entre as tags, por exemplo, um texto estilizado:

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

Demo

Isso produz o traçado animado ao vivo ( sem dependências ) -

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>


21
Eu sou o único enlouquecendo por isso? Parece tão real, pelo menos, muito melhor que a primeira resposta e mais próximo da pergunta do interlocutor.
KhoPhi

5
Acabei usando a outra resposta, porque precisava dela imediatamente como um hack rápido e sujo que usei no dia seguinte e nunca mais o toquei, mas estou aceitando essa porque está muito mais perto do que estava procurando para.
strugee

Como podemos fazer várias linhas e um bloco de texto longo?
Saad Farooq

1
@ K3N Sim, foi realmente um toque agradável: p Ótimo trabalho.
Keyser

1
@ AliAl-arnous, você pode definir x na extremidade oposta, subtrair a largura do caractere em vez de adicionar, transformar com espaço negativo negado e alterar clearRect para limpar do outro lado do caractere.

216

Editar 2019


Eu criei uma biblioteca javascript que pode criar animações realistas. É fácil de usar e requer um arquivo JSON especial que atua como fonte.

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>

Confira a página do Github para obter documentação e exemplos. E Codepen


Resposta Anterior

O exemplo abaixo usa snap.js para criar tspanelementos dinamicamente e animar cada um deles stroke-dashoffset.

Resposta Anterior


Você pode fazer algo assim usando svg's stroke-dasharray

Sem keyframesanimação, você pode fazer algo assim

E para suporte ao IE, você pode usar jquery / javascript


4
Uau, isso é realmente interessante. Peguei seu snippet de código original e o aprimorei de alguma forma, removendo propriedades CSS duplicadas, usando deslocamentos baseados em porcentagem e valores de dasharray e alterando a largura do traço para tornar mais aparente como o código está funcionando: jsfiddle.net/Ajedi32/gdc4azLn / 1 Sinta-se à vontade para editar qualquer uma dessas melhorias na sua resposta, se desejar.
Ajedi32

2
Como é uma solução épica para esta pergunta, o SVG é melhor que o canvas (+1), pois, caso o navegador não o suporte, ele exibirá o texto.
Jeffery ThaGintoki

3
@JefferyThaGintoki, você também pode fazer isso com a tela, basta colocar o texto entre as tags da tela, se a tela não for suportada, o texto (ou gif animado, como na outra resposta mostrada no texto do corpo) será exibido. Se o navegador não suportar canvas, provavelmente também não suportará svg.
torox

1
Eu acho que o uso de texto SVG é ótimo, no entanto, eu estou pensando, é possível adicionar o preenchimento em algum momento? apenas o contorno das letras não fica bonito em todos os projetos, felicidades! e, é claro, +1 a esta resposta
randomguy04

1
@ randomguy04 Verifique o primeiro trecho, editei-o para adicionar um efeito de preenchimento. Ele é feito adicionando $(this).css('fill', 'red')como uma chamada de retorno para a animação
Akshay

2

Somente 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>


0

Após muitos testes, aqui estão algumas notas. O objetivo é exibir dados de texto rápidos da maneira menos obstrutiva, em páginas pesadas do DOM que exigem interações dos usuários.

É claro que existem muitas maneiras de conseguir a mesma coisa. Neste exemplo, as diferenças podem não ser óbvias, elas realmente se aplicam a interfaces complexas.

Mais lento : innerHTMLestilo em linha. O DOM é recalculado a cada iterações. O navegador está trabalhando duro para manter o trem. Ele falhará rapidamente, causando vazamentos e congelamentos de memória:

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

Muito melhor : Usando textContent, requestAnimationFrameea API de animação web. Isso fica mais suave, é óbvio nas páginas pesadas do DOM. As interações do usuário não bloqueiam as repetições. Algumas repetições podem ser ignoradas, para manter a interface bem responsiva.

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>

No exemplo acima, o DOM ainda está sendo recalculado para o excesso de texto. Podemos ver o depurador piscando bastante. Isso realmente importa em elementos em cascata! Isso ainda pode atrasar a rolagem de javascript e usuário.

insira a descrição da imagem aqui

Potência total : é possível usar o css sozinho para atualizar os dados com a contentregra css e as variáveis ​​css. O texto não será selecionável.

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>

insira a descrição da imagem aqui

Meus testes mostram grandes melhorias, o mecanismo javascript está pulando rapidamente em outras tarefas. Às vezes, pode começar um pouco mais lento que o exemplo acima. Mas, além disso, isso não bloqueia a rolagem dos usuários, e o depurador também está gostando, sem mais pulos.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.