All pastes #259300 Raw Edit

Untitled

public text v1 · immutable
#259300 ·published 2006-11-27 10:05 UTC
rendered paste body
// ShapeBuilder - simple ActionScript drawing API functions
// Version 0.15
//
// Copyright (C) 2006, Michiel Sikma <michiel@thingmajig.org>

// makeMap function     map drawer.
// Usage:
//      makeMap(line, object, direction,
//              color, thickness, radius, speed, master, depth)
// Parameters:
//      line        name of the resulting movie clip
//      object      coordinates of the line
//      direction   the initial direction in which the line moves
//      color       color of the line (in hexadecimal)
//      thickness   thickness of the line (in pixels)
//      radius      radius of the curvature
//      speed       speed at which the line is drawn (in pixels)
//      master      container movie clip for the line
//      depth       depth of the resulting movie clip in the master
//      fix         whether improper line movements should be amended (true)
// Description:
//      Uses makeRoute() to create a multitude of lines on the screen.
//      Unlike makeRoute(), it is possible to create comprehensive drawings
//      that are not limited to being just from A to B. The object parameter
//      must be an array with objects that contain x and y indices. The first
//      object inside of the array is seen as the starting position, and from
//      there on, one long connected line will be drawn from all the given
//      points. The rest of the parameters are passed on to makeRoute().
//      Unless the fix argument is false, improper line movements will be
//      amended.

function makeMap(       mc:String,
                    object:Object,
                 direction:String,
                     color:Number,
                 thickness:Number,
                    radius:Number,
                     speed:Number,
                    master:MovieClip,
                     depth:Number,
                       fix:Boolean):MovieClip
{
    if (arguments.length < 9) return;
    if (!master[mc])
        var container:MovieClip = master.createEmptyMovieClip(mc, depth);
    var n:Number = 0;
    var dx:Number = 0;
    var dy:Number = 0;
    var ex:Number = 0;
    var ey:Number = 0;
    container.finished = false;
    function makeSegment(cnt:Boolean)
    {
        if (cnt) if (direction == "x") direction = "y"; else
                 if (direction == "y") direction = "x";
        if (fix != false) {
            var subst:Boolean = false;
            if (object[n-1].x < object[n].x) dx = 1; else dx = 0;
            if (object[n-1].y < object[n].y) dy = 1; else dy = 0;
            // Check whether the line is about to move back into itself.
            // If so, fix it by making an extra line.
            if (dx != (object[n].x < object[n+1].x) && direction == "x" && n) {
                // Add an extra line towards the opposite x direction and
                // half the next y coordinate.
                ex = object[n].x + (radius * ((dx * 2) - 1));
                ey = (object[n].y + object[n+1].y) / 2;
                subst = true;
            }
            if (dy != (object[n].y < object[n+1].y) && direction == "y" && n) {
                // Add an extra line towards half the next x coordinate and
                // the opposite y direction.
                ex = (object[n].x + object[n+1].x) / 2;
                ey = object[n].y + (radius * ((dy * 2) - 1));
                subst = true;
            }
            if (subst) {
                // This is the actual inserting of an extra coordinate.
                var tmp:Array = object.splice(n+1);
                object.push({x: ex, y: ey});
                object = object.concat(tmp);
            }
        }
        this["mapSegment_"+n] = makeRoute(mc+"_"+n, object[n].x, object[n].y,
        object[n+1].x, object[n+1].y, direction, color, thickness, radius,
        speed, container, depth + n);
        mapIterator=this["mapSegment_"+n].createEmptyMovieClip("mapIterator",1);
        mapIterator.onEnterFrame = function()
        {
            if (this._parent.finished) {
                removeMovieClip(this);
                if (n > object.length - 2) {
                trace("At: "+n+" done.");
                    container.finished = true;
                    return;
                } else makeSegment(true);
            }
        };
        n++;
    };
    makeSegment();
    return container;
};

// makeRoute function   route segment drawer.
// Usage:
//      makeRoute(mc, start_x, start_y, end_x, end_y, direction,
//                color, thickness, radius, speed, master, depth, zeropoint)
// Parameters:
//      line        name of the resulting (new) movie clip
//      start_x     starting position x coordinate
//      start_y     starting position y coordinate
//      end_x       ending position x coordinate
//      end_y       ending position y coordinate
//      direction   the initial direction in which the line moves
//      color       color of the line (in hexadecimal)
//      thickness   thickness of the line (in pixels)
//      radius      radius of the curvature
//      speed       speed at which the line is drawn (in pixels)
//      master      container movie clip for the line
//      depth       depth of the resulting movie clip in the master
//      zeropoint   does not set the starting coordinates of the mc if true
// Description:
//      Draws a line from x, y to x, y with a straight horizontal and
//      vertical line, which is connected with a rounded corner. The resulting
//      movie clip will set a boolean named "finished" to true once it's
//      fully traced its path. Note that the line variable must be a string.
//      It will be created automatically if it does not exist; do not
//      supply a direct reference to an existing movie clip.
//      Originally developed for the Ector Hoogstad website.

function makeRoute(       mc:String,
                     start_x:Number,
                     start_y:Number,
                       end_x:Number,
                       end_y:Number,
                   direction:String,
                       color:Number,
                   thickness:Number,
                      radius:Number,
                       speed:Number,
                      master:MovieClip,
                       depth:Number):MovieClip
{
    if (arguments.length < 12) return;
    if (!master[mc])
        var line:MovieClip = master.createEmptyMovieClip(mc, depth);
    else
        var line:MovieClip = master[mc];
    if (!direction || (direction != "x" && direction != "y"))
        direction = "x";
    
    // Initialize the basic settings of the line movie clip.
    line._x = start_x;
    line._y = start_y;
    end_x -= start_x;
    end_y -= start_y;
    line.lineStyle(thickness, color, 100);
    
    line.finished = false;
    
    // Set the start angles for the curve based on the destination.
    if (end_x > 0) var direction_x:Number =  1; else
                   var direction_x:Number = -1;
    if (end_y > 0) var direction_y:Number =  1; else
                   var direction_y:Number = -1;
    if (direction_x > 0 && direction_y > 0)
        if (direction == "x") var curveStart:Number =  90; else
        if (direction == "y") var curveStart:Number = 180;
    if (direction_x < 0 && direction_y > 0)
        if (direction == "x") var curveStart:Number =  90; else
        if (direction == "y") var curveStart:Number =   0;
    if (direction_x > 0 && direction_y < 0)
        if (direction == "x") var curveStart:Number = 270; else
        if (direction == "y") var curveStart:Number = 180;
    if (direction_x < 0 && direction_y < 0)
        if (direction == "x") var curveStart:Number = 270; else
        if (direction == "y") var curveStart:Number =   0;
    
    var curve_x:Number = end_x - (radius * direction_x);
    var curve_y:Number = end_y - (radius * direction_y);
    
    var lineCaret_x:Number = 0;
    var lineCaret_y:Number = 0;
    
    // Every frame, a segment of the line is drawn.
    line.onEnterFrame = function():Void
    {
        if (!line.step) line.step = 1;
        if (line.step == 1) {
            // First, draw a line until the position of the curve.
            if (direction == "x") {
                lineCaret_x += speed * direction_x;
                if (((direction_x < 0) && lineCaret_x <= curve_x) ||
                    ((direction_x > 0) && lineCaret_x >= curve_x)) {
                    lineCaret_x = curve_x;
                    line.step = 2;
                }
            } else if (direction == "y") {
                lineCaret_y += speed * direction_y;
                if (((direction_y < 0) && lineCaret_y <= curve_y) ||
                    ((direction_y > 0) && lineCaret_y >= curve_y)) {
                    lineCaret_y = curve_y;
                    line.step = 2;
                }
            }           
            line.lineTo(lineCaret_x, lineCaret_y);
        }
        if (line.step == 2) {
            // Then, draw an arc to simulate the curve of the line.
            if (!line.curve) line.curve = 0;
            if (direction == "x") {
                line.moveTo(lineCaret_x, 0);
                if (direction_x > 0 && direction_y > 0)
                    curveDirection = -1;
                else if (direction_x < 0 && direction_y < 0)
                    curveDirection = -1;
                else
                    curveDirection =  1;
            } else if (direction == "y") {
                line.moveTo(0, lineCaret_y);
                if (direction_x > 0 && direction_y > 0)
                    curveDirection =  1;
                else if (direction_x < 0 && direction_y < 0)
                    curveDirection =  1;
                else
                    curveDirection = -1;
            }
            // We calculate the correct speed at which to draw the curve.
            // Since it's a quarter of a circle, we use pi.
            range = ((radius * 2) * Math.PI) / 4;
            line.curve += (speed * (90 / range)) * curveDirection;
            if (direction == "x") {
                if (line.curve >= 90 &&(!(direction_x > 0 && direction_y > 0) || 
                    (direction_x < 0 && direction_y < 0))) line.curve = 90;
                if (line.curve <= -90 &&((direction_x > 0 && direction_y > 0) || 
                    (direction_x < 0 && direction_y < 0))) line.curve = -90;
                line_xy = line._drawArc(lineCaret_x, 0,
                                        radius, radius, line.curve, curveStart);
            } else if (direction == "y") {
                if (line.curve >= 90 &&(!(direction_x > 0 && direction_y < 0) || 
                    (direction_x < 0 && direction_y > 0))) line.curve =  90;
                if (line.curve <= -90 &&((direction_x > 0 && direction_y < 0) || 
                    (direction_x < 0 && direction_y > 0))) line.curve = -90;
                line_xy = line._drawArc(0, lineCaret_y,
                                        radius, radius, line.curve, curveStart);
            }
            if (line.curve == 90 || line.curve == -90) {                
                lineCaret_x = line_xy.x;
                lineCaret_y = line_xy.y;
                line.step = 3;
            }
        }
        if (line.step == 3) {
            // Finally, draw the remainder.
            line.moveTo(lineCaret_x, lineCaret_y);
            if (direction == "x") {
                lineCaret_y += speed * direction_y;
                if (((direction_y < 0) && lineCaret_y <= end_y) ||
                    ((direction_y > 0) && lineCaret_y >= end_y)) {
                    lineCaret_y = end_y;
                    line.step = 4;
                }
            } else if (direction == "y") {
                lineCaret_x += speed * direction_x;
                if (((direction_x < 0) && lineCaret_x <= end_x) ||
                    ((direction_x > 0) && lineCaret_x >= end_x)) {
                    lineCaret_x = end_x;
                    line.step = 4;
                }
            }
            line.lineTo(lineCaret_x, lineCaret_y);
        }
        if (line.step == 4) {
            line.finished = true;
            delete line.onEnterFrame;
        }
        line.glcaret_x = lineCaret_x + start_x;
        line.glcaret_y = lineCaret_y + start_y;
        line.caret_x = lineCaret_x;
        line.caret_y = lineCaret_y;
    };
    // We also manually run the onEnterFrame function once to ensure there
    // is a minimal delay before it actually begins.
    line.onEnterFrame();
    return line;
};

// _drawArc function    arc segment drawer.
// Usage:
//      _drawarc(x, y, radius_x, radius_y, arc, startAngle)
// Parameters:
//      x           the current pen position coordinate x
//      y           the current pen position coordinate y
//      radius_x    the radius of the arc.
//      radius_y    a modifier for the radius to produce elliptical arcs
//      arc         the sweep of the arc
//      startAngle  starting angle in degrees
// Description:
//      Prototype method for drawing arc segments. It should be used by
//      another function rather than on its own (hence the underscore in the
//      function name).

MovieClip.prototype._drawArc = function(         x:Number,
                                                 y:Number,
                                          radius_x:Number,
                                          radius_y:Number,
                                               arc:Number,
                                        startAngle:Number):Object
{
    if (arguments.length < 6) return;
    if (radius_y == undefined) {
        // In case there's no radius_y defined, make a circular arc.
        radius_y = radius_x;
    }
    if (Math.abs(arc) > 360) {
        // A value bigger than 360 would cause more to be drawn than would
        // be visible.
        arc = 360;
    }
    var sa, theta, ang, angm, segs, ax, ay, bx, by, cx, cy;
    // Calculates how many segments are necessary for our arc.
    segs = Math.ceil(Math.abs(arc) / 45);
    // Calculate the sweep of each segment.
    sa = arc / segs;
    // The math requires radians rather than degrees; convert.
    theta = -(sa / 180) * Math.PI;
    ang = -(startAngle / 180) * Math.PI;
    
    // Determine the starting points (ax, ay) relative to the specified x, y.
    ax = x-Math.cos(ang) * radius_x;
    ay = y-Math.sin(ang) * radius_y;
    if (segs > 0) {
        for (var a = 0; a < segs; a++) {
            ang += theta;
            // Determine the angle halfway between the last and new one.
            angm = ang - (theta / 2);
            // Determine the end point.
            bx = ax + Math.cos(ang) * radius_x;
            by = ay + Math.sin(ang) * radius_y;
            // Determine the control point.
            cx = ax + Math.cos(angm) * (radius_x / Math.cos(theta / 2));
            cy = ay + Math.sin(angm) * (radius_y / Math.cos(theta / 2));
            this.curveTo(cx, cy, bx, by);
        }
    }
    // Finally, return the end point for further processing.
    return {x: bx, y: by};
};