Hack of the Day: using 3D on text in lieu of embedding fonts.

You make a text field, give it a text format, and put some text in it. All is good, until you start doing something to that text field. There are at least two specific problems you’ll run into:

1. Rotate it and your text disappears.

2. Scale it up or down, and it’s going to be all jittery as the text field chooses different sizes of text to match the scale.

Normally, the handling for all of these is to embed the font in the text field. But with Flash 10, there’s a quick trick that might get you by in a lot of these cases: use 3D properties.

To see what I mean, here’s our text field guinea pig:

[as]var tf:TextField = new TextField();
tf.defaultTextFormat = new TextFormat(“Arial”, 24);
tf.text = “Hello World”;
tf.autoSize = TextFieldAutoSize.LEFT;
tf.height = tf.textHeight;
tf.x = 100;
tf.y = 100;
addChild(tf);[/as]

And here’s how we are going to abuse this poor text field:

[as]addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(event:Event):void
{
tf.rotation = mouseY;
// tf.scaleX = tf.scaleY = mouseX / stage.stageWidth * 2;
}[/as]

As is, this will rotate the text field according to the position of the mouse. Because the fonts aren’t embedded, you’ll only see the text when the mouse is at 0 y, or possibly at 360 y. Comment out that line and uncomment the other, and the text will scale according to the mouse x position. It might look fine at first, but if you move your mouse slowly, you’ll see the jittering I was talking about. If you are trying to scale some text smoothly and somewhat slowly, it’s going to look like crap.

Again, the usual fix for this is to embed the font the text field is using. But let’s look at the alternate hacks using Flash 10.

First for rotation, just use rotationZ instead of rotation.

[as]tf.rotationZ = mouseY;[/as]

Voila! Rotate and retain visibility.

And for scaling, just set the z property of the text field to anything. Even zero:

[as]tf.x = 100;
tf.y = 100;
tf.z = 0;[/as]

Now your scaling will be perfectly smooth. This works best for scaling down, as you can probably see. If you need to scale it up, you’re best to start out with a larger size, set the z, then scale down to the size you want. That way when you are scaling up, you’re actually scaling to the original size.

So how does this work? Basically, as soon as you start messing with the new 3D properties, a display object turns into a 3D object. Instead of altering it’s transform.matrix property, you are now altering its transform.matrix3D property. When this happens, the object isn’t simply transformed the “old fashioned” way. It’s actually drawn to a bitmap and then this bitmap is drawn to 3D transformed coordinates using the Flash 10 drawing API. So you aren’t actually rotating or scaling the text field anymore, but rotating and scaling the bitmap representation of it. This is the reason why scaling up looks bad. You are scaling up a bitmap representation of the originally sized text.

Naturally, this doesn’t solve all the problems that embedding a font would, e.g. using a special font that the end user may not have. And as you can see with the scaling, there may be other artifacts. But I found this is a neat hack that can save you time now and then.

This entry was posted in ActionScript, Flash. Bookmark the permalink.

19 Responses to Hack of the Day: using 3D on text in lieu of embedding fonts.

  1. felix says:

    You can achieve the same thing by applying a filter to the text field.

  2. This happens because the text field gets cached as bitmap in order to have the filter applied to it or rotated in space coordinates, but every time you rotate the edit field its internal cache representation is regenerated, it is ok if you have only one, can be bottleneck when you have a lot

  3. Sorry, mouse scrolled too fast… just repeated what you have said already!

  4. Stelimar says:

    Correct me if I’m wrong because I haven’t actually tried it, but I think putting the TextField inside a MovieClip and rotating/scaling the MovieClip would work just as well, and it wouldn’t require flash player 10. It may even run faster than using 3D transformations.

  5. kp says:

    Stelimar, nope. Putting it inside a movie clip doesn’t do a thing.

    Felix, you have code that shows a filter working for that? I’m not seeing it working:

    var tf:TextField = new TextField();
    tf.defaultTextFormat = new TextFormat(“Arial”, 24);
    tf.text = “Hello World”;
    tf.autoSize = TextFieldAutoSize.LEFT;
    tf.height = tf.textHeight;
    tf.x = 100;
    tf.y = 100;
    tf.filters = [new BlurFilter()];
    addChild(tf);

    addEventListener(Event.ENTER_FRAME, onEnterFrame);
    function onEnterFrame(event:Event):void
    {
    tf.rotation = mouseY;
    // tf.scaleX = tf.scaleY = mouseX / stage.stageWidth * 2;
    }

  6. kp says:

    Actually, it doesn’t make sense that a filter would work. Say you have a 45 degree drop shadow filter on text and you rotate the text. The filter needs to be regenerated based on the new orientation of the text. i.e. if you rotate the text 45 degrees, the shadow should still be 45 degrees, not 90. So it has to destroy the old bitmap and create a new one. The new one is based on the rotated text, not the original text. I think most other filters are orientation sensitive too.

    However, when using 3D properties, the bitmap is created from the original, untransformed object. All the transformations are then done only to the bitmap. In fact, you can see this if you add a 45 degree dropshadow to text and then rotate it using rotateZ instead of rotate. The shadow does rotate along with the text, which can actually look pretty strange.

  7. Keith,

    Have you tried the Flash Text Engine & TLF in Flash Player 10? Supposedly this would also solve the non-embedded fonts problems:
    http://www.jamesward.com/blog/2009/08/11/fonts-in-flex-4-flash-player-10-air-1-5-make-me-happy/

    Cheers,
    Daniel

  8. vamapaull says:

    great tip… thanks!! 😀

  9. Carly says:

    Is flash smart enough to keep this cached bitmap while performing a range of transitions for a text animation, or would it be better performance to use the bitmap draw functions to create a bitmap and then manipulate it for the animation?

  10. tenegri says:

    Changing the alpha value of a textfield with non-embedded font is what can be achieved by applying a filter to it (the most practical is a BlurFilter(0, 0)). It’s quite simple solution, I also use it sometimes. Unfortunatelly it doesn’t work for rotation.

  11. felix says:

    oops yeah I was wrong. Filters work for alpha not for rotation.

  12. felix says:

    Note that you can also use Flash 10’s new TextLine class to rotate non-embedded text as described here: http://www.yswfblog.com/blog/2009/05/21/the-knack-to-rotating-dynamic-text-in-flash-10/

  13. Keith Peters says:

    felix, ok, you got me on that one. Never even heard of that. thanks.

  14. sliz says:

    hello Keith Peters,i like MinimalComps very much!
    but why not add ‘layoutManage’ and ‘UIManage’.
    so we can use ‘new PushButton(“button”)’ make different look and feel.and just use ‘setLayout(new MyLayout())’ make different layout.

  15. I’ve found that there’s often a flash of text when fading in from alpha 0 to 100, so to counter this I apply a blendMode of Layer to the element I’m transitioning in. Seems to clear up the flash of content when using alpha fades on non embedded text.

  16. I did something similar using the Bitmap data. I just used if for rotation, but fades would work too. http://www.forestandthetrees.com/2009/06/29/rotating-text-without-embedding-fonts/

  17. Gareth West says:

    Why didn’t I think of that? KP, you are a genuis.

    The shaky effect that you get on scaling, is that not maybe the advanced anti Alias setting on the text field? Making this normal (tf.antiAliasType = AntiAliasType.NORMAL) fixes that too.

  18. Pradeep says:

    Hello all,

    Anybody know that how can i appy the effect like skew,arch,wave,flag,fish to text using actionscript 2?

    thanks in advance.

    Please reply me, i am waiting you the same.

    thanks,

    Pradeep

  19. k0zer says:

    This hack is good for motion blur filter too (BlurFilter(blurX, 0) + rotationZ)

Leave a Reply