在HTML画布中添加字母间距

时间:2015-11-27 10:50:33

标签: html canvas text fonts

我已经阅读了很多StackOverflow答案以及其他讨论如何在Canvas中进行字母间距的页面。其中一个更有用的是Letter spacing in canvas element

正如其他问题所说,'我有这个画布元素,我正在绘制文字。我想设置字母间距类似于CSS字母间距属性。我的意思是在绘制字符串时增加字母之间的像素数量。请注意,字母间距有时会被错误地称为字距调整。

我注意到一般的方法似乎是逐字母输出字符串,使用measureText(字母)来获取字母的宽度,然后添加额外的间距。这个问题是它没有考虑字母字距调整对等。有关此示例和相关注释,请参阅上面的链接。

对我而言,对于“间距”的行间距,这样做的方法是做类似的事情:

  1. 从位置(X,Y)开始。
  2. 使用measureText()
  3. 测量wAll,整个字符串的宽度
  4. 从字符串中删除第一个字符
  5. 使用fillText()
  6. 打印位置(X,Y)的第一个字符
  7. 使用measureText()测量wShorter,得到的较短字符串的宽度。
  8. 从整个字符串的宽度中减去较短字符串的宽度,给出字符的字距宽度,wChar = wAll - wShorter
  9. 按wChar +间距增加X
  10. wAll = wShorter
  11. 从第3步开始重复
  12. 这不会考虑到字距调整吗?我错过了什么吗? measureText()是否会根据最外面的字符或其他内容添加一个填充加载,如果是,则fillText()不会使用相同的系统输出字符,否定该问题?上面的链接中有人提到'像素对齐字体提示',但我不知道这是如何适用的。任何人都可以一般或具体地建议这是否有效或者是否有问题?

    编辑:这不是另一个问题的重复 - 它链接到并引用。根据拟议的副本,问题不在于如何做“画布上的字母间距”;这提出了一个可能的解决方案(据我所知,其他人没有建议)解决这个问题和其他问题,并询问是否有人能够看到或知道该提出的解决方案的任何问题 - 即它询问提出的解决方案和它的要点,包括measureText(),fillText()和'像素对齐字体提示'的细节。

2 个答案:

答案 0 :(得分:2)

嗯,我已根据上面的伪代码编写了代码,并通过截屏和眼球对差异进行了一些比较(缩放,使用例如剪辑框的直线来比较每个的X位置和宽度)字符)。对我来说看起来完全一样,间距设置为0。

这是HTML:

<canvas id="Test1" width="800px" height="200px"><p>Your browser does not support canvas.</p></canvas>

以下是代码:

this.fillTextWithSpacing = function(context, text, x, y, spacing)
{
    //Start at position (X, Y).
    //Measure wAll, the width of the entire string using measureText()
    wAll = context.measureText(text).width;

    do
    {
    //Remove the first character from the string
    char = text.substr(0, 1);
    text = text.substr(1);

    //Print the first character at position (X, Y) using fillText()
    context.fillText(char, x, y);

    //Measure wShorter, the width of the resulting shorter string using measureText().
    if (text == "")
        wShorter = 0;
    else
        wShorter = context.measureText(text).width;

    //Subtract the width of the shorter string from the width of the entire string, giving the kerned width of the character, wChar = wAll - wShorter
    wChar = wAll - wShorter;

    //Increment X by wChar + spacing
    x += wChar + spacing;

    //wAll = wShorter
    wAll = wShorter;

    //Repeat from step 3
    } while (text != "");
}

演示/眼球测试代码:

element1 = document.getElementById("Test1");
textContext1 = element1.getContext('2d');

textContext1.font = "72px Verdana, sans-serif";
textContext1.textAlign = "left";
textContext1.textBaseline = "top";
textContext1.fillStyle = "#000000";

text = "Welcome to go WAVE";
this.fillTextWithSpacing(textContext1, text, 0, 0, 0);
textContext1.fillText(text, 0, 100);

理想情况下,我会在其上投掷多个随机字符串并逐个像素地进行比较。我也不确定Verdana的默认字距是多么好,虽然我明白它比Arial更好 - 其他字体的建议值得感激接受。

所以...到目前为止看起来不错。事实上它看起来很完美。 仍然希望有人能指出这个过程中的任何缺陷。

与此同时,我会把这个放在别人面前,看看他们是否在寻找解决方案。

答案 1 :(得分:0)

我的回答被删除了。 所以,我使用的是Chrome,这是我的完整代码。

second_image = $('#block_id').first();
canvas = document.getElementById('canvas');
canvas.style.letterSpacing = '2px';
ctx = canvas.getContext('2d');
canvas.crossOrigin = "Anonymous";
canvasDraw = function(text, font_size, font_style, fill_or_stroke){
    canvas.width = second_image.width();
    canvas.height = second_image.height();
    ctx.clearRect(0,0,canvas.width,canvas.height);
    ctx.drawImage(second_image.get(0), 0, 0, canvas.width, canvas.height);
    //refill text
    ctx.font = font_size +'px '+ font_style + ',Symbola';
    $test = ctx.font;
    ctx.textAlign = "center";
    if(fill_or_stroke){
        ctx.fillStyle = "#d2b76d";
        ctx.strokeStyle = "#9d8a5e";
        ctx.strokeText(text,canvas.width*$left,canvas.height*$top);
        ctx.fillText(text,canvas.width*$left,canvas.height*$top);
    }
    else{
        ctx.strokeStyle = "#888888";
        ctx.strokeText(text,canvas.width*$left,canvas.height*$top);
    }
};

您不需要使用此功能this.fillTextWithSpacing。我没有使用它,它就像一个魅力)