【问题标题】:how to parse html markup in fillText method of canvas如何在画布的fillText方法中解析html标记
【发布时间】:2016-04-19 14:47:42
【问题描述】:

我有一个带有标签的画布元素。每个标签都是使用fillText 方法创建的。

我希望能够发送这样的文本:“CH2”,但我不认为这是最终结果。 <sub> 元素没有被正确解析。我该如何解决这个问题?

下面是一些示例代码:

 var ctx = document.getElementById('canvas').getContext('2d');
  ctx.font = "48px serif";
  ctx.fillText("Hello <sub>world</sub>", 10, 50);
&lt;canvas id="canvas" width=500 height=500 &gt;&lt;canvas&gt;

【问题讨论】:

标签: javascript jquery html canvas


【解决方案1】:

您可以使用 cmets Simon's solution 中提到的 @lipp 来解决此问题,并将已经下标的字符插入到字符串中。

您还可以创建一个简单的解析器来检测一些代码并以不同的方式呈现下一段(见下文)。

也有可能使用SVG to use HTML for drawing on canvas,但它有其缺点,例如异步行为、有限的内容(在安全机制阻止它被绘制到画布之前)以及在某些情况下缺乏跨浏览器支持。

解析器示例

这只是一个开始的例子。您可以选择任何代码以及添加新代码等。这只是一种方式,还有很多其他方式......

如果您有一个 HTML 源字符串,只需用代码替换这些标签,或者扩展解析器来处理这些标签。

var ctx = c.getContext("2d"),
    fontSize = 28,
    str = "This string has codes to enable |subscripted| text.";

setFontSize(fontSize);

// parse string
for(var i = 0, x = 10, tx = 0, isSub = false; i < str.length; i++) { // iterate over chars
  if (str[i] === "|") {                                              // special code?
    ctx.fillText(str.substring(tx, i), x, 50 + (isSub ? 7 : 0));     // draw current text seg
    x += ctx.measureText(str.substring(tx, i)).width;                // add width to x
    tx = ++i;                                                        // update start pointer
    isSub = !isSub;                                                  // toggle subscript mode
    setFontSize(isSub ? fontSize * 0.5 : fontSize);                  // set font size
  }
}

ctx.fillText(str.substring(tx, i), x, 50);                           // draw last text part

function setFontSize(sz) {ctx.font = sz + "px sans-serif"}
&lt;canvas id=c width=600&gt;&lt;/canvas&gt;

【讨论】:

    【解决方案2】:

    这是一个将 html 字符串转换为一系列 fillText 语句的函数。它处理多行字符串并让您指定对齐方式(左、右、中心)。

    <canvas id="textCanvas" width="700" height="150" style="border:1px solid #d3d3d3;">
    
    <script>
    
    function parse_html(ctx, s, x0, y0, align, font, fontsize, col) {
        // 2d canvas context, string, pos.x, pos.y, left/right/center, font, font height, color
        // Convert html code to a series of individual strings, each displayable by fillText().
        font = 'px '+font
        var lines = []
        var line = [0]
        var part = '' // the text element preceding a '<'
        var cmd = ''
        var bold = false
        var italic = false
        var sup = false
        var sub = false
        var x = 0, y = 0
        var dx, start
        var legal = ['b', 'strong', 'i', 'em', 'sup', 'sub']
    
        function add_part() {
            var style = ''
            var fs = fontsize
            if (bold) style += 'bold '
            if (italic) style += 'italic '
            if (sup || sub) {
                fs = 0.8*fontsize
                if (sup) y -= 0.3*fontsize // y increases downward in 2D canvas
                else y += 0.3*fontsize
            }
            ctx.font = style+fs+font
            dx = ctx.measureText(part).width
            line.push([x, y, ctx.font, part])
            part = ''
            x += dx
        }
    
        function end_line() {
            if (part !== '') add_part()
            line[0] = x
            lines.push(line)
            line = [0]
            x = y = 0
        }
    
        for (var i=0; i<s.length; i++) {
            var c = s[i]
            if (c == '\n') {
                end_line()
            } else if (c != '<') {
                part += c // a part of the text
            } else { // encountered '<'
                //if (part !== '') add_part()
                start = i+1
                i++
                cmd = s[i]
                var end = false
                if (cmd == '/') {
                    cmd = ''
                    end = true
                }
                var ok = true
                for (i=i+1; i<s.length; i++) {
                    if (s[i] == '<') { // This means that the intial '<' did not start a command
                        i = i-1 // back up
                        part += '<'+cmd
                        add_part()
                        ok = false // signal that we encountered '<'
                        break
                    }
                    if (s[i] == '>') break
                    cmd += s[i]
                }
                if (!ok) continue
                if (cmd == 'br' || cmd == 'br/') {
                    end_line()
                } else {
                    if (legal.indexOf(cmd) >= 0 && part !== '') add_part()
                    switch (cmd) {
                        case 'b':
                        case 'strong':
                            bold = !end
                            break
                        case 'i':
                        case 'em':
                            italic = !end
                            break
                        case 'sup':
                            sup = !end
                            if (end) y = 0
                            break
                        case 'sub':
                            sub = !end
                            if (end) y = 0
                            break
                        default:
                            part += '<'+cmd+'>'
                    }
                }
            }
        }
        if (part.length > 0) line.push([x, y, fontsize+font, part])
        ctx.font = fontsize+font
        line[0] = x + ctx.measureText(part).width
        lines.push(line)
    
        function rgb_to_html(rgb) { // convert RGB 0-1 to html 0-255
            var r = Math.floor(255 * rgb[0])
            var g = Math.floor(255 * rgb[1])
            var b = Math.floor(255 * rgb[2])
            return 'rgb(' + r + ',' + g + ',' + b + ')'
        }
    
        var width, L
        var nline = 0
        // Each line in lines starts with the total width of the line, followed by
        // elements of the form {x, y, font, text}, where x and y start at zero.
        var maxwidth = -1
        for (L in lines) {
            if (lines[L][0] > maxwidth) maxwidth = lines[L][0]
        }
        for (L in lines) {
            y0 += nline*1.2*fontsize
            nline++
            for (var p in lines[L]) {
                var k = lines[L][p]
                if (k[1] === undefined) {
                    width = k
                    continue
                }
                ctx.font = k[2]
                ctx.fillStyle = rgb_to_html(col)
                switch (align) {
                    case 'left':
                        x = x0 + k[0]
                        y = y0 + k[1]
                        break
                    case 'center':
                        x = x0 + k[0] - width/2
                        y = y0 + k[1]
                        break
                    case 'right':
                        x = x0 + k[0] - maxwidth
                        y = y0 + k[1]
                        break
                    default:
                        throw new Error(align+' is not a possible alignment option.')
                }
                ctx.fillText(k[3], x, y)
            }
        }
    }
    
    var c = document.getElementById("textCanvas")
    var ctx = c.getContext("2d")
    var s = 'The <b><i>quick</i> fox</b> <i>jumps.</i><br><i>M</i><sub>sys</sub> >= 10<sup>-3</sup> kg'
    parse_html(ctx, s, 350, 50, 'center', 'Verdana', 30, [0,0,1])
    </script>
    

    【讨论】:

    • 忘了说它处理(或)、(或)、
      (或
      。要显示“
    • 修改了代码,允许'\n'作为'
      '的同义词,显示'
    猜你喜欢
    • 2012-07-27
    • 2011-10-29
    • 2019-03-03
    • 2014-05-14
    • 2018-09-10
    • 2017-05-27
    • 2016-12-12
    • 2020-05-18
    • 2011-02-18
    相关资源
    最近更新 更多