HTML5画布文字打字机效果和自动换行?

3
我想在HTML5画布上实现一个动态打字机效果,但是我在单词换行方面遇到了很大的困难。
这里是我的Shapes.js代码片段:https://gist.github.com/Jamesking56/0d7df54473085b3c5394 在代码中,我创建了一个名为Text的对象,其中包含许多方法之一是typeText()typeText()基本上启动了打字机效果,但它会持续掉落并且我真的很难找到解决单词换行的方法。
有人能指导我最好的做法吗?

1
+1的解决方案中_没有任何插件!使用标准JavaScript和HTML5 Canvas!_我很喜欢这个。但是你的代码注释太少了。不清楚typeText方法需要哪些参数,以及baseObjects到底是什么。 - ShuklaSannidhya
请问您是如何调用 typeText 函数的?您传递了哪些参数? - ShuklaSannidhya
baseObjects 是画布上所有对象的数组(用于重绘目的)。typeText() 是从 Text 对象调用的。所以我会这样做 var text = new Text(); 然后调用 text.typeText(baseObjects, 20); - Jamesking56
4个回答

2
我使用的解决方案大致如下:

...

var maxWidth = 250;
var text = 'lorem ipsum dolor et sit amet...';

var words = text.split(' ');
var line = [words[0]]; //begin with a single word

for(var i=1; i<words.length; i++){
    while(ctx.measureText(line.join(' ')) < maxWidth && i<words.length-1){
        line.push(words[i++]);
    }
    if(i < words.length-1) { //Loop ended because line became too wide
        line.pop(); //Remove last word
        i--; //Take one step back
    }
    //Ouput the line
}

由于似乎没有办法测量输出文本的高度,您需要手动偏移每行输出的一些硬编码行高。


哦,我明白了,你可以预先计算单词,然后开始打字。唯一的缺点是我也在寻找响应性,那么如果用户调整了我的画布大小会发生什么呢? - Jamesking56
这是我目前看到的最简单的解决方案,我可以将其集成到我的“Text”对象中。 - Jamesking56
@Jamesking56,你不能使用这种方法添加打字效果。 - ShuklaSannidhya
@PeterHerdenborg 我并不是在批评你。我只是想说这段代码无法满足原帖的两个要求之一。你的代码没有问题,但是你不能将它用于打字机效果。如果你认为可以,那么我想看一下演示。 - ShuklaSannidhya

0

我弄不明白你的Text构造函数是怎么工作的。所以我写了一个独立的函数(不属于任何对象)。你只需要传递给这个函数一个字符串、XY位置、行高和内边距。它假设画布被分配给变量canvas,2D上下文被分配给变量ctx

var canvas, ctx;
function typeOut(str, startX, startY, lineHeight, padding) {
    var cursorX = startX || 0;
    var cursorY = startY || 0;
    var lineHeight = lineHeight || 32;
    padding = padding || 10;
    var i = 0;
    $_inter = setInterval(function() {
        var w = ctx.measureText(str.charAt(i)).width;
        if(cursorX + w >= canvas.width - padding) {
            cursorX = startX;
            cursorY += lineHeight;
        }
        ctx.fillText(str.charAt(i), cursorX, cursorY);
        i++;
        cursorX += w;
        if(i === str.length) {
            clearInterval($_inter);
        }
    }, 75);
}

点击这里查看演示。

提示-

我正在查看你的代码,发现了这样的东西-

function Rectangle(x,y,width,height,colour) {
    //properties
    this.draw = function() { //Don't assigns object methods through constructors
        ctx.fillStyle = this.colour;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    };
}

不应该通过构造函数向对象添加方法,因为这会在每次实例化对象时创建该方法。相反,应该将方法添加到对象的原型中,这样它们只会被创建一次,并且将被所有实例共享。例如:

function Rectangle(x,y,width,height,colour) {
    //properties
}
Rectangle.prototype.draw = function() {
    ctx.fillStyle = this.colour;
    ctx.fillRect(this.x, this.y, this.width, this.height);
}

另外,我发现你正在创建额外的变量来指向某些对象。例如 -

var that = this;
var fadeIn = setInterval(function() {
    //code
    that.draw();
    //code
}, time);

您不应该创建一个额外的指向 Text 对象的引用。使用 bind 方法,这样 this 就会指向 Text 对象。例如:

var fadeIn = setInterval(function() {
    //code
    this.draw(); // <-- Check this it is `this.draw` no need for `that.draw`
    //code
}.bind(this), time);   //bind the object

了解有关绑定此处的更多信息。

希望这有所帮助。

附言:每个字符需要75毫秒,那将是每分钟800个字符!!!


更新 - 如果你需要可扩展的图形,你应该考虑 SVG。Canvas 是基于光栅的,而 SVG 是基于矢量的。这意味着 SVG 可以轻松地调整大小,而当你调整 Canvas 的大小时,Canvas 的内容将开始出现像素化并且变得模糊。阅读更多

要调整 Canvas 的内容大小,你需要重新绘制整个 Canvas。每当在 Canvas 上绘制某些内容时,浏览器都会进行绘制然后忘记它。因此,如果你想更改对象的大小/位置,你需要完全清除 Canvas 并重新绘制对象。在你的情况下,你需要根据 Canvas 的大小更改 ctx.font 然后更新 Canvas,这将是一个非常繁琐的任务。


我对你的演示唯一的问题是我的画布可以被用户调整大小(它始终与浏览器的高度和宽度匹配)。如果用户在中途调整了画布大小,会发生什么? - Jamesking56
感谢您提供的编程技巧,我在大学里学习时被教授使用 this.draw = function(){} 来定义对象方法。不知道是否有任何标准可以遵循?至于 that = this;,我之前并不知道 .bind() 的存在,这对我很有帮助。 - Jamesking56
客户要求必须使用Canvas,所以很遗憾我不能使用SVG。 - Jamesking56

-1

<canvas> 不是为文本处理而设计的。通过在 <canvas> 顶部叠加透明的 DOM 元素,这样做会更加容易。当然,这假设您不需要在 <canvas> 中后处理文本像素。否则,您需要在 Javascript 中重新实现整个文本处理过程,这有点像重复造轮子,因为浏览器可以为我们简单地完成它。

以下是使用 CSS position: absoluteposition: relative 执行此操作的更多信息。

允许用户在 HTML5 Canvas 游戏中输入文本

我认为您应该拥有一个具有所有文本的透明颜色的 DOM 元素,每个字母都包裹在一个 <span> 中。然后,通过调整不透明度来使这些 <span> 可见。这样,字母位置就不会改变。


那种我想要的打字效果怎么样?我应该如何逐个输入每个字母? - Jamesking56
还有响应性方面怎么办?我的画布是响应式的,覆盖的文字也可以这样实现响应式吗? - Jamesking56
  1. 在每个字母外面包裹<span>标签
  2. 我不明白为什么不行
- Mikko Ohtamaa

-1

个人而言,在我的画布游戏中需要文本时,我总是使用位图字体。它有几个优点:

  1. 画布上的FillText很慢。位图字体要快得多。
  2. 你知道每个字母的宽度,使换行和文本对齐更容易。

通过使用各种合成操作选择字体颜色,通过动态调整绘制宽度高度来选择字体大小,仍然可以获得好处。


你能展示一下你的意思,并演示如何使用位图字体吗?就目前而言,这是一个不够详细以实际实现的糟糕回答。 - George Stocker
你说得对。这应该是一条注释。然而,这么多的文本无法放在注释中。那么我不应该包含它吗?嗯,我认为这仍然是非常有效和有用的信息,对于一个看似复杂的任务来说,这是值得分享的。我猜投反对票更容易些。 - Jarrod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接