fillText支持\r; drawTextContent标点禁则; 道具描述多行文本

This commit is contained in:
ckcz123 2020-10-28 12:13:17 +08:00
parent 90d4488ffb
commit 618759f28a
4 changed files with 71 additions and 77 deletions

View File

@ -1930,7 +1930,7 @@ baseline: 可为alphabetic, top, hanging, middle, ideographic, bottom
参考资料https://www.w3school.com.cn/tags/canvas_textbaseline.asp
splitLines: fn(name: string|CanvasRenderingContext2D, text: string, maxWidth?: number, font?: string)
字符串自动换行的分割;具有标点禁则功能
字符串自动换行的分割
strokeArc: fn(name: string|CanvasRenderingContext2D, x: number, y: number, r: number, start: number, end: number, style?: string, lineWidth?: number)
在某个canvas上绘制一段弧

View File

@ -3434,7 +3434,7 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [
"!type": "fn(name: string|CanvasRenderingContext2D)"
},
"splitLines": {
"!doc": "字符串自动换行的分割;具有标点禁则功能",
"!doc": "字符串自动换行的分割",
"!type": "fn(name: string|CanvasRenderingContext2D, text: string, maxWidth?: number, font?: string)"
},
"setAlpha": {

View File

@ -82,13 +82,19 @@ ui.prototype.fillText = function (name, text, x, y, style, font, maxWidth) {
if (font) core.setFont(name, font);
var ctx = this.getContextByName(name);
if (!ctx) return;
var currentStyle = ctx.fillStyle;
text = (text + "").replace(/\\r/g, '\r');
var originText = text.replace(/\r(\[.*\])?/g, "");
var index = text.indexOf('\r');
if (maxWidth != null) {
this.setFontForMaxWidth(ctx, index >= 0 ? text.replace(/\r(\[.*\])?/g, "") : text, maxWidth);
this.setFontForMaxWidth(ctx, index >= 0 ? originText : text, maxWidth);
}
if (index >= 0) {
var currentStyle = ctx.fillStyle;
var textWidth = core.calWidth(ctx, originText);
var textAlign = ctx.textAlign;
if (textAlign == 'center') x -= textWidth / 2;
else if (textAlign == 'right') x -= textWidth;
ctx.textAlign = 'left';
text = text.replace(/\r(?!\[.*\])/g, "\r[" + currentStyle + "]");
var colorArray = text.match(/(?<=\r\[).*(?=\])/g);
var textArray = text.split(/\r\[.*\]/);
@ -96,9 +102,10 @@ ui.prototype.fillText = function (name, text, x, y, style, font, maxWidth) {
for (var i = 0; i < textArray.length; i++) {
var subtext = textArray[i];
if (colorArray[i-1]) ctx.fillStyle = colorArray[i-1];
width += core.calWidth(ctx, subtext, x, y);
ctx.fillText(subtext, x + width, y);
width += core.calWidth(ctx, subtext, x, y);
}
ctx.textAlign = textAlign;
ctx.fillStyle = currentStyle;
} else {
ctx.fillText(text, x, y);
@ -508,56 +515,23 @@ ui.prototype.splitLines = function (name, text, maxWidth, font) {
if (!ctx) return [text];
if (font) core.setFont(name, font);
// 不能在行首的标点
var forbidStart = ")】》>﹞>)]»›〕〉}]」}〗』" + ",。?!:;·…,.?!:;、……~&@#";
// 不能在行尾的标点
var forbidEnd = "(【《<﹝<([«‹〔〈{[「{〖『";
var contents = [];
var last = 0;
var forceChangeLine = false; // 是否强制换行避免多个连续forbidStart存在
for (var i = 0; i < text.length; i++) {
if (text.charAt(i) == '\n') {
contents.push(text.substring(last, i));
last = i + 1;
forceChangeLine = false;
}
else if (text.charAt(i) == '\\' && text.charAt(i + 1) == 'n') {
contents.push(text.substring(last, i));
last = i + 2;
forceChangeLine = false;
}
else {
var curr = text.charAt(i);
var toAdd = text.substring(last, i + 1);
var width = core.calWidth(name, toAdd);
if (maxWidth && width > maxWidth) {
// --- 当前应当换行然而还是检查一下是否是forbidStart
if (!forceChangeLine && forbidStart.indexOf(curr) >= 0) {
forceChangeLine = true;
continue;
}
contents.push(text.substring(last, i));
last = i;
forceChangeLine = false;
} else {
// --- 当前不应该换行;但是提前检查一下是否是行尾标点
var curr = text.charAt(i);
if (forbidEnd.indexOf(curr) >= 0 && i < text.length -1) {
// 检查是否是行尾
var nextcurr = text.charAt(i+1);
// 确认不是手动换行
if (nextcurr != '\n' && !(nextcurr == '\\' && text.charAt(i+2) == 'n')) {
var toAdd = text.substring(last, i+2);
var width = core.calWidth(name, toAdd);
if (maxWidth && width > maxWidth) {
// 下一项会换行,因此在此处换行
contents.push(text.substring(last, i));
last = i;
forceChangeLine = false;
}
}
}
}
}
}
@ -1165,6 +1139,11 @@ ui.prototype._drawTextContent_next = function (tempCtx, content, config) {
// 绘制下一个字符
ui.prototype._drawTextContent_drawChar = function (tempCtx, content, config, ch) {
// 标点禁则:不能在行首的标点
var forbidStart = ")】》>﹞>)]»›〕〉}]」}〗』" + ",。?!:;·…,.?!:;、……~&@#";
// 标点禁则:不能在行尾的标点
var forbidEnd = "(【《<﹝<([«‹〔〈{[「{〖『";
// \n, \\n
if (ch == '\n' || (ch=='\\' && content.charAt(config.index)=='n')) {
this._drawTextContent_newLine(tempCtx, config);
@ -1191,12 +1170,34 @@ ui.prototype._drawTextContent_drawChar = function (tempCtx, content, config, ch)
if (c == 'z') return this._drawTextContent_emptyChar(tempCtx, content, config);
}
// 检查是不是自动换行
var charwidth = core.calWidth(tempCtx, ch) + config.interval;
if (config.maxWidth != null && config.offsetX + charwidth > config.maxWidth) {
this._drawTextContent_newLine(tempCtx, config);
config.index--;
return this._drawTextContent_next(tempCtx, content, config);
if (config.maxWidth != null) {
var charwidth = core.calWidth(tempCtx, ch) + config.interval;
if (config.offsetX + charwidth > config.maxWidth) {
// --- 当前应当换行然而还是检查一下是否是forbidStart
if (!config.forceChangeLine && forbidStart.indexOf(ch) >= 0) {
config.forceChangeLine = true;
} else {
this._drawTextContent_newLine(tempCtx, config);
config.index--;
return this._drawTextContent_next(tempCtx, content, config);
}
} else if (forbidEnd.indexOf(ch) >= 0 && config.index < content.length) {
// --- 当前不应该换行;但是提前检查一下是否是行尾标点
var nextch = content.charAt(config.index);
// 确认不是手动换行
if (nextch != '\n' && !(nextch == '\\' && content.charAt(config.index+1) == 'n')) {
// 检查是否会换行
var nextchwidth = core.calWidth(tempCtx, nextch) + config.interval;
if (config.offsetX + charwidth + nextchwidth > config.maxWidth) {
// 下一项会换行,因此在此处换行
this._drawTextContent_newLine(tempCtx, config);
config.index--;
return this._drawTextContent_next(tempCtx, content, config);
}
}
}
}
// 输出
var left = config.offsetX, top = config.offsetY + config.topMargin;
core.fillText(tempCtx, ch, left, top);
@ -1230,6 +1231,7 @@ ui.prototype._drawTextContent_newLine = function (tempCtx, config) {
config.offsetY += config.lineMaxHeight;
config.lineMaxHeight = config.currfont + config.lineMargin;
config.line++;
config.forceChangeLine = false;
}
ui.prototype._drawTextContent_changeColor = function (tempCtx, content, config) {
@ -2535,26 +2537,23 @@ ui.prototype._drawToolbox_drawDescription = function (info, max_height) {
core.setTextAlign('ui', 'left');
if (!info.selectId) return;
var item=core.material.items[info.selectId];
core.fillText('ui', item.name, 10, 32, core.status.globalAttribute.selectColor, this._buildFont(20, true))
var text = item.text||"该道具暂无描述。";
try {
// 检查能否eval
text = core.replaceText(text);
} catch (e) {}
var name = item.name || "未知道具";
try { name = core.replateText(name); } catch (e) {}
core.fillText('ui', name, 10, 32, core.status.globalAttribute.selectColor, this._buildFont(20, true))
var text = item.text || "该道具暂无描述。";
try { text = core.replaceText(text); } catch (e) {}
for (var font_size = 17; font_size >= 14; font_size -= 3) {
var lines = core.splitLines('ui', text, this.PIXEL - 15, this._buildFont(font_size, false));
var line_height = parseInt(font_size * 1.4), curr = 37 + line_height;
if (curr + lines.length * line_height < max_height) break;
var height = null;
for (var fontSize = 17; fontSize >= 9; fontSize -= 2) {
var config = { left: 10, top: 46, fontSize: fontSize, maxWidth: this.PIXEL - 15, bold: false, color: "white" };
height = 42 + core.getTextContentHeight(text, config);
if (height < max_height || fontSize == 9) {
core.drawTextContent('ui', text, config);
break;
}
}
core.setFillStyle('ui', '#FFFFFF');
for (var i=0;i<lines.length;++i) {
core.fillText('ui', lines[i], 10, curr);
curr += line_height;
if (curr>=max_height) break;
}
if (curr < max_height) {
core.fillText('ui', '<继续点击该道具即可进行使用>', 10, curr, '#CCCCCC', this._buildFont(14, false));
if (height < max_height - 33) {
core.fillText('ui', '<继续点击该道具即可进行使用>', 10, max_height - 15, '#CCCCCC', this._buildFont(14, false));
}
}
@ -2647,24 +2646,19 @@ ui.prototype._drawEquipbox_description = function (info, max_height) {
core.fillText('ui', equip.name + "" + equipString + "", 10, 32, core.status.globalAttribute.selectColor, this._buildFont(20, true))
// --- 描述
var text = equip.text || "该装备暂无描述。";
try {
text = core.replaceText(text);
} catch (e) {}
try { text = core.replaceText(text); } catch (e) {}
for (var font_size = 17; font_size >= 11; font_size -= 3) {
var lines = core.splitLines('ui', text, this.PIXEL - 15, this._buildFont(font_size, false));
var line_height = parseInt(font_size * 1.4), curr = 37 + line_height;
if (curr + lines.length * line_height < max_height) break;
}
core.setFillStyle('ui', '#FFFFFF');
for (var i = 0; i < lines.length; ++i) {
core.fillText('ui', lines[i], 10, curr);
curr += line_height;
if (curr >= max_height) break;
var height = null;
for (var fontSize = 17; fontSize >= 9; fontSize -= 2) {
var config = { left: 10, top: 46, fontSize: fontSize, maxWidth: this.PIXEL - 15, bold: false, color: "white" };
height = 42 + core.getTextContentHeight(text, config);
if (height < max_height - 30 || fontSize == 9) {
core.drawTextContent('ui', text, config);
break;
}
}
// --- 变化值
if (curr >= max_height) return;
this._drawEquipbox_drawStatusChanged(info, curr, equip, equipType);
this._drawEquipbox_drawStatusChanged(info, max_height - 15, equip, equipType);
}
ui.prototype._drawEquipbox_getStatusChanged = function (info, equip, equipType, y) {

2
runtime.d.ts vendored
View File

@ -2123,7 +2123,7 @@ declare class ui {
/** 设置某个canvas的baseline */
setTextBaseline(name: string | CanvasRenderingContext2D, baseline: any): void
/** 字符串自动换行的分割;具有标点禁则功能 */
/** 字符串自动换行的分割 */
splitLines(name: string | CanvasRenderingContext2D, text: string, maxWidth?: number, font?: string): void
/** 在某个canvas上绘制一个图标 */