diff options
Diffstat (limited to 'openstack_dashboard/dashboards/infrastructure/static/infrastructure/js/horizon.d3circleschart.js')
-rw-r--r-- | openstack_dashboard/dashboards/infrastructure/static/infrastructure/js/horizon.d3circleschart.js | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/openstack_dashboard/dashboards/infrastructure/static/infrastructure/js/horizon.d3circleschart.js b/openstack_dashboard/dashboards/infrastructure/static/infrastructure/js/horizon.d3circleschart.js new file mode 100644 index 00000000..305b2182 --- /dev/null +++ b/openstack_dashboard/dashboards/infrastructure/static/infrastructure/js/horizon.d3circleschart.js @@ -0,0 +1,279 @@ +/* + Draw circles chart in d3. + + To use, a div is required with the data attributes + data-chart-type="circles_chart", data-url and data-size in the + div. + + data-chart-type - must be "circles_chart" so chart gets initialized + data-url - (string) url for the json data for the chart + data-time - (string) time parameter, gets appended to url as time=... + data-size - (integer) size of the circles in pixels + + If used in popup, initialization must be made manually e.g.: + addHorizonLoadEvent(function() { + horizon.d3_circles_chart.init('.html_element'); + horizon.d3_circles_chart.init('.health_chart'); + }); + + + Example: + <div class="html_element" + data-chart-type="circles_chart" + data-url="/infrastructure/racks/1/top_communicating.json?cond=to" + data-time="now" + data-size="22"> + </div> + + There are controll elements for the cirles chart, implementing some commands + that will be executed over the chart. + + 1. The selectbox for time change, implements ChangeTime command. It has to + have data attribute data-circles-chart-command="change_time", with defined + receiver as jquery selector (selector can point to more elements and it will + execute the command on all of them) e.g. data-receiver="#rack_health_chart" + Option value is then appended to url and chart is refreshed. + + Example + <div class="span3 circles_chart_time_picker"> + <select data-circles-chart-command="change_time" + data-receiver="#rack_health_chart"> + <option value="now">Now</option> + <option value="yesterday">Yesterday</option> + <option value="last_week">Last Week</option> + <option value="last_month">Last Month</option> + </select> + </div> + <div class="clear"></div> + + 2. Bootstrap tabs for switching different circle_charts implement command + ChangeUrl. It has to have data attribute data-circles-chart-command="change_url", + with defined receiver as jquery selector (selector can point to more elements and + it will execute the command on all of them) e.g. data-receiver="#rack_health_chart" + + Inner li a element has to have attribute data-url, e.g. + data-url="/infrastructure/racks/1/top_communicating.json?type=alerts" + + The url of the chart is then switched and chart is refreshed. + + <ul class="nav nav-tabs" + data-circles-chart-command="change_url" + data-receiver="#rack_health_chart"> + <li class="active"> + <a data-url="/infrastructure/racks/1/top_communicating.json?type=overall_health" href="#"> + Overall Health</a> + </li> + <li> + <a data-url="/infrastructure/racks/1/top_communicating.json?type=alerts" href="#"> + Alerts</a> + </li> + <li> + <a data-url="/infrastructure/racks/1/top_communicating.json?type=capacities" href="#"> + Capacities</a> + </li> + <li> + <a data-url="/infrastructure/racks/1/top_communicating.json?type=status" href="#"> + Status</a> + </li> + </ul> +*/ + + +horizon.d3_circles_chart = { + CirclesChart: function(chart_class, html_element){ + this.chart_class = chart_class; + this.html_element = html_element; + + var jquery_element = $(html_element); + this.size = jquery_element.data('size'); + this.time = jquery_element.data('time'); + this.url = jquery_element.data('url'); + + this.final_url = this.url; + if (this.final_url.indexOf('?') > -1){ + this.final_url += '&time=' + this.time; + }else{ + this.final_url += '?time=' + this.time; + } + + this.time = jquery_element.data('time'); + this.data = [] + + this.refresh = refresh; + function refresh(){ + var self = this; + this.jqxhr = $.getJSON( this.final_url, function() { + //FIXME add loader in the target element + }) + .done(function(data) { + // FIXME find a way how to only update graph with new data + // not delete and create + $(self.html_element).html(""); + + self.data = data.data; + self.settings = data.settings; + self.chart_class.render(self.html_element, self.size, self.data, self.settings); + }) + .fail(function() { + // FIXME add proper fail message + console.log( "error" ); }) + .always(function() { + // FIXME add behaviour that should be always done + }); + } + }, + init: function(selector, settings) { + var self = this; + $(selector).each(function() { + self.refresh(this); + }); + self.bind_commands(); + }, + refresh: function(html_element){ + var chart = new this.CirclesChart(this, html_element) + // FIXME save chart objects somewhere so I can use them again when + // e.g. I am swithing tabs, or if I want to update them + // via web sockets + // this.charts.add_or_update(chart) + chart.refresh(); + }, + render: function(html_element, size, data, settings){ + var self = this; + // FIXME rewrite to scatter plot once we have some cool D3 chart + // library + var width = size + 4, + height = size + 4, + round = size / 2; + center_x = width / 2, + center_y = height / 2; + + var svg = d3.select(html_element).selectAll("svg") + .data(data) + .enter().append("svg") + .attr("width", width) + .attr("height", height); + + // FIXME use some pretty tooltip from some library we will use + // this one is just temporary + var tooltip = d3.select(html_element).append("div") + .style("position", "absolute") + .style("z-index", "10") + .style("visibility", "hidden") + .style("min-width", "100px") + .style("max-width", "110px") + .style("min-height", "30px") + .style("border", "1px ridge grey") + .style("background-color", "white") + .text(function(d) { "a simple tooltip"; }); + + var circle = svg.append("circle") + .attr("r", round)//function(d) { return d.r; })// can be sent form server + .attr("cx", center_x) + .attr("cy", center_y) + .attr("stroke", "#cecece") + .attr("stroke-width", function(d) { + return 1; + }) + .style("fill", function(d) { + if (d.color){ + return d.color; + } else if (settings.scale == "linear_color_scale"){ + return self.linear_color_scale(d.percentage, settings.domain, settings.range) + + } + }) + .on("mouseover", function(d){ + if (d.tooltip) { + tooltip.html(d.tooltip); + } else { + tooltip.html(d.name + "<br/>" + d.status); + } + tooltip.style("visibility", "visible");}) + .on("mousemove", function(d){tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px");}) + .on("mouseout", function(d){tooltip.style("visibility", "hidden");}); + ; + + /* + // or just d3 title element + circle.append("svg:title") + .text(function(d) { return d.x; }); + + */ + }, + linear_color_scale: function(percentage, domain, range){ + usage_color = d3.scale.linear() + .domain(domain) + .range(range); + return usage_color(percentage); + }, + bind_commands: function (){ + var change_time_command_selector = 'select[data-circles-chart-command="change_time"]'; + var change_url_command_selector = '[data-circles-chart-command="change_url"]'; + var self = this; + bind_change_time = function(){ + $(change_time_command_selector).each(function() { + $(this).change(function(){ + var invoker = $(this); + var command = new self.Command.ChangeTime(self, invoker); + command.execute(); + }); + }); + } + bind_change_url = function(){ + $(change_url_command_selector + ' a').click(function (e) { + // Bootstrap tabs functionality + e.preventDefault(); + $(this).tab('show'); + + // Command for url change and refresh + var invoker = $(this); + var command = new self.Command.ChangeUrl(self, invoker); + command.execute(); + }) + } + bind_change_time(); + bind_change_url(); + }, + Command: { + ChangeTime: function (chart_class, invoker){ + // Invoker of the command should know about it's receiver. + // Also invoker brings all parameters of the command. + this.receiver_selector = invoker.data('receiver'); + this.new_time = invoker.find("option:selected").val(); + + this.execute = execute; + function execute(){ + var self = this; + $(this.receiver_selector).each(function(){ + // change time of the chart + $(this).data('time', self.new_time); + // refresh the chart + chart_class.refresh(this) + }); + } + }, + ChangeUrl: function (chart_class, invoker, new_url){ + // Invoker of the command should know about it's receiver. + // Also invoker brings all parameters of the command. + this.receiver_selector = invoker.parents('ul').first().data('receiver'); + this.new_url = invoker.data('url'); + + this.execute = execute; + function execute(){ + var self = this; + $(this.receiver_selector).each(function(){ + // change time of the chart + $(this).data('url', self.new_url); + // refresh the chart + chart_class.refresh(this) + }); + } + } + } +} + +/* init the graphs */ +horizon.addInitFunction(function () { + horizon.d3_circles_chart.init('div[data-chart-type="circles_chart"]'); +}); + |