All pastes #259299 Raw Edit

Something

public text v1 · immutable
#259299 ·published 2006-11-27 10:04 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};
};