如何使用HTML5 Canvas在同一行中给不同的单词上色? [英] How can I colour different words in the same line with HTML5 Canvas?

查看:52
本文介绍了如何使用HTML5 Canvas在同一行中给不同的单词上色?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下循环,该循环遍历对象中的键值对:

Consider this loop that runs through key value pairs in an object:

Object.keys(categories).forEach(categoryKey => {
  ctx.fillText(`${categoryKey}: ${categories[categoryKey]}`, 40, (30 * i) + 160);
  ctx.fillStyle = '#fff';
  i++;
});

所有文本均为白色,但我想要的是 $ {categoryKey} 处的文本为红色.

All text is white, but what I would like is for the text at: ${categoryKey} to be red.

因为它在同一字符串中运行,所以我不确定如何在不中断的情况下执行此操作,因为我希望它位于同一 ctx.fillText()调用中./p>

Because this runs in the same string, I'm unsure how to do this without breaking it out, because I'd like it to be within the same ctx.fillText() call.

推荐答案

我需要多次格式化画布渲染的文本格式(尤其是数学示例),因此下面是对我用来修改渲染文本的功能的修改使用嵌套的格式指南.

There are many times I need to format text for canvas rendering (particularly for math examples) so below is a modification of the function I use to modify the rendered text using a nested formatting guide.

我自己的库中的修改后的副本,可根据嵌套样式规则设置文本格式.

A modified copy from my own library that formats text according to nested style rules.

simpleTextStyler 的工作方式是先获取字体中每个字符的大小(使用 simpleTextStyler.setFont()设置当前上下文字体,否则它将不起作用)然后查看字符串中的每个字符,以分离出具有相同样式的字符组,并一次渲染一个字符.

The simpleTextStyler works by first getting the size of each character in the font (use simpleTextStyler.setFont() to set the current context font or it will not work) and then looking at each character in the string separating out groups of characters with the same styles and rendering them one at a time.

如果发现新样式"{",它将使用堆栈来保存当前样式,从而将样式推入堆栈.并在每个结束}"

It uses a stack to hold the current style pushing a style onto the stack if a new one is found "{" and popping the style off the stack at each closing "}"

如果"\ n"被发现.如果出现"\ t",则移至下一个制表位.并在" {{" }" 内使用各种嵌套样式,其中"{" 之后的第一个字符表示功能.

It will add a new line if "\n" is found. Move to the next tab stop if "\t" and use various nested style inside "{" and "}" where the first character after the "{" denotes the function.

  • s 子脚本
  • S 超级脚本
  • + 较大的文字
  • -较小的文本
  • #颜色后必须是6个字符的十六进制颜色,例如红色{#FF0000此文本为红色}
  • s sub script
  • S super script
  • + bigger text
  • - smaller text
  • # colour must be followed by 6 char hex colour eg red {#FF0000This text is red}

注意::必须仅使用7个字符的CSS十六进制颜色.例如将颜色更改为{#FF0000Red}"

NOTE: Must use only 7 char CSS hex colour. eg "Change colour to {#FF0000Red}"

文本样式可以嵌套,例如"text {Ssuper {ssub {Ssuper}} {Ssuper super}}" 是text Super Sub super 超级超级

Text styles can be nested eg "text{Ssuper{ssub{Ssuper}}{Ssuper super}}" is textSuperSubsuperSuper super

该演示呈现字符串" Testing \ nnewline \ n \ tTab \ n \ t \ tTab \ n \ t \ t \ tTab \ nSub {sScript} Super {SScript} Size {+ Big {+ Bigger}}正常{-Small {-Smaller}} \ n \ n \ n {#FF0000Red} {#00FF00Green} {#0000FFBlue}"

满足您的需求

simpleTextStyler.setFont(); // only needs to be set for the font family
                            // sizing text is in the last argument of the next call

simpleTextStyler.drawText(ctx,
    `{#FF0000${categoryKey}}: ${categories[categoryKey]}`, 40, (30 * i) + 160,fontSize);

var ctx = canvas.getContext("2d");
ctx.font = "18px arial";
setTimeout(drawExamples,0);
function drawExamples(){
  simpleTextStyler.setFont(); // set the current font
  simpleTextStyler.drawText(ctx,
  "Testing simple Canvas2D text styler...\nnewline\n\tTab\n\t\tTab\n\t\t\tTab\nSub{sScript} Super{SScript} Size {+Big {+Bigger}} Normal {-Small {-Smaller}}\nAnd now colours \n{#FF0000Red} {#00FF00Green} {#0000FFBlue}",
      10,20,18)
}
      

const simpleTextStyler = (function(){
    const simpleTextStyler = {
        sizes: [],
        baseSize: undefined,
        font: undefined,
        controlChars: "{}\n\t",
        spaceSize: 0,
        tabSize: 8, // in spaceSize units
        tabs: (function() {var t = []; for(var i=0; i < 100; i += 8){t.push(i);}; return t;})(),
        getNextTab: function(x) {
            var i = 0;
            while (i < this.tabs.length) {
                if (x < this.tabs[i] * this.tabSize * this.spaceSize) {
                    return this.tabs[i] * this.tabSize * this.spaceSize;
                }
                i++;
            }
            return this.tabs[i-1] * this.tabSize * this.spaceSize;
        },
        getFontSize: function(font){
            var numFind = /[0-9]+/;
            var number = numFind.exec(font)[0];
            if (isNaN(number)) {
                throw Error("SimpleTextStyler Cant find font size");
            }
            return Number(number);
        },
        setFont: function(font = ctx.font) {
            this.font = ctx.font = font;
            this.baseSize = this.getFontSize(font);
            for (var i = 32; i < 256; i ++) {
                this.sizes[i - 32] = ctx.measureText(String.fromCharCode(i), 0, 0).width/this.baseSize;
            }
            this.spaceSize = this.sizes[0];
        },
        drawText: function(context, text, x, y, size) {
            var i, len, subText;
            var w, scale;
            var xx, yy, ctx;
            var state = [];
            if(text === undefined){ return }
            xx = x;
            yy = y;
            if (!context.setTransform) { // simple test if this is a 2D context
                if (context.ctx) { ctx = context.ctx } // may be a image with attached ctx?
                else{ return }
            } else { ctx = context }

            function renderText(text) {
                ctx.save();
                ctx.fillStyle = colour;
                ctx.translate(x, y)
                ctx.scale(scale, scale)
                ctx.fillText(text, 0, 0);
                ctx.restore();
            }
            var colour = ctx.fillStyle;
            ctx.font = this.font;
            len = text.length;
            subText = "";
            w = 0;
            i = 0;
            scale = size / this.baseSize;
            while (i < len) {
                const c = text[i];
                const cc = text.charCodeAt(i);
                if (cc < 256) { // only ascii
                    if (this.controlChars.indexOf(c) > -1) {
                        if (subText !== "") {
                            scale = size / this.baseSize;
                            renderText(subText);
                            x += w;
                            w = 0;
                            subText = "";                        
                        }
                        if (c === "\n") {  // return move to new line
                            x = xx;
                            y += size;
                        } else if (c === "\t") { // tab move to next tab
                            x = this.getNextTab(x - xx) + xx;
                        } else if (c === "{") {   // Text format delimiter                       
                            state.push({size, colour, x, y})
                            i += 1;
                            const t = text[i];
                            if (t === "+") {  // Increase size
                                size *= 1/(3/4);
                            } else if (t === "-") {  // decrease size
                                size *= 3/4;
                            } else if (t === "s") { // sub script
                                y += size * (1/3);
                                size  *= (2/3);
                            } else if (t === "S") { // super script
                                y -= size * (1/3);
                                size  *= (2/3);
                            } else if (t === "#") {
                                colour = text.substr(i,7);
                                i+= 6;
                            }
                        } else if (c  === "}"){
                            const s = state.pop();
                            y = s.y;
                            size = s.size;
                            colour = s.colour;
                            scale = size / this.baseSize;
                        }
                    } else {
                        subText += c;
                        w += this.sizes[cc-32] * size;
                    }
                 }
                 i += 1;
            }
            if (subText !== "") { renderText(subText) }
        },
    }
    return simpleTextStyler;
})();

canvas {
    border : 2px solid black;
}

<canvas id="canvas" width=512 height=160></canvas>

这篇关于如何使用HTML5 Canvas在同一行中给不同的单词上色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆