【问题标题】:Drawing text with an outer stroke with HTML5's canvas使用 HTML5 的画布绘制带有外部笔划的文本
【发布时间】:2012-11-17 14:31:14
【问题描述】:

我目前正在使用 HTML5 的画布使用 fillText 方法来呈现多个字符串。这很好用,但我也想给每个字符串一个 1px 黑色外笔划。不幸的是,strokeText 函数似乎应用了内部笔划。为了解决这个问题,我编写了一个 drawStrokedText 函数来实现我想要的效果。不幸的是,它太慢了(原因很明显)。

是否有一种快速、跨浏览器的方法可以使用原生画布功能实现 1 像素的外部笔划?

drawStrokedText = function(context, text, x, y)
{
    context.fillStyle = "rgb(0,0,0)";
    context.fillText(text, x-1, y-1);
    context.fillText(text, x+1, y-1);
    context.fillText(text, x-1, y);
    context.fillText(text, x+1, y);
    context.fillText(text, x-1, y+1);
    context.fillText(text, x+1, y+1);

    context.fillStyle = "rgb(255,255,255)";
    context.fillText(text, x, y);
};

这是一个工作效果的例子:

【问题讨论】:

  • 如何使用strokeText 渲染文本,但使用稍大的字体来解决内部笔划?此外,在 drawStrokedText 方法中,您可能会跳过水平/垂直移位。 (无论如何,您似乎已经错过了垂直领域)

标签: javascript html canvas html5-canvas


【解决方案1】:

中风怎么了?由于一半的笔画将在形状之外,因此您始终可以先绘制笔画,线宽为您想要的两倍。所以如果你想要一个 4px 的外笔画,你可以这样做:

function drawStroked(text, x, y) {
    ctx.font = '80px Sans-serif';
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 8;
    ctx.strokeText(text, x, y);
    ctx.fillStyle = 'white';
    ctx.fillText(text, x, y);
}


drawStroked("37°", 50, 150);

这使得:

在这里直播:http://jsfiddle.net/vNWn6/


如果碰巧在较小的文本渲染比例下看起来不那么准确,您总是可以将其画大但按比例缩小(在上述情况下,您会这样做 ctx.scale(0.25, 0.25)

【讨论】:

  • 我在下面的链接中添加了一些额外的代码来稍微润色一下。尽管如此,为这个聪明的解决方案向 Simon +1!
【解决方案2】:

Simon 的答案是一个很好的解决方案,但在某些情况下可能会出现斜接故障,尤其是大写“M”、“V”和“W”:

drawStroked("MVW", 50, 150);

http://jsfiddle.net/hwG42/1/

在这种情况下,最好利用:

ctx.miterLimit=2;

http://jsfiddle.net/hwG42/3/

祝你好运!

【讨论】:

  • 这也可以通过ctx.lineJoin = 'round'; 实现。可能值得同时使用miterLimit 和lineJoin,以确保在所有浏览器中看起来都不错。
【解决方案3】:

为了获得平滑的阴影,你可以试试这个

ctx.beginPath();
ctx.fillStyle = 'white';
ctx.font = "bold 9pt Tahoma";
ctx.shadowBlur = 3;
ctx.textAlign = "center";
ctx.shadowColor = "#000000";
ctx.shadowOffs = 0;                 
ctx.fillText('www.ifnotpics.com', 100, 50);        
ctx.closePath();

【讨论】:

    【解决方案4】:

    上面的答案很棒,使用其中一些解决方案*和我自己的一些想法,我在下面的小提琴中做了一个快速参考和一些创造性的替代方案。

    *在小提琴代码中到期的所有学分

    drawStrokedText   ( text, x, y );
    drawShadowedText  ( text, x, y, shadowBlur);
    drawGlowingText   ( text, x, y, glowColorHex, glowDistance);
    drawBlurredText   ( text, x, y, blurAmount);
    drawReflectedText ( text, x, y, reflectionScale, reflectionOpacity);
    

    https://jsfiddle.net/vtmnyea8/

    // Author: Aaron Edmistone
    // Text effects using HTML5 Canvas with 2D Context.
    // https://stackoverflow.com/questions/7814398/a-glow-effect-on-html5-canvas
    
    var canvas = document.getElementById('myCanvas');
    var ctx = canvas.getContext('2d');
    
    // prepare the presentation of the canvas
    ctx.fillStyle = 'black';
    ctx.fillRect(0,0,250,450);
    ctx.fillStyle = 'gray';
    ctx.fillRect(250,0,250,450);
    ctx.fillStyle = 'white';
    ctx.fillRect(500,0,250,450);
    ctx.fillStyle = '#0066CC';
    ctx.fillRect(750,0,250,450);
    
    // prepare the font and fill
    ctx.font = "80px Sans-serif";
    ctx.fillStyle = "white";
    
    function drawStrokedText(text, x, y)
    {
            // using the solutions from @Simon Sarris and @Jackalope from
        // https://stackoverflow.com/questions/7814398/a-glow-effect-on-html5-canvas
            ctx.save();
        ctx.strokeStyle = 'black';
        ctx.lineWidth = 8;
        ctx.lineJoin="round";
          ctx.miterLimit=2;
        ctx.strokeText(text, x, y);
        ctx.fillText(text, x, y);
        ctx.restore();
    }
    
    function drawShadowedText(text, x, y, shadowBlur = 3)
    {
            ctx.save();
        ctx.shadowBlur = shadowBlur;
        ctx.shadowColor = "#000000";
        ctx.shadowOffsetX = 4;
        ctx.shadowOffsetY = 4;
        ctx.fillText(text, x, y);
        ctx.restore();
    }
    
    function drawGlowingText(text, x, y, glowColorHexString, glowDistance = 10)
    {
            ctx.save();
        ctx.shadowBlur = glowDistance;
        ctx.shadowColor = glowColorHexString;
        ctx.strokeText(text, x, y);
        
        for(let i = 0; i < 3; i++)
            ctx.fillText(text, x, y); //seems to be washed out without 3 fills
          
        ctx.restore();
    }
    
    function drawBlurredText(text, x, y, blur = 5)
    {
        //using technique from https://www.html5rocks.com/en/tutorials/canvas/texteffects/
        ctx.save();
      let width = ctx.measureText(text).width + blur * 2;
      ctx.shadowColor = ctx.fillStyle;
      ctx.shadowOffsetX = width + x + ctx.canvas.width;
      ctx.shadowOffsetY = 0;
      ctx.shadowBlur = blur;
      ctx.fillText(text, -width + -ctx.canvas.width, y);
      ctx.restore();
    }
    
    function drawReflectedText(text, x, y, reflectionScale = 0.2, reflectionAlpha = 0.10)
    {
        ctx.save();
      ctx.fillText(text, x, y);
        ctx.scale(1, -reflectionScale);
      ctx.globalAlpha = reflectionAlpha;
      ctx.shadowColor = ctx.fillStyle;
      ctx.shadowBlur = 15;
        ctx.fillText(text, x, -(y * (1 / reflectionScale)));
      ctx.restore();
    }
    
    for(let i = 0; i < 4; i++)
    {
        drawStrokedText     ("MVW", 20 + i * 250, 80 * 1);
        drawShadowedText    ("MVW", 20 + i * 250, 80 * 2, 3);
      drawGlowingText       ("MVW", 20 + i * 250, 80 * 3, "#FF0000", 10);
      drawBlurredText       ("MVW", 20 + i * 250, 80 * 4, 5);
      drawReflectedText ("MVW", 20 + i * 250, 80 * 5, 0.5, 0.5);
    }
    &lt;canvas id="myCanvas" width="1000" height="500"&gt;&lt;/canvas&gt;

    小提琴的输出:

    它支持什么:

    • 大纲文本
    • 阴影文字
    • 发光的文字
    • 文字模糊
    • 反射文本

    一些性能指标:

    考虑在游戏中或在高帧率下使用它? 使用上述方法查看这个 jsperf

    https://jsperf.com/various-text-effects-html5-2d-context

    【讨论】:

    • 只是关于性能部分的一点:基准测试将使用 CPU 轮次来计算通过的脚本的性能,大多数 Canvas2D 实现现在实际上使用硬件加速,GPU 完成了大部分工作。因此,您只测量脚本的一小部分,较慢的部分(模糊、阴影文本渲染)稍后将由 GPU 完成。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-11
    • 2013-01-10
    • 1970-01-01
    • 1970-01-01
    • 2011-10-10
    • 2015-04-25
    相关资源
    最近更新 更多