/******************************************************************* 
* File    : JSFX_Graphics.js  © JavaScript-FX.com
*              Inspired by http://www.walterzorn.com/jsgraphics/jsgraphics_e.htm
* Created : 2003/04/03 
* Author  : Roy Whittle  (Roy@Whittle.com) www.Roy.Whittle.com 
* Purpose : To create a cross browser vector graphics library.
* History 
* Date         Version        Description 
* 2003-04-03	1.0		Couldn't understand the walterzorn "js" so I went back
*					to line rasterization basics.
*					Wrote the initial version in about 3 hours. (NS4, NS6+, IE4+).
*					(It needs a lot of optimization but it does work!)
* 2003-04-03	1.1		Made it into an object and allowed for a parent "canvas".
***********************************************************************/ 
if(!window.JSFX)
{
	alert("Requires JSFX_Layer.js!!!");
	JSFX=new Object();
}

JSFX.Layer.prototype.getGraphics = function()
{
	if(this.graphics == null)
		this.graphics = new JSFX.Graphics(this.elem);

	return this.graphics;
}

/*
 * Class Graphics
 * Create a graphics object into which we can draw lines, circles
 */
JSFX.Graphics = function(parent)
{
	if(parent == null && !document.layers)
		parent=document.body;

	this.parent    = parent;
	this.lineColor = "#FF0000";
	this.lineWidth = 1;
}

/*
 * Method: makeBlock
 * private method to create a colored block of the correct width & height
 */
if(document.layers)
	JSFX.Graphics.prototype.makeBlock = makeBlock_NS;
else if(document.all)
	JSFX.Graphics.prototype.makeBlock = makeBlock_IE;
else if(document.getElementById)
	JSFX.Graphics.prototype.makeBlock = makeBlock_DOM;

function makeBlock_NS(x, y, w, h)
{
	var block=this.parent ? new Layer(w,this.parent) : new Layer(w);
	block.bgColor = this.lineColor;
	block.moveTo(x,y);
	block.clip.width	=w;
	block.clip.height	=h;
	block.visibility = "show"; 
}
function makeBlock_IE(x, y, w, h)
{
	var txt = '<div 	style="position:absolute;left:'+x+'px;top:'+y+'px;width:'+w+'px;height:'+h+'px;clip:rect(0,'+w+'px,'+h+'px,0);overflow:hidden;background-color:'+this.lineColor+';"><\/div>';

	this.parent.insertAdjacentHTML("BeforeEnd",txt); 
}
function makeBlock_DOM(x, y, w, h)
{
	var txt = '<div 	style="position:absolute;left:'+x+'px;top:'+y+'px;width:'+w+'px;height:'+h+'px;clip:rect(0,'+w+'px,'+h+'px,0);overflow:hidden;background-color:'+this.lineColor+';"><\/div>';
		var newRange = document.createRange();
		newRange.setStartBefore(this.parent);
		var strFrag = newRange.createContextualFragment(txt);
		this.parent.appendChild(strFrag);
}

/*
 * Method: drawPoint
 * public method to draw a single point on the canvas
 * param: x,y - coordinate of the point
 */
JSFX.Graphics.prototype.drawPoint = function(x,y)
{
	this.makeBlock(x, y, 1, 1);
	return this;
}

/*
 * Method: drawLine
 * public method to draw a single line on the canvas
 * param: x1,y1 - coordinate of the start point of the line
 * param: x2,y2 - coordinate of the end point of the line
 */
JSFX.Graphics.prototype.drawLine = function(x1, y1, x2, y2)
{
	var xw = Math.abs(x2-x1);
	var yw = Math.abs(y2-y1);
	if(xw > yw)
		this.xline(x1, y1, x2, y2, xw, yw)
	else
		this.yline(x1, y1, x2, y2, xw, yw)

	return this;
}

/*
 * Method: yLine
 * private method to draw a single line on the canvas where the line is higher than it is wide
 * param: x1,y1 - coordinate of the start point of the line
 * param: x2,y2 - coordinate of the end point of the line
 */
JSFX.Graphics.prototype.yline = function(x1, y1, x2, y2, xw, yw)
{
	if(y1 > y2)
	{
		var t;
		t  = x1;
		x1 = x2;
		x2 = t;

		t  = y1;
		y1 = y2;
		y2 = t;
	}

	var x = x1;
	var xstep = (x2>x1) ? +1 : -1;
	var step = 0;
	var sx=x1;
	var sy=y1;
	for(var y=y1 ; y<y2 ; y++)
	{
		step += xw;
		if(step > yw)
		{
			this.makeBlock(sx, sy, this.lineWidth, y-sy);
			step -= yw;
			x += xstep;
			sx = x;
			sy = y;
		}
	}
	if(sy != y)
		this.makeBlock(sx, sy, this.lineWidth, y-sy);
}

/*
 * Method: xLine
 * private method to draw a single line on the canvas where the line is wider than it is high
 * param: x1,y1 - coordinate of the start point of the line
 * param: x2,y2 - coordinate of the end point of the line
 */
JSFX.Graphics.prototype.xline = function(x1, y1, x2, y2, xw, yw)
{
	if(x1 > x2)
	{
		var t;
		t  = x1;
		x1 = x2;
		x2 = t;

		t  = y1;
		y1 = y2;
		y2 = t;
	}

	var y = y1;
	var ystep = (y2>y1) ? +1 : -1;
	var step = 0;
	var sx=x1;
	var sy=y1;
	for(var x=x1 ; x<x2 ; x++)
	{
		step += yw;
		if(step > xw)
		{
			this.makeBlock(sx, sy, x-sx, this.lineWidth);
			step -= xw;
			y += ystep;
			sx = x;
			sy = y;
		}
	}
	if(sx != x)
		this.makeBlock(sx, sy, x-sx, this.lineWidth);
}

/*
 * Method: drawCircle
 * public method to draw a single circle on the canvas
 * param: x,y - coordinate of the center point of the circle
 * param: r   - the radius of the circle
 *
 * NOTE: This is a very inefficient way of doing this - need to go back
 * to my "Fundementals of Computer Graphics" to learn how to "rasterise" a circle.
 */
JSFX.Graphics.prototype.drawCircle = function(x, y, r)
{
	var a=0;
	var aStep = 0.1;
	var sx=x + r*Math.sin(a);
	var sy=y + r*Math.cos(a);
	var end = 2*Math.PI + aStep;
	for(a=0 ; a<end ; a+=aStep)
	{
		var nx=x + r*Math.sin(a);
		var ny=y + r*Math.cos(a);
		this.drawLine(sx, sy, nx, ny);
		sx=nx;
		sy=ny;
	}
	return this;
}

/*
 * Method: drawRect
 * public method to draw a single rectangle on the canvas
 * param: x1,y1 - coordinate of the start corner of the rectangle
 * param: x2,y2 - coordinate of the end corner of the rectangle
 */
JSFX.Graphics.prototype.drawRect = function(x1, y1, x2, y2)
{
	this.drawLine(x1, y1, x2, y1);
	this.drawLine(x2, y1, x2, y2);
	this.drawLine(x2, y2, x1, y2);
	this.drawLine(x1, y2, x1, y1);
	return this;
}

/*
 * Method: fillRect
 * public method to draw a single filled rectangle on the canvas
 * param: x1,y1 - coordinate of the start corner of the rectangle
 * param: x2,y2 - coordinate of the end corner of the rectangle
 */
JSFX.Graphics.prototype.fillRect = function(x1, y1, x2, y2)
{
	var t;
	if(x1>x2)
	{
		t  = x1;
		x1 = x2;
		x2 = t;
	}
	if(y1>y2)
	{
		t  = y1;
		y1 = y2;
		y2 = t;
	}
	this.makeBlock(x1, y1, x2-x1, y2-y1);
	return this;
}

/*
 * Method: setColor
 * public method to set the color of the pen used to draw objects
 * param: color - the color of the pen (e.g. "#FF0000" for the color red)
 */
JSFX.Graphics.prototype.setColor = function(color)
{
	this.lineColor=color;
	return this;
}

/*
 * Method: setWidth
 * public method to set the width of the pen used to draw objects
 * param: width - the width in pixels of the pen.
 * MOTE: very crude, doesn't work too well
 */
JSFX.Graphics.prototype.setWidth = function(width)
{
	this.lineWidth=width;
	return this;
}

