/*////////////////////////////////////////////////////////////////////////////////////////////////////////// Devin Reimer - blog.almostlogical.com - 2010-06-25 (this version was modified to support new version of the library both AS3 1.1 and AS3 FP10 1.0 ) Version: 2.0 based on class DynamicText3D: FIVe3D Flash Interactive Vector-based 3D Mathieu Badimon | five3d@mathieu-badimon.com http://five3D.mathieu-badimon.com | http://five3d.mathieu-badimon.com/archives/ | http://code.google.com/p/five3d/ /*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// package almostlogical.five3d.display { import net.badimon.five3D.typography.Typography3D; import net.badimon.five3D.display.Sprite3D; import net.badimon.five3D.display.Graphics3D; import net.badimon.five3D.display.Shape3D; import flash.geom.ColorTransform; public class DynamicText3DMultiline extends Sprite3D { public static const LEFT:String = "left"; public static const RIGHT:String = "right"; public static const CENTER:String = "center"; private var __text:String = ""; private var __typography:Typography3D; private var __size:Number = 10; private var __color:uint = 0x000000; private var __letterSpacing:Number = 0; private var __lineSpacing:Number = 0; private var __wordWrap:Boolean = false; //if wordwrap is enabled private var __textWidth:Number = 0; //width of display text if word wrap is false, else it is equal to width private var __textHeight:Number = 0; //height the of the text area (selected text height * number of rows) private var __width:Number = 100; //used if wordwrapping is enable to set the max width private var __align:String = LEFT; // Calculation private var __sizeMultiplicator:Number = __size / 100; /** * Creates a new DynamicText3DMultiline instance. * * @param typography the Typography3D object that the DynamicText3D instance uses to display the text. */ public function DynamicText3DMultiline(typography:Typography3D) { __typography = typography; } //---------------------------------------------------------------------------------------------------- // Properties //---------------------------------------------------------------------------------------------------- /** * Indicates the current text of the DynamicText3DMultiline instance. */ public function get text():String { return __text; } public function set text(value:String):void { createGlyphs(value); __text = value; removeAdditionalGlyphs(); placeGlyphs(); } private function createGlyphs(text:String):void { var charOld:String, charNew:String, identical:Boolean = true; var len:int = text.length; for (var i:int = 0;i < len; i++) { charOld = __text.charAt(i); charNew = text.charAt(i); if ((charOld != charNew) || !identical) { createGlyph(i, charNew); identical = false; } } } private function createGlyph(index:Number, char:String):void { var shape:Shape3D = new Shape3D(); shape.graphics3D.addMotif([['B', [__color, 1]]].concat(Graphics3D.clone(__typography.getMotif(char))).concat([['E']])); shape.scaleX = shape.scaleY = __sizeMultiplicator; addChildAt(shape, index); } private function removeAdditionalGlyphs():void { var num:int = numChildren; var len:int = __text.length; for (var i:int = num - 1;i >= len; i--) removeChildAt(i); } //this function has been completely changed by Devin Reimer to allow for Multiline and WordWrap support private function placeGlyphs():void { var horizOffset:Number = 0; var vertOffset:Number = 0; var letterWidth:Number = 0; var letterHeight:Number = __typography.getHeight() * __sizeMultiplicator; var nextWord:String; var nextWordStart:int = 0; var shape:Shape3D; var num:int = numChildren; __textWidth = 0; //reset for (var i:int = 0; i < num; i++) { shape = getChildAt(i) as Shape3D; letterWidth = __typography.getWidth(__text.charAt(i)) * __sizeMultiplicator; nextWord = ""; if (wordWrap) { if (nextWordStart <= i) //if it is now the beginning of the next word { nextWord = getNextWord(i); nextWordStart = i + nextWord.length; if (horizOffset + getWordWidth(nextWord) > width) //premature line break for word wrapping { if (horizOffset > __textWidth) __textWidth = horizOffset; //if this horizoffset is the largest it now is the textwidth alignRow(i-1,horizOffset); horizOffset = 0; vertOffset += letterHeight + (lineSpacing * __sizeMultiplicator); } } if (horizOffset + letterWidth > width) //general line break on letter, helps break words to long for the width { if (horizOffset > __textWidth) __textWidth = horizOffset; //if this horizoffset is the largest it now is the textwidth alignRow(i-1,horizOffset); horizOffset = 0; vertOffset += letterHeight + (__lineSpacing * __sizeMultiplicator); } } if (shape.x != horizOffset) shape.x = horizOffset; if (shape.y != vertOffset) shape.y = vertOffset; horizOffset += letterWidth + (__letterSpacing * __sizeMultiplicator); } horizOffset -= (__letterSpacing * __sizeMultiplicator); //removes final letterspacing from width if (horizOffset > __textWidth) __textWidth = horizOffset; //if this horizoffset is the largest it now is the textwidth __textHeight = vertOffset + letterHeight; alignRow(numChildren - 1, horizOffset); } private function alignRow(lastRowLetter:int,rowHorizWidth:Number):void { var shape:Shape3D; var currentRowY:Number = -1; var rowDiff:Number = width - rowHorizWidth; //the difference between what the desired width is and what the actually row width is if (align != LEFT) //only proceed if not left, it automatically left aligns by default { for (var i = lastRowLetter; i >= 0; i--) { shape = getChildAt(i) as Shape3D; if (currentRowY < 0) { currentRowY = shape.y; } if (currentRowY == shape.y) //moved to a different row { if (align == CENTER) { shape.x += rowDiff / 2; } else if (align == RIGHT) { shape.x += rowDiff; } } else { i = 0; //break out of for loop } } } } //gets a string of the next word including it's trailing puncutation and spaces, // ex: The quick brown fox jumps over the lazy dog, with starting index of 4 would produce 'quick ' private function getNextWord(index:int):String { var nextWord:String = ""; var textLength:int = __text.length; while (index < textLength && __text.charAt(index) != " ") //gets full word { nextWord += __text.charAt(index); index++; } while (index < textLength && __text.charAt(index) == " ") //gets trailing spaces { nextWord += __text.charAt(index); index++; } return nextWord; } public function getWordWidth(word:String):Number { var wordWidth:Number = 0; for (var i:int = 0; i < word.length; i++) { wordWidth += (__typography.getWidth(word.charAt(i)) + __letterSpacing) * __sizeMultiplicator; if (i == word.length - 1) { wordWidth -= (__letterSpacing * __sizeMultiplicator); } } return wordWidth; } /** * Indicates the Typography3D object that the DynamicText3DMultiline instance uses to display the text. */ public function get typography():Typography3D { return __typography; } public function set typography(value:Typography3D):void { __typography = value; reinitText(__text); } private function reinitText(text:String):void { __text = ""; this.text = text; } //useful after tweening or changing letter position to revert to default public function resetLetterPositions():void { placeGlyphs(); } /** * Indicates the text size (in pixels) of the DynamicText3DMultiline instance. */ public function get size():Number { return __size; } public function set size(value:Number):void { __size = value; __sizeMultiplicator = __size / 100; resizeGlyphs(); placeGlyphs(); } private function resizeGlyphs():void { var num:int = numChildren; for (var i:int = 0;i < num; i++) { var shape:Shape3D = getChildAt(i) as Shape3D; shape.scaleX = shape.scaleY = __sizeMultiplicator; } } /** * Indicates the text color of the DynamicText3DMultiline instance. */ public function get color():uint { return __color; } public function set color(value:uint):void { __color = value; colorateGlyphs(); } private function colorateGlyphs():void { var colorTransform:ColorTransform = new ColorTransform(); colorTransform.color = __color; var num:int = numChildren; for (var i:int = 0;i < num; i++) { var shape:Shape3D = getChildAt(i) as Shape3D; shape.transform.colorTransform = colorTransform; } } /** * Indicates the amount of space between every character of the DynamicText3DMultiline instance. */ public function get letterSpacing():Number { return __letterSpacing; } public function set letterSpacing(value:Number):void { __letterSpacing = value; placeGlyphs(); } /** * Indicates the width of the text (in pixels) of the DynamicText3DMultiline instance. */ public function get textWidth():Number { return __textWidth; } /** * Indicates the height of the text (in pixels) of the DynamicText3DMultiline instance. */ public function get textHeight():Number { return __textHeight; } public function get lineSpacing():Number { return __lineSpacing; } public function set lineSpacing(val:Number):void { __lineSpacing = val; if (wordWrap) placeGlyphs(); } public override function get width():Number { return __width; } public override function set width(val:Number):void { __width = val; placeGlyphs(); } public override function get height():Number { return __textHeight; } public function get wordWrap():Boolean { return __wordWrap; } public function set wordWrap(val:Boolean):void{ __wordWrap = val; placeGlyphs(); } public function get align():String { return __align; } public function set align(val:String):void { var alignmentChange:Boolean = false; if (val != LEFT && val != RIGHT && val != CENTER) val = LEFT; if (align != val) alignmentChange = true; //allows only to update glyphs if change occurs __align = val; if (alignmentChange) placeGlyphs(); } //---------------------------------------------------------------------------------------------------- // Errors //---------------------------------------------------------------------------------------------------- /** * @private */ override public function get graphics3D():Graphics3D { throw new Error("The DynamicText3D class does not implement this property or method."); } } }