#167 JS development of hashchange-dependant tabbing mechanism, and of Rickshaw graphs with separate legends.
[ckanext-ga-report.git] / ckanext / ga_report / public / scripts / ckanext_ga_reports.js
blob:a/ckanext/ga_report/public/scripts/ckanext_ga_reports.js -> blob:b/ckanext/ga_report/public/scripts/ckanext_ga_reports.js
   
var CKAN = CKAN || {}; var CKAN = CKAN || {};
CKAN.GA_Reports = {}; CKAN.GA_Reports = {};
   
CKAN.GA_Reports.render_rickshaw = function( css_name, data, mode, colorscheme ) { CKAN.GA_Reports.render_rickshaw = function( css_name, data, mode, colorscheme ) {
var graphLegends = $('#graph-legend-container'); var graphLegends = $('#graph-legend-container');
   
  function renderError(alertClass,alertText,legendText) {
  $("#chart_"+css_name)
  .html( '<div class="alert '+alertClass+'">'+alertText+'</div>')
  .closest('.rickshaw_chart_container').css('height',50);
  var myLegend = $('<div id="legend_'+css_name+'"/>')
  .html(legendText)
  .appendTo(graphLegends);
  }
   
  if (!Modernizr.svg) {
  renderError('','Your browser does not support vector graphics. No graphs can be rendered.','(Graph cannot be rendered)');
  return;
  }
  if (data.length==0) {
  renderError('alert-info','There is not enough data to render a graph.','(No graph available)');
  return
  }
var myLegend = $('<div id="legend_'+css_name+'"/>').appendTo(graphLegends); var myLegend = $('<div id="legend_'+css_name+'"/>').appendTo(graphLegends);
   
var palette = new Rickshaw.Color.Palette( { scheme: colorscheme } ); var palette = new Rickshaw.Color.Palette( { scheme: colorscheme } );
$.each(data, function(i, object) { $.each(data, function(i, object) {
object['color'] = palette.color(); object['color'] = palette.color();
}); });
  // Rickshaw renders the legend in reverse order...
  data.reverse();
   
var graphElement = document.querySelector("#chart_"+css_name); var graphElement = document.querySelector("#chart_"+css_name);
   
var graph = new Rickshaw.Graph( { var graph = new Rickshaw.Graph( {
element: document.querySelector("#chart_"+css_name), element: document.querySelector("#chart_"+css_name),
renderer: mode, renderer: mode,
series: data , series: data ,
height: 328 height: 328
}); });
var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } ); var x_axis = new Rickshaw.Graph.Axis.Time( {
  graph: graph
  } );
var y_axis = new Rickshaw.Graph.Axis.Y( { var y_axis = new Rickshaw.Graph.Axis.Y( {
graph: graph, graph: graph,
orientation: 'left', orientation: 'left',
tickFormat: Rickshaw.Fixtures.Number.formatKMBT, tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
element: document.getElementById('y_axis_'+css_name), element: document.getElementById('y_axis_'+css_name)
} ); } );
var legend = new Rickshaw.Graph.Legend( { var legend = new Rickshaw.Graph.Legend( {
element: document.querySelector('#legend_'+css_name), element: document.querySelector('#legend_'+css_name),
graph: graph graph: graph
} ); } );
var hoverDetail = new Rickshaw.Graph.HoverDetail( { var shelving = new Rickshaw.Graph.Behavior.Series.Toggle( {
graph: graph, graph: graph,
formatter: function(series, x, y) { legend: legend
var date = '<span class="date">' + new Date(x * 1000).toUTCString() + '</span>';  
var swatch = '<span class="detail_swatch" style="background-color: ' + series.color + '"></span>';  
var content = swatch + series.name + ": " + parseInt(y) + '<br>' + date;  
return content;  
}  
} ); } );
  myLegend.prepend('<div class="instructions">Click on a series below to isolate its graph:</div>');
graph.render(); graph.render();
}; };
   
CKAN.GA_Reports.bind_sparklines = function() { CKAN.GA_Reports.bind_sparklines = function() {
/* /*
* Bind to the 'totals' tab being on screen, when the * Bind to the 'totals' tab being on screen, when the
* Sparkline graphs should be drawn. * Sparkline graphs should be drawn.
* Note that they cannot be drawn sooner. * Note that they cannot be drawn sooner.
*/ */
  var created = false;
$('a[href="#totals"]').on( $('a[href="#totals"]').on(
'shown', 'shown',
function() { function() {
var sparkOptions = { if (!created) {
enableTagOptions: true, var sparkOptions = {
type: 'line', enableTagOptions: true,
width: 100, type: 'line',
height: 26, width: 100,
chartRangeMin: 0, height: 26,
spotColor: '', chartRangeMin: 0,
maxSpotColor: '', spotColor: '',
minSpotColor: '', maxSpotColor: '',
highlightSpotColor: '000000', minSpotColor: '',
lineColor: '3F8E6D', highlightSpotColor: '#000000',
fillColor: 'B7E66B' lineColor: '#3F8E6D',
}; fillColor: '#B7E66B'
$('.sparkline').sparkline('html',sparkOptions); };
} $('.sparkline').sparkline('html',sparkOptions);
  created = true;
  }
  $.sparkline_display_visible();
  }
); );
}; };
   
CKAN.GA_Reports.bind_sidebar = function() { CKAN.GA_Reports.bind_sidebar = function() {
/* /*
* Bind to changes in the tab behaviour: * Bind to changes in the tab behaviour:
* Show the correct rickshaw graph in the sidebar. * Show the correct rickshaw graph in the sidebar.
* Not to be called before all graphs load. * Not to be called before all graphs load.
*/ */
$('a[data-toggle="hashchange"]').on( $('a[data-toggle="hashtab"]').on(
'shown', 'shown',
function(e) { function(e) {
var href = $(e.target).attr('href'); var href = $(e.target).attr('href');
var pane = $(href); var pane = $(href);
if (!pane.length) { console.err('bad href',href); return; } if (!pane.length) { console.err('bad href',href); return; }
var legend_name = "none"; var legend_name = "none";
var graph = pane.find('.rickshaw_chart'); var graph = pane.find('.rickshaw_chart');
if (graph.length) { if (graph.length) {
legend_name = graph.attr('id').replace('chart_',''); legend_name = graph.attr('id').replace('chart_','');
} }
legend_name = '#legend_'+legend_name; legend_name = '#legend_'+legend_name;
$('#graph-legend-container > *').hide(); $('#graph-legend-container > *').hide();
  $('#graph-legend-container .instructions').show();
$(legend_name).show(); $(legend_name).show();
} }
); );
  /* The first tab might already have been shown */
  $('li.active > a[data-toggle="hashtab"]').trigger('shown');
}; };
   
/* CKAN.GA_Reports.bind_month_selector = function() {
* Custom bootstrap plugin for handling data-toggle="hashchange". var handler = function(e) {
* Behaves like data-toggle="tab" but I respond to the hashchange. var target = $(e.delegateTarget);
* Page state is memo-ized in the URL this way. Why doesn't Bootstrap do this? var form = target.closest('form');
*/ var url = form.attr('action')+'?month='+target.val()+window.location.hash;
$(function() { window.location = url;
var mapping = {}; };
$('a[data-toggle="hashchange"]').each( var selectors = $('select[name="month"]');
function(i,link) { assert(selectors.length>0);
link = $(link); selectors.bind('change', handler);
mapping[link.attr('href')] = link; };
}  
);  
$(window).hashchange(function() {  
var link = mapping[window.location.hash];  
if (link) { link.tab('show'); }  
});  
});