【问题标题】:HTML5 Canvas typewriter effect with word wrapping?带有自动换行的 HTML5 Canvas 打字机效果?
【发布时间】:2013-03-08 07:47:06
【问题描述】:

我正在尝试在 HTML5 Canvas 上获得动画打字机效果,但我真的很努力使用自动换行。

这是我在 Gist 中的 Shapes.js:https://gist.github.com/Jamesking56/0d7df54473085b3c5394

在那里,我创建了一个具有很多方法的 Text 对象。其中之一称为typeText()

typeText() 基本上是从打字效果开始的,但它一直在下降,我真的很难找到一种修复自动换行的方法。

谁能指导我最好的方法是什么?

【问题讨论】:

  • +1 用于无插件的解决方案!标准 JavaScript 和 HTML5 画布!。我喜欢。但是您的代码评论不佳。目前尚不清楚typeText 方法采用什么参数以及baseObjects 实际上是什么。
  • 请问您是如何调用typeText的,您传递的参数是什么?
  • baseObjects 是我在画布上的所有对象的数组(用于重绘)。 typeText() 从 Text 对象中调用。所以我会做var text = new Text(); 然后打电话给text.typeText(baseObjects, 20);

标签: javascript html canvas


【解决方案1】:

我用过的一个解决方案大致是:

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
}

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

【讨论】:

  • 哦,我明白了,您可以预先计算单词然后开始输入。唯一的缺点是我也在寻找响应性,那么如果用户调整我的画布大小会发生什么?
  • 这是迄今为止看到的最简单的解决方案,我可以将它集成到我的 Text 对象中。
  • @Jamesking56 无法使用此方法添加打字效果。
  • @PeterHerdenborg 我不是在批评。我只是说这段代码无法满足 OP 的两个要求之一。你的代码没有问题。但是,您不能将它与打字机效果一起使用。如果您认为可以,那么我想看一个演示。
【解决方案2】:

我无法弄清楚您的 Text 构造函数是如何工作的。所以我写了一个独立的函数(不属于任何对象)。您需要传递给此函数的只是一个字符串、XY 位置、行高和填充。它假设画布分配给变量canvas,二维上下文分配给变量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);
}

查看演示 here

提示-

我正在浏览您的代码并找到了一些链接-

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

阅读有关绑定here 的更多信息。

希望对您有所帮助。

PS:每个字符 75 毫秒,那将是神圣的每分钟 800 个字符!!!


更新 - 如果您想要可缩放的图形,您应该考虑SVG。 Canvas 是基于光栅的,而 SVG 是基于矢量的。这意味着 SVG 可以轻松调整大小,而当您调整画布大小时,画布的内容将开始像素化并且看起来很模糊。 Read more

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

【讨论】:

  • 我对您的演示的唯一问题是我的画布可以由用户调整大小(它始终与浏览器的高度和宽度相匹配)。如果用户在中途调整画布大小会发生什么?
  • 感谢编码提示,实际上我在大学阶段被教导使用this.draw = function(){} 作为我的对象的方法。真的不知道这是否有任何标准?至于that = this;,我实际上并不知道.bind() 存在,所以这很有用。
  • Canvas 是客户的强制要求,所以很遗憾我不能使用 SVG。
【解决方案3】:

&lt;canvas&gt; 不是为文本处理而设计的。通过在&lt;canvas&gt; 的顶部覆盖透明的 DOM 元素,这样做会容易得多。这自然假设您不需要对&lt;canvas&gt; 中的文本像素进行后处理。否则,您需要在 Javascript 中重新实现整个文本处理的东西,这有点重新发明轮子,因为浏览器可以简单地为我们做这件事。

这里有更多信息如何使用 CSS position: absoluteposition: relative 来执行它。

Allowing the user to type text in a HTML5 Canvas game

我认为你应该有一个 DOM 元素,它的所有文本都是透明颜色的,每个字母都用 &lt;span&gt; 包裹。然后你就开始通过调整不透明度使那些&lt;span&gt;s 可见。这样字母位置就不会改变。

【讨论】:

  • 我一直在寻找的 Type 书写效果怎么样?我将如何单独输入每个字母?
  • 那么响应性呢?我的画布是响应式的,重叠的文本也可以这样响应吗?
  • 1) 用&lt;span&gt; 包裹每个字母 2) 我不明白为什么会这样
【解决方案4】:

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

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

您仍然可以通过使用案例合成操作来选择字体颜色,并通过动态调整绘制宽度高度来选择字体大小。

【讨论】:

  • 您能否举例说明您的意思以及如何使用位图字体?就目前而言,这是一个糟糕的答案,因为它没有详细介绍实际实现它所需的细节。
  • 你是对的。应该是评论。但是,该数量的文本不适合评论。所以我不应该包括它吗?嗯,我认为它仍然是非常有效和有用的信息,对于看似复杂的任务,值得分享。我想投反对票更容易。
猜你喜欢
  • 1970-01-01
  • 2012-09-01
  • 2013-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-30
  • 1970-01-01
相关资源
最近更新 更多