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