jQuery in XPages #1 – Highcharts – How does it work?

This how does it work article is a follow on from the original jQuery in XPages #1 – Highcharts and goes into depth as to how the functionality was created and how you can modify it yourself.

Be fore-warned this is quite dry and not for the faint of heart, but hopefully will provide a good insight and understanding.

How does this work?

This Highchart demonstration is made up of the following design elements

  • XPage
    • xFruit (the container XPage)
  • Custom Controls (where all the hard work is done)
  • Theme
    • Highchart (extends oneuiv2)
  • View
    • Fruit (data source for the viewPanel)
  • Form
    • Fruit (data container)
  • JavaScript Library
    • jsformFruit

To avoid making this article long(er than it already is) I am going to focus just on the drawHighchart custom control and the Highchart theme. The sample database is available for download and you can pick it to pieces at your leisure.

Highcharts Theme

The theme works by:

  • Extending the oneuiv2 theme (as a demonstration that it does not conflict)
  • Imports the jQuery library we need (jquery-1.7.1.min.js)
  • Imports the highchart.js library. Because this is a pure JavaScript library there are no associated image files (amazing really)

<theme extends="oneuiv2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="platform:/plugin/com.ibm.designer.domino.stylekits/schema/stylekit.xsd" >
	<resource>
		<content-type>text/css</content-type>
		<href>theme/style.css</href>
	</resource>
	<resource>
		<content-type>application/x-javascript</content-type>
		<href>jquery-1.7.1.min.js</href>
 	</resource>
	<resource>
		<content-type>application/x-javascript</content-type>
		<href>Highcharts/js/highcharts.js</href>
 	</resource>

</theme>

drawHighchart custom Control

This custom control is intended to be self contained for the sake of this demonstration and can be dropped onto any XPage in your application. The example has a dropdown for theme and graph type choices. These parameters are fed into the Highchart.js file based on the selected field values, but in your application where you only want a specific chart type they could be hard-coded. Later in the article you will see where the parameters are fed into the highchart.js library and how you can configure them yourself.

The code for the custom control breaks down like this:

  • Both the chart theme and chart type fields have a full refresh set on the “onchange” event. This reloads the page and data when a change is made. Again for the sake of a demonstration this is ok, but in your real-world application you would only provide one chart type and remove these drop downs.
    • NOTE: because the code is instantiated in the $(document).ready(function()  that means a partial refresh will NOT work
Full update onchange event
Full update onchange event
  • The onClientLoad event of the custom control contains all the JavaScript which makes this work

    onClientLoad event of the custom control
    onClientLoad event of the custom control
  • The JavaScript is shown below and performs two basic tasks
    • It determines the selected theme and calls a function in the jsFormFruit library which sets the theme
      • e.g. callGray()
    • It instantiates the Highchart and passes the chart type as a value derived from the XPage
    • htmlTableGraph(“#{id:viewPanel1}”, “#{javascript: getComponent(‘chartType’).getValue()}”)
      • “#{id:viewPanel1}” is the idTag for the viewPanel <—change this if your view panel is called something different
      •  “#{javascript: getComponent(‘chartType’).getValue()}” is the value chosen for chart type

$(document).ready(function() {

var sTheme=x$('#{id:theme1}').val() //get the value from the theme dropdown on the webpage
switch(sTheme)
    {
    case 'gray':
        callGray()
        break;
    case 'darkBlue':
        callDarkBlue()
        break;
    case 'grid':
        callGrid()
        break;
    default:
        ""
    }

htmlTableGraph("#{id:viewPanel1}", "#{javascript: getComponent('chartType').getValue()}")

})

jsFormFruit JavascriptLibrary

The callGray(), callDarkBlue and callGrid() functions are all very similar and while it might look like a lot, it is actually very readable and you can see how the color scheme is created. NOTE : this is all JavaScript and can therefore be changed to suit your own needs – no images!! This is a snippet and the whole code is available in the database in the script library


function callGray(){
	Highcharts.theme = {
			   colors: ["#DDDF0D", "#7798BF", "#55BF3B", "#DF5353", "#aaeeee", "#ff0066", "#eeaaee",
			      "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"],
			   chart: {
			      backgroundColor: {
			         linearGradient: [0, 0, 0, 400],
			         stops: [
			            [0, 'rgb(96, 96, 96)'],
			            [1, 'rgb(16, 16, 16)']
			         ]
			      },
			      borderWidth: 0,
			      borderRadius: 15,
			      plotBackgroundColor: null,
			      plotShadow: false,
			      plotBorderWidth: 0
			   },
			   title: {
			      style: {
			         color: '#FFF',
			         font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
			      }
			   },
			   subtitle: {
			      style: {
			         color: '#DDD',
			         font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
			      }
			   },
			   xAxis: {
			      gridLineWidth: 0,
			      lineColor: '#999',
			      tickColor: '#999',
			      labels: {
			         style: {

			         etc etc etc.............
			         systematically going through each element and setting the style
			};

			// Apply the theme
			var highchartsOptions = Highcharts.setOptions(Highcharts.theme);
}

The htmlTableGraph() function

The htmlTableGraph is my modified version of the example given at the Highcharts website. I had to modify it because the viewPanel table created by XPages is not the same as the simple example given. Here’s the breakdown……


function htmlTableGraph(idTag, sType){

	/**
	 * Visualize an HTML table using Highcharts. The top (horizontal) header
	 * is used for series names, and the left (vertical) header is used
	 * for category names. This function is based on jQuery.
	 * @param {Object} table The reference to the HTML table to visualize
	 * @param {Object} options Highcharts options
	 */
	Highcharts.visualize = function(table, options) {
		// the categories
		options.xAxis.categories = [];
		$('tbody tr td:first-child', table).each( function(i) {
			options.xAxis.categories.push(this.lastChild.innerHTML);
		});

		// the data series
		options.series = [];
		$('tr', table).each( function(i) {
			var tr = this;
			$('th, td', tr).each( function(j) {
				if (j > 0) { // skip first column
					if (i == 0) { // get the name and init the series
						options.series[j - 1] = {
							name: this.lastChild.innerHTML,
							data: []
						};
					} else { // add values
						options.series[j - 1].data.push(parseFloat(this.lastChild.innerHTML));
					}
				}
			});
		});

		var chart = new Highcharts.Chart(options);
	}
            //idTag is the viewPanel1 id passed into the function
	var table = document.getElementById(idTag),
	options = {
		chart: {
			renderTo: 'container',
			type: sType
		},
		title: {
			text: 'Data extracted from a HTML table in the page'
		},
		xAxis: {
		},
		yAxis: {
			title: {
				text: 'Units'
			}
		},
		tooltip: {
			formatter: function() {
				return '<b>'+ this.series.name +'</b><br/>'+
					this.y +' '+ this.x.toLowerCase();
			}
		}
	};
	Highcharts.visualize(table, options);

}

The HTML created by the XPages server

The HTML generated by the XPage to display the viewPanel  looks like this where every table row TR has three table cells – inside each TD cell there is a span and inside that a value

<tbody>
<tr>
<td>
    <span id="view:_id1:_id2:_id23:viewPanel1:0:viewColumn1:_internalViewText">
        Bananas
    </span>
</td>
<td>
    <span id="view:_id1:_id2:_id23:viewPanel1:0:viewColumn2:_internalViewText">
        1.0
    </span>
</td>
<td>
    <span id="view:_id1:_id2:_id23:viewPanel1:0:viewColumn3:_internalViewText">2</span>
</td>
</tr>

How we parse the generated HTML in jQuery

The first thing I want to discuss is this part of the function

		options.xAxis.categories = [];
		$('tbody tr td:first-child', table).each( function(i) {
			options.xAxis.categories.push(this.lastChild.innerHTML);
		});

Breaking it down section by section

options.xAxis.categories = []; //sets up the array into which we will add the xAxis (the fruit)

We will work right to left to read what is going on

$('tbody tr td:first-child', table)
  • within the table (viewPanel1) element select everything which matches
    • the first td (td:first-child)
    • inside the tr
    • inside the tdbody
.each( function(i) {
  • because we can chain jQuery functions together we are cycling through each of the selected elements and for each element we are going to execute the function
options.xAxis.categories.push(this.lastChild.innerHTML);
  • this (the element we are acting on)
    • .lastChild (the last DOM element within the TD) – this bypasses the span within the TD
    • .innerHTML – the HTML within the element
  • options.xAxis.categories.push (add (push) the value into the options object on the xAxis.categories value)

Simply put this 4 lines of code cycles through the table, extracts the fruit values and adds them to an array for display on the xAxis (Apples, Oranges etc)

Parsing the table values

options.series = [];
$('tr', table).each( function(i) {
	var tr = this;
	$('th, td', tr).each( function(j) {
		if (j > 0) { // skip first column
			if (i == 0) { // get the name and init the series
				options.series[j - 1] = {
					name: this.lastChild.innerHTML,
						data: []
				};
			} else { // add values
				options.series[j - 1].data.push(parseFloat(this.lastChild.innerHTML));
			}
		}
	});
});
options.series = [];
  • Creates the array for drawing the chart values
$('tr', table).each( function(i) {
});
  •  For each TR within the table (viewPanel) provided cycle through each row
  •  i is the counter here as to which row we are on going down the table
	var tr = this;
	$('th, td', tr).each( function(j) {
	});
  •  for every th or td in each tr
  •  j is the counter here as we are going across the row
	if (j > 0) { // skip first column
		if (i == 0) { // get the name and init the series
			options.series[j - 1] = {
				name: this.lastChild.innerHTML,
					data: []
			};
		} else { // add values
			options.series[j - 1].data.push(parseFloat(this.lastChild.innerHTML));
		}
	}
  •  We ignore the first column (xAxis)
  •  if j > 0 (skiping the first column which is the xAxis (apples) values)
  •  if i = 0 (we are on the first row (the top one) and therefore we have the name Jane and John
  • add this (tr).lastChild.innerHTML (the HTML within the span) to the NAME value within the options.series array (NO DATA)
  • else (we are not on the top row) add the innerHTML value (converted to a number with parseFloat) to the options.series array

This section creates a string which looks like this – that is then parsed by the highchart.js

options = {series: [{
			name: Adam,
			data: {1, 2, 2, 6 }
		},
		{
			name: Jane,
			data: 2, 0, 4, 9 }
		]
	}

And finally, once we have created all the data arrays – display the highchart

	Highcharts.visualize(table, options);
Advertisement

4 thoughts on “jQuery in XPages #1 – Highcharts – How does it work?

  1. If i try tu use this in my xpages i retrive this error:

    Highcharts is not defined
    Highcharts.theme = {

    I have imported Highcharts folder and jquery-1.7.1.min.js in WebContent

    what would be the error?

    • I saw that the problem arises when the data is displayed in the table in this way:

      2011

      In fact, if I raise the everything works as you can remove it?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s