Enhance pie chart capabilities
Add support for distribution pie charts Change-Id: I59e31be87b59c38a59ad861e270d6e20a6493432 Implements: blueprint piechart-enhancement
This commit is contained in:
parent
54e4dab456
commit
1317e4273e
|
@ -42,7 +42,7 @@
|
|||
Json with variety of settings described below.
|
||||
|
||||
used-label-placement='string' OPTIONAL
|
||||
String determinign where the floating label stating number of percent
|
||||
String determining where the floating label stating number of percent
|
||||
will be placed. So far only left is supported.
|
||||
|
||||
width="integer" OPTIONAL
|
||||
|
|
|
@ -1,31 +1,64 @@
|
|||
/*
|
||||
Draw pie chart in d3.
|
||||
Draw pie charts in d3.
|
||||
|
||||
To use, a div is required with the class .d3_pie_chart
|
||||
and a data-used attribute in the div
|
||||
that stores the percentage to fill the chart
|
||||
To use, a div is required with the class .d3_pie_chart_usage or
|
||||
.d3_pie_chart_distribution, and a data-used attribute in the div
|
||||
that stores the data used to fill the chart.
|
||||
|
||||
Example:
|
||||
<div class="d3_pie_chart"
|
||||
Example (usage):
|
||||
<div class="d3_pie_chart_usage"
|
||||
data-used="{% widthratio current_val max_val 100 %}">
|
||||
</div>
|
||||
|
||||
Example (distribution):
|
||||
<div class="d3_pie_chart_distribution"
|
||||
data-used="Controller=1|Compute=2|Object Storage=3|Block Storage=4">
|
||||
</div>
|
||||
*/
|
||||
|
||||
horizon.d3_pie_chart = {
|
||||
w: 100,
|
||||
h: 100,
|
||||
r: 45,
|
||||
bkgrnd: "#F2F2F2",
|
||||
frgrnd: "#006CCF",
|
||||
full: "#D0342B",
|
||||
nearlyfull: "orange",
|
||||
// Pie chart dimensions
|
||||
var WIDTH = 100;
|
||||
var HEIGHT = 100;
|
||||
var RADIUS = 45;
|
||||
|
||||
// Colors
|
||||
var BKGRND = "#F2F2F2";
|
||||
var FRGRND = "#006CCF";
|
||||
var FULL = "#D0342B";
|
||||
var NEARLY_FULL = "#FFA500";
|
||||
var STROKE = "#CCCCCC";
|
||||
|
||||
|
||||
function create_vis(chart) {
|
||||
return d3.select(chart).append("svg:svg")
|
||||
.attr("class", "chart")
|
||||
.attr("width", WIDTH)
|
||||
.attr("height", HEIGHT)
|
||||
.append("g")
|
||||
.attr("transform",
|
||||
"translate(" + (RADIUS + 2) + "," + (RADIUS + 2) + ")");
|
||||
}
|
||||
|
||||
function create_arc() {
|
||||
return d3.svg.arc()
|
||||
.outerRadius(RADIUS)
|
||||
.innerRadius(0);
|
||||
}
|
||||
|
||||
function create_pie(param) {
|
||||
return d3.layout.pie()
|
||||
.sort(null)
|
||||
.value(function(d){ return d[param]; });
|
||||
}
|
||||
|
||||
|
||||
horizon.d3_pie_chart_usage = {
|
||||
init: function() {
|
||||
var self = this;
|
||||
|
||||
// Pie Charts
|
||||
var pie_chart_data = $(".d3_pie_chart");
|
||||
self.chart = d3.selectAll(".d3_pie_chart");
|
||||
var pie_chart_data = $(".d3_pie_chart_usage");
|
||||
self.chart = d3.selectAll(".d3_pie_chart_usage");
|
||||
|
||||
for (var i = 0; i < pie_chart_data.length; i++) {
|
||||
var used = Math.min(parseInt($(pie_chart_data[i]).data("used")), 100);
|
||||
|
@ -36,79 +69,179 @@ horizon.d3_pie_chart = {
|
|||
// Draw a pie chart
|
||||
pieChart: function(i) {
|
||||
var self = this;
|
||||
var vis = d3.select(self.chart[0][i]).append("svg:svg")
|
||||
.attr("class", "chart")
|
||||
.attr("width", self.w)
|
||||
.attr("height", self.h)
|
||||
.append("g")
|
||||
.attr("transform",
|
||||
"translate(" + (self.r + 2) + "," + (self.r + 2) + ")");
|
||||
|
||||
var arc = d3.svg.arc()
|
||||
.outerRadius(self.r)
|
||||
.innerRadius(0);
|
||||
|
||||
var pie = d3.layout.pie()
|
||||
.sort(null)
|
||||
.value(function(d){ return d.percentage; });
|
||||
var vis = create_vis(self.chart[0][i]);
|
||||
var arc = create_arc();
|
||||
var pie = create_pie("percentage");
|
||||
|
||||
// Draw an empty pie chart
|
||||
var piechart = vis.selectAll(".arc")
|
||||
vis.selectAll(".arc")
|
||||
.data(pie([{"percentage":10}]))
|
||||
.enter()
|
||||
.append("path")
|
||||
.attr("class","arc")
|
||||
.attr("d", arc)
|
||||
.style("fill", function(d){
|
||||
if (self.data[0].percentage >= 100) {
|
||||
return self.full;
|
||||
} else if (self.data[0].percentage >= 80) {
|
||||
return self.nearlyfull;
|
||||
} else {
|
||||
return self.frgrnd;
|
||||
}
|
||||
})
|
||||
.style("stroke", "#CCCCCC")
|
||||
.style("stroke-width", 1)
|
||||
.each(function(d) {
|
||||
self.current = d;
|
||||
return d;
|
||||
});
|
||||
.append("path")
|
||||
.attr("class","arc")
|
||||
.attr("d", arc)
|
||||
.style("fill", function(){
|
||||
if (self.data[0].percentage >= 100) {
|
||||
return FULL;
|
||||
} else if (self.data[0].percentage >= 80) {
|
||||
return NEARLY_FULL;
|
||||
} else {
|
||||
return FRGRND;
|
||||
}
|
||||
})
|
||||
.style("stroke", STROKE)
|
||||
.style("stroke-width", 1)
|
||||
.each(function(d) {
|
||||
self.current = d;
|
||||
return d;
|
||||
});
|
||||
|
||||
// Animate filling the pie chart
|
||||
animate = function(data) {
|
||||
var piechart = vis.selectAll(".arc")
|
||||
var animate = function(data) {
|
||||
vis.selectAll(".arc")
|
||||
.data(pie(data))
|
||||
.enter()
|
||||
.append("path")
|
||||
.attr("class","arc")
|
||||
.attr("d", arc)
|
||||
.style("fill", self.bkgrnd)
|
||||
.style("stroke", "#CCCCCC")
|
||||
.style("stroke-width", function(d) {
|
||||
if (self.data[0].percentage >= 100) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
})
|
||||
.each(function(d) {
|
||||
self.current = d;
|
||||
return d;
|
||||
})
|
||||
.append("path")
|
||||
.attr("class","arc")
|
||||
.attr("d", arc)
|
||||
.style("fill", BKGRND)
|
||||
.style("stroke", STROKE)
|
||||
.style("stroke-width", function() {
|
||||
if (self.data[0].percentage >= 100) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
})
|
||||
.each(function(d) {
|
||||
self.current = d;
|
||||
return d;
|
||||
})
|
||||
.transition()
|
||||
.duration(500)
|
||||
.attrTween("d", function(a) {
|
||||
var tween = d3.interpolate(self.current, a);
|
||||
self.current = tween(0);
|
||||
return function(t) { return arc(tween(t)); };
|
||||
});
|
||||
.duration(500)
|
||||
.attrTween("d", function(a) {
|
||||
var tween = d3.interpolate(self.current, a);
|
||||
self.current = tween(0);
|
||||
return function(t) { return arc(tween(t)); };
|
||||
});
|
||||
};
|
||||
|
||||
animate(self.data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
horizon.d3_pie_chart_distribution = {
|
||||
colors: d3.scale.category20(),
|
||||
|
||||
init: function() {
|
||||
var self = this;
|
||||
var pie_chart_data = $(".d3_pie_chart_distribution");
|
||||
self.chart = d3.selectAll(".d3_pie_chart_distribution");
|
||||
|
||||
for (var i = 0; i < pie_chart_data.length; i++) {
|
||||
var parts = $(pie_chart_data[i]).data("used").split("|");
|
||||
self.data = [];
|
||||
self.keys = [];
|
||||
for (var j = 0; j < parts.length; j++) {
|
||||
var key_value = parts[j].split("=");
|
||||
var d = {};
|
||||
d["key"] = key_value[0];
|
||||
d["value"] = key_value[1];
|
||||
self.data.push(d);
|
||||
self.keys.push(key_value[0]);
|
||||
}
|
||||
self.pieChart(i);
|
||||
}
|
||||
},
|
||||
// Draw a pie chart
|
||||
pieChart: function(i) {
|
||||
var self = this;
|
||||
var vis = create_vis(self.chart[0][i]);
|
||||
var arc = create_arc();
|
||||
var pie = create_pie("value");
|
||||
|
||||
var total = 0;
|
||||
for (var j = 0; j < self.data.length; j++) {
|
||||
total = total + parseInt(self.data[j]["value"]);
|
||||
}
|
||||
|
||||
// Draw an empty pie chart
|
||||
vis.selectAll(".arc")
|
||||
.data(pie([]))
|
||||
.enter()
|
||||
.append("path")
|
||||
.attr("class","arc")
|
||||
.attr("d", arc)
|
||||
.style("stroke", STROKE)
|
||||
.style("stroke-width", 1);
|
||||
|
||||
// Animate filling the pie chart
|
||||
var animate = function(data) {
|
||||
vis.selectAll(".arc")
|
||||
.data(pie(data))
|
||||
.enter()
|
||||
.append("path")
|
||||
.attr("class","arc")
|
||||
.attr("d", arc)
|
||||
.style("fill", function(d) { return self.colors(d.data.key); })
|
||||
.style("stroke", STROKE)
|
||||
.style("stroke-width", 1)
|
||||
.transition()
|
||||
.duration(500)
|
||||
.attrTween("d", function(start) {
|
||||
start.endAngle = start.startAngle;
|
||||
var end = jQuery.extend({}, start);
|
||||
end.endAngle = end.startAngle + 2 * Math.PI / total * end.value;
|
||||
var tween = d3.interpolate(start, end);
|
||||
return function(t) { return arc(tween(t)); };
|
||||
});
|
||||
};
|
||||
|
||||
animate(self.data);
|
||||
|
||||
// Add a legend
|
||||
var legend = d3.select(self.chart[0][i])
|
||||
.append("svg")
|
||||
.attr("class", "legend")
|
||||
.attr("width", WIDTH * 2)
|
||||
.attr("height", self.data.length * 18 + 20)
|
||||
.selectAll("g")
|
||||
.data(self.keys)
|
||||
.enter()
|
||||
.append("g")
|
||||
.attr("transform", function(d, i) {
|
||||
return "translate(0," + i * 20 + ")";
|
||||
});
|
||||
|
||||
legend.append("rect")
|
||||
.attr("width", 18)
|
||||
.attr("height", 18)
|
||||
.style("fill", self.colors);
|
||||
|
||||
legend.append("text")
|
||||
.attr("x", 24)
|
||||
.attr("y", 9)
|
||||
.attr("dy", ".35em")
|
||||
.text(function(d) {
|
||||
var value = 0;
|
||||
for (var j = 0; j < self.data.length; j++) {
|
||||
if (self.data[j]["key"] == d) {
|
||||
value = self.data[j]["value"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return d + " " + Math.round(value/total * 100) + "%";
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
horizon.addInitFunction(function () {
|
||||
horizon.d3_pie_chart.init();
|
||||
horizon.d3_pie_chart_usage.init();
|
||||
});
|
||||
|
||||
|
||||
horizon.addInitFunction(function () {
|
||||
horizon.d3_pie_chart_distribution.init();
|
||||
});
|
||||
|
|
|
@ -3,49 +3,49 @@
|
|||
<div class="quota-dynamic">
|
||||
<h3 class="quota-heading">{% trans "Limit Summary" %}</h3>
|
||||
<div class="d3_quota_bar">
|
||||
<div class="d3_pie_chart" data-used="{% widthratio usage.limits.totalInstancesUsed usage.limits.maxTotalInstances 100 %}"></div>
|
||||
<div class="d3_pie_chart_usage" data-used="{% widthratio usage.limits.totalInstancesUsed usage.limits.maxTotalInstances 100 %}"></div>
|
||||
<strong>{% trans "Instances" %} <br />
|
||||
{% blocktrans with used=usage.limits.totalInstancesUsed|intcomma available=usage.limits.maxTotalInstances|quotainf|intcomma %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<div class="d3_quota_bar">
|
||||
<div class="d3_pie_chart" data-used="{% widthratio usage.limits.totalCoresUsed usage.limits.maxTotalCores 100 %}"></div>
|
||||
<div class="d3_pie_chart_usage" data-used="{% widthratio usage.limits.totalCoresUsed usage.limits.maxTotalCores 100 %}"></div>
|
||||
<strong>{% trans "VCPUs" %} <br />
|
||||
{% blocktrans with used=usage.limits.totalCoresUsed|intcomma available=usage.limits.maxTotalCores|quotainf|intcomma %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<div class="d3_quota_bar">
|
||||
<div class="d3_pie_chart" data-used="{% widthratio usage.limits.totalRAMUsed usage.limits.maxTotalRAMSize 100 %}"></div>
|
||||
<div class="d3_pie_chart_usage" data-used="{% widthratio usage.limits.totalRAMUsed usage.limits.maxTotalRAMSize 100 %}"></div>
|
||||
<strong>{% trans "RAM" %} <br />
|
||||
{% blocktrans with used=usage.limits.totalRAMUsed|mb_float_format available=usage.limits.maxTotalRAMSize|quotainf|mb_float_format %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<div class="d3_quota_bar">
|
||||
<div class="d3_pie_chart" data-used="{% widthratio usage.limits.totalFloatingIpsUsed usage.limits.maxTotalFloatingIps 100 %}"></div>
|
||||
<div class="d3_pie_chart_usage" data-used="{% widthratio usage.limits.totalFloatingIpsUsed usage.limits.maxTotalFloatingIps 100 %}"></div>
|
||||
<strong>{% trans "Floating IPs" %} <br />
|
||||
{% blocktrans with used=usage.limits.totalFloatingIpsUsed|intcomma available=usage.limits.maxTotalFloatingIps|quotainf|intcomma %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<div class="d3_quota_bar">
|
||||
<div class="d3_pie_chart" data-used="{% widthratio usage.limits.totalSecurityGroupsUsed usage.limits.maxSecurityGroups 100 %}"></div>
|
||||
<div class="d3_pie_chart_usage" data-used="{% widthratio usage.limits.totalSecurityGroupsUsed usage.limits.maxSecurityGroups 100 %}"></div>
|
||||
<strong>{% trans "Security Groups" %} <br />
|
||||
{% blocktrans with used=usage.limits.totalSecurityGroupsUsed|intcomma available=usage.limits.maxSecurityGroups|quotainf|intcomma%}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
|
||||
</strong>
|
||||
</div>
|
||||
{% if usage.limits.totalVolumesUsed >= 0 %}
|
||||
<div class="d3_quota_bar">
|
||||
<div class="d3_pie_chart" data-used="{% widthratio usage.limits.totalVolumesUsed usage.limits.maxTotalVolumes 100 %}"></div>
|
||||
<div class="d3_pie_chart_usage" data-used="{% widthratio usage.limits.totalVolumesUsed usage.limits.maxTotalVolumes 100 %}"></div>
|
||||
<strong>{% trans "Volumes" %} <br />
|
||||
{% blocktrans with used=usage.limits.totalVolumesUsed|intcomma available=usage.limits.maxTotalVolumes|quotainf|intcomma %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<div class="d3_quota_bar">
|
||||
<div class="d3_pie_chart" data-used="{% widthratio usage.limits.totalGigabytesUsed usage.limits.maxTotalVolumeGigabytes 100 %}"></div>
|
||||
<div class="d3_pie_chart_usage" data-used="{% widthratio usage.limits.totalGigabytesUsed usage.limits.maxTotalVolumeGigabytes 100 %}"></div>
|
||||
<strong>{% trans "Volume Storage" %} <br />
|
||||
{% blocktrans with used=usage.limits.totalGigabytesUsed|diskgbformat available=usage.limits.maxTotalVolumeGigabytes|quotainf|diskgbformat %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
|
||||
</strong>
|
||||
|
|
|
@ -11,21 +11,21 @@
|
|||
<div class="quota-dynamic">
|
||||
<h3>{% trans "Hypervisor Summary" %}</h3>
|
||||
<div class="d3_quota_bar">
|
||||
<div class="d3_pie_chart" data-used="{% widthratio stats.vcpus_used stats.vcpus 100 %}"></div>
|
||||
<div class="d3_pie_chart_usage" data-used="{% widthratio stats.vcpus_used stats.vcpus 100 %}"></div>
|
||||
<strong>{% trans "VCPU Usage" %} <br />
|
||||
{% blocktrans with used=stats.vcpus_used|intcomma available=stats.vcpus|intcomma %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<div class="d3_quota_bar">
|
||||
<div class="d3_pie_chart" data-used="{% widthratio stats.memory_mb_used stats.memory_mb 100 %}"></div>
|
||||
<div class="d3_pie_chart_usage" data-used="{% widthratio stats.memory_mb_used stats.memory_mb 100 %}"></div>
|
||||
<strong>{% trans "Memory Usage" %} <br />
|
||||
{% blocktrans with used=stats.memory_mb_used|mbformat available=stats.memory_mb|mbformat %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<div class="d3_quota_bar">
|
||||
<div class="d3_pie_chart" data-used="{% widthratio stats.local_gb_used stats.local_gb 100 %}"></div>
|
||||
<div class="d3_pie_chart_usage" data-used="{% widthratio stats.local_gb_used stats.local_gb 100 %}"></div>
|
||||
<strong>{% trans "Disk Usage" %} <br />
|
||||
{% blocktrans with used=stats.local_gb_used|diskgbformat available=stats.local_gb|diskgbformat %}Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
|
||||
</strong>
|
||||
|
|
Loading…
Reference in New Issue