Add interval selector to modal line charts

Change-Id: I6b22d120989bbb159bdfba3767dc7d88a1d491f8
This commit is contained in:
Imre Farkas 2013-07-03 13:50:36 +02:00 committed by Tomas Sedovic
parent c6329f592b
commit c550d330e1
4 changed files with 126 additions and 51 deletions

View File

@ -12,7 +12,6 @@ horizon.d3_modal_line_chart = {
init: function() {
var self = this;
// Load modals for modal chart links
$(document).on('click', '.modal_chart', function (evt) {
evt.preventDefault();
var $this = $(this);
@ -23,50 +22,65 @@ horizon.d3_modal_line_chart = {
var modal = $('.modal:last');
modal.modal();
$(modal).on('click', 'ul#interval_selector li a', function(event){
event.preventDefault();
interval = $(event.target).data("interval");
self.draw('/infrastructure/resource_management/racks/usage_data', {interval: interval});
$("ul#interval_selector li").removeClass("active");
$(event.target).parent().addClass("active");
})
self.init_svg();
self.draw('/infrastructure/resource_management/racks/usage_data')
});
},
draw: function(url) {
init_svg: function() {
var self = this;
var margin = {top: 20, right: 80, bottom: 30, left: 50};
var width = 700 - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;
self.margin = {top: 20, right: 80, bottom: 30, left: 50};
self.width = 700 - self.margin.left - self.margin.right;
self.height = 400 - self.margin.top - self.margin.bottom;
var svg = d3.select("#modal_chart")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
self.svg = d3.select("#modal_chart")
.append("svg")
.attr("width", self.width + self.margin.left + self.margin.right)
.attr("height", self.height + self.margin.top + self.margin.bottom)
.append("g")
.attr("transform", "translate(" + self.margin.left + "," + self.margin.top + ")");
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
self.x = d3.time.scale().range([0, self.width]);
self.y = d3.scale.linear().range([self.height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
self.xAxis = d3.svg.axis()
.scale(self.x)
.orient("bottom").ticks(6);
self.yAxis = d3.svg.axis()
.scale(self.y)
.orient("left");
var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%S.%L").parse;
self.parse_date = d3.time.format("%Y-%m-%dT%H:%M:%S.%L").parse;
var line = d3.svg.line().interpolate("linear")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.value); });
self.line = d3.svg.line().interpolate("linear")
.x(function(d) { return self.x(d.date); })
.y(function(d) { return self.y(d.value); });
var color = d3.scale.category10();
self.color = d3.scale.category10();
},
d3.json(url, function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
});
draw: function(url, url_options) {
var self = this;
var url_options = url_options || {};
url_options.interval = url_options.interval || "1w";
color.domain(d3.keys(data[0]).filter(function(key) { return key !== 'date'; }));
d3.json(self.data_url(url, url_options), function(error, data) {
data.forEach(function(d) { d.date = self.parse_date(d.date); });
var usage_values = color.domain().map(function(name) {
self.color.domain(d3.keys(data[0]).filter(function(key) { return key !== 'date'; }));
var usage_values = self.color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
@ -75,32 +89,42 @@ horizon.d3_modal_line_chart = {
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(usage_values, function(u) { return d3.min(u.values, function(v) { return v.value; }) - 1; }),
d3.max(usage_values, function(u) { return d3.max(u.values, function(v) { return v.value; }) + 6; })
]);
self.svg.selectAll(".axis").remove();
self.x.domain(d3.extent(data, function(d) { return d.date; }));
self.y.domain([0, 15]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.attr("class", "axis")
.call(xAxis);
svg.append("g")
.attr("class", "axis")
.call(yAxis)
self.svg.append("g")
.attr("transform", "translate(0," + self.height + ")")
.attr("class", "axis")
.call(self.xAxis);
self.svg.append("g")
.attr("class", "axis")
.call(self.yAxis)
var usage = svg.selectAll(".usage")
.data(usage_values)
.enter().append("g");
var usages = self.svg.selectAll(".usage")
.data(usage_values, function(d) { return self.key(d) });
var usage = usages.enter().append("g")
.attr("class", "usage");
usage.append("path")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); })
.style("fill", "none")
.style("stroke-width", 3);
.attr("d", function(d) { return self.line(d.values); })
.style("stroke", function(d) { return self.color(d.name); })
.style("fill", "none")
.style("stroke-width", 3);
usages.exit().remove();
});
},
data_url: function(url, options) {
return url + '?' + $.param(options);
},
key: function(data){
return data.name + data.values.length + data.values[0].date + data.values[data.values.length-1].date
},
};
horizon.addInitFunction(function () {

View File

@ -6,6 +6,13 @@
{% block template %}
{% jstemplate %}
<div class="modal" style="top: 80px; display: block;">
<ul id="interval_selector">
<li><a href="#" data-interval="12h">12h</a></li>
<li><a href="#" data-interval="24h">24h</a></li>
<li class="active"><a href="#" data-interval="1w">1w</a></li>
<li><a href="#" data-interval="1m">1m</a></li>
<li><a href="#" data-interval="1y">1y</a></li>
</ul>
<div id="modal_chart"></div>
</div>
{% endjstemplate %}

View File

@ -108,9 +108,29 @@ class DetailView(tabs.TabView):
class UsageDataView(View):
def get(self, request, *args, **kwargs):
interval = request.GET.get('interval', '1w')
if interval == '12h':
data_count = 12
timedelta_param = 'hours'
elif interval == '24h':
data_count = 24
timedelta_param = 'hours'
elif interval == '1m':
data_count = 30
timedelta_param = 'days'
elif interval == '1y':
data_count = 52
timedelta_param = 'weeks'
else:
# default is 1 week
data_count = 7
timedelta_param = 'days'
values = []
for i in range(10):
values.append({'date': datetime.now() + timedelta(days=i),
for i in range(data_count):
timediff = timedelta(**{timedelta_param: i})
values.append({'date': datetime.now() - timediff,
'ram': random.randint(1, 9)})
return HttpResponse(json.dumps(values, cls=DjangoJSONEncoder),

View File

@ -19,6 +19,30 @@ table.capacities{
}
#interval_selector {
position: absolute;
right: 15px;
top: 15px;
li {
display: inline;
list-style-type: none;
padding-right: 5px;
&.active {
font-weight: bold;
a {
color: black;
&:hover {
text-decoration:none;
}
}
}
}
}
svg {
.axis {
path, line {