Comment animer le dessin d'un texte sur une page Web?

229

Je veux avoir une page Web qui a un mot centré.

Je veux que ce mot soit dessiné avec une animation, de telle sorte que la page "écrit" le mot de la même manière que nous le ferions, c'est-à-dire qu'il commence à un point et dessine des lignes et des courbes dans le temps de sorte que le résultat final soit un glyphe.

Je ne me soucie pas si cela est fait avec <canvas>ou le DOM, et je me fiche que ce soit fait avec JavaScript ou CSS. L'absence de jQuery serait bien, mais pas obligatoire.

Comment puis-je faire ceci? J'ai cherché exhaustivement sans chance.

strugee
la source
2
J'ai réfléchi à la façon de réellement "écrire à la main" des caractères et j'ai posté mes pensées ici: stackoverflow.com/questions/12700731/…
markE
Il y a quelque chose de vraiment similaire dans un article codrops (avec une démo sur tympan )
Francisco Presencia
1
À l'époque, je faisais cette animation en Flash à l'aide de masques de sprites animés. Ce dont vous avez besoin, c'est d'animer un masque, ce qui signifie qu'il doit progressivement révéler le texte. L'animation serait faite d'images de masque.
Tiberiu-Ionuț Stan
Bien sûr, vous auriez l'avantage de pouvoir décomposer le texte en courbes. Vous devez le faire en utilisant au préalable des SVG et un éditeur SVG (Illustrator, ou tout autre élément pouvant créer un SVG de votre texte). Je ne sais pas si les SVG prennent en charge les masques, mais s'ils le font, cela deviendrait beaucoup plus facile à animer.
Tiberiu-Ionuț Stan
Utilisez SVG et manipulez le code SVG avec JavaScript pour créer l'animation.
The Demz

Réponses:

264

Je veux que ce mot soit dessiné avec une animation, de telle sorte que la page "écrit" le mot de la même manière que nous le ferions

Version toile

Cela va dessiner des caractères uniques plus comme on écrirait à la main. Il utilise un long tableau de bord où l'ordre d'activation / désactivation est permuté dans le temps par caractère. Il a également un paramètre de vitesse.

Instantané
Exemple d'animation (voir démo ci-dessous)

Pour augmenter le réalisme et la sensation organique, j'ai ajouté un espacement aléatoire des lettres, un décalage y delta, de la transparence, une rotation très subtile et enfin une police déjà "manuscrite". Celles-ci peuvent être regroupées sous forme de paramètres dynamiques pour fournir une large gamme de "styles d'écriture".

Pour un aspect encore plus réaliste, les données de chemin seraient nécessaires, ce qui n'est pas le cas par défaut. Mais il s'agit d'un morceau de code court et efficace qui se rapproche du comportement manuscrit et facile à implémenter.

Comment ça fonctionne

En définissant un motif de tiret, nous pouvons créer des fourmis en marche, des lignes pointillées, etc. Profitant de cela en définissant un point très long pour le point "off" et en augmentant progressivement le point "on", cela donnera l'illusion de dessiner la ligne quand elle sera caressée tout en animant la longueur du point.

Étant donné que le point désactivé est si long, le motif répétitif ne sera pas visible (la longueur variera en fonction de la taille et des caractéristiques de la police de caractères utilisée). Le chemin de la lettre aura une longueur, nous devons donc nous assurer que chaque point couvre au moins cette longueur.

Pour les lettres qui se composent de plus d'un chemin (par exemple O, R, P, etc.) comme pour le contour, pour la partie creuse, les lignes semblent tracées simultanément. Nous ne pouvons pas faire grand-chose avec cette technique car elle nécessiterait que l'accès à chaque segment de chemin soit tracé séparément.

Compatibilité

Pour les navigateurs qui ne prennent pas en charge l'élément canvas, une autre façon d'afficher le texte peut être placée entre les balises, par exemple un texte stylisé:

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

Démo

Cela produit le passage en direct animé ( pas de dépendances ) -

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>


la source
21
Suis-je le seul à devenir fou pour ça? Semble si réel, au moins, bien meilleur que la première réponse, et le plus proche de la question de l'interrogateur.
KhoPhi
5
J'ai fini par utiliser l'autre réponse, car j'en avais besoin tout de suite comme un hack rapide et sale que j'ai utilisé le lendemain et que je n'ai plus jamais touché, mais j'accepte celle-ci parce qu'elle est bien plus proche de ce que je cherchais pour.
strugee
Comment pouvons-nous le faire pour plusieurs lignes et un long bloc de texte?
Saad Farooq
1
@ K3N Oui, c'était en fait une belle touche: p Excellent travail.
keyser
1
@ AliAl-arnous vous pouvez définir x à l'extrémité opposée, soustraire la largeur de caractère au lieu d'ajouter, transformer avec un espace négatif annulé et changer clearRect pour effacer de l'autre côté du caractère.
216

Modifier 2019


J'ai créé une bibliothèque javascript qui peut créer des animations réalistes. Il est facile à utiliser et nécessite un fichier JSON spécial qui fait office de police.

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>

Consultez la page Github pour la documentation et des exemples. Et Codepen


Réponse précédente

L'exemple ci-dessous utilise snap.js pour créer dynamiquement des tspanéléments, puis animer chacun d'eux stroke-dashoffset.

Réponse précédente


Vous pouvez faire quelque chose comme ça en utilisant les svg stroke-dasharray

Sans keyframesanimation, vous pouvez faire quelque chose comme ça

Et pour le support IE, vous pouvez utiliser jquery / javascript

Akshay
la source
4
Wow, c'est vraiment intéressant. J'ai pris votre extrait de code d'origine et l'ai amélioré quelque peu en supprimant les propriétés CSS en double, en utilisant des décalages basés sur des pourcentages et des valeurs de tableau de données, et en changeant la largeur du trait pour rendre plus visible le fonctionnement du code: jsfiddle.net/Ajedi32/gdc4azLn / 1 N'hésitez pas à modifier l'une de ces améliorations dans votre réponse si vous le souhaitez.
Ajedi32
2
c'est une solution épique pour cette question, SVG est meilleur que canvas (+1) dans la mesure où dans le cas où le navigateur ne le prend pas en charge, il affichera le texte à la place.
Jeffery ThaGintoki
3
@JefferyThaGintoki vous pouvez également le faire avec le canevas, placez simplement le texte entre les balises du canevas, si le canevas n'est pas pris en charge, le texte (ou le gif animé comme dans les autres réponses le montre dans le corps du texte) apparaîtra à la place. Si le navigateur ne prend pas en charge le canevas, il ne prendra probablement pas en charge le svg non plus.
torox
1
Je pense que l'utilisation du texte SVG est excellente, mais je me demande, est-il possible d'ajouter le remplissage à un moment donné? juste le contour des lettres n'est pas beau dans tous les projets, bravo! et bien sûr +1 à cette réponse
randomguy04
1
@ randomguy04 Vérifiez le premier extrait, je l'ai édité pour ajouter un effet de remplissage. Cela se fait en ajoutant $(this).css('fill', 'red')comme rappel à l'animation
Akshay
2

Uniquement 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
la source
0

Après de nombreux tests, voici quelques notes. Le but est d'afficher des données texte rapides de la manière la moins bloquante, sur des pages lourdes DOM nécessitant des interactions utilisateurs.

Il y a bien sûr plusieurs façons de réaliser la même chose. Sur cet exemple, les différences peuvent ne pas être évidentes, elles s'appliquent vraiment aux interfaces complexes.

Style le plus lent : innerHTMLet en ligne. Le DOM est recalculé à chaque itération. Le navigateur travaille dur pour garder le train. Il échouera rapidement, provoquant des fuites et gels de mémoire:

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

Bien mieux : l' utilisation textContent, requestAnimationFrameet l'animation Web api. Cela va beaucoup plus facilement, c'est évident sur les pages lourdes DOM. Les interactions utilisateur ne bloqueront pas les repeints. Certains repeints peuvent être ignorés pour que l'interface reste bien réactive.

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>

Dans l'exemple ci-dessus, le DOM est toujours en cours de recalcul pour le débordement de texte. Nous pouvons voir le débogueur clignoter fortement. Cela compte vraiment sur les éléments en cascade! Cela peut encore ralentir le javascript et le défilement des utilisateurs.

entrez la description de l'image ici

Pleine puissance : il est possible d'utiliser css seul pour actualiser les données avec la contentrègle css et les variables css. Le texte ne sera alors plus sélectionnable.

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>

entrez la description de l'image ici

Mes tests ont montré de grandes améliorations, le moteur javascript saute rapidement sur d'autres tâches. Parfois, il peut démarrer un peu plus lentement que l'exemple ci-dessus. Mais à côté de cela, cela ne bloque pas les parchemins des utilisateurs, et le débogueur aime aussi, plus de sauts.

NVRM
la source