ShowTable of Contents
=Pie Chart With Events=
Now I'm going to create a chart that allows you to click through to get content. For me this is the real power of XPages, using repeat controls to produce innovative and dynamic methods of navigation. Outlines or menus are okay, but we can do so much more. Dashboards look nice, but allow your users to click on the charts to drill down to the underlying data and they become so much more than just a nice picture to print out.
You can see the sample I've put together here. You'll see it's a pie chart of Open Calls and, as you click on each slice of the pie, the table on the right changes. All I am using is a pie chart (along the lines of the chart created in Part Two) and a view panel. The code for the series is very similar.
while (viewEnt != null) {
if (viewEnt.isCategory() & !viewEnt.isTotal()) {
if (viewEnt.getColumnValues()[5] > 0) {
/* parameters:
@y: number, corresponding to size of pie
@text: label (can be suppressed by setting 'labels' parameter of pie is set to false)
@color: colour of the pie section. Can be a colour name (e.g. "blue"), rgb or hex colours.
If dojox.charting.action2d.Highlight is used, the highlight colour is the negative (so if color is black, highlight is white)
@legend: can be used to override the text parameter for legends
@tooltip: if dojox.charting.action2d.Tooltip is used, this is the tooltip that's added.
*/
labelName = (viewEnt.getColumnValues()[5] > 20) ? viewEnt.getColumnValues()[0] : "";
output += "{y: " + viewEnt.getColumnValues()[5] + ", text: \"" + labelName + "\",legend: \"" + viewEnt.getColumnValues()[0] + "\"},";
}
}
viewEnt = viewNav.getNext(viewEnt);
}
The difference between this and the code for PartTwo is that I'm only getting the data for each client where open calls are greater than zero. I'm then (line 12) generating a label name if there are more than 20 open calls. The text parameter for my series element is the label name the legend is the client name. This means I'm showing a label for the larger slices of the pie, not showing a label for the smaller slices, but showing the client name for all slices in the legend.
There are then two additions. An Edit Box control, hidden using style="display:none" so it's available for javascript but hidden from view, called category, bound to a viewScope called category. Here's the code:
<xp:inputText id="category" style="display:none"
value="#{viewScope.category}">
</xp:inputText>
The second addition is javascript to set this field and call a partial refresh of my view panel:
var catField="#{id:category}";
chart1.connectToPlot("default", function(o){
/* o @params
@type: onclick, onmouseover, onmouseout
@element: marker, bar, column, circle, slice - this depends on the chart type and should be self-explanatory, so slice for pie chart
@x: a number, the value on the x axis, defined in your series
@y: a number, the value of the y axis, defined in your series
@index: a number, the index of the data point, so the nth element of the series
@run: the data run object, gets a handle on the original series, from whcih we can get the properties defined for the series
@plot: the plot object defined above, in this case "default"
@hAxis: the h axis object for the plot, more relevant for other chart types
@vAxis: the v axis object for the plot, more relevant for other chart types
@event: the event that started the event processing
@shape: the shape object that represents a data point
@outline: the outline object defined for the shape, only for specific chart types
@shadow: the shadow object defined for the shape, only for specific chart types
@cx: a number, the value of the visual centre of the shape on the x axis
@cy: a number, the value of the visual centre of the shape on the y axis
@cr: a number, the value of the radius of a circle or pie
*/
if (o.type == "onclick" && o.element == "slice") {
// Set the category field and call a partial refresh on the viewPanel.
// onStart etc. add a mask in case it takes a while
dojo.byId(catField).value = o.run.data[o.index].legend;
XSP.partialRefreshPost("#{id:refreshPanel}", {
onStart:loading(),
onComplete:stoploading(),
onError:stoploading()
})
}
});
So this code adds a function to chart1, connected to the default plot. For other chart types where you may have more than one plot, you can add different events to different plots. Then we create the code to trigger, using attributes of o. So here, if it's an onclick event taking place on a slice of the pie, we set the category field's value to be the legend attribute of the relevant element of the series. We then do a partial refresh of a panel with the id refreshPanel. The code within that just adds a mask while the partial refresh is happening, using code Mark Hughes blogged about. The view panel's data is filtered based upon the viewScope variable category, which we've just set y setting the field on line 24.
I've updated the sample charting database with this new chart, and it can be downloaded here.
I've had one big frustration, and if anyone can solve it I'll be very happy, as I'm sure will the community. The event handler we add to plot prevents the tooltips working. The other actions like magnify work fine, but the tooltip just doesn't show. I tried generating the tooltip by adding an onmouseover event into the event handler. I tried using the normal dijit.Tooltip module, but this throws an error because it can't change the style of the relevant parent dom node. That's why I'm adding a label onto the larger slices of the pie, so there are enough labels to cross-reference with the legend, but not so many that the chart becomes unreadable. It's not wonderful, but at the moment it's the best I can do.
About the Author
Paul Withers is a Domino Developer at Intec Systems Ltd. The original post of this and other tips / observations / tutorials are available at the
Intec Blog