/*////////////////////////////////////////////////////////////////////////////////////////////////////////// Devin Reimer - blog.almostlogical.com - 2009-07-19 (this version supports wordwrap and alignment) Version: 1.2 based on class DynamicText3D: FIVe3D v2.1.2 - 2008-10-12 Flash Interactive Vector-based 3D Mathieu Badimon | five3d.mathieu-badimon.com | www.mathieu-badimon.com | contact@mathieu-badimon.com /*////////////////////////////////////////////////////////////////////////////////////////////////////////// package almostlogical.five3d.display { import flash.display.DisplayObject; import flash.geom.ColorTransform; import five3D.display.Graphics3D; import five3D.display.Shape3D; import five3D.display.Sprite3D; 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:Object; 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; public function DynamicText3DMultiline(typography:Object) { __typography = typography; if (!__typography.__initialized) __typography.initialize(); } 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 identical:Boolean = true; for (var i:int = 0; i < text.length; i++){ if ((text.charAt(i) != __text.charAt(i)) || !identical){ createGlyph(i, text.charAt(i)); identical = false; } } } private function createGlyph(number:Number, glyph:String):void { var shape:Shape3D = new Shape3D(); shape.graphics3D.addMotif([['B', [__color, 1]]].concat(Graphics3D.clone(__typography.__motifs[glyph])).concat([['E']])); shape.scaleX = shape.scaleY = __size/100; addChildAt(shape, number); } private function removeAdditionalGlyphs():void { for (var i:int = numChildren-1; i >= __text.length; i--) removeChildAt(i); } //this function has been completely changed by Devin Reimer private function placeGlyphs():void { var horizOffset:Number = 0; var vertOffset:Number = 0; var letterWidth:Number = 0; var letterHeight:Number = __typography.__height * getSizeScale(); var nextWord:String; var nextWordStart:int = 0; var shape:Shape3D; __textwidth = 0; //reset for (var i:int = 0; i < numChildren; i++) { shape = Shape3D(getChildAt(i)); letterWidth = (__typography.__widths[__text.charAt(i)]) * getSizeScale(); 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 * getSizeScale()); } } 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 * getSizeScale()); } } if (shape.x != horizOffset) shape.x = horizOffset; if (shape.y != vertOffset) shape.y = vertOffset; horizOffset += letterWidth + (__letterspacing * getSizeScale()); } horizOffset -= (__letterspacing * getSizeScale()); //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 = Shape3D(getChildAt(i)); 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 } } } } private function getSizeScale():Number { return __size / 100; } //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.__widths[word.charAt(i)] + __letterspacing) * getSizeScale(); if (i == word.length - 1) { wordWidth -= (__letterspacing * getSizeScale()); } } return wordWidth; } public function get typography():Object { return __typography; } public function set typography(value:Object):void { __typography = value; if (!__typography.__initialized) __typography.initialize(); reinitText(__text); } private function reinitText(text:String):void { __text = ""; this.text = text; } public function get size():Number { return __size; } public function set size(value:Number):void { __size = value; resizeGlyphs(); placeGlyphs(); } private function resizeGlyphs():void { for (var i:int = 0; i < numChildren; i++) { var shape:Shape3D = Shape3D(getChildAt(i)); shape.scaleX = shape.scaleY = __size/100; } } 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; for (var i:int = 0; i < numChildren; i++) { var shape:Shape3D = Shape3D(getChildAt(i)); shape.transform.colorTransform = colortransform; } } public function get letterSpacing():Number { return __letterspacing; } public function set letterSpacing(value:Number):void { __letterspacing = value; placeGlyphs(); } 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 textWidth():Number { return __textwidth; } public function get textHeight():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 override public function get graphics3D():Graphics3D { throw new Error("The DynamicText3D class does not implement this property or method."); } } }