| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919 |
- /*!
- * @pixi/text - v6.5.10
- * Compiled Thu, 06 Jul 2023 15:25:11 UTC
- *
- * @pixi/text is licensed under the MIT License.
- * http://www.opensource.org/licenses/mit-license
- */
- 'use strict';
- Object.defineProperty(exports, '__esModule', { value: true });
- var sprite = require('@pixi/sprite');
- var core = require('@pixi/core');
- var settings = require('@pixi/settings');
- var math = require('@pixi/math');
- var utils = require('@pixi/utils');
- /*! *****************************************************************************
- Copyright (c) Microsoft Corporation.
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
- ***************************************************************************** */
- /* global Reflect, Promise */
- var extendStatics = function(d, b) {
- extendStatics = Object.setPrototypeOf ||
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
- function (d, b) { for (var p in b) { if (b.hasOwnProperty(p)) { d[p] = b[p]; } } };
- return extendStatics(d, b);
- };
- function __extends(d, b) {
- extendStatics(d, b);
- function __() { this.constructor = d; }
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
- }
- /**
- * Constants that define the type of gradient on text.
- * @static
- * @constant
- * @name TEXT_GRADIENT
- * @memberof PIXI
- * @type {object}
- * @property {number} LINEAR_VERTICAL Vertical gradient
- * @property {number} LINEAR_HORIZONTAL Linear gradient
- */
- exports.TEXT_GRADIENT = void 0;
- (function (TEXT_GRADIENT) {
- TEXT_GRADIENT[TEXT_GRADIENT["LINEAR_VERTICAL"] = 0] = "LINEAR_VERTICAL";
- TEXT_GRADIENT[TEXT_GRADIENT["LINEAR_HORIZONTAL"] = 1] = "LINEAR_HORIZONTAL";
- })(exports.TEXT_GRADIENT || (exports.TEXT_GRADIENT = {}));
- // disabling eslint for now, going to rewrite this in v5
- var defaultStyle = {
- align: 'left',
- breakWords: false,
- dropShadow: false,
- dropShadowAlpha: 1,
- dropShadowAngle: Math.PI / 6,
- dropShadowBlur: 0,
- dropShadowColor: 'black',
- dropShadowDistance: 5,
- fill: 'black',
- fillGradientType: exports.TEXT_GRADIENT.LINEAR_VERTICAL,
- fillGradientStops: [],
- fontFamily: 'Arial',
- fontSize: 26,
- fontStyle: 'normal',
- fontVariant: 'normal',
- fontWeight: 'normal',
- letterSpacing: 0,
- lineHeight: 0,
- lineJoin: 'miter',
- miterLimit: 10,
- padding: 0,
- stroke: 'black',
- strokeThickness: 0,
- textBaseline: 'alphabetic',
- trim: false,
- whiteSpace: 'pre',
- wordWrap: false,
- wordWrapWidth: 100,
- leading: 0,
- };
- var genericFontFamilies = [
- 'serif',
- 'sans-serif',
- 'monospace',
- 'cursive',
- 'fantasy',
- 'system-ui' ];
- /**
- * A TextStyle Object contains information to decorate a Text objects.
- *
- * An instance can be shared between multiple Text objects; then changing the style will update all text objects using it.
- *
- * A tool can be used to generate a text style [here](https://pixijs.io/pixi-text-style).
- *
- * @memberof PIXI
- */
- var TextStyle = /** @class */ (function () {
- /**
- * @param {object} [style] - The style parameters
- * @param {string} [style.align='left'] - Alignment for multiline text ('left', 'center' or 'right'),
- * does not affect single line text
- * @param {boolean} [style.breakWords=false] - Indicates if lines can be wrapped within words, it
- * needs wordWrap to be set to true
- * @param {boolean} [style.dropShadow=false] - Set a drop shadow for the text
- * @param {number} [style.dropShadowAlpha=1] - Set alpha for the drop shadow
- * @param {number} [style.dropShadowAngle=Math.PI/6] - Set a angle of the drop shadow
- * @param {number} [style.dropShadowBlur=0] - Set a shadow blur radius
- * @param {string|number} [style.dropShadowColor='black'] - A fill style to be used on the dropshadow e.g 'red', '#00FF00'
- * @param {number} [style.dropShadowDistance=5] - Set a distance of the drop shadow
- * @param {string|string[]|number|number[]|CanvasGradient|CanvasPattern} [style.fill='black'] - A canvas
- * fillstyle that will be used on the text e.g 'red', '#00FF00'. Can be an array to create a gradient
- * eg ['#000000','#FFFFFF']
- * {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle|MDN}
- * @param {number} [style.fillGradientType=PIXI.TEXT_GRADIENT.LINEAR_VERTICAL] - If fill is an array of colours
- * to create a gradient, this can change the type/direction of the gradient. See {@link PIXI.TEXT_GRADIENT}
- * @param {number[]} [style.fillGradientStops] - If fill is an array of colours to create a gradient, this array can set
- * the stop points (numbers between 0 and 1) for the color, overriding the default behaviour of evenly spacing them.
- * @param {string|string[]} [style.fontFamily='Arial'] - The font family
- * @param {number|string} [style.fontSize=26] - The font size (as a number it converts to px, but as a string,
- * equivalents are '26px','20pt','160%' or '1.6em')
- * @param {string} [style.fontStyle='normal'] - The font style ('normal', 'italic' or 'oblique')
- * @param {string} [style.fontVariant='normal'] - The font variant ('normal' or 'small-caps')
- * @param {string} [style.fontWeight='normal'] - The font weight ('normal', 'bold', 'bolder', 'lighter' and '100',
- * '200', '300', '400', '500', '600', '700', '800' or '900')
- * @param {number} [style.leading=0] - The space between lines
- * @param {number} [style.letterSpacing=0] - The amount of spacing between letters, default is 0
- * @param {number} [style.lineHeight] - The line height, a number that represents the vertical space that a letter uses
- * @param {string} [style.lineJoin='miter'] - The lineJoin property sets the type of corner created, it can resolve
- * spiked text issues. Possible values "miter" (creates a sharp corner), "round" (creates a round corner) or "bevel"
- * (creates a squared corner).
- * @param {number} [style.miterLimit=10] - The miter limit to use when using the 'miter' lineJoin mode. This can reduce
- * or increase the spikiness of rendered text.
- * @param {number} [style.padding=0] - Occasionally some fonts are cropped. Adding some padding will prevent this from
- * happening by adding padding to all sides of the text.
- * @param {string|number} [style.stroke='black'] - A canvas fillstyle that will be used on the text stroke
- * e.g 'blue', '#FCFF00'
- * @param {number} [style.strokeThickness=0] - A number that represents the thickness of the stroke.
- * Default is 0 (no stroke)
- * @param {boolean} [style.trim=false] - Trim transparent borders
- * @param {string} [style.textBaseline='alphabetic'] - The baseline of the text that is rendered.
- * @param {string} [style.whiteSpace='pre'] - Determines whether newlines & spaces are collapsed or preserved "normal"
- * (collapse, collapse), "pre" (preserve, preserve) | "pre-line" (preserve, collapse). It needs wordWrap to be set to true
- * @param {boolean} [style.wordWrap=false] - Indicates if word wrap should be used
- * @param {number} [style.wordWrapWidth=100] - The width at which text will wrap, it needs wordWrap to be set to true
- */
- function TextStyle(style) {
- this.styleID = 0;
- this.reset();
- deepCopyProperties(this, style, style);
- }
- /**
- * Creates a new TextStyle object with the same values as this one.
- * Note that the only the properties of the object are cloned.
- *
- * @return New cloned TextStyle object
- */
- TextStyle.prototype.clone = function () {
- var clonedProperties = {};
- deepCopyProperties(clonedProperties, this, defaultStyle);
- return new TextStyle(clonedProperties);
- };
- /** Resets all properties to the defaults specified in TextStyle.prototype._default */
- TextStyle.prototype.reset = function () {
- deepCopyProperties(this, defaultStyle, defaultStyle);
- };
- Object.defineProperty(TextStyle.prototype, "align", {
- /**
- * Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text
- *
- * @member {string}
- */
- get: function () {
- return this._align;
- },
- set: function (align) {
- if (this._align !== align) {
- this._align = align;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "breakWords", {
- /** Indicates if lines can be wrapped within words, it needs wordWrap to be set to true. */
- get: function () {
- return this._breakWords;
- },
- set: function (breakWords) {
- if (this._breakWords !== breakWords) {
- this._breakWords = breakWords;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "dropShadow", {
- /** Set a drop shadow for the text. */
- get: function () {
- return this._dropShadow;
- },
- set: function (dropShadow) {
- if (this._dropShadow !== dropShadow) {
- this._dropShadow = dropShadow;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "dropShadowAlpha", {
- /** Set alpha for the drop shadow. */
- get: function () {
- return this._dropShadowAlpha;
- },
- set: function (dropShadowAlpha) {
- if (this._dropShadowAlpha !== dropShadowAlpha) {
- this._dropShadowAlpha = dropShadowAlpha;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "dropShadowAngle", {
- /** Set a angle of the drop shadow. */
- get: function () {
- return this._dropShadowAngle;
- },
- set: function (dropShadowAngle) {
- if (this._dropShadowAngle !== dropShadowAngle) {
- this._dropShadowAngle = dropShadowAngle;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "dropShadowBlur", {
- /** Set a shadow blur radius. */
- get: function () {
- return this._dropShadowBlur;
- },
- set: function (dropShadowBlur) {
- if (this._dropShadowBlur !== dropShadowBlur) {
- this._dropShadowBlur = dropShadowBlur;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "dropShadowColor", {
- /** A fill style to be used on the dropshadow e.g 'red', '#00FF00'. */
- get: function () {
- return this._dropShadowColor;
- },
- set: function (dropShadowColor) {
- var outputColor = getColor(dropShadowColor);
- if (this._dropShadowColor !== outputColor) {
- this._dropShadowColor = outputColor;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "dropShadowDistance", {
- /** Set a distance of the drop shadow. */
- get: function () {
- return this._dropShadowDistance;
- },
- set: function (dropShadowDistance) {
- if (this._dropShadowDistance !== dropShadowDistance) {
- this._dropShadowDistance = dropShadowDistance;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "fill", {
- /**
- * A canvas fillstyle that will be used on the text e.g 'red', '#00FF00'.
- *
- * Can be an array to create a gradient eg ['#000000','#FFFFFF']
- * {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle|MDN}
- *
- * @member {string|string[]|number|number[]|CanvasGradient|CanvasPattern}
- */
- get: function () {
- return this._fill;
- },
- set: function (fill) {
- // TODO: Can't have different types for getter and setter. The getter shouldn't have the number type as
- // the setter converts to string. See this thread for more details:
- // https://github.com/microsoft/TypeScript/issues/2521
- // TODO: Not sure if getColor works properly with CanvasGradient and/or CanvasPattern, can't pass in
- // without casting here.
- var outputColor = getColor(fill);
- if (this._fill !== outputColor) {
- this._fill = outputColor;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "fillGradientType", {
- /**
- * If fill is an array of colours to create a gradient, this can change the type/direction of the gradient.
- *
- * @see PIXI.TEXT_GRADIENT
- */
- get: function () {
- return this._fillGradientType;
- },
- set: function (fillGradientType) {
- if (this._fillGradientType !== fillGradientType) {
- this._fillGradientType = fillGradientType;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "fillGradientStops", {
- /**
- * If fill is an array of colours to create a gradient, this array can set the stop points
- * (numbers between 0 and 1) for the color, overriding the default behaviour of evenly spacing them.
- */
- get: function () {
- return this._fillGradientStops;
- },
- set: function (fillGradientStops) {
- if (!areArraysEqual(this._fillGradientStops, fillGradientStops)) {
- this._fillGradientStops = fillGradientStops;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "fontFamily", {
- /** The font family. */
- get: function () {
- return this._fontFamily;
- },
- set: function (fontFamily) {
- if (this.fontFamily !== fontFamily) {
- this._fontFamily = fontFamily;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "fontSize", {
- /**
- * The font size
- * (as a number it converts to px, but as a string, equivalents are '26px','20pt','160%' or '1.6em')
- */
- get: function () {
- return this._fontSize;
- },
- set: function (fontSize) {
- if (this._fontSize !== fontSize) {
- this._fontSize = fontSize;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "fontStyle", {
- /**
- * The font style
- * ('normal', 'italic' or 'oblique')
- *
- * @member {string}
- */
- get: function () {
- return this._fontStyle;
- },
- set: function (fontStyle) {
- if (this._fontStyle !== fontStyle) {
- this._fontStyle = fontStyle;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "fontVariant", {
- /**
- * The font variant
- * ('normal' or 'small-caps')
- *
- * @member {string}
- */
- get: function () {
- return this._fontVariant;
- },
- set: function (fontVariant) {
- if (this._fontVariant !== fontVariant) {
- this._fontVariant = fontVariant;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "fontWeight", {
- /**
- * The font weight
- * ('normal', 'bold', 'bolder', 'lighter' and '100', '200', '300', '400', '500', '600', '700', 800' or '900')
- *
- * @member {string}
- */
- get: function () {
- return this._fontWeight;
- },
- set: function (fontWeight) {
- if (this._fontWeight !== fontWeight) {
- this._fontWeight = fontWeight;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "letterSpacing", {
- /** The amount of spacing between letters, default is 0. */
- get: function () {
- return this._letterSpacing;
- },
- set: function (letterSpacing) {
- if (this._letterSpacing !== letterSpacing) {
- this._letterSpacing = letterSpacing;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "lineHeight", {
- /** The line height, a number that represents the vertical space that a letter uses. */
- get: function () {
- return this._lineHeight;
- },
- set: function (lineHeight) {
- if (this._lineHeight !== lineHeight) {
- this._lineHeight = lineHeight;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "leading", {
- /** The space between lines. */
- get: function () {
- return this._leading;
- },
- set: function (leading) {
- if (this._leading !== leading) {
- this._leading = leading;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "lineJoin", {
- /**
- * The lineJoin property sets the type of corner created, it can resolve spiked text issues.
- * Default is 'miter' (creates a sharp corner).
- *
- * @member {string}
- */
- get: function () {
- return this._lineJoin;
- },
- set: function (lineJoin) {
- if (this._lineJoin !== lineJoin) {
- this._lineJoin = lineJoin;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "miterLimit", {
- /**
- * The miter limit to use when using the 'miter' lineJoin mode.
- *
- * This can reduce or increase the spikiness of rendered text.
- */
- get: function () {
- return this._miterLimit;
- },
- set: function (miterLimit) {
- if (this._miterLimit !== miterLimit) {
- this._miterLimit = miterLimit;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "padding", {
- /**
- * Occasionally some fonts are cropped. Adding some padding will prevent this from happening
- * by adding padding to all sides of the text.
- */
- get: function () {
- return this._padding;
- },
- set: function (padding) {
- if (this._padding !== padding) {
- this._padding = padding;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "stroke", {
- /**
- * A canvas fillstyle that will be used on the text stroke
- * e.g 'blue', '#FCFF00'
- */
- get: function () {
- return this._stroke;
- },
- set: function (stroke) {
- // TODO: Can't have different types for getter and setter. The getter shouldn't have the number type as
- // the setter converts to string. See this thread for more details:
- // https://github.com/microsoft/TypeScript/issues/2521
- var outputColor = getColor(stroke);
- if (this._stroke !== outputColor) {
- this._stroke = outputColor;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "strokeThickness", {
- /**
- * A number that represents the thickness of the stroke.
- *
- * @default 0
- */
- get: function () {
- return this._strokeThickness;
- },
- set: function (strokeThickness) {
- if (this._strokeThickness !== strokeThickness) {
- this._strokeThickness = strokeThickness;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "textBaseline", {
- /**
- * The baseline of the text that is rendered.
- *
- * @member {string}
- */
- get: function () {
- return this._textBaseline;
- },
- set: function (textBaseline) {
- if (this._textBaseline !== textBaseline) {
- this._textBaseline = textBaseline;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "trim", {
- /** Trim transparent borders. */
- get: function () {
- return this._trim;
- },
- set: function (trim) {
- if (this._trim !== trim) {
- this._trim = trim;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "whiteSpace", {
- /**
- * How newlines and spaces should be handled.
- * Default is 'pre' (preserve, preserve).
- *
- * value | New lines | Spaces
- * --- | --- | ---
- * 'normal' | Collapse | Collapse
- * 'pre' | Preserve | Preserve
- * 'pre-line' | Preserve | Collapse
- *
- * @member {string}
- */
- get: function () {
- return this._whiteSpace;
- },
- set: function (whiteSpace) {
- if (this._whiteSpace !== whiteSpace) {
- this._whiteSpace = whiteSpace;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "wordWrap", {
- /** Indicates if word wrap should be used. */
- get: function () {
- return this._wordWrap;
- },
- set: function (wordWrap) {
- if (this._wordWrap !== wordWrap) {
- this._wordWrap = wordWrap;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextStyle.prototype, "wordWrapWidth", {
- /** The width at which text will wrap, it needs wordWrap to be set to true. */
- get: function () {
- return this._wordWrapWidth;
- },
- set: function (wordWrapWidth) {
- if (this._wordWrapWidth !== wordWrapWidth) {
- this._wordWrapWidth = wordWrapWidth;
- this.styleID++;
- }
- },
- enumerable: false,
- configurable: true
- });
- /**
- * Generates a font style string to use for `TextMetrics.measureFont()`.
- *
- * @return Font style string, for passing to `TextMetrics.measureFont()`
- */
- TextStyle.prototype.toFontString = function () {
- // build canvas api font setting from individual components. Convert a numeric this.fontSize to px
- var fontSizeString = (typeof this.fontSize === 'number') ? this.fontSize + "px" : this.fontSize;
- // Clean-up fontFamily property by quoting each font name
- // this will support font names with spaces
- var fontFamilies = this.fontFamily;
- if (!Array.isArray(this.fontFamily)) {
- fontFamilies = this.fontFamily.split(',');
- }
- for (var i = fontFamilies.length - 1; i >= 0; i--) {
- // Trim any extra white-space
- var fontFamily = fontFamilies[i].trim();
- // Check if font already contains strings
- if (!(/([\"\'])[^\'\"]+\1/).test(fontFamily) && genericFontFamilies.indexOf(fontFamily) < 0) {
- fontFamily = "\"" + fontFamily + "\"";
- }
- fontFamilies[i] = fontFamily;
- }
- return this.fontStyle + " " + this.fontVariant + " " + this.fontWeight + " " + fontSizeString + " " + fontFamilies.join(',');
- };
- return TextStyle;
- }());
- /**
- * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string.
- * @private
- * @param color
- * @return The color as a string.
- */
- function getSingleColor(color) {
- if (typeof color === 'number') {
- return utils.hex2string(color);
- }
- else if (typeof color === 'string') {
- if (color.indexOf('0x') === 0) {
- color = color.replace('0x', '#');
- }
- }
- return color;
- }
- function getColor(color) {
- if (!Array.isArray(color)) {
- return getSingleColor(color);
- }
- else {
- for (var i = 0; i < color.length; ++i) {
- color[i] = getSingleColor(color[i]);
- }
- return color;
- }
- }
- /**
- * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string.
- * This version can also convert array of colors
- * @private
- * @param array1 - First array to compare
- * @param array2 - Second array to compare
- * @return Do the arrays contain the same values in the same order
- */
- function areArraysEqual(array1, array2) {
- if (!Array.isArray(array1) || !Array.isArray(array2)) {
- return false;
- }
- if (array1.length !== array2.length) {
- return false;
- }
- for (var i = 0; i < array1.length; ++i) {
- if (array1[i] !== array2[i]) {
- return false;
- }
- }
- return true;
- }
- /**
- * Utility function to ensure that object properties are copied by value, and not by reference
- * @private
- * @param target - Target object to copy properties into
- * @param source - Source object for the properties to copy
- * @param propertyObj - Object containing properties names we want to loop over
- */
- function deepCopyProperties(target, source, propertyObj) {
- for (var prop in propertyObj) {
- if (Array.isArray(source[prop])) {
- target[prop] = source[prop].slice();
- }
- else {
- target[prop] = source[prop];
- }
- }
- }
- // Default settings used for all getContext calls
- var contextSettings = {
- // TextMetrics requires getImageData readback for measuring fonts.
- willReadFrequently: true,
- };
- /**
- * The TextMetrics object represents the measurement of a block of text with a specified style.
- *
- * ```js
- * let style = new PIXI.TextStyle({fontFamily : 'Arial', fontSize: 24, fill : 0xff1010, align : 'center'})
- * let textMetrics = PIXI.TextMetrics.measureText('Your text', style)
- * ```
- * @memberof PIXI
- */
- var TextMetrics = /** @class */ (function () {
- /**
- * @param text - the text that was measured
- * @param style - the style that was measured
- * @param width - the measured width of the text
- * @param height - the measured height of the text
- * @param lines - an array of the lines of text broken by new lines and wrapping if specified in style
- * @param lineWidths - an array of the line widths for each line matched to `lines`
- * @param lineHeight - the measured line height for this style
- * @param maxLineWidth - the maximum line width for all measured lines
- * @param {PIXI.IFontMetrics} fontProperties - the font properties object from TextMetrics.measureFont
- */
- function TextMetrics(text, style, width, height, lines, lineWidths, lineHeight, maxLineWidth, fontProperties) {
- this.text = text;
- this.style = style;
- this.width = width;
- this.height = height;
- this.lines = lines;
- this.lineWidths = lineWidths;
- this.lineHeight = lineHeight;
- this.maxLineWidth = maxLineWidth;
- this.fontProperties = fontProperties;
- }
- /**
- * Measures the supplied string of text and returns a Rectangle.
- * @param text - The text to measure.
- * @param style - The text style to use for measuring
- * @param wordWrap - Override for if word-wrap should be applied to the text.
- * @param canvas - optional specification of the canvas to use for measuring.
- * @returns Measured width and height of the text.
- */
- TextMetrics.measureText = function (text, style, wordWrap, canvas) {
- if (canvas === void 0) { canvas = TextMetrics._canvas; }
- wordWrap = (wordWrap === undefined || wordWrap === null) ? style.wordWrap : wordWrap;
- var font = style.toFontString();
- var fontProperties = TextMetrics.measureFont(font);
- // fallback in case UA disallow canvas data extraction
- // (toDataURI, getImageData functions)
- if (fontProperties.fontSize === 0) {
- fontProperties.fontSize = style.fontSize;
- fontProperties.ascent = style.fontSize;
- }
- var context = canvas.getContext('2d', contextSettings);
- context.font = font;
- var outputText = wordWrap ? TextMetrics.wordWrap(text, style, canvas) : text;
- var lines = outputText.split(/(?:\r\n|\r|\n)/);
- var lineWidths = new Array(lines.length);
- var maxLineWidth = 0;
- for (var i = 0; i < lines.length; i++) {
- var lineWidth = context.measureText(lines[i]).width + ((lines[i].length - 1) * style.letterSpacing);
- lineWidths[i] = lineWidth;
- maxLineWidth = Math.max(maxLineWidth, lineWidth);
- }
- var width = maxLineWidth + style.strokeThickness;
- if (style.dropShadow) {
- width += style.dropShadowDistance;
- }
- var lineHeight = style.lineHeight || fontProperties.fontSize + style.strokeThickness;
- var height = Math.max(lineHeight, fontProperties.fontSize + style.strokeThickness)
- + ((lines.length - 1) * (lineHeight + style.leading));
- if (style.dropShadow) {
- height += style.dropShadowDistance;
- }
- return new TextMetrics(text, style, width, height, lines, lineWidths, lineHeight + style.leading, maxLineWidth, fontProperties);
- };
- /**
- * Applies newlines to a string to have it optimally fit into the horizontal
- * bounds set by the Text object's wordWrapWidth property.
- * @param text - String to apply word wrapping to
- * @param style - the style to use when wrapping
- * @param canvas - optional specification of the canvas to use for measuring.
- * @returns New string with new lines applied where required
- */
- TextMetrics.wordWrap = function (text, style, canvas) {
- if (canvas === void 0) { canvas = TextMetrics._canvas; }
- var context = canvas.getContext('2d', contextSettings);
- var width = 0;
- var line = '';
- var lines = '';
- var cache = Object.create(null);
- var letterSpacing = style.letterSpacing, whiteSpace = style.whiteSpace;
- // How to handle whitespaces
- var collapseSpaces = TextMetrics.collapseSpaces(whiteSpace);
- var collapseNewlines = TextMetrics.collapseNewlines(whiteSpace);
- // whether or not spaces may be added to the beginning of lines
- var canPrependSpaces = !collapseSpaces;
- // There is letterSpacing after every char except the last one
- // t_h_i_s_' '_i_s_' '_a_n_' '_e_x_a_m_p_l_e_' '_!
- // so for convenience the above needs to be compared to width + 1 extra letterSpace
- // t_h_i_s_' '_i_s_' '_a_n_' '_e_x_a_m_p_l_e_' '_!_
- // ________________________________________________
- // And then the final space is simply no appended to each line
- var wordWrapWidth = style.wordWrapWidth + letterSpacing;
- // break text into words, spaces and newline chars
- var tokens = TextMetrics.tokenize(text);
- for (var i = 0; i < tokens.length; i++) {
- // get the word, space or newlineChar
- var token = tokens[i];
- // if word is a new line
- if (TextMetrics.isNewline(token)) {
- // keep the new line
- if (!collapseNewlines) {
- lines += TextMetrics.addLine(line);
- canPrependSpaces = !collapseSpaces;
- line = '';
- width = 0;
- continue;
- }
- // if we should collapse new lines
- // we simply convert it into a space
- token = ' ';
- }
- // if we should collapse repeated whitespaces
- if (collapseSpaces) {
- // check both this and the last tokens for spaces
- var currIsBreakingSpace = TextMetrics.isBreakingSpace(token);
- var lastIsBreakingSpace = TextMetrics.isBreakingSpace(line[line.length - 1]);
- if (currIsBreakingSpace && lastIsBreakingSpace) {
- continue;
- }
- }
- // get word width from cache if possible
- var tokenWidth = TextMetrics.getFromCache(token, letterSpacing, cache, context);
- // word is longer than desired bounds
- if (tokenWidth > wordWrapWidth) {
- // if we are not already at the beginning of a line
- if (line !== '') {
- // start newlines for overflow words
- lines += TextMetrics.addLine(line);
- line = '';
- width = 0;
- }
- // break large word over multiple lines
- if (TextMetrics.canBreakWords(token, style.breakWords)) {
- // break word into characters
- var characters = TextMetrics.wordWrapSplit(token);
- // loop the characters
- for (var j = 0; j < characters.length; j++) {
- var char = characters[j];
- var k = 1;
- // we are not at the end of the token
- while (characters[j + k]) {
- var nextChar = characters[j + k];
- var lastChar = char[char.length - 1];
- // should not split chars
- if (!TextMetrics.canBreakChars(lastChar, nextChar, token, j, style.breakWords)) {
- // combine chars & move forward one
- char += nextChar;
- }
- else {
- break;
- }
- k++;
- }
- j += char.length - 1;
- var characterWidth = TextMetrics.getFromCache(char, letterSpacing, cache, context);
- if (characterWidth + width > wordWrapWidth) {
- lines += TextMetrics.addLine(line);
- canPrependSpaces = false;
- line = '';
- width = 0;
- }
- line += char;
- width += characterWidth;
- }
- }
- // run word out of the bounds
- else {
- // if there are words in this line already
- // finish that line and start a new one
- if (line.length > 0) {
- lines += TextMetrics.addLine(line);
- line = '';
- width = 0;
- }
- var isLastToken = i === tokens.length - 1;
- // give it its own line if it's not the end
- lines += TextMetrics.addLine(token, !isLastToken);
- canPrependSpaces = false;
- line = '';
- width = 0;
- }
- }
- // word could fit
- else {
- // word won't fit because of existing words
- // start a new line
- if (tokenWidth + width > wordWrapWidth) {
- // if its a space we don't want it
- canPrependSpaces = false;
- // add a new line
- lines += TextMetrics.addLine(line);
- // start a new line
- line = '';
- width = 0;
- }
- // don't add spaces to the beginning of lines
- if (line.length > 0 || !TextMetrics.isBreakingSpace(token) || canPrependSpaces) {
- // add the word to the current line
- line += token;
- // update width counter
- width += tokenWidth;
- }
- }
- }
- lines += TextMetrics.addLine(line, false);
- return lines;
- };
- /**
- * Convienience function for logging each line added during the wordWrap method.
- * @param line - The line of text to add
- * @param newLine - Add new line character to end
- * @returns A formatted line
- */
- TextMetrics.addLine = function (line, newLine) {
- if (newLine === void 0) { newLine = true; }
- line = TextMetrics.trimRight(line);
- line = (newLine) ? line + "\n" : line;
- return line;
- };
- /**
- * Gets & sets the widths of calculated characters in a cache object
- * @param key - The key
- * @param letterSpacing - The letter spacing
- * @param cache - The cache
- * @param context - The canvas context
- * @returns The from cache.
- */
- TextMetrics.getFromCache = function (key, letterSpacing, cache, context) {
- var width = cache[key];
- if (typeof width !== 'number') {
- var spacing = ((key.length) * letterSpacing);
- width = context.measureText(key).width + spacing;
- cache[key] = width;
- }
- return width;
- };
- /**
- * Determines whether we should collapse breaking spaces.
- * @param whiteSpace - The TextStyle property whiteSpace
- * @returns Should collapse
- */
- TextMetrics.collapseSpaces = function (whiteSpace) {
- return (whiteSpace === 'normal' || whiteSpace === 'pre-line');
- };
- /**
- * Determines whether we should collapse newLine chars.
- * @param whiteSpace - The white space
- * @returns should collapse
- */
- TextMetrics.collapseNewlines = function (whiteSpace) {
- return (whiteSpace === 'normal');
- };
- /**
- * Trims breaking whitespaces from string.
- * @param text - The text
- * @returns Trimmed string
- */
- TextMetrics.trimRight = function (text) {
- if (typeof text !== 'string') {
- return '';
- }
- for (var i = text.length - 1; i >= 0; i--) {
- var char = text[i];
- if (!TextMetrics.isBreakingSpace(char)) {
- break;
- }
- text = text.slice(0, -1);
- }
- return text;
- };
- /**
- * Determines if char is a newline.
- * @param char - The character
- * @returns True if newline, False otherwise.
- */
- TextMetrics.isNewline = function (char) {
- if (typeof char !== 'string') {
- return false;
- }
- return (TextMetrics._newlines.indexOf(char.charCodeAt(0)) >= 0);
- };
- /**
- * Determines if char is a breaking whitespace.
- *
- * It allows one to determine whether char should be a breaking whitespace
- * For example certain characters in CJK langs or numbers.
- * It must return a boolean.
- * @param char - The character
- * @param [_nextChar] - The next character
- * @returns True if whitespace, False otherwise.
- */
- TextMetrics.isBreakingSpace = function (char, _nextChar) {
- if (typeof char !== 'string') {
- return false;
- }
- return (TextMetrics._breakingSpaces.indexOf(char.charCodeAt(0)) >= 0);
- };
- /**
- * Splits a string into words, breaking-spaces and newLine characters
- * @param text - The text
- * @returns A tokenized array
- */
- TextMetrics.tokenize = function (text) {
- var tokens = [];
- var token = '';
- if (typeof text !== 'string') {
- return tokens;
- }
- for (var i = 0; i < text.length; i++) {
- var char = text[i];
- var nextChar = text[i + 1];
- if (TextMetrics.isBreakingSpace(char, nextChar) || TextMetrics.isNewline(char)) {
- if (token !== '') {
- tokens.push(token);
- token = '';
- }
- tokens.push(char);
- continue;
- }
- token += char;
- }
- if (token !== '') {
- tokens.push(token);
- }
- return tokens;
- };
- /**
- * Overridable helper method used internally by TextMetrics, exposed to allow customizing the class's behavior.
- *
- * It allows one to customise which words should break
- * Examples are if the token is CJK or numbers.
- * It must return a boolean.
- * @param _token - The token
- * @param breakWords - The style attr break words
- * @returns Whether to break word or not
- */
- TextMetrics.canBreakWords = function (_token, breakWords) {
- return breakWords;
- };
- /**
- * Overridable helper method used internally by TextMetrics, exposed to allow customizing the class's behavior.
- *
- * It allows one to determine whether a pair of characters
- * should be broken by newlines
- * For example certain characters in CJK langs or numbers.
- * It must return a boolean.
- * @param _char - The character
- * @param _nextChar - The next character
- * @param _token - The token/word the characters are from
- * @param _index - The index in the token of the char
- * @param _breakWords - The style attr break words
- * @returns whether to break word or not
- */
- TextMetrics.canBreakChars = function (_char, _nextChar, _token, _index, _breakWords) {
- return true;
- };
- /**
- * Overridable helper method used internally by TextMetrics, exposed to allow customizing the class's behavior.
- *
- * It is called when a token (usually a word) has to be split into separate pieces
- * in order to determine the point to break a word.
- * It must return an array of characters.
- * @example
- * // Correctly splits emojis, eg "🤪🤪" will result in two element array, each with one emoji.
- * TextMetrics.wordWrapSplit = (token) => [...token];
- * @param token - The token to split
- * @returns The characters of the token
- */
- TextMetrics.wordWrapSplit = function (token) {
- return token.split('');
- };
- /**
- * Calculates the ascent, descent and fontSize of a given font-style
- * @param font - String representing the style of the font
- * @returns Font properties object
- */
- TextMetrics.measureFont = function (font) {
- // as this method is used for preparing assets, don't recalculate things if we don't need to
- if (TextMetrics._fonts[font]) {
- return TextMetrics._fonts[font];
- }
- var properties = {
- ascent: 0,
- descent: 0,
- fontSize: 0,
- };
- var canvas = TextMetrics._canvas;
- var context = TextMetrics._context;
- context.font = font;
- var metricsString = TextMetrics.METRICS_STRING + TextMetrics.BASELINE_SYMBOL;
- var width = Math.ceil(context.measureText(metricsString).width);
- var baseline = Math.ceil(context.measureText(TextMetrics.BASELINE_SYMBOL).width);
- var height = Math.ceil(TextMetrics.HEIGHT_MULTIPLIER * baseline);
- baseline = baseline * TextMetrics.BASELINE_MULTIPLIER | 0;
- canvas.width = width;
- canvas.height = height;
- context.fillStyle = '#f00';
- context.fillRect(0, 0, width, height);
- context.font = font;
- context.textBaseline = 'alphabetic';
- context.fillStyle = '#000';
- context.fillText(metricsString, 0, baseline);
- var imagedata = context.getImageData(0, 0, width, height).data;
- var pixels = imagedata.length;
- var line = width * 4;
- var i = 0;
- var idx = 0;
- var stop = false;
- // ascent. scan from top to bottom until we find a non red pixel
- for (i = 0; i < baseline; ++i) {
- for (var j = 0; j < line; j += 4) {
- if (imagedata[idx + j] !== 255) {
- stop = true;
- break;
- }
- }
- if (!stop) {
- idx += line;
- }
- else {
- break;
- }
- }
- properties.ascent = baseline - i;
- idx = pixels - line;
- stop = false;
- // descent. scan from bottom to top until we find a non red pixel
- for (i = height; i > baseline; --i) {
- for (var j = 0; j < line; j += 4) {
- if (imagedata[idx + j] !== 255) {
- stop = true;
- break;
- }
- }
- if (!stop) {
- idx -= line;
- }
- else {
- break;
- }
- }
- properties.descent = i - baseline;
- properties.fontSize = properties.ascent + properties.descent;
- TextMetrics._fonts[font] = properties;
- return properties;
- };
- /**
- * Clear font metrics in metrics cache.
- * @param {string} [font] - font name. If font name not set then clear cache for all fonts.
- */
- TextMetrics.clearMetrics = function (font) {
- if (font === void 0) { font = ''; }
- if (font) {
- delete TextMetrics._fonts[font];
- }
- else {
- TextMetrics._fonts = {};
- }
- };
- Object.defineProperty(TextMetrics, "_canvas", {
- /**
- * Cached canvas element for measuring text
- * TODO: this should be private, but isn't because of backward compat, will fix later.
- * @ignore
- */
- get: function () {
- if (!TextMetrics.__canvas) {
- var canvas = void 0;
- try {
- // OffscreenCanvas2D measureText can be up to 40% faster.
- var c = new OffscreenCanvas(0, 0);
- var context = c.getContext('2d', contextSettings);
- if (context && context.measureText) {
- TextMetrics.__canvas = c;
- return c;
- }
- canvas = settings.settings.ADAPTER.createCanvas();
- }
- catch (ex) {
- canvas = settings.settings.ADAPTER.createCanvas();
- }
- canvas.width = canvas.height = 10;
- TextMetrics.__canvas = canvas;
- }
- return TextMetrics.__canvas;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(TextMetrics, "_context", {
- /**
- * TODO: this should be private, but isn't because of backward compat, will fix later.
- * @ignore
- */
- get: function () {
- if (!TextMetrics.__context) {
- TextMetrics.__context = TextMetrics._canvas.getContext('2d', contextSettings);
- }
- return TextMetrics.__context;
- },
- enumerable: false,
- configurable: true
- });
- return TextMetrics;
- }());
- /**
- * Internal return object for {@link PIXI.TextMetrics.measureFont `TextMetrics.measureFont`}.
- * @typedef {object} FontMetrics
- * @property {number} ascent - The ascent distance
- * @property {number} descent - The descent distance
- * @property {number} fontSize - Font size from ascent to descent
- * @memberof PIXI.TextMetrics
- * @private
- */
- /**
- * Cache of {@see PIXI.TextMetrics.FontMetrics} objects.
- * @memberof PIXI.TextMetrics
- * @type {object}
- * @private
- */
- TextMetrics._fonts = {};
- /**
- * String used for calculate font metrics.
- * These characters are all tall to help calculate the height required for text.
- * @static
- * @memberof PIXI.TextMetrics
- * @name METRICS_STRING
- * @type {string}
- * @default |ÉqÅ
- */
- TextMetrics.METRICS_STRING = '|ÉqÅ';
- /**
- * Baseline symbol for calculate font metrics.
- * @static
- * @memberof PIXI.TextMetrics
- * @name BASELINE_SYMBOL
- * @type {string}
- * @default M
- */
- TextMetrics.BASELINE_SYMBOL = 'M';
- /**
- * Baseline multiplier for calculate font metrics.
- * @static
- * @memberof PIXI.TextMetrics
- * @name BASELINE_MULTIPLIER
- * @type {number}
- * @default 1.4
- */
- TextMetrics.BASELINE_MULTIPLIER = 1.4;
- /**
- * Height multiplier for setting height of canvas to calculate font metrics.
- * @static
- * @memberof PIXI.TextMetrics
- * @name HEIGHT_MULTIPLIER
- * @type {number}
- * @default 2.00
- */
- TextMetrics.HEIGHT_MULTIPLIER = 2.0;
- /**
- * Cache of new line chars.
- * @memberof PIXI.TextMetrics
- * @type {number[]}
- * @private
- */
- TextMetrics._newlines = [
- 0x000A,
- 0x000D ];
- /**
- * Cache of breaking spaces.
- * @memberof PIXI.TextMetrics
- * @type {number[]}
- * @private
- */
- TextMetrics._breakingSpaces = [
- 0x0009,
- 0x0020,
- 0x2000,
- 0x2001,
- 0x2002,
- 0x2003,
- 0x2004,
- 0x2005,
- 0x2006,
- 0x2008,
- 0x2009,
- 0x200A,
- 0x205F,
- 0x3000 ];
- /**
- * A number, or a string containing a number.
- * @memberof PIXI
- * @typedef {object} IFontMetrics
- * @property {number} ascent - Font ascent
- * @property {number} descent - Font descent
- * @property {number} fontSize - Font size
- */
- var defaultDestroyOptions = {
- texture: true,
- children: false,
- baseTexture: true,
- };
- /**
- * A Text Object will create a line or multiple lines of text.
- *
- * The text is created using the [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API).
- *
- * The primary advantage of this class over BitmapText is that you have great control over the style of the text,
- * which you can change at runtime.
- *
- * The primary disadvantages is that each piece of text has it's own texture, which can use more memory.
- * When text changes, this texture has to be re-generated and re-uploaded to the GPU, taking up time.
- *
- * To split a line you can use '\n' in your text string, or, on the `style` object,
- * change its `wordWrap` property to true and and give the `wordWrapWidth` property a value.
- *
- * A Text can be created directly from a string and a style object,
- * which can be generated [here](https://pixijs.io/pixi-text-style).
- *
- * ```js
- * let text = new PIXI.Text('This is a PixiJS text',{fontFamily : 'Arial', fontSize: 24, fill : 0xff1010, align : 'center'});
- * ```
- * @memberof PIXI
- */
- var Text = /** @class */ (function (_super) {
- __extends(Text, _super);
- /**
- * @param text - The string that you would like the text to display
- * @param {object|PIXI.TextStyle} [style] - The style parameters
- * @param canvas - The canvas element for drawing text
- */
- function Text(text, style, canvas) {
- var _this = this;
- var ownCanvas = false;
- if (!canvas) {
- canvas = settings.settings.ADAPTER.createCanvas();
- ownCanvas = true;
- }
- canvas.width = 3;
- canvas.height = 3;
- var texture = core.Texture.from(canvas);
- texture.orig = new math.Rectangle();
- texture.trim = new math.Rectangle();
- _this = _super.call(this, texture) || this;
- _this._ownCanvas = ownCanvas;
- _this.canvas = canvas;
- _this.context = canvas.getContext('2d', {
- // required for trimming to work without warnings
- willReadFrequently: true,
- });
- _this._resolution = settings.settings.RESOLUTION;
- _this._autoResolution = true;
- _this._text = null;
- _this._style = null;
- _this._styleListener = null;
- _this._font = '';
- _this.text = text;
- _this.style = style;
- _this.localStyleID = -1;
- return _this;
- }
- /**
- * Renders text to its canvas, and updates its texture.
- *
- * By default this is used internally to ensure the texture is correct before rendering,
- * but it can be used called externally, for example from this class to 'pre-generate' the texture from a piece of text,
- * and then shared across multiple Sprites.
- * @param respectDirty - Whether to abort updating the text if the Text isn't dirty and the function is called.
- */
- Text.prototype.updateText = function (respectDirty) {
- var style = this._style;
- // check if style has changed..
- if (this.localStyleID !== style.styleID) {
- this.dirty = true;
- this.localStyleID = style.styleID;
- }
- if (!this.dirty && respectDirty) {
- return;
- }
- this._font = this._style.toFontString();
- var context = this.context;
- var measured = TextMetrics.measureText(this._text || ' ', this._style, this._style.wordWrap, this.canvas);
- var width = measured.width;
- var height = measured.height;
- var lines = measured.lines;
- var lineHeight = measured.lineHeight;
- var lineWidths = measured.lineWidths;
- var maxLineWidth = measured.maxLineWidth;
- var fontProperties = measured.fontProperties;
- this.canvas.width = Math.ceil(Math.ceil((Math.max(1, width) + (style.padding * 2))) * this._resolution);
- this.canvas.height = Math.ceil(Math.ceil((Math.max(1, height) + (style.padding * 2))) * this._resolution);
- context.scale(this._resolution, this._resolution);
- context.clearRect(0, 0, this.canvas.width, this.canvas.height);
- context.font = this._font;
- context.lineWidth = style.strokeThickness;
- context.textBaseline = style.textBaseline;
- context.lineJoin = style.lineJoin;
- context.miterLimit = style.miterLimit;
- var linePositionX;
- var linePositionY;
- // require 2 passes if a shadow; the first to draw the drop shadow, the second to draw the text
- var passesCount = style.dropShadow ? 2 : 1;
- // For v4, we drew text at the colours of the drop shadow underneath the normal text. This gave the correct zIndex,
- // but features such as alpha and shadowblur did not look right at all, since we were using actual text as a shadow.
- //
- // For v5.0.0, we moved over to just use the canvas API for drop shadows, which made them look much nicer and more
- // visually please, but now because the stroke is drawn and then the fill, drop shadows would appear on both the fill
- // and the stroke; and fill drop shadows would appear over the top of the stroke.
- //
- // For v5.1.1, the new route is to revert to v4 style of drawing text first to get the drop shadows underneath normal
- // text, but instead drawing text in the correct location, we'll draw it off screen (-paddingY), and then adjust the
- // drop shadow so only that appears on screen (+paddingY). Now we'll have the correct draw order of the shadow
- // beneath the text, whilst also having the proper text shadow styling.
- for (var i = 0; i < passesCount; ++i) {
- var isShadowPass = style.dropShadow && i === 0;
- // we only want the drop shadow, so put text way off-screen
- var dsOffsetText = isShadowPass ? Math.ceil(Math.max(1, height) + (style.padding * 2)) : 0;
- var dsOffsetShadow = dsOffsetText * this._resolution;
- if (isShadowPass) {
- // On Safari, text with gradient and drop shadows together do not position correctly
- // if the scale of the canvas is not 1: https://bugs.webkit.org/show_bug.cgi?id=197689
- // Therefore we'll set the styles to be a plain black whilst generating this drop shadow
- context.fillStyle = 'black';
- context.strokeStyle = 'black';
- var dropShadowColor = style.dropShadowColor;
- var rgb = utils.hex2rgb(typeof dropShadowColor === 'number' ? dropShadowColor : utils.string2hex(dropShadowColor));
- var dropShadowBlur = style.dropShadowBlur * this._resolution;
- var dropShadowDistance = style.dropShadowDistance * this._resolution;
- context.shadowColor = "rgba(" + rgb[0] * 255 + "," + rgb[1] * 255 + "," + rgb[2] * 255 + "," + style.dropShadowAlpha + ")";
- context.shadowBlur = dropShadowBlur;
- context.shadowOffsetX = Math.cos(style.dropShadowAngle) * dropShadowDistance;
- context.shadowOffsetY = (Math.sin(style.dropShadowAngle) * dropShadowDistance) + dsOffsetShadow;
- }
- else {
- // set canvas text styles
- context.fillStyle = this._generateFillStyle(style, lines, measured);
- // TODO: Can't have different types for getter and setter. The getter shouldn't have the number type as
- // the setter converts to string. See this thread for more details:
- // https://github.com/microsoft/TypeScript/issues/2521
- context.strokeStyle = style.stroke;
- context.shadowColor = 'black';
- context.shadowBlur = 0;
- context.shadowOffsetX = 0;
- context.shadowOffsetY = 0;
- }
- var linePositionYShift = (lineHeight - fontProperties.fontSize) / 2;
- if (!Text.nextLineHeightBehavior || lineHeight - fontProperties.fontSize < 0) {
- linePositionYShift = 0;
- }
- // draw lines line by line
- for (var i_1 = 0; i_1 < lines.length; i_1++) {
- linePositionX = style.strokeThickness / 2;
- linePositionY = ((style.strokeThickness / 2) + (i_1 * lineHeight)) + fontProperties.ascent
- + linePositionYShift;
- if (style.align === 'right') {
- linePositionX += maxLineWidth - lineWidths[i_1];
- }
- else if (style.align === 'center') {
- linePositionX += (maxLineWidth - lineWidths[i_1]) / 2;
- }
- if (style.stroke && style.strokeThickness) {
- this.drawLetterSpacing(lines[i_1], linePositionX + style.padding, linePositionY + style.padding - dsOffsetText, true);
- }
- if (style.fill) {
- this.drawLetterSpacing(lines[i_1], linePositionX + style.padding, linePositionY + style.padding - dsOffsetText);
- }
- }
- }
- this.updateTexture();
- };
- /**
- * Render the text with letter-spacing.
- * @param text - The text to draw
- * @param x - Horizontal position to draw the text
- * @param y - Vertical position to draw the text
- * @param isStroke - Is this drawing for the outside stroke of the
- * text? If not, it's for the inside fill
- */
- Text.prototype.drawLetterSpacing = function (text, x, y, isStroke) {
- if (isStroke === void 0) { isStroke = false; }
- var style = this._style;
- // letterSpacing of 0 means normal
- var letterSpacing = style.letterSpacing;
- // Checking that we can use moddern canvas2D api
- // https://developer.chrome.com/origintrials/#/view_trial/3585991203293757441
- // note: this is unstable API, Chrome less 94 use a `textLetterSpacing`, newest use a letterSpacing
- // eslint-disable-next-line max-len
- var supportLetterSpacing = Text.experimentalLetterSpacing
- && ('letterSpacing' in CanvasRenderingContext2D.prototype
- || 'textLetterSpacing' in CanvasRenderingContext2D.prototype);
- if (letterSpacing === 0 || supportLetterSpacing) {
- if (supportLetterSpacing) {
- this.context.letterSpacing = letterSpacing;
- this.context.textLetterSpacing = letterSpacing;
- }
- if (isStroke) {
- this.context.strokeText(text, x, y);
- }
- else {
- this.context.fillText(text, x, y);
- }
- return;
- }
- var currentPosition = x;
- // Using Array.from correctly splits characters whilst keeping emoji together.
- // This is not supported on IE as it requires ES6, so regular text splitting occurs.
- // This also doesn't account for emoji that are multiple emoji put together to make something else.
- // Handling all of this would require a big library itself.
- // https://medium.com/@giltayar/iterating-over-emoji-characters-the-es6-way-f06e4589516
- // https://github.com/orling/grapheme-splitter
- var stringArray = Array.from ? Array.from(text) : text.split('');
- var previousWidth = this.context.measureText(text).width;
- var currentWidth = 0;
- for (var i = 0; i < stringArray.length; ++i) {
- var currentChar = stringArray[i];
- if (isStroke) {
- this.context.strokeText(currentChar, currentPosition, y);
- }
- else {
- this.context.fillText(currentChar, currentPosition, y);
- }
- var textStr = '';
- for (var j = i + 1; j < stringArray.length; ++j) {
- textStr += stringArray[j];
- }
- currentWidth = this.context.measureText(textStr).width;
- currentPosition += previousWidth - currentWidth + letterSpacing;
- previousWidth = currentWidth;
- }
- };
- /** Updates texture size based on canvas size. */
- Text.prototype.updateTexture = function () {
- var canvas = this.canvas;
- if (this._style.trim) {
- var trimmed = utils.trimCanvas(canvas);
- if (trimmed.data) {
- canvas.width = trimmed.width;
- canvas.height = trimmed.height;
- this.context.putImageData(trimmed.data, 0, 0);
- }
- }
- var texture = this._texture;
- var style = this._style;
- var padding = style.trim ? 0 : style.padding;
- var baseTexture = texture.baseTexture;
- texture.trim.width = texture._frame.width = canvas.width / this._resolution;
- texture.trim.height = texture._frame.height = canvas.height / this._resolution;
- texture.trim.x = -padding;
- texture.trim.y = -padding;
- texture.orig.width = texture._frame.width - (padding * 2);
- texture.orig.height = texture._frame.height - (padding * 2);
- // call sprite onTextureUpdate to update scale if _width or _height were set
- this._onTextureUpdate();
- baseTexture.setRealSize(canvas.width, canvas.height, this._resolution);
- texture.updateUvs();
- this.dirty = false;
- };
- /**
- * Renders the object using the WebGL renderer
- * @param renderer - The renderer
- */
- Text.prototype._render = function (renderer) {
- if (this._autoResolution && this._resolution !== renderer.resolution) {
- this._resolution = renderer.resolution;
- this.dirty = true;
- }
- this.updateText(true);
- _super.prototype._render.call(this, renderer);
- };
- /** Updates the transform on all children of this container for rendering. */
- Text.prototype.updateTransform = function () {
- this.updateText(true);
- _super.prototype.updateTransform.call(this);
- };
- Text.prototype.getBounds = function (skipUpdate, rect) {
- this.updateText(true);
- if (this._textureID === -1) {
- // texture was updated: recalculate transforms
- skipUpdate = false;
- }
- return _super.prototype.getBounds.call(this, skipUpdate, rect);
- };
- /**
- * Gets the local bounds of the text object.
- * @param rect - The output rectangle.
- * @returns The bounds.
- */
- Text.prototype.getLocalBounds = function (rect) {
- this.updateText(true);
- return _super.prototype.getLocalBounds.call(this, rect);
- };
- /** Calculates the bounds of the Text as a rectangle. The bounds calculation takes the worldTransform into account. */
- Text.prototype._calculateBounds = function () {
- this.calculateVertices();
- // if we have already done this on THIS frame.
- this._bounds.addQuad(this.vertexData);
- };
- /**
- * Generates the fill style. Can automatically generate a gradient based on the fill style being an array
- * @param style - The style.
- * @param lines - The lines of text.
- * @param metrics
- * @returns The fill style
- */
- Text.prototype._generateFillStyle = function (style, lines, metrics) {
- // TODO: Can't have different types for getter and setter. The getter shouldn't have the number type as
- // the setter converts to string. See this thread for more details:
- // https://github.com/microsoft/TypeScript/issues/2521
- var fillStyle = style.fill;
- if (!Array.isArray(fillStyle)) {
- return fillStyle;
- }
- else if (fillStyle.length === 1) {
- return fillStyle[0];
- }
- // the gradient will be evenly spaced out according to how large the array is.
- // ['#FF0000', '#00FF00', '#0000FF'] would created stops at 0.25, 0.5 and 0.75
- var gradient;
- // a dropshadow will enlarge the canvas and result in the gradient being
- // generated with the incorrect dimensions
- var dropShadowCorrection = (style.dropShadow) ? style.dropShadowDistance : 0;
- // should also take padding into account, padding can offset the gradient
- var padding = style.padding || 0;
- var width = (this.canvas.width / this._resolution) - dropShadowCorrection - (padding * 2);
- var height = (this.canvas.height / this._resolution) - dropShadowCorrection - (padding * 2);
- // make a copy of the style settings, so we can manipulate them later
- var fill = fillStyle.slice();
- var fillGradientStops = style.fillGradientStops.slice();
- // wanting to evenly distribute the fills. So an array of 4 colours should give fills of 0.25, 0.5 and 0.75
- if (!fillGradientStops.length) {
- var lengthPlus1 = fill.length + 1;
- for (var i = 1; i < lengthPlus1; ++i) {
- fillGradientStops.push(i / lengthPlus1);
- }
- }
- // stop the bleeding of the last gradient on the line above to the top gradient of the this line
- // by hard defining the first gradient colour at point 0, and last gradient colour at point 1
- fill.unshift(fillStyle[0]);
- fillGradientStops.unshift(0);
- fill.push(fillStyle[fillStyle.length - 1]);
- fillGradientStops.push(1);
- if (style.fillGradientType === exports.TEXT_GRADIENT.LINEAR_VERTICAL) {
- // start the gradient at the top center of the canvas, and end at the bottom middle of the canvas
- gradient = this.context.createLinearGradient(width / 2, padding, width / 2, height + padding);
- // we need to repeat the gradient so that each individual line of text has the same vertical gradient effect
- // ['#FF0000', '#00FF00', '#0000FF'] over 2 lines would create stops at 0.125, 0.25, 0.375, 0.625, 0.75, 0.875
- // Actual height of the text itself, not counting spacing for lineHeight/leading/dropShadow etc
- var textHeight = metrics.fontProperties.fontSize + style.strokeThickness;
- for (var i = 0; i < lines.length; i++) {
- var lastLineBottom = (metrics.lineHeight * (i - 1)) + textHeight;
- var thisLineTop = metrics.lineHeight * i;
- var thisLineGradientStart = thisLineTop;
- // Handle case where last & this line overlap
- if (i > 0 && lastLineBottom > thisLineTop) {
- thisLineGradientStart = (thisLineTop + lastLineBottom) / 2;
- }
- var thisLineBottom = thisLineTop + textHeight;
- var nextLineTop = metrics.lineHeight * (i + 1);
- var thisLineGradientEnd = thisLineBottom;
- // Handle case where this & next line overlap
- if (i + 1 < lines.length && nextLineTop < thisLineBottom) {
- thisLineGradientEnd = (thisLineBottom + nextLineTop) / 2;
- }
- // textHeight, but as a 0-1 size in global gradient stop space
- var gradStopLineHeight = (thisLineGradientEnd - thisLineGradientStart) / height;
- for (var j = 0; j < fill.length; j++) {
- // 0-1 stop point for the current line, multiplied to global space afterwards
- var lineStop = 0;
- if (typeof fillGradientStops[j] === 'number') {
- lineStop = fillGradientStops[j];
- }
- else {
- lineStop = j / fill.length;
- }
- var globalStop = Math.min(1, Math.max(0, (thisLineGradientStart / height) + (lineStop * gradStopLineHeight)));
- // There's potential for floating point precision issues at the seams between gradient repeats.
- globalStop = Number(globalStop.toFixed(5));
- gradient.addColorStop(globalStop, fill[j]);
- }
- }
- }
- else {
- // start the gradient at the center left of the canvas, and end at the center right of the canvas
- gradient = this.context.createLinearGradient(padding, height / 2, width + padding, height / 2);
- // can just evenly space out the gradients in this case, as multiple lines makes no difference
- // to an even left to right gradient
- var totalIterations = fill.length + 1;
- var currentIteration = 1;
- for (var i = 0; i < fill.length; i++) {
- var stop = void 0;
- if (typeof fillGradientStops[i] === 'number') {
- stop = fillGradientStops[i];
- }
- else {
- stop = currentIteration / totalIterations;
- }
- gradient.addColorStop(stop, fill[i]);
- currentIteration++;
- }
- }
- return gradient;
- };
- /**
- * Destroys this text object.
- *
- * Note* Unlike a Sprite, a Text object will automatically destroy its baseTexture and texture as
- * the majority of the time the texture will not be shared with any other Sprites.
- * @param options - Options parameter. A boolean will act as if all options
- * have been set to that value
- * @param {boolean} [options.children=false] - if set to true, all the children will have their
- * destroy method called as well. 'options' will be passed on to those calls.
- * @param {boolean} [options.texture=true] - Should it destroy the current texture of the sprite as well
- * @param {boolean} [options.baseTexture=true] - Should it destroy the base texture of the sprite as well
- */
- Text.prototype.destroy = function (options) {
- if (typeof options === 'boolean') {
- options = { children: options };
- }
- options = Object.assign({}, defaultDestroyOptions, options);
- _super.prototype.destroy.call(this, options);
- // set canvas width and height to 0 to workaround memory leak in Safari < 13
- // https://stackoverflow.com/questions/52532614/total-canvas-memory-use-exceeds-the-maximum-limit-safari-12
- if (this._ownCanvas) {
- this.canvas.height = this.canvas.width = 0;
- }
- // make sure to reset the context and canvas.. dont want this hanging around in memory!
- this.context = null;
- this.canvas = null;
- this._style = null;
- };
- Object.defineProperty(Text.prototype, "width", {
- /** The width of the Text, setting this will actually modify the scale to achieve the value set. */
- get: function () {
- this.updateText(true);
- return Math.abs(this.scale.x) * this._texture.orig.width;
- },
- set: function (value) {
- this.updateText(true);
- var s = utils.sign(this.scale.x) || 1;
- this.scale.x = s * value / this._texture.orig.width;
- this._width = value;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(Text.prototype, "height", {
- /** The height of the Text, setting this will actually modify the scale to achieve the value set. */
- get: function () {
- this.updateText(true);
- return Math.abs(this.scale.y) * this._texture.orig.height;
- },
- set: function (value) {
- this.updateText(true);
- var s = utils.sign(this.scale.y) || 1;
- this.scale.y = s * value / this._texture.orig.height;
- this._height = value;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(Text.prototype, "style", {
- /**
- * Set the style of the text.
- *
- * Set up an event listener to listen for changes on the style object and mark the text as dirty.
- */
- get: function () {
- // TODO: Can't have different types for getter and setter. The getter shouldn't have the ITextStyle
- // since the setter creates the TextStyle. See this thread for more details:
- // https://github.com/microsoft/TypeScript/issues/2521
- return this._style;
- },
- set: function (style) {
- style = style || {};
- if (style instanceof TextStyle) {
- this._style = style;
- }
- else {
- this._style = new TextStyle(style);
- }
- this.localStyleID = -1;
- this.dirty = true;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(Text.prototype, "text", {
- /** Set the copy for the text object. To split a line you can use '\n'. */
- get: function () {
- return this._text;
- },
- set: function (text) {
- text = String(text === null || text === undefined ? '' : text);
- if (this._text === text) {
- return;
- }
- this._text = text;
- this.dirty = true;
- },
- enumerable: false,
- configurable: true
- });
- Object.defineProperty(Text.prototype, "resolution", {
- /**
- * The resolution / device pixel ratio of the canvas.
- *
- * This is set to automatically match the renderer resolution by default, but can be overridden by setting manually.
- * @default 1
- */
- get: function () {
- return this._resolution;
- },
- set: function (value) {
- this._autoResolution = false;
- if (this._resolution === value) {
- return;
- }
- this._resolution = value;
- this.dirty = true;
- },
- enumerable: false,
- configurable: true
- });
- /**
- * New behavior for `lineHeight` that's meant to mimic HTML text. A value of `true` will
- * make sure the first baseline is offset by the `lineHeight` value if it is greater than `fontSize`.
- * A value of `false` will use the legacy behavior and not change the baseline of the first line.
- * In the next major release, we'll enable this by default.
- */
- Text.nextLineHeightBehavior = false;
- /**
- * New rendering behavior for letter-spacing which uses Chrome's new native API. This will
- * lead to more accurate letter-spacing results because it does not try to manually draw
- * each character. However, this Chrome API is experimental and may not serve all cases yet.
- */
- Text.experimentalLetterSpacing = false;
- return Text;
- }(sprite.Sprite));
- exports.Text = Text;
- exports.TextMetrics = TextMetrics;
- exports.TextStyle = TextStyle;
- //# sourceMappingURL=text.js.map
|