Flash + Fonts: getCharBoundaries Tips, adding End Signs
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.
We are using it at kidthing on the phase 2 to do something kinda neat - 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 = field.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);
-
}
-
Full Flash-website Deconstruction #1
This is going to be the opening post on the phase2 of the award winning http://www.kidthing.com website. What's been learned along the way about adding: SEO, deeplinking, CMS, blog, and store,web services, Browser resizing, dealing with big files and big traffic days, CDN wrangling, shared libraries, Font sanity and clarity. To a flash RIA website. There are so much more to creating successful websites than just uploading webpages to the web!
Why Flash?
The brilliant design and animator team team do really amazing work in Illustrator and AfterFx, both of which are a natural fit to take directly into Flash and result in smaller pages than slicing up images Photoshop. Some of the pages in phase 2 are 2-7Kb for the rich graphics.
Compared to conventional HTML we have much better control over preloading and transitions, the ability to do engaging interstitials while the pages load up behind, resulting in a better end user experience. Compared to pure AJAX+DHTML there are less browser compatibility issues.
Stay tuned.
Blog opened up for commenting.
Finally got time to install recaptcha, so comments no longer require registering, which I don't think was possible either as I had it turned off due to damn spammers. Thanks to Doug for reminding me.
Speaking of the blog. Funny how being a web professional means that I never have time to work on my own stuff, so my main site is still the same one built in 2004 (I kinda actually take pride in it). And this blog design started last year was supposed to be finished barely has changed, thus the lame 'flash cateogries here'.
On the brightside been working on some flash front end skinning to wordpress at kidthing we are using it a s an inexpensive CMS at several places. Which means I might be able to resuse some of the lessons learned on it on this blog and get past some of the annoying things I can't do easily with html+dhtml.
Flash + Fonts: autosize textfield html fix
More fun with text. TextFieldAutoSize only appears to work when TextFields are set to MultiLine noWrap in the Text Tool properties editor, or in actionscript
-
-
txt.multiline = true;
-
-
txt.wordWrap = false;
Otherwise it's appeared to be ignored. I'm sure this is documented somewhere, it's not on the livedocs, but it would be nice if there was a warning for this if this actually the case.
Printing in Flash with LayoutUtils
Printing movie clips from Flash becomes extremely easy with the printImage functions of the LayoutUtils package from Troyworks.
Two functions printImagePortrait and printImageLandscape will place your image portrait like or landscape like. Moreover, it doesn’t matter for this printing function if the paper is set to Portrait or Landscape. The image will be scaled to the size of paper (using the scaleTo function in the crop mode of the LayoutUtils) and centered; however, margins are left to fit the standard printer settings. To use the printing functions we need a movie clip, say “mc”, and then we create a snapshot object for it.
-
-
var snapObject:IDisplayObjectSnapShot = LayoutUtil.snapshotDimensions(mc);
Now, using the snapObject, we can print our image in portrait mode:
-
-
LayoutUtil.printImagePortrait(mc, snapObject);
Or in landscape:
-
-
LayoutUtil.printImageLandscape(mc, snapObject);
The other useful function is to print all the frames of the movie clip. To do that you can call one of the two functions
-
-
LayoutUtil.printImageLandscapeFrames(mc, snapObject, true);
-
-
LayoutUtil.printImagePortraitFrames(mc, snapObject, true);
The last boolean parameter indicating if you want to print all the frames of the movie clip (true) or just the first one (false). Each new frame would be printed on a new page.
If you need the reverse process, printing from PDF to SWF, you can use the PDF2SWF Converter from SWFTools, which is a free collection of SWF manipulation and creation utilities. PDF2SWF converts every page of the PDF document into a frame in the SWF file. The last version of the converter supports Flash 9 output format.
That’s it!
You can find LayoutUtil.as source code on GoogleCode or you can have a look here
Flash + Fonts: Dynamically Loaded Fonts + Embedding + CSS + HTML == Hell
I swear about every year I end up reexploring the dark internals to flash's murky font seas, lose a day to a weekend everytime.
Basically the embedded fonts + html is a fairly complicated beast, that in order to work has to be called in a very specific order to work.
Here's a new twist. As I've covered in previous articles the ability to load fonts dynamically is very cool, but what of those textfields on stage used as placeholders? How do they join in the font fun? THEY DON'T. It doesn't appear possible to have them styled as CSS+HTML+Embedded, even if you set it to new text with CSS the text inside just dissapears. However you can create a new TextField that does support those values at the exact same place, and swap them like:
-
-
//////////// Takes a clip on stage and replaces it with an 'identical' one ////////////////////////////////////////
-
public static function swapClip(txt : TextField) : TextField {
-
trace("swapClip2..............." + txt.name);
-
var par : DisplayObjectContainer = txt.parent;
-
-
var tf : TextField = new TextField();
-
var ss : StyleSheet = new StyleSheet();
-
var tff : TextFormat = txt.defaultTextFormat;
-
-
var p : Object = new Object();
-
p.fontSize = tff.size;
-
-
p.fontFamily = tff.font;
-
//"Myriad Pro";
-
p.color = tff.color;
-
p.size = tff.size;
-
ss.setStyle("p", p);
-
//
-
tff.font = tff.font;
-
//"Myriad Pro";
-
tf.defaultTextFormat = tff;
-
// new TextFormat("Myriad Pro", 16, 0);
-
tf.styleSheet = ss;
-
-
-
tf.width = txt.width;
-
tf.height = txt.height;
-
tf.x = txt.x;
-
tf.y = txt.y;
-
// tf.border = true;
-
-
tf.embedFonts = true;
-
tf.antiAliasType = AntiAliasType.ADVANCED;
-
tf.selectable = true;
-
tf.multiline = true;
-
tf.wordWrap = true;
-
tf.condenseWhite = false;
-
-
// tf.rotation = 15;
-
// txt.visible = false;
-
trace("swapClip htmlText " + txt.htmlText);
-
var html : String = "<p>" + txt.text + "</p>";
-
tf.htmlText = html;
-
tf.name = txt.name + "";
-
-
// par
-
par.addChildAt(tf, par.getChildIndex(txt));
-
par.removeChild(txt);
-
return tf;
-
}
-
Weirdly you have to give it both TextFormat and styleSheet to get the similar formatting as the clip on stage, clearly Flash's internal renderer has significant internal state and both TextFormat or StyleSheet overlapp controlling different aspects of it.
XHTML + E4X + Namespaces
Namespaces in flash are cool and...pretty pesky.
- for unknown reasons, querying a E4X's queries in the same block apparently have to be individually namespaced. Neither putting the default namespace in the class or function worked.
- anything that tries to get at the xml while it's being passed around has to have a copy of the namespace. This isn't particularly efficient when you are serializing between objects and XHTML.
Steven Sachs has a good tutorial on some of the issues faced when working with XHTML and Flash. In particular the namespace. However after losing about 2hrs I've come up with an alternate solution...just stripping the namespace out as it's introducing more code chaos than the namespace would have solved.
In the next rev of kidthing.com's website we are going to XHTML for SEO and CMS, deeplinking etc reasons. In addition we are consuming Wordpress, initially as RSS and eventually as fully skinning the main pages in Wordpress. Since Flash's support for HTML is limited we run things through a 'cleaner' that replaces quotes, superscript, some bullets with the appropriately embedded characters. It was easy to add the following to strip it out on the complete load of the XHTML
res = res.split('xmlns="http://www.w3.org/1999/xhtml"').join('');
I switched over from String manipulation to XML manipulation to get at selective DIV's that get mapped to textfields in the flash templates (Flash is like CSS on steroids) E4X here really shines.
Flash + Fonts:W TF?! just linking to a font, no embedding…13Kb increase in swf size!?
Trying to optimize a banner ad., baffling, a single textfield, no embedded fonts, just switching to a different font has HUGE differences in the swf size. Interestingly that actually embedding the glyphs don't seem to take up as much space as I would have though. Here's a size report with a bunchof textfields on stage:
Font Name Bytes Characters
---------------------- --------- --------------
DejaVu Sans Light 28510
Linux Libertine 26852
Warnock Pro SmBd 26184
Warnock Pro 25379
Chaparral Pro 20827
Myriad Pro 17713 abcdefghijklmnopqrstuvwxyz <--very little diff.
Myriad Pro 15541
Adobe Caslon Pro 11549
Kozuka Mincho Pro EL 3809
Franklin Gothic Medium 2697
_sans 2447
Arial 2447
_serif 2335
Tahoma 1819
Verdana 1445
Abadi MT 1183
Baskerville 1158
Abadi MT Light 1082
Trebuchet MS 335
Times 319
Microsoft Sans Serif 38
Arno Pro 30
Courier New 31
Letter Gothic Std 22
Courier New 19
Sveningsson 19
Wingdings 18
Arno Pro 18
AbcPrint 18
Georgia 17
Futura 17
The goal here is to have a lightweight placeholder font, so that the runtime fonts can be loaded up once. At the moment just mentioning Myriad Pro ends up taking as much space as the font library we created earlier (!). My present guess is that the size of the library is related to the number of characters inside it, some of the doubling may be the jump from small ascii tables, to big unicode tables.
As much as I love Myriad Pro, alternates with similar spacing and weight for MyriadPro (16K), are Georgia (18bytes), Arno Pro(30B), Trebuchet (335B), Abadi MT (1K)...more than doubling in size at every step!
UPDATE:
Something very wierd is going on. In playing around with it, I was able to get one text field that had only 22Bytes and used Myriad Pro. However other fields that looked identical in the properties panel, when turned on ended up being 17Kb. I'm wondering if somehow turning on/off embedding causes this switch.
PDF 2 SWF 2 PDF Overview.
Getting things between the PDF and SWF world is very useful, both are ubiquitous, one is portable, one is easily viewable in the web and remixable.
AS3 creating PDF's with AlivePDF
Best free PDF 2 SWF convertor (and can be used with Flash9/Flex)
Useful with a print to PDF driver, like PDF995 to get other formats like PPT, Word, XLS over. Here are some other approaches people have tried.
Other options:
Flash Paper (discontinued but still on sale) and it's Print2PDF, and SwfPrinter and VectorPrinter
Upload documents to get converted to virtual flip books
Flash: Multiple Runtime Font Sharing Embedding with only Partial Character sets: How To.
Here's another example of runtime font loading, this time using html text, multiple flavors of the font library, in two separate swf libs, one with the regular font, the other with the bold, italic, bold italic flavors. Typically these would be loaded at different times, but this example should give you the basic idea.
The multiple font lib built by FlashDevelop + Flex 3.0 as "FontLibs.swf", being output as 'MyriadProExtendedFontLibs.swf', the one we created in the previous is now being loaded as 'MyriadProRegMinLib.swf'
package{ import flash.display.Sprite;import flash.text.Font;
public class MyriadExtendedLib extends Sprite
{
[Embed(source='C:/WINDOWS/Fonts/MyriadPro-Bold.otf', fontWeight='bold', fontName='Myriad Pro', unicodeRange='U+0020-U+0020,U+0021-U+0021,U+0022-U+0022,U+0023-U+0023,U+0024-U+0024,U+0025-U+0025,U+0026-U+0026,U+0027-U+0027,U+0028-U+0028,U+0029-U+0029,U+002A-U+002A,U+002B-U+002B,U+002C-U+002C,U+002D-U+002D,U+002E-U+002E,U+002F-U+002F,U+0030-U+0030,U+0031-U+0031,U+0032-U+0032,U+0033-U+0033,U+0034-U+0034,U+0035-U+0035,U+0036-U+0036,U+0037-U+0037,U+0038-U+0038,U+0039-U+0039,U+003A-U+003A,U+003B-U+003B,U+003C-U+003C,U+003D-U+003D,U+003E-U+003E,U+003F-U+003F,U+0040-U+0040,U+0041-U+0041,U+0042-U+0042,U+0043-U+0043,U+0044-U+0044,U+0045-U+0045,U+0046-U+0046,U+0047-U+0047,U+0048-U+0048,U+0049-U+0049,U+004A-U+004A,U+004B-U+004B,U+004C-U+004C,U+004D-U+004D,U+004E-U+004E,U+004F-U+004F,U+0050-U+0050,U+0051-U+0051,U+0052-U+0052,U+0053-U+0053,U+0054-U+0054,U+0055-U+0055,U+0056-U+0056,U+0057-U+0057,U+0058-U+0058,U+0059-U+0059,U+005A-U+005A,U+005B-U+005B,U+005C-U+005C,U+005D-U+005D,U+005E-U+005E,U+005F-U+005F,U+0060-U+0060,U+0061-U+0061,U+0062-U+0062,U+0063-U+0063,U+0064-U+0064,U+0065-U+0065,U+0066-U+0066,U+0067-U+0067,U+0068-U+0068,U+0069-U+0069,U+006A-U+006A,U+006B-U+006B,U+006C-U+006C,U+006D-U+006D,U+006E-U+006E,U+006F-U+006F,U+0070-U+0070,U+0071-U+0071,U+0072-U+0072,U+0073-U+0073,U+0074-U+0074,U+0075-U+0075,U+0076-U+0076,U+0077-U+0077,U+0078-U+0078,U+0079-U+0079,U+007A-U+007A,U+007B-U+007B,U+007C-U+007C,U+007D-U+007D,U+007E-U+007E,U+00A9-U+00A9,U+00AE-U+00AE,U+00B7-U+00B7,U+02C6-U+02C6,U+02DC-U+02DC,U+2013-U+2013,U+2014-U+2014,U+2018-U+2018,U+2019-U+2019,U+201A-U+201A,U+201C-U+201C,U+201D-U+201D,U+201E-U+201E,U+2020-U+2020,U+2021-U+2021,U+2022-U+2022,U+2026-U+2026,U+2030-U+2030,U+2039-U+2039,U+203A-U+203A,U+20AC-U+20AC,U+2122-U+2122')]
public static var _MyriadProBold:Class;
[Embed(source='C:/WINDOWS/Fonts/MyriadPro-BoldIt.otf', fontWeight='bold', fontStyle='italic', fontName='Myriad Pro', unicodeRange='U+0020-U+0020,U+0021-U+0021,U+0022-U+0022,U+0023-U+0023,U+0024-U+0024,U+0025-U+0025,U+0026-U+0026,U+0027-U+0027,U+0028-U+0028,U+0029-U+0029,U+002A-U+002A,U+002B-U+002B,U+002C-U+002C,U+002D-U+002D,U+002E-U+002E,U+002F-U+002F,U+0030-U+0030,U+0031-U+0031,U+0032-U+0032,U+0033-U+0033,U+0034-U+0034,U+0035-U+0035,U+0036-U+0036,U+0037-U+0037,U+0038-U+0038,U+0039-U+0039,U+003A-U+003A,U+003B-U+003B,U+003C-U+003C,U+003D-U+003D,U+003E-U+003E,U+003F-U+003F,U+0040-U+0040,U+0041-U+0041,U+0042-U+0042,U+0043-U+0043,U+0044-U+0044,U+0045-U+0045,U+0046-U+0046,U+0047-U+0047,U+0048-U+0048,U+0049-U+0049,U+004A-U+004A,U+004B-U+004B,U+004C-U+004C,U+004D-U+004D,U+004E-U+004E,U+004F-U+004F,U+0050-U+0050,U+0051-U+0051,U+0052-U+0052,U+0053-U+0053,U+0054-U+0054,U+0055-U+0055,U+0056-U+0056,U+0057-U+0057,U+0058-U+0058,U+0059-U+0059,U+005A-U+005A,U+005B-U+005B,U+005C-U+005C,U+005D-U+005D,U+005E-U+005E,U+005F-U+005F,U+0060-U+0060,U+0061-U+0061,U+0062-U+0062,U+0063-U+0063,U+0064-U+0064,U+0065-U+0065,U+0066-U+0066,U+0067-U+0067,U+0068-U+0068,U+0069-U+0069,U+006A-U+006A,U+006B-U+006B,U+006C-U+006C,U+006D-U+006D,U+006E-U+006E,U+006F-U+006F,U+0070-U+0070,U+0071-U+0071,U+0072-U+0072,U+0073-U+0073,U+0074-U+0074,U+0075-U+0075,U+0076-U+0076,U+0077-U+0077,U+0078-U+0078,U+0079-U+0079,U+007A-U+007A,U+007B-U+007B,U+007C-U+007C,U+007D-U+007D,U+007E-U+007E,U+00A9-U+00A9,U+00AE-U+00AE,U+00B7-U+00B7,U+02C6-U+02C6,U+02DC-U+02DC,U+2013-U+2013,U+2014-U+2014,U+2018-U+2018,U+2019-U+2019,U+201A-U+201A,U+201C-U+201C,U+201D-U+201D,U+201E-U+201E,U+2020-U+2020,U+2021-U+2021,U+2022-U+2022,U+2026-U+2026,U+2030-U+2030,U+2039-U+2039,U+203A-U+203A,U+20AC-U+20AC,U+2122-U+2122')]
public static var _MyriadProItalBold:Class;
[Embed(source='C:/WINDOWS/Fonts/MyriadPro-It.otf', fontName='Myriad Pro', fontStyle='italic', unicodeRange='U+0020-U+0020,U+0021-U+0021,U+0022-U+0022,U+0023-U+0023,U+0024-U+0024,U+0025-U+0025,U+0026-U+0026,U+0027-U+0027,U+0028-U+0028,U+0029-U+0029,U+002A-U+002A,U+002B-U+002B,U+002C-U+002C,U+002D-U+002D,U+002E-U+002E,U+002F-U+002F,U+0030-U+0030,U+0031-U+0031,U+0032-U+0032,U+0033-U+0033,U+0034-U+0034,U+0035-U+0035,U+0036-U+0036,U+0037-U+0037,U+0038-U+0038,U+0039-U+0039,U+003A-U+003A,U+003B-U+003B,U+003C-U+003C,U+003D-U+003D,U+003E-U+003E,U+003F-U+003F,U+0040-U+0040,U+0041-U+0041,U+0042-U+0042,U+0043-U+0043,U+0044-U+0044,U+0045-U+0045,U+0046-U+0046,U+0047-U+0047,U+0048-U+0048,U+0049-U+0049,U+004A-U+004A,U+004B-U+004B,U+004C-U+004C,U+004D-U+004D,U+004E-U+004E,U+004F-U+004F,U+0050-U+0050,U+0051-U+0051,U+0052-U+0052,U+0053-U+0053,U+0054-U+0054,U+0055-U+0055,U+0056-U+0056,U+0057-U+0057,U+0058-U+0058,U+0059-U+0059,U+005A-U+005A,U+005B-U+005B,U+005C-U+005C,U+005D-U+005D,U+005E-U+005E,U+005F-U+005F,U+0060-U+0060,U+0061-U+0061,U+0062-U+0062,U+0063-U+0063,U+0064-U+0064,U+0065-U+0065,U+0066-U+0066,U+0067-U+0067,U+0068-U+0068,U+0069-U+0069,U+006A-U+006A,U+006B-U+006B,U+006C-U+006C,U+006D-U+006D,U+006E-U+006E,U+006F-U+006F,U+0070-U+0070,U+0071-U+0071,U+0072-U+0072,U+0073-U+0073,U+0074-U+0074,U+0075-U+0075,U+0076-U+0076,U+0077-U+0077,U+0078-U+0078,U+0079-U+0079,U+007A-U+007A,U+007B-U+007B,U+007C-U+007C,U+007D-U+007D,U+007E-U+007E,U+00A9-U+00A9,U+00AE-U+00AE,U+00B7-U+00B7,U+02C6-U+02C6,U+02DC-U+02DC,U+2013-U+2013,U+2014-U+2014,U+2018-U+2018,U+2019-U+2019,U+201A-U+201A,U+201C-U+201C,U+201D-U+201D,U+201E-U+201E,U+2020-U+2020,U+2021-U+2021,U+2022-U+2022,U+2026-U+2026,U+2030-U+2030,U+2039-U+2039,U+203A-U+203A,U+20AC-U+20AC,U+2122-U+2122')]
public static var _MyriadProItal:Class;
public function MyriadExtendedLib()
{
super();
Font.registerFont(_MyriadProBold);
Font.registerFont(_MyriadProItalBold);
Font.registerFont(_MyriadProItal);
}
}
}
And the consumer of the fonts
-
package {import flash.display.Loader;import flash.display.Sprite;
-
-
import flash.events.Event;
-
-
import flash.net.URLRequest;
-
-
import flash.text.*;
-
-
public class MultiFontLoader extends Sprite {
-
-
public function MultiFontLoader() {
-
-
loadFont("MyriadProRegMinLib.swf");
-
-
loadFont("BaskervilleRegFontLib.swf");
-
-
loadFont("MyriadProExtendedFontLibs.swf", true);
-
-
}
-
-
private function loadFont(url:String, complete:Boolean = false):void {
-
-
var loader:Loader = new Loader();
-
-
if (complete) {
-
-
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, fontLoaded);
-
-
}
-
-
loader.load(new URLRequest(url));
-
-
}
-
-
private function fontLoaded(event:Event):void {
-
-
drawText();
-
-
}
-
-
public function drawText():void {
-
-
var tf:TextField = new TextField();
-
-
tf.defaultTextFormat = new TextFormat("Myriad Pro", 16, 0);
-
-
tf.embedFonts = true;
-
-
tf.antiAliasType = AntiAliasType.ADVANCED;
-
-
tf.multiline = true;
-
-
tf.autoSize = TextFieldAutoSize.LEFT;
-
-
tf.border = true;
-
-
tf.htmlText = "<p><b>Troy</b> was <b><i>here</i></b><br/> <font face='Baskerville'>Scott was</font> <i>here too</i><br/>...:;*&^% </p>";
-
-
tf.rotation = 15;
-
-
addChild(tf);
-
-
}
-
-
}
-
-
}
