| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908 | 
							- /*
 
- 	Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
 
- 	Available via Academic Free License >= 2.1 OR the modified BSD license.
 
- 	see: http://dojotoolkit.org/license for details
 
- */
 
- if(!dojo._hasResource["dojox.widget.DataPresentation"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
 
- dojo._hasResource["dojox.widget.DataPresentation"] = true;
 
- dojo.provide("dojox.widget.DataPresentation");
 
- dojo.experimental("dojox.widget.DataPresentation");
 
- dojo.require("dojox.grid.DataGrid");
 
- dojo.require("dojox.charting.Chart2D");
 
- dojo.require("dojox.charting.widget.Legend");
 
- dojo.require("dojox.charting.action2d.Tooltip");
 
- dojo.require("dojox.charting.action2d.Highlight");
 
- dojo.require("dojo.colors");
 
- dojo.require("dojo.data.ItemFileWriteStore");
 
- (function(){
 
- 	
 
- 	// sort out the labels for the independent axis of the chart
 
- 	var getLabels = function(range, labelMod, charttype, domNode){
 
- 		
 
- 		// prepare labels for the independent axis
 
- 		var labels = [];
 
- 		// add empty label, hack
 
- 		labels[0] = {value: 0, text: ''};
 
- 		var nlabels = range.length;
 
- 		// auto-set labelMod for horizontal charts if the labels will otherwise collide
 
- 		if((charttype !== "ClusteredBars") && (charttype !== "StackedBars")){
 
-     		var cwid = domNode.offsetWidth;
 
-     		var tmp = ("" + range[0]).length * range.length * 7; // *assume* 7 pixels width per character ( was 9 )
 
-     	  
 
-     		if(labelMod == 1){
 
-     			for(var z = 1; z < 500; ++z){
 
-     				if((tmp / z) < cwid){
 
-     					break;
 
-     				}
 
-     				++labelMod;
 
-     			}
 
-     		}
 
- 	    }
 
- 		// now set the labels
 
- 		for(var i = 0; i < nlabels; i++){
 
- 			//sparse labels
 
- 			labels.push({
 
- 				value: i + 1,
 
- 				text: (!labelMod || i % labelMod) ? "" : range[i]
 
- 			});
 
- 		}
 
- 		
 
- 		// add empty label again, hack
 
- 		labels.push({value: nlabels + 1, text:''});
 
- 		
 
- 		return labels;
 
- 	};
 
- 	
 
- 	// get the configuration of an independent axis for the chart
 
- 	var getIndependentAxisArgs = function(charttype, labels){
 
- 		var args = { vertical: false, labels: labels, min: 0, max: labels.length-1, majorTickStep: 1, minorTickStep: 1 };
 
- 		
 
- 		// clustered or stacked bars have a vertical independent axis
 
- 		if((charttype === "ClusteredBars") || (charttype === "StackedBars")){
 
- 			args.vertical = true;
 
- 		}
 
- 		
 
- 		// lines, areas and stacked areas don't need the extra slots at each end
 
- 		if((charttype === "Lines") || (charttype === "Areas") || (charttype === "StackedAreas")){
 
- 			args.min++;
 
- 			args.max--;
 
- 		}
 
- 		return args;
 
- 	};
 
- 	// get the configuration of a dependent axis for the chart
 
- 	var getDependentAxisArgs = function(charttype, axistype, minval, maxval){
 
- 		
 
- 		var args = { vertical: true, fixLower: "major", fixUpper: "major", natural: true };
 
- 		
 
- 		// secondary dependent axis is not left-bottom
 
- 		if(axistype === "secondary"){
 
- 			args.leftBottom = false;
 
- 		}
 
- 		// clustered or stacked bars have horizontal dependent axes
 
- 		if((charttype === "ClusteredBars") || (charttype === "StackedBars")){
 
- 			args.vertical = false;
 
- 		}
 
- 		
 
- 		// ensure axis does not "collapse" for flat series
 
- 		if(minval == maxval){
 
- 			args.min = minval - 1;
 
- 			args.max = maxval + 1;
 
- 		}
 
- 		
 
- 		return args;
 
- 	};
 
- 	
 
- 	// get the configuration of a plot for the chart
 
- 	var getPlotArgs = function(charttype, axistype, animate){
 
- 		
 
- 		var args = { type: charttype, hAxis: "independent", vAxis: "dependent-" + axistype, gap: 4, lines: false, areas: false, markers: false };
 
- 		
 
- 		// clustered or stacked bars have horizontal dependent axes
 
- 		if((charttype === "ClusteredBars") || (charttype === "StackedBars")){
 
- 			args.hAxis = args.vAxis;
 
- 			args.vAxis = "independent";
 
- 		}
 
- 		// turn on lines for Lines, Areas and StackedAreas
 
- 		if((charttype === "Lines") || (charttype === "Hybrid-Lines") || (charttype === "Areas") || (charttype === "StackedAreas")){
 
- 			args.lines = true;
 
- 		}
 
- 		
 
- 		// turn on areas for Areas and StackedAreas
 
- 		if((charttype === "Areas") || (charttype === "StackedAreas")){
 
- 			args.areas = true;
 
- 		}
 
- 		
 
- 		// turn on markers and shadow for Lines
 
- 		if(charttype === "Lines"){
 
- 			args.markers = true;
 
- 		}
 
- 		
 
- 		// turn on shadow for Hybrid-Lines
 
- 		// also, Hybrid-Lines is not a true chart type: use Lines for the actual plot
 
- 		if(charttype === "Hybrid-Lines"){
 
- 			args.shadows = {dx: 2, dy: 2, dw: 2};
 
- 			args.type = "Lines";
 
- 		}
 
- 		
 
- 		// also, Hybrid-ClusteredColumns is not a true chart type: use ClusteredColumns for the actual plot
 
- 		if(charttype === "Hybrid-ClusteredColumns"){
 
- 			args.type = "ClusteredColumns";
 
- 		}
 
- 		
 
- 		// enable animation on the plot if animation is requested
 
- 		if(animate){
 
- 			args.animate = animate;
 
- 		}
 
- 		
 
- 		return args;
 
- 	};
 
- 	// set up a chart presentation
 
- 	var setupChart = function(/*DomNode*/domNode, /*Object?*/chart, /*String*/type, /*Boolean*/reverse, /*Object*/animate, /*Integer*/labelMod, /*String*/theme, /*String*/tooltip, /*Object?*/store, /*String?*/query, /*String?*/queryOptions){
 
- 		var _chart = chart;
 
- 		
 
- 		if(!_chart){
 
- 			domNode.innerHTML = "";  // any other content in the node disrupts the chart rendering
 
- 			_chart = new dojox.charting.Chart2D(domNode);
 
- 		}
 
- 		
 
- 		// set the theme
 
- 		if(theme){
 
- 			// workaround for a theme bug: its _clone method
 
- 			// does not transfer the markers, so we repair
 
- 			// that omission here
 
- 			// FIXME this should be removed once the theme bug is fixed
 
- 	        theme._clone = function(){
 
- 			      var result = new dojox.charting.Theme({
 
- 			        chart: this.chart,
 
- 			        plotarea: this.plotarea,
 
- 			        axis: this.axis,
 
- 			        series: this.series,
 
- 			        marker: this.marker,
 
- 			        antiAlias: this.antiAlias,
 
- 			        assignColors: this.assignColors,
 
- 			        assignMarkers: this.assigneMarkers,
 
- 			        colors: dojo.delegate(this.colors)
 
- 			      });
 
- 			      
 
- 			      result.markers = this.markers;
 
- 			      result._buildMarkerArray();
 
- 			      
 
- 			      return result;
 
- 	        };
 
- 			
 
- 			_chart.setTheme(theme);
 
- 		}
 
- 		var range = store.series_data[0].slice(0);
 
- 		
 
- 		// reverse the labels if requested
 
- 		if(reverse){
 
- 			range.reverse();
 
- 		}
 
- 			
 
- 		var labels = getLabels(range, labelMod, type, domNode);
 
- 		// collect details of whether primary and/or secondary axes are required
 
- 		// and what plots we have instantiated using each type of axis
 
- 		var plots = {};
 
- 		
 
- 		// collect maximum and minimum data values
 
- 		var maxval = null;
 
- 		var minval = null;
 
- 		
 
- 		var seriestoremove = {};
 
- 		for(var sname in _chart.runs){
 
- 			seriestoremove[sname] = true;
 
- 		}
 
- 		// set x values & max data value
 
- 		var nseries = store.series_name.length;
 
- 		for(var i = 0; i < nseries; i++){
 
- 			// only include series with chart=true and with some data values in
 
- 			if(store.series_chart[i] && (store.series_data[i].length > 0)){
 
- 				var charttype = type;
 
- 				var axistype = store.series_axis[i];
 
- 				if(charttype == "Hybrid"){
 
- 					if(store.series_charttype[i] == 'line'){
 
- 						charttype = "Hybrid-Lines";
 
- 					}else{
 
- 						charttype = "Hybrid-ClusteredColumns";
 
- 					}
 
- 				}
 
- 				
 
- 				// ensure we have recorded that we are using this axis type
 
- 				if(!plots[axistype]){
 
- 					plots[axistype] = {};
 
- 				}
 
- 				
 
- 				// ensure we have the correct type of plot for this series
 
- 				if(!plots[axistype][charttype]){
 
- 					var axisname = axistype + "-" + charttype;
 
- 					
 
- 					// create the plot and enable tooltips
 
- 					_chart.addPlot(axisname, getPlotArgs(charttype, axistype, animate));
 
- 					var tooltipArgs = {};
 
- 					if(typeof tooltip == 'string'){
 
- 						tooltipArgs.text = function(o){
 
- 							var substitutions = [o.element, o.run.name, range[o.index], ((charttype === "ClusteredBars") || (charttype === "StackedBars")) ? o.x : o.y];
 
- 							return dojo.replace(tooltip, substitutions);  // from Dojo 1.4 onward
 
- 							//return tooltip.replace(/\{([^\}]+)\}/g, function(_, token){ return dojo.getObject(token, false, substitutions); });  // prior to Dojo 1.4
 
- 						}
 
- 					}else if(typeof tooltip == 'function'){
 
- 						tooltipArgs.text = tooltip;
 
- 					}
 
- 					new dojox.charting.action2d.Tooltip(_chart, axisname, tooltipArgs);
 
- 					
 
- 					// add highlighting, except for lines
 
- 					if(charttype !== "Lines" && charttype !== "Hybrid-Lines"){
 
- 						new dojox.charting.action2d.Highlight(_chart, axisname);
 
- 					}
 
- 					
 
- 					// record that this plot type is now created
 
- 					plots[axistype][charttype] = true;
 
- 				}
 
- 				
 
- 				// extract the series values
 
- 				var xvals = [];
 
- 				var valen = store.series_data[i].length;
 
- 				for(var j = 0; j < valen; j++){
 
- 					var val = store.series_data[i][j];
 
- 					xvals.push(val);
 
- 					if(maxval === null || val > maxval){
 
- 						maxval = val;
 
- 					}
 
- 					if(minval === null || val < minval){
 
- 						minval = val;
 
- 					}
 
- 				}
 
- 					
 
- 				// reverse the values if requested
 
- 				if(reverse){
 
- 					xvals.reverse();
 
- 				}
 
- 				var seriesargs = { plot: axistype + "-" + charttype };
 
- 				if(store.series_linestyle[i]){
 
- 					seriesargs.stroke = { style: store.series_linestyle[i] };
 
- 				}
 
- 				_chart.addSeries(store.series_name[i], xvals, seriesargs);
 
- 				delete seriestoremove[store.series_name[i]];
 
- 			}
 
- 		}
 
- 		
 
- 		// remove any series that are no longer needed
 
- 		for(sname in seriestoremove){
 
- 			_chart.removeSeries(sname);
 
- 		}
 
- 		// create axes
 
- 		_chart.addAxis("independent", getIndependentAxisArgs(type, labels));
 
- 		_chart.addAxis("dependent-primary", getDependentAxisArgs(type, "primary", minval, maxval));
 
- 		_chart.addAxis("dependent-secondary", getDependentAxisArgs(type, "secondary", minval, maxval));
 
- 		
 
- 		return _chart;
 
- 	};
 
- 	// set up a legend presentation
 
- 	var setupLegend = function(/*DomNode*/domNode, /*Legend*/legend, /*Chart2D*/chart, /*Boolean*/horizontal){
 
- 		// destroy any existing legend and recreate
 
- 		var _legend = legend;
 
- 		
 
- 		if(!_legend){
 
- 			_legend = new dojox.charting.widget.Legend({ chart: chart, horizontal: horizontal }, domNode);
 
- 		}else{
 
- 			_legend.refresh();
 
- 		}
 
- 		
 
- 		return _legend;
 
- 	};
 
- 	
 
- 	// set up a grid presentation
 
- 	var setupGrid = function(/*DomNode*/domNode, /*Object?*/grid, /*Object?*/store, /*String?*/query, /*String?*/queryOptions){
 
- 		var _grid = grid || new dojox.grid.DataGrid({}, domNode);
 
- 		_grid.startup();
 
- 		_grid.setStore(store, query, queryOptions);
 
- 		
 
- 		var structure = [];
 
- 		for(var ser = 0; ser < store.series_name.length; ser++){
 
- 			// only include series with grid=true and with some data values in
 
- 			if(store.series_grid[ser] && (store.series_data[ser].length > 0)){
 
- 				structure.push({ field: "data." + ser, name: store.series_name[ser], width: "auto", formatter: store.series_gridformatter[ser] });
 
- 			}
 
- 		}
 
- 		
 
- 		_grid.setStructure(structure);
 
- 		
 
- 		return _grid;
 
- 	};
 
- 	
 
- 	// set up a title presentation
 
- 	var setupTitle = function(/*DomNode*/domNode, /*object*/store){
 
- 		if(store.title){
 
- 			domNode.innerHTML = store.title;
 
- 		}
 
- 	};
 
- 	
 
- 	// set up a footer presentation
 
- 	var setupFooter = function(/*DomNode*/domNode, /*object*/store){
 
- 		if(store.footer){
 
- 			domNode.innerHTML = store.footer;
 
- 		}
 
- 	};
 
- 	
 
- 	// obtain a subfield from a field specifier which may contain
 
- 	// multiple levels (eg, "child.foo[36].manacle")
 
- 	var getSubfield = function(/*Object*/object, /*String*/field){
 
- 		var result = object;
 
- 		
 
- 		if(field){
 
- 			var fragments = field.split(/[.\[\]]+/);
 
- 			for(var frag = 0, l = fragments.length; frag < l; frag++){
 
- 				if(result){
 
- 					result = result[fragments[frag]];
 
- 				}
 
- 			}
 
- 		}
 
- 		
 
- 		return result;
 
- 	};
 
- 	
 
- 	dojo.declare("dojox.widget.DataPresentation", null, {
 
- 		//	summary:
 
- 		//
 
- 		//		DataPresentation
 
- 		//
 
- 		//		A widget that connects to a data store in a simple manner,
 
- 		//      and also provides some additional convenience mechanisms
 
- 		//      for connecting to common data sources without needing to
 
- 		//      explicitly construct a Dojo data store. The widget can then
 
- 		//      present the data in several forms: as a graphical chart,
 
- 		//      as a tabular grid, or as display panels presenting meta-data
 
- 		//      (title, creation information, etc) from the data. The
 
- 		//      widget can also create and manage several of these forms
 
- 		//      in one simple construction.
 
- 		//
 
- 		//      Note: this is a first experimental draft and any/all details
 
- 		//      are subject to substantial change in later drafts.
 
- 		//
 
- 		//	example:
 
- 		//
 
- 		//	 	var pres = new dojox.data.DataPresentation("myChartNode", {
 
- 		//	 		type: "chart",
 
- 		//	 		url: "/data/mydata",
 
- 		//          gridNode: "myGridNode"
 
- 		//	 	});
 
- 		//
 
- 		//	properties:
 
- 		//
 
- 		//  store: Object
 
- 		//      Dojo data store used to supply data to be presented. This may
 
- 		//      be supplied on construction or created implicitly based on
 
- 		//      other construction parameters ('data', 'url').
 
- 		//
 
- 		//  query: String
 
- 		//      Query to apply to the Dojo data store used to supply data to
 
- 		//      be presented.
 
- 		//
 
- 		//  queryOptions: String
 
- 		//      Query options to apply to the Dojo data store used to supply
 
- 		//      data to be presented.
 
- 		//
 
- 		//  data: Object
 
- 		//      Data to be presented. If supplied on construction this property
 
- 		//      will override any value supplied for the 'store' property.
 
- 		//
 
- 		//  url: String
 
- 		//      URL to fetch data from in JSON format. If supplied on
 
- 		//      construction this property will override any values supplied
 
- 		//      for the 'store' and/or 'data' properties. Note that the data
 
- 		//      can also be comment-filtered JSON, although this will trigger
 
- 		//      a warning message in the console unless djConfig.useCommentedJson
 
- 		//      has been set to true.
 
- 		//
 
- 		//  urlContent: Object
 
- 		//      Content to be passed to the URL when fetching data. If a URL has
 
- 		//      not been supplied, this value is ignored.
 
- 		//
 
- 		//  urlError: function
 
- 		//      A function to be called if an error is encountered when fetching
 
- 		//      data from the supplied URL. This function will be supplied with
 
- 		//      two parameters exactly as the error function supplied to the
 
- 		//      dojo.xhrGet function. This function may be called multiple times
 
- 		//      if a refresh interval has been supplied.
 
- 		//
 
- 		//  refreshInterval: Number
 
- 		//      the time interval in milliseconds after which the data supplied
 
- 		//      via the 'data' property or fetched from a URL via the 'url'
 
- 		//      property should be regularly refreshed. This property is
 
- 		//      ignored if neither the 'data' nor 'url' property has been
 
- 		//      supplied. If the refresh interval is zero, no regular refresh is done.
 
- 		//
 
- 		//  refreshIntervalPending:
 
- 		//      the JavaScript set interval currently in progress, if any
 
- 		//
 
- 		//  series: Array
 
- 		//      an array of objects describing the data series to be included
 
- 		//      in the data presentation. Each object may contain the
 
- 		//      following fields:
 
- 		//			datapoints: the name of the field from the source data which
 
- 		//				contains an array of the data points for this data series.
 
- 		//				If not supplied, the source data is assumed to be an array
 
- 		//				of data points to be used.
 
- 		//			field: the name of the field within each data point which
 
- 		//				contains the data for this data series. If not supplied,
 
- 		//				each data point is assumed to be the value for the series.
 
- 		//      	name: a name for the series, used in the legend and grid headings
 
- 		//          namefield: the name of the field from the source data which
 
- 		//              contains the name the series, used in the legend and grid
 
- 		//              headings. If both name and namefield are supplied, name takes
 
- 		//              precedence. If neither are supplied, a default name is used.
 
- 		//			chart: true if the series should be included in a chart presentation (default: true)
 
- 		//          charttype: the type of presentation of the series in the chart, which can be
 
- 		//				"range", "line", "bar" (default: "bar")
 
- 		//          linestyle: the stroke style for lines (if applicable) (default: "Solid")
 
- 		//          axis: the dependant axis to which the series will be attached in the chart,
 
- 		//              which can be "primary" or "secondary"
 
- 		//			grid: true if the series should be included in a data grid presentation (default: true)
 
- 		//			gridformatter: an optional formatter to use for this series in the data grid
 
- 		//
 
- 		//      a call-back function may alternatively be supplied. The function takes
 
- 		//      a single parameter, which will be the data (from the 'data' field or
 
- 		//      loaded from the value in the 'url' field), and should return the array
 
- 		//      of objects describing the data series to be included in the data
 
- 		//      presentation. This enables the series structures to be built dynamically
 
- 		//      after data load, and rebuilt if necessary on data refresh. The call-back
 
- 		//      function will be called each time new data is set, loaded or refreshed.
 
- 		//      A call-back function cannot be used if the data is supplied directly
 
- 		//      from a Dojo data store.
 
- 		//
 
- 		//  type: String
 
- 		//      the type of presentation to be applied at the DOM attach point.
 
- 		//      This can be 'chart', 'legend', 'grid', 'title', 'footer'. The
 
- 		//      default type is 'chart'.
 
- 		type: "chart",
 
- 		//
 
- 		//  chartType: String
 
- 		//      the type of chart to display. This can be 'clusteredbars',
 
- 		//      'areas', 'stackedcolumns', 'stackedbars', 'stackedareas',
 
- 		//      'lines', 'hybrid'. The default type is 'bar'.
 
- 		chartType: "clusteredBars",
 
- 		//
 
- 		//  reverse: Boolean
 
- 		//      true if the chart independant axis should be reversed.
 
- 		reverse: false,
 
- 		//
 
- 		//  animate: Object
 
- 		//      if an object is supplied, then the chart bars or columns will animate
 
- 		//      into place. If the object contains a field 'duration' then the value
 
- 		//      supplied is the duration of the animation in milliseconds, otherwise
 
- 		//      a default duration is used. A boolean value true can alternatively be
 
- 		//      supplied to enable animation with the default duration.
 
- 		//      The default is null (no animation).
 
- 		animate: null,
 
- 		//
 
- 		//  labelMod: Integer
 
- 		//      the frequency of label annotations to be included on the
 
- 		//      independent axis. 1=every label. 0=no labels. The default is 1.
 
- 		labelMod: 1,
 
- 		//
 
- 		//  tooltip: String | Function
 
- 		//      a string pattern defining the tooltip text to be applied to chart
 
- 		//      data points, or a function which takes a single parameter and returns
 
- 		//      the tooltip text to be applied to chart data points. The string pattern
 
- 		//      will have the following substitutions applied:
 
- 		//       {0} - the type of chart element ('bar', 'surface', etc)
 
- 		//       {1} - the name of the data series
 
- 		//       {2} - the independent axis value at the tooltip data point
 
- 		//       {3} - the series value at the tooltip data point point
 
- 		//      The function, if supplied, will receive a single parameter exactly
 
- 		//      as per the dojox.charting.action2D.Tooltip class. The default value
 
- 		//      is to apply the default tooltip as defined by the
 
- 		//      dojox.charting.action2D.Tooltip class.
 
- 		//
 
- 		//  legendHorizontal: Boolean | Number
 
- 		//      true if the legend should be rendered horizontally, or a number if
 
- 		//      the legend should be rendered as horizontal rows with that number of
 
- 		//      items in each row, or false if the legend should be rendered
 
- 		//      vertically (same as specifying 1). The default is true (legend
 
- 		//      rendered horizontally).
 
- 		legendHorizontal: true,
 
- 		//
 
- 		//  theme: String|Theme
 
- 		//      a theme to use for the chart, or the name of a theme.
 
- 		//
 
- 		//  chartNode: String|DomNode
 
- 		//      an optional DOM node or the id of a DOM node to receive a
 
- 		//      chart presentation of the data. Supply only when a chart is
 
- 		//      required and the type is not 'chart'; when the type is
 
- 		//      'chart' this property will be set to the widget attach point.
 
- 		//
 
- 		//  legendNode: String|DomNode
 
- 		//      an optional DOM node or the id of a DOM node to receive a
 
- 		//      chart legend for the data. Supply only when a legend is
 
- 		//      required and the type is not 'legend'; when the type is
 
- 		//      'legend' this property will be set to the widget attach point.
 
- 		//
 
- 		//  gridNode: String|DomNode
 
- 		//      an optional DOM node or the id of a DOM node to receive a
 
- 		//      grid presentation of the data. Supply only when a grid is
 
- 		//      required and the type is not 'grid'; when the type is
 
- 		//      'grid' this property will be set to the widget attach point.
 
- 		//
 
- 		//  titleNode: String|DomNode
 
- 		//      an optional DOM node or the id of a DOM node to receive a
 
- 		//      title for the data. Supply only when a title is
 
- 		//      required and the type is not 'title'; when the type is
 
- 		//      'title' this property will be set to the widget attach point.
 
- 		//
 
- 		//  footerNode: String|DomNode
 
- 		//      an optional DOM node or the id of a DOM node to receive a
 
- 		//      footer presentation of the data. Supply only when a footer is
 
- 		//      required and the type is not 'footer'; when the type is
 
- 		//      'footer' this property will be set to the widget attach point.
 
- 		//
 
- 		//  chartWidget: Object
 
- 		//      the chart widget, if any
 
- 		//
 
- 		//  legendWidget: Object
 
- 		//      the legend widget, if any
 
- 		//
 
- 		//  gridWidget: Object
 
- 		//      the grid widget, if any
 
- 		
 
- 		constructor: function(node, args){
 
- 			// summary:
 
- 			//		Set up properties and initialize.
 
- 			//
 
- 			//	arguments:
 
- 			//		node: DomNode
 
- 			//			The node to attach the data presentation to.
 
- 			//		kwArgs:	Object (see above)
 
- 			
 
- 			// apply arguments directly
 
- 			dojo.mixin(this, args);
 
- 			// store our DOM attach point
 
- 			this.domNode = dojo.byId(node);
 
- 			
 
- 			// also apply the DOM attach point as the node for the presentation type
 
- 			this[this.type + "Node"] = this.domNode;
 
- 			
 
- 			// load the theme if provided by name
 
- 			if(typeof this.theme == 'string'){
 
- 				this.theme = dojo.getObject(this.theme);
 
- 			}
 
- 			
 
- 			// resolve any the nodes that were supplied as ids
 
- 			this.chartNode = dojo.byId(this.chartNode);
 
- 			this.legendNode = dojo.byId(this.legendNode);
 
- 			this.gridNode = dojo.byId(this.gridNode);
 
- 			this.titleNode = dojo.byId(this.titleNode);
 
- 			this.footerNode = dojo.byId(this.footerNode);
 
- 			
 
- 			// we used to support a 'legendVertical' so for now
 
- 			// at least maintain backward compatibility
 
- 			if(this.legendVertical){
 
- 				this.legendHorizontal = !this.legendVertical;
 
- 			}
 
- 			
 
- 			if(this.url){
 
- 				this.setURL(null, null, this.refreshInterval);
 
- 			}
 
- 			else{
 
- 				if(this.data){
 
- 					this.setData(null, this.refreshInterval);
 
- 				}
 
- 				else{
 
- 					this.setStore();
 
- 				}
 
- 			}
 
- 		},
 
- 		
 
- 		setURL: function(/*String?*/url, /*Object?*/ urlContent, /*Number?*/refreshInterval){
 
- 			// summary:
 
- 			//      Sets the URL to fetch data from, with optional content
 
- 			//      supplied with the request, and an optional
 
- 			//      refresh interval in milliseconds (0=no refresh)
 
- 			// if a refresh interval is supplied we will start a fresh
 
- 			// refresh after storing the supplied url
 
- 			if(refreshInterval){
 
- 				this.cancelRefresh();
 
- 			}
 
- 			
 
- 			this.url = url || this.url;
 
- 			this.urlContent = urlContent || this.urlContent;
 
- 			this.refreshInterval = refreshInterval || this.refreshInterval;
 
- 			
 
- 			var me = this;
 
- 			
 
- 			dojo.xhrGet({
 
- 				url: this.url,
 
- 				content: this.urlContent,
 
- 				handleAs: 'json-comment-optional',
 
- 				load: function(response, ioArgs){
 
- 					me.setData(response);
 
- 				},
 
- 				error: function(xhr, ioArgs){
 
- 					if(me.urlError && (typeof me.urlError == "function")){
 
- 						me.urlError(xhr, ioArgs);
 
- 					}
 
- 				}
 
- 			});
 
- 			
 
- 			if(refreshInterval && (this.refreshInterval > 0)){
 
- 				this.refreshIntervalPending = setInterval(function(){
 
- 					me.setURL();
 
- 				}, this.refreshInterval);
 
- 			}
 
- 		},
 
- 		
 
- 		setData: function(/*Object?*/data, /*Number?*/refreshInterval){
 
- 			// summary:
 
- 			//      Sets the data to be presented, and an optional
 
- 			//      refresh interval in milliseconds (0=no refresh)
 
- 			
 
- 			// if a refresh interval is supplied we will start a fresh
 
- 			// refresh after storing the supplied data reference
 
- 			if(refreshInterval){
 
- 				this.cancelRefresh();
 
- 			}
 
- 			
 
- 			this.data = data || this.data;
 
- 			this.refreshInterval = refreshInterval || this.refreshInterval;
 
- 			
 
- 			// TODO if no 'series' property was provided, build one intelligently here
 
- 			// (until that is done, a 'series' property must be supplied)
 
- 			
 
- 			var _series = (typeof this.series == 'function') ? this.series(this.data) : this.series;
 
- 			var datasets = [],
 
- 				series_data = [],
 
- 				series_name = [],
 
- 				series_chart = [],
 
- 				series_charttype = [],
 
- 				series_linestyle = [],
 
- 				series_axis = [],
 
- 				series_grid = [],
 
- 				series_gridformatter = [],
 
- 				maxlen = 0;
 
- 			
 
- 			// identify the dataset arrays in which series values can be found
 
- 			for(var ser = 0; ser < _series.length; ser++){
 
- 				datasets[ser] = getSubfield(this.data, _series[ser].datapoints);
 
- 				if(datasets[ser] && (datasets[ser].length > maxlen)){
 
- 					maxlen = datasets[ser].length;
 
- 				}
 
- 				
 
- 				series_data[ser] = [];
 
- 				// name can be specified in series structure, or by field in series structure, otherwise use a default
 
- 				series_name[ser] = _series[ser].name || (_series[ser].namefield ? getSubfield(this.data, _series[ser].namefield) : null) || ("series " + ser);
 
- 				series_chart[ser] = (_series[ser].chart !== false);
 
- 				series_charttype[ser] = _series[ser].charttype || "bar";
 
- 				series_linestyle[ser] = _series[ser].linestyle;
 
- 				series_axis[ser] = _series[ser].axis || "primary";
 
- 				series_grid[ser] = (_series[ser].grid !== false);
 
- 				series_gridformatter[ser] = _series[ser].gridformatter;
 
- 			}
 
- 		
 
- 			// create an array of data points by sampling the series
 
- 			// and an array of series arrays by collecting the series
 
- 			// each data point has an 'index' item containing a sequence number
 
- 			// and items named "data.0", "data.1", ... containing the series samples
 
- 			// and the first data point also has items named "name.0", "name.1", ... containing the series names
 
- 			// and items named "series.0", "series.1", ... containing arrays with the complete series in
 
- 			var point, datapoint, datavalue, fdatavalue;
 
- 			var datapoints = [];
 
- 			
 
- 			for(point = 0; point < maxlen; point++){
 
- 				datapoint = { index: point };
 
- 				for(ser = 0; ser < _series.length; ser++){
 
- 					if(datasets[ser] && (datasets[ser].length > point)){
 
- 						datavalue = getSubfield(datasets[ser][point], _series[ser].field);
 
- 						
 
- 						if(series_chart[ser]){
 
- 							// convert the data value to a float if possible
 
- 							fdatavalue = parseFloat(datavalue);
 
- 							if(!isNaN(fdatavalue)){
 
- 								datavalue = fdatavalue;
 
- 							}
 
- 						}
 
- 						
 
- 						datapoint["data." + ser] = datavalue;
 
- 						series_data[ser].push(datavalue);
 
- 					}
 
- 				}
 
- 				datapoints.push(datapoint);
 
- 			}
 
- 			if(maxlen <= 0){
 
- 				datapoints.push({index: 0});
 
- 			}
 
- 		
 
- 			// now build a prepared store from the data points we've constructed
 
- 			var store = new dojo.data.ItemFileWriteStore({ data: { identifier: 'index', items: datapoints }});
 
- 			if(this.data.title){
 
- 				store.title = this.data.title;
 
- 			}
 
- 			if(this.data.footer){
 
- 				store.footer = this.data.footer;
 
- 			}
 
- 			
 
- 			store.series_data = series_data;
 
- 			store.series_name = series_name;
 
- 			store.series_chart = series_chart;
 
- 			store.series_charttype = series_charttype;
 
- 			store.series_linestyle = series_linestyle;
 
- 			store.series_axis = series_axis;
 
- 			store.series_grid = series_grid;
 
- 			store.series_gridformatter = series_gridformatter;
 
- 			
 
- 			this.setPreparedStore(store);
 
- 			
 
- 			if(refreshInterval && (this.refreshInterval > 0)){
 
- 				var me = this;
 
- 				this.refreshIntervalPending = setInterval(function(){
 
- 					me.setData();
 
- 				}, this.refreshInterval);
 
- 			}
 
- 		},
 
- 		
 
- 		refresh: function(){
 
- 			// summary:
 
- 			//      If a URL or data has been supplied, refreshes the
 
- 			//      presented data from the URL or data. If a refresh
 
- 			//      interval is also set, the periodic refresh is
 
- 			//      restarted. If a URL or data was not supplied, this
 
- 			//      method has no effect.
 
- 			if(this.url){
 
- 				this.setURL(this.url, this.urlContent, this.refreshInterval);
 
- 			}else if(this.data){
 
- 				this.setData(this.data, this.refreshInterval);
 
- 			}
 
- 		},
 
- 		
 
- 		cancelRefresh: function(){
 
- 			// summary:
 
- 			//      Cancels any and all outstanding data refreshes
 
- 			if(this.refreshIntervalPending){
 
- 				// cancel existing refresh
 
- 				clearInterval(this.refreshIntervalPending);
 
- 				this.refreshIntervalPending = undefined;
 
- 			}
 
- 		},
 
- 	
 
- 		setStore: function(/*Object?*/store, /*String?*/query, /*Object?*/queryOptions){
 
- 			// FIXME build a prepared store properly -- this requires too tight a convention to be followed to be useful
 
- 			this.setPreparedStore(store, query, queryOptions);
 
- 		},
 
- 		
 
- 		setPreparedStore: function(/*Object?*/store, /*String?*/query, /*Object?*/queryOptions){
 
- 			// summary:
 
- 			//		Sets the store and query.
 
- 			//
 
- 			this.preparedstore = store || this.store;
 
- 			this.query = query || this.query;
 
- 			this.queryOptions = queryOptions || this.queryOptions;
 
- 			
 
- 			if(this.preparedstore){
 
- 				if(this.chartNode){
 
- 					this.chartWidget = setupChart(this.chartNode, this.chartWidget, this.chartType, this.reverse, this.animate, this.labelMod, this.theme, this.tooltip, this.preparedstore, this.query, this,queryOptions);
 
- 					this.renderChartWidget();
 
- 				}
 
- 				if(this.legendNode){
 
- 					this.legendWidget = setupLegend(this.legendNode, this.legendWidget, this.chartWidget, this.legendHorizontal);
 
- 				}
 
- 				if(this.gridNode){
 
- 					this.gridWidget = setupGrid(this.gridNode, this.gridWidget, this.preparedstore, this.query, this.queryOptions);
 
- 					this.renderGridWidget();
 
- 				}
 
- 				if(this.titleNode){
 
- 					setupTitle(this.titleNode, this.preparedstore);
 
- 				}
 
- 				if(this.footerNode){
 
- 					setupFooter(this.footerNode, this.preparedstore);
 
- 				}
 
- 			}
 
- 		},
 
- 		
 
- 		renderChartWidget: function(){
 
- 			// summary:
 
- 			//      Renders the chart widget (if any). This method is
 
- 			//      called whenever a chart widget is created or
 
- 			//      configured, and may be connected to.
 
- 			if(this.chartWidget){
 
- 				this.chartWidget.render();
 
- 			}
 
- 		},
 
- 		
 
- 		renderGridWidget: function(){
 
- 			// summary:
 
- 			//      Renders the grid widget (if any). This method is
 
- 			//      called whenever a grid widget is created or
 
- 			//      configured, and may be connected to.
 
- 			if(this.gridWidget){
 
- 				this.gridWidget.render();
 
- 			}
 
- 		},
 
- 		
 
- 		getChartWidget: function(){
 
- 			// summary:
 
- 			//      Returns the chart widget (if any) created if the type
 
- 			//      is "chart" or the "chartNode" property was supplied.
 
- 			return this.chartWidget;
 
- 		},
 
- 		
 
- 		getGridWidget: function(){
 
- 			// summary:
 
- 			//      Returns the grid widget (if any) created if the type
 
- 			//      is "grid" or the "gridNode" property was supplied.
 
- 			return this.gridWidget;
 
- 		},
 
- 		
 
- 		destroy: function(){
 
- 			// summary:
 
- 			//		Destroys the widget and all components and resources.
 
- 			// cancel any outstanding refresh requests
 
- 			this.cancelRefresh();
 
- 			
 
- 			if(this.chartWidget){
 
- 				this.chartWidget.destroy();
 
- 				delete this.chartWidget;
 
- 			}
 
- 			
 
- 			if(this.legendWidget){
 
- 				// no legend.destroy()
 
- 				delete this.legendWidget;
 
- 			}
 
- 			if(this.gridWidget){
 
- 				// no grid.destroy()
 
- 				delete this.gridWidget;
 
- 			}
 
- 			
 
- 			if(this.chartNode){
 
- 				this.chartNode.innerHTML = "";
 
- 			}
 
- 			
 
- 			if(this.legendNode){
 
- 				this.legendNode.innerHTML = "";
 
- 			}
 
- 			
 
- 			if(this.gridNode){
 
- 				this.gridNode.innerHTML = "";
 
- 			}
 
- 			
 
- 			if(this.titleNode){
 
- 				this.titleNode.innerHTML = "";
 
- 			}
 
- 			
 
- 			if(this.footerNode){
 
- 				this.footerNode.innerHTML = "";
 
- 			}
 
- 		}
 
- 		
 
- 	});
 
- 		
 
- })();
 
- }
 
 
  |