Flash + Fonts: getCharBoundaries Tips, adding End Signs

by troy on September 30, 2008

One of the coolest things about Flash9 in my opinion is the increased power of the TextField, we are already seeing applications like Buzzword only really possible now, and Flash 10 promises even more with enhanced - exotic even ligatures and system / device font antialiasing.

If ligatures aren't turning your typographic socks,  there are several great examples of how to use it to do practical things live search and highlighting of text, using the magic of getCharBoundaries.

One neat thing you can do with this is End Signs. You know those small little playful graphics used typically in magazines, at the end of a story to indicate no more hunting through advertisements for the next section. It's a great way to brand the experience but is rarely in web except for magazines like the New Yorker.

  As mentioned in previous articles we are consuming XHTML +CSS to convert into rich headers, and MovieClip dingbats at the end of a section. In implementing the later this eve I ran into some quirks. The goal is to find the last character of HTML formatted text and place the graphic on the same line a character or so to the right. Note that just putting it on the bounding box border of a TextField wouldn't work as there might only be a single word on that line.

The magic is getCharBoundaries getting the last character is assumed to have a period, so makes this easy:

	var idx : int = (myTextField.text as String).lastIndexOf(".");
	var bnds : Rectangle = myTextField.getCharBoundaries(idx);

Tells you the position of the character, in this case a period at the very end of our section.

Tip1: Wait a Frame
When all the auto-goodness are turned on, e.g. wordWrap, autoKern, antiAliasType, on the TextField, it takes a frame for Flash to report back accurate positioning. This took me some time to figure out as the layout routines using it would report back values, it wasn't until testing them again in response to clicking that I realized that they weren't *quite* the right ones.

The easiest way to do this for me was to set a setTimeOut(setupDingBat, 1000/24); to fire about a frame later.

Tip2: Add the position of the TextField as an Offset
Unlike DisplayObject.getBounds(scope). it doesn't really tell you where that bounds actually belongs in the parent, but is relative to the textfield itself so you have to add the position of the textfield's x and y values as an offset.

	graphics.clear();  
	graphics.beginFill(0xFF0000, .9);
	graphics.drawRect(myTextField.x + (bnds.x ), myTextField.y + (bnds.y), Math.abs(bnds.width), bnds.height);
	graphics.endFill();

Tip3: Beware Negatives
NOTE the weird Math.abs on the bnds.width, was returning a negative width, making the graphic placed the opposite from where it was supposed to.

Tip4: Get Creative
It's very easy to create a static array with multiple linkageId's of symbols to attach, e.g. we have a bunch of bugs.

try {
					// checking if the imageHeader exists in the library
					//cycle through them
					var mcStyle : String = blockEnds.shift();
					blockEnds.push(mcStyle);
					//	trace("put end sign " + mcStyle);
					//trace("==================================================");
					var ClassReference : Class = getDefinitionByName(mcStyle) as Class;
					blockEndSymbol = new ClassReference();
					addChild(blockEndSymbol);
 
					// positioning
					blockEndSymbol.x = field.x + (bnds.x ) +Math.abs(bnds.width*2);
					blockEndSymbol.y =field.y + (bnds.y);
 
				} 
                catch(e : Error) {
					trace("ERROR in TextPageBlock " + e.message);
				}