Aggregating view data for use in d3js graphics
Dashboards are all the rage, so it is natural that your XPages application need a dash of a dashboard. A view makes an excellent source for dashboard data and the ability to categorize views handles the heavy lifting of aggregating the values you want to use e.g. in a bar or pie chart. I've been fallen in love with d3js since she is the ultimate visualization (if in doubt, read the classics ).
D3Js is a harsh mistress of exceptional beauty, so you might want to check out some of her offsprings like RickShaw, NVD3 or xCharts. Indulge in myriads of tutorials and reviews (check part 2 too) and the over 1000 examples.
With just a few lines of JavaScript any categorized view can be used as source for d3js. The script can read a categorized view with one to three categories. If you have one it reads the view, for two you get hierarchical data or provide a key, so you only retrieve the selected category etc.Since I use a viewNavigator performance is quite good:
As usual: YMMV
P.S.: for end-users, check out Tableau
D3Js is a harsh mistress of exceptional beauty, so you might want to check out some of her offsprings like RickShaw, NVD3 or xCharts. Indulge in myriads of tutorials and reviews (check part 2 too) and the over 1000 examples.
With just a few lines of JavaScript any categorized view can be used as source for d3js. The script can read a categorized view with one to three categories. If you have one it reads the view, for two you get hierarchical data or provide a key, so you only retrieve the selected category etc.Since I use a viewNavigator performance is quite good:
function getCategoryData(viewName, dataColumn, getChildren, key) { var v = database.getView(viewName); var nav; if (key) { nav = v.createViewNavFromCategory(key); } else { nav= v.createViewNav(); } var ve = nav.getFirst(); var isFirst = true; var result = "["; while (ve) { if (!ve.isTotal()) { var curData = ve.getColumnValues(); if (!isFirst) { result += ","; } result += "{label : \""; if (key) { result += curData[1 ]; } else { result += curData[0 ]; } result += "\", value : "; result += curData[dataColumn ]; /*for 2 level categories we fetch additional data*/ if (getChildren) { var childve = nav.getChild(); var firstChild = true; result += ", children : ["; while (childve) { var childData = childve.getColumnValues(); if (!firstChild) { result += ","; } result += "{label : \""; result += childData[1 ]; result += "\", value : "; result += childData[dataColumn ]; result += "}"; firstChild = false; childve = nav.getNextSibling(childve); } result += " ]" } result += "}"; isFirst = false; } ve = nav.getNextSibling(ve); } result += " ]"; return result; }A very typical use are year-to-date graphs, that accummulate the values from category to category. Here I use this:
function getCumulativeCategoryData(viewName, key, dataColumn, fetchChildren) { var v = database.getView(viewName); var nav = v.createViewNavFromCategory(key); var ve = nav.getFirst(); var nextVe; var isFirst = true; var result = "["; var runningTotal = 0; while (ve) { // Prefetch the next entry nextVe = nav.getNextSibling(ve); if (!ve.isTotal()) { var curData = ve.getColumnValues(); if (!isFirst) { result += ","; } result += "{label : \""; result += curData[1 ]; result += "\", value : "; runningTotal += Number(curData[dataColumn ]); result += runningTotal; /*for 2 level categories we fetch additional data*/ if (fetchChildren) { var runningSubTotal = 0; var childve = nav.getChild(); var nextChildVe; var firstChild = true; result += ", children : ["; while (childve) { nextChildVe = nav.getNextSibling(childve); var childData = childve.getColumnValues(); if (!firstChild) { result += ","; } result += "{label : \""; result += childData[2 ]; result += "\", value : "; runningSubTotal += Number(childData[dataColumn ]); result += runningSubTotal; result += "}"; firstChild = false; try { childve.recycle(); } catch (e) { // No action } childve = nextChildVe; result += " ]" } } result += "}"; isFirst = false; } // Cleanup view entry try { ve.recycle(); } catch (e) { // We don't care } ve = nextVe; } result += " ]"; // Cleanup all objects try { nav.recyle(); v.recycle(); } catch (e) { // We don't care } return result; }
As usual: YMMV
P.S.: for end-users, check out Tableau
Posted by Stephan H Wissel on 24 September 2013 | Comments (2) | categories: XPages