1 //Class AreaChart : Chart
  2 //This is the custom wrapper class for protovis area/line charts
  3 
  4 //Constructor
  5 wso2vis.s.chart.protovis.AreaChart = function(div, chartTitle, chartDesc) {
  6     wso2vis.s.chart.Chart.call(this, div, chartTitle, chartDesc);
  7 
  8     this.band(12)
  9         .ySuffix("")
 10         .xSuffix("")
 11         .xInterval(10000)
 12 		.dirFromLeft(true);
 13 
 14     /* @private */
 15     this.dataHistory = [];
 16     this.vis = null;
 17     this.x = null;
 18     this.y = null;
 19 };
 20 
 21 // this makes AreaChart.prototype inherit from Chart
 22 wso2vis.extend(wso2vis.s.chart.protovis.AreaChart, wso2vis.s.chart.Chart);
 23 
 24 wso2vis.s.chart.protovis.AreaChart.prototype
 25     .property("band")
 26     .property("dataField")
 27     .property("dataValue")
 28     .property("dataLabel")
 29     .property("ySuffix")
 30     .property("xSuffix")
 31     .property("xInterval")
 32 	.property("dirFromLeft");
 33 
 34 //Public function load
 35 //Loads the chart inside the given HTML element
 36 wso2vis.s.chart.protovis.AreaChart.prototype.load = function (w, h, band) {
 37     if ( w !== undefined ) {
 38         this.width(w);
 39     }
 40     if ( h !== undefined ) {
 41         this.height(h);
 42     }
 43     if ( band !== undefined ) {
 44         this.band(band);
 45     }
 46 
 47     var thisObject = this;
 48 
 49     this.x = pv.Scale.linear(0, this.band()).range(0, this.width());
 50     this.y = pv.Scale.linear(0, 50).range(0, this.height()*0.9);
 51  
 52     this.vis = new pv.Panel()
 53         .canvas(function() { return thisObject.divEl(); })
 54         .width(function() { return thisObject.width(); })
 55         .height(function() { return thisObject.height(); })
 56         .bottom(20)
 57         .top(0)
 58         .left(30)
 59         .right(10);
 60 
 61     var panel = this.vis.add(pv.Panel)
 62         .data(function() { return thisObject.getData(thisObject); })
 63         .top(function() { return (thisObject.height() * (1 - thisObject.titleSpacing())); })
 64         .height(function() { return (thisObject.height() * thisObject.titleSpacing()); });
 65         //.strokeStyle("#ccc");
 66 
 67     var area = panel.add(pv.Area)
 68         .data(function(a) { return a; })
 69         .left(function(d) 
 70 			  {
 71 				  if (thisObject.dirFromLeft())
 72 				  	 return thisObject.x(this.index);
 73 			      return thisObject.x((thisObject.dataHistory[this.parent.index].length <= thisObject.band()) ? (thisObject.band() - thisObject.dataHistory[this.parent.index].length) + this.index + 1: this.index); 
 74 			  })
 75         .bottom(0)//pv.Layout.stack())
 76         .height(function(d) { return thisObject.y(d); })
 77         .title(function() {
 78             var dataObj = thisObject.traverseToDataField(thisObject.data, thisObject.dataField());
 79             if( dataObj instanceof Array ) {
 80                 return thisObject.onTooltip(dataObj[this.parent.index]);
 81             }
 82             else {
 83                 return thisObject.onTooltip(dataObj);
 84             }
 85         })
 86         .event("click", function() {
 87             var dataObj = thisObject.traverseToDataField(thisObject.data, thisObject.dataField());
 88             if( dataObj instanceof Array ) {
 89                 return thisObject.onClick(dataObj[this.parent.index]);
 90             }
 91             else {
 92                 return thisObject.onClick(dataObj);
 93             }
 94         });
 95 
 96     var areaDot = area.anchor("top").add(pv.Dot).title(function(d) { return d; })
 97         .visible(function() { return thisObject.marks(); })
 98         .fillStyle("#fff")
 99         .size(10);
100         //.add(pv.Label);
101 
102     /* Legend */
103     panel.add(pv.Dot)
104         .visible(function() { return thisObject.legend(); })
105         .right(100)
106         .fillStyle(function() { return area.fillStyle(); })
107         .bottom(function() { return (this.parent.index * 15) + 10; })
108         .size(20) 
109         .lineWidth(1)
110         .strokeStyle("#000")
111       .anchor("right").add(pv.Label)
112         .text(function() { return thisObject.getDataLabel(this.parent.index); });
113      
114     /* Vertical Grid Lines */
115     panel.add(pv.Rule)
116         .data(function() { return thisObject.x.ticks(); })
117         //.visible(function(d) { return (d > 0); })
118         .left(function(d) { return (Math.round(thisObject.x(d)) - 0.5); })
119         //.strokeStyle("rgba(128,128,128,.1)")
120       //.add(pv.Rule)
121         .bottom(-2)
122         .height(5)
123         .strokeStyle("rgba(128,128,128,1)")
124       .anchor("bottom").add(pv.Label)
125         .textMargin(10)
126         .text(function(d) { var n = new Number(((thisObject.dirFromLeft())? d : thisObject.band() - d) * thisObject.xInterval() / 1000); return n.toFixed() + thisObject.xSuffix(); })
127         .font(function() { return thisObject.labelFont(); })
128         .textStyle("rgb(0,0,0)");
129     
130     /* Horizontal Grid Lines */
131     panel.add(pv.Rule)
132         .data(function() { return thisObject.y.ticks(); })
133         //.visible(function() { return !(this.parent.index % 2); })
134         .bottom(function(d) { return (Math.round(thisObject.y(d)) - 0.5); })
135         .strokeStyle("rgba(128,128,128,.2)")
136         //.strokeStyle(function(d) { return (d==12) ? "green" : "rgba(128,128,128,.2)"; })
137       .add(pv.Rule)
138         .left(-5)
139         .width(5)
140         .strokeStyle("rgba(128,128,128,1)")
141       .anchor("left").add(pv.Label)
142         .textMargin(10)
143         .text(function(d) {return d.toFixed() + thisObject.ySuffix(); })
144         .font(function() { return thisObject.labelFont(); })
145         .textStyle("rgb(0,0,0)");
146 
147     this.vis.add(pv.Label)
148         .left(this.width() / 2)
149         .visible(function() { return !(thisObject.title() === ""); })
150         .top(16)
151         .textAlign("center")
152         .text(function() { return thisObject.title(); })
153         .font(function() { return thisObject.titleFont(); });
154 };
155 
156 /**
157 * @private
158 */
159 wso2vis.s.chart.protovis.AreaChart.prototype.titleSpacing = function () {
160     if(this.title() === "") {
161         return 1;
162     }
163     else {
164         return 0.9;
165     }
166 };
167 
168 /**
169 * @private 
170 */
171 wso2vis.s.chart.protovis.AreaChart.prototype.populateData = function (thisObject) {
172     var _dataField = thisObject.traverseToDataField(thisObject.data, thisObject.dataField());
173 
174     var dataGrpCount = 1;
175     if( _dataField instanceof Array ) {
176         dataGrpCount = _dataField.length;
177     }
178 
179     thisObject.formattedData = pv.range(dataGrpCount).map(genDataMap);
180 
181     thisObject.x.domain(0, thisObject.band()).range(0,thisObject.width());
182     var maxheight = calcMaxHeight();
183     if (maxheight < 5) maxheight = 5; // fixing value repeating issue.
184     thisObject.y.domain(0, maxheight).range(0, (thisObject.height() * thisObject.titleSpacing()) - 35);
185     thisObject.y.nice();
186     
187     var maxLabelLength = (maxheight == 0) ? 1 : Math.floor(Math.log(maxheight)/Math.log(10)) + 1; //TODO: maxheight will never become 0. But we check it just to be in the safe side. useless?
188     this.vis.left((maxLabelLength*9.5)+10);
189     
190     function genDataMap(x) {
191         var rootObj;
192         if( _dataField instanceof Array ) {
193             rootObj = _dataField[x];
194         }
195         else {
196             rootObj = _dataField;
197         }
198         var valObj = parseInt(thisObject.traverseToDataField(rootObj, thisObject.dataValue()));
199 
200         if (thisObject.dataHistory[x] === undefined){
201             thisObject.dataHistory[x] = new Array();
202         }
203 		if (thisObject.dirFromLeft()) {
204 			thisObject.dataHistory[x].unshift(valObj);
205 
206 			if(thisObject.dataHistory[x].length > thisObject.band()+1){
207 				thisObject.dataHistory[x].pop();
208 			}
209 		}
210 		else {
211 			thisObject.dataHistory[x].push(valObj);
212 
213 			if(thisObject.dataHistory[x].length > thisObject.band()+1){
214 				thisObject.dataHistory[x].shift();
215 			}
216 		}
217         return thisObject.dataHistory[x];
218     }
219 
220     function calcMaxHeight() {
221         var totHeights = [];
222         for (var k=0; k<thisObject.dataHistory.length; k++) {
223             totHeights.push(thisObject.dataHistory[k].max());
224         }
225         return totHeights.max();
226     }
227 };
228 
229 wso2vis.s.chart.protovis.AreaChart.prototype.getData = function (thisObject) {
230     return thisObject.formattedData;
231 };
232 
233 wso2vis.s.chart.protovis.AreaChart.prototype.update = function () {
234     this.populateData(this);
235     this.vis.render();
236     if(this.tooltip() === true) {
237         tooltip.init();
238     }
239 };
240 
241 wso2vis.s.chart.protovis.AreaChart.prototype.getDataLabel = function (i) {
242     if (this.data !== null){
243         var rootObj = this.traverseToDataField(this.data, this.dataField());
244         if( rootObj instanceof Array ) {
245             return  this.traverseToDataField(rootObj[i], this.dataLabel());
246         }
247         else {
248             return  this.traverseToDataField(rootObj, this.dataLabel());
249         }
250     }
251     return i;
252 };
253 
254 wso2vis.s.chart.protovis.AreaChart.prototype.clear = function () {
255     this.dataHistory.length = 0;
256 };
257 
258