在HTML画布中添加字母间距

在HTML画布中添加字母间距,html,canvas,text,fonts,Html,Canvas,Text,Fonts,我已经阅读了很多关于如何在画布上设置字母间距的StackOverflow答案和其他页面。其中一个更有用的是 正如另一个问题所说,“我有一个画布元素,我正在绘制文本。我想设置类似于CSS字母间距属性的字母间距。我的意思是在绘制字符串时增加字母之间的像素量。请注意,字母间距有时被错误地称为紧排 我注意到,一般的方法似乎是逐字母输出字符串,使用measureText(字母)获得字母的宽度,然后添加额外的间距。问题是它没有考虑字母紧排对等。请参阅上面的链接以获取此示例和相关注释 在我看来,对于“间距”的

我已经阅读了很多关于如何在画布上设置字母间距的StackOverflow答案和其他页面。其中一个更有用的是

正如另一个问题所说,“我有一个画布元素,我正在绘制文本。我想设置类似于CSS字母间距属性的字母间距。我的意思是在绘制字符串时增加字母之间的像素量。请注意,字母间距有时被错误地称为紧排

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

在我看来,对于“间距”的行距,这样做的方法是:

  • 从位置(X,Y)开始
  • 使用measureText()测量整个字符串的宽度
  • 从字符串中删除第一个字符
  • 使用fillText()在位置(X,Y)处打印第一个字符
  • Measure wShorter,即使用measureText()生成的较短字符串的宽度
  • 从整个字符串的宽度中减去较短字符串的宽度,给出字符的紧排宽度,wChar=wAll-wShorter
  • 通过wChar+间距增加X
  • 墙=wShorter
  • 重复步骤3
  • 这不考虑字距调整吗?我错过什么了吗?measureText()是否添加了根据最外层的字符或其他内容而变化的填充负载,如果添加了,fillText()是否会使用相同的系统来输出字符,从而消除该问题?上面的链接中有人提到了“像素对齐字体暗示”,但我不认为这在这里适用。是否有人能给出一般性或具体的建议,这是否可行,或者是否存在问题


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

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

    以下是HTML:

    <canvas id="Test1" width="800px" height="200px"><p>Your browser does not support canvas.</p></canvas>
    
    演示/眼球测试代码:

    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好——关于其他字体的建议值得尝试

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

    同时,我会把这个放在这里,让其他人看看他们是否在寻找解决方案。

    我的答案被删除了。 所以,我使用的是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.filltextwithspace
    。我没有使用,它就像一个符咒一样工作)

    我已经做了一些初步测试,它看起来很有效。。。但我还没有做过详尽的测试。你的问题不清楚你想要实现什么?如果你想让字母在[x,y]上居中,你可以这样做:
    context.textAlign='center'
    在x上水平居中,
    context.textb基线='middle'
    在y上垂直居中,
    context.fillText('a',x,y)
    在[x,y]上画一个居中的字母。请分享一些代码…@markE,我希望现在更清楚。抱歉我无意中将你的评论标记为有用,因为它与我所追求的内容无关,但你关于它的不清楚的评论至少让我澄清了它,所以谢谢。@bvl-我给出伪代码的原因是因为我没有代码,我希望除非它有用,否则不要写它。尽管如此,在等待答案的过程中,我继续写下了代码,你可以在下面的答案中看到。应该注意的是,虽然这并不是对我问题的回答,但它回答了很多关于如何做到这一点的问题,它就是为了这个目的而存在的。如果有人回答了我的问题,解释为什么它不是一个好的系统,那么这个答案显然会取代我的答案。这个解决方案的一个缺点是它的复杂性为O(n^2),因为measureText在字符串中的其余字符上循环,并且每个字符只调用一次。似乎很容易将其转换为只考虑当前字符和下一个字符,从而将其转换为O(n)算法。除此之外,非常好的解决方案@Joaquincuencabela-我同意,出于你给出的理由,这可能是过分的。我就这样离开了,因为我不确定是否根据整个字符串(而不是成对的字符)添加了某种“魔法酱”,但我怀疑您的添加结果会完全相同,如果没有,一行至少三个字符或整个单词可能就够了。欢迎任何人测试-请发回。两点-1。此解决方案适用于大多数拉丁语脚本(英语、法语等),但对于来自非拉丁语脚本(如婆罗米语、阿拉伯语、希伯来语等)的字符,会给出错误的结果。2。此解决方案可以稍加修改,以使用表情符号给出正确的结果。您好@NirmitDalal,您能详细介绍一下您对表情符号的修改建议吗?
    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);
        }
    };