/* * BitmapText * Visit http://createjs.com/ for documentation, updates and examples. * * Copyright (c) 2010 gskinner.com, inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ this.createjs = this.createjs || {}; (function () { "use strict"; // constructor: /** * Displays text using bitmap glyphs defined in a sprite sheet. Multi-line text is supported using new line characters, * but automatic wrapping is not supported. See the {{#crossLink "BitmapText/spriteSheet:property"}}{{/crossLink}} * property for more information on defining glyphs. * * <strong>Important:</strong> While BitmapText extends Container, it is not designed to be used as one. * As such, methods like addChild and removeChild are disabled. * * * @class BitmapText * @extends DisplayObject * @param {String} [text=""] The text to display. * @param {SpriteSheet} [spriteSheet=null] The spritesheet that defines the character glyphs. * @constructor **/ function BitmapText(text, spriteSheet) { this.Container_constructor(); // public properties: /** * The text to display. * @property text * @type String * @default "" **/ this.text = text||""; /** * A SpriteSheet instance that defines the glyphs for this bitmap text. Each glyph/character * should have a single frame animation defined in the sprite sheet named the same as * corresponding character. For example, the following animation definition: * * "A": {frames: [0]} * * would indicate that the frame at index 0 of the spritesheet should be drawn for the "A" character. The short form * is also acceptable: * * "A": 0 * * Note that if a character in the text is not found in the sprite sheet, it will also * try to use the alternate case (upper or lower). * * See SpriteSheet for more information on defining sprite sheet data. * @property spriteSheet * @type SpriteSheet * @default null **/ this.spriteSheet = spriteSheet; /** * The height of each line of text. If 0, then it will use a line height calculated * by checking for the height of the "1", "T", or "L" character (in that order). If * those characters are not defined, it will use the height of the first frame of the * sprite sheet. * @property lineHeight * @type Number * @default 0 **/ this.lineHeight = 0; /** * This spacing (in pixels) will be added after each character in the output. * @property letterSpacing * @type Number * @default 0 **/ this.letterSpacing = 0; /** * If a space character is not defined in the sprite sheet, then empty pixels equal to * spaceWidth will be inserted instead. If 0, then it will use a value calculated * by checking for the width of the "1", "l", "E", or "A" character (in that order). If * those characters are not defined, it will use the width of the first frame of the * sprite sheet. * @property spaceWidth * @type Number * @default 0 **/ this.spaceWidth = 0; // private properties: /** * @property _oldProps * @type Object * @protected **/ this._oldProps = {text:0,spriteSheet:0,lineHeight:0,letterSpacing:0,spaceWidth:0}; /** * Used to track the object which this class attached listeners to, helps optimize listener attachment. * @property _oldStage * @type Stage * @protected */ this._oldStage = null; /** * The event listener proxy triggered drawing draw for special circumstances. * @property _drawAction * @type function * @protected */ this._drawAction = null; } var p = createjs.extend(BitmapText, createjs.Container); // static properties: /** * BitmapText uses Sprite instances to draw text. To reduce the creation and destruction of instances (and thus garbage collection), it maintains * an internal object pool of sprite instances to reuse. Increasing this value can cause more sprites to be * retained, slightly increasing memory use, but reducing instantiation. * @property maxPoolSize * @type Number * @static * @default 100 **/ BitmapText.maxPoolSize = 100; /** * Sprite object pool. * @property _spritePool * @type {Array} * @static * @private */ BitmapText._spritePool = []; // public methods: // Docced in superclass p.draw = function(ctx, ignoreCache) { if (this.DisplayObject_draw(ctx, ignoreCache)) { return; } this._updateState(); this.Container_draw(ctx, ignoreCache); }; // Docced in superclass p.getBounds = function() { this._updateText(); return this.Container_getBounds(); }; /** * Returns true or false indicating whether the display object would be visible if drawn to a canvas. * This does not account for whether it would be visible within the boundaries of the stage. * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. * @method isVisible * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas **/ p.isVisible = function() { var hasContent = this.cacheCanvas || (this.spriteSheet && this.spriteSheet.complete && this.text); return !!(this.visible && this.alpha > 0 && this.scaleX !== 0 && this.scaleY !== 0 && hasContent); }; p.clone = function() { return this._cloneProps(new BitmapText(this.text, this.spriteSheet)); }; /** * <strong>Disabled in BitmapText.</strong> * @method addChild **/ /** * <strong>Disabled in BitmapText.</strong> * @method addChildAt **/ /** * <strong>Disabled in BitmapText.</strong> * @method removeChild **/ /** * <strong>Disabled in BitmapText.</strong> * @method removeChildAt **/ /** * <strong>Disabled in BitmapText.</strong> * @method removeAllChildren **/ p.addChild = p.addChildAt = p.removeChild = p.removeChildAt = p.removeAllChildren = function() {}; // private methods: // Docced in superclass p._updateState = function() { this._updateText(); }; /** * @method _cloneProps * @param {BitmapText} o * @return {BitmapText} o * @protected **/ p._cloneProps = function(o) { this.Container__cloneProps(o); o.lineHeight = this.lineHeight; o.letterSpacing = this.letterSpacing; o.spaceWidth = this.spaceWidth; return o; }; /** * @method _getFrameIndex * @param {String} character * @param {SpriteSheet} spriteSheet * @return {Number} * @protected **/ p._getFrameIndex = function(character, spriteSheet) { var c, o = spriteSheet.getAnimation(character); if (!o) { (character != (c = character.toUpperCase())) || (character != (c = character.toLowerCase())) || (c=null); if (c) { o = spriteSheet.getAnimation(c); } } return o && o.frames[0]; }; /** * @method _getFrame * @param {String} character * @param {SpriteSheet} spriteSheet * @return {Object} * @protected **/ p._getFrame = function(character, spriteSheet) { var index = this._getFrameIndex(character, spriteSheet); return index == null ? index : spriteSheet.getFrame(index); }; /** * @method _getLineHeight * @param {SpriteSheet} ss * @return {Number} * @protected **/ p._getLineHeight = function(ss) { var frame = this._getFrame("1",ss) || this._getFrame("T",ss) || this._getFrame("L",ss) || ss.getFrame(0); return frame ? frame.rect.height : 1; }; /** * @method _getSpaceWidth * @param {SpriteSheet} ss * @return {Number} * @protected **/ p._getSpaceWidth = function(ss) { var frame = this._getFrame("1",ss) || this._getFrame("l",ss) || this._getFrame("e",ss) || this._getFrame("a",ss) || ss.getFrame(0); return frame ? frame.rect.width : 1; }; /** * @method _updateText * @protected **/ p._updateText = function() { var x=0, y=0, o=this._oldProps, change=false, spaceW=this.spaceWidth, lineH=this.lineHeight, ss=this.spriteSheet; var pool=BitmapText._spritePool, kids=this.children, childIndex=0, numKids=kids.length, sprite; for (var n in o) { if (o[n] != this[n]) { o[n] = this[n]; change = true; } } if (!change) { return; } var hasSpace = !!this._getFrame(" ", ss); if (!hasSpace && !spaceW) { spaceW = this._getSpaceWidth(ss); } if (!lineH) { lineH = this._getLineHeight(ss); } for(var i=0, l=this.text.length; i<l; i++) { var character = this.text.charAt(i); if (character == " " && !hasSpace) { x += spaceW; continue; } else if (character=="\n" || character=="\r") { if (character=="\r" && this.text.charAt(i+1) == "\n") { i++; } // crlf x = 0; y += lineH; continue; } var index = this._getFrameIndex(character, ss); if (index == null) { continue; } if (childIndex < numKids) { sprite = kids[childIndex]; } else { kids.push(sprite = pool.length ? pool.pop() : new createjs.Sprite()); sprite.parent = this; numKids++; } sprite.spriteSheet = ss; sprite.gotoAndStop(index); sprite.x = x; sprite.y = y; childIndex++; x += sprite.getBounds().width + this.letterSpacing; } while (numKids > childIndex) { // faster than removeChild. pool.push(sprite = kids.pop()); sprite.parent = null; numKids--; } if (pool.length > BitmapText.maxPoolSize) { pool.length = BitmapText.maxPoolSize; } }; createjs.BitmapText = createjs.promote(BitmapText, "Container"); }());