AS3 Tooltip

At last, I got around to porting my Tooltip Class to Actionscript  3.  Well, when I say “porting”, that’s not quite accurate: this is a complete rewrite.  As such, alot of property names in the options have been changed, some of the defaults are different, and there are a few more public methods.  So if you’ve been using the old AS2 Tooltip, don’t just copy and paste your code, first have a look at the Class, which is fully documented. 

Get The Tooltip Class Here.

If you’re not familiar with the old AS2 Tooltip: this is a customizable static Singleton Class for generating and displaying Tooltips from anywhere in your code.   There are no assests for the library, since the tooltip is created and drawn dynamically, by invoking the static methods:

Tooltip.show(tooltip:String = “”, localOptions:Object = null, target:DisplayObject = null) 
Tooltip.hide()

But now there’s another way to invoke the Tooltip:   DisplayObject instances can now subscribe and unsubscribe themselves from the tooltip for automatic handling:

Tooltip.subscribe(target:DisplayObject, tooltip:String = “”, options:Object = null)

This will register the ROLL_OVER, ROLL_OUT, MOUSE_DOWN, and CLICK events of your target with listeners in the Tooltip, to show and hide the passed tooltip string at the appropriate times.  This is great when your target’s tooltip string doesn’t need to change much, but if you do need to change it,  just call the subscribe() method again with the new arguments.   For example, if you have a custom button class with a String property called ”tooltip”, you can use accessor methods to set or change the tooltip, and inside the accessor call Tooltip.subscribe().

And, of course, to unsubscribe:

Tooltip.unsubscribe(target:DisplayObject)

You may have noticed that there’s a third argument in the original Tooltip.show() method.    This is entirely optional, and it’s one of the ways to make sure that the Tooltip is registered with the stage. Since Actionscript3 limits stage access to DisplayObject instances that are already on it, you have to make sure that the stage reference is passed to the Tooltip at least once in the programme’s lifetime.  This is done by passing a DisplayObject instance that’s already registered with the stage, and you can chose one of several ways to do so:

  1. Subscribe a target DisplayObject to the tooltip – this will automatically attach the tooltip to the Stage the moment the target becomes a child of the Stage (via an Event.ADDED_TO_STAGE listener).
  2.  Pass an optional “target” parameter to the Tooltip.show() method.
  3.  Call Tooltip.getInstance(target) once before using the Tooltip.

 

Formatting and Customisation:

All the Tooltip’s options can be customised both globally and locally.  For global customisation, use the static get/set options accessors to pass an object containing one or more options, or set them one at a time using the static setOption () method. 

Tooltip.options = newOptions:Object
Tooltip.setOption(optionName:String, optionValue:*)

For local customisation of individual tooltips, pass an options object to the static Tooltip.show () method, or register local options with the subscribe(method). It’s not necessary to pass all the options – Each default option is applied unless overridden by a global option, which can in turn be overriden by a local option. So only pass the options you want to override with your object.

The text is rendered using html and styled with CSS (it’s no longer necessary or possible to switch html on or off).  The body text is wrapped with  XML <tooltip></tooltip> tags  and the main stylesheet uses the “tooltip” xml selector to format the text,  but additional selectors can be used to format various html entities, by passing a styleSheet property with the options.
 
The Tooltip uses a fadeIn/fadeOut animation by default, so fonts are also embedded by default - but only if the font corresponding to the fontFamily option is embedded in the Flash file.  The class checks for existance of the Font and switches the embed on or off accordingly. But you can always switch embedFonts off completely.

When a CSS-style comma separated list of fonts is used for fontFamily, the code uses the first located font and ingores all others. However, overriding or additional fonts in the styleSheet option are not checked by the code, so you need to make sure that all those fonts are embedded or turn off the automatic embedding using the embedFonts option.
 
By default, the Tooltip’s background is a rounded rectangle, with customisable corner rounding. The backgroundColor, lineColor, alpha transparacy, and dropShadow are all customisable using the options.   To use a different background, for example a Symbol in the library, you can pass a customBackground option.  This attaches a MovieClip or other DisplayObject from the library as the tooltip’s background property.   The custom background is then streched to the default dimensions (text width and height plus margins), but for extra control you can also access the Tooltip’s instance properties from within the background instance or anywhere else using:

Tooltip.getInstance().getDimensions();
Tooltip.getInstance.getLocalOptions();

For non-rectangular custom backgrounds, you may need to play around with margins. To set all the margins at once, use the margin property. To override specific margins, use marginLeft, marginRight, marginTop, or marginBottom.  

For non standard implementations, if you want the tooltip displayed in a fixed spot on the stage (eg, for a status bar or speech bubble), you can use offsetX and offsetY together with fixedPosition – inn this case, the offset will be relative to the stage instead of the mouse. You can also use fixedWidth to prevent the tooltip from shrinking to fit a single line, and boundingRect to constrain it to an area other than the stage.

    
List of Tooltip Options:

delay:Number (default: 0.5 seconds) delay in seconds

width:Number (defalut: 200) maximum width of the tooltip rectangle (default: 200px)

alpha:Number (default: 0.8) Alpha transparency of the tooltip’s background 

corner:Number (default: 10) The diameter for the rounded corner. For sharp corners pass 0)

margin:Number (default: 4) Overall margin

marginLeft:Number (default: Tooltip.MARGIN) Left margin. Defaults to the overall margin value

marginRight:Number (default: Tooltip.MARGIN) Left margin. Defaults to the overall margin value

marginTop:Number (default: Tooltip.MARGIN) Left margin. Defaults to the overall margin value

marginBottom:Number (default: Tooltip.MARGIN) Left margin. Defaults to the overall margin value

color:Color Text and line color, can also accept a string hex value (default 0×000000)  

backgroundColor:int Background color of the tooltip (default: 0xFFFFDD – light yellow)

shadowColor:int (default: Tooltip.COLOR_TEXT) Drop shadow colour. By default duplicates the color property.

shadowType:int (default: Tooltip.SHADOW_HOLLOW), )

lineColor:Color (default: Tooltip.COLOR_TEXT) COLOR_TEXT uses same colour as the options.color. For no line use COLOR_NONE.

customBackground:DisplayObject (defult:null) If true overrides background and line colour settings and inserts a custom class as background. The mc is automatically stretched to fit the dimensions, but can use getDimensions() and getLocalOptions() methods of the Tooltip instance to adjust itself.

styleSheet:TextField.StyleSheet (default: null) Use to extend the default stylesheet.

fontFamily:String (default: “Verdana,Helvetica,_sans”) Can be a single font or a comma separated list of fonts (no spaces between commas allowed).

fontSize:Number Font size (default: 11)

fontWeight:String (default: “normal”)

leading:Number line spacing (default: 2)

textAlign:String (default: TextFormatAlign.LEFT)

embedFonts:Boolean (default: true) If true, will first check if the embedded font passed in the fontFamily option is available (if it’s a list of fonts, it will use the first available font in the list). If set to false, it will not embed the fonts regardles of availability.

followMouse:Boolean (default: true) If true the tooltip will follow mouse

duration:Number or Boolean (default:1) The duration of the fadeIn/fadeOut animation. 

offsetX:Number (default 20) Horizontal distance from mouse.

offsetY:Number (default 25) Vertical distance from mouse.

fixedPosition:Boolean (default: false) – If true, the tooltip will appear in a fixed position on the stage, instead of at the mouse position. A fixed tooltip will not adjust to Stage dimensions or follow the mouse.

 fixedWidth:Boolean (default: false) don’t adjust the width of a single line tooltip.

boundingRect:Object (default: Tooltip.STAGE_RECT) set the constraining bounds to other than the stage (x, y, width, height);

Usage Example:

 import com.neoarchaic.ui.Tooltip;
Tooltip.options = {width: 500, margin:10}
Tooltip.subscribe(this, “I’m a subscribed tooltip”, {backgroundColor:0×000000, color:”#FFFFFF”});
Tooltip.show(”I’m a tooltip. &lt;br/&gt;I’m 500 pixels wide and have a 10 pixel margin”);
Tooltip.show(”I’m a delayed tooltip.”, {delay: 2});
Tooltip.hide(); 
Tooltip.unsubscribe(this); 

 

Download:

 Get The Tooltip Class Here. 

Do let me know if there are any problems with it, any ideas for improvement, and of course if you managed to use it successfully.

13 Responses to “AS3 Tooltip”

  1. Gerry says:

    Is this line in your example an error?
    Toolip.subscribe(this, “I’m a subscribed tooltip”, {backgroundColor:0×000000, color:”#FFFFFF});

  2. Gerry says:

    Syntax error… two typos to fix above. You have Toolip which should be Tooltip then in that same line you left off the trailing quotation mark.
    Just an FYI for those that run into this error.

  3. Gerry says:

    I’m loving this Tooltip but I’m trying to wrap the text so it looks something like this…
    Mr. Smith
    President & CEO

    My text is coming from an XML node attribute and I’ve tried using \n , & for next line but to no avail. Any tips?

  4. Karina says:

    Hi Gerry,

    Thank for the feedback, made the changes to the description text.

    I’ve noticed the wrapping problem you’re talking about, although \n does for me. You can also add a stylesheet with display:block selectors and assign paragraphs and headings to the text.

    I’ll let you know if I find a solution.

  5. Peder says:

    Hi, I’m enjoying your Tooltip class, so I started to read the source code to see what I could learn, and I’m getting some great ideas.. thanks! Quick question: Is there any particular design pattern that influenced your design, or if not a design pattern, some type of named programming technique that I could read up on?

    Thanks again for the great class.

  6. Peder says:

    Let me rephrase my question: Any patters *other* than the singleton. ;)

  7. Peder says:

    In your source code comments, you write:

    //PROTECTED METHODS

    /**
    * Create tooltip elements and place as the top child of the stage.
    * Broken up into multiple protected functions for easier inheritance.
    * @param e
    */

    But when I try to extend your class with my own, eg. ControlbarTooltip extends Tooltip, I get the following error when attempting to use my extended class:

    “Call to a possibly undefined method subscribe through a reference with static type Class.”

    Have you tried to extend your class, and if so, what is the trick?

    Thanks again,

    Peder J.

  8. Karina says:

    Hi Peder,

    Thanks for your comments, I’m glad you’re finding it helpful.

    To answer your first question – Singleton is really the only pattern that applies here. I don’t really use design patterns all that much, except for MVC, which does not apply here. Again, I don’t think I use MVC in any “officially approved” kind of way. I have a a number of classes that extend a View class, some classes that extend a Model class, and a Controller class who’s sheer purpose in life is to bind them together with a system of listeners. I call that MVC for lack of a better term, but others might not.
    I think that you can learn much by studying design patterns, but I woudn’t necessarily follow them blindly. They’re like recipes: you can take what you like, leave what you don’t like, or make something up.

    Regarding inheritance: I haven’t tried to extend it yet, and I believe it might be trickier than I thought at first. The main problem is that static functions can’t be inherited, so they’d have be be re-declared on the extended class. So before it can be properly inherited, I’ll have to rewrite it to facilitate that. On the bright side, I haven’t actually needed to extend the tooltip yet, because there are so many other ways to customise it, so I hope it’s enough to keep you going until I find some time to revisit the tooltip for inheritance.

    The Tooltip was my first AS3 class, after many years of coding with AS2 (and AS1 before that), so there are bound to be mistakes, imperfections, and better ways of coding it. It’s far from perfect, but it has worked quite well for me so far, through a major AS3 project, and I hope that you will also find it useful.

    Karina

  9. Knalle says:

    Nice class.

    By the way, if you want the text (using systemfonts) to fade put this line in the class (remember to import the blurFilter):

    tipText.filters = [new BlurFilter(0,0,0)];

    (a classic hack from http://www.airtightinteractive.com/news/?p=109)

  10. Knalle says:

    I also found the tooltip behaving more smoothly by moving this line:

    removeEventListener(Event.ENTER_FRAME, placeTip);

    down in the fadeOut function

    if (alpha <= 0) {
    removeEventListener(Event.ENTER_FRAME, placeTip);
    }

  11. Andrew says:

    Would you mind adding a few more fully fleshed usage examples to this great resource? I, as one person, am having trouble updating my older AS2 coded example to work with the AS3 model in your rewrite.

    For example, the following code doesn’t work with the new Class when I try to attach the tooltip to the hover of a simple icon. I am over my head it seems.

    import com.neoarchaic.ui.Tooltip;
    Tooltip.options = {width: 200, margin:10}

    watermark.onRollOver = function() {Tooltip.subscribe};
    watermark.onRelease = function() {getURL(”mailto:BLAH@BLAH.COM”)};

    watermark.onRollOver = function(){
    display.text = “onRollOver ” + this
    Tooltip.show(”Click to Email.”, {fontFamily:”gotham”, embedFonts:true, size: 12, delay: .2, color:0×666666, fade:true, align:”center”, follow:true, fade:.5, margin:5, alpha: 70, corner: 3})
    }
    //Rollout events for all the buttons
    //Release outside events for all the buttons – safety net for rollouts
    watermark.onRollOut = watermark.onReleaseOutside = function(){
    Tooltip.hide()
    }

  12. Andrew says:

    Oops, forgive my previous note that was clearly not close to what AS3 needs. My AS3 version doesn’t work yet, though, either.

    // Tooltip addition
    import com.neoarchaic.ui.Tooltip;
    Tooltip.options = {width: 200, margin:10}
    import flash.display.MovieClip;
    import flash.events.MouseEvent;

    watermark.addEventListener(MouseEvent.ROLL_OVER, onRollOverHandler);
    watermark.addEventListener(MouseEvent.ROLL_OUT, onRollOutHandler);
    watermark.addEventListener(MouseEvent.CLICK, onClickHandler)
    watermark.addEventListener(MouseEvent.MOUSE_DOWN, onPressHandler);
    watermark.addEventListener(MouseEvent.MOUSE_UP, onReleaseHandler);

    watermark.buttonMode = true;
    watermark.useHandCursor = true;

    function onRollOverHandler(myEvent:MouseEvent){
    Tooltip.show(”I’m a tooltip.”);
    trace(”Over and show tooltip”);
    }

    function onRollOutHandler(myEvent:MouseEvent){
    Tooltip.hide();
    trace(”Out and Tooltip should hide”);
    }

    function onClickHandler(myEvent:MouseEvent){
    trace(”I waited for Press AND Release and email should popup onclick!”);
    var url:String = “mailto:Email@email.com”;
    var request:URLRequest = new URLRequest(url);
    try {
    navigateToURL(request, ‘_blank’);
    } catch (e:Error) {
    trace(”Error occurred!”);
    }
    }

    function onPressHandler(myEvent:MouseEvent){
    trace(”Press”);
    }

    function onReleaseHandler(myEvent:MouseEvent){
    trace(”Release”);
    }

  13. Daniel says:

    The Global option method are not working for me.

    I try:
    Tooltip.options = {’width’:100};
    or
    trace (Tooltip.getOption(’alpha’));

    and I get
    TypeError: Error #1009: Cannot access a property or method of a null object reference.

    The options in the subscribe method works fine.

Leave a Reply