diff --git a/_docs/api.md b/_docs/api.md index c961f2b3..ce19861a 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -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上绘制一段弧 diff --git a/_server/CodeMirror/defs.js b/_server/CodeMirror/defs.js index a5996228..403e2d4c 100644 --- a/_server/CodeMirror/defs.js +++ b/_server/CodeMirror/defs.js @@ -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": { diff --git a/libs/ui.js b/libs/ui.js index d26eef1b..134b1364 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -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=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) { diff --git a/runtime.d.ts b/runtime.d.ts index 88fdf497..6aab980a 100644 --- a/runtime.d.ts +++ b/runtime.d.ts @@ -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上绘制一个图标 */