views:

43

answers:

1

As a UI specialist, I am often asked to build tool-tip displays and other sorts of popups that display text. One of styles clients seem most keen on is text in a comic-book balloon. I would like to create this balloons programmatically (as opposed to embedding or linking to rendered graphics), because these balloons will have to change size at runtime, depending on how much text they have to hold.

Balloons are easy to draw for the most part: circles, rectangles or rounded-corner rectangles. The tough part, for me, is the tail (the little arrow-like part of the comic balloon that points towards the speaker). If you google comic balloon, you see that there are many varieties of tails. They ones clients request from me most often are curved. E.g...

http://www.macybugs.com/round%20bubble.PNG

and

http://thumb10.shutterstock.com.edgesuite.net/display_pic_with_logo/121360/121360,1222432252,2/stock-vector-vector-cartoon-speech-balloon-add-your-own-text-easily-17961022.jpg

The tail will always be on the bottom of the balloon, and it will sometimes point left and sometimes point right. I have been trying to come up with tail-drawing algorithms for a while, but I'm not happy with the results. I'm basically stumbling around in the dark, changing variables, looking at the results, and using trial and error to try to move closer to the magic numbers that will work. "Work" just means a result that looks pleasing, which I realize is subjective. Most of my clients will be a happy with anything that looks reasonably good and professional.

I want this result to scale. And it would be great if it could work with as few inputs as possible, maybe just isFacingLeft, tailWidth and tailHeight (Which could maybe be a percentage of the whole balloon). Maybe an adjustable curveAmount.

If it matters, I'm using Flash/Actionscript, but any system that has some sort of turtle graphics engine should work pretty much the same way: I'm working with that standard flipped Cartesian grid (y increases downward), x and y coordinates, the ability to move a pen, draw lines and draw curves.

One caveat: Flash only allows me to draw 3-point bezier curves -- start point, control point, end point.

Note: balloons won't have to scale after the are drawn.

A: 

First of all let me tell you I created an account to answer this question because the current project I'm working on does the same thing you define. For a demo you can check my application page.

Here's how my bubble algorithm works basically:

1- Bubble drawing: For a circular or rectangular bubble, default actionscript drawRoundRect and drawEllipse methods are used. For scream (spikey) and thought bubbles I used 2 ellipses. For scream bubble outer ellipse has the start and end points whereas inner ellipse has control points for cubic bezier curve. For thought bubble outer ellipse has control points and inner ellipse has start and end points. I found the cubic bezier drawing class from cartogrammar [dot] com/blog, if it's not still there, I can send you the class, just drop me a message.

2- Tail drawing: This is the tricky part, to create a sleek comic bubble tail effect I used an isosceles triangle, whose equal edges can be also bent. The middle point of the base of the triangle is also the middle of the bubble.

When you click and drag the endpoint of the bubble tail around, the base of the triangle faces the mouse pointer coordinates using arctangent function, then the endpoints of the base of the triangle are set to precalculated points.

Arctangent function:

    //p1= center of circle
    //p2= target point
    //find angle between point 1, point 2 and y=0 line and returns degree value
    private function findAngle(p1:Point,p2:Point):Number{

        var rad:Number = 0;
        var angle:Number = 0;

        if(p2.x - p1.x == 0 || p1.x - p2.x == 0){
            angle = -90

        }else{
            rad = Math.atan((p2.y-p1.y)/(p2.x-p1.x));   
            angle = Math.floor((rad * (180/Math.PI)));

        }       

        return angle;
    }

Here's how I calculated the potential endpoints for the triangle base:

        //calculates circle points for drawing tail triangle
    private function calculateCircle():void{

        var steps:uint = 360;
        var rad:Number = CENTER_RADIUS;

        //delete array
        this.circleArray.splice(0);
        for(var i:int = 0; i < 360; i+= 360/steps){

            var alpha:Number = i * (Math.PI /180);
            var sinAlpha:Number = Math.sin(alpha);
            var cosAlpha:Number = Math.cos(alpha);

            var circX:Number = circleCenter.x + (rad * cosAlpha);
            var circY:Number = circleCenter.y + (rad * sinAlpha);

            var  p:Point = new Point(circX,circY);
            this.circleArray.push(p);

        }           
    }

My last problem was handling outlines and inside of the bubble graphics. Normally when you draw tail above the bubble the two sides of the triangle (tail) goes right into the center of the bubble. If you put the bubble on top, then the bubble outline cuts the tail. I'm an Actionscript newbie so it didn't come to me quick but adding graphic layers with the order BubbleTailOutline, Bubble,BubbleTailInside solved the problem.

Znt