如何为网页上的文字绘制动画?


229

我想要一个包含一个中心词的网页。

我希望用动画来绘制该单词,以便页面以与我们相同的方式“写”出该单词,即,它从一个点开始并随时间绘制线条和曲线,从而最终结果是一个字形。

我不在乎这是使用<canvas>DOM还是DOM 完成,也不关心它是使用JavaScript还是CSS完成的。缺少jQuery会很好,但不是必需的。

我怎样才能做到这一点?我进行了详尽的搜索,没有运气。


2
我花了心思如何真正“手写”字符和张贴在这里我的想法:stackoverflow.com/questions/12700731/...
坊间


1
以前,我是在Flash中使用动画精灵蒙版制作此动画的。您需要为面具设置动画,这意味着让它逐渐显示文本。动画将由蒙版帧组成。
Tiberiu-Ionuț Stan

当然,您会受益于beeing能够将文本分成曲线。您必须先手动使用SVG和某些SVG编辑器(Illustrator或其他可以创建文本的SVG)来执行此操作。我不知道SVG是否支持蒙版,但是如果支持蒙版,这将使动画更容易。
Tiberiu-Ionuț Stan

使用SVG并使用JavaScript处理SVG代码以制作动画。
Demz,2015年

Answers:


264

我希望通过动画来绘制该单词,以便页面将“单词”写出的方式与我们将

画布版本

这将绘制单个字符,就像用手写的字符一样。它使用长破折号模式,其中每个字符的时间按开/关顺序交换。它还具有速度参数。

快照
动画示例(请参见下面的演示)

为了增加真实感和自然感,我添加了随机字母间距,y增量偏移,透明度,非常细微的旋转,最后使用了已经“手写”的字体。这些可以包装为动态参数,以提供广泛的“书写样式”。

为了更真实的外观,将需要路径数据,默认情况下不需要。但这是一段简短高效的代码,近似于手写行为,并且易于实现。

这个怎么运作

通过定义破折号模式,我们可以创建行进蚂蚁,虚线等。通过为“ off”点定义一个非常长的点并逐渐增加“ on”点来利用这一点,这会给人一种在绘制点的动画时画线的动画效果,同时赋予点长以动画效果。

由于关闭点太长,因此无法看到重复图案(长度会随所用字体的大小和特性而变化)。字母的路径将有一个长度,因此我们需要确保每个点至少覆盖该长度。

对于包含多个路径(例如O,R,P等)的字母,其中一个用于轮廓,一个用于空心部分,线条似乎会同时绘制。对于这种技术,我们不能做太多事情,因为它需要分别访问每个路径段。

兼容性

对于不支持canvas元素的浏览器,可以在标签之间放置另一种显示文本的方法,例如,带样式的文本:

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

演示版

这将产生实时动画启动(无依赖项)-

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
我是唯一为此疯狂的人吗?看起来如此真实,至少比第一个答案要好,并且最接近发问者的问题。
KhoPhi 2015年

5
我最终使用了另一个答案,因为我马上就需要它作为第二天使用的快速n脏黑客,然后再也没有碰过,但是我接受了这个答案,因为它离我正在寻找的东西更近了对于。
2015年

我们如何才能将其用于多行和一个长文本块?
Saad Farooq,2015年

1
@ K3N是的,这实际上是一个不错的选择:p很棒的工作。
2015年

1
@ AliAl-arnous,您可以将x设置为相反的一端,减去char宽度而不是添加,用负的负空间进行变换,然后更改clearRect以清除char的另一侧。

216

编辑2019


我创建了一个可以创建逼真的动画的javascript库。它易于使用,并且需要一个特殊的JSON文件作为字体。

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>

请查看Github页面以获取文档和示例。和Codepen


上一个答案

以下示例使用snap.js动态创建tspan元素,然后为每个元素设置动画stroke-dashoffset

上一个答案


您可以使用svg stroke-dasharray

没有keyframes动画,您可以做这样的事情

对于IE支持,您可以使用jquery / javascript


4
哇,这真的很有趣。我已经采用了原始代码段,并通过删除重复的CSS属性,使用基于百分比的偏移量和破折号值以及更改笔触宽度使代码的工作方式更加明显来对其进行了某种程度的改进jsfiddle.net/Ajedi32/gdc4azLn / 1如果需要,可以将所有这些改进内容编辑到您的答案中。
Ajedi32

2
对于这个问题,这是一个史诗般的解决方案,在浏览器不支持的情况下,SVG比canvas(+1)更好,它将显示文本。
Jeffery ThaGintoki 2015年

3
@JefferyThaGintoki您也可以使用canvas进行此操作,只需将文本放在canvas标签之间,如果不支持canvas文本(或正文文本中其他答案所示的gif动画),则会代替显示。如果浏览器不支持canvas,则可能也不支持svg。
大约

1
我认为SVG文本的用法很棒,但是我想知道,是否可以在某个时候添加填充?只是字母的轮廓在所有项目中看起来都不太好,加油!并且当然对此答案+1
randomguy04 '16

1
@ randomguy04检查第一个代码段,我对其进行了编辑以添加填充效果。通过向$(this).css('fill', 'red')动画添加回调来完成
Akshay,2016年

2

仅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

经过多次测试,这里有一些注意事项。目标是在需要用户交互的DOM重磅页面上,以最少的阻塞方式显示快速文本数据。

当然,有很多方法可以实现相同的目的。在此示例中,差异可能并不明显,它确实适用于复杂的接口。

最慢innerHTML和内联样式。每次迭代都会重新计算DOM。浏览器正在努力保持列车运行。它会很快失败,从而导致内存泄漏和冻结:

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

更好的方式:使用textContentrequestAnimationFrame和网页动画API。这种方法更加平滑,在DOM繁重的页面上很明显。用户交互不会阻止重绘。为了使界面保持良好的响应性,可能会跳过一些重画。

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>

在上面的示例中,仍在为文本溢出重新计算DOM。我们可以看到调试器在闪烁。这对于级联元素真的很重要!这仍然会降低javascript和用户的滚动速度。

在此处输入图片说明

强大功能:可以单独使用css来使用css content规则和css变量刷新数据。文本将无法选择。

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>

在此处输入图片说明

我的测试显示出很大的改进,javascript引擎在其他任务上迅速跳过。有时它的启动速度可能比上面的示例慢。但是除此之外,这不会阻止用户滚动,并且调试器也很喜欢,不再有跳跃。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.