考虑这个循环遍历对象中的键值对:
Object.keys(categories).forEach(categoryKey => {
ctx.fillText(`${categoryKey}: ${categories[categoryKey]}`, 40, (30 * i) + 160);
ctx.fillStyle = '#fff';
i++;
});
所有文字都是白色的,但我想要的是:${categoryKey}
的文字为红色。
因为它在同一个字符串中运行,所以我不确定如何在不破坏的情况下执行此操作,因为我希望它在同一个ctx.fillText()
调用中。
答案 0 :(得分:2)
我需要多次为画布渲染设置文本格式(特别是对于数学示例),所以下面是我使用嵌套格式指南修改渲染文本的函数的修改。
来自我自己的库的修改后的副本,它根据嵌套的样式规则格式化文本。
simpleTextStyler
首先获取字体中每个字符的大小(使用simpleTextStyler.setFont()
设置当前上下文字体或不起作用),然后查看字符串中的每个字符输出具有相同样式的字符组,并一次渲染一个。
它使用一个堆栈来保存当前样式,如果找到一个新样式,将一个样式压入堆栈" {"并在每次结束时将样式弹出堆栈"}"
如果" \ n"它将添加一个新行。找到了。如果" \ t"请转到下一个制表位。并在"{"
和"{"
中使用variouse嵌套样式,其中"{"
后面的第一个字符表示函数。
文本样式可以嵌套,例如"text{Ssuper{ssub{Ssuper}}{Ssuper super}}"
是文本超级 Sub 超级 超级超级 < / p>
该演示呈现字符串"Testing\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}"
根据您的需要
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\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(){
var 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){
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){
var c = text[i];
var 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 : size,
colour : colour,
x:x,
y:y,
})
i += 1;
var 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 === "}"){
var 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;
})();
&#13;
canvas {
border : 2px solid black;
}
&#13;
<canvas id="canvas" width=512 height=200></canvas>
&#13;
答案 1 :(得分:0)
感谢@ Blindman67建议使用measureText()
。
这是我最终如何做到的(虽然这个上下文中的一些代码对你来说没有意义,因为它可能是更重要的一部分)。希望你能够看到关键部分:
let i = 0;
Object.keys(categories).forEach(categoryKey => {
const category = paramKeyToCategoryName(categoryKey);
const offsetTop = 190;
const offsetLeft = 40;
const spacing = 30;
if (category.length) {
// Category text.
ctx.fillStyle = '#f13f3d';
ctx.fillText(`${category.toUpperCase()}:`, offsetLeft, (spacing * i) + offsetTop);
// Measure category text length.
const measure = ctx.measureText(category.toUpperCase());
const measureWidth = measure.width + 12;
// Selected artist text.
ctx.fillStyle = '#fff';
ctx.fillText(`${categories[categoryKey].toUpperCase()}`, (offsetLeft + measureWidth), (spacing * i) + offsetTop);
i++;
}
});
希望这有助于某人。