1 //Class c.protovis.ClusteredColumnChart : Chart 2 //This is the custom wrapper class for protovis bar charts 3 4 //Constructor 5 wso2vis.s.chart.protovis.ClusteredColumnChart = function(canvas, chartTitle, chartDesc) { 6 wso2vis.s.chart.Chart.call(this, canvas, chartTitle, chartDesc); 7 8 this.ySuffix("") 9 .xSuffix(""); 10 11 /* @private */ 12 this.vis = null; 13 this.y = null; 14 this.x = null; 15 this.dataFieldCount = 1; 16 this.subDataFieldCount = 1; 17 this.maxDataValue = 50; 18 } 19 20 // this makes c.protovis.ClusteredColumnChart.prototype inherit from Chart 21 wso2vis.extend(wso2vis.s.chart.protovis.ClusteredColumnChart, wso2vis.s.chart.Chart); 22 23 wso2vis.s.chart.protovis.ClusteredColumnChart.prototype 24 .property("dataField") 25 .property("dataLabel") 26 .property("subDataField") 27 .property("subDataValue") 28 .property("subDataLabel") 29 .property("ySuffix") 30 .property("xSuffix"); 31 32 //Public function load 33 //Loads the chart inside the given HTML element 34 wso2vis.s.chart.protovis.ClusteredColumnChart.prototype.load = function (w, h) { 35 if ( w !== undefined ) { 36 this.width(w); 37 } 38 if ( h !== undefined ) { 39 this.height(h); 40 } 41 42 var thisObject = this; 43 44 this.y = pv.Scale.linear(0, this.maxDataValue).range(0, this.height()); 45 this.x = pv.Scale.ordinal(pv.range(this.dataFieldCount)).splitBanded(0, this.width(), 4/5); 46 47 this.vis = new pv.Panel() 48 .canvas(function() { return thisObject.divEl(); }) 49 .width(function() { return thisObject.width(); }) 50 .height(function() { return thisObject.height(); }); 51 52 var chart = this.vis.add(pv.Panel) 53 .width(function() { return (thisObject.width() - thisObject.paddingLeft() - thisObject.paddingRight()); }) 54 .height(function() { return (thisObject.height() - thisObject.paddingTop() - thisObject.paddingBottom()); }) 55 .top(thisObject.paddingTop()) 56 .bottom(thisObject.paddingBottom()) 57 .left(thisObject.paddingLeft()) 58 .right(thisObject.paddingRight()); 59 60 var bar = chart.add(pv.Panel) 61 .data(function() { return thisObject.getData(thisObject); }) 62 .left(function() { return thisObject.x(this.index); }) 63 .add(pv.Bar) 64 .data(function(a) { return a; }) 65 .left(function() { return (this.index * thisObject.x.range().band / thisObject.subDataFieldCount); }) 66 .width(function() { return (thisObject.x.range().band / thisObject.subDataFieldCount); }) 67 .bottom(0) 68 .height(thisObject.y) 69 .fillStyle(pv.Colors.category20().by(pv.index)) 70 .title(function() { 71 var dataObj = thisObject.traverseToDataField(thisObject.data, thisObject.dataField()); 72 if( dataObj instanceof Array ) { 73 return thisObject.onTooltip(dataObj[this.parent.index], this.index); 74 } 75 else { 76 return thisObject.onTooltip(dataObj); 77 } 78 }) 79 .event("click", function() { 80 var dataObj = thisObject.traverseToDataField(thisObject.data, thisObject.dataField()); 81 if( dataObj instanceof Array ) { 82 return thisObject.onClick(dataObj[this.parent.index], this.index); 83 } 84 else { 85 return thisObject.onClick(dataObj); 86 } 87 }); 88 89 bar.anchor("top").add(pv.Label) 90 .visible(function() { return thisObject.marks(); }) 91 .textStyle("white") 92 .text(function(d) { return d; }); 93 94 chart.add(pv.Label) 95 .data(function() { return pv.range(thisObject.dataFieldCount); }) 96 .bottom(0) 97 .left(function() { return thisObject.x(this.index); }) //TODO fix the alignment issue (+ thisObject.x.range().band / 2) 98 .textMargin(5) 99 .textBaseline("top") 100 .text(function() { return thisObject.getDataLabel(this.index); }) 101 .font(function() { return thisObject.labelFont(); }); 102 103 chart.add(pv.Rule) 104 .data(function() { return thisObject.y.ticks(); }) 105 .bottom(function(d) { return (Math.round(thisObject.y(d)) - 0.5); }) 106 .strokeStyle(function(d) { return (d ? "rgba(128,128,128,.3)" : "#000"); }) 107 .add(pv.Rule) 108 .left(0) 109 .width(5) 110 .strokeStyle("rgba(128,128,128,1)") 111 .anchor("left").add(pv.Label) 112 .text(function(d) { return d.toFixed(); }) 113 .font(function() { return thisObject.labelFont(); }); 114 115 this.vis.add(pv.Label) 116 .left(this.width() / 2) 117 .visible(function() { return !(thisObject.title() === ""); }) 118 .top(16) 119 .textAlign("center") 120 .text(function() { return thisObject.title(); }) 121 .font(function() { return thisObject.titleFont(); }); 122 }; 123 124 /** 125 * @private 126 */ 127 wso2vis.s.chart.protovis.ClusteredColumnChart.prototype.titleSpacing = function () { 128 if(this.title() === "") { 129 return 1; 130 } 131 else { 132 return 0.9; 133 } 134 }; 135 136 wso2vis.s.chart.protovis.ClusteredColumnChart.prototype.populateData = function (thisObject) { 137 138 var tmpMaxValHolder = []; 139 var _dataField = thisObject.traverseToDataField(thisObject.data, thisObject.dataField()); 140 141 var dataGrpCount = 1; 142 if( _dataField instanceof Array ) { 143 dataGrpCount = _dataField.length; 144 } 145 146 thisObject.subDataFieldCount = 1; 147 thisObject.formattedData = pv.range(dataGrpCount).map( genDataMap ); 148 thisObject.dataFieldCount = dataGrpCount; 149 thisObject.maxDataValue = tmpMaxValHolder.max(); 150 if (thisObject.maxDataValue < 5) thisObject.maxDataValue = 5; // fixing value repeating issue. 151 152 thisObject.y.domain(0, thisObject.maxDataValue).range(0, (thisObject.height() - thisObject.paddingTop() - thisObject.paddingBottom())); 153 thisObject.x.domain(pv.range(thisObject.dataFieldCount)).splitBanded(0, (thisObject.width() - thisObject.paddingLeft() - thisObject.paddingRight()), 4/5); 154 155 function genDataMap(x) { 156 var innerArray = []; 157 158 var rootObja; 159 if( _dataField instanceof Array ) { 160 rootObja = _dataField[x]; 161 } 162 else { 163 rootObja = _dataField; 164 } 165 166 var _subDataField = thisObject.traverseToDataField(rootObja, thisObject.subDataField()); 167 168 var subDataGrpCount = 1; 169 if( _subDataField instanceof Array ) { 170 subDataGrpCount = _subDataField.length; 171 thisObject.subDataFieldCount = (thisObject.subDataFieldCount < _subDataField.length) ? _subDataField.length : thisObject.subDataFieldCount; 172 } 173 174 for(var y=0; y<subDataGrpCount; y++) { 175 var rootObjb; 176 if( _subDataField instanceof Array ) { 177 rootObjb = _subDataField[y]; 178 } 179 else { 180 rootObjb = _subDataField; 181 } 182 var temp = parseInt(thisObject.traverseToDataField(rootObjb, thisObject.subDataValue())); 183 innerArray.push(temp); 184 } 185 tmpMaxValHolder.push(innerArray.max()); 186 return innerArray; 187 } 188 }; 189 190 wso2vis.s.chart.protovis.ClusteredColumnChart.prototype.getData = function (thisObject) { 191 192 return thisObject.formattedData; 193 }; 194 195 wso2vis.s.chart.protovis.ClusteredColumnChart.prototype.update = function () { 196 197 this.populateData(this); 198 this.vis.render(); 199 if(this.tooltip() === true) { 200 tooltip.init(); 201 } 202 }; 203 204 wso2vis.s.chart.protovis.ClusteredColumnChart.prototype.getDataLabel = function (i) { 205 if (this.data !== null){ 206 207 var rootObj = this.traverseToDataField(this.data, this.dataField()); 208 if( rootObj instanceof Array ) { 209 return this.traverseToDataField(rootObj[i], this.dataLabel()); 210 } 211 else { 212 return this.traverseToDataField(rootObj, this.dataLabel()); 213 } 214 } 215 return i; 216 }; 217 218 wso2vis.s.chart.protovis.ClusteredColumnChart.prototype.getSubDataLable = function (i, j) { 219 if (this.data !== null){ 220 var rootDataObj; 221 var _dataField = this.traverseToDataField(this.data, this.dataField()); 222 223 if( _dataField instanceof Array ) { 224 rootDataObj = _dataField[i]; 225 } 226 else { 227 rootDataObj = _dataField; 228 } 229 230 var rootSubDataObj = this.traverseToDataField(rootDataObj, this.subDataField()); 231 232 if( rootSubDataObj instanceof Array ) { 233 return this.traverseToDataField(rootSubDataObj[j], this.subDataLabel()); 234 } 235 else { 236 return this.traverseToDataField(rootSubDataObj, this.subDataLabel()); 237 } 238 } 239 return j; 240 }; 241 242