简单的画布标记
您可以定义自己的标记格式,然后根据标记规则呈现文本。
例如一个字符串"This is normal, <b>this is bold</b> and back to normal."
标签<b> 和</b> 定义文本粗体部分的开始和结束。
然后根据标签的位置迭代将字符串分成几部分。我将手动搜索并使用堆栈来跟踪嵌套样式,而不是使用 RegExp。
要定义样式,您只需创建一个通过单个字符映射样式的对象
const styles = {
default: { font: "16px arial", fillStyle: "black", },
b: { font: "16px arial black", fillStyle: "black", },
w: { fillStyle: "white" },
};
样式使用Object.assign(ctx, styles["b"])设置
示例
函数canvasMarkupText(ctx, str, x, y, styles) 使用简单的标记和方案styles 呈现文本。
-
它创建一个堆栈,其中包含一个包含字符串位置和规则名称的内容对象,
-
渲染函数,将渲染内容对象中的细节,
-
一个简单的迭代器(while 循环),用于控制何时从堆栈中添加和删除内容,以及何时呈现内容。
-
在退出之前,它会检查堆栈是否有内容并呈现剩余的文本。
-
函数返回渲染文本的宽度。
注意没有验证标记。
注意样式级联向下但不向上。
注意此示例仅适用于单字符标签。
注意 示例中使用"<" 作为标记分隔符意味着函数无法呈现该字符。为此,您需要添加某种形式的转义序列。例如 double "<<" 可以代表那个字符。
这只是一个示例,并不意味着作为解决方案。将其用作构建您自己的指南。
ctx = canvas.getContext("2d");
const styles = {
default: {font: "14px arial", fillStyle: "black",},
b: {font: "14px arial black", fillStyle: "black",},
w: {fillStyle: "white"},
};
canvasMarkupText(ctx, "Testing <b>testing BOLD <w>bold white</w></b> and testing with default <w>and white</w>", 10, 14, styles)
function canvasMarkupText(ctx, str, x, y, styles) {
const content = (start, end, rule) => ({start, end, rule});
const render = content => {
Object.assign(ctx, styles[content.rule] ? styles[content.rule] : {});
const s = str.slice(content.start, content.end)
ctx.fillText(s, x, y);
x += ctx.measureText(s).width;
};
const stack = [], xx = x;
var pos = 0, current = content(pos, pos, "default");
stack.push(current);
while (pos < str.length) {
const c = str[pos++];
if (c === "<") {
if (str[pos] === "/") {
render(stack.pop());
current = stack[stack.length - 1];
current.start = current.end = (pos += 3);
} else {
render(current);
pos += 2;
stack.push(current = content(pos, pos, str[pos - 2]));
}
} else { current.end = pos }
}
stack.length && render(current);
return x - xx;
}
canvas {background: #59D}
<canvas id="canvas" width="500" height="20"></canvas>