Category Archives: Charts

Interactive Charts using Google Visualization API v2.0

You find v3 of this tool here


16.08.2011 I have released version 2.9.3. Read about it here


05.06.2011 I have released version 2.9.1. Read about it here


05.05.2011 I have released version 2.8.5. Read about it here


27.03.2011 I have released version 2.8 featuring different filtering methods. Read about it here


*** See bottom of article for change log on older versions ***


Since i posted the previous version of the solution that utilizes the Google Chart Tools / Interactive Charts (aka Visualization API), Google has updated their API and made the previous version more or less obsolete.

NOTE:
I have made a “bridge” between Google’s Visualization API and SharePoint. How the charts render or function it up to Google to decide – it is their “product”. Refer the various configuration options by following the link from the “Edit chart UI”.

Read Google’s terms of Use here.

Google’s Data Policy on this charts
All code and data are processed and rendered in the browser. No data is sent to any server.

This new release features these chart types:

Other modifications made:

  • All code in one file: “ChartUsingGoogleVisualizationAPI.js”
  • In the CEWP: Refer the above file, jQuery (fixed external link) and the Google jsapi (fixed external link)
  • Chart configuration list is automatically created if it is not already present

The solution is tested in IE8, Google Chrome 5.0.375.127 and Firefox 3.6.8.

Some screenshots (from v2.0 – changes introduced in subsequent versions are not reflected her):

Not all chart types are presented.
When first adding a chart CEWP to a site, the configuration list is created:

Press OK:

Gauge – a good KPI:

GeoMap:

Column chart – counting unique values per country:


This chart type merges all “lines” where the country is the same, counting “fruits” in the choice column named “Fruit or vegetable”.

LineChart:

Map:

Motion Chart:



The “date” column can be a SharePoint data-column, or a “US formatted” string (still formatted as “Date in the UI”) in the format “mm/dd/yyyy”. Refer the “Instructions for MotionChart” link in the UI.

Organizational Chart:



This is the data that makes up this chart. Note that it is built with various calculated columns – no need for it to render as HTML in the list – it is “raw data”.

PieChart:

More examples – including custom CAML-queries will be added on request.


The new GUI from v2.6.5 (introduced in v2.5)



The Code:

This is the CEWP code:

<div id="MyChart1"></div>
<script type="text/javascript">
/*****************************************************
		Address all containers
*****************************************************/
// All charts must be represented by a container with a unique id. This container  must be present in the page
arrOfChartContainers = ["MyChart1"];
</script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript" src="/test/English/Javascript/ChartUsingGoogleVisualizationAPI.js"></script>
Note the <div id=”MyChart1″></div> This is the chart “placeholder”. To add more charts, add more placeholders and add them to the array “arrOfChartContainers”.

The placeholders can be inserted in other CEWP’s as long as they render before the chart is initiated (place them above the “Chart CEWP”).

It is essential that the scripts tags for “jsapi” and “ChartUsingGoogleVisualizationAPI.js” are placed below the script tag that defines the “arrOfChartContainers”.

The code for the file “ChartUsingGoogleVisualizationAPI.js”:

Download code from this location

This link can contain different “versions”:

  • ChartUsingGoogleVisualizationAPI_vX.Y.Z.js – Uncompressed code
  • ChartUsingGoogleVisualizationAPI_vX.Y.Z-min.js – Minified using YUI Compressor to reduce the file size
  • ChartUsingGoogleVisualizationAPI_vX.Y.Z-packer.js – Compressed/obfuscated using Dean Edward’s Packer to further reduce the file size

You must update the script name in the CEWP to reflect the version number.

Note:

When new versions are released, they will be placed in a folder with the version number as label. Be sure to download the latest version.

If you are using a browser other than IE, right click the file and select “Save link as” or “Save linked content as…”.

Tip:

To make it convenient for end users to use this charting tool, create a few CEWP’s with your favorite setup (1 placeholder, 4 placeholders in a table form and so on). Export the CEWP and upload it to your web part gallery (in the root of the site collection).

You can now add it as a regular webpart from the “web part selector” in edit page mode.

Enjoy!
Alexander


Change log:

27.03.2011 : New features are described here

19.10.2010 v2.7 is released. You find it in the “download section” above This version is the final fix (i hope…) for the web selector problems for non Site Collection Administrators (SCA).

For SCA’s there are no changes, but for those not SCA, I have abandoned my attempt to auto populate a web selector and gone for a input field. The user must write the URL of the web to load the list collection from. The reason for this is the fact that the method “GetAllSubWebCollection” is not accessible to non SCA’s, and that the manual iteration trough all webs caused prompts for credentials as it hit webs the current user did not have access to.

You will still get a credential prompt if you try to load the list collection for a web you have no rights to, but you will not get stuck in a “endless” loop of credential prompts.

New features:
In this version i have added the option to restrict edit access for a individual chart to a specific SharePoint user group. You find this setting in the Advanced option area in the “Edit Chart GUI”:

This is no “real” security setting as it only skips the rendering of the “edit chart button” and does not restrict the edit rights to the chart configuration list. If you want a true security setting you must change the permissions for each “chart” in the configuration list, or the permission for the configuration list itself.

Important!

v2.7 requires you to add one column of type “Single line of text” to the chart configuration list. The name of the field must be exactly “EditAccessGroupID” (without the quotes). Optionally you can delete the configuration list and have the script recreate it. The latter will result in you loosing all your existing chart configurations.


05.10.2010 v2.6.5 unintentionally made it impossible for other than site collection administrators to select web. This update (v2.6.6) fixes this issue. For uses that are not site collection administrators, the loading of the web selector may take a few seconds extra.

The check for edit page rights has been removed due to feedback from users that had problems editing charts. To restrict editing of the charts, manage user right for the configuration list – all users must have at least read access!

28.09.2010 Still some issues with the web selector as the v2.6.5 unintentionally made it impossible for other than site collection administrators to select web. I’m working on an updated version that will fix this. In the meantime, use v2.6.4 if you are not on a managed path…

23.09.2010 A new release (v2.6.5) has been added to the download section. This intends to fix the empty web selector for users with site collection on a managed path.

22.09.2010 There are some unresolved issues with the current release. You can follow the progress in the comment section below.

19.09.2010 A new version (2.6.1) is added to the “download section” – see bottom of article. It features enhanced functionality for selecting web. It now let you pick freely from all sites within the site collection (siblings, parent sites and subsites). This version may contain bugs, so please let me know if you find any.

14.09.2010 Small update to the code to fix the “Initial state” in motion charts, as well as some minor bug fixes. I have moved the files to my home server for you to download. This provides a better solution then manually highlighting and saving 2000+ lines of code. Please note that the file now come in three different “versions”. Read more in the “download section” below.

09.09.2010 Small update to the description regarding update from v2.0 to v2.5. I forgot to mention another field required to be added to the Chart configuration list: ListBaseUrl. This in addition to the already mentioned “ChartFormatters”. I have also removed an alert that was left in the code (line 40).

Christophe notified me of a problem with the 2010 compatibility in sub-site “homepage” – which is a wiki page. The CEWP HTML handling in SP2010 is a bit “different” than in SP2007. When editing the HTML source code, it actually pulls the contents generated by the script into the edit dialog and does not use the content that was originally saved to the CEWP… This is a bit of a headache!. A workaround for the wiki-pages is to use the “Content Link” property for the CEWP and link to a .txt file with the CEWP code placed in a document library (alongside the other scripts).

06.09.2010 Updated the script “ChartUsingGoogleVisualizationAPI.js” and the CEWP code. The version number is notched up to 2.5 and the changes are:

  • Added the ability to chart data from all ascending parent sites and all first level subwebs of current site
  • Added a few formatter options in the UI – refer the linked resources for instructions (thanks to Paulo for the tip).
  • Added new “action” for formatting as % (value*100).
  • The solution is now SharePoint 2010 compatible
  • Enhanced the UI for editing charts – all options and columns are now directly editable.
  • No more need to specify the “userListGuid” and the “userListBaseUrl” in the CEWP code.
  • The naming of the charts in the Chart Configuration list is enhanced – it now prefixes the chartId with “location.pathname” to prevent overwriting an existing chart when reusing the CEWP code in another page (thanks to Christophe for the tip).
  • Edit chart is now done in the standard “Browse mode” and not in “EditPage mode”. The edit button is found in the top left corner of the chart. The button is only visible for users with “Edit page rights” and does not show on printouts.
  • And more…

Note: This update introduces two new columns in the configuration list (GoogleVisualization_InteractiveChartsConfig). To reuse the existing Chart configuration list you must add one field of type “Multiple lines of text (Plain text) named “ChartFormatters” and one field of type “Single line of text” named “ListBaseUrl”. Optionally you can delete the Configuration list and have this solution automatically recreate it for you.

Please note that the CEWP code has changed alongside the code for the file “ChartUsingGoogleVisualizationAPI.js”.

Note about existing charts:
All your existing charts will need to be updated with the new “page id” in the chart configuration list (GoogleVisualization_InteractiveChartsConfig). Look at the new configuration item that is automatically added – copy it’s name and update your existing chart configuration – while deleting the newly added (empty) chart configuration.

27.08.2010 Small update to the file “ChartUsingGoogleVisualizationAPI.js” to fix a formatting issue when using object literal notation in the chart options.

Interactive Charts using Google Visualization API

25.08.2010 You find a new version of this feature here

24.05.2010 The code for the file “ChartUsingGoogleVisualizationAPI.js” is updated. Modified the array of fields to use for chart label and value columns. The two now uses the same array: ‘Number’, ‘Currency’, ‘Text’, ‘Calculated’, ‘Boolean’ ,’User’ ,’DateTime’ ,’Choice’ ,’Lookup’.

The version number is now set to 1.0.

21.05.2010 Added support for Lookup column as “Chart value column”. The code for the file “ChartUsingGoogleVisualizationAPI.js” is updated.

12.05.2010 Added support for Lookup column as “Chart label column”. The code for the file “ChartUsingGoogleVisualizationAPI.js” is updated.


11.05.2010 Added some examples at the bottom of the article.


08.05.2010 Updated to fix some bugs:

  • Added support for “Currency”.
  • Fixed this issue noticed by Charlie.: Each time I edit the CEWP/Chart, the “Chart label column” field returns to the top-most selection.

An example on Custom CAML is added (see image below).

The code for the file “ChartUsingGoogleVisualizationAPI.js” is updated.


This is a solution for creating charts directly from SharePoint lists using Google Visualization API. The solution is a CEWP-solution and requiring no other than a few script references. All code and data are processed and rendered in the browser. No data is sent to any server.

The solution features “Sum”, “Count” and “Average”, and can pull data from any column type, including calculated columns. The chart config is stored in a separate “chart config list”, but all the configuration is done in the GUI seen in the bottom picture.

You can pull data from any existing list view (even from personal views – for personal use), or using a custom CAML-query. If you use a custom query, you have the ability to filter the data source using a user profile property pulled from the user profile of the logged in user.

You may use a regular expression to separate out the part of the profile property to use:
IMG

An example on Custom CAML:
IMG

A few pictures to look at while you wait for the code:
Multiple charts setup in the same CEWP
IMG

The same page in “Edit page mode”:
IMG

The code

As always we start like this:
Create a document library to hold your scripts (or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Javascript” (a sub site named “test” with a sub site named “English” with a document library named “Javascript”):
IMG

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.4.2.min. If you use another version, please update the reference in the code.

The scripts “interaction.js” and “stringBuffer.js” is created by Erucy and published on CodePlex.

Create a list to hold the configuration with these fields:

  • Title (the standard title field already in the list)
  • ChartConfig (Multiple lines of plain text)
  • LabelCol (Single line of text)
  • NumCols (Multiple lines of plain text)
  • UseCustomCAML (Yes/No check box)
  • CustomQuery (Multiple lines of plain text)
  • ViewGuid (Single line of text)
  • ListGuid (Single line of text)
  • ChartHeight (Single line of text)
  • ChartWidth (Single line of text)
  • ChartType (Single line of text)
  • GetFilterFromProfile (Yes/No check box)
  • UserProfileProperty (Single line of text)
  • RegexProfileProperty (Single line of text)

Note: These are FieldInternalNames and must be exactly like the above fields.

The GUID for this configuration list is used in the CEWP code below. Read here how to get the GUID for a list.

Add this code to a CEWP and place it in the page where you want the chart to appear:

&lt;!-- Chart goes in this container --&gt;
&lt;div id=&quot;DemoChart1&quot;&gt;&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot; src=&quot;http://www.google.com/jsapi&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jquery-1.4.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/interaction.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/stringBuffer.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/ChartUsingGoogleVisualizationAPI.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
/*****************************************************
			Set list Guids and parameters
*****************************************************/
// List name or Guid of the config list. This list must reside in the same site as the charts are to be displayed
chartConfigListGuid = 'E7A71324-043F-49A0-95EF-1E3E51DD8A85'; 
// The &quot;People and Groups&quot; list - must be set to support filtering by user profile data.
userListGuid = &quot;{570D772F-0EAB-45A8-8C54-9CCD4EC6A0AF}&quot;; 
// Modify if the site collection is on a managed path
userListBaseUrl = ''; 
// Each chart must be represented by a container with a unique id. This container  must be present in the page
arrOfChartContainers = ['DemoChart1'];

/*****************************************************
			Init charts
*****************************************************/
// Load the visualizations from Google
google.load(&quot;visualization&quot;,&quot;1&quot;,{packages:[&quot;columnchart&quot;,&quot;barchart&quot;,&quot;areachart&quot;,&quot;linechart&quot;,&quot;piechart&quot;,&quot;OrgChart&quot;]});
google.setOnLoadCallback(onloadInitChart);
// Call the script when the visualization packages are loaded
function onloadInitChart(){
	call_drawChart(arrOfChartContainers);
}
&lt;/script&gt;

The list item in the configuration list is automatically created when you call the script using a “chartID” not already found in the configuration list:
IMG

A “chartID” can be “reused” if you want the same chart to appear in multiple pages. The chart configuration list is not suppoosed to be “hand edited”, all configuration are done trough the UI in “Edit page mode”. There i however nothing that stops you from hand editing the configuration if you like.

When adding a new chartID, you get an empty chart:
IMG

Edit page to access the configuration:
IMG

The code for the file “ChartUsingGoogleVisualizationAPI.js”:

/* Charting for SharePoint using Google Visualization API
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * Copyright (c) 2009-2010 Alexander Bautz (Licensed under the MIT X11 License)
 * v1.0
 * LastMod: 24.05.2010
 * LastChange: Modified the array of fields to use for chart label and value columns. The two now uses the same array:
			   'Number', 'Currency', 'Text', 'Calculated', 'Boolean' ,'User' ,'DateTime' ,'Choice' ,'Lookup'
 * ---------------------------------------------
 * Include reference to:
 *  jquery - http://jquery.com
 *  interaction.js - http://spjslib.codeplex.com/
 *  stringBuffer.js - http://spjslib.codeplex.com/
 * 	http://www.google.com/jsapi
 *	ChartUsingGoogleVisualizationAPI.js (this file)
 * ---------------------------------------------
*/

function call_drawChart(arrOfChartContainerIDs){
	$.each(arrOfChartContainerIDs,function(i,chartContainerID){
		init_drawChart(chartContainerID);
	});
}

function init_drawChart(cId){
// Check if container is defined
if($(&quot;#&quot;+cId).length==0){
	alert(&quot;The container with id &quot;+cId+&quot;, is not defined!&quot;);
	return;
}
$(&quot;#&quot;+cId).before(&quot;&lt;div id='&quot;+cId+&quot;_chartConfig' style='padding:10px;border:1px silver solid;background-color:#F5F5DC;display:none'&gt;&lt;/div&gt;&quot;);
wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/';
var query = &quot;&lt;Where&gt;&lt;Eq&gt;&lt;FieldRef Name='Title' /&gt;&lt;Value Type='Text'&gt;&quot;+cId+&quot;&lt;/Value&gt;&lt;/Eq&gt;&lt;/Where&gt;&quot;;
chartConfig = queryItems(chartConfigListGuid,query,
	['ID',
	'Title',
	'ChartConfig',
	'LabelCol',
	'NumCols',
	'UseCustomCAML',
	'CustomQuery',
	'GetFilterFromProfile',
	'UserProfileProperty',
	'RegexProfileProperty',
	'ListGuid',
	'ViewGuid',
	'ChartHeight',
	'ChartWidth',
	'ChartType'],1);
	if(chartConfig.count==0){
		addChartId = addItem(chartConfigListGuid,{'Title':cId,'ChartHeight':'250','ChartWidth':'500','ChartConfig':'title:Add chart title here'});
		if(!addChartId.success){
			alert(&quot;An error occured while creating the configuration container:n&quot;+addChartId.errorText);
		}else{
			var myChartConfig = {
				myChartId:cId,
				chartConfigID:addChartId.id,
				configRaw:'title:Add chart title here',
				useCustomCAML:false,
				useUserProfileProperty:false,
				userProfileProperty:'',
				regexProfileProperty:'',
				customCAML:'',	
				listGuid:'',
				viewGuid:'',
				labelCol:'',
				numCols:'',
				chartHeight:'200',
				chartWidth:'450',
				chartType:'ColumnChart'}
		}
	}else{
		thisChartConfig = chartConfig.items[0];
		var myChartConfig = {
			myChartId:cId,	
			chartConfigID:thisChartConfig['ID'],
			configRaw:(thisChartConfig['ChartConfig']!=null)?thisChartConfig['ChartConfig']:'',
			useCustomCAML:(thisChartConfig['UseCustomCAML']==1)?true:false,
			useUserProfileProperty:(thisChartConfig['GetFilterFromProfile']==1)?true:false,
			userProfileProperty:(thisChartConfig['UserProfileProperty']!=null)?thisChartConfig['UserProfileProperty']:'',
			regexProfileProperty:(thisChartConfig['RegexProfileProperty']!=null)?thisChartConfig['RegexProfileProperty']:'',
			customCAML:(thisChartConfig['CustomQuery']!=null)?thisChartConfig['CustomQuery']:'',	
			listGuid:(thisChartConfig['ListGuid']!=null)?thisChartConfig['ListGuid']:'',
			viewGuid:(thisChartConfig['ViewGuid']!=null)?thisChartConfig['ViewGuid']:'',
			labelCol:(thisChartConfig['LabelCol']!=null)?thisChartConfig['LabelCol']:'',
			numCols:(thisChartConfig['NumCols']!=null)?thisChartConfig['NumCols']:'',
			chartHeight:(thisChartConfig['ChartHeight']!=null)?thisChartConfig['ChartHeight']:'200',
			chartWidth:(thisChartConfig['ChartWidth']!=null)?thisChartConfig['ChartWidth']:'450',
			chartType:(thisChartConfig['ChartType']!=null)?thisChartConfig['ChartType']:'ColumnChart'}
	}
	// Code inactive in &quot;edit page mode&quot;
	if($(&quot;.ms-WPAddButton&quot;).length&gt;0){
		editChartConfig(myChartConfig);
	}else{
		// build chart option object
		chartOptions = {};
		if(arrConfig!=''){
			var arrConfig = myChartConfig.configRaw.split(';');			
			$.each(arrConfig,function(i,optRaw){
				var split = optRaw.split(':');
				if(split.length==2){
					var param = split[0];
					var val = split[1];
				}else{
					var param = optRaw.substring(0,optRaw.indexOf(':'));
					var val = optRaw.substring(optRaw.indexOf(':')+1);
				}
				
				if(param=='colors'){
					var colorArr = [];
					if(val.indexOf('color')&gt;-1 &amp;&amp; val.indexOf('darker')&gt;-1){
						var colorArrRaw = val.match(/{color:.*?}/g);
						$.each(colorArrRaw,function(i,colorRaw){
							var colorSplit = colorRaw.replace(/{|}|&quot;|'/g,'').split(',');
							var color = colorSplit[0].split(':')[1];
							var darker = colorSplit[1].split(':')[1];
							obj = {color:$.trim(color),darker:$.trim(darker)};
							colorArr.push(obj);
						});
					}else{
						var colorArrRaw = val.replace(/[|]|&quot;|'/g,'').split(',');
						$.each(colorArrRaw,function(i,color){
							colorArr.push(color);
						});
					}
					val = colorArr;
				}				
				chartOptions[param]=val;	
			});
		}
		// Width and height
		chartOptions.height=myChartConfig.chartHeight;
		chartOptions.width=myChartConfig.chartWidth;
		
		// labelCol
		if(myChartConfig.labelCol!=''){
			myChartConfig.labelCol = myChartConfig.labelCol.split(':')[0];
		}
		// NumCol
		numColNameLabelAndType = [];
		if(myChartConfig.numCols!=''){
			var arrNumFields = myChartConfig.numCols.split(';');		
			$.each(arrNumFields,function(i,fieldOpt){
				if(fieldOpt.length==0)return;
				var full = fieldOpt.split(',');		
					numFieldObj = {};
					$.each(full,function(i,paramRaw){
						var split = paramRaw.split(':');		
						var param = split[0];
						var val = split[1];
						numFieldObj[param]=val;

					});
				numColNameLabelAndType.push(numFieldObj);				
			});
		}
		// Call chartBuilsing function
		drawChart(myChartConfig,numColNameLabelAndType,chartOptions);
	}
}

/*****************************************************
					Get views
*****************************************************/
function getViewsForThisList(obj,lGuid,vGuid){
	var onLoad = true;
	if(typeof(obj)=='object'){
		onLoad = false;
		var listGuid = obj.find('option:selected').val();
		var chartID = obj.attr('chartID');
	}else{		
		var listGuid = lGuid;
	}
	if(listGuid!=''){
		var viewColl = customGetViewCollection(listGuid);
		var options = &quot;&lt;option value=''&gt;&amp;lt;Select view&amp;gt;&lt;/option&gt;&quot;;
		$.each(viewColl.views,function(){
		var personalView = '';
		var personalViewTooltip = '';
			if($(this).attr('Personal')=='TRUE'){
				var personalView = &quot; (Personal view)&quot;;
				var personalViewTooltip = &quot;If you create a chart from a personal view, the chart will only be available for you. Other users accessing the chart will receive a &quot;No Data&quot; message.&quot;;
			}
			if($(this).attr('Name')==vGuid){
				selected = &quot;selected='selected'&quot;;
			}else{
				selected = '';
			}	
			options+=&quot;&lt;option title='&quot;+personalViewTooltip+&quot;' value='&quot;+$(this).attr('Name')+&quot;' &quot;+selected+&quot;&gt;&quot;+$(this).attr('DisplayName')+personalView+&quot;&lt;/option&gt;&quot;;
		});	
		// Load eller select	
		if(onLoad){
			return options;
		}else{
			$(&quot;#&quot;+chartID+&quot;_viewGuid&quot;).html(options);
			//customGetListFields(listGuid,false);
			fieldsOnloadOrOnchange('',listGuid,chartID);
		}
	}else{
		// Load or select	
		if(onLoad){
			alert(&quot;ListGuid not defined&quot;);
			return '';
		}else{
			$(&quot;#&quot;+chartID+&quot;_viewGuid&quot;).html('');
			$(&quot;#&quot;+chartID+&quot;_labelFieldsDiv&quot;).html('');
			$(&quot;#&quot;+chartID+&quot;_numFieldsDiv&quot;).parents('td:first').find('select').each(function(){
				$(this).remove();
			});
			$(&quot;#&quot;+chartID+&quot;_numFieldsDiv&quot;).html('');
			$(&quot;#&quot;+chartID+&quot;_cloneNumSelectLink&quot;).hide();
		}
	}
}

function customCloneFieldSelector(chartID){
	var td = $(&quot;#&quot;+chartID+&quot;_numColTd&quot;);
	var clone = td.find('select:last').parent().clone();
	clone.find('option:first').attr('selected',true);
	td.append(&quot;&lt;div&gt;&quot;+clone.html()+&quot;&lt;/div&gt;&quot;);
}

/*****************************************************
					Save config
*****************************************************/
function saveChartConfig(obj,chartId,chartConfigId){
chartConfigData = [];
var configDiv = obj.parents(&quot;div[id='&quot;+chartId+&quot;_chartConfig']&quot;);
	// Current options
	configDiv.find(&quot;input[fin='ChartConfig']&quot;).each(function(){	
		chartConfigData.push($(this).attr('optionName')+&quot;:&quot;+$(this).val());
	});
	// New options
	configDiv.find(&quot;div.newChartConfigDiv&quot;).each(function(){
		var newOptionName = $(this).find('input:first').val();
		var newOptionVal = 	$(this).find('input:last').val();
		if(newOptionName!=''&amp;&amp;newOptionVal!=''){
			chartConfigData.push(newOptionName+&quot;:&quot;+newOptionVal);
		}
	});
	
	useCustomCAML = (configDiv.find(&quot;input[id='&quot;+chartId+&quot;_UseCustomCAML']&quot;).attr('checked')==true)?'1':'0';
	useUserProfileProperty = (configDiv.find(&quot;input[id='&quot;+chartId+&quot;_GetFilterFromUserProfile']&quot;).attr('checked')==true)?'1':'0';
	userProfileProperty = configDiv.find(&quot;select[id='&quot;+chartId+&quot;_selectUserprofileProperty'] option:selected&quot;).val();
	regexProfileProperty= configDiv.find(&quot;input[id='&quot;+chartId+&quot;_RegexProfileProperty']&quot;).val();

	customQueryData = $.trim(configDiv.find(&quot;textarea[id='&quot;+chartId+&quot;_customQuery']&quot;).val());
	listGuidVal = $.trim(configDiv.find(&quot;select[id='&quot;+chartId+&quot;_listGuid'] option:selected&quot;).val());
	viewGuidVal = $.trim(configDiv.find(&quot;select[id='&quot;+chartId+&quot;_viewGuid'] option:selected&quot;).val());

	var labelSelect = $(&quot;#&quot;+chartId+&quot;_labelFieldsDiv&quot;).find('select option:selected');
	labelCol = labelSelect.val()+&quot;:&quot;+labelSelect.text();
	
	numCols = '';
	$(&quot;#&quot;+chartId+&quot;_numColTd&quot;).find('span').each(function(){
		if($(this).attr('fin')!=undefined){
			numCols += &quot;label:&quot;+$(this).attr('value')+&quot;,fin:&quot;+$(this).attr('fin')+&quot;,action:&quot;+$(this).attr('action')+&quot;,prefix:&quot;+$(this).attr('prefix')+&quot;,fieldType:&quot;+$(this).attr('fieldType')+&quot;;&quot;;
		}
	});
	
	$(&quot;#&quot;+chartId+&quot;_numColTd&quot;).find('select.numFieldSelect').each(function(){
		var thisOpt = $(this).find('option:selected');
		if(thisOpt.val()!=''){
			var fieldAction = $(this).next().find('option:selected').val();
			var prefix = $(this).next().next().attr('checked');
			numCols += &quot;label:&quot;+thisOpt.text()+&quot;,fin:&quot;+thisOpt.val()+&quot;,action:&quot;+fieldAction+&quot;,prefix:&quot;+prefix+&quot;,fieldType:&quot;+thisOpt.attr('fieldType')+&quot;;&quot;;
		}
	});
	chartHeight = $.trim(configDiv.find(&quot;input[id='&quot;+chartId+&quot;_ChartHeight']&quot;).val());
	chartWidth = $.trim(configDiv.find(&quot;input[id='&quot;+chartId+&quot;_ChartWidth']&quot;).val());
	chartType = configDiv.find(&quot;select[id='&quot;+chartId+&quot;_selectChartType'] option:selected&quot;).val();
	wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/';
	res = updateItem(chartConfigListGuid,chartConfigId,
		{'ChartConfig':chartConfigData.join(';'),
		'UseCustomCAML':useCustomCAML,
		'GetFilterFromProfile':useUserProfileProperty,
		'UserProfileProperty':userProfileProperty,
		'RegexProfileProperty':regexProfileProperty,
		'CustomQuery':customQueryData,
		'ListGuid':listGuidVal,
		'ViewGuid':viewGuidVal,
		'LabelCol':labelCol,
		'NumCols':numCols,
		'ChartHeight':chartHeight,
		'ChartWidth':chartWidth,
		'ChartType':chartType});
	
	if(!res.success){
		alert(&quot;Update chart config error:n&quot;+res.errorText);
	}else{
		if(confirm(&quot;Saved OKnnRefresh page?&quot;))location.href=location.href;
	}
}

/*****************************************************
				Test regular expression
*****************************************************/
function testRegExp(id){
	var testRegExp = $(&quot;#&quot;+id+&quot;_RegexProfileProperty&quot;).val();
	var profileProperty = $(&quot;#&quot;+id+&quot;_selectUserprofileProperty&quot;).val();
	var up = getUserInfo();
	if(up[profileProperty]!=''){
		try
		{
		var regexResult = up[profileProperty].match(testRegExp);		
		msgBuffer = [&quot;The full text in the user property field &quot;&quot;+profileProperty+&quot;&quot; for the user &quot;&quot;+up.Title+&quot;&quot; is:n&quot;];	
		msgBuffer.push(up[profileProperty]);	
		msgBuffer.push(&quot;nnThe full RegExp match is this:n&quot;+regexResult);
		msgBuffer.push(&quot;nnThe part that will be used as a filter is this:n&quot;+regexResult[1]);	
		var msg = msgBuffer.join('');
		}catch(err){
			var msg = err.description;
		}
	}else{
		var msg = &quot;The property field &quot;&quot;+profileProperty+&quot;&quot; is empty!&quot;;		
	}
	alert(msg);
}

/*****************************************************
				Chart config options link
*****************************************************/
function setLinkToConfigurationOptions(obj,chartType,chartId){
var link = [];
var onLoad = true;
	if(typeof(obj)=='object'){
		var chartId = obj.attr('chartID');
		var selectedChartOption = obj.find('option:selected');
		var chartType = selectedChartOption.val();
		var chartTypeFriendly = selectedChartOption.text();	
	}else{
		var selectedChartOption = $(&quot;#&quot;+chartId+&quot;_selectChartType&quot;).find('option:selected');
		var chartType = selectedChartOption.val();
		var chartTypeFriendly = selectedChartOption.text();
	}
	link.push(&quot;&lt;a title='Opens in new window' href='http://code.google.com/intl/en-EN/apis/visualization/documentation/gallery/&quot;);
	link.push(chartType.toLowerCase()+&quot;.html#Configuration_Options' target='_blank'&gt;Instructions for &quot;+chartTypeFriendly+&quot;&lt;/a&gt;&quot;);
	link = link.join('');
	// Write to placeholder
	$(&quot;#&quot;+chartId+&quot;_chartOptionsLink&quot;).html(&quot;&lt;div style='font-size:10px;font-weight:normal;display:inline'&gt;&quot;+link+&quot;&lt;/div&gt;&quot;);
}

/*****************************************************
				Edit chart config
*****************************************************/
function editChartConfig(config){
var editOptLeftColArr = [];
var editOptRightColArr = [];
var editOptBottomArr = [];
var editOptTopColArr = [];
var editOptTopLeftColArr = [];
var editOptTopRightColArr = [];
var arrOfChartTypes = ['BarChart|Bar Chart','ColumnChart|Column Chart','AreaChart|Area Chart','LineChart|Line Chart',&quot;PieChart|Pie Chart&quot;,&quot;OrgChart|Org Chart&quot;];
var strChartTypeOptions = [];
	// Chart types
	$.each(arrOfChartTypes,function(i,typeRaw){
	var split = typeRaw.split('|');
		var cType = split[0];
		var cTypeFriendly = split[1];
		if(config.chartType==cType){
			strChartTypeOptions.push(&quot;&lt;option value='&quot;+cType+&quot;' selected&gt;&quot;+cTypeFriendly+&quot;&lt;/option&gt;&quot;);
		}else{
			strChartTypeOptions.push(&quot;&lt;option value='&quot;+cType+&quot;'&gt;&quot;+cTypeFriendly+&quot;&lt;/option&gt;&quot;);
		}
	});
	
	strChartTypeOptions= strChartTypeOptions.join('');
	// ChartType
		var strArr = [];
			strArr.push(&quot;&lt;tr&gt;&quot;);
			strArr.push(&quot;&lt;td colspan='2' style='padding:3 5 0 5'&gt;&lt;label style='font-weight:bold'&gt;Chart type&lt;/label&gt;&lt;br /&gt;&quot;);
			strArr.push(&quot;&lt;select id='&quot;+config.myChartId+&quot;_selectChartType' chartID='&quot;+config.myChartId+&quot;' onchange='javascript:setLinkToConfigurationOptions($(this))'&gt;&quot;);		
			strArr.push(strChartTypeOptions);
			strArr.push(&quot;&lt;/selec&gt;&quot;);		
			strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		
// ListGuid
views = &quot;&lt;option value='' selected&gt;Select list first&lt;/option&gt;&quot;;

var listColl = customGetListCollection();
var listOptionsStrBuffer = [&quot;&lt;option value=''&gt;&amp;lt;Select list&amp;gt;&lt;/option&gt;&quot;];
$.each(listColl.lists,function(){
	if($(this).attr('Name')==config.listGuid){			
		views = getViewsForThisList('',config.listGuid,config.viewGuid);
		selected = &quot;selected='selected'&quot;;
	}else{
		selected = '';
	}
	listOptionsStrBuffer.push(&quot;&lt;option value='&quot;+$(this).attr('Name')+&quot;' &quot;+selected+&quot;&gt;&quot;+$(this).attr('Title')+&quot;&lt;/option&gt;&quot;);
});

	listSelect = &quot;&lt;select id='&quot;+config.myChartId+&quot;_listGuid' chartID='&quot;+config.myChartId+&quot;' onchange='javascript:getViewsForThisList($(this),&quot;&quot;+config.listGuid+&quot;&quot;,&quot;&quot;+config.viewGuid+&quot;&quot;)'&gt;&quot;+listOptionsStrBuffer.join('')+&quot;&lt;/select&gt;&quot;;

		strArr.push(&quot;&lt;tr&gt;&quot;);
		strArr.push(&quot;&lt;td colspan='2' style='padding:3 5 0 5'&gt;&lt;label style='font-weight:bold'&gt;Select list&lt;/label&gt;&lt;br /&gt;&quot;);
		strArr.push(listSelect);			
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);		
		
// ViewGuid
		strArr.push(&quot;&lt;tr&gt;&quot;);
		strArr.push(&quot;&lt;td colspan='2' style='padding:3 5 0 5'&gt;&lt;label style='font-weight:bold'&gt;Select view or use custom CAML&lt;/label&gt;&lt;br /&gt;&quot;);
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan='2' style='padding:0 5 0 5'&gt;&lt;select id='&quot;+config.myChartId+&quot;_viewGuid' chartID='&quot;+config.myChartId+&quot;'&gt;&quot;);
		strArr.push(views);
		strArr.push(&quot;&lt;/select&gt;&quot;);		
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
// Width and height
		strArr.push(&quot;&lt;tr&gt;&quot;);
		strArr.push(&quot;&lt;td colspan='2' style='padding:3 5 0 5'&gt;&lt;label style='font-weight:bold'&gt;Chart height&lt;/label&gt;&lt;br /&gt;&quot;);
		strArr.push(&quot;&lt;input style='width:100px' id='&quot;+config.myChartId+&quot;_ChartHeight' value='&quot;+config.chartHeight+&quot;' /&gt;&quot;);			
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		strArr.push(&quot;&lt;tr&gt;&quot;);
		strArr.push(&quot;&lt;td colspan='2' style='padding:3 5 0 5'&gt;&lt;label style='font-weight:bold'&gt;Chart width&lt;/label&gt;&lt;br /&gt;&quot;);
		strArr.push(&quot;&lt;input style='width:100px' id='&quot;+config.myChartId+&quot;_ChartWidth' value='&quot;+config.chartWidth+&quot;' /&gt;&quot;);			
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		str = strArr.join('');
	editOptTopLeftColArr.push(str);	

// Fields
	var strArr = [];
		strArr.push(&quot;&lt;tr&gt;&quot;);
		strArr.push(&quot;&lt;td colspan='2' style='padding:3 5 0 5'&gt;&lt;label style='font-weight:bold'&gt;Chart label column&lt;/label&gt;&lt;br /&gt;&quot;);
		strArr.push(&quot;&lt;div id='&quot;+config.myChartId+&quot;_labelFieldsDiv'&gt;&lt;/div&gt;&quot;);
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		strArr.push(&quot;&lt;tr&gt;&lt;td colspan='2' style='padding:3 5 0 5'&gt;&lt;label style='font-weight:bold'&gt;Chart value columns&lt;/label&gt;&lt;/td&gt;&lt;/tr&gt;&quot;);
		strArr.push(&quot;&lt;tr&gt;&lt;td colspan='2' id='&quot;+config.myChartId+&quot;_numColTd' style='padding:0 5 0 5'&gt;&lt;div id='&quot;+config.myChartId+&quot;_numFieldsDiv'&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&quot;);
		strArr.push(&quot;&lt;tr&gt;&lt;td colspan='2' style='padding:0 5 0 5'&gt;&lt;a id='&quot;+config.myChartId+&quot;_cloneNumSelectLink' chartID='&quot;+config.myChartId+&quot;' style='display:none' href='javascript:customCloneFieldSelector(&quot;&quot;+config.myChartId+&quot;&quot;)'&gt;Add new&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&quot;);
		strArr.push(&quot;&lt;tr&gt;&lt;td colspan='2' style='padding:10 5 0 5'&gt;&lt;div title='Click to read about column types' style='cursor:pointer;font-weight:bold' onclick='$(this).next().toggle()'&gt;About column types&lt;/div&gt;&quot;);
		strArr.push(&quot;&lt;div style='display:none;width:350px'&gt;&quot;);
		strArr.push(&quot;&lt;div style='padding:3px;border:1px silver solid'&gt;Columns containing numbers can be summed. The column can contain text and number mixed. &quot;);
		strArr.push(&quot;A Regular expression extracts the number from the text.&lt;br /&gt;&lt;br /&gt;&quot;);
		strArr.push(&quot;However notice that only the first occurance of a int/float is used.&lt;br /&gt;&lt;br /&gt;&quot;);
		strArr.push(&quot;Boolean columns can be counted or summed (Yes=1, No=0).&lt;br /&gt;&lt;br /&gt;&quot;);
		strArr.push(&quot;All columns can be counted (not empty=1, empty=0)&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&quot;)
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		str = strArr.join('');
	editOptTopRightColArr.push(str);	

// Options
	if(config.configRaw!=''){
	var arrConfigData = config.configRaw.split(';');
		$.each(arrConfigData,function(i,rawOption){
			split = rawOption.split(':');
			if(split.length==2){
				var label = split[0];
				var val = split[1].replace(/'/g,'&quot;');
			}else{
				var label = rawOption.substring(0,rawOption.indexOf(':'));
				var val = rawOption.substring(rawOption.indexOf(':')+1).replace(/'/g,'&quot;');				
			}
			var strArr = [];
				strArr.push(&quot;&lt;tr&gt;&quot;);
				strArr.push(&quot;&lt;td style='padding:0 5 0 5'&gt;&quot;+label+&quot;&lt;/td&gt;&quot;);
				strArr.push(&quot;&lt;td style='padding:0 5 0 5'&gt;&lt;input style='width:150px' &quot;);
				strArr.push(&quot;fin='ChartConfig' optionName='&quot;+label+&quot;' id='&quot;+config.myChartId+&quot;_&quot;+label+&quot;' type='Text' value='&quot;+val+&quot;' /&gt;&quot;);
				strArr.push(&quot;&lt;a title='Remove current option' style='padding-left:5px' href='javascript:' onclick='addOrRemove($(this),false)'&gt;X&lt;/a&gt;&quot;);
				strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);			
				str = strArr.join('');
			editOptLeftColArr.push(str);
		});
	}

// Add new option
	var strArr = [];
		strArr.push(&quot;&lt;tr&gt;&quot;);
		strArr.push(&quot;&lt;td colspan='2' style=''&gt;&quot;);
		strArr.push(&quot;&lt;a style='padding-left:5px' href='javascript:' onclick='addOrRemove($(this),true)'&gt;Add new option&lt;/a&gt;&quot;);
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		str = strArr.join('');
	editOptLeftColArr.push(str);

	// CAML
	var customCAMLchecked = '';
	var customCAMLAreaDisplay = 'none'
	if(config.useCustomCAML){
		customCAMLchecked = 'checked';
		customCAMLAreaDisplay = 'block';
	}
	var filterFromUPchecked = '';
	var filterFromUPdisplay = 'none';
	if(config.useUserProfileProperty){
		filterFromUPchecked = 'checked';
		var filterFromUPdisplay = 'block';
	}

	var strArr = [];
		strArr.push(&quot;&lt;tr&gt;&quot;);
		strArr.push(&quot;&lt;td colspan='2' style='padding:0 5 0 5'&gt;&quot;);
		strArr.push(&quot;&lt;input type='checkbox' id='&quot;+config.myChartId+&quot;_UseCustomCAML' &quot;+customCAMLchecked+&quot; onclick='javascript:$(&quot;#&quot;+config.myChartId+&quot;_tableUseCustomCAML&quot;).toggle()'&gt;&lt;label for='&quot;+config.myChartId+&quot;_UseCustomCAML'&gt;Use custom CAML (overrides selected view)&lt;/label&gt;&quot;);
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);		
		strArr.push(&quot;&lt;tr&gt;&lt;td id='&quot;+config.myChartId+&quot;_tableUseCustomCAML' style='display:&quot;+customCAMLAreaDisplay+&quot;'&gt;&quot;);
		strArr.push(&quot;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&quot;);
		strArr.push(&quot;&lt;input type='checkbox' id='&quot;+config.myChartId+&quot;_GetFilterFromUserProfile' &quot;+filterFromUPchecked+&quot; onclick='javascript:$(&quot;#&quot;+config.myChartId+&quot;_userProfilePropertyDescription&quot;).toggle()'&gt;&lt;label for='&quot;+config.myChartId+&quot;_GetFilterFromUserProfile'&gt;Get filter value from this profile property:&amp;nbsp;&lt;/label&gt;&quot;);
		strArr.push(&quot;&lt;select id='&quot;+config.myChartId+&quot;_selectUserprofileProperty' chartID='&quot;+config.myChartId+&quot;'&gt;&quot;);		
		var arrOfUserProfileProperties = ['ID','Name','Title','EMail','Department','JobTitle','SipAddress'];
		$.each(arrOfUserProfileProperties,function(i,prop){
			var propSelected = '';
			if(prop==config.userProfileProperty){
				propSelected = 'selected';
			}
			strArr.push(&quot;&lt;option value='&quot;+prop+&quot;' &quot;+propSelected+&quot;&gt;&quot;+prop+&quot;&lt;/option&gt;&quot;);
		});
		strArr.push(&quot;&lt;/select&gt;&quot;);
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		strArr.push(&quot;&lt;tr&gt;&lt;td colspan='2' style='padding:0 5 0 5'&gt;&quot;);
		strArr.push(&quot;&lt;div id='&quot;+config.myChartId+&quot;_userProfilePropertyDescription' style='width:390px;display:&quot;+filterFromUPdisplay+&quot;'&gt;&quot;);
		strArr.push(&quot;&lt;div style='color:red'&gt;&quot;);
		strArr.push(&quot;To use the user profile property as a filter, you must insert {} as a placeholder where the user profile property is to be inserted.&lt;br /&gt;&lt;br /&gt;&quot;);
		strArr.push(&quot;If you use a regular expression to identify the value, it is the first backreference that is used.&lt;/div&gt;&lt;br /&gt;&quot;);
		strArr.push(&quot;&lt;label&gt;Optional RegEx to match property:&amp;nbsp;&lt;/label&gt;&lt;a href='javascript:testRegExp(&quot;&quot;+config.myChartId+&quot;&quot;)'&gt;Test regular expression&lt;/a&gt;&lt;br /&gt;&quot;);		
		strArr.push(&quot;&lt;input id='&quot;+config.myChartId+&quot;_RegexProfileProperty' type='Text' value='&quot;+config.regexProfileProperty+&quot;' style='width:100%'&gt;&lt;/div&gt;&quot;);
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		str = strArr.join('');
	editOptRightColArr.push(str);
	
	escapedCAML = config.customCAML.replace(/&lt;/g,'&amp;lt;').replace(/&gt;/g,'&amp;gt;');
	var strArr = [];
		strArr.push(&quot;&lt;tr&gt;&quot;);
		strArr.push(&quot;&lt;td style='padding:0 5 0 5'&gt;&lt;label&gt;Custom CAML-query&lt;/label&gt;&lt;br /&gt;&quot;);
		strArr.push(&quot;&lt;textarea style='width:400px;height:150px' id='&quot;+config.myChartId+&quot;_customQuery'&gt;&quot;+escapedCAML+&quot;&lt;/textarea&gt;&quot;);	
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&quot;);	
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		str = strArr.join('');
	editOptRightColArr.push(str);
// Save button
	var strArr = [];
		strArr.push(&quot;&lt;tr&gt;&quot;);
		strArr.push(&quot;&lt;td colspan='2' style='text-align:right'&gt;&quot;);
		strArr.push(&quot;&lt;input onclick='javascript:saveChartConfig($(this),&quot;&quot;+config.myChartId+&quot;&quot;,&quot;&quot;+config.chartConfigID+&quot;&quot;);' type='button' value='Save' /&gt;&quot;);
		strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		str = strArr.join('');
	editOptBottomArr.push(str);
	
// wrap up
	var strArr = [];
		strArr.push(&quot;&lt;table style='background-color:#ffffff;width:100%' cellpadding='0' cellspacing='2'&gt;&quot;);
		strArr.push(editOptTopColArr.join(''));
		strArr.push(&quot;&lt;/table&gt;&quot;);
	wrapTop = strArr.join('');
	
	var strArr = [];
		strArr.push(&quot;&lt;table style='background-color:#ffffff;width:100%;' cellpadding='2' cellspacing='0'&gt;&quot;);
		strArr.push(editOptTopLeftColArr.join(''));
		strArr.push(&quot;&lt;/table&gt;&quot;);
	wrapTopLeft = strArr.join('');
	
	var strArr = [];
		strArr.push(&quot;&lt;table style='background-color:#ffffff;width:100%' cellpadding='2' cellspacing='0'&gt;&quot;);
		strArr.push(editOptTopRightColArr.join(''));
		strArr.push(&quot;&lt;/table&gt;&quot;);
	wrapTopRight = strArr.join('');

	var strArr = [];
		strArr.push(&quot;&lt;table style='background-color:#ffffff;width:100%;' cellpadding='2' cellspacing='0'&gt;&quot;);
		strArr.push(editOptLeftColArr.join(''));
		strArr.push(&quot;&lt;/table&gt;&quot;);
	wrapBottomLeft = strArr.join('');
	
	var strArr = [];
		strArr.push(&quot;&lt;table style='background-color:#ffffff;width:100%' cellpadding='2' cellspacing='0'&gt;&quot;);
		strArr.push(editOptRightColArr.join(''));
		strArr.push(&quot;&lt;/table&gt;&quot;);
	wrapBottomRight = strArr.join('');

	var strArr = [];
		strArr.push(&quot;&lt;table style='background-color:#ffffff;width:100%' cellpadding='2' cellspacing='0'&gt;&quot;);
		strArr.push(editOptBottomArr.join(''));
		strArr.push(&quot;&lt;/table&gt;&quot;);
	wrapBottom = strArr.join('');
	
	var wrap = [];
		wrap.push(&quot;&lt;table cellpadding='0' cellspacing='0'&gt;&quot;);
		wrap.push(&quot;&lt;tr&gt;&lt;td valign='top' colspan='2' style='padding:5px;font-size:14px;font-weight:bold;background-color:#F5F5DC'&gt;Chart configuration for &quot;+config.myChartId+&quot;&lt;/td&gt;&quot;);
		wrap.push(&quot;&lt;tr&gt;&lt;td valign='top' colspan='2' style='border-left:1px silver solid;border-top:1px silver solid;border-right:1px silver solid'&gt;&quot;+wrapTop+&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		wrap.push(&quot;&lt;tr&gt;&lt;td valign='top' style='border-left:1px silver solid;border-bottom:1px silver solid;padding:3px'&gt;&quot;+wrapTopLeft+&quot;&lt;/td&gt;&quot;)
		wrap.push(&quot;&lt;td valign='top' style='border-right:1px silver solid;border-bottom:1px silver solid;padding:3px'&gt;&quot;+wrapTopRight+&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		wrap.push(&quot;&lt;tr&gt;&lt;td valign='top' style='padding:5px;font-size:14px;font-weight:bold;background-color:#F5F5DC'&gt;Options&amp;nbsp;&lt;span id='&quot;+config.myChartId+&quot;_chartOptionsLink'&gt;&lt;/span&gt;&lt;/td&gt;&quot;);
		wrap.push(&quot;&lt;td valign='top' style='padding:5px;font-size:14px;font-weight:bold;background-color:#F5F5DC'&gt;Advanced options&lt;/td&gt;&lt;/tr&gt;&quot;);
		wrap.push(&quot;&lt;tr&gt;&lt;td valign='top' style='border-left:1px silver solid;border-top:1px silver solid;padding:3px'&gt;&quot;+wrapBottomLeft+&quot;&lt;/td&gt;&quot;);
		wrap.push(&quot;&lt;td valign='top' style='border-top:1px silver solid;border-right:1px silver solid;padding:3px'&gt;&quot;+wrapBottomRight+&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
		wrap.push(&quot;&lt;tr&gt;&lt;td colspan='2' valign='top' style='border-left:1px silver solid;border-bottom:1px silver solid;border-right:1px silver solid;text-align:right;padding:3'&gt;&quot;+wrapBottom+&quot;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&quot;);
	wrap = wrap.join('');	
	
	$(&quot;#&quot;+config.myChartId+&quot;_chartConfig&quot;).show().html(wrap);
	// Fields	
	if(config.listGuid!=''){
		fieldsOnloadOrOnchange(config);
	}else{
		$(&quot;#&quot;+config.myChartId+&quot;_labelFieldsDiv&quot;).html('Select list first');
		$(&quot;#&quot;+config.myChartId+&quot;_numFieldsDiv&quot;).html('Select list first');
	}
	// Option link	
	var chartConfigLink = setLinkToConfigurationOptions('',config.chartType,config.myChartId);
}

function fieldsOnloadOrOnchange(config,listGuid,chartID){
	if(typeof(config)=='object'){
		var onLoad = true;
		listGuid = config.listGuid;
	}else{
		var onLoad = false;		
	}
	var fieldsObj = customGetListFields(listGuid,true);	
	var currNumFieldsStrBuffer = [];
	var labelFieldSelectBuffer = [];
	var numFieldSelectBuffer = [&quot;&lt;option value=''&gt;&amp;lt;select&amp;gt;&lt;/option&gt;&quot;];	
		if(onLoad){
			// Numcols
			currNumFieldsArr = config.numCols.split(';');
			$.each(currNumFieldsArr,function(i,rawVal){
				var split = rawVal.split(',');
				if(split.length&gt;1){
					var label = split[0].split(':')[1];
					var fin = split[1].split(':')[1];
					var action = split[2].split(':')[1];
					var prefix = split[3].split(':')[1];
					var fieldType = split[4].split(':')[1];
					var actionLabel = &quot; (&quot;+action+&quot;)&quot;;
					if(prefix!='true'){
						var actionLabel = &quot; (&quot;+action+&quot; no prefix)&quot;;
					}
					currNumFieldsStrBuffer.push(&quot;&lt;span title='Click to remove' style='cursor:pointer;padding-left:10px;' &quot;);
					currNumFieldsStrBuffer.push(&quot;fin='&quot;+fin+&quot;' value='&quot;+label+&quot;' action='&quot;+action+&quot;' prefix='&quot;+prefix+&quot;' fieldType='&quot;+fieldType+&quot;' onclick='javascript:$(this).next().andSelf().remove()'&gt;&quot;);
					currNumFieldsStrBuffer.push(&quot;&amp;bull;&amp;nbsp;&quot;+label+actionLabel+&quot;&lt;/span&gt;&lt;br /&gt;&quot;);					
				}
			});
	
			// Build the select for the &quot;string&quot; col
			var labelColSplit = config.labelCol.split(':');
			var strFin = labelColSplit[0];
			var strLabel = labelColSplit[1];
					
		}
		
		// Build field selector
		$.each(fieldsObj.labelFields,function(i,rawOpt){
			var split = rawOpt.split('|');
			var fin = split[0];
			var disp = split[1];
			var selected = '';
			if(onLoad){
				if(fin==strFin){
					selected = &quot;selected&quot;;
				}
			}
			labelFieldSelectBuffer.push(&quot;&lt;option value='&quot;+fin+&quot;' &quot;+selected+&quot;&gt;&quot;+disp+&quot;&lt;/option&gt;&quot;);
		});
		
		$.each(fieldsObj.numFields,function(i,rawOpt){
			var split = rawOpt.split('|');
			var fin = split[0];
			var disp = split[1];
			var fieldType = split[2];
			numFieldSelectBuffer.push(&quot;&lt;option value='&quot;+fin+&quot;' fieldType='&quot;+fieldType+&quot;'&gt;&quot;+disp+&quot;&lt;/option&gt;&quot;);
		});
		numFieldsBuffer = [];
		labelFields = &quot;&lt;div&gt;&lt;select chartID='&quot;+config.myChartId+&quot;'&gt;&quot;+labelFieldSelectBuffer.join('')+&quot;&lt;/select&gt;&lt;/div&gt;&quot;;
		if(fieldsObj.onLoad){
			numFieldsBuffer.push(currNumFieldsStrBuffer.join(''));
		}
		numFieldsBuffer.push(&quot;&lt;div&gt;&lt;select class='numFieldSelect'&gt;&quot;+numFieldSelectBuffer.join('')+&quot;&lt;/select&gt;&quot;);
		numFieldsBuffer.push(&quot;&lt;select class='numActionSelect'&gt;&quot;);
		numFieldsBuffer.push(&quot;&lt;option value='Sum' selected&gt;Sum&lt;/option&gt;&quot;);
		numFieldsBuffer.push(&quot;&lt;option value='Count'&gt;Count&lt;/option&gt;&quot;);
		numFieldsBuffer.push(&quot;&lt;option value='Average'&gt;Average&lt;/option&gt;&lt;/select&gt;&quot;);
		numFieldsBuffer.push(&quot;&lt;input title='Uncheck to remove the &quot;Sum of&quot;, &quot;Count of&quot; or &quot;Average of&quot; prefix' type='checkbox' checked&gt;&lt;label&gt;Prefix&lt;/label&gt;&lt;/div&gt;&quot;);
		var numFields = numFieldsBuffer.join('');
	// Load or select	
	if(onLoad){	
		$(&quot;#&quot;+config.myChartId+&quot;_labelFieldsDiv&quot;).html(labelFields);
		$(&quot;#&quot;+config.myChartId+&quot;_numFieldsDiv&quot;).html(numFields);
		$(&quot;#&quot;+config.myChartId+&quot;_cloneNumSelectLink&quot;).show();
	}else if(!onLoad){	
		$(&quot;#&quot;+chartID+&quot;_labelFieldsDiv&quot;).html(labelFields);
		$(&quot;#&quot;+chartID+&quot;_numFieldsDiv&quot;).parents('td:first').find('select').each(function(){
			$(this).parent().remove();
		});
		$(&quot;#&quot;+chartID+&quot;_numFieldsDiv&quot;).html(numFields);
		$(&quot;#&quot;+chartID+&quot;_cloneNumSelectLink&quot;).show();
	}
}

/*****************************************************
					Get fields
*****************************************************/
function customGetListFields(listName,onLoad){
	xmlStr = [];
	xmlStr.push('&lt;GetList xmlns=&quot;http://schemas.microsoft.com/sharepoint/soap/&quot;&gt;');
	xmlStr.push('&lt;listName&gt;' + listName + '&lt;/listName&gt;');
	xmlStr.push('&lt;/GetList&gt;');
	xmlStr = xmlStr.join('');
	var result = {success:false,labelFields:[],numFields:[]};
	wrapSoapRequest(wsBaseUrl + 'lists.asmx', 'http://schemas.microsoft.com/sharepoint/soap/GetList', xmlStr, function(data){
		if($('ErrorText', data).length &gt; 0){
			result.success = false;
		}else{
			result.onLoad = (onLoad==true)?true:false;
			result.success = true;
			result.name = $('List', data).attr('Name');
			var arrOfTypesToIncludeInStr = ['Number','Currency','Text','Calculated','Boolean','User','DateTime','Choice','Lookup'];
			var arrOfTypesToIncludeInNum = ['Number','Currency','Text','Calculated','Boolean','User','DateTime','Choice','Lookup'];
			$('Field', data).each(function(){
				if($(this).attr('DisplayName')!=undefined){	
					if($.inArray($(this).attr('Type'),arrOfTypesToIncludeInStr)&gt;-1){
						// Include user created single item lookup
						if($(this).attr('Type')=='Lookup' &amp;&amp; $(this).attr('FromBaseType')=='TRUE')return;
						result.labelFields.push($(this).attr('Name')+&quot;|&quot;+$(this).attr('DisplayName'));
					}
					if($.inArray($(this).attr('Type'),arrOfTypesToIncludeInNum)&gt;-1){
						// Include user created single item lookup
						if($(this).attr('Type')=='Lookup' &amp;&amp; $(this).attr('FromBaseType')=='TRUE')return;		
						result.numFields.push($(this).attr('Name')+&quot;|&quot;+$(this).attr('DisplayName')+&quot;|&quot;+$(this).attr('Type'));
					}
				}
			});
		}
	});
return result;
}

/*****************************************************
				Get list collection
*****************************************************/
function customGetListCollection(){
	xmlStr = '&lt;GetListCollection xmlns=&quot;http://schemas.microsoft.com/sharepoint/soap/&quot; /&gt;';
	var result = {success:false, errorCode:'', errorText:'internal error', lists:[]};	
	wrapSoapRequest(L_Menu_BaseUrl + '/_vti_bin/lists.asmx', 'http://schemas.microsoft.com/sharepoint/soap/GetListCollection', xmlStr, function(data){
	
		if ($('ErrorText', data).length &gt; 0) {
			result.success = false;
		} else {
			result.success = true;
			var arrTypesToSkip = ['110','111','112','113','114','115','116','117','118'];
			$('List', data).each(function(i){
				if($.inArray($(this).attr('ServerTemplate'),arrTypesToSkip)==-1){
					result.lists.push($(this));
				}
			});			
		}
	});
	return result;
}

/*****************************************************
				Get view collection
*****************************************************/
function customGetViewCollection(listGuid){
	xmlStr = &quot;&lt;GetViewCollection xmlns='http://schemas.microsoft.com/sharepoint/soap/'&gt;&lt;listName&gt;&quot;+listGuid+&quot;&lt;/listName&gt;&lt;/GetViewCollection&gt;&quot;;
	var result = {success:false, errorCode:'', errorText:'internal error', views:[]};	
	wrapSoapRequest(L_Menu_BaseUrl + '/_vti_bin/views.asmx', 'http://schemas.microsoft.com/sharepoint/soap/GetViewCollection', xmlStr, function(data){
		if ($('ErrorText', data).length &gt; 0) {
			result.success = false;
		} else {
			result.success = true;
			$('View', data).each(function(i){
				if($(this).attr('Hidden')!='TRUE'){
					result.views.push($(this));
				}
			});			
		}
	});
	return result;
}

/*****************************************************
				Wrap webservice call
*****************************************************/
function wrapSoapRequest(webserviceUrl,requestHeader,soapBody,successFunc){
	var xmlWrap = [];
		xmlWrap.push(&quot;&lt;?xml version='1.0' encoding='utf-8'?&gt;&quot;);
		xmlWrap.push(&quot;&lt;soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'&gt;&quot;);
		xmlWrap.push(&quot;&lt;soap:Body&gt;&quot;);
		xmlWrap.push(soapBody);
		xmlWrap.push(&quot;&lt;/soap:Body&gt;&quot;);
		xmlWrap.push(&quot;&lt;/soap:Envelope&gt;&quot;);
		xmlWrap = xmlWrap.join('');
	$.ajax({
		async:false,
		type:&quot;POST&quot;,
		url:webserviceUrl,
		contentType:&quot;text/xml; charset=utf-8&quot;,
		processData:false,
		data:xmlWrap,
		dataType:&quot;xml&quot;,
		beforeSend:function(xhr){
			xhr.setRequestHeader('SOAPAction',requestHeader);
		},
		success:successFunc,
		error:function(xhr){
			alert(xhr.statusText);
		}
	});
}

/*****************************************************
			Add or remove chart config option
*****************************************************/
function addOrRemove(obj,add){
	if(add){
		var strArr = [];
			strArr.push(&quot;&lt;tr&gt;&quot;);
			strArr.push(&quot;&lt;td style='padding:0 5 0 5'&gt;Option name&lt;/td&gt;&quot;);
			strArr.push(&quot;&lt;td style='padding:0 5 0 5'&gt;&lt;div class='newChartConfigDiv'&gt;&lt;input title='Option name' style='width:100px' id='NewOptionName' type='Text' /&gt;&quot;);
			strArr.push(&quot;&lt;label style='padding:0 5 0 5'&gt;Value&lt;/label&gt;&lt;input title='Option value' style='width:100px' id='NewOptionVal' type='Text' /&gt;&quot;);
			strArr.push(&quot;&lt;a title='Remove current option' style='padding-left:5px' href='javascript:' onclick='addOrRemove($(this),false)'&gt;X&lt;/a&gt;&lt;/div&gt;&quot;);
			strArr.push(&quot;&lt;/td&gt;&lt;/tr&gt;&quot;);
			str = strArr.join('');
		obj.parents('tr:first').before(str);
	}else{
		obj.parents('tr:first').remove();
	}
}

/*****************************************************
					Draw chart
*****************************************************/
chart = '';
function drawChart(config,numFieldsArrFromConfig,options) {
var data = new google.visualization.DataTable();
// String
data.addColumn('string',config.labelCol);
// Number
if(config.chartType=='OrgChart'){
	var coltype = 'string';
}else{
	var coltype = 'number';
}             
$.each(numFieldsArrFromConfig,function(i,colObj){
var actionFriendlyName = '';
	if(colObj.prefix=='true'){
		switch(colObj.action){
			case 'Sum':
				var actionFriendlyName = 'Sum of ';
			break;
			case 'Count':
				var actionFriendlyName = 'Count of ';
			break;
			case 'Average':
				var actionFriendlyName = 'Average of ';
			break;
			default:
				var actionFriendlyName = '';
		}
	}	
	data.addColumn(coltype,actionFriendlyName+colObj.label);	
});

	wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/';
	viewFields = [config.labelCol];
	$.each(numFieldsArrFromConfig,function(i,colObj){
		viewFields.push(colObj.fin);
	});
	if(config.useCustomCAML){
		var customCAML = config.customCAML;
		if(config.useUserProfileProperty){
			userInfoObj = getUserInfo();
			var filterValue = userInfoObj[config.userProfileProperty];	
			if(config.regexProfileProperty!='' &amp;&amp; filterValue!=''){
				try
				{
					var regExpMatch = filterValue.match(config.regexProfileProperty)[1];
				}
				catch(err)
				{
					window.status=&quot;SharePoint Javascripts - Error in RegExp match in chart with ID &quot;&quot;+config.myChartId+&quot;&quot;. The error was: &quot;+err.description;
				}
				if(regExpMatch!=undefined){
					filterValue=regExpMatch;
				}
			}	
			if(filterValue==''){
				$(&quot;#&quot;+config.myChartId).after(&quot;&lt;div style='width:&quot;+options.width+&quot;;padding-left:5px;font-size:8px'&gt;The selected user profile property (&quot;+config.userProfileProperty+&quot;) is empty!&lt;/div&gt;&quot;);
			}else{
				$(&quot;#&quot;+config.myChartId).after(&quot;&lt;div style='width:&quot;+options.width+&quot;;padding-left:5px;font-size:8px'&gt;Filtered by user profile property &quot;+config.userProfileProperty+&quot;=&quot;+filterValue+&quot;&lt;/div&gt;&quot;);
			}			
			customCAML = customCAML.replace(/{}/,filterValue);
		}
		res = queryItems(config.listGuid,customCAML,viewFields);
		if(res.count==-1){
			alert(&quot;An error occured in the &quot;customCAML&quot; for the chart: &quot;+config.myChartId+&quot;.n&quot;+
				  &quot;Check list guid and CAML query:nn&quot;+ 
				  &quot;ListGuid:n&quot;+config.listGuid+&quot;nn&quot;+
				  &quot;CAML-query:n&quot;+config.customCAML);
		}
	}else{
		res = queryItemsByViewName(config.listGuid,config.viewGuid,viewFields);
	}
	dataObj = {};
	var rowCount = 0;
	$.each(res.items,function(i,item){
		labelColVal = (item[config.labelCol]!=null)?item[config.labelCol]:'';
		// Strip off any prefix	
		if(labelColVal!=null&amp;&amp;labelColVal.indexOf(';#')&gt;-1){	
			labelColVal = labelColVal.substring(labelColVal.indexOf(';#')+2);
		}
		if(dataObj[labelColVal]==undefined){
			dataObj[labelColVal]={};
			rowCount ++;			
		}
		if(config.chartType=='OrgChart'){
			$.each(numFieldsArrFromConfig,function(idx,obj){		
				var thisVal = item[obj.fin];
				// If the source is a calculated column
				if(thisVal!=null&amp;&amp;thisVal.indexOf(';#')&gt;-1){
					thisVal = thisVal.match(/([d.]+$)/)[0];
				}
				// Build object			
				if(dataObj[labelColVal][obj.fin]==undefined){			
					var val = (thisVal!=null)?thisVal:null;				
					dataObj[labelColVal][obj.fin]=val;
				}
			});
		}else{
			$.each(numFieldsArrFromConfig,function(idx,obj){		
				var thisVal = item[obj.fin];
				// If the source is a calculated column - find first number
				if(thisVal!=null&amp;&amp;thisVal.indexOf(';#')&gt;-1){
					thisVal = thisVal.match(/[0-9.-]+/).toString();
				}				
				// Build object				
				if(dataObj[labelColVal][obj.fin+obj.action]==undefined){				
					if(obj.action=='Sum'){	
						var val = (thisVal!=null)?parseFloat(thisVal.match(/[0-9.-]+/).toString()):null;
						if(isNaN(val))val=null;
					}else if(obj.action=='Count'){	
						if(obj.fieldType=='Boolean'){
							var val = (thisVal==1)?1:0;
						}else{
							var val = (thisVal!=null)?1:0;
						}							
					}else if(obj.action=='Average'){
						var val = (thisVal!=null)?parseFloat(thisVal.match(/[0-9.-]+/).toString()):null;
						if(isNaN(val))val=null;
					}
					dataObj[labelColVal][obj.fin+obj.action]={'value':val,'action':obj.action,'count':1};
				}else{
					if(obj.action=='Sum'){					
						var val = (thisVal!=null)?parseFloat(thisVal.match(/[0-9.-]+/).toString()):null;
						if(isNaN(val))val=null;
					}else if(obj.action=='Count'){
						if(obj.fieldType=='Boolean'){
							var val = (thisVal==1)?1:0;
						}else{
							var val = (thisVal!=null)?1:0;
						}	
					}else if(obj.action=='Average'){
						var val = (thisVal!=null)?parseFloat(thisVal.match(/[0-9.-]+/).toString()):null;
						if(isNaN(val))val=null;					
					}
					dataObj[labelColVal][obj.fin+obj.action]['value']+=val;
					dataObj[labelColVal][obj.fin+obj.action]['count']+=1;
				}
			});		
		}
	});
	
	data.addRows(rowCount);
	rowIndex=0;	
	if(config.chartType=='OrgChart'){	
		$.each(dataObj,function(propName,obj){
			var descr = null;
			// If the name is added with a comma and a description - like &quot;Bruce Springsteen,Bruce Springsteen&lt;br /&gt;&lt;div style=&quot;text-align:center&quot;&gt;&lt;font color=&quot;red&quot;&gt;&lt;em&gt;The Boss&lt;/em&gt;&lt;/font&gt;&lt;/div&gt;&quot;
			var split = propName.split(',');
				if(split.length&gt;1){
					propName=split[0];						
					descr=split[1];
				}
			data.setCell(rowIndex,0,propName,descr);			
			colIndex=1;
			$.each(obj,function(idx,objVal){			
				data.setCell(rowIndex,colIndex,objVal);
				colIndex++
			});
			rowIndex++
		});
	}else{		
		$.each(dataObj,function(propName,obj){
			data.setValue(rowIndex,0,propName);
			colIndex=1;
			$.each(obj,function(idx,objVal){
				if(objVal.action=='Average'){
					val = objVal.value/objVal.count;
				}else{
					val = objVal.value;
				}
				var roundedVal = Math.round(val*100)/100;
				data.setValue(rowIndex,colIndex,roundedVal);
				colIndex++
			});
			rowIndex++
		});
	}
	// Draw chart
	chart = new google.visualization[config.chartType](document.getElementById(config.myChartId));
	chart.draw(data,options);
	// Add mouse over
	google.visualization.events.addListener(chart,'onmouseover',chartMouseOver);
	google.visualization.events.addListener(chart,'onmouseout',chartMouseOut);
}

function chartMouseOver(e){
	this.setSelection([e]);
}

function chartMouseOut(e){
   this.setSelection([{'row': null, 'column': null}]);
}

/*****************************************************
					Web service calls
*****************************************************/
function queryItemsByViewName(listName, viewName, viewFields, pagingInfo){
	var content = buildQueryContentByViewName(listName, viewName, viewFields, pagingInfo);
	var result = {count:-1, nextPagingInfo:'', items:new Array()};
	innerPost(wsBaseUrl + 'lists.asmx', 'http://schemas.microsoft.com/sharepoint/soap/GetListItems', content, function(data){
		result.count = $('rs\:data', data).attr('ItemCount');
		result.nextPagingInfo = $('rs\:data', data).attr('ListItemCollectionPositionNext');
		$('z\:row', data).each(function(idx, itemData){
			result.items.push(generateItem(itemData, viewFields));
		});
	});
	return result;
}

function buildQueryContentByViewName(listName, viewName, viewFields, pagingInfo){
	var result = new StringBuffer();
	result.append('&lt;GetListItems xmlns=&quot;http://schemas.microsoft.com/sharepoint/soap/&quot;&gt;');
	result.append('&lt;listName&gt;' + listName + '&lt;/listName&gt;');
	result.append('&lt;viewName&gt;' + viewName + '&lt;/viewName&gt;');
	if(viewFields != null &amp;&amp; viewFields.length &gt; 0){
		result.append('&lt;viewFields&gt;&lt;ViewFields xmlns=&quot;&quot;&gt;');
		$.each(viewFields, function(idx, field){
			result.append('&lt;FieldRef Name=&quot;' + field + '&quot;/&gt;');
		});
		result.append('&lt;/ViewFields&gt;&lt;/viewFields&gt;');
	}
	result.append('&lt;queryOptions&gt;&lt;QueryOptions xmlns=&quot;&quot;&gt;&lt;IncludeMandatoryColumns&gt;FALSE&lt;/IncludeMandatoryColumns&gt;');
	if(pagingInfo != undefined &amp;&amp; pagingInfo != null &amp;&amp; pagingInfo != '')
		result.append('&lt;Paging ListItemCollectionPositionNext=&quot;' + pagingInfo.replace(/&amp;/g, '&amp;amp;') + '&quot; /&gt;');
	result.append('&lt;/QueryOptions&gt;&lt;/queryOptions&gt;');
	result.append('&lt;/GetListItems&gt;');
	return result.toString();
}

/*****************************************************
	Access user infor for filtering chart data
*****************************************************/
function getUserInfo(UserId){
wsBaseUrl = userListBaseUrl + '/_vti_bin/';
var uiObj = {};

if(typeof(UserId)==&quot;undefined&quot; || UserId=='')UserId = _spUserId;

var arrOfFields = ['ID', 'Name', 'Title', 'EMail', 'Department', 'JobTitle', 'Notes', 'Picture',
'IsSiteAdmin', 'Created', 'Author', 'Modified', 'Editor', 'SipAddress', 'Deleted'];

var item = getItemById(userListGuid,UserId,arrOfFields);
    if(item != null){
	    for(i=0;i&lt;arrOfFields.length;i++){
	    	if(item[arrOfFields[i]]!=null){
	    		uiObj[arrOfFields[i]] = item[arrOfFields[i]];
	    	}else{
	    		uiObj[arrOfFields[i]] = '';
	    	}
	    }
       	return uiObj;
    }else{
        for(i=0;i&lt;arrOfFields.length;i++){
    		uiObj[arrOfFields[i]] = &quot;User with id &quot; + UserId + &quot; not found.&quot;;
    	}
		return uiObj;
	}
}

Hover over the code, select “view source”, highlight and copy. Save as “ChartUsingGoogleVisualizationAPI.js”, mind the file extension, and upload to the scriptlibrary as shown above.

The article is not finished and will be updated with examples and more info, please be patient…


Examples

This example shows a web part page with 3 CEWP’s. The top two holds a <div> with unique id’s. The bottom one holds the code that calls the “chart builder” with an array of the id’s of the “containers” set in the top two CEWP’s:
IMG
The “container div” can be inserted in a CEWP holding text or other content.

You must ensure is that the CEWP holding the script are placed in the bottom (right) web part zone to ensure that the containers are rendered before the code “needs them”.


Regards
Alexander