UNPKG

@visactor/vrender-core

Version:
126 lines (120 loc) 9.28 kB
import { calculateLineHeight } from "../../common/utils"; import { measureTextCanvas, getStrByWithCanvas } from "./utils"; function getFixedLRTB(left, right, top, bottom) { const leftInt = Math.round(left), topInt = Math.round(top), rightInt = Math.round(right), bottomInt = Math.round(bottom); return { left: left > leftInt ? leftInt : leftInt - .5, top: top > topInt ? topInt : topInt - .5, right: rightInt > right ? rightInt : rightInt + .5, bottom: bottomInt > bottom ? bottomInt : bottomInt + .5 }; } export default class Paragraph { constructor(text, newLine, character, ascentDescentMode) { this.fontSize = character.fontSize || 16, this.textBaseline = character.textBaseline || "alphabetic", this.ascentDescentMode = ascentDescentMode; const lineHeight = calculateLineHeight(character.lineHeight, this.fontSize); this.lineHeight = "number" == typeof lineHeight ? lineHeight > this.fontSize ? lineHeight : this.fontSize : Math.floor(1.2 * this.fontSize), this.height = this.lineHeight; const {ascent: ascent, height: height, descent: descent, width: width} = measureTextCanvas(text, character, this.ascentDescentMode); let halfDetaHeight = 0, deltaAscent = 0, deltaDescent = 0; this.height > height && (halfDetaHeight = (this.height - height) / 2, deltaAscent = Math.ceil(halfDetaHeight), deltaDescent = Math.floor(halfDetaHeight)), "top" === this.textBaseline ? (this.ascent = halfDetaHeight, this.descent = height - halfDetaHeight) : "bottom" === this.textBaseline ? (this.ascent = height - halfDetaHeight, this.descent = halfDetaHeight) : "middle" === this.textBaseline ? (this.ascent = this.height / 2, this.descent = this.height / 2) : (this.ascent = ascent + deltaAscent, this.descent = descent + deltaDescent), this.length = text.length, this.width = width || 0, this.text = text || "", this.newLine = newLine || !1, this.character = character, this.left = 0, this.top = 0, this.ellipsis = "normal", this.ellipsisWidth = 0, this.ellipsisOtherParagraphWidth = 0, "vertical" === character.direction && (this.direction = character.direction, this.widthOrigin = this.width, this.heightOrigin = this.height, this.width = this.heightOrigin, this.height = this.widthOrigin, this.lineHeight = this.height), this.ellipsisStr = "..."; } updateWidth() { const {width: width} = measureTextCanvas(this.text, this.character, this.ascentDescentMode); this.width = width, "vertical" === this.direction && (this.widthOrigin = this.width, this.width = this.heightOrigin, this.height = this.widthOrigin); } drawBackground(ctx, top, ascent, deltaLeft, isLineFirst, textAlign, lineHeight) { if ("" === this.text || "\n" === this.text || !this.character.background || this.character.backgroundOpacity && !(this.character.backgroundOpacity > 0)) return; let baseline = top + ascent, text = this.text, left = this.left + deltaLeft; baseline += this.top; let direction = this.direction; if (this.verticalEllipsis) text = this.ellipsisStr, direction = "vertical", baseline -= this.ellipsisWidth / 2; else { if ("hide" === this.ellipsis) return; if ("add" === this.ellipsis) text += this.ellipsisStr, "right" !== textAlign && "end" !== textAlign || (left -= this.ellipsisWidth); else if ("replace" === this.ellipsis) { const index = getStrByWithCanvas(text, ("vertical" === direction ? this.height : this.width) - this.ellipsisWidth + this.ellipsisOtherParagraphWidth, this.character, text.length - 1); if (text = text.slice(0, index), text += this.ellipsisStr, "right" === textAlign || "end" === textAlign) { const {width: width} = measureTextCanvas(this.text.slice(index), this.character, this.ascentDescentMode); "vertical" === direction || (left -= this.ellipsisWidth - width); } } } const lrtb = getFixedLRTB(left, left + (this.widthOrigin || this.width), top, top + lineHeight); return Object.assign(Object.assign({}, lrtb), { fillStyle: this.character.background, globalAlpha: this.character.backgroundOpacity }); } draw(ctx, top, ascent, deltaLeft, isLineFirst, textAlign, lineHeight) { let baseline = top + ascent, text = this.text, left = this.left + deltaLeft; baseline += this.top; let direction = this.direction; if (this.verticalEllipsis) text = this.ellipsisStr, direction = "vertical", baseline -= this.ellipsisWidth / 2; else { if ("hide" === this.ellipsis) return; if ("add" === this.ellipsis) text += this.ellipsisStr, "right" !== textAlign && "end" !== textAlign || (left -= this.ellipsisWidth); else if ("replace" === this.ellipsis) { const index = getStrByWithCanvas(text, ("vertical" === direction ? this.height : this.width) - this.ellipsisWidth + this.ellipsisOtherParagraphWidth, this.character, text.length - 1); if (text = text.slice(0, index), text += this.ellipsisStr, "right" === textAlign || "end" === textAlign) { const {width: width} = measureTextCanvas(this.text.slice(index), this.character, this.ascentDescentMode); "vertical" === direction || (left -= this.ellipsisWidth - width); } } } switch (this.character.script) { case "super": baseline -= this.ascent * (1 / 3); break; case "sub": baseline += this.descent / 2; } "vertical" === direction && (ctx.save(), ctx.rotateAbout(Math.PI / 2, left, baseline), ctx.translate(-this.heightOrigin || -this.lineHeight / 2, -this.descent / 2), ctx.translate(left, baseline), left = 0, baseline = 0); const {lineWidth: lineWidth = 1} = this.character; if (this.character.stroke && lineWidth && ctx.strokeText(text, left, baseline), this.character.fill && ctx.fillText(text, left, baseline), this.character.fill) if (this.character.lineThrough || this.character.underline) { if (this.character.underline) { const top = 1 + baseline, lrtb = getFixedLRTB(left, left + (this.widthOrigin || this.width), top, top + (this.character.fontSize ? Math.max(1, Math.floor(this.character.fontSize / 10)) : 1)); ctx.fillRect(lrtb.left, 1 + baseline, lrtb.right - lrtb.left, this.character.fontSize ? Math.max(1, Math.floor(this.character.fontSize / 10)) : 1); } if (this.character.lineThrough) { const top = 1 + baseline - this.ascent / 2, lrtb = getFixedLRTB(left, left + (this.widthOrigin || this.width), top, top + (this.character.fontSize ? Math.max(1, Math.floor(this.character.fontSize / 10)) : 1)); ctx.fillRect(lrtb.left, 1 + baseline - this.ascent / 2, lrtb.right - lrtb.left, this.character.fontSize ? Math.max(1, Math.floor(this.character.fontSize / 10)) : 1); } } else if ("underline" === this.character.textDecoration) { const top = 1 + baseline, lrtb = getFixedLRTB(left, left + (this.widthOrigin || this.width), top, top + (this.character.fontSize ? Math.max(1, Math.floor(this.character.fontSize / 10)) : 1)); ctx.fillRect(lrtb.left, 1 + baseline, lrtb.right - lrtb.left, this.character.fontSize ? Math.max(1, Math.floor(this.character.fontSize / 10)) : 1); } else if ("line-through" === this.character.textDecoration) { const top = 1 + baseline - this.ascent / 2, lrtb = getFixedLRTB(left, left + (this.widthOrigin || this.width), top, top + (this.character.fontSize ? Math.max(1, Math.floor(this.character.fontSize / 10)) : 1)); ctx.fillRect(lrtb.left, 1 + baseline - this.ascent / 2, lrtb.right - lrtb.left, this.character.fontSize ? Math.max(1, Math.floor(this.character.fontSize / 10)) : 1); } "vertical" === direction && ctx.restore(); } getWidthWithEllips(direction) { let text = this.text; const width = "vertical" === direction ? this.height : this.width; if ("hide" === this.ellipsis) return width; if ("add" === this.ellipsis) return width + this.ellipsisWidth; if ("replace" === this.ellipsis) { const index = getStrByWithCanvas(text, width - this.ellipsisWidth + this.ellipsisOtherParagraphWidth, this.character, text.length - 1); text = text.slice(0, index), text += this.ellipsisStr; const {width: measureWidth} = measureTextCanvas(this.text.slice(index), this.character, this.ascentDescentMode); return width + this.ellipsisWidth - measureWidth; } return width; } } export function seperateParagraph(paragraph, index) { const text1 = paragraph.text.slice(0, index), text2 = paragraph.text.slice(index); return [ new Paragraph(text1, paragraph.newLine, paragraph.character, paragraph.ascentDescentMode), new Paragraph(text2, !0, paragraph.character, paragraph.ascentDescentMode) ]; } //# sourceMappingURL=paragraph.js.map