Source: dvisual.js

CanvasRenderingContext2D.prototype.sector = function (x, y, radius, sDeg, eDeg) {
	this.save();
	this.translate(x, y);
	this.beginPath();
	this.arc(0,0,radius,sDeg, eDeg);
	this.save();
	this.rotate(eDeg);
	this.moveTo(radius,0);
	if ((eDeg - sDeg)%(Math.PI*2)!=0)
		this.lineTo(0,0);
	//this.lineTo(0,0);
	this.restore();
	this.rotate(sDeg);
	this.lineTo(radius,0);
	this.closePath();
	this.restore();
	return this;
}
CanvasRenderingContext2D.prototype.clear_canvas = function () {
	this.clearRect(0,0,10000,10000);
	return this;
}

CanvasRenderingContext2D.prototype.clear_arc = function() {
    this.save();
    this.globalCompositeOperation = 'destination-out';
    this.fillStyle = 'black';
    this.fill();
    this.restore();
};

CanvasRenderingContext2D.prototype.clearArc = function(x, y, radius, startAngle, endAngle, anticlockwise) {
    this.beginPath();
    this.arc(x, y, radius, startAngle, endAngle, anticlockwise);
    this.clear_arc();
};

DVChartList = [DVBarChart,DVPieChart,DVLineChart,DVHistChart,DVRadarChart,DVMulLineChart,DVMulBarChart];
DVCanvasList = [];

Object.prototype.cloneAll=function(){
	function clonePrototype(){};
	clonePrototype.prototype = this;
	var obj = new clonePrototype();
	for(var ele in obj){
		if(typeof(obj[ele])=='object')
			obj[ele] = obj[ele].cloneAll();
	}
	return obj;
}


Array.prototype.max = function()
{ 
	return Math.max.apply({},this) 
} 
Array.prototype.min = function()
{ 
	return Math.min.apply({},this) 
} 

/**
 * The Main Class of DVisual
 * @constructor
 * @param {string} canvasName - the canvas's id you want to paint
 * @example new DVisual(canvas_id);
 */
function DVisual(canvasName)
{
	reshape_flag = true;
	for (var i=0;i<DVCanvasList.length;i++)
		if (DVCanvasList[i]==canvasName)
		{
			reshape_flag = false;
		}
	if (reshape_flag)
		DVCanvasList.push(canvasName);
 	this.canvas = document.getElementById(canvasName);
	this.ctx = this.canvas.getContext('2d');
	this.ctx.clear_canvas();
	this.eles = new Array();

	this.devicePixelRatio = window.devicePixelRatio || 1;
    this.backingStorePixelRatio = this.ctx.webkitBackingStorePixelRatio ||
                                             this.ctx.mozBackingStorePixelRatio ||
                                             this.ctx.msBackingStorePixelRatio ||
                                             this.ctx.oBackingStorePixelRatio ||
                                             this.ctx.backingStorePixelRatio || 1;
    this.ratio = this.devicePixelRatio / this.backingStorePixelRatio;
    if (reshape_flag)
    {
    	this.oldWidth = this.canvas.width;
    	this.oldHeight = this.canvas.height;
		if (this.devicePixelRatio !== this.backingStorePixelRatio) 
		{
			this.canvas.width = this.oldWidth * this.ratio;
			this.canvas.height = this.oldHeight * this.ratio;

			this.canvas.style.width = this.oldWidth + 'px';
			this.canvas.style.height = this.oldHeight + 'px';
			this.ctx.scale(this.ratio, this.ratio);
	    }
	} else
	{
		this.oldWidth = this.canvas.width/this.ratio;
    	this.oldHeight = this.canvas.height/this.ratio;
	}

    this.Xinc = 0;
	this.Yinc = 0;
	this.Xmargin = this.oldWidth - 40;
	this.Ymargin = this.oldHeight - 55; 
	this.XZoom = 1;
	this.YZoom = 1;
	this.originX = 25;
	this.originY = this.oldHeight - 40;
	this.drawed = false;
	this.mouseMove = false;
	this.clickDot = {'X':new Array(),'Y':new Array()};
    // canvasName = this;
    // this.canvas.addEventListener('mousemove', function(e){
    //   p = getEventPosition(e);
    //   canvasName.ctx.clear();
    //   canvasName.draw()

    //   canvasName.ctx.moveTo(0,p.y);
    //   canvasName.ctx.lineTo(canvasName.oldWidth,p.y);
    //   canvasName.ctx.moveTo(p.x,0);
    //   canvasName.ctx.lineTo(p.x,canvasName.oldHeight);
    //   canvasName.ctx.strokeText(canvasName.transXY(p.x,p.y)[0].toFixed(2)+" "+canvasName.transXY(p.x,p.y)[1].toFixed(2),p.x,p.y)
    //   canvasName.ctx.stroke();
      
    // }, false);
  
}
/**
 * set the mouseMove to true,you can get the coordinate when you move the mouse on the canvas
 * @function
 */
DVisual.prototype.setMouseMove = function()
{
	this.mouseMove = true;
    var canvasName = this;
    this.canvas.addEventListener('mousemove', function(e){
      p = getEventPosition(e);
      canvasName.ctx.clear_canvas();
      canvasName.draw()

      canvasName.ctx.moveTo(0,p.y);
      canvasName.ctx.lineTo(canvasName.oldWidth,p.y);
      canvasName.ctx.moveTo(p.x,0);
      canvasName.ctx.lineTo(p.x,canvasName.oldHeight);
      canvasName.ctx.strokeText(canvasName.transXY(p.x,p.y)[0].toFixed(2)+" "+canvasName.transXY(p.x,p.y)[1].toFixed(2),p.x,p.y)
      canvasName.ctx.stroke();
      
    }, false);
}

/**
 * set the clickDot to true,you can click the canvas to add a dot on the canvas
 * @function
 * @param {DVColor} - the color of the dot you want
 */
DVisual.prototype.setClickDot = function(color)
{
    var canvasName = this;
    if (arguments.length==0)
    	color = DVgetRandomColor(1)[0];

    this.canvas.addEventListener('mouseup', function(e){
      p = getEventPosition(e);
      canvasName.ctx.clear_canvas();
      canvasName.addElement(new DVDot({'x':p.x,'y':p.y,'color':color}));
      canvasName.draw();
      real = canvasName.transXY(p.x,p.y);
      canvasName.clickDot.X.push(real[0]);
      canvasName.clickDot.Y.push(real[1]);
    }, false);
}
/**
 * return 
 * @function
 * @return {Objects} clickDot - return the clicked dot data
 */
DVisual.prototype.getClickDot = function()
{
   return this.clickDot;
}


/**
 * The Formated Color Class of DVisual
 * @constructor
 * @param {double} r - the Red component of RGBs,0 in default,[0-256]
 * @param {double} g - the Green component of RGBs,0 in default,[0-256]
 * @param {double} b - the Blue component of RGBs,0 in default,[0-256]
 * @param {double} a - the Alpha component of RGBa,1 in default,[0-1]
 */
function DVColor(r,g,b,a)
{
	if (arguments.length<4)
		a = 1;
	if (arguments.length<3)
		b = 0;
	if (arguments.length<2)
		g = 0;
	if (arguments.length<1)
		r = 0;
	this.a = a;
	this.r = r;
	this.g = g;
	this.b = b;
}
/**
 * translate the color to the html color style
 * @function
 * @return {string} the rgba style string
 */
DVColor.prototype.tostring = function()
{
	return "rgba("+this.r+","+this.g+","+this.b+","+this.a+")";
}

/**
 * get the eventPosition on canvas
 * @function
 * @return {{}} {x:x,y:y}
 */
function getEventPosition(ev){
  	var x, y;
  	if (ev.layerX || ev.layerX == 0) {
    	x = ev.layerX;
    	y = ev.layerY;
 	}else if (ev.offsetX || ev.offsetX == 0) { // Opera
    	x = ev.offsetX;
    	y = ev.offsetY;
  	}
  	return {x: x, y: y};
}



/**
 * translate the x and y coordinate from data space to real canvas space
 * @function
 * @param {double} x - x value in data space
 * @param {double} y - y value in data space
 * @return {Array(double)} [resultX,resultY] - the real coordinate value of (x,y)
 */
DVisual.prototype.xyTrans = function(x,y)
{
	resultX = (x*1.0 - this.Xinc)/this.XZoom + this.originX;
	resultY = this.originY - (y*1.0 - this.Yinc)/this.YZoom;
	return [resultX,resultY]
}

/**
 * translate the x and y coordinate from real canvas space to data space
 * @function
 * @param {double} x - x value in real canvas space
 * @param {double} y - y value in real canvas space
 * @return {Array(double)} [resultX,resultY] - the real coordinate value of (x,y)
 */
DVisual.prototype.transXY = function(x,y)
{
	resultX = (x - this.originX)*this.XZoom+this.Xinc;
	resultY = (this.originY - y)*this.YZoom+this.Yinc;
	return [resultX,resultY]
}

/**
 * translate the x length from data space to real canvas space
 * @function
 * @param {double} len - the length in data space
 * @return {double} length - the length in real canvas space
 */
DVisual.prototype.xLenTrans = function(len) {
	return len*1.0/this.XZoom;
}

/**
 * translate the y length from data space to real canvas space
 * @function
 * @param {double} len - the length in data space
 * @return {double} length - the length in real canvas space
 */
DVisual.prototype.yLenTrans = function(len) {
	return len*1.0/this.YZoom;
}

/**
 * initialize the Z data degree for zoom
 * @function
 * @param {Array(double)} Z - the Z degree data,should contain the maxium and minum.
 */
DVisual.prototype.initialZ = function(Z) {
		zmm = [Z.min(),Z.max()];
		this.zinc = 0;
		if ((zmm[1]-zmm[0])*1.0/zmm[0]<0.2)
			this.zinc = zmm[0];
		this.Zzoom = (Math.min(this.oldWidth,this.oldHeight)/10 - 5)/(zmm[1] - this.zinc);
}

/**
 * translate the z length from data space to real canvas space
 * @function
 * @param {double} len - the length in data space
 * @return {double} length - the length in real canvas space
 */
DVisual.prototype.zLenTrans = function(len)
{
		return (len - this.zinc)*this.Zzoom+5;

}

/**
 * set the base value of X and Y
 * @function
 * @param {double} Xinc - the base increment value of X
 * @param {double} Yinc - the base increment value of Y
 */
DVisual.prototype.setinc = function(Xinc,Yinc)
{
	this.Xinc = Xinc;
	this.Yinc = Yinc;
};

/**
 * set the margin of data space,set the zoom value of x and y;
 * @function
 * @param {double} Xmargin - the margin of X in data space
 * @param {double} Ymargin - the margin of Y in data space
 */
DVisual.prototype.setmargin = function(Xmargin,Ymargin)
{	
	this.XZoom = Xmargin*1.2/this.Xmargin;
	this.YZoom = Ymargin*1.2/this.Ymargin;
	this.Xmargin = Xmargin*1.2;
	this.Ymargin = Ymargin*1.2;
};

/**
 * intialize the zoom and margin of X and Y
 * @function
 * @param {Array(double)} X - the data'X
 * @param {Array(double)} Y - the data'Y 
 */
DVisual.prototype.initial = function(X,Y)
{	
	incX = Math.min(0.0,Math.floor(X.min()));
	incY = Math.min(0.0,Math.floor(Y.min()));
	xmargin = this.oldWidth;
	ymargin = this.oldHeight;
	if (this.Drawed)
	{
		return 0;
	}
	
	if (X.length!=0)
	{
		xm = (X.max()-X.min())*1.0;
		if ((xm/X.max())<0.3)
			incX = Math.floor(X.min())-1;
		xmargin = X.max()-incX;
	}
	if (Y.length!=0)
	{
		ym = (Y.max()-Y.min())*1.0;
		if ((ym/Y.max())<0.3)
			incY = Math.floor(Y.min())-1;
		ymargin = Y.max()-incY;
	}
	this.setinc(incX,incY);

	this.setmargin(xmargin,ymargin);

	this.Drawed = true;
};

/**
 * add the element to the main class
 * @function
 * @param {DVElement} ele - DVElement can be any DVisual Graph Class,contain a draw() fucntion to draw itself on canvas.
 */
DVisual.prototype.addElement = function(ele)
{

	this.eles.push(ele);
}

/**
 * draw all graph on the canvas
 * @function
 */
DVisual.prototype.draw = function()
{
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(this);
}



/**
 * A DVisual graph element indicate a dot.(bubble)
 * @constructor
 * @example new DVDot({'x':100,'y':100});
 * @param {Object[]} args - a array contain arguments below
 * @param {double} args.x - the x value of the dot
 * @param {double} args.y - the y value of the dot,0 in default
 * @param {DVColor=} [args.color = new DVColor()] - the color of the dot,black in default
 * @param {string=} [args.style ='fill']- the style of this dot,should be one of 'fill','stroke' and 'bubble'
 * @param {string=} [args.bubbleText ='']- the text show in the bubble
 * @param {boolean=} [args.shadow ='true'] - whether draw dot's shadow.
 * @param {double=} [args.radius = '2'] - the radius of this dot(a circle)
 * @param {double=} [args.lineWidth = '1'] - the lineWidth of this dot(a circle)
 */

function DVDot(args)
{

	if (arguments.length==0)
		args = {};
	this.args = args.cloneAll();
	if (args['x']==null)
		this.args['x'] = 0;

	if (args['y']==null)
		this.args['y'] = 0;

	if (args['color']==null)
		this.args['color'] = new DVColor();

	if (args['style']==null || (args.style!="fill" && args.style!="stroke" && args.style!="bubble" ))
		this.args['style'] = "fill";

	if (args['bubbleText']==null)
		this.args['bubbleText'] = "";

	if (args['shadow']==null)
		this.args['shadow'] = true;

	if (args['radius']==null)
		this.args['radius'] = 2;
	
	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;

}

/**
 * draw the dot on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw the dot
 */
DVDot.prototype.draw = function(dv)
{
	dv.ctx.save();
	dv.ctx.fillStyle = this.args.color.tostring();
	dv.ctx.strokeStyle = this.args.color.tostring();
	dv.ctx.lineWidth = this.args['lineWidth'];
	shadow = new DVColor(100,100,100,0.3);
	if (this.args['shadow'])
	{
		if (this.shadowDot == null)
		{
			shadowArgs = this.args.cloneAll();
			shadowArgs['color'] = new DVColor(100,100,100,0.3);
			shadowArgs['shadow'] = false;
			shadowArgs['x']+=1;
			shadowArgs['y']+=1;
			shadowArgs['description'] = "";
			this.shadowDot = new DVDot(shadowArgs);
		}
		this.shadowDot.draw(dv);
	}
	if (this.args['style']=='stroke')
	{
		dv.ctx.sector(this.args.x,this.args.y,this.args.radius,0,2*Math.PI);
		dv.ctx.stroke();
	}
	if (this.args['style']=='fill')
	{
		dv.ctx.sector(this.args.x,this.args.y,this.args.radius,0,2*Math.PI);
		dv.ctx.fill();
	}
	if (this.args['style']=='bubble')
	{
		dv.ctx.sector(this.args.x,this.args.y,this.args.radius,0,2*Math.PI);
		dv.ctx.stroke();
		a = this.args.color.a;
		if (this.args.color.a>0.7)
			a = 0.4;
		dv.ctx.fillStyle = (new DVColor(this.args.color.r,this.args.color.g,this.args.color.b,a)).tostring();
		dv.ctx.sector(this.args.x,this.args.y,this.args.radius,0,2*Math.PI);
		dv.ctx.fill();
		if (this.args.bubbleText!="")
		{
			testStr = this.args.bubbleText;
			if (dv.ctx.measureText("D").width>dv.ctx.measureText("testStr").width)
				teststr = 'D';
			rightfont = DVgetRightTextStyleByStrLenght(dv,teststr,this.args.radius*1.8);
			dv.ctx.font = rightfont;
			dv.ctx.textAlign = 'center';
			dv.ctx.fillStyle = '#FFF';
			dv.ctx.fillText(this.args.bubbleText,this.args.x,this.args.y+dv.ctx.measureText("D").width*1.0/2);
		}
	}
	dv.ctx.restore();
}


/**
 * A DVisual graph element indicate a text
 * @constructor
 * @example new DVDot({'x':100,'y':100,'font'="13px Arial"});
 * @param {Object[]} args - a array contain arguments below
 * @param {double} args.x - the x value of the dot
 * @param {double} args.y - the y value of the dot,0 in default
 * @param {string} args.text - the text content you want to draw
 * @param {string=} [args.font="8px Arial"] - the text's font
 * @param {DVColor=} [args.color = new DVColor()] - the color of the dot,black in default
 * @param {string=} [args.style ='fill']- the style of this dot,should be one of 'fill','stroke'
 * @param {boolean=} [args.shadow =true] - whether draw text's shadow.
 * @param {double=} [args.maxwidth =-1] - the limited width of printed text,-1 means no limit
 * @param {string=} [args.textAlign = 'left'] - the text align of printed text position
 * @param {string=} [args.direction = 'horizontal'] - the direction of text:horizontal or vertical
 * @param {double=} [args.lineWidth = '1'] - the lineWidth of text
 * @param {double=} [args.rotate = 0] - the lineWidth of text
 */
function DVText(args)
{
	if (arguments.length==0)
		args = {};
	this.args = args.cloneAll();
	if (args['x']==null)
		this.args['x'] = 0;

	if (args['y']==null)
		this.args['y'] = 0;

	if (args['text']==null)
		this.args['text'] = "";

	if (args['font']==null)
		this.args['font'] = "8px Arial";

	if (args['color']==null)
		this.args['color'] = new DVColor();

	if (args['style']==null || (args.style!="stroke" && args.style!="fill"))
		this.args['style'] = "fill";

	if (args['shadow']==null)
		this.args['shadow'] = true;

	if (args['maxwidth']==null)
		this.args['maxwidth'] = -1;

	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;

	if (args['rotate']==null)
		this.args['rotate'] = 0;

	if (args['textAlign']==null)
		this.args['textAlign'] = 'left';

	if (args['direction']==null || (args['direction']!='vertical' && args['direction']!='horizontal'))
		this.args['direction'] = 'horizontal';

}
/**
 * draw the text on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw
 */
DVText.prototype.draw = function(dv)
{
	dv.ctx.save();
	dv.ctx.fillStyle = this.args.color.tostring();
	dv.ctx.strokeStyle = this.args.color.tostring();
	dv.ctx.font = this.args['font'];
	dv.ctx.lineWidth = this.args['lineWidth'];
	dv.ctx.textAlign = this.args['textAlign'];
	shadow = new DVColor(100,100,100,0.3);
	if (this.args['shadow'])
	{
		if (this.shadowText == null)
		{
			shadowArgs = this.args.cloneAll();
			shadowArgs['color'] = new DVColor(100,100,100,0.3);
			shadowArgs['shadow'] = false;
			shadowArgs['x']+=1;
			shadowArgs['y']+=1;
			this.shadowText = new DVText(shadowArgs);
		}
		this.shadowText.draw(dv);
	}
	x = this.args.x;
	y = this.args.y;
	if (this.args.direction=='vertical')
	{
		dv.ctx.rotate(-Math.PI/2)
		tmp = x;
		x = -y;
		y = tmp;
	}
	if (this.args.rotate!=0)
	{
		
		dv.ctx.translate(x,y);
		x = 0;
		y = 0;
		dv.ctx.rotate(this.args.rotate);
	}
	if (this.args['style']=='stroke')
	{
		if (this.args['maxwidth']==-1)
			dv.ctx.strokeText(this.args.text,x,y);
		else
			dv.ctx.strokeText(this.args.text,x,y,this.args['maxwidth']);
	}
	if (this.args['style']=='fill')
	{
		if (this.args['maxwidth']==-1)
			dv.ctx.fillText(this.args.text,x,y);
		else
			dv.ctx.fillText(this.args.text,x,y,this.args['maxwidth']);
	}
	if (this.args.direction=='vertical')
	{
		dv.ctx.rotate(Math.PI/2);
	}
	if (this.args.rotate!=0)
	{
		dv.ctx.rotate(-this.args.rotate);
		dv.ctx.translate(-this.args.x,-this.args.y);
	}
	dv.ctx.restore();
}

/**
 * A DVisual graph element indicate a line
 * @constructor
 * @example new DVLine({'beginX':100,'beginY':100,'endX':20,'endY':20,'style':'dash'});
 * @param {Object[]} args - a array contain arguments below
 * @param {double} args.beginX - the x value of the start node
 * @param {double} args.beginY - the y value of the start node
 * @param {double} args.endX - the x value of the stop node
 * @param {double} args.endY - the y value of the stop node
 * @param {DVColor=} [args.color = new DVColor()] - the color of the dot,black in default
 * @param {string=} [args.style ='real']- the style of this dot,should be one of 'real','dash'
 * @param {boolean=} [args.shadow =true] - whether draw the line's shadow.
 * @param {double=} [args.lineWidth = '1'] - the lineWidth of line
 */
function DVLine(args)
{
	if (arguments.length==0)
		args = {};
	this.args = args.cloneAll();
	if (args['beginX']==null)
		this.args['beginX'] = 0;

	if (args['beginY']==null)
		this.args['beginY'] = 0;

	if (args['endX']==null)
		this.args['endX'] = 0;

	if (args['endY']==null)
		this.args['endY'] = 0;

	if (args['color']==null)
		this.args['color'] = new DVColor();

	if (args['style']==null || (args.style!="real" && args.style!="dash"))
		this.args['style'] = "real";

	if (args['shadow']==null)
		this.args['shadow'] = true;
	
	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;
}
/**
 * get the shadow according to the line's direction
 * @function
 * @return [0,1]
 */
DVLine.prototype.getShadow = function()
{
	// if ((this.args.beginX<this.args.endX && this.args.beginY<=this.args.endY)
	// 	|| (this.args.beginX>this.args.endX && this.args.beginY>this.args.endY))
	// 	return [0,-1]
	return [0,1]
}
/**
 * whether the node in the lines's region
 * @function
 * @param {double} x -the x value of test node
 * @param {double} y -the y value of test node
 * @return {boolean} result -whether (x,y) is in the line's region
 */
DVLine.prototype.between =function(x,y)
{
	if (x>=Math.min(this.args['beginX'],this.args['endX']) && x<=Math.max(this.args['beginX'],this.args['endX']) &&
		y>=Math.min(this.args['beginY'],this.args['endY']) && y<=Math.max(this.args['beginY'],this.args['endY']))
		return true;
	return false;
}
/**
 * draw the line on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVLine.prototype.draw = function(dv)
{
	dv.ctx.save();
	dv.ctx.fillStyle = this.args.color.tostring();
	dv.ctx.strokeStyle = this.args.color.tostring();
	dv.ctx.lineWidth = this.args['lineWidth'];
	if (this.args['shadow'])
	{
		if (this.shadowLine==null)
		{
			shadowArgs = this.args.cloneAll();
			shadowArgs['color'] = new DVColor(100,100,100,0.3);
			shadowArgs['shadow'] = false;
			shadow = this.getShadow();
			shadowArgs['beginX']+=shadow[0];
			shadowArgs['beginY']+=shadow[1];
			shadowArgs['endX']+=shadow[0];
			shadowArgs['endY']+=shadow[1];
			this.shadowLine = new DVLine(shadowArgs);
		}
		
		this.shadowLine.draw(dv);
	}
	if (this.args['style']=='real')
	{
		dv.ctx.beginPath();
		dv.ctx.moveTo(this.args.beginX,this.args.beginY);
		dv.ctx.lineTo(this.args.endX,this.args.endY);
		dv.ctx.closePath();
		dv.ctx.fill();
		dv.ctx.stroke();
	}
	if (this.args['style']=='dash')
	{
		dv.ctx.beginPath();
		xinc = this.args['endX'] - this.args['beginX'];
		yinc = this.args['endY'] - this.args['beginY'];
		length = Math.sqrt(xinc*xinc+yinc*yinc);
		doted = Math.max(length*1.0/50,5);

		xinc*=doted/length;
		yinc*=doted/length;
		x = this.args['beginX'];
		y = this.args['beginY'];
		while (this.between(x+xinc,y+yinc))
		{
			dv.ctx.moveTo(x,y)
			dv.ctx.lineTo(x+xinc,y+yinc)
			x+=2*xinc;
			y+=2*yinc;
		}
		dv.ctx.moveTo(x,y)
		dv.ctx.lineTo(this.args['endX'],this.args['endY'])
		dv.ctx.closePath();
		dv.ctx.stroke();
	}
	dv.ctx.restore();
}




/**
 * A DVisual graph element indicate a quadratic Curve
 * @constructor
 * @example new DVLine({'beginX':100,'beginY':100,'endX':20,'endY':20,'style':'dash'});
 * @param {Object[]} args - a array contain arguments below
 * @param {double} args.beginX - the x value of the start node
 * @param {double} args.beginY - the y value of the start node
 * @param {double} args.endX - the x value of the stop node
 * @param {double} args.endY - the y value of the stop node
 * @param {double} args.cpx - the x value of the control node
 * @param {double} args.cpy - the y value of the control node
 * @param {DVColor=} [args.color = new DVColor()] - the color of the dot,black in default
 * @param {double=} [args.lineWidth = '1'] - the lineWidth of line
 */
function DVCurve(args)
{
	if (arguments.length==0)
		args = {};
	this.args = args.cloneAll();
	if (args['beginX']==null)
		this.args['beginX'] = 0;

	if (args['beginY']==null)
		this.args['beginY'] = 0;

	if (args['endX']==null)
		this.args['endX'] = 0;

	if (args['endY']==null)
		this.args['endY'] = 0;

	if (args['color']==null)
		this.args['color'] = new DVColor();

	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;
}


/**
 * draw the curve on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVCurve.prototype.draw = function(dv)
{
	dv.ctx.save();
	dv.ctx.fillStyle = this.args.color.tostring();
	dv.ctx.strokeStyle = this.args.color.tostring();
	dv.ctx.lineWidth = this.args['lineWidth'];
	dv.ctx.beginPath();
	dv.ctx.moveTo(this.args.beginX,this.args.beginY);
	dv.ctx.quadraticCurveTo(this.args.cpx,this.args.cpy,this.args.endX,this.args.endY);
	dv.ctx.stroke();
	dv.ctx.restore();
}



/**
 * A DVisual graph element indicate a polygon
 * @constructor
 * @example new DVPolygon({'X':[10,10,20,20],'Y':[10,20,20,10],'style':'stroke'});
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(double)} args.X - the set of a series nodes' x value
 * @param {Array(double)} args.Y - the set of a series nodes' y value
 * @param {DVColor=} [args.color = new DVColor()] - the color of the dot,black in default
 * @param {string=} [args.style ='fill']- the style of this dot,should be one of 'fill','stroke'
 * @param {boolean=} [args.shadow =true] - whether draw text's shadow.
 * @param {double=} [args.lineWidth = '1'] - the lineWidth of text
 */
 function DVPolygon(args)
{
	if (arguments.length==0)
		args = {};
	this.args = args.cloneAll();
	if (args['X']==null)
		this.args['X'] = [];

	if (args['Y']==null)
		this.args['Y'] = [];

	if (this.args.X.length!=this.args.Y.length)
		return null;

	if (args['color']==null)
		this.args['color'] = new DVColor();

	if (args['style']==null || (args.style!="fill" && args.style!="stroke" && args.style!="transFill"))
		this.args['style'] = "transFill";

	if (args['shadow']==null)
		this.args['shadow'] = true;
	
	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;

}

/**
 * draw the polygon on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVPolygon.prototype.draw = function(dv)
{
	dv.ctx.save();
	dv.ctx.fillStyle = this.args.color.tostring();
	dv.ctx.strokeStyle = this.args.color.tostring();
	dv.ctx.lineWidth = this.args['lineWidth'];
	if (this.args['shadow'])
	{
		if (this.shadowPoly==null)
		{
			shadowArgs = this.args.cloneAll();
			shadowArgs['color'] = new DVColor(200,200,200,0.3);
			shadowArgs['shadow'] = false;
			for (var i=0;i<shadowArgs.X.length;i++ )
			{
				shadowArgs.X[i]+=1;
				shadowArgs.Y[i]+=1;
			}
			this.shadowPoly = new DVPolygon(shadowArgs);
		}
		this.shadowPoly.draw(dv);
	}
	if (this.args['style']=='stroke' || this.args['style']=='fill')
	{
		dv.ctx.beginPath();
		dv.ctx.moveTo(this.args.X[0],this.args.Y[0]);
		for (var i=0;i<this.args.X.length;i++)
		{
			dv.ctx.lineTo(this.args.X[(i+1)%this.args.X.length],this.args.Y[(i+1)%this.args.X.length]);
		}
		dv.ctx.closePath();
		if (this.args['style']=='stroke')
			dv.ctx.stroke();
		if (this.args['style']=='fill')
			dv.ctx.fill();
	}

	if (this.args['style']=='transFill')
	{
		dv.ctx.beginPath();
		dv.ctx.moveTo(this.args.X[0],this.args.Y[0]);
		for (var i=0;i<this.args.X.length;i++)
		{
			dv.ctx.lineTo(this.args.X[(i+1)%this.args.X.length],this.args.Y[(i+1)%this.args.X.length]);
		}	
		dv.ctx.closePath();
		dv.ctx.stroke();

		dv.ctx.fillStyle = (new DVColor(this.args.color.r,this.args.color.g,this.args.color.b,0.5)).tostring();
		dv.ctx.beginPath();
		dv.ctx.moveTo(this.args.X[0],this.args.Y[0]);
		for (var i=0;i<this.args.X.length;i++)
		{
			dv.ctx.lineTo(this.args.X[(i+1)%this.args.X.length],this.args.Y[(i+1)%this.args.X.length]);
		}		
		dv.ctx.closePath();
		dv.ctx.fill();
	}
	dv.ctx.restore();
}

/**
 * A DVisual graph element indicate a Rect
 * @constructor
 * @example new DVLine({'beginX':100,'beginY':100,'endX':20,'endY':20,'style':'dash'});
 * @param {Object[]} args - a array contain arguments below
 * @param {double} args.x - the x value of the Rect's start node(left top node)
 * @param {double} args.y - the y value of the Rect's start node(left top node)
 * @param {double} args.height - the height of the Rect
 * @param {double} args.y - the width of the Rect
 * @param {others=} [args.others] - !!!the same with DVPolygon's arguments.!!!(others is not an argument,but an annotation)
 */
function DVRect(args)
{
	if (arguments.length==0)
		args = {};
	this.args = args.cloneAll();
	if (args['x']==null)
		this.args['x'] = 0;

	if (args['y']==null)
		this.args['y'] = 0;

	if (args['height']==null)
		this.args['height'] = 0;

	if (args['width']==null)
		this.args['width'] = 0;
}
/**
 * draw the Rect on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVRect.prototype.draw = function(dv)
{
	if (this.polyRect==null)
	{
		this.args['X'] = [this.args['x'],this.args['x'],this.args['x']+this.args['width'],this.args['x']+this.args['width']];
		this.args['Y'] = [this.args['y'],this.args['y']+this.args['height'],this.args['y']+this.args['height'],this.args['y']];
		this.polyRect = new DVPolygon(this.args);
	}
	this.polyRect.draw(dv);
}

/**
 * A DVisual graph element indicate a Coordinate,the main structure of most chart
 * @constructor
 * @example new DVCoordinate({'xDescript':"time",'yDescript':"value",'xSpan':20,'ySpan'});
 * @param {Object[]} args - a array contain arguments below
 * @param {boolean} args.xGrid - whether draw the grid line started from X axes
 * @param {boolean} args.yGrid - whether draw the grid line started from Y axes
 * @param {string=} [args.xStyle='value'] - the X axes's style,'value' or 'class'
 * @param {string=} [args.yStyle='value'] - the Y axes's style,'value' or 'percentage%'
 * @param {Array(string)} args.classes - when x's Style is 'class',you need this argument to show the texts of each class on the X-axes
 * @param {Array(string)} args.yClass - to make the horizental chart
 * @param {string=} [args.xDescript='x'] - the X axes's description
 * @param {string=} [args.yDescript='y'] - the Y axes's description
 * @param {double} args.xSpan - the increment on x value in each grid,(data space)
 * @param {double} args.ySpan - the increment on y value in each grid,(data space)
 * @param {double=} [args.lineWidth = '1'] - the lineWidth of text
 */
function DVCoordinate(args)
{
	if (arguments.length==0)
		args = {};
	this.args = args.cloneAll();
	if (args['xGrid']==null)
		this.args['xGrid'] = true;

	if (args['yGrid']==null)
		this.args['yGrid'] = true;

	if (args['xStyle']==null || (args['xStyle']!='value' && args['xStyle']!='class'))
		this.args['xStyle'] = 'value';

	if (args['yStyle']==null || (args['yStyle']!='value' && args['yStyle']!='percentage' && args['yStyle']!='class'))
		this.args['yStyle'] = 'value';

	if (args['classes']==null)
		this.args['classes'] = ["A",'B','C'];

	if (args['yClasses']==null)
		this.args['yClasses'] = ["A",'B','C'];

	if (args['xDescript']==null)
		this.args['xDescript'] = "";

	if (args['yDescript']==null)
		this.args['yDescript'] = "";

	if (args['xSpan']==null)
		this.args['xSpan'] = 50.0;

	if (args['ySpan']==null)
		this.args['ySpan'] = 50.0;

	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;

	this.eles = new Array();

}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVCoordinate.prototype.prepare = function(dv)
{
	x_axes_arg = {'beginX':dv.originX,'beginY':dv.originY,'endX':dv.oldWidth-20,'endY':dv.originY};
	y_axes_arg = {'beginX':dv.originX,'beginY':dv.originY,'endX':dv.originX,'endY':20};
	this.eles.push(new DVLine(x_axes_arg));
	this.eles.push(new DVLine(y_axes_arg));

	if (this.args['xDescript']!="")
	{
		x_des_arg = {'x':dv.oldWidth-20-20+2,'y':dv.originY+10,'text':this.args['xDescript'],'textAlign':'center','maxwidth':40}
		x_des_poly_arg = {'X':[dv.oldWidth-20-40,dv.oldWidth-20-40,dv.oldWidth-20,dv.oldWidth-20+10,dv.oldWidth-20],
							'Y':[dv.originY,dv.originY+15,dv.originY+15,dv.originY+7.5,dv.originY],'style':'stroke'}
		this.eles.push(new DVPolygon(x_des_poly_arg));
		this.eles.push(new DVText(x_des_arg));
	}


	x = dv.Xinc;
	if (this.args['xStyle']=='class')
		x+=0.5;
	y = dv.Yinc;
	//dv.XZoom = 0.01;
	while (dv.xyTrans(x,y)[0]<dv.oldWidth - 70)
	{
		if (this.args['xStyle']=='class' && x>=this.args.classes.length)
			break;
		result = dv.xyTrans(x,y);
		str = x + "";
		if (this.args['xStyle']=='class')
			str = this.args.classes[x-0.5];
		metrics = dv.ctx.measureText(str);
		x_kedu_arg = {'x':result[0]-metrics.width/2,'y':result[1]+ dv.ctx.measureText("D").width+8,'text':str,'lineWidth':this.args['lineWidth']};
		x_kedu_line_arg = {'beginX':result[0],'beginY':result[1],'endX':result[0],'endY':result[1]-5};
		if (this.args.xGrid)
		{
			color = new DVColor(100,100,100,0.1);
			if (dv.Xinc<0 && x==0)
				color = new DVColor(256,0,0,0.3);
			xgrid_line = {'beginX':result[0],'beginY':result[1],'endX':result[0],'endY':0,'color':color,'shadow':false};
			this.eles.push(new DVLine(xgrid_line));
		}
		this.eles.push(new DVText(x_kedu_arg));
		this.eles.push(new DVLine(x_kedu_line_arg));

		x += this.args.xSpan;
		if (this.args['xStyle']=='class' && x>=this.args.classes.length)
			break;
	}
	

	if (this.args['yDescript']!="")
	{
		x_des_arg = {'x':21,'y':40-2,'text':this.args['yDescript'],'textAlign':'center','maxwidth':40,'direction':'vertical'}
		x_des_poly_arg = {'X':[dv.originX,dv.originX-15,dv.originX-15,dv.originX-7.5,dv.originX],
							'Y':[20+40,20+40,20,10,20],'style':'stroke'}
		this.eles.push(new DVPolygon(x_des_poly_arg));
		this.eles.push(new DVText(x_des_arg));
	}
	x = dv.Xinc;
	y = dv.Yinc;
	count = 0;
	while (dv.xyTrans(x,y)[1]>70)
	{
		result = dv.xyTrans(x,y);
		if (this.args.yStyle=='value')
			str = y+"";
		else if (this.args.yStyle=='percentage')
			str = y.toFixed(2)*100+"%";
		else if (this.args.yStyle=='class' && count<this.args.yClasses.length)
			str = this.args.yClasses[count];
		count++;

		metrics = dv.ctx.measureText(str);
		y_kedu_arg = {'x':result[0]-metrics.width-2,'y':result[1]+dv.ctx.measureText("D").width/2,'text':str};
		y_kedu_line_arg = {'beginX':result[0],'beginY':result[1],'endX':result[0]+5,'endY':result[1]};
		if (this.args.yGrid)
		{
			color = new DVColor(100,100,100,0.1);
			if (dv.Yinc<0 && y==0)
				color = new DVColor(256,0,0,0.3);
			ygrid_line = {'beginX':result[0],'beginY':result[1],'endX':result[0]+dv.oldWidth,'endY':result[1],'color':color,'shadow':false};
			this.eles.push(new DVLine(ygrid_line));
		}
		this.eles.push(new DVText(y_kedu_arg));
		this.eles.push(new DVLine(y_kedu_line_arg));
		y += this.args.ySpan;
	}
}
/**
 * draw the Coordinate on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVCoordinate.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
}



/**
 * A DVisual graph element indicate a Legend,an important structure of most chart
 * @constructor
 * @example new DVLegend({'xDescript':"time",'yDescript':"value",'xSpan':20,'ySpan'});
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(string)} args.classes - the classes's texts for the legend
 * @param {Array(DVColor)=} [args.colors=DVgetRandomColor(this.args.classes.length,0.7);] - the classes's colors for the legend
 * @param {double} args.x - the x value of the Legend's start node(left bottom node)
 * @param {double} args.y - the y value of the Legend's start node(left bottom node)
 * @param {string=} [args.style='rect'] - the legend's note shape for each class,'rect','line' or 'bubble'
 * @param {boolean=} [args.outerbox='true'] - whether draw the outerbox of legend
 * @param {string=} [args.direction='vertical'] - the direction of legend,'vertical' means put all data in a column.'horizontal' means in a row
 * @param {double=} [args.height=!!according to the canvas!!] - the height limit of Legend
 * @param {double=} [args.width=!!according to the canvas!!] - the width limit of Legend
 */
function DVLegend(args)
{
	if (arguments.length==0)
		args = {};
	this.args = args.cloneAll();

	if (args['classes']==null)
		this.args['classes'] = ["A",'B','C'];

	if (args['colors']==null)
		this.args['colors'] = DVgetRandomColor(this.args.classes.length,0.7);

	if (args['x']==null)
		this.args['x'] = 100;

	if (args['y']==null)
		this.args['y'] = 100;

	if (args['style']==null || (args['style']!='rect' && args['style']!='line'  && args['style']!='bubble'))
		this.args['style'] = 'rect';

	if (args['outerbox']==null)
		this.args['outerbox'] = true;

	if (args['direction']==null || (args['direction']!='vertical' && args['direction']!='horizontal') )
		this.args['direction'] = 'vertical';

	if (args['height']==null)
		this.args['height'] = 0;

	if (args['width']==null)
		this.args['width'] = 0;
	this.eles = new Array();

}
/**
 * get the legend's height and width according to the dvisual instance
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 * @return {Array} result - [height,width] 
 */
DVLegend.prototype.getHeightWidth =function(dv)
{
	if (this.args['direction']=='vertical')
		return [dv.yLenTrans((dv.Ymargin*1.0/6)),dv.xLenTrans((dv.Xmargin*1.0/5))]
	return [20,dv.xLenTrans((dv.Xmargin*1.0*2/3))]
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVLegend.prototype.prepare = function(dv)
{
	if (this.args['width']==0 && this.args['height']==0)
	{
		this.args['height'] = this.getHeightWidth(dv)[0];
		this.args['width'] = this.getHeightWidth(dv)[1];
	}
	if (this.args.direction=='vertical')
		TextHeight = this.args['height']/(this.args.classes.length*4.0/3);
	else 
		TextHeight = 20.0/4*3;
	drawXinc = 0.0;
	drawYinc = 0.0;
	drawLength = this.args['width']/(6.0/5);
	if (this.args.direction=='vertical')
		drawYinc = TextHeight*4.0/3;
	else
	{
		drawXinc = this.args['width']/(6.0/5*this.args.classes.length)*6/5;
		drawLength = this.args['width']/(6.0/5*this.args.classes.length);
	}

	font = DVgetRightTextStyle(dv,TextHeight*0.5);
	boxtopy = this.args.y-this.args.height;
	if (this.args.outerbox)
	{
		this.eles.push(new DVRect({'x':this.args.x,'y':boxtopy,'width':this.args.width,'height':this.args.height,'style':'fill',
									'color':new DVColor(30,144,255,0.3)}))
	}
	dv.ctx.save();
	dv.ctx.font = font;
	maxlength = 0;
	for (var i=0;i<this.args.classes.length;i++)
	{
		maxlength = Math.max(maxlength,dv.ctx.measureText(this.args.classes[i]).width);
	}
	for (var i=0;i<this.args.classes.length;i++)
	{
		paintX = drawLength/10 + drawXinc*i +this.args.x;
		paintY = TextHeight/6 +drawYinc*i +boxtopy;
		ratio = 2.0/4;
		// this.eles.push(new DVRect({'x':paintX,'y':paintY,'width':drawLength,'height':TextHeight,'style':'fill',
		// 							'color':new DVColor(0,0,0,0.7)}))
		if (maxlength<drawLength*(1-ratio)*1.0)
		{
			ratio = 1 - maxlength*1.0/drawLength;
		}
		if (this.args.style=='rect')
			this.eles.push(new DVRect({'x':paintX,'y':paintY,'width':drawLength*ratio,'height':TextHeight,'style':'fill',
									'color':this.args.colors[i]}));
		else if (this.args.style=='line')
			this.eles.push(new DVLine({'beginX':paintX,'beginY':paintY+TextHeight*1.0/2,
									'endX':paintX + drawLength*ratio,"endY":paintY+TextHeight*1.0/2,
									'color':this.args.colors[i],'lineWidth':3}));
		else if (this.args.style=='bubble')
		{ 
			this.eles.push(new DVDot({'x':paintX+drawLength*ratio/3,'y':paintY+TextHeight*1.0/2,'radius':TextHeight*1.0/2,'style':'bubble','color':this.args.colors[i]}));
			ratio*=3.0/4;
		}
		this.eles.push(new DVText({'text':this.args.classes[i],'x':paintX + drawLength*ratio+drawLength*(1-ratio)*1.0*0+2,'y':paintY+TextHeight*1.0/1.3,'textAlign':'left',
									'maxwidth':drawLength*(1-ratio)*1.0,'font':font}))
	}
	dv.ctx.restore();
}
/**
 * draw the Coordinate on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVLegend.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=0;i<this.eles.length;i++)
		this.eles[i].draw(dv);
}

/**
 * get the fitted font style according to the height of text
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 * @param {double} length - the height limit of text
 * @return {string} font - the fitted font string.
 */
DVgetRightTextStyle = function(dv,length)
{
	dv.ctx.save();
	i = 0;
	for (i=1;i<100;i++)
	{
		dv.ctx.font = i+"px Arial";
		if (dv.ctx.measureText("D").width>length)
		{
			i = i - 1;
			dv.ctx.restore();
			return i+"px Arial";
		}
	}
	dv.ctx.restore();
	return i + "px Arial";
	
}

/**
 * get the fitted font style according to text and the length limit of text
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 * @param {string} str - the text you want to draw
 * @param {double} length - the height limit of text
 * @return {string} font - the fitted font string.
 */
DVgetRightTextStyleByStrLenght = function(dv,str,length)
{
	dv.ctx.save();
	i = 0;
	for (i=1;i<100;i++)
	{
		dv.ctx.font = i+"px Arial";
		if (dv.ctx.measureText(str).width>length)
		{
			i = i - 1;
			dv.ctx.restore();
			return i+"px Arial";
		}
	}
	dv.ctx.restore();
	return i + "px Arial";
	
}

 

/**
 * A DVisual graph element indicate a LineChart,integrate the dot,line,area or bubble  chart for a single path
 * @constructor
 * @example new DVLineChart({'X':[1,2,3,4,5],'Y':[1,2,3,4,5],'style':'area|dot'});
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(double)} args.X - the set of a series nodes' x value
 * @param {Array(double)} args.Y - the set of a series nodes' y value
 * @param {string=} [args.style='dot|line'] - the legend's note shape for each class,'dot','line','area' can be used simultaneously,'bubble' style is unique
 * @param {DVColor=} [args.color = new DVColor(256,0,0,0.8)] - the color of the line/dot/area/bubble
 * @param {double=} [args.lineWidth = '1'] - the lineWidth of graph
 * @param {string=} [args.xDescript='x'] - the X axes's description
 * @param {string=} [args.yDescript='y'] - the Y axes's description
 * @param {boolean=} [args.xGrid=true] - whether draw the grid line started from X axes
 * @param {boolean=} [args.yGrid=true] - whether draw the grid line started from Y axes
 * @param {Array(double)} args.bubbleRadius - when the style is bubble,you should indicate the radius for each bubble
 */
function DVLineChart(args)
{
	if (arguments.length==0)
		args = {};

	this.args = args.cloneAll();
	if (args['X']==null)
		this.args['X'] = [];

	if (args['Y']==null)
		this.args['Y'] = [];

	if (args['style']==null)
		this.args['style'] = 'dot|line';

	if (args['color']==null)
		this.args['color'] = new DVColor(256,0,0,0.8);

	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;

	if (args['xDescript']==null)
		this.args['xDescript'] = "x";

	if (args['yDescript']==null)
		this.args['yDescript'] = "y";

	if (args['xGrid']==null)
		this.args['xGrid'] = true;

	if (args['yGrid']==null)
		this.args['yGrid'] = true;

	if (args['bubbleRadius']==null)
		this.args['bubbleRadius'] = [];

	this.eles = new Array();
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVLineChart.prototype.prepare = function(dv)
{
	if (!dv.drawed)
	{
		dv.initial(this.args.X,this.args.Y);
		ySpan = DVGetSpan(dv.Ymargin)
		xSpan = DVGetSpan(dv.Xmargin)
		cord_arg = {'xGrid':this.args.xGrid,'yGrid':this.args.yGrid,'xDescript':this.args.xDescript,'yDescript':this.args.yDescript,
					'xSpan':xSpan,'ySpan':ySpan}

		this.eles.push(new DVCoordinate(cord_arg));
		dv.initialZ(this.args.bubbleRadius);
	}

	Xs = new Array();
	Ys = new Array();
	for (var i=0;i<this.args.X.length;i++)
	{
		result = dv.xyTrans(this.args.X[i],this.args.Y[i]);
		Xs.push(result[0]);
		Ys.push(result[1]);
	}
	if (this.args.style.indexOf('dot')!=-1)
	{
		for (var i=0;i<this.args.X.length;i++)
		{
			this.eles.push(new DVDot({'x':Xs[i],'y':Ys[i],'color':this.args.color}));
		}
	}
	if (this.args.style.indexOf('line')!=-1)
	{
		for (var i=0;i<this.args.X.length-1;i++)
		{
			this.eles.push(new DVLine({'beginX':Xs[i],'beginY':Ys[i],'endX':Xs[i+1],'endY':Ys[i+1],'color':this.args.color}));
		}
	}
	if (this.args.style.indexOf('area')!=-1)
	{
		beginsX = dv.xyTrans(this.args.X[0],0)[0];
		endX = dv.xyTrans(this.args.X[Xs.length-1],0)[0];
		SubY = dv.xyTrans(this.args.X[Xs.length-1],0)[1];
		Xs.push(endX)
		Xs.push(beginsX)
		Ys.push(SubY-1)
		Ys.push(SubY-1)
		poly_arg = {'X':Xs,'Y':Ys,'color':this.args.color}
		this.eles.push(new DVPolygon(poly_arg));
	}
	if (this.args.style.indexOf('bubble')!=-1)
	{
		for (var i=0;i<this.args.X.length;i++)
		{
			this.eles.push(new DVDot({'x':Xs[i],'y':Ys[i],'color':this.args.color,'style':'bubble','radius':dv.zLenTrans(this.args.bubbleRadius[i])}));
		}
	}
}
/**
 * draw the DVLineChart on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVLineChart.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
}
/**
 * get a random number in certain margin
 * @function
 * @param {double} N - the margin of random number you want
 * @return {double} randomN - the random number
 */
function getrandom(N)
{
	return Math.floor(Math.random() * ( N + 1));
}

/**
 * get a series of DVColor
 * @function
 * @param {int} lens - how many colors you want.
 * @param {double=} [alpha=0.7] - the alpha component 
 * @return {Array()} randomN - the random color set
 */
function DVgetRandomColor(lens,alpha)
{
	result = new Array();
	if (arguments.length==1)
		alpha = 0.7;
	for (var i=0;i<lens;i++)
	{
		result.push(new DVColor(getrandom(256),getrandom(256),getrandom(256),alpha));
	}
	return result
}
/**
 * get the min and max for a 2d array
 * @function
 * @param {Array(Array(double))} Xs - the 2d Array
 * @return {Array()} [min,max] - the minium and maxium of the 2D array.
 */
function DV2dArrMinMax(Xs)
{
	mins = 100000;
	maxx = -10000;
	for (var i=0;i<Xs.length;i++)
		for (var j=0;j<Xs[i].length;j++)
		{
			mins = Math.min(mins,Xs[i][j]);
			maxx = Math.max(maxx,Xs[i][j]);
		}
	return [mins,maxx]
}

/**
 * A DVisual graph element indicate a Multiple Line Chart,integrate the dot,line,area or bubble  chart for multiple path
 * @constructor
 * @example new DVMulLineChart({'Xs':[[1,2,3,4,5,6],[1,2,3,4,5,6]],'Ys':[[1,2,3,4,3,6],[3,5,2,7,5,2]],'classes':['A','B'],'style':'dot|line'});
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(Array(double))} args.Xs - the set of multiple series nodes' x value,the length indicate how many kinds (dot,line,area,bubble)'s  you want to draw
 * @param {Array(Array(double))} args.Ys - the set of multiple series nodes' y value,the length indicate how many kinds (dot,line,area,bubble)'s  you want to draw
 * @param {boolean=} [args.legendOuterBox=true] - whether draw the outer box of legend
 * @param {Array(Array(double))=} args.Zs - !!!the third degree of data,the bubble chart need it.!!!
 * @param {Array(Array(DVColor))=} [args.colors=!!randomcolor!!] - the color for each kind of elements.
 * @param {Array(string)} args.classes - the description for each set of (dot,line,area,bubble),the length is the kinds number of (dot,line,area,bubble)
 * @param {string=} [args.xDescript='x'] - the X axes's description
 * @param {string=} [args.yDescript='y'] - the Y axes's description
 * @param {boolean=} [args.xGrid=true] - whether draw the grid line started from X axes
 * @param {boolean=} [args.yGrid=true] - whether draw the grid line started from Y axes
 */
function DVMulLineChart(args)
{
	if (arguments.length==0)
		args = {};
	this.args = args.cloneAll();

	if (args['Xs']==null)
		this.args['Xs'] = [];

	if (args['Ys']==null)
		this.args['Ys'] = [];

	if (args['legendOuterBox']==null)
		this.args['legendOuterBox'] = true;

	if (args['Zs']==null)
		this.args['Zs'] = [];

	if (args['classes']==null)
		this.args['classes'] = [];

	if (args['style']==null)
		this.args['style'] = 'dot|line';

	if (args['colors']==null)
		this.args['colors'] = DVgetRandomColor(this.args['classes'].length)

	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;

	if (args['xDescript']==null)
		this.args['xDescript'] = "x";

	if (args['yDescript']==null)
		this.args['yDescript'] = "y";

	if (args['xGrid']==null)
		this.args['xGrid'] = true;

	if (args['yGrid']==null)
		this.args['yGrid'] = true;

	this.eles = new Array();
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVMulLineChart.prototype.prepare = function(dv)
{
	dv.drawed = true;
	x_minmax = DV2dArrMinMax(this.args.Xs);
	y_minmax = DV2dArrMinMax(this.args.Ys);
	dv.initial(x_minmax,y_minmax)
	ySpan = DVGetSpan(dv.Ymargin)
	xSpan = DVGetSpan(dv.Xmargin)
	cord_arg = {'xGrid':this.args.xGrid,'yGrid':this.args.yGrid,'xDescript':this.args.xDescript,'yDescript':this.args.yDescript,
				'xSpan':xSpan,'ySpan':ySpan}
	this.eles.push(new DVCoordinate(cord_arg));
	if (this.args.style=='bubble')
	{
		dv.initialZ(DV2dArrMinMax(this.args.Zs))
		this.Rs = [];
		for (var i=0;i<this.args.Zs.length;i++)
		{
			this.Rs.push([])
			for (var j=0;j<this.args.Zs[i].length;j++)
			{
				this.Rs[i].push(dv.zLenTrans(this.args.Zs[i][j]));
			}
		}
	}
	for (var i=0;i<this.args.classes.length;i++)
	{
		line_arg = this.args.cloneAll();
		line_arg.Xs = null;
		line_arg.Ys = null;
		line_arg['X'] = this.args.Xs[i];
		line_arg['Y'] = this.args.Ys[i];
		line_arg.color = this.args.colors[i];
		if (this.args.style!='bubble')
		{
			this.eles.push(new DVLineChart({'X':this.args.Xs[i],'Y':this.args.Ys[i],'color':this.args.colors[i],'lineWidth':this.args.lineWidth,
											'style':this.args.style}));
		}
		else
		{
			this.eles.push(new DVLineChart({'X':this.args.Xs[i],'Y':this.args.Ys[i],'color':this.args.colors[i],'lineWidth':this.args.lineWidth,
											'bubbleRadius':this.args.Zs[i],'style':this.args.style}));
		}
	}
	if (this.args.style.indexOf('line')==-1)
	{
		style = 'rect';
		if (this.args.style=='bubble')
			style = 'bubble';
		result = dv.xyTrans(dv.Xmargin*(1-0.16)+dv.Xinc,dv.Ymargin/30+dv.Yinc);
		this.eles.push(new DVLegend({'classes':this.args.classes,'colors':this.args.colors,'x':result[0],'y':result[1],'outerbox':this.args.legendOuterBox,'style':style}))
	}
	else
	{
		result = dv.xyTrans(dv.Xmargin/5+dv.Xinc,dv.Ymargin/30+dv.Yinc);
		this.eles.push(new DVLegend({'classes':this.args.classes,'colors':this.args.colors,'x':result[0],'y':dv.oldHeight,
						'direction':'horizontal','style':'line','outerbox':this.args.legendOuterBox}))

	}
}
/**
 * draw the DVMulLineChart on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVMulLineChart.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
}



/**
 * A DVisual graph element indicate a Bar Chart,integrate the normal,stacked bar chart.
 * @constructor
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(string)} args.X - a list of string for each x-label
 * @param {Array(double)} args.Y - the set of a series value
 * @param {string=} [args.style='bar'] - the style of bar chart,'stacked' or 'bar'
 * @param {Array(Array(double))} args.stackedY - use for stacked bar chart,for each element in this array have #stacked_component numbers.
 * @param {Array(string)} args.stackedClass - a series of string indicate each stacked_component class.
 * @param {Array(DVColor)} args.stackedColors - a series of DVColor indicate each stacked_component class.
 * @param {int} args.all - how many bar you want for each X-label
 * @param {int} args.index - current data is the i-th bar for the each X-label
 * @param {DVColor=} [args.color = new DVColor(256,0,0,0.8)] - the color of the bar(normal bar)
 * @param {boolean=} [args.xGrid=false] - whether draw the grid line started from X axes
 * @param {boolean=} [args.yGrid=true] - whether draw the grid line started from Y axes
 * @param {string=} [args.xDescript='x'] - the X axes's description
 * @param {string=} [args.yDescript='y'] - the Y axes's description
 * @param {boolean=} [args.legendOuterBox=true] - whether draw the outer box of legend
 */
function DVBarChart(args)
{
	if (arguments.length==0)
		args = {};

	this.args = args.cloneAll();
	if (args['X']==null)
		this.args['X'] = [];

	if (args['Y']==null)
		this.args['Y'] = [];

	if (args['style']==null || (args['style']!='bar' && args['style']!='stacked'))
		this.args['style'] = 'bar';

	if (args['stackedY']==null)
		this.args['stackedY'] = [[]];

	if (args['stackedClass']==null)
		this.args['stackedClass'] = [];

	if (args['stackedColor']==null)
		this.args['stackedColor'] = DVgetRandomColor(this.args['stackedClass'].length);

	if (args['all']==null)
		this.args['all'] = 1;

	if (args['index']==null)
		this.args['index'] = 1;

	if (args['color']==null)
		this.args['color'] = new DVColor(256,0,0,0.8);

	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;

	if (args['xDescript']==null)
		this.args['xDescript'] = "x";

	if (args['yDescript']==null)
		this.args['yDescript'] = "y";

	if (args['xGrid']==null)
		this.args['xGrid'] = false;

	if (args['yGrid']==null)
		this.args['yGrid'] = true;

	if (args['legendOuterBox']==null)
		this.args['legendOuterBox'] = true;

	this.eles = new Array();
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVBarChart.prototype.prepare = function(dv)
{
	if (!dv.drawed)
	{
		if (this.args.style=='bar')
			dv.initial([0,this.args.X.length],this.args.Y);
		else
		{
			max_sum = 0;
			for (var i=0;i<this.args.X.length;i++)
			{
				sum = 0;
				for (var j=0;j<this.args.stackedY[i][j];j++)
					sum+=this.args.stackedY[i][j];
				max_sum = Math.max(max_sum,sum)
			}
			dv.initial([0,this.args.X.length],[0,max_sum*1.2]);
		}
		ySpan = DVGetSpan(dv.Ymargin)
		xSpan = 1;	
		cord_arg = {'xGrid':this.args.xGrid,'yGrid':this.args.yGrid,'xDescript':this.args.xDescript,'yDescript':this.args.yDescript,
					'xSpan':xSpan,'ySpan':ySpan,'xStyle':'class','classes':this.args.X}
		this.eles.push(new DVCoordinate(cord_arg));
	}

	if (this.args.style=='bar')
	{
		dv.ctx.save();
		for (var i=0;i<this.args.Y.length;i++)
		{
			left_most_X = i + 0.5 - 0.3;
			right_most_X = i + 0.5 - 0.3;
			K = this.args.all;
			xsec = 0.6/(5*K - 1);
			xwidth = xsec * 4;
			result = dv.xyTrans(left_most_X+xsec*5*(this.args.index-1),dv.Yinc+this.args.Y[i]);
			this.eles.push(new DVRect({'x':result[0],'y':result[1],
						'height':dv.yLenTrans(this.args.Y[i])-1,'width':dv.xLenTrans(xwidth),'color':this.args.color}));
			font = Math.min(dv.oldHeight,dv.oldWidth)/400*10+"px Arial";
			dv.ctx.font = font;
			
			this.eles.push(new DVText({'font':font,'text':this.args.Y[i],'textAlign':'center','x':result[0]+dv.xLenTrans(xwidth)/2,'y':result[1]-dv.ctx.measureText('D').width/2,'maxwidth':dv.xLenTrans(xwidth)}));
			
		}
		dv.ctx.restore();
	}
	if (this.args.style=='stacked')
	{
		for (var i=0;i<this.args.stackedY.length;i++)
		{
			left_most_X = i + 0.5 - 0.3;
			right_most_X = i + 0.5 - 0.3;
			K = this.args.all;
			xsec = 0.6/(5*K - 1);
			xwidth = xsec * 4;
			tmpy = dv.Yinc;
			for (var j=0;j<this.args.stackedY[i].length;j++)
			{
				result = dv.xyTrans(left_most_X+xsec*5*(this.args.index-1),tmpy+this.args.stackedY[i][j]);
				this.eles.push(new DVRect({'x':result[0],'y':result[1],
							'height':dv.yLenTrans(this.args.stackedY[i][j])-1,'width':dv.xLenTrans(xwidth),'color':this.args.stackedColor[j],'style':'fill'}));
				tmpy += this.args.stackedY[i][j];
			}
			//this.eles.push(new DVText({'text':this.args.Y[i],'textAlign':'center','x':result[0]+dv.xLenTrans(xwidth)/2,'y':result[1]-3,'maxwidth':dv.xLenTrans(xwidth)}));
		}
		result = dv.xyTrans(this.args.stackedY.length,dv.Ymargin/20);
		this.eles.push(new DVLegend({'outerbox':this.args.legendOuterBox,'classes':this.args.stackedClass,'colors':this.args.stackedColor,'x':result[0],'y':result[1]}))
	}
	// Xs = new Array();
	// Ys = new Array();
	// for (var i=0;i<this.args.X.length;i++)
	// {
	// 	result = dv.xyTrans(this.args.X[i],this.args.Y[i]);
	// 	Xs.push(result[0]);
	// 	Ys.push(result[1]);
	// }
}
/**
 * draw the DVBarChart on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVBarChart.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
}



/**
 * A DVisual graph element indicate a Muliple Bar Chart
 * @constructor
 * @param {Object} args - a array contain arguments below
 * @param {Array(string)} args.X - a list of string for each x-label
 * @param {Array(Array(double))} args.Ys - 2d Array,indicate a series bar value for each x-label.
 * @param {Array(string)} args.Z - a list of string indicate each kind of bar
 * @param {boolean=} [args.legendOuterBox=true] - whether draw the outer box of legend
 * @param {Array(DVColor)=} [args.colors=DVgetRandomColor(this.args['Z'].length)] - a series of DVColor indicate each kind of bar.
 * @param {boolean=} [args.xGrid=false] - whether draw the grid line started from X axes
 * @param {boolean=} [args.yGrid=true] - whether draw the grid line started from Y axes
 * @param {string=} [args.xDescript='x'] - the X axes's description
 * @param {string=} [args.yDescript='y'] - the Y axes's description
 */
function DVMulBarChart(args)
{
	if (arguments.length==0)
		args = {};

	this.args = args.cloneAll();
	if (args['X']==null)
		this.args['X'] = [];

	if (args['Ys']==null)
		this.args['Ys'] = [[]];

	if (args['Z']==null)
		this.args['Z'] = [];

	if (args['legendOuterBox']==null)
		this.args['legendOuterBox'] = false;

	if (args['colors']==null)
		this.args['colors'] = DVgetRandomColor(this.args['Z'].length);

	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;

	if (args['xDescript']==null)
		this.args['xDescript'] = "x";

	if (args['yDescript']==null)
		this.args['yDescript'] = "y";

	if (args['xGrid']==null)
		this.args['xGrid'] = false;

	if (args['yGrid']==null)
		this.args['yGrid'] = true;

	this.eles = new Array();
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVMulBarChart.prototype.prepare = function(dv)
{
	dv.drawed = true;
	ymm = DV2dArrMinMax(this.args.Ys);
	dv.initial([0,this.args.X.length],ymm);

		ySpan = DVGetSpan(dv.Ymargin)
		xSpan = 1;	
		cord_arg = {'xGrid':this.args.xGrid,'yGrid':this.args.yGrid,'xDescript':this.args.xDescript,'yDescript':this.args.yDescript,
					'xSpan':xSpan,'ySpan':ySpan,'xStyle':'class','classes':this.args.X}
	this.eles.push(new DVCoordinate(cord_arg));
	for (var i=0;i<this.args.Z.length;i++)
	{
		tmpY = new Array();
		for (var j=0;j<this.args.X.length;j++)
			tmpY.push(this.args.Ys[j][i]);

		this.eles.push(new DVBarChart({'X':this.args.X,'Y':tmpY,'color':this.args.colors[i],'all':this.args.Z.length,'index':i+1}));
	}
	result = dv.xyTrans(this.args.X.length+dv.Xinc,dv.Ymargin/20+dv.Yinc);
	this.eles.push(new DVLegend({'classes':this.args.Z,'colors':this.args.colors,'x':result[0],'y':result[1],'outerbox':this.args.legendOuterBox}))
	

}
/**
 * draw the DVMulLineChart on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVMulBarChart.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
}


/**
 * A DVisual graph element indicate a Histgram Chart
 * @constructor
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(double)} args.X - a series of value,the hist chart will be created by this data
 * @param {DVColor=} [args.color = new DVColor(256,0,0,0.8)] - the color of the bar(normal bar)
 * @param {sec=} [args.sec = this.getsec(this.args.X)] - the segment for the input data for each hist,will be calculate in default.
 * @param {string=} [args.yStyle='value'] - show the value of each bar or the percentage,'value' or 'percentage'
 * @param {double=} [args.lineWidth = '1'] - the lineWidth of graph
 * @param {string=} [args.xDescript='x'] - the X axes's description
 * @param {string=} [args.yDescript='y'] - the Y axes's description
 * @param {boolean=} [args.xGrid=false] - whether draw the grid line started from X axes
 * @param {boolean=} [args.yGrid=true] - whether draw the grid line started from Y axes
 */
function DVHistChart(args)
{
	if (arguments.length==0)
		args = {};
	this.incX = 0.0;
	this.args = args.cloneAll();
	if (args['X']==null)
		this.args['X'] = [];

	if (args['color']==null)
		this.args['color'] = new DVColor(142,214,249,1);

	if (args['sec']==null)
		this.args['sec'] = this.getsec(this.args.X);

	if (args['yStyle']==null || (this.args['yStyle']!='value' && this.args['yStyle']!='percentage'))
		this.args['yStyle'] = "value";

	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;

	if (args['xDescript']==null)
		this.args['xDescript'] = "x";

	if (args['yDescript']==null)
		this.args['yDescript'] = "y";

	if (args['xGrid']==null)
		this.args['xGrid'] = false;

	if (args['yGrid']==null)
		this.args['yGrid'] = true;

	this.eles = new Array();
}
/**
 * calculate the segment if the user haven't set.
 * @function
 * @param {Array(double)} X - the set of input data
 * @return {double} sec - the segment ofr the hist chart
 */
DVHistChart.prototype.getsec = function(X)
{
	this.incX = 0.0;
	xmargin = this.oldWidth;
	if (X.length!=0)
	{
		xm = (X.max()-X.min())*1.0;
		if ((xm/X.max())<0.3)
			this.incX = Math.floor(X.min())-1;
		xmargin = X.max()-incX;
		if (xmargin<=5)
			return 0.5;
		if (xmargin<=10)
			return 1;
		if (xmargin<=50);
			return 5;
		if (xmargin<=100);
			return 10;
		if (xmargin<=500);
			return 50;
	}
	return 1;
}
/**
 * get the span for a settled margin
 * @function
 * @param {double} margin - the margin
 * @return {double} Span - the span for the input margin
 */
function DVGetSpan(margin)
{
	Span = 1;
	if (margin<0.5)
		Span = 0.05;
	else if (margin<1)
		Span = 0.1;
	else if (margin<5)
		Span = 0.5;
	else if (margin<15)
		Span = 1;
	else if (margin<50)
		Span = 5;
	else if (margin<100)
		Span = 10;
	else if (margin<500)
		Span = 50;
	else if (margin<1000)
		Span = 100;
	return Span;
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVHistChart.prototype.prepare = function(dv)
{

		xSpan = this.args.sec;
		this.Ysum = new Array();

		//alert((this.args.X.max()-this.incX)/xSpan+1)
		for (var i=0;i<(this.args.X.max()-this.incX)/xSpan+1;i++)
			this.Ysum.push(0)

		for (var i=0;i<this.args.X.length;i++)
		{
			this.Ysum[Math.floor((this.args.X[i]-this.incX)*1.0/xSpan)]++;
		}
		if (this.args.yStyle=='percentage')
		{

			dv.initial(this.args.X,[0,this.Ysum.max()/this.args.X.length]);
		}
		else
		{
			dv.initial(this.args.X,[0,this.Ysum.max()]);

		}
		ySpan = DVGetSpan(dv.Ymargin);
		cord_arg = {'xGrid':this.args.xGrid,'yGrid':this.args.yGrid,'xDescript':this.args.xDescript,'yDescript':this.args.yDescript,
						'xSpan':xSpan,'ySpan':ySpan,'yStyle':this.args.yStyle}
	
	this.eles.push(new DVCoordinate(cord_arg));
	for (var i=0;i<this.Ysum.length;i++)
	{
		left = this.incX + i*xSpan;
		tops = 0;
		str = Math.floor(this.Ysum[i]) + "";
		if (this.args.yStyle=='percentage')
		{
			tops = this.Ysum[i]*1.0 / this.args.X.length;
			str = Math.floor(((this.Ysum[i]*1.0 / this.args.X.length)).toFixed(2)*100)+"%"; 
		}
		else
			tops = this.Ysum[i];
		result = dv.xyTrans(left,tops);
		width = xSpan;
		this.eles.push(new DVRect({'x':result[0]+0.5,'y':result[1],
						'height':dv.yLenTrans(tops),'width':dv.xLenTrans(width)-1,'color':this.args.color,'style':'fill'}))
		this.eles.push(new DVRect({'x':result[0]+0.5,'y':result[1],
						'height':dv.yLenTrans(tops),'width':dv.xLenTrans(width)-1,'color':new DVColor(),'style':'stroke'}))
		this.eles.push(new DVText({'x':result[0]+dv.xLenTrans(width)/2,'y':result[1]-3,
						'text':str,'textAlign':'center'}))
	}
}
/**
 * draw the DVMulLineChart on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVHistChart.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
}

/**
 * A DVisual graph element indicate a sector
 * @constructor
 * @param {Object[]} args - a array contain arguments below
 * @param {double} args.x - the center's x value
 * @param {double} args.y - the center's y value
 * @param {double} args.radius - the radius of sector
 * @param {double} args.sDeg - the stared angle Degree
 * @param {double} args.eDeg - the end angle Degree
 * @param {DVColor=} [args.color = DVgetRandomColor(1,0.6)[0]] - the color of the dot,random in default
 * @param {boolean=} [args.pop =false] - whether poo out this sector
 * @param {boolean=} [args.shadow =true] - whether draw text's shadow.
 * @param {string=} [args.style ='fill']- the style of this sector,should be one of 'fill','stroke','transFill' means translucent fill.
 * @param {string=} [args.innerText ='']- the text you want to shao in the center of sector
 * @param {double=} [args.ring_ratio = 0] - the ring ratio,to calculate the text location
 */
function DVSector(args)
{
	if (arguments.length==0)
		args = {};

	this.args = args.cloneAll();
	if (args['x']==null)
		this.args['x'] = 100;

	if (args['y']==null)
		this.args['y'] = 100;

	if (args['radius']==null)
		this.args['radius'] = 50;

	if (args['sDeg']==null)
		this.args['sDeg'] = 0;

	if (args['eDeg']==null)
		this.args['eDeg'] = 0;

	if (args['color']==null)
		this.args['color'] = DVgetRandomColor(1,0.6)[0];

	if (args['shadow']==null)
		this.args['shadow'] = true;

	if (args['ring_ratio']==null)
		this.args['ring_ratio'] = 0;

	if (args['pop']==null)
		this.args['pop'] = false;

	if (args['style']==null || (args.style!="fill" && args.style!="stroke" && args.style!="transFill"))
		this.args['style'] = "fill";

	if (args['innerText']==null)
		this.args['innerText'] = "";

	if (args['outerText']==null)
		this.args['outerText'] = "";
	if (this.args['pop'])
	{
		this.args['x']+=this.args.radius/20*Math.cos((this.args.sDeg + this.args.eDeg)*1.0/2);
		this.args['y']+=this.args.radius/20*Math.sin((this.args.sDeg + this.args.eDeg)*1.0/2);
	}
}

/**
 * draw the sector on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVSector.prototype.draw = function(dv)
{
	dv.ctx.save();
	dv.ctx.fillStyle = this.args.color.tostring();
	dv.ctx.strokeStyle = this.args.color.tostring();
	if (this.args['shadow'])
	{
		if (this.shadowSector == null)
		{
			shadowArgs = this.args.cloneAll();
			shadowArgs['color'] = new DVColor(100,100,100,0.3);
			shadowArgs['shadow'] = false;
			shadowArgs['pop'] = false;
			shadowArgs['radius']*=1.01;
			shadowArgs['x']+=shadowArgs.radius/50*Math.cos((shadowArgs.sDeg + shadowArgs.eDeg)*1.0/2);
			shadowArgs['y']+=shadowArgs.radius/50*Math.sin((shadowArgs.sDeg + shadowArgs.eDeg)*1.0/2);
			shadowArgs['innerText'] = "";
			shadowArgs['outerText'] = "";
			this.shadowSector = new DVSector(shadowArgs);
		}
		this.shadowSector.draw(dv);
	}
	if (this.args.style=='stroke' || this.args.style=='fill')
	{
		dv.ctx.sector(this.args.x,this.args.y,this.args.radius,this.args.sDeg,this.args.eDeg);
		if (this.args.style=='fill')
			dv.ctx.fill();
		else
			dv.ctx.stroke();

	}
	else
	{
		dv.ctx.sector(this.args.x,this.args.y,this.args.radius,this.args.sDeg,this.args.eDeg);
		dv.ctx.stroke();
		dv.ctx.fillStyle = (new DVColor(this.args.color.r,this.args.color.g,this.args.color.b,0.5)).tostring();
		dv.ctx.sector(this.args.x,this.args.y,this.args.radius,this.args.sDeg,this.args.eDeg);
		dv.ctx.fill();
	}
	if (this.args.innerText!="")
	{
		if (this.innerDV==null)
		{
			r = this.args.radius/(1/Math.sin((this.args.eDeg - this.args.sDeg)/2)+1) //扇形内最大圆半径
			if (r>this.args.radius*(1-this.args.ring_ratio)*1.0/2.2)
			{
				r = this.args.radius*(1-this.args.ring_ratio)*1.0/2.2;
			}
			teststr = this.args.innerText;
			//alert(teststr.length)
			if (teststr[teststr.length-1]=="%" && teststr.length<3)
				teststr = "12%";
			font = DVgetRightTextStyleByStrLenght(dv,teststr,Math.min(1.7*r,Math.min(dv.oldWidth,dv.oldHeight)*1.0/10));
			dv.ctx.font = font;
			yinc = dv.ctx.measureText('D').width/2;
			textX = this.args.x + (this.args.radius-r)*Math.cos((this.args.sDeg + this.args.eDeg)*1.0/2);
			textY = this.args.y + (this.args.radius-r)*Math.sin((this.args.sDeg + this.args.eDeg)*1.0/2)+yinc;
			if (this.args.ring>0)
			{
				textX = this.args.x + (this.args.radius-r)*Math.cos((this.args.sDeg + this.args.eDeg)*1.0/2);
				textY = this.args.y + (this.args.radius-r)*Math.sin((this.args.sDeg + this.args.eDeg)*1.0/2)+yinc;
			}

			this.innerDV = new DVText({'maxwidth':1.7*r,'text':this.args.innerText,'x':textX,'y':textY,'textAlign':'center','color':new DVColor(256,256,256,1),'font':font})	
		}
		this.innerDV.draw(dv);
	}
	dv.ctx.restore();
}


/**
 * A DVisual graph element indicate a Pie Chart
 * @constructor
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(string)} args.X - a series of string,indicate for each component on the pie
 * @param {Array(double)} args.Y - a series of value,the hist chart will be created by this data
 * @param {boolean=} [args.legendOuterBox=true] - whether draw the outer box of legend
 * @param {Array(DVColor)=} [args.colors = DVgetRandomColor(this.args.X.length)] - the colors for each component
 * @param {douboe=} [args.ring_ratio = 0] - the ring ratio of the pie,0 in default,means no ring
 * @param {Array(string)=} [args.text=!!label+':'+value!!] - a series of string you want to show on each sector on the pie.
 * @param {string=} [args.style='showPercentage'] - show the value of each bar or the percentage,'empty' or 'showtext' or 'showPercentage',or 'ring' to show a ring chart
 */
function DVPieChart(args)
{
	if (arguments.length==0)
		args = {};

	this.args = args.cloneAll();
	if (args['X']==null)
		this.args['X'] = [];

	if (args['Y']==null)
		this.args['Y'] = [];

	if (args['legendOuterBox']==null)
		this.args['legendOuterBox'] = true;

	if (args['ring_ratio']==null || args['ring_ratio']>1 || args['ring_ratio']<0)
		this.args['ring_ratio'] = 0;

	if (args['colors']==null)
		this.args['colors'] = DVgetRandomColor(this.args.X.length);

	if (args['text']==null)
	{
		this.args['text'] = new Array();
		for (var i=0;i<this.args.X.length;i++)
			this.args['text'].push(this.args.X[i]+":"+this.args.Y[i]);
	}

	if (args['style']==null || (args.style!="empty" && args.style!="showPercentage" && args.style!="showtext" && args.style!="ring"))
		this.args['style'] = 'showPercentage';
	this.eles = new Array();
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVPieChart.prototype.prepare = function(dv)
{
	acumDeg = 0;
	sum = 0;
	for (var i=0;i<this.args.X.length;i++)
	{
		sum+=this.args.Y[i];
	}

	D = Math.min(dv.oldWidth,dv.oldHeight);

	//this.eles.push(new DVSector({'ring_ratio':this.args.ring_ratio,'x':D/2-D/15,'y':D/2-D/15,'sDeg':0,'radius':D*1.0/6*3*this.args.ring_ratio,'eDeg':Math.PI*2,'color':new DVColor(256,256,256,1)}))
	
	for (var i=0;i<this.args.X.length;i++)
	{
		sDeg = acumDeg;
		eDeg = sDeg + (this.args.Y[i]*1.0/sum)*(Math.PI*2);
		str = Math.floor((this.args.Y[i]*1.0/sum).toFixed(2)*100)+"%";
		r = D*1.0/2/6*5;
		//alert(D+" "+r)
		if (this.args.style=='showtext')
			str = this.args.text[i];
		else if (this.args.style=='empty')
			str = "";

		this.eles.push(new DVSector({'ring_ratio':this.args.ring_ratio,'x':D/2-D/15,'y':D/2-D/15,'sDeg':sDeg,'radius':r,'eDeg':eDeg,'innerText':str,'color':this.args.colors[i]}));
		acumDeg = eDeg;
	}

	xs = (7.0/24/1.41+5.0/12+1.0/9);
	this.eles.push(new DVLegend({'classes':this.args.X,'colors':this.args.colors,'x':xs*D,'y':dv.oldHeight,
						'height':(1-xs)*D,'width':(1-xs)*D,'outerbox':this.args.legendOuterBox}))
}
/**
 * draw the Pie chart on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVPieChart.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
	D = Math.min(dv.oldWidth,dv.oldHeight);
	dv.ctx.clearArc(D/2-D/15,D/2-D/15,D*1.0/6*3*this.args.ring_ratio,0,Math.PI*2);
}

/**
 * A DVisual graph element indicate a Radar Chart
 * @constructor
 * @example new DVRadarChart({'X':["型号1","型号2"],'Y':[[6,7,3,5,6,9],[8,6,7,2,8,6]],'arguments':["速度","能力","强度","战斗力","成本","价格"]})
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(string)} args.X - a series of string,indicate for each player you want to draw,() 
 * @param {Array(Array(double))} args.Y - a series of value,it's length should be player's number,each element of this should be an array for arguments' number
 * @param {Array(string)} args.arguments - a series of string,indicate each arguments.
 * @param {double=} [args.argumax=10] - the maxium value for argument.(unified for all argument)
 * @param {double=} [args.argumin=0] - the minium value for argument.(unified for all argument)
 * @param {boolean=} [args.legendOuterBox=true] - whether draw the outer box of legend
 * @param {Array(DVColor)=} [args.colors = !!randomColor!!] - the colors for each player
 */
function DVRadarChart(args)
{
	if (arguments.length==0)
		args = {};

	this.args = args.cloneAll();
	if (args['X']==null)
		this.args['X'] = [];

	if (args['Y']==null)
		this.args['Y'] = [];

	if (args['arguments']==null)
		this.args['arguments'] = [];

	if (args['argumax']==null)
		this.args['argumax'] = 10;

	if (args['argumin']==null)
		this.args['argumin'] = 0;

	if (args['legendOuterBox']==null)
		this.args['legendOuterBox'] = true;

	if (args['colors']==null)
		this.args['colors'] = DVgetRandomColor(this.args.X.length,0.4);

	this.eles = new Array();
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVRadarChart.prototype.prepare = function(dv)
{
	Deg = (Math.PI*2)/this.args.arguments.length;
	D = Math.min(dv.oldWidth,dv.oldHeight);
	oX = D/2;
	oY = D/2;
	r = D*1.0/2/6*5;
	for (var step=0;step<=5;step++)
	{
		tmpX =[]
		tmpY =[]
		if (step==5)
			color = new DVColor();
		else
			color = new DVColor(100,100,100,0.2);
		for (var i=0;i<this.args.arguments.length;i++)
		{
			nX = oX + Math.cos(Deg*i+1.5*Math.PI)*r/5*step;
			nY = oY + Math.sin(Deg*i+1.5*Math.PI)*r/5*step;
			if (step==5)
			{
				this.eles.push(new DVLine({'beginX':oX,'beginY':oY,'endX':nX,'endY':nY,'color':new DVColor(100,100,100,0.8),'shadow':false}));
				
				font = DVgetRightTextStyle(dv,D*1.0/30);
				dv.ctx.font = font;
				yinc = dv.ctx.measureText("D").width*1.0/2;
				textX = oX + r*1.12*Math.cos(Deg*i+1.5*Math.PI);
				textY = oY + r*1.12*Math.sin(Deg*i+1.5*Math.PI)+yinc;
				this.eles.push(new DVText({'text':this.args.arguments[i],'x':textX,'y':textY,'textAlign':'center','shadow':false,'font':font}))

			}
			if (i==0)
			{
				text = (this.args.argumax - this.args.argumin)*1.0/5*step + "";
				this.eles.push(new DVText({'text':text,'x':nX,'y':nY,'shadow':false}));
			}
			tmpX.push(nX);
			tmpY.push(nY);
		}
		lineWidth=1;
		if (step==5)
			lineWidth=2;
		this.eles.push(new DVPolygon({'X':tmpX,'Y':tmpY,'style':'stroke','color':color,'shadow':false,'lineWidth':lineWidth}));
	}
	for (var i=0;i<this.args.X.length;i++)
	{
		tmpX = [];
		tmpY = [];
		for (var j=0;j<this.args.arguments.length;j++)
		{
			nX = oX + Math.cos(Deg*j+1.5*Math.PI)*r*(this.args.Y[i][j]-this.args.argumin)/this.args.argumax;
			nY = oY + Math.sin(Deg*j+1.5*Math.PI)*r*(this.args.Y[i][j]-this.args.argumin)/this.args.argumax;
			tmpX.push(nX);
			tmpY.push(nY);
			//this.eles.push(new DVDot({'x':nX,'y':nY,'color':this.args.colors[i],'style':'stroke'}));
		}
		this.eles.push(new DVPolygon({'X':tmpX,'Y':tmpY,'style':'fill','color':this.args.colors[i],'shadow':true,'lineWidth':2}));
	}
	xs = 0.82;
	this.eles.push(new DVLegend({'classes':this.args.X,'colors':this.args.colors,'x':xs*D,'y':dv.oldHeight,
						'height':(1-xs)*D,'width':(1-xs)*D,'outerbox':this.args.legendOuterBox}))

}
/**
 * draw the Radar chart on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVRadarChart.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
}





/**
 * A DVisual graph element indicate a Area Pie Chart,all arguments are same with Pie Chart,bu different style of image
 * @constructor
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(string)} args.X - a series of string,indicate for each component on the pie
 * @param {Array(double)} args.Y - a series of value,the hist chart will be created by this data
 * @param {boolean=} [args.legendOuterBox=true] - whether draw the outer box of legend
 * @param {Array(DVColor)=} [args.colors = DVgetRandomColor(this.args.X.length)] - the colors for each component
 * @param {Array(string)=} [args.text=!!label+':'+value!!] - a series of string you want to show on each sector on the pie.
 * @param {string=} [args.style='showPercentage'] - show the value of each bar or the percentage,'empty' or 'showtext' or 'showPercentage'
 */
function DVAreaPieChart(args)
{
	if (arguments.length==0)
		args = {};

	this.args = args.cloneAll();
	if (args['X']==null)
		this.args['X'] = [];

	if (args['Y']==null)
		this.args['Y'] = [];

	if (args['legendOuterBox']==null)
		this.args['legendOuterBox'] = true;

	if (args['colors']==null)
		this.args['colors'] = DVgetRandomColor(this.args.X.length);

	if (args['text']==null)
	{
		this.args['text'] = new Array();
		for (var i=0;i<this.args.X.length;i++)
			this.args['text'].push(this.args.X[i]+":"+this.args.Y[i]);
	}

	if (args['style']==null || (args.style!="empty" && args.style!="showPercentage" && args.style!="showtext"))
		this.args['style'] = 'showPercentage';
	this.eles = new Array();
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
*/
DVAreaPieChart.prototype.prepare = function(dv)
{
	acumDeg = 0;
	sum = 0;
	for (var i=0;i<this.args.X.length;i++)
	{
		sum+=this.args.Y[i];
	}
	D = Math.min(dv.oldWidth,dv.oldHeight);
	maxR = D*1.0/2/6*5;
	maxY = this.args.Y.max();

	for (var i=0;i<this.args.X.length;i++)
	{
		sDeg = acumDeg;
		eDeg = sDeg + (Math.PI*2)/this.args.X.length;
		str = Math.floor((this.args.Y[i]*1.0/sum).toFixed(2)*100)+"%";
		r = Math.sqrt(this.args.Y[i]*1.0/maxY)*maxR;
		//alert(D+" "+r)
		if (this.args.style=='showtext')
			str = this.args.text[i];
		else if (this.args.style=='empty')
			str = "";

		this.eles.push(new DVSector({'x':D/2-D/15,'y':D/2-D/15,'sDeg':sDeg,'radius':r,'eDeg':eDeg,'innerText':str,'color':this.args.colors[i]}));
		acumDeg = eDeg;
	}
	xs = (7.0/24/1.41+5.0/12+1.0/9);
	this.eles.push(new DVLegend({'classes':this.args.X,'colors':this.args.colors,'x':xs*D,'y':dv.oldHeight,
						'height':(1-xs)*D,'width':(1-xs)*D,'outerbox':this.args.legendOuterBox}))
}
/**
 * draw the Pie chart on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVAreaPieChart.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
}




/**
 * A DVisual graph element indicate a Box Chart,integrate the normal,stacked bar chart.
 * @constructor
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(string)} args.X - a list of string for each x-label
 * @param {Array(Array(double))} args.Ys - the value set of each x.
 * @param {Array(DVColor)} args.colors - a series of DVColor indicate each x.
 * @param {boolean=} [args.xGrid=false] - whether draw the grid line started from X axes
 * @param {boolean=} [args.yGrid=false] - whether draw the grid line started from Y axes
 * @param {string=} [args.xDescript='x'] - the X axes's description
 * @param {string=} [args.yDescript='y'] - the Y axes's description
 * @param {boolean=} [args.legendOuterBox=true] - whether draw the outer box of legend
 */
function DVBoxChart(args)
{
	if (arguments.length==0)
		args = {};

	this.args = args.cloneAll();
	if (args['X']==null)
		this.args['X'] = [];

	if (args['Ys']==null)
		this.args['Y'] = [];

	if (args['style']==null || (args['style']!='bar' && args['style']!='stacked'))
		this.args['style'] = 'bar';

	if (args['colors']==null)
		this.args['colors'] = DVgetRandomColor(this.args['X'].length);

	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;

	if (args['xDescript']==null)
		this.args['xDescript'] = "x";

	if (args['yDescript']==null)
		this.args['yDescript'] = "y";

	if (args['xGrid']==null)
		this.args['xGrid'] = false;

	if (args['yGrid']==null)
		this.args['yGrid'] = false;

	if (args['legendOuterBox']==null)
		this.args['legendOuterBox'] = true;

	this.eles = new Array();
}
/**
 * calculate the median of an array
 * @function
 * @param {Array(double)} Y - the data to be calculate
 */
function DVMedian(X)
{
	Y = X.slice(0);
	Y.sort();
	if (Y.length%2==1)
		return Y[Math.floor(Y.length/2)];
	return (Y[Math.floor(Y.length/2)]+Y[Math.floor(Y.length/2)-1])*1.0/2;
}

/**
 * calculate the needed value for each box
 * @function
 * @param {Array(double)} Y - an array of double.the data needed statistic.
 * @return {Object} staValue - the value returns
 * @return {double} staValue.median - the median of Y
 * @return {double} staValue.upperQuartile - the upper quartile of Y
 * @return {double} staValue.lowerQuartile - the lower quartile of Y
 * @return {double} staValue.upperBound - the upper Bound of Y
 * @return {double} staValue.lowerBound - the lower Bound of Y
 * @return {Array(double)} staValue.outlier - the outlier bound for the Y,[min,max]
 */
DVBoxChart.prototype.statistic = function(Y)
{
	if (Y.length==0)
		return null;
	staValue = {};
	Y.sort(function(a,b)
			{
				return a - b;
			});
	if (Y.length%2==1)
	{
		staValue.median = Y[Math.floor(Y.length/2)];
		staValue.upperQuartile = DVMedian(Y.slice(Math.floor(Y.length/2)+1));
		staValue.lowerQuartile = DVMedian(Y.slice(0,Math.floor(Y.length/2)));
	}
	else
	{
		staValue.median = (Y[Math.floor(Y.length/2)]+Y[Math.floor(Y.length/2)-1])*1.0/2;
		staValue.upperQuartile = DVMedian(Y.slice(Math.floor(Y.length/2)));
		staValue.lowerQuartile = DVMedian(Y.slice(0,Math.floor(Y.length/2)));
	}
	staValue.outlier = [];
	IQR = (staValue.upperQuartile - staValue.lowerQuartile)*1.0/2;
	staValue.outlier.push(staValue.median-3*IQR);
	staValue.outlier.push(staValue.median+3*IQR);
	staValue.upperBound = -1000000;
	staValue.lowerBound = 1000000;
	for (var i=0;i<Y.length;i++)
	{
		if (Y[i]>=staValue.outlier[0])
			staValue.lowerBound = Math.min(staValue.lowerBound,Y[i]);
		if (Y[i]<=staValue.outlier[1])
		{
			staValue.upperBound = Math.max(staValue.upperBound,Y[i]);
		}
	}
	return staValue;
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVBoxChart.prototype.prepare = function(dv)
{

	tmpY = DV2dArrMinMax(this.args.Ys);
	if (this.args.style=='bar')
		dv.initial([0,this.args.X.length],tmpY);

	ySpan = DVGetSpan(dv.Ymargin)
	xSpan = 1;	
	cord_arg = {'xGrid':this.args.xGrid,'yGrid':this.args.yGrid,'xDescript':this.args.xDescript,'yDescript':this.args.yDescript,
				'xSpan':xSpan,'ySpan':ySpan,'xStyle':'class','classes':this.args.X}
	this.eles.push(new DVCoordinate(cord_arg));
	for (var i=0;i<this.args.X.length;i++)
	{
		staValue = this.statistic(this.args.Ys[i]);
		half_len = 0.2;
		half_rect_width = 0.3;
		begin = dv.xyTrans(i-half_len+0.5,staValue.lowerBound);
		end  = dv.xyTrans(i+half_len+0.5,staValue.lowerBound);
		this.eles.push(new DVLine({'beginX':begin[0],'beginY':begin[1],'endX':end[0],'endY':end[1]}));

		begin = dv.xyTrans(i-half_len+0.5,staValue.upperBound);
		end  = dv.xyTrans(i+half_len+0.5,staValue.upperBound);
		this.eles.push(new DVLine({'beginX':begin[0],'beginY':begin[1],'endX':end[0],'endY':end[1]}));

		begin = dv.xyTrans(i-half_rect_width+0.5,staValue.median);
		end  = dv.xyTrans(i+half_rect_width+0.5,staValue.median);
		this.eles.push(new DVLine({'beginX':begin[0],'beginY':begin[1],'endX':end[0],'endY':end[1],'lineWidth':2}));

		rectNode = dv.xyTrans(i-half_rect_width+0.5,staValue.upperQuartile);
		rectWidth = dv.xLenTrans(half_rect_width*2);
		rectHeight = dv.yLenTrans(staValue.upperQuartile-staValue.lowerQuartile);
		this.eles.push(new DVRect({'x':rectNode[0],'y':rectNode[1],'width':rectWidth,'height':rectHeight,'color':this.args.colors[i]}));

		begin = dv.xyTrans(i+0.5,staValue.upperBound);
		end  = dv.xyTrans(i+0.5,staValue.upperQuartile);
		this.eles.push(new DVLine({'beginX':begin[0],'beginY':begin[1],'endX':end[0],'endY':end[1]-3,'style':'dash'}));	

		begin = dv.xyTrans(i+0.5,staValue.lowerBound);
		end  = dv.xyTrans(i+0.5,staValue.lowerQuartile);
		this.eles.push(new DVLine({'beginX':begin[0],'beginY':begin[1],'endX':end[0],'endY':end[1]+4,'style':'dash'}));	
		for (var j=0;j<this.args.Ys[i].length;j++)
		{
			if (this.args.Ys[i][j]<staValue.outlier[0] || this.args.Ys[i][j]>staValue.outlier[1])
			{
				dotxy = dv.xyTrans(i+0.5,this.args.Ys[i][j]);
				this.eles.push(new DVDot({'x':dotxy[0],'y':dotxy[1],'color':this.args.colors[i],'style':'bubble'}))
			}
		}
	}
}
/**
 * draw the DVBarChart on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVBoxChart.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
}





/**
 * A DVisual graph element indicate a General Graph
 * @constructor
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(string)} args.nodes - a series of string,indicate for each node's text actualy
 * @param {Array(Array())} args.edges - a series of tuple,which contain two index number for the edge.example[[0,1],[1,2]]
 * @param {Array(DVColor)=} [args.color = random] - the color of the node
 * @param {string=} [args.style='undirected'] - the graph style.'undirected' or 'directed'
 */
function DVGraph(args)
{
	if (arguments.length==0)
		args = {};

	this.args = args.cloneAll();
	if (args['nodes']==null)
		this.args['nodes'] = [];

	if (args['edges']==null)
		this.args['edges'] = [];


	if (args['color']==null)
		this.args['color'] = DVgetRandomColor(1)[0];


	if (args['style']==null || (args.style!="undirected" && args.style!="directed"))
		this.args['style'] = 'undirected';

	this.eles = new Array();
}

DVGraph.prototype.isLinked = function(i,j)
{
	for (var k =0;k<this.args.edges.length;k++)
	{
		if (this.args.edges[k][0]==i && this.args.edges[k][1]==j) 
			return true;
		if (this.args.edges[k][1]==i && this.args.edges[k][0]==j) 
			return true;
	}
	return false;
}

DVGraph.prototype.distance = function(i,j)
{
	return Math.sqrt(Math.pow((this.eles[i].args.x - this.eles[j].args.x),2)+Math.pow((this.eles[i].args.y - this.eles[j].args.y),2))
}
/**
 * using the layout algorithm to appoint the location for each node
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 * @param {Array(Object)} V - the vertice array
 * @param {Array(Object)} E - the edges array
 */
DVGraph.prototype.rerange = function(dv,V,E)
{
	var area = (dv.oldWidth-40)*(dv.oldHeight-40)*0.5;
	var k = Math.sqrt(area/V.length);
	fa = function(x)
	{
		return x*x*1.0/k;
	}
	fr = function(x)
	{
		return k*k*1.0/x;
	}
	var t = 10;
	for (var step=0;step<200;step++)
	{
		for (var i=0;i<V.length;i++)
		{
			V[i].dispx = 0;
			V[i].dispy = 0;
			for (var j=0;j<V.length;j++)
				if (i!=j)
				{
					tmpx = V[i].x - V[j].x;
					tmpy = V[i].y - V[j].y;
					tmp = Math.sqrt(tmpx*tmpx+tmpy*tmpy);
					V[i].dispx+=tmpx*1.0/tmp*fr(tmp)
					V[i].dispy+=tmpy*1.0/tmp*fr(tmp)
				}
		}
		for (var e=0;e<E.length;e++)
		{
			tmpx = V[E[e][0]].x - V[E[e][1]].x;
			tmpy = V[E[e][0]].y - V[E[e][1]].y;
			tmp = Math.sqrt(tmpx*tmpx+tmpy*tmpy);
			V[E[e][0]].dispx-=tmpx*1.0/tmp*fa(tmp);
			V[E[e][0]].dispy-=tmpy*1.0/tmp*fa(tmp);
			V[E[e][1]].dispx+=tmpx*1.0/tmp*fa(tmp);
			V[E[e][1]].dispy+=tmpy*1.0/tmp*fa(tmp);
		}

		for (var i=0;i<V.length;i++)
		{
			vdisp = Math.sqrt(V[i].dispy*V[i].dispy+V[i].dispx*V[i].dispx);

			V[i].x += V[i].dispx*1.0/vdisp*Math.min(vdisp,t);
			V[i].y += V[i].dispy*1.0/vdisp*Math.min(vdisp,t);
			V[i].x = Math.min(dv.oldWidth-20,Math.max(20,V[i].x));
			V[i].y = Math.min(dv.oldHeight-20,Math.max(20,V[i].y));
		}
		t = t*0.99;
	}
	return V;
	//alert(this.eles[0].args['x']+" "+this.eles[0].args['y'])
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVGraph.prototype.prepare = function(dv)
{
	var V = []
	for (var i=0;i<this.args.nodes.length;i++)
	{
		V.push({'x':getrandom(dv.oldWidth-40)+20
				,'y':getrandom(dv.oldHeight-40)+20
				,'dispx':0
				,'dispy':0})
		//this.eles.push(new DVDot({'color':this.args.color,'x':getrandom(dv.oldWidth-40)+20,'y':getrandom(dv.oldHeight-40)+20,'style':'bubble','radius':10,'bubbleText':this.args.nodes[i]}))
	}
	V = this.rerange(dv,V,this.args.edges);
	for (var i=0;i<this.args.nodes.length;i++)
	{
		this.eles.push(new DVDot({'color':this.args.color,'x':V[i].x,'y':V[i].y,'style':'bubble','radius':10,'bubbleText':this.args.nodes[i]}))
	}
	for (var i=0;i<this.args.edges.length;i++)
	{
		bx = this.eles[this.args.edges[i][0]].args.x;
		by = this.eles[this.args.edges[i][0]].args.y;
		ex = this.eles[this.args.edges[i][1]].args.x;
		ey = this.eles[this.args.edges[i][1]].args.y;
		tmp = 10/Math.sqrt((bx-ex)*(bx-ex)+(by-ey)*(by-ey));
		eex = tmp*bx + (1-tmp)*ex;
		eey = tmp*by + (1-tmp)*ey;
		bbx = tmp*ex + (1-tmp)*bx;
		bby = tmp*ey + (1-tmp)*by;
		this.eles.push(new DVLine({'beginX':bbx,'beginY':bby,
						'endX':eex,'endY':eey}))
		if (this.args.style=='directed')
		{
			theta = 30.0/180*Math.PI;
			r = 5;
			basic = 0;
			if (eex>=bbx)
				basic = Math.PI;
			basic = basic + Math.atan((bby-eey)/(bbx-eex));
			this.eles.push(new DVLine({'beginX':eex+Math.cos(basic+theta)*r,'beginY':eey+Math.sin(basic+theta)*r,
						'endX':eex,'endY':eey}))
			this.eles.push(new DVLine({'beginX':eex+Math.cos(basic-theta)*r,'beginY':eey+Math.sin(basic-theta)*r,
						'endX':eex,'endY':eey}))
			
		}

	}
	//this.rerange('y');
}
/**
 * draw the Pie chart on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVGraph.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
}


/**
 * A DVisual graph element indicate a Dendrogram,which can show some combination rule for the data
 * @constructor
 * @param {Object[]} args - a array contain arguments below
 * @param {object[]} args.tree - a set indicate the tree you want to draw,the base element is string,for example:["A",["B","C"]]
 * @param {DVColor=} [args.color = DVgetRandomColor(1)[0]] - the color for bubble
 * @param {string=} [args.style='bubble'] - the tree base element style,'bubble' or 'text'
 */
function DVDendrogram(args)
{
	if (arguments.length==0)
		args = {};

	this.args = args.cloneAll();
	if (args['tree']==null)
		this.args['tree'] = [];

	if (args['color']==null)
		this.args['color'] = DVgetRandomColor(1)[0];

	if (args['style']==null || (args.style!="bubble" && args.style!="text"))
		this.args['style'] = 'bubble';

	this.eles = new Array();
	this.baseEleCount = 0;
	this.baseIndex = 0;
}

/**
 * recurrence prepare the needed elements
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 * @param {elements} tree - the tree you want to draw,can be string at the node,otherwise object
 * @param {DVisual} level - the level of this procedure
 * @return {object} - return the width and base level from the bottom,[double,int]
 */
DVDendrogram.prototype.recurrencePrepare = function(dv,tree,level)
{

	if (typeof(tree)=="object")
	{
		var children = new Array();
		var levels = new Array();
		for (var i=0;i<tree.length;i++)
		{
			tmp = this.recurrencePrepare(dv,tree[i],level+1);
			children.push(tmp[0]);
			levels.push(tmp[1]);
			//alert(level + "   " +children);
		}
		nowHeight = this.calHeight(dv,levels.min()-1);
		this.eles.push(new DVLine({'beginX':children[0],'beginY':nowHeight,'endX':children[children.length-1],'endY':nowHeight}));

		var radius = Math.min((dv.oldWidth-40)*0.9/(this.baseEleCount)*1.0/2,18);

		for (var i=0;i<levels.length;i++)
		{
			var IsNode = radius;
			if (levels[i]!=this.maxlevel)
				IsNode = 0;
			this.eles.push(new DVLine({'beginX':children[i],'beginY':nowHeight,
										'endX':children[i],'endY':this.calHeight(dv,levels[i])-IsNode}));
		}
		return [(children[children.length-1] + children[0])*1.0/2,levels.min()-1];
	}
	if (typeof(tree)=="string")
	{
		nowHeight = this.calHeight(dv,this.maxlevel);
		nowWidth = this.baseIndex*(dv.oldWidth-40)*1.0/(this.baseEleCount-1)+20;
		radius = Math.min((dv.oldWidth-40)*0.9/(this.baseEleCount)*1.0/2,15);
		if (this.args.style=='bubble')
		{
			this.eles.push(new DVDot({'x':nowWidth,'y':nowHeight,'color':this.args.color,'style':'bubble','radius':radius,'bubbleText':tree}));
		}
		else
		{
			this.eles.push(new DVText({'text':tree,'x':nowWidth,'y':nowHeight,
						'maxwidth':Math.min((dv.oldWidth-40)*0.9/(this.baseEleCount)*1.0/2,40),'textAlign':'center','direction':'horizontal'}));
		}
		//this.eles.push(new DVLine({'beginX':nowWidth,'beginY':nowHeight-radius,'endX':nowWidth,'endY':this.levelHeight*(this.maxlevel-1)+20}));

		this.baseIndex += 1;
		return [nowWidth,this.maxlevel];
	}

	//this.rerange('y');
}

/**
 * recurrently calculate the depth of the tree
 * @function
 * @param {object} tree - tree you want to calculate
 * @return {int} level - the depth of the tree
 */
DVDendrogram.prototype.calMaxLevel = function(tree)
{
	if (typeof(tree)=="object")
	{
		var maxx = 0;
		for (var i=0;i<tree.length;i++)
		{
			maxx = Math.max(this.calMaxLevel(tree[i]),maxx)
		}
		return maxx+1;
	}
	if (typeof(tree)=="string")
	{
		this.baseEleCount += 1;
	}
	return 1;
	//this.rerange('y');
}

/**
 * calculate the height of instance level,use L2 function to make the chart more beautiful
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 * @param {int} level - the level
 * @param {double} height - the height of the passed level 
 */
DVDendrogram.prototype.calHeight = function(dv,level)
{

	//return this.levelHeight*level+20;
	var radius = Math.min((dv.oldWidth-40)*0.9/(this.baseEleCount)*1.0/2,18)+5;
	if (level!=this.maxlevel)
		radius = 0;
	return -(level-this.maxlevel)*(level-this.maxlevel)*((dv.oldHeight - 80)*1.0)/(this.maxlevel*this.maxlevel) + (dv.oldHeight - 60) + radius + 20
}


/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVDendrogram.prototype.prepare = function(dv)
{
	this.maxlevel = this.calMaxLevel(this.args.tree)-1;
	this.levelHeight = (dv.oldHeight-60)/this.maxlevel;
	this.baseIndex = 0;
	this.recurrencePrepare(dv,this.args.tree,0);
	//this.rerange('y');
}

/**
 * draw the Dendrogram on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVDendrogram.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	for (var i=this.eles.length-1;i>=0;i--)
		this.eles[i].draw(dv);
}





/**
 * A DVisual graph element indicate a Dendrogram,which can show some combination rule for the data
 * @constructor
 * @param {Object[]} args - a array contain arguments below
 * @param {Object[]} args.nodes - indicate a set of nodes,the elements is a string.
 * @param {Object[]} args.edges - indicate a set of edges,the elements is a tuple with two index,eg: [[0,1]] means an edge connect 0-th node and 1-th node
 * @param {Object=} [args.edgesValue = empty] - can be empty,to change the curve's width to show more infomation
 * @param {DVColor=} [args.CurveColor = DVgetRandomColor(1)[0]] - the Curve's Color 
 * @param {DVColor=} [args.NodeColor = new DVColor()] - the Node's Color 
 * @param {string=} [args.style='bubble'] - the node element style,'bubble' or 'text'
 * @param {boolean=} [args.bubble = true] - whether add a bubble to each node 
 * @param {int=} [args.bubbleRadius = 2] - the radius of the added bubble
 * @param {double=} [args.lineWidth = 2] - the lineWidth of curve,when the edgesValue is not empty,lineWidth indicate the maxium Curve Width.
 */
function DVCircleConnectChart(args)
{
	if (arguments.length==0)
		args = {};

	this.args = args.cloneAll();
	if (args['nodes']==null)
		this.args['nodes'] = [];

	if (args['edges']==null)
		this.args['edges'] = [];

	if (args['edgesValue']==null)
		this.args['edgesValue'] = [];

	if (args['NodeColor']==null)
		this.args['NodeColor'] = new DVColor();

	if (args['CurveColor']==null)
		this.args['CurveColor'] = DVgetRandomColor(1)[0];

	if (args['bubble']==null)
		this.args['bubble'] = true;

	if (args['bubbleRadius']==null)
		this.args['bubbleRadius'] = 2;

	if (args['lineWidth']==null)
		this.args['lineWidth'] = 2;

	this.eles = new Array();
}


/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVCircleConnectChart.prototype.prepare = function(dv)
{

	R = (Math.min(dv.oldHeight,dv.oldWidth) - 60)/2;
	mid = Math.min(dv.oldHeight,dv.oldWidth)/2;
	addang = Math.asin(dv.ctx.measureText('D').width*1.0/2/R);
	nodelocation = []
	angs = []
	for (var i=0;i<this.args.nodes.length;i++)
	{
		ang = Math.PI*2/this.args.nodes.length*i;
		TextR = R;
		if (this.args['bubble'])
			TextR = TextR + this.args['bubbleRadius']*1.2;
		tmpx = mid + Math.cos(ang+addang)*TextR;
		tmpy = mid + Math.sin(ang+addang)*TextR;
		this.eles.push(new DVText({'text':this.args.nodes[i],'x':tmpx,'y':tmpy,'rotate':ang,'maxwidth':30}));
		nodelocation.push([mid + Math.cos(ang)*R,mid + Math.sin(ang)*R]);
		angs.push(ang);
		if (this.args['bubble'])
			this.eles.push(new DVDot({'color':this.args.NodeColor,'x':mid + Math.cos(ang)*R,'y':mid + Math.sin(ang)*R,'style':'bubble','radius':this.args['bubbleRadius']}))
		//this.eles.push(new DVLine({'beginX':mid,'beginY':mid,'endX':mid + Math.cos(ang)*R,'endY':mid + Math.sin(ang)*R}));
	}
	curveColor = this.args.CurveColor;
	for (var i=0;i<this.args.edges.length;i++)
	{
		node = this.args.edges[i];
		a = node[0];
		b = node[1];
		cp_ratio = Math.sqrt((nodelocation[a][0]-nodelocation[b][0])*(nodelocation[a][0]-nodelocation[b][0])+(nodelocation[a][1]-nodelocation[b][1])*(nodelocation[a][1]-nodelocation[b][1]))/2/R; 
		ang = (angs[a]+angs[b])*1.0/2;
		if (Math.abs(angs[a]-angs[b])>Math.PI)
		{
			ang = ang + Math.PI;
		}
		cpx = mid +  Math.cos(ang)*R*(1-cp_ratio);
		cpy = mid +  Math.sin(ang)*R*(1-cp_ratio);
		lineWidth = this.args.lineWidth;
		if (this.args.edgesValue.length>0)
		{
			if (this.args.edgesValue.length!=this.args.edges.length)
			{
				console.log("ERROR! in DVCircleConnectChart,the edgesValue's length is not the same as edges' length")
				break;
			}
			lineWidth = lineWidth * this.args.edgesValue[i]/this.args.edgesValue.max(); 
		}
		this.eles.push(new DVCurve({'beginX':nodelocation[a][0],'beginY':nodelocation[a][1],'endX':nodelocation[b][0],'endY':nodelocation[b][1],
									'cpx':cpx,'cpy':cpy,'color':curveColor,'lineWidth':lineWidth}));
	}
	
}

/**
 * draw the Dendrogram on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVCircleConnectChart.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	//for (var i=0;i<this.eles.length;i++)
	//	this.eles[i].draw(dv);
	 for (var i=this.eles.length-1;i>=0;i--)
	 	this.eles[i].draw(dv);
}


/**
 * A DVisual graph element indicate a Parallel coordinate
 * @constructor
 * @param {Object[]} args - a array contain arguments below
 * @param {Array(Array(double))} args.Xs - the set of multiple series nodes' x value,the length of Xs is the instance's number you want to draw,the elements' length is same with the arguments' length
 * @param {Array(string)} args.arguments - the arguments' name
 * @param {DVColor=} [args.color = new DVColor(100,100,100,0.3)] - the lines' default color,the more color optional can be configured in ColorPattern arguments
 * @param {Object[]} [args.ColorPattern = empty] - the color pattern of lines,the element is [[DVColor1,indexs1,indexs2...],[DVColor2,indexs11,indexs12...]]
 */
function DVParallelCoordinate(args)
{
	if (arguments.length==0)
		args = {};
	this.args = args.cloneAll();

	if (args['Xs']==null)
		this.args['Xs'] = [];

	if (args['arguments']==null)
		this.args['arguments'] = [];

	if (args['classes']==null)
		this.args['classes'] = [];

	if (args['style']==null)
		this.args['style'] = 'dot|line';

	if (args['color']==null)
		this.args['color'] = new DVColor(100,100,100,0.3);

	if (args['ColorPattern']==null)
		this.args['ColorPattern'] = {};

	if (args['xGrid']==null)
		this.args['xGrid'] = true;

	if (args['yGrid']==null)
		this.args['yGrid'] = true;

	if (args['lineWidth']==null)
		this.args['lineWidth'] = 1;

	this.eles = new Array();
}
/**
 * prepare the needed elements on the first time to draw it
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVParallelCoordinate.prototype.prepare = function(dv)
{

	coordinate = (dv.oldWidth*1.0)/(this.args.arguments.length);
	yupper =  20;
	ybottom = dv.oldHeight - 30;

	var ydrawMargin = ybottom - yupper;
	var maxx = [];
	var minn = [];
	var colors = [];
	for (var i =0;i<this.args.Xs.length;i++)
	{
		colors.push(this.args.color);
		if (this.args.Xs[i].length!=this.args.arguments.length)
		{
			console.log("ERROR! the Xs and arugument length in DVParallelCoordinate can not match");
			return -1;
		}
		for (var j=0;j<this.args.arguments.length;j++)
		{
			if (i==0)
			{
				maxx.push(this.args.Xs[i][j]);
				minn.push(this.args.Xs[i][j]);
			} else
			{
				maxx[j] = Math.max(maxx[j],this.args.Xs[i][j]);
				minn[j] = Math.min(minn[j],this.args.Xs[i][j]);
			}
		}
	}
	for (var j=0;j<this.args.arguments.length;j++)
	{
		maxx[j] = Math.ceil(maxx[j]);
		minn[j] = Math.floor(minn[j]);	
	}
	for (var i=0;i<this.args.arguments.length;i++)
	{
		nowx = i*coordinate + coordinate/2;
		this.eles.push(new DVLine({'beginX':nowx,'beginY':yupper,'endX':nowx,'endY':ybottom,'lineWidth':2}));
		texty = ybottom  + 29;
		this.eles.push(new DVText({'text':this.args.arguments[i],'x':nowx,'y':texty,'font':'12px Arial','textAlign':'center','maxwidth':coordinate*0.8}))
		this.eles.push(new DVText({'text':minn[i].toFixed(1),'x':nowx,'y':texty-22,'textAlign':'center','maxwidth':coordinate*0.8}))
		this.eles.push(new DVText({'text':maxx[i].toFixed(1),'x':nowx,'y':18,'textAlign':'center','maxwidth':coordinate*0.8}))
	}

	for (var j=0;j<this.args.ColorPattern.length;j++)
	{
		s = this.args.ColorPattern[j]
		for (var i=1;i<s.length;i++)
		{
			colors[s[i]] = s[0];
		}
	}
	var nowx = 0;
	var nowy = 0;
	var oldx = 0;
	var oldy = 0;
	

	for (var i=0;i<this.args.Xs.length;i++)
	{
		for (var j=0;j<this.args.arguments.length;j++)
		{
			nowy = ybottom - (this.args.Xs[i][j] - minn[j])*1.0/(maxx[j] - minn[j])*ydrawMargin
			nowx = j*coordinate + coordinate/2;
			color = colors[i];
			add = 0;
			if (color.tostring()!=this.args.color.tostring())
				add = 0.3;
			if (j!=0)
			{
				this.eles.push(new DVLine({'beginX':oldx,'beginY':oldy,'endX':nowx,'endY':nowy,'lineWidth':this.args.lineWidth+add,'color':color,'shadow':false}))
			}
			oldx = nowx;
			oldy = nowy;
		}
	}
}

/**
 * draw the Parallel Coordinate on dv's canvas
 * @function
 * @param {DVisual} dv - the Dvisual instance you want to draw 
 */
DVParallelCoordinate.prototype.draw = function(dv)
{
	if (this.eles.length==0)
	{
		this.prepare(dv);
	}
	//for (var i=0;i<this.eles.length;i++)
	//	this.eles[i].draw(dv);
	 for (var i=this.eles.length-1;i>=0;i--)
	 	this.eles[i].draw(dv);
}