Creating a simple Organizational Chart in XPages

A couple of days ago Jesse Gallagher posted a great entry on how to create a basic organizational chart using the XPages Extension Library navigator control in conjunction with a BeanTreeNode that generates the hierarchy. Truth be told, Jesse actually wrote this code based on the frustration that I had with trying to wrap my head around recursion to do the exact same thing.

While investigating different ways to build an organizational chart I also come across a nice little library from Google called Google Chart Tools which takes in a fairly flat data table and generates from it a chart that looks similar to the following..

Adding the chart to your XPage is very easy, first you need to add a new external JavaScript resource

<xp:this.resources>
	<xp:script src="https://www.google.com/jsapi" clientSide="true">
	</xp:script>
</xp:this.resources>

Then add a script block to the page that loads the orgchart visualization and, once loaded, calls a function to draw the chart into a div called chart_div.

<xp:scriptBlock id="scriptBlock1">
		<xp:this.value><![CDATA[google.load('visualization', '1', {packages:['orgchart']});
google.setOnLoadCallback(drawChart);

function drawChart() {
	var jsonData = dojo.xhrGet({
		url: "./orgChart.xsp/getOrgData",
		handleAs:"json",
		load: function(data){
        	var chartdata = new google.visualization.DataTable(data);
        	var chart = new google.visualization.OrgChart(document.getElementById('chart_div'));
        	chart.draw(chartdata, {allowHtml:true, allowCollapse:true});
    	}
		});
     }]]></xp:this.value>
	</xp:scriptBlock>

While you could directly add the data for the orgchart into the drawChart function I wanted to use a view in a database for the data so I’m loading my data using the Extension Library custom REST service. My REST service returns a JSON data construct that defines the information for the organization chart. The REST service is on the same page is the OrgChart and looks like this. It is a bit ugly as the way the data is defined means you needs arrays of objects inside arrays of other objects inside another array of objects. I am also manually defining the top of the orgChart by creating a single node with no manager.

	<xe:restService id="restService1" pathInfo="getOrgData">
		<xe:this.service>
			<xe:customRestService contentType="application/json">
				<xe:this.doGet><![CDATA[#{javascript:// Columns Array
var columns = new Array();

var col1 = new Object();
col1.type = "string";
col1.id = "";
col1.label = "Name";
columns.push(col1);

var col2 = new Object();
col2.type = "string";
col2.id = "";
col2.label = "Manager";
columns.push(col2);

var col3 = new Object();
col3.type = "string";
col3.id = "";
col3.label = "ToolTip";
columns.push(col3);

// Build Rows Array
var rows = new Array();

// Add TOP
var topRowName = new Object();
topRowName.v = "Mike";
var topRowMgr = new Object();
topRowMgr.v = "";
var topRowTip = new Object();
topRowTip.v = "President";

var topRowArray = new Array();
topRowArray.push(topRowName);
topRowArray.push(topRowMgr);
topRowArray.push(topRowTip);

var topRowObject = new Object();
topRowObject.c = topRowArray;
rows.push(topRowObject);

// Add employees
var empDB:NotesDatabase = session.getDatabase(database.getServer(),"employees.nsf",false);
var empView:NotesView = empDB.getView("lkp_byManager");
var empDoc:NotesDocument = empView.getFirstDocument();
while (empDoc != null){

	var thisRowName = new Object();
	var empName:NotesName = session.createName(empDoc.getItemValueString("FullName"));
	thisRowName.v = empName.getCommon();

	var thisRowMgr = new Object();
	var mgrName:NotesName = session.createName(empDoc.getItemValueString("Manager"));
	thisRowMgr.v = mgrName.getCommon();

	var thisRowTip = new Object();
	thisRowTip.v = empDoc.getItemValueString("JobTitle");

	var thisRowArray = new Array();
	thisRowArray.push(thisRowName);
	thisRowArray.push(thisRowMgr);
	thisRowArray.push(thisRowTip);

	var thisRowObject = new Object();
	thisRowObject.c = thisRowArray;
	rows.push(thisRowObject);

	empDoc = empView.getNextDocument(empDoc);
}

// Build final array
var alldata = new Object();
alldata.cols = columns;
alldata.rows = rows;

// pass it back as JSON
return toJson(alldata);}]]></xe:this.doGet>
			</xe:customRestService>
		</xe:this.service>
	</xe:restService>

The view that I’m looking up has been setup to only display people who have their manager field filled in. Google Chart Tools OrgChart will do some weird stuff if your data is bad, like if a person has a manager who doesn’t exist as an employee then a second org chart will appear to right of the main chart with the employees name linked to the non-existant managers name.

I also found that the chart got very wide when fed in a lot of data so this org chart is really only suited for a small company or on a department by department basis.

While this is a great example of how to use Google Chart Tools to create an OrgChart there are lots of other chart types available in the library and using the same technique to load the data via a JSON REST service using the ExtLib you can easily add charting to any XPage application.

Advertisements
Tagged with: , , , ,
Posted in None
Archives
%d bloggers like this: