UNPKG

phaser3-rex-plugins

Version:
460 lines (393 loc) 14.7 kB
import DrawMethods from './DrawMethods.js'; import PenManager from '../penmanger/PenManager.js'; import HitAreaManager from '../hitareamanager/HitAreaManager.js'; import SetInteractive from './SetInteractive.js'; import GetHitArea from './GetHitArea.js'; import CONST from '../../../textbase/const.js'; import WrapText from '../wraptext/WrapText.js'; import Clone from '../../../../utils/object/Clone.js'; import MeasureText from '../../../textbase/textstyle/MeasureText.js'; const GetValue = Phaser.Utils.Objects.GetValue; const NO_WRAP = CONST.NO_WRAP; const NO_NEWLINE = CONST.NO_NEWLINE; const RAW_NEWLINE = CONST.RAW_NEWLINE; const WRAPPED_NEWLINE = CONST.WRAPPED_NEWLINE; class CanvasText { constructor(config) { this.parent = config.parent; this.scene = this.parent.scene; this.context = GetValue(config, 'context', null); this.canvas = this.context.canvas; this.parser = GetValue(config, 'parser', null); this.defaultStyle = GetValue(config, 'style', null); this.autoRound = true; this.pensPool = config.pensPool; // Required this.linesPool = config.linesPool; // Required this.wrapTextLinesPool = config.wrapTextLinesPool; // Required this.penManager = this.newPenManager(); this._tmpPenManager = null; this.hitAreaManager = new HitAreaManager(); this.lastHitAreaKey = null; this.urlTagCursorStyle = null; } destroy() { this.parent = undefined; this.scene = undefined; this.context = undefined; this.canvas = undefined; this.parser = undefined; this.defaultStyle = undefined; if (this.penManager) { this.penManager.destroy(); this.penManager = undefined; } if (this._tmpPenManager) { this._tmpPenManager.destroy(); this._tmpPenManager = undefined; } if (this.hitAreaManager) { this.hitAreaManager.destroy(); this.hitAreaManager = undefined; } this.pensPool = undefined; this.linesPool = undefined; this.wrapTextLinesPool = undefined; } updatePenManager(text, wrapMode, wrapWidth, lineHeight, penManager) { if (penManager === undefined) { penManager = this.penManager; } penManager.clear(); if (text === "") { return penManager; } var textStyle = this.parent.style; if (textStyle.isWrapFitMode) { var padding = this.parent.padding; wrapWidth = textStyle.fixedWidth - padding.left - padding.right; } var canvas = this.canvas; var context = this.context; var cursorX = 0, cursorY = 0; var customTextWrapCallback = textStyle.wrapCallback, customTextWrapCallbackScope = textStyle.wrapCallbackScope; var isBuiltInWrappingMode = (!customTextWrapCallback); var reuseLines = true; var plainText, curProp, curStyle; var match = this.parser.splitText(text), result, wrapLines, wrapTextLinesPool = this.wrapTextLinesPool; for (var i = 0, len = match.length; i < len; i++) { result = this.parser.tagTextToProp(match[i], curProp); plainText = result.plainText; curProp = result.prop; if (curProp.img) { // Image tag var cursor = this.addImagePen( curProp, cursorX, cursorY, wrapWidth, wrapMode, lineHeight, penManager ); cursorX = cursor.x; cursorY = cursor.y; } else if (plainText !== '') { // wrap text to lines // Save the current context. context.save(); curStyle = this.parser.propToContextStyle(this.defaultStyle, curProp); curStyle.buildFont(); curStyle.syncFont(canvas, context); curStyle.syncStyle(canvas, context); var metrics = MeasureText(curStyle); if (isBuiltInWrappingMode) { wrapLines = WrapText( plainText, context, wrapMode, wrapWidth, curStyle.letterSpacing, cursorX, wrapTextLinesPool ); } else { // customTextWrapCallback wrapLines = customTextWrapCallback.call(customTextWrapCallbackScope, plainText, context, wrapWidth, curStyle.letterSpacing, cursorX ); if (typeof (wrapLines) === 'string') { wrapLines = wrapLines.split('\n'); } var segment; for (var j = 0, jLen = wrapLines.length; j < jLen; j++) { segment = wrapLines[j]; if (typeof (segment) === 'string') { wrapLines[j] = wrapTextLinesPool.getLine( segment, context.measureText(segment).width, (j < (jLen - 1)) ? WRAPPED_NEWLINE : NO_NEWLINE ); } else { reuseLines = false; } } } // customTextWrapCallback // add pens var segment; for (var j = 0, jLen = wrapLines.length; j < jLen; j++) { segment = wrapLines[j]; penManager.addTextPen( segment.text, cursorX, cursorY, segment.width, Clone(curProp), segment.newLineMode, metrics ); if (segment.newLineMode !== NO_NEWLINE) { cursorX = 0; cursorY += lineHeight; } else { cursorX += segment.width; } } if (reuseLines) { wrapTextLinesPool.freeLines(wrapLines); } wrapLines = null; context.restore(); } } // Process last pen of each line var lines = penManager.lines; for (var i = 0, len = lines.length; i < len; i++) { // Last pen of a line var line = lines[i]; var pens = line.pens; var lastPen = pens[pens.length - 1]; if (lastPen) { // Add strokeThinkness lastPen.width += this.parser.getStrokeThinkness(this.defaultStyle, lastPen.prop); // Remove letterSpacing lastPen.width -= this.parser.getLetterSpacing(this.defaultStyle, lastPen.prop); } } this.updateLineOffsets(lines, textStyle); return penManager; } addImagePen(prop, cursorX, cursorY, wrapWidth, wrapMode, lineHeight, penManager) { var imgWidth = this.imageManager.getOuterWidth(prop.img); var imgHeight = this.imageManager.getOuterHeight(prop.img); var imgMetrics; if (imgHeight > 0) { var ascent = this.defaultStyle.metrics.ascent; var descent = imgHeight - ascent; if (descent < 0) { descent = 0; } imgMetrics = { ascent: ascent, descent: descent, height: ascent + descent }; } if ((wrapWidth > 0) && (wrapMode !== NO_WRAP)) { // Wrap mode if (wrapWidth < (cursorX + imgWidth)) { penManager.addNewLinePen(); cursorY += lineHeight; cursorX = 0; } } penManager.addImagePen(cursorX, cursorY, imgWidth, Clone(prop), imgMetrics); cursorX += imgWidth; return { x: cursorX, y: cursorY }; } updateLineOffsets(lines, textStyle) { var lineSpacing = textStyle.lineSpacing; var defaultMetrics = this.defaultStyle.metrics; var defaultAscent = defaultMetrics.ascent; var defaultDescent = defaultMetrics.descent; var offsetY = 0; var fixedLineHeightMode = textStyle.fixedLineHeightMode; for (var i = 0, len = lines.length; i < len; i++) { var line = lines[i]; var lineAscent = line.maxAscent; var lineDescent = line.maxDescent; if (fixedLineHeightMode || (lineAscent === 0 && lineDescent === 0)) { lineAscent = defaultAscent; lineDescent = defaultDescent; } line.maxAscent = lineAscent; line.maxDescent = lineDescent; line.lineHeight = lineAscent + lineDescent; line.startOffset = offsetY; line.endOffset = offsetY + line.lineHeight; var baselineOffset = offsetY + lineAscent - defaultAscent; var pens = line.pens; for (var penIdx = 0, penCnt = pens.length; penIdx < penCnt; penIdx++) { pens[penIdx].y = baselineOffset; } offsetY = line.endOffset + lineSpacing; } } get startXOffset() { return this.defaultStyle.xOffset; } get startYOffset() { return this.defaultStyle.metrics.ascent; } get lines() { return this.penManager.lines; } get displayLinesCount() { var linesCount = this.penManager.linesCount, maxLines = this.defaultStyle.maxLines; if ((maxLines > 0) && (linesCount > maxLines)) { linesCount = maxLines; } return linesCount; } get linesWidth() { return Math.ceil(this.penManager.getMaxLineWidth()); } get linesHeight() { var linesCount = this.displayLinesCount; return this.getLinesHeight(0, linesCount); } getLineHeight(line) { var lineHeight = (line) ? line.lineHeight : 0; if (lineHeight > 0) { return lineHeight; } var metrics = this.defaultStyle.metrics; return metrics.ascent + metrics.descent; } getLinesHeight(start, end) { var lines = this.penManager.lines; var linesCount = lines.length; if (start === undefined) { start = 0; } if (end === undefined || end > linesCount) { end = linesCount; } if (end <= start) { return 0; } var height = 0; for (var i = start; i < end; i++) { height += this.getLineHeight(lines[i]); } var count = end - start; if (count > 1) { height += this.defaultStyle.lineSpacing * (count - 1); } return height; } get imageManager() { return this.parent.imageManager; } get rtl() { return this.parent.style.rtl; } newPenManager() { return new PenManager({ pensPool: this.pensPool, linesPool: this.linesPool, tagToText: this.parser.propToTagText, tagToTextScope: this.parser }); } get tmpPenManager() { if (this._tmpPenManager === null) { this._tmpPenManager = this.newPenManager(); } return this._tmpPenManager; } getPlainText(text, start, end) { var plainText; if (text == null) { plainText = this.penManager.plainText; } else { var m, match = this.parser.splitText(text, 1); // PLAINTEXTONLY_MODE plainText = ""; for (var i = 0, len = match.length; i < len; i++) { plainText += match[i]; } } if ((start != null) || (end != null)) { if (start == null) { start = 0; } if (end == null) { end = plainText.length; } plainText = plainText.substring(start, end); } return plainText; } getPenManager(text, retPenManager) { if (text === undefined) { return this.copyPenManager(retPenManager, this.penManager); } if (retPenManager === undefined) { retPenManager = this.newPenManager(); } var defaultStyle = this.defaultStyle; this.updatePenManager( text, defaultStyle.wrapMode, defaultStyle.wrapWidth, defaultStyle.lineHeight, retPenManager ); return retPenManager; } getText(text, start, end, wrap) { if (text == null) { return this.penManager.getSliceTagText(start, end, wrap); } var penManager = this.tmpPenManager; var defaultStyle = this.defaultStyle; this.updatePenManager( text, defaultStyle.wrapMode, defaultStyle.wrapWidth, defaultStyle.lineHeight, penManager ); return penManager.getSliceTagText(start, end, wrap); } copyPenManager(ret, src) { if (src === undefined) { src = this.penManager; } return src.copy(ret); } getTextWidth(penManager) { if (penManager === undefined) { penManager = this.penManager; } return penManager.getMaxLineWidth(); } getLastPen(penManager) { if (penManager === undefined) { penManager = this.penManager; } return penManager.lastPen; } }; var methods = { setInteractive: SetInteractive, getHitArea: GetHitArea, } Object.assign( CanvasText.prototype, DrawMethods, methods ); export default CanvasText;