Connecting two dots

by leichtgewicht
Various ways to connect two points with rounded corners. Useful for creating animations with dynamic shapes.
♥10 | Line 295 | Modified 2011-09-30 08:53:06 | MIT License
play

ActionScript3 source code

/**
 * Copyright leichtgewicht ( http://wonderfl.net/user/leichtgewicht )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/sZY7
 */

package {
    import flash.text.TextFieldAutoSize;
    import flash.text.AntiAliasType;
    import flash.text.TextFormat;
    import flash.text.TextField;
    import flash.ui.Mouse;
    import flash.events.MouseEvent;
    import flash.events.KeyboardEvent;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.display.Sprite;
    
    import com.bit101.components.HSlider;
    
    public class ConnectingTheDots extends Sprite {
        
        private static const INFOS: Object = {
            "1": { color: 0x660000, hide: true, name: "horizontal bezier curve" },
            "2": { color: 0x666600, hide: true, name: "vertical bezier curve" },
            "3": { color: 0xAA0000, hide: true, name: "automatic bezier curve" },
            "4": { color: 0x006600, hide: false, name: "adapted curve algorithm" },
            "5": { color: 0x00AA00, hide: true, name: "horizontal rounding-perserved curve" },
            "6": { color: 0x006666, hide: true, name: "vertical rounding-perserved curve" },
            "7": { color: 0x0000AA, hide: true, name: "automatic rounding-perserved curve" },
            "8": { color: 0xAA00AA, hide: true, name: "horizontal straight rounded line" },
            "9": { color: 0x66AA00, hide: true, name: "vertical straight rounded line" },
            "0": { color: 0x0066AA, hide: true, name: "automatic straight rounded line" }
        };
        
        private static const VISIBLE_ALPHA: Number = 0.575;
        private static const IN_VISIBLE_ALPHA: Number = 0.035;
        
        private var radius: HSlider = new HSlider();
        
        public function ConnectingTheDots() {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            
            radius.maximum = 200.0;
            radius.minimum = 1.0;
            radius.value = 110.0;

            Mouse.hide();
            
            stage.addEventListener( MouseEvent.MOUSE_MOVE, updateLine );
            stage.addEventListener( KeyboardEvent.KEY_DOWN, updateVisibility );
            stage.addEventListener( MouseEvent.MOUSE_WHEEL, updateRadius );
            
            createInfo();
            updateLine();
        }
        
        private function updateVisibility( e: KeyboardEvent ): void
        {
            var code: String = String.fromCharCode( e.keyCode ).toUpperCase();
            if( INFOS[code] )
            {
                INFOS[code].hide = !INFOS[code].hide;
                updateLine();
            }
        }
        
        private function updateRadius( e: MouseEvent ): void
        {
            radius.value += e.delta/3.0;
            updateLine();
        }

        private function updateLine( e: Event = null ): void {
            graphics.clear();
            var startX: int = stage.stageWidth/2;
            var startY: int = stage.stageHeight/2 ;
            var endX: int = mouseX;
            var endY: int = mouseY;
            graphics.lineStyle( 1, INFOS["1"].color, INFOS["1"].hide ? IN_VISIBLE_ALPHA : VISIBLE_ALPHA );
            drawNormalLineA( graphics, startX, startY, endX, endY, false, radius.value );
            graphics.lineStyle( 1, INFOS["2"].color, INFOS["2"].hide ? IN_VISIBLE_ALPHA : VISIBLE_ALPHA);
            drawNormalLineA( graphics, startX, startY, endX, endY, true, radius.value  );
            graphics.lineStyle( 1, INFOS["3"].color, INFOS["3"].hide ? IN_VISIBLE_ALPHA : VISIBLE_ALPHA );
            drawNormalLineB( graphics, startX, startY, endX, endY, radius.value );
            graphics.lineStyle( 1, INFOS["4"].color, INFOS["4"].hide ? IN_VISIBLE_ALPHA : VISIBLE_ALPHA );
            drawAdaptedLine( graphics, startX, startY, endX, endY, radius.value );
            graphics.lineStyle( 1, INFOS["5"].color, INFOS["5"].hide ? IN_VISIBLE_ALPHA : VISIBLE_ALPHA );
            drawRoundedLineHorizontal( graphics, startX, startY, endX, endY, radius.value );
            graphics.lineStyle( 1, INFOS["6"].color, INFOS["6"].hide ? IN_VISIBLE_ALPHA : VISIBLE_ALPHA );
            drawRoundedLineVertical( graphics, startX, startY, endX, endY, radius.value );
            graphics.lineStyle( 1, INFOS["7"].color, INFOS["7"].hide ? IN_VISIBLE_ALPHA : VISIBLE_ALPHA );
            drawRoundedLine( graphics, startX, startY, endX, endY, radius.value );
            graphics.lineStyle( 1, INFOS["8"].color, INFOS["8"].hide ? IN_VISIBLE_ALPHA : VISIBLE_ALPHA );
            drawStraightRoundedLineH( graphics, startX, startY, endX, endY, radius.value );
            graphics.lineStyle( 1, INFOS["9"].color, INFOS["9"].hide ? IN_VISIBLE_ALPHA : VISIBLE_ALPHA );
            drawStraightRoundedLineV( graphics, startX, startY, endX, endY, radius.value );
            graphics.lineStyle( 1, INFOS["0"].color, INFOS["0"].hide ? IN_VISIBLE_ALPHA : VISIBLE_ALPHA );
            drawStraightRoundedLineA( graphics, startX, startY, endX, endY, radius.value );
            with( graphics )
            {
                lineStyle( 1, 0 );
                moveTo( startX-2, startY );
                lineTo( startX+3, startY );
                moveTo( startX, startY-2);
                lineTo( startX, startY+3);
                moveTo( endX-2, endY );
                lineTo( endX+3, endY );
                moveTo( endX, endY-2);
                lineTo( endX, endY+3);
            }
            for( var i: String in INFOS ) {
                INFOS[i].tF.alpha = INFOS[i].hide ? 0.2 : 0.8;
            }
        }
        
        private function createInfo(): void{
            var sprite: Sprite = new Sprite();
            sprite.x = 5.0;
            sprite.y = 5.0;
            sprite.addChild(createText( 0x000000, "Enter 0-9 to change the visibility." ));
            
            var tF: TextField;
            var yOff: Number = 20.0;
            for( var i: String in INFOS ) {
                tF = createText( INFOS[i].color, "["+i+"] "+INFOS[i].name );
                tF.y = yOff;
                tF.x = 5.0;
                yOff += 15.0;
                INFOS[i].tF = tF;
                sprite.addChild( tF );
            }
            tF = createText( 0x000000, "Radius of the lines" );
            yOff += 10.0;
            tF.y = yOff;
            yOff += 20.0;
            radius.y = yOff;
            radius.x = 5.0;
            sprite.addChild(radius);
            sprite.addChild(tF);
            addChild( sprite );
        }
        
        private function createText(color: uint, text:String):TextField {
            var tF: TextField = new TextField();
            tF.defaultTextFormat = new TextFormat("Verdana", 10, color );
            tF.selectable = false;
            tF.embedFonts = false;
            tF.antiAliasType = AntiAliasType.ADVANCED;
            tF.text = text;
            tF.autoSize = TextFieldAutoSize.LEFT;
            return tF;
        }

    }
}
import flash.display.Graphics;

function drawNormalLineA( graphics: Graphics, startX: Number, startY: Number, endX: Number, endY: Number, vertical: Boolean = false, radius: Number = 20 ): void {
    
    var w: Number = endX-startX;
    var h: Number = endY-startY;
    var wA: Number = Math.abs(w);
    var hA: Number = Math.abs(h);
    var xDir: Number = w < wA ? -1.0 : 1.0;
    var yDir: Number = h < hA ? -1.0 : 1.0;
    
    radius = Math.min( wA/2.0, hA/2.0, radius );
    
    var vTangent: Number = vertical ? radius * yDir : 0.0;
    var hTangent: Number = vertical ? 0.0 : radius * xDir;
    
    graphics.moveTo( startX, startY );
    graphics.curveTo( startX + hTangent, startY + vTangent, startX + (w / 2.0), startY + (h / 2.0) );
    graphics.curveTo( endX - hTangent, endY - vTangent, endX, endY );
}

function drawNormalLineB( graphics: Graphics, startX: Number, startY: Number, endX: Number, endY: Number, radius: Number = 20 ): void {
    
    var w: Number = endX-startX;
    var h: Number = endY-startY;
    var wA: Number = Math.abs(w);
    var hA: Number = Math.abs(h);
    var xDir: Number = w < wA ? -1.0 : 1.0;
    var yDir: Number = h < hA ? -1.0 : 1.0;
    
    radius = Math.min( wA/2.0, hA/2.0, radius );
    
    var vertical: Boolean = wA > hA;
    
    var vTangent: Number = vertical ? radius * yDir : 0.0;
    var hTangent: Number = vertical ? 0.0 : radius * xDir;
    
    graphics.moveTo( startX, startY );
    graphics.curveTo( startX + hTangent, startY + vTangent, startX + (w / 2.0), startY + (h / 2.0) );
    graphics.curveTo( endX - hTangent, endY - vTangent, endX, endY );
}

function drawAdaptedLine( graphics: Graphics, startX: Number, startY: Number, endX: Number, endY: Number, radius: Number = 20 ): void {
    
    var w: Number = endX-startX;
    var h: Number = endY-startY;
    var wA: Number = Math.abs(w);
    var hA: Number = Math.abs(h);
    var xDir: Number = w < wA ? -1.0 : 1.0;
    var yDir: Number = h < hA ? -1.0 : 1.0;
    
    radius = Math.min( wA/2.0, hA/2.0, radius );
    
    var rXDir: Number = radius * xDir;
    var rYDir: Number = radius * yDir;
    
    var wD: Number = wA - radius * 2.0;
    var hD: Number = hA - radius * 2.0;
    
    var tangent: Number ;
    var vertical: Boolean = wD > hD;
    if( !vertical ) {
        if( hD == 0 ) {
           tangent = radius;
        } else {
           tangent = radius - ( wD / hD * radius);
        }
    } else {
        if( wD == 0 ) {
            tangent = radius;
        } else {
            tangent = radius - ( hD / wD * radius)
        }
    }
    
    var vTangent: Number = vertical ? tangent * yDir : 0.0;
    var hTangent: Number = vertical ? 0.0 : tangent * xDir;
    
    graphics.moveTo( startX, startY );
    graphics.curveTo( startX + hTangent, startY + vTangent, startX + rXDir, startY + rYDir );
    graphics.lineTo( endX - rXDir, endY - rYDir );
    graphics.curveTo( endX - hTangent, endY - vTangent, endX, endY );
}

function drawRoundedLineHorizontal( graphics: Graphics, startX: Number, startY: Number, endX: Number, endY: Number, radius: Number = 20 ): void {
    
    var w: Number = Math.abs( endX-startX );
    var h: Number = Math.abs( endY-startY );
    var w2: Number = w/2.0;
    var h2: Number = h/2.0;
    
    radius = Math.min( w2, radius );
                
    var h2r: Number = h2-radius;
    var d2: Number = Math.sqrt( h2r*h2r+w2*w2-radius*radius );
    var angle1: Number = Math.atan2(radius,d2);
    var angle2: Number = Math.atan2(h2r,w2);
    var angle: Number = -angle1-angle2;
    
    var xDir: Number = startX > endX ? -1.0 : 1.0;
    var yDir: Number = startY > endY ? -1.0 : 1.0;
    
    var y1: Number = radius*yDir-Math.cos(angle)*radius*yDir;
    var x1: Number = -Math.sin( angle )*radius*xDir;
    var t: Number = radius*Math.tan( -angle/2.0 );
    
    graphics.moveTo( startX, startY );
    graphics.curveTo( startX+t*xDir, startY, startX+x1, startY+y1 );
    graphics.lineTo( endX-x1, endY-y1);
    graphics.curveTo( endX-t*xDir, endY, endX, endY );
}

function drawRoundedLineVertical( graphics: Graphics, startX: Number, startY: Number, endX: Number, endY: Number, radius: Number = 20 ): void {
    
    var w: Number = Math.abs( endX-startX );
    var h: Number = Math.abs( endY-startY );
    var w2: Number = w/2.0;
    var h2: Number = h/2.0;
    
    radius = Math.min( h2, radius );
    
    var w2r: Number = w2-radius;
    var d2: Number = Math.sqrt( w2r*w2r+h2*h2-radius*radius );
    var angle1: Number = Math.atan2(radius,d2);
    var angle2: Number = Math.atan2(w2r,h2);
    var angle: Number = -angle1-angle2;
    
    var xDir: Number = startX > endX ? -1.0 : 1.0;
    var yDir: Number = startY > endY ? -1.0 : 1.0;
    
    var x1: Number = radius*xDir-Math.cos(angle)*radius*xDir;
    var y1: Number = -Math.sin( angle )*radius*yDir;
    var t: Number = radius*Math.tan( -angle/2.0 );
    
    graphics.moveTo( startX, startY );
    graphics.curveTo( startX, startY+t*yDir, startX+x1, startY+y1 );
    graphics.lineTo( endX-x1, endY-y1);
    graphics.curveTo( endX, endY-t*yDir, endX, endY );
}

function drawRoundedLine( graphics: Graphics, startX: Number, startY: Number, endX: Number, endY: Number, radius: Number = 20 ): void {
    var w: Number = Math.abs(endX-startX);
    var h: Number = Math.abs(endY-startY);
    if( w < h )
    {
        drawRoundedLineHorizontal( graphics, startX, startY, endX, endY, radius );
    }
    else
    {
        drawRoundedLineVertical( graphics, startX, startY, endX, endY, radius );
    }
}

function drawStraightRoundedLineH( graphics: Graphics, startX: Number, startY: Number, endX: Number, endY: Number, radius: Number = 20 ): void {
    var w: Number = endX-startX;
    var h: Number = endY-startY;
    var w2: Number = w/2.0;
    var h2: Number = h/2.0;
    radius = Math.min( Math.abs(w2), Math.abs(h2), radius );
    
    var xDir: Number = startX > endX ? -1.0 : 1.0;
    var yDir: Number = startY > endY ? -1.0 : 1.0;
    
    graphics.moveTo( startX, startY );
    graphics.lineTo( startX+w2-radius*xDir, startY );
    graphics.curveTo( startX+w2, startY, startX+w2, startY+radius*yDir );
    graphics.lineTo( startX+w2, startY+h-radius*yDir );
    graphics.curveTo( startX+w2, startY+h, startX+w2+radius*xDir, startY+h);
    graphics.lineTo( endX, endY );
}

function drawStraightRoundedLineV( graphics: Graphics, startX: Number, startY: Number, endX: Number, endY: Number, radius: Number = 20 ): void {
    var w: Number = endX-startX;
    var h: Number = endY-startY;
    var w2: Number = w/2.0;
    var h2: Number = h/2.0;
    radius = Math.min( Math.abs(w2), Math.abs(h2), radius );
    
    var xDir: Number = startX > endX ? -1.0 : 1.0;
    var yDir: Number = startY > endY ? -1.0 : 1.0;
    
    graphics.moveTo( startX, startY );
    graphics.lineTo( startX, startY+h2-radius*yDir);
    graphics.curveTo( startX, startY+h2, startX+radius*xDir, startY+h2 );
    graphics.lineTo( startX+w-radius*xDir, startY+h2 );
    graphics.curveTo( startX+w, startY+h2, startX+w, startY+h2+radius*yDir);
    graphics.lineTo( endX, endY );
}

function drawStraightRoundedLineA( graphics: Graphics, startX: Number, startY: Number, endX: Number, endY: Number, radius: Number = 20 ): void {
    var w: Number = Math.abs(endX-startX);
    var h: Number = Math.abs(endY-startY);
    if( w < h )
    {
        drawStraightRoundedLineH( graphics, startX, startY, endX, endY, radius );
    }
    else
    {
        drawStraightRoundedLineV( graphics, startX, startY, endX, endY, radius );
    }
}