UNPKG

phaser4-rex-plugins

Version:
583 lines (471 loc) 16.5 kB
import TextBase from '../../textbase/TextBase.js'; import TextStyle from '../../textbase/textstyle/TextStyle.js'; import GetString from '../../../utils/text/GetString.js'; import CanvasText from './canvastext/CanvasText.js'; import Pool from '../../../pool.js'; import WrapTextLinesPoolClass from './wraptext/WrapTextLinesPool.js'; import CONST from '../../textbase/const.js'; import ImageManager from '../../../utils/texture/imagemanager/ImageManager.js'; import CopyCanvasToTexture from '../../../utils/texture/CopyCanvasToTexture.js'; import AppendText from '../../../utils/text/AppendText.js'; const IsPlainObject = Phaser.Utils.Objects.IsPlainObject; const AddToDOM = Phaser.DOM.AddToDOM; const CanvasPool = Phaser.Display.Canvas.CanvasPool; const GameObject = Phaser.GameObjects.GameObject; const GetValue = Phaser.Utils.Objects.GetValue; const RemoveFromDOM = Phaser.DOM.RemoveFromDOM; const SPLITREGEXP = CONST.SPLITREGEXP; const UUID = Phaser.Utils.String.UUID; const DefaultImageNodes = Phaser.Renderer.WebGL.RenderNodes.Defaults.DefaultImageNodes; // Reuse objects can increase performance var SharedPensPools = null; var SharedLinesPool = null; var SharedWrapTextLinesPool = null; class Text extends TextBase { constructor(scene, x, y, text, style, type, parser) { if (IsPlainObject(x)) { var config = x; x = GetValue(config, 'x', 0); y = GetValue(config, 'y', 0); text = GetValue(config, 'text', ''); style = GetValue(config, 'style'); } if (x === undefined) { x = 0; } if (y === undefined) { y = 0; } super(scene, type); this.renderer = scene.sys.game.renderer; this.setPosition(x, y); this.setOrigin(0, 0); this.initRenderNodes(this._defaultRenderNodesMap); this.canvas = CanvasPool.create(this); this._imageManager = undefined; if (style) { // Override align if (style.hasOwnProperty('align')) { var halign = style.align; delete style.align; style.halign = halign; } // Has Stroke color but stroke thinkness, set stroke thinkness to 1 if (style.hasOwnProperty('stroke') && !style.hasOwnProperty('strokeThickness')) { style.strokeThickness = 1; } } this.style = new TextStyle(this, style); var imageData = GetValue(style, 'images', undefined); if (imageData) { this.addImage(imageData); } this.autoRound = true; this._text = undefined; this.padding = { left: 0, right: 0, top: 0, bottom: 0 }; this.width = 1; this.height = 1; this.dirty = false; // If resolution wasn't set, force it to 1 if (this.style.resolution === 0) { this.style.resolution = 1; } this._crop = this.resetCropObject(); // Create a Texture for this Text object this._textureKey = UUID(); this.texture = scene.sys.textures.addCanvas(this._textureKey, this.canvas); // Set the context to be the CanvasTexture context this.context = this.texture.context; // Get the frame this.frame = this.texture.get(); // Set the resolution this.frame.source.resolution = this.style.resolution; if (this.renderer && this.renderer.gl) { // Clear the default 1x1 glTexture, as we override it later this.renderer.deleteTexture(this.frame.source.glTexture); this.frame.source.glTexture = null; } var sharedPoolMode = GetValue(style, 'sharedPool', true); var pensPool, linesPool, wrapTextLinesPool; if (sharedPoolMode) { // Use pools first time if (!SharedPensPools) { SharedPensPools = {}; SharedLinesPool = new Pool(); SharedWrapTextLinesPool = new WrapTextLinesPoolClass(); // Remove cached data this.scene.game.events.once('destroy', function () { SharedPensPools = null; SharedLinesPool = null; SharedWrapTextLinesPool = null; }); } if (!SharedPensPools.hasOwnProperty(type)) { SharedPensPools[type] = new Pool(); } pensPool = SharedPensPools[type]; linesPool = SharedLinesPool; wrapTextLinesPool = SharedWrapTextLinesPool; } else { pensPool = new Pool(); linesPool = new Pool(); wrapTextLinesPool = new WrapTextLinesPoolClass(); } this.canvasText = new CanvasText({ parent: this, context: this.context, parser: parser, style: this.style, pensPool: pensPool, linesPool: linesPool, wrapTextLinesPool: wrapTextLinesPool, }); this.parser = parser; this.initRTL(); if (style && style.padding) { this.setPadding(style.padding); } this.setText(text); this.setUrlTagCursorStyle(GetValue(style, 'urlTagCursorStyle', 'pointer')); if (GetValue(style, 'interactive', false)) { this.setInteractive(); } } get _defaultRenderNodesMap() { return DefaultImageNodes; } preDestroy() { RemoveFromDOM(this.canvas); // Do nothing if canvas did not add to parent node before this.canvasText.destroy(); this.canvasText = undefined; if (this._imageManager) { this._imageManager.destroy(); this._imageManager = undefined; } CanvasPool.remove(this.canvas); var texture = this.texture; if (texture) { texture.destroy(); } } set text(value) { this.setText(value); } get text() { return this._text; } initRTL() { if (!this.style.rtl) { return; } // Here is where the crazy starts. // // Due to browser implementation issues, you cannot fillText BiDi text to a canvas // that is not part of the DOM. It just completely ignores the direction property. this.canvas.dir = 'rtl'; // Experimental atm, but one day ... this.context.direction = 'rtl'; // Add it to the DOM, but hidden within the parent canvas. this.canvas.style.display = 'none'; AddToDOM(this.canvas, this.scene.sys.canvas); // And finally we set the x origin this.originX = 1; } setRTL(rtl) { if (rtl === undefined) { rtl = true; } var style = this.style; if (style.rtl === rtl) { return this; } style.rtl = rtl; if (rtl) { this.canvas.dir = 'rtl'; this.context.direction = 'rtl'; this.canvas.style.display = 'none'; AddToDOM(this.canvas, this.scene.sys.canvas); } else { this.canvas.dir = 'ltr'; this.context.direction = 'ltr'; } if (style.halign === 'left') { style.halign = 'right'; } else if (style.halign === 'right') { style.halign = 'left'; } if (this._imageManager) { var images = this._imageManager.images; for (var key in images) { images[key].originX = 1 - images[key].originX; } } return this; } setText(value) { value = GetString(value); if (value === this._text) { return this; } this._text = value; this.updateText(); return this; } setPadding(left, top, right, bottom) { if (typeof left === 'object') { var config = left; // If they specify x and/or y this applies to all var x = GetValue(config, 'x', null); if (x !== null) { left = x; right = x; } else { left = GetValue(config, 'left', 0); right = GetValue(config, 'right', left); } var y = GetValue(config, 'y', null); if (y !== null) { top = y; bottom = y; } else { top = GetValue(config, 'top', 0); bottom = GetValue(config, 'bottom', top); } } else { if (left === undefined) { left = 0; } if (top === undefined) { top = left; } if (right === undefined) { right = left; } if (bottom === undefined) { bottom = top; } } this.padding.left = left; this.padding.top = top; this.padding.right = right; this.padding.bottom = bottom; return this.updateText(false); } updateText(runWrap) { if (runWrap === undefined) { runWrap = true; } var canvasText = this.canvasText; // wrap text to pens var style = this.style; if (runWrap) { canvasText.updatePenManager( this._text, style.wrapMode, style.wrapWidth, style.lineHeight ); } // resize var padding = this.padding; var textWidth, textHeight; var linesWidth = Math.ceil(canvasText.linesWidth); if (style.fixedWidth === 0) { this.width = linesWidth + padding.left + padding.right; textWidth = linesWidth; } else { this.width = style.fixedWidth; textWidth = this.width - padding.left - padding.right; if (textWidth < linesWidth) { textWidth = linesWidth; } } if (style.fixedHeight === 0) { this.height = canvasText.linesHeight + padding.top + padding.bottom; textHeight = canvasText.linesHeight; } else { this.height = style.fixedHeight; textHeight = this.height - padding.top - padding.bottom; if (textHeight < canvasText.linesHeight) { textHeight = canvasText.linesHeight; } } var w = this.width; var h = this.height; this.updateDisplayOrigin(); var resolution = style.resolution; w *= resolution; h *= resolution; w = Math.max(Math.ceil(w), 1); h = Math.max(Math.ceil(h), 1); var canvas = this.canvas; var context = this.context; if (canvas.width !== w || canvas.height !== h) { canvas.width = w; canvas.height = h; this.frame.setSize(w, h); this.frame.source.updateSize(w, h); this.frame.updateUVs(); } else { context.clearRect(0, 0, w, h); } context.save(); context.scale(resolution, resolution); // draw var startX = (!this.style.rtl) ? padding.left : padding.right; var startY = padding.top; canvasText.draw( startX, startY, textWidth, textHeight, ); context.restore(); if (this.renderer && this.renderer.gl) { this.frame.source.glTexture = this.renderer.canvasToTexture(canvas, this.frame.source.glTexture, true); if (typeof WEBGL_DEBUG) { this.frame.glTexture.spectorMetadata = { textureKey: 'BBCodeText Game Object' }; } } this.dirty = true; var input = this.input; if (input && !input.customHitArea) { input.hitArea.width = this.width; input.hitArea.height = this.height; } return this; } toJSON() { var out = Components.ToJSON(this); // Extra Text data is added here var data = { autoRound: this.autoRound, text: this._text, style: this.style.toJSON(), resolution: this.resolution, padding: { left: this.padding.left, right: this.padding.right, top: this.padding.top, bottom: this.padding.bottom } }; out.data = data; return out; } setInteractive(hitArea, hitAreaCallback, dropZone) { var isInteractived = !!this.input; GameObject.prototype.setInteractive.call(this, hitArea, hitAreaCallback, dropZone); if (!isInteractived) { this.canvasText.setInteractive(); } return this; } setUrlTagCursorStyle(cursor) { this.urlTagCursorStyle = cursor; return this; } get urlTagCursorStyle() { return this.canvasText.urlTagCursorStyle; } set urlTagCursorStyle(value) { this.canvasText.urlTagCursorStyle = value; } getWrappedText(text, start, end) { if (typeof (text) === 'number') { end = start; start = text; text = undefined; } text = this.canvasText.getText(text, start, end, true); return text.split(SPLITREGEXP); } getPlainText(text, start, end) { if (typeof (text) === 'number') { end = start; start = text; text = undefined; } return this.canvasText.getPlainText(text, start, end); } getText(text, start, end, wrap) { if (typeof (text) === 'number') { wrap = end; end = start; start = text; text = undefined; } if (wrap === undefined) { wrap = false; } return this.canvasText.getText(text, start, end, wrap); } getSubString(text, start, end) { if (typeof (text) === 'number') { end = start; start = text; text = undefined; } return this.getText(text, start, end); } copyPenManager(penManager) { return this.canvasText.copyPenManager(penManager); } getPenManager(text, penManager) { return this.canvasText.getPenManager(text, penManager); } setSize(width, height) { return this.setFixedSize(width, height); } resize(width, height) { return this.setFixedSize(width, height); } get imageManager() { if (!this._imageManager) { this._imageManager = new ImageManager(this.scene); } return this._imageManager; } addImage(key, config) { this.imageManager.add(key, config); return this; } drawAreaBounds(graphics, color) { this.canvasText.hitAreaManager.drawBounds(graphics, color, this); return this; } generateTexture(key, x, y, width, height) { var srcCanvas = this.canvas; if (width === undefined) { width = srcCanvas.width; } else { width *= this.resolution; } if (height === undefined) { height = srcCanvas.height; } else { height *= this.resolution; } CopyCanvasToTexture(this.scene, srcCanvas, key, x, y, width, height); return this; } getHitArea(worldX, worldY, camera) { return this.canvasText.getHitArea(worldX, worldY, camera); } } var methods = { appendText: AppendText, } Object.assign( Text.prototype, methods ) export default Text;