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