EVOLUTION-MANAGER
Edit File: pie-chart.js
// http://jsfiddle.net/stephenboak/hYuPb/ // Wrapper function function do_pie(name, update_url, url_params, units, refresh) { var pie = new PieChart(name, update_url, url_params, units, refresh); if (refresh) pie.setInterval(setInterval(function(){pie.update();}, refresh)); // Return new class instance, with return pie; } function PieChart(name, update_url, url_params, units, refresh) { // Add object properties like this this.name = name; this.update_url = update_url; this.url_params = url_params; this.units = units; this.refresh = refresh; this.pieInterval; var pieData = []; var oldPieData = []; var filteredPieData = []; var rsp = create_pie_chart(name, units); var arc_group = rsp[0]; var donut = rsp[1]; var totalValue = rsp[2]; var totalUnits = rsp[3]; var color = rsp[4]; var tweenDuration = rsp[5]; var arc = rsp[6]; var label_group = rsp[7]; var center_group = rsp[8]; var r = rsp[9]; var textOffset = rsp[10]; // to run each time data is generated this.update = function() { // console.log(this.name); // console.log(this.url_params); $.ajax({ type: 'GET', url: this.update_url, data: this.url_params, success: function(content) { update_pie_chart(jQuery.parseJSON(content)); } }); } /////////////////////////////////////////////////////////// // STREAKER CONNECTION //////////////////////////////////// /////////////////////////////////////////////////////////// // Needed to draw the pie immediately this.update(); this.update(); // var updateInterval = window.setInterval(update, refresh); function compare_by_label(a, b) { if (a.label < b.label){ return -1; } else if (a.label > b.label) { return 1; } else { return 0; } } function update_pie_chart(data) { data.sort(compare_by_label); streakerDataAdded = data; oldPieData = filteredPieData; pieData = donut(streakerDataAdded); var totalOctets = 0; filteredPieData = pieData.filter(filterData); function filterData(element, index, array) { element.name = streakerDataAdded[index].label; element.value = streakerDataAdded[index].value; element.url = streakerDataAdded[index].url; totalOctets += element.value; return (element.value > 0); } if((filteredPieData.length > 0) && (oldPieData.length > 0)) { //REMOVE PLACEHOLDER CIRCLE arc_group.selectAll("circle").remove(); if(totalValue) { totalValue.text(function() { var kb = totalOctets/1024; return kb.toFixed(1); //return bchart.label.abbreviated(totalOctets*8); }); } //DRAW ARC PATHS paths = arc_group.selectAll("path").data(filteredPieData); paths.enter().append("svg:path") .attr("stroke", "white") .attr("stroke-width", 0.5) .attr("fill", function(d, i) { return color(i); }) .transition() .duration(tweenDuration) .attrTween("d", pieTween); paths .transition() .duration(tweenDuration) .attrTween("d", pieTween); paths.exit() .transition() .duration(tweenDuration) .attrTween("d", removePieTween) .remove(); //DRAW TICK MARK LINES FOR LABELS lines = label_group.selectAll("line").data(filteredPieData); lines.enter().append("svg:line") .attr("x1", 0) .attr("x2", 0) .attr("y1", -r-3) .attr("y2", -r-8) .attr("stroke", "gray") .attr("transform", function(d) { return "rotate(" + (d.startAngle+d.endAngle)/2 * (180/Math.PI) + ")"; }); lines.transition() .duration(tweenDuration) .attr("transform", function(d) { return "rotate(" + (d.startAngle+d.endAngle)/2 * (180/Math.PI) + ")"; }); lines.exit().remove(); //DRAW LABELS WITH PERCENTAGE VALUES valueLabels = label_group.selectAll("text.value").data(filteredPieData) .attr("dy", function(d){ if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) { return 5; } else { return -7; } }) .attr("text-anchor", function(d){ if ( (d.startAngle+d.endAngle)/2 < Math.PI ){ return "beginning"; } else { return "end"; } }) .text(function(d){ var percentage = (d.value/totalOctets)*100; return percentage.toFixed(1) + "%"; }); valueLabels.enter().append("svg:text") .attr("class", "value") .attr("transform", function(d) { return "translate(" + Math.cos(((d.startAngle+d.endAngle - Math.PI)/2)) * (r+textOffset) + "," + Math.sin((d.startAngle+d.endAngle - Math.PI)/2) * (r+textOffset) + ")"; }) .attr("dy", function(d){ if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) { return 5; } else { return -7; } }) .attr("text-anchor", function(d){ if ( (d.startAngle+d.endAngle)/2 < Math.PI ){ return "beginning"; } else { return "end"; } }).text(function(d){ if (totalOctets <= 1) return ""; var percentage = (d.value/totalOctets)*100; return percentage.toFixed(1) + "%"; }); valueLabels.transition().duration(tweenDuration).attrTween("transform", textTween); valueLabels.exit().remove(); //DRAW LABELS WITH ENTITY NAMES nameLabels = label_group.selectAll("text.units").data(filteredPieData) .attr("dy", function(d){ if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) { return 17; } else { return 5; } }) .attr("text-anchor", function(d){ if ((d.startAngle+d.endAngle)/2 < Math.PI ) { return "beginning"; } else { return "end"; } }).text(function(d){ return d.name; }) .on("click", function(d) { if (d.url) window.location.href = d.url; }); nameLabels.enter().append("svg:text") .attr("class", "units") .attr("transform", function(d) { return "translate(" + Math.cos(((d.startAngle+d.endAngle - Math.PI)/2)) * (r+textOffset) + "," + Math.sin((d.startAngle+d.endAngle - Math.PI)/2) * (r+textOffset) + ")"; }) .attr("dy", function(d){ if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) { return 17; } else { return 5; } }) .attr("text-anchor", function(d){ if ((d.startAngle+d.endAngle)/2 < Math.PI ) { return "beginning"; } else { return "end"; } }).text(function(d){ return d.name; }) .on("click", function(d) { if (d.url) window.location.href = d.url; }); nameLabels.transition().duration(tweenDuration).attrTween("transform", textTween); nameLabels.exit().remove(); } } /////////////////////////////////////////////////////////// // FUNCTIONS ////////////////////////////////////////////// /////////////////////////////////////////////////////////// // Interpolate the arcs in data space. function pieTween(d, i) { var s0; var e0; if(oldPieData[i]){ s0 = oldPieData[i].startAngle; e0 = oldPieData[i].endAngle; } else if (!(oldPieData[i]) && oldPieData[i-1]) { s0 = oldPieData[i-1].endAngle; e0 = oldPieData[i-1].endAngle; } else if(!(oldPieData[i-1]) && oldPieData.length > 0){ s0 = oldPieData[oldPieData.length-1].endAngle; e0 = oldPieData[oldPieData.length-1].endAngle; } else { s0 = 0; e0 = 0; } var i = d3.interpolate({startAngle: s0, endAngle: e0}, {startAngle: d.startAngle, endAngle: d.endAngle}); return function(t) { var b = i(t); return arc(b); }; } function removePieTween(d, i) { s0 = 2 * Math.PI; e0 = 2 * Math.PI; var i = d3.interpolate({startAngle: d.startAngle, endAngle: d.endAngle}, {startAngle: s0, endAngle: e0}); return function(t) { var b = i(t); return arc(b); }; } function textTween(d, i) { var a; if(oldPieData[i]){ a = (oldPieData[i].startAngle + oldPieData[i].endAngle - Math.PI)/2; } else if (!(oldPieData[i]) && oldPieData[i-1]) { a = (oldPieData[i-1].startAngle + oldPieData[i-1].endAngle - Math.PI)/2; } else if(!(oldPieData[i-1]) && oldPieData.length > 0) { a = (oldPieData[oldPieData.length-1].startAngle + oldPieData[oldPieData.length-1].endAngle - Math.PI)/2; } else { a = 0; } var b = (d.startAngle + d.endAngle - Math.PI)/2; var fn = d3.interpolateNumber(a, b); return function(t) { var val = fn(t); return "translate(" + Math.cos(val) * (r+textOffset) + "," + Math.sin(val) * (r+textOffset) + ")"; }; } } /////////////////////////////////////////////////////////// // PUBLIC FUNCIONTS //////////////////////////////////// /////////////////////////////////////////////////////////// PieChart.prototype.setUrlParams = function(url_params) { this.url_params = url_params; this.forceUpdate(); } PieChart.prototype.forceUpdate = function(url_params) { this.stopInterval(); this.update(); this.startInterval(); } PieChart.prototype.setInterval = function(p_pieInterval) { this.pieInterval = p_pieInterval; } PieChart.prototype.stopInterval = function() { //disabled graph interval clearInterval(this.pieInterval); } PieChart.prototype.startInterval = function() { this.pieInterval = setInterval(this.update(), this.refresh) } /////////////////////////////////////////////////////////// // INIT FUNCIONTS //////////////////////////////////// /////////////////////////////////////////////////////////// function create_pie_chart(name, units) { var w = 500; //380 - Please keep in sync with pie-chart.css var h = 325; //280 var ir = 52; //45 var textOffset = 14; var tweenDuration = 250; var r = 116; //100; if($(name).hasClass("pie-chart-small")) { w = 330; h = 250; r = w / 5 + 15; ir = r / 2; } var lines, valueLabels, nameLabels; //D3 helper function to populate pie slice parameters from array data var donut = d3.layout.pie().value(function(d){ if (d.value == 0) {d.value = 1;} // Force to 1, in order to update the graph return d.value; }); //D3 helper function to create colors from an ordinal scale var color = d3.scale.category20(); //D3 helper function to draw arcs, populates parameter "d" in path object var arc = d3.svg.arc() .startAngle(function(d){ return d.startAngle; }) .endAngle(function(d){ return d.endAngle; }) .innerRadius(ir) .outerRadius(r); /////////////////////////////////////////////////////////// // CREATE VIS & GROUPS //////////////////////////////////// /////////////////////////////////////////////////////////// var vis = d3.select(name).append("svg:svg") .attr("width", w) .attr("height", h) .attr("viewBox","0 0 " + w + " " + h) .attr("preserveAspectRatio","xMidYMid"); //GROUP FOR ARCS/PATHS var arc_group = vis.append("svg:g") .attr("class", "arc") .attr("transform", "translate(" + (w/2) + "," + (h/2) + ")"); //GROUP FOR LABELS var label_group = vis.append("svg:g") .attr("class", "label_group") .attr("transform", "translate(" + (w/2) + "," + (h/2) + ")"); //GROUP FOR CENTER TEXT var center_group = vis.append("svg:g") .attr("class", "center_group") .attr("transform", "translate(" + (w/2) + "," + (h/2) + ")"); //PLACEHOLDER GRAY CIRCLE var paths = arc_group.append("svg:circle") .attr("fill", "#EFEFEF") .attr("r", r); /////////////////////////////////////////////////////////// // CENTER TEXT //////////////////////////////////////////// /////////////////////////////////////////////////////////// //WHITE CIRCLE BEHIND LABELS var whiteCircle = center_group.append("svg:circle") .attr("fill", "white") .attr("r", ir); var totalUnits = null; var totalLabel = null; var totalValue = null; if(units) { // "TOTAL" LABEL totalLabel = center_group.append("svg:text") .attr("class", "label") .attr("dy", -15) .attr("text-anchor", "middle") // text-align: right .text("TOTAL"); //TOTAL TRAFFIC VALUE totalValue = center_group.append("svg:text") .attr("class", "total") .attr("dy", 7) .attr("text-anchor", "middle") // text-align: right .text("Waiting..."); //UNITS LABEL totalUnits = center_group.append("svg:text") .attr("class", "units") .attr("dy", 21) .attr("text-anchor", "middle") // text-align: right .text(units); } return([arc_group, donut, totalValue, totalUnits, color, tweenDuration, arc, label_group, center_group, r, textOffset]); }