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)
- commonContainer (overall look an feel using the oneuiv2 example layout @ OpenNTF)
- formFruit (basic form and viewPanel)
- drawHighchart (charting capability)
- 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

- The onClientLoad event of the custom control contains all the JavaScript which makes this work
- 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
- It determines the selected theme and calls a function in the jsFormFruit library which sets the theme
$(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);
Reblogged this on Xomino.
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?
I am afraid I do not understand the question – is it working for you now?