lib/public/js/dash.js in batsd-dash-0.2.1 vs lib/public/js/dash.js in batsd-dash-0.3.0

- old
+ new

@@ -1,84 +1,105 @@ // Location Hash wrapper script -var LocationHash=function(a){function c(){var a=location.hash.substr(1).split("&");b={};for(var c=0,d;d=a[c];c++){var e=d.split("="),f=e[1].split(",");b[e[0]]=f.length>1?f:f[0]}}function d(){var a=[];for(var c in b){var d=b[c];a.push(c+"="+(d.join?d.join(","):d))}location.hash=a.join("&")}var b;return a(window).on("hashchange",c).trigger("hashchange"),{params:function(){return a.param(b)},get:function(a){return b[a]},set:function(a){for(var c in a){var e=a[c];e==undefined?delete b[c]:b[c]=e}d()}}}(jQuery); +// https://gist.github.com/2927857 +var LocationHash=function(e){function r(){var e=location.hash.substr(1).split("&");t={};for(var r=0,i;i=e[r];r++){var s=i.split("=");if(s.length){var o=s[1].split(",");t[s[0]]=o.length>1?o:o[0]}}for(var r=0,u;u=n[r];r++)u()}function i(e){var n=[];for(var r in t){var i=t[r],s="=";if(e=="h")n.push(r+s+(i.join?i.join(","):i));else{i.join?s="[]=":i=[i];for(var o=0,u;u=i[o];o++)n.push(r+s+u)}}return n.join("&")}var t,n=[];return e(window).on("hashchange",r),r(),{params:function(e){return i(e)},changed:function(e){n.push(e)},get:function(e){return t[e]},set:function(e){for(var n in e){var r=e[n];r==undefined?delete t[n]:t[n]=r}location.hash=i("h")}}}(d3.select); -// set Accept header to JSON -$.ajaxSetup({ beforeSend: function(req){ req.setRequestHeader('Accept', 'application/json'); } }); +// TODO find a d3 datetimepicker (or make one) +// then drop jquery, jqueryui and datetimerpicker altogether +(function(){ + $('button').button(); -// Date.now polyfill (if needed) -if (!Date.now) Date.now = function(){ return +new Date; }; + var now = Date.now(); + var defaults = [now - (1000 * 60 * 30), now]; -$(function(){ - var main = $('#main-graph'); - var graph_opts = { - xaxis: { - mode: 'time', timeformat: '%h:%M:%S', - minTickSize: [10, 'second'] - }, + $('.date-time').datetimepicker().each(function(i){ + var input = $(this); + var time = LocationHash.get(input.attr('name')); - yaxis: { min: 0, minTickSize: 1 }, - lines: { show: true }, points: { show: false }, + input.datetimepicker('setDate', new Date(time ? time * 1000 : defaults[i])); + }); +}()); - grid: { borderColor:'#FFF', color:'#FFF' }, - legend: { backgroundColor:'#000' } + +// graphs using nv.d3 +(function(){ + var loading = d3.select('#loading'); + var main_el = d3.select('#main-graph'); + + if (main_el.empty()) + return; + + var validate = /counters|timers|gauges/; + var inputs = d3.selectAll('.date-time')[0]; + + var graph = main_el.select('svg'); + var view = d3.select('button'); + + loading.toggle = function(){ + this.style('display', this.style('display') == 'block' ? 'none' : 'block'); }; - function timestamp(str){ - return Math.round(+new Date(str) / 1000); - } + function set_time_params(){ + var map = {}; - function parse_error(xhr){ - var data; + for (var i = 0, elem; elem = inputs[i]; i++) + map[elem.name] = +new Date(elem.value) / 1000; - try { - data = xhr.status == 500 ? { error: 'zomg server fail :(' } : $.parseJSON(xhr.responseText); - } catch(e) { - data = { error: 'unknown error' }; - } finally { - return data; - } + LocationHash.set(map); } - function update_graph(graph){ - var req = { dataType: 'json', data: LocationHash.params() }; - var path = location.pathname; + function time_axis_formatter(resp){ + var format = { 600: '%x', 60: '%X', 10: '%X' }[resp.interval]; - graph.html('<h2>Loading...</h2>'); - $.ajax(path, req).done(function(data){ - $.plot(graph, data.metrics, graph_opts); + return function(d){ + return d3.time.format(format)(new Date(d)); + }; + } - }).fail(function(xhr){ - var data = parse_error(xhr); + function render_graph(){ + var xhr, params = LocationHash.params(); - graph.html('<h2>Error: '+ data.error +'</h2>'); - }); - } - + if (!validate.test(params) && location.pathname != '/') + return alert('Need to supply at least one counter, timer or gauge'); - // initialize the graph itself - $('.graph').each(function(){ update_graph($(this)); }); + main_el.select('em').remove(); + loading.toggle(); - // initialize date time picker - var inputs = $('input.date-time').datetimepicker(); + d3.json('/data?'+ params, function(resp){ + loading.toggle(); - var start = LocationHash.get('start'); - var stop = LocationHash.get('stop'); + if (!resp) + return main_el.append('em').text('An Error Occurred!'); - inputs.first().datetimepicker('setDate', start ? new Date(start * 1000) : new Date(Date.now() - (1000*60*60*2))); - inputs.last().datetimepicker('setDate', stop ? new Date(stop * 1000) : new Date()); + nv.addGraph(function(){ + // initialize a new chart object + var chart = nv.models.lineChart() + .x(function(d){ return d[0]; }) + .y(function(d){ return d[1]; }) - // style View button and bind handler - $('button').button().on('click', function(){ - // set location hash with new values - LocationHash.set({ - start: timestamp(inputs.first().val()), - stop: timestamp(inputs.last().val()), + // set xAxis tick format based up range and interval + chart.xAxis.tickFormat(time_axis_formatter(resp)) + + // force 0 into yAxis domain + chart.forceY([0]); + + // bind data and render graph + graph.datum(resp.results) + .transition().duration(500) + .call(chart); + + return chart; + }); }); + } - update_graph(main); + // view button handler + view.on('click', function(){ + set_time_params(); + render_graph(); }); - $(window).on('hashchange', function(){ - update_graph(main); - }); -}); + // listen for changes to URL + LocationHash.changed(render_graph); + // initial graph render + render_graph(); +}());