graph.js

Summary

No overview generated for 'graph.js'


Class Summary
Graph  

/**
 *	Graph class.
 *
 *	This class eases the creation and display of data
 *
 *	@author Mathieu HENRI, Opera Software ASA
 *	@constructor
 *	@version	1.1
 */
function Graph()
{
	/**	'untitled Graph' @type String */
	this.title			= 'untitled Graph';
	/**	the width of the graphs ( '480px' by default ) @type String */
	this.width			= '480px';
	/**	the height of the graphs ( '360px' by default ) @type String */
	this.height			= '360px';
	/**	the background limit colors ( '#ffcc99' by default ) @type String */
	this.bgColor		= '#ffcc99';
	/**	the foreground limit colors ( '#336600' by default ) @type String */
	this.fgColor		= '#336600';


	/**	'renderer_' use this prefix to name the renderer methods you add to the prototype @type String */
	var	rendererMethodPrefix	= 'renderer_';
	/** @type Array */
	var	labels					= [];
	/** @type Array */
	var	dataSets				= [];
	var	min;
	var	max;


	/**
	 *	check if a variable is an Array.
	 *
	 *	@private
	 *	@param	what	the variable to test
	 *	@return	{Boolean}
	 */
	function isArray( what )
	{
		return (typeof(what)=='object' && what.constructor==Array);
	}

	/**
	 *	reset the graph.
	 *
	 *	@private
	 */
	function reset()
	{
		labels			= [];
		dataSets		= [];
		min = undefined;
		max = undefined;
	}

	/**
	 *	set the labels.
	 *	This will reset the entire Graph if there is not as many labels as before.
	 *
	 *	@param	{Array}	_labels	the array of {@link #labels}
	 *	@return	{Boolean}
	 *	@see	#getLabels
	 *	@see	#reset
	 */
	this.setLabels = function( _labels )
	{
		if( !isArray(_labels) )
			return false;

		//	there was something in the dataSets for a different number of labels -> reset the graph.
		//if( dataSets.length && dataSets[0].data.length!=_labels.length )
			reset();

		labels = _labels;
		return true;
	}

	/**
	 *	get the labels.
	 *
	 *	Especially meant to be used in the renderer methods.
	 *
	 *	@return	{Array}	the array of {@link #labels}
	 *	@see	#setLabels
	 */
	this.getLabels = function()
	{
		return labels;
	}

	/**
	 *	adds a set of data.
	 *	The data set will be rejected if it does not have as many values as the labels of the Graph.
	 *
	 *	@param	{String}	_dataId		the id of the dataSet
	 *	@param	{Array}		_dataSet	an array of numbers
	 *	@param	{String}	_color		[OPTIONNAL] the color to use for this dataSet
	 *	@return	{Boolean}
	 *	@see	#getDataSets
	 *	@see	#getDataRange
	 */
	this.addDataSet = function( _dataId, _dataSet, _color )
	{
		if( !isArray(_dataSet) || _dataSet.length!=labels.length )
			return false;

		for( var i=0; i<_dataSet.length; i++ )
			if( isNaN(_dataSet[i]) )
				return false;

		max	= Math.max( max||-Infinity, Math.max.apply( Math, _dataSet ) );
		min	= Math.min( min||Infinity, Math.min.apply( Math, _dataSet ) );

		dataSets.push( typeof(_color)=='string'?{id:_dataId, data:_dataSet, color:_color }:{id:_dataId, data:_dataSet } );
		return true;
	}

	/**
	 *	get the labels.
	 *
	 *	Especially meant to be used in the renderer methods.
	 *
	 *	@return	{Array}	the array of {@link #dataSets}
	 *	@see	#addDataSet
	 */
	this.getDataSets = function()
	{
		return dataSets;
	}

	/**
	 *	get the min/max range of the dataSets.
	 *
	 *	Especially meant to be used in the renderer methods.
	 *
	 *	@return	{Object}	an object with the minimum and maximum properties, or NULL
	 *	@see	#addDataSet
	 */
	this.getDataRange = function()
	{
		if( dataSets.length )
			return {minimum:min,maximum:max};

		return null;
	}

	/**
	 *	get the color of a given dataSet or a stable pseudo random color in the [ {@link #bgColor} ; {@link #fgColor} ] range.
	 *
	 *	Especially meant to be used in the renderer methods.
	 *
	 *	@param	{Number}	index	the index of the dataSet
	 *	@return 			false if the index is invalid or a color {String}
	 */
	this.getDataSetColor = function( index )
	{
		if( isNaN(index) || index<0 || !dataSets[index]  )
			return false;

		if( this.colorList==undefined )
		{
			this.colorList = [];
			this.colorList[ -1 ] = { seed:	0x01337 }
		}

		if( !this.colorList[ index ] )
		{
			var currentSeed = this.colorList[ this.colorList.length-1 ].seed;
			for( var i=this.colorList.length; i<=index; i++ )
			{
				if( !dataSets[i].color )
			{
					currentSeed *= 1337;
					currentSeed = (currentSeed&0x0aaaa>>1)+(currentSeed&0x05555<<1);
					var rnd255 = (currentSeed&255)/255;
					this.colorList.push( {seed:currentSeed, color:'#'+ (''+( Math.round(this.colorObjBg.b+this.colorObjDelta.b*rnd255) + 256*Math.round(this.colorObjBg.g+this.colorObjDelta.g*rnd255) + 65536*Math.round(this.colorObjBg.r+this.colorObjDelta.r*rnd255) ).toString(16)).slice(-6) } );
				}
				else
					this.colorList.push( {seed:currentSeed, color:dataSets[i].color } );
			}
		}

		return this.colorList[index].color;
	}


	/**
	 *	list the renderers.
	 *
	 *	@return	{Array}	an array with the name of the renderer methods ( without the {@link #rendererMethodPrefix} )
	 */
	this.listStyles = function()
	{
		var renderers = [];
		for( var key in this )
			if( key.substr(0,rendererMethodPrefix.length)==rendererMethodPrefix && typeof(this[key])=='function' )
				renderers.push( key.substr(rendererMethodPrefix.length) );

		return renderers;
	}

	/**
	 *	render the graph
	 *
	 *	@param	{String}		_style			the renderer to use
	 *	@param	{HTMLElement}	_renderTarget	[OPTIONNAL] the HTMLElement where the graph must be rendered, document.body by default
	 *	@return	{Boolean}
	 */
	this.render = function( _style, _renderTarget )
	{
		if( typeof(_style)!='string' || !_style.length || !dataSets.length )
			return false;

		var	graphRendererId	= rendererMethodPrefix+_style;
		if( typeof(this[graphRendererId])!='function' )
			return false;

		var SVG			= createSVGElement
			(
				'svg',
				{
					width:this.width,
					height:this.height,
					xmlns:'http://www.w3.org/2000/svg',
					viewBox:'0 0 '+ parseFloat(this.width) +' '+ parseFloat(this.height)
				}
			)

		//	init random color range
		var c1 = parseInt( this.bgColor.substr( 1 ), 16 ),
			c2 = parseInt( this.fgColor.substr( 1 ), 16 );

		this.colorObjBg		= { r:c1>>16, g:c1>>8&255, b:c1&255 };
		this.colorObjDelta	= { r:(c2>>16)-this.colorObjBg.r, g:(c2>>8&255)-this.colorObjBg.g, b:(c2&255)-this.colorObjBg.b };

		//	render
		var renderState = this[graphRendererId]( SVG );

		delete this.colorList;
		delete this.colorObjBg;
		delete this.colorObjDelta;

		if( renderState )
			(_renderTarget||document.body).appendChild( SVG );

		return renderState;
	}

	return this;
}


/**
 *	create an SVGElement with some attributes.
 *
 *	This method is meant to ease the rendering of the graphs
 *
 *	@param	nodeName	{String} the name of the SVGElement to create
 *	@param	attributesList	{Object} [OPTIONAL] a dictionnary of attributes
 *	@return	{Boolean}
 */
window.createSVGElement = function( nodeName, attributesList )
{
	var svgElement = document.createElementNS( 'http://www.w3.org/2000/svg', nodeName );
	if( attributesList!=undefined )
		for( var key in attributesList )
			if( typeof(key)=='string' )
				svgElement.setAttribute( key, attributesList[key] );

	return svgElement;
}


Documentation generated by JSDoc on Wed Jun 14 11:01:46 2006