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'); |
if (!Modernizr.svg) { | |
$("#chart_"+css_name) | |
.html( '<div class="alert">Your browser does not support vector graphics. No graphs can be rendered.</div>') | |
.closest('.rickshaw_chart_container').css('height',50); | |
var myLegend = $('<div id="legend_'+css_name+'"/>') | |
.html('(Graph cannot be rendered)') | |
.appendTo(graphLegends); | |
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(); |
}); | }); |
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; | |
} | |
} ); | } ); |
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. |
*/ | */ |
$('a[href="#totals"]').on( | $('a[href="#totals"]').on( |
'shown', | 'shown', |
function() { | function() { |
var sparkOptions = { | var sparkOptions = { |
enableTagOptions: true, | enableTagOptions: true, |
type: 'line', | type: 'line', |
width: 100, | width: 100, |
height: 26, | height: 26, |
chartRangeMin: 0, | chartRangeMin: 0, |
spotColor: '', | spotColor: '', |
maxSpotColor: '', | maxSpotColor: '', |
minSpotColor: '', | minSpotColor: '', |
highlightSpotColor: '000000', | highlightSpotColor: '000000', |
lineColor: '3F8E6D', | lineColor: '3F8E6D', |
fillColor: 'B7E66B' | fillColor: 'B7E66B' |
}; | }; |
$('.sparkline').sparkline('html',sparkOptions); | $('.sparkline').sparkline('html',sparkOptions); |
} | } |
); | ); |
}; | }; |
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="hashchange"]').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(); |
$(legend_name).show(); | $(legend_name).show(); |
} | } |
); | ); |
}; | }; |
/* | /* |
* Custom bootstrap plugin for handling data-toggle="hashchange". | * Custom bootstrap plugin for handling data-toggle="hashchange". |
* Behaves like data-toggle="tab" but I respond to the hashchange. | * Behaves like data-toggle="tab" but I respond to the hashchange. |
* Page state is memo-ized in the URL this way. Why doesn't Bootstrap do this? | * Page state is memo-ized in the URL this way. Why doesn't Bootstrap do this? |
*/ | */ |
$(function() { | $(function() { |
var mapping = {}; | var mapping = {}; |
$('a[data-toggle="hashchange"]').each( | $('a[data-toggle="hashchange"]').each( |
function(i,link) { | function(i,link) { |
link = $(link); | link = $(link); |
mapping[link.attr('href')] = link; | mapping[link.attr('href')] = link; |
} | } |
); | ); |
$(window).hashchange(function() { | $(window).hashchange(function() { |
var link = mapping[window.location.hash]; | var link = mapping[window.location.hash]; |
if (link) { link.tab('show'); } | if (link) { link.tab('show'); } |
}); | }); |
}); | }); |
/* | |
* Collection of shims to allow d3 and Rickshaw to load, error-free | |
* (but ultimately unusable) on Internet Explorer 7. The browser's | |
* API lacks several crucial functions which these libraries depend | |
* upon to load; we try to hide these errors from the user. | |
* | |
* With thanks to Array functions from: | |
* http://stackoverflow.com/questions/2790001/fixing-javascript-array-functions-in-internet-explorer-indexof-foreach-etc | |
* | |
* Use (Modernizr.svg==true) to detect whether it's okay to draw a graph. | |
*/ | |
'use strict'; | |
window.Element = window.Element || {'prototype': {}}; | |
window.CSSStyleDeclaration = window.CSSStyleDeclaration || {'prototype':{}}; | |
// Add ECMA262-5 method binding if not supported natively | |
// | |
if (!('bind' in Function.prototype)) { | |
Function.prototype.bind= function(owner) { | |
var that= this; | |
if (arguments.length<=1) { | |
return function() { | |
return that.apply(owner, arguments); | |
}; | |
} else { | |
var args= Array.prototype.slice.call(arguments, 1); | |
return function() { | |
return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments))); | |
}; | |
} | |
}; | |
} | |
// Add ECMA262-5 string trim if not supported natively | |
// | |
if (!('trim' in String.prototype)) { | |
String.prototype.trim= function() { | |
return this.replace(/^\s+/, '').replace(/\s+$/, ''); | |
}; | |
} | |
// Add ECMA262-5 Array methods if not supported natively | |
// | |
if (!('indexOf' in Array.prototype)) { | |
Array.prototype.indexOf= function(find, i /*opt*/) { | |
if (i===undefined) i= 0; | |
if (i<0) i+= this.length; | |
if (i<0) i= 0; | |
for (var n= this.length; i<n; i++) | |
if (i in this && this[i]===find) | |
return i; | |
return -1; | |
}; | |
} | |
if (!('lastIndexOf' in Array.prototype)) { | |
Array.prototype.lastIndexOf= function(find, i /*opt*/) { | |
if (i===undefined) i= this.length-1; | |
if (i<0) i+= this.length; | |
if (i>this.length-1) i= this.length-1; | |
for (i++; i-->0;) /* i++ because from-argument is sadly inclusive */ | |
if (i in this && this[i]===find) | |
return i; | |
return -1; | |
}; | |
} | |
if (!('forEach' in Array.prototype)) { | |
Array.prototype.forEach= function(action, that /*opt*/) { | |
for (var i= 0, n= this.length; i<n; i++) | |
if (i in this) | |
action.call(that, this[i], i, this); | |
}; | |
} | |
if (!('map' in Array.prototype)) { | |
Array.prototype.map= function(mapper, that /*opt*/) { | |
var other= new Array(this.length); | |
for (var i= 0, n= this.length; i<n; i++) | |
if (i in this) | |
other[i]= mapper.call(that, this[i], i, this); | |
return other; | |
}; | |
} | |
if (!('filter' in Array.prototype)) { | |
Array.prototype.filter= function(filter, that /*opt*/) { | |
var other= [], v; | |
for (var i=0, n= this.length; i<n; i++) | |
if (i in this && filter.call(that, v= this[i], i, this)) | |
other.push(v); | |
return other; | |
}; | |
} | |
if (!('every' in Array.prototype)) { | |
Array.prototype.every= function(tester, that /*opt*/) { | |
for (var i= 0, n= this.length; i<n; i++) | |
if (i in this && !tester.call(that, this[i], i, this)) | |
return false; | |
return true; | |
}; | |
} | |
if (!('some' in Array.prototype)) { | |
Array.prototype.some= function(tester, that /*opt*/) { | |
for (var i= 0, n= this.length; i<n; i++) | |
if (i in this && tester.call(that, this[i], i, this)) | |
return true; | |
return false; | |
}; | |
} | |
<html xmlns:py="http://genshi.edgewall.org/" | <html xmlns:py="http://genshi.edgewall.org/" |
xmlns:i18n="http://genshi.edgewall.org/i18n" | xmlns:i18n="http://genshi.edgewall.org/i18n" |
xmlns:xi="http://www.w3.org/2001/XInclude" | xmlns:xi="http://www.w3.org/2001/XInclude" |
py:strip=""> | py:strip=""> |
<xi:include href="../ga_util.html" /> | <xi:include href="../ga_util.html" /> |
<py:def function="page_title">Site usage</py:def> | <py:def function="page_title">Site usage</py:def> |
<py:def function="optional_head"> | <py:def function="optional_head"> |
<link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> | <link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> |
<link rel="stylesheet" type="text/css" href="/css/ga_report.css"/> | <link rel="stylesheet" type="text/css" href="/css/ga_report.css"/> |
<script type="text/javascript" src="/scripts/ckanext_ga_reports.js"></script> | <script type="text/javascript" src="/scripts/ckanext_ga_reports.js"></script> |
<script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> | <script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> |
<script type="text/javascript" src="/scripts/rickshaw_ie7_shim.js"></script> | |
<script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> | <script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> |
<script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> | <script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> |
<script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> | <script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> |
</py:def> | </py:def> |
<py:match path="primarysidebar"> | <py:match path="primarysidebar"> |
<li class="widget-container boxed widget_text"> | <li class="widget-container boxed widget_text"> |
<h4>Download</h4> | <h4>Download</h4> |
<p><center> | <p><center> |
<a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='csv',month=c.month or 'all')}">Download as CSV</a></center> | <a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='csv',month=c.month or 'all')}">Download as CSV</a></center> |
</p> | </p> |
</li> | </li> |
<li class="widget-container boxed widget_text"> | <li class="widget-container boxed widget_text"> |
<h4>Graph Legend</h4> | <h4>Graph Legend</h4> |
<div id="graph-legend-container"> | <div id="graph-legend-container"> |
<div id="legend_none">(No graph loaded)</div> | <div id="legend_none">(No graph loaded)</div> |
</div> | </div> |
</li> | </li> |
<xi:include href="../notes.html" /> | <xi:include href="../notes.html" /> |
</py:match> | </py:match> |
<div py:match="content"> | <div py:match="content"> |
<h1>Site Usage</h1> | <h1>Site Usage</h1> |
${usage_nav('Site-wide')} | ${usage_nav('Site-wide')} |
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> |
<div class="controls"> | <div class="controls"> |
${month_selector(c.month, c.months, c.day)} | ${month_selector(c.month, c.months, c.day)} |
<input class="btn button btn-primary" type='submit' value="Update"/> | <input class="btn button btn-primary" type='submit' value="Update"/> |
</div> | </div> |
</form> | </form> |
<div class="tabbable"> | <div class="tabbable"> |
<ul class="nav nav-tabs"> | <ul class="nav nav-tabs"> |
<li><a href="#totals" data-toggle="hashchange">Totals</a></li> | <li><a href="#totals" data-toggle="hashchange">Totals</a></li> |
<li class="dropdown"> | <li class="dropdown"> |
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Browsers | <a href="#" class="dropdown-toggle" data-toggle="dropdown">Browsers |
<b class="caret"></b></a> | <b class="caret"></b></a> |
<ul class="dropdown-menu"> | <ul class="dropdown-menu"> |
<li><a href="#browsers_names" data-toggle="hashchange">Browsers</a></li> | <li><a href="#browsers_names" data-toggle="hashchange">Browsers</a></li> |
<li><a href="#browsers_versions" data-toggle="hashchange">Versions</a></li> | <li><a href="#browsers_versions" data-toggle="hashchange">Versions</a></li> |
</ul> | </ul> |
</li> | </li> |
<li class="dropdown"> | <li class="dropdown"> |
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Operating Systems | <a href="#" class="dropdown-toggle" data-toggle="dropdown">Operating Systems |
<b class="caret"></b></a> | <b class="caret"></b></a> |
<ul class="dropdown-menu"> | <ul class="dropdown-menu"> |
<li><a href="#os" data-toggle="hashchange">Operating Systems</a></li> | <li><a href="#os" data-toggle="hashchange">Operating Systems</a></li> |
<li><a href="#os_versions" data-toggle="hashchange">Versions</a></li> | <li><a href="#os_versions" data-toggle="hashchange">Versions</a></li> |
</ul> | </ul> |
</li> | </li> |
<li class="dropdown"> | <li class="dropdown"> |
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Social | <a href="#" class="dropdown-toggle" data-toggle="dropdown">Social |
<b class="caret"></b></a> | <b class="caret"></b></a> |
<ul class="dropdown-menu"> | <ul class="dropdown-menu"> |
<li><a href="#social_networks" data-toggle="hashchange">All networks</a></li> | <li><a href="#social_networks" data-toggle="hashchange">All networks</a></li> |
<li><a href="#social_referrals_totals" data-toggle="hashchange">Referral links</a></li> | <li><a href="#social_referrals_totals" data-toggle="hashchange">Referral links</a></li> |
</ul> | </ul> |
</li> | </li> |
<li><a href="#languages" data-toggle="hashchange">Languages</a></li> | <li><a href="#languages" data-toggle="hashchange">Languages</a></li> |
<li><a href="#country" data-toggle="hashchange">Country</a></li> | <li><a href="#country" data-toggle="hashchange">Country</a></li> |
</ul> | </ul> |
<div class="tab-content"> | <div class="tab-content"> |
<div class="tab-pane" id="totals"> | <div class="tab-pane" id="totals"> |
<table class="table table-condensed table-bordered table-striped"> | <table class="table table-condensed table-bordered table-striped"> |
<tr> | <tr> |
<th>Name</th> | <th>Name</th> |
<th>Value</th> | <th>Value</th> |
<th>History</th> | <th>History</th> |
</tr> | </tr> |
<py:for each="name, value, graph in c.global_totals"> | <py:for each="name, value, graph in c.global_totals"> |
<tr> | <tr> |
<td>${name}</td> | <td>${name}</td> |
<td>${value}</td> | <td>${value}</td> |
<td class="sparkline-cell"> | <td class="sparkline-cell"> |
<span class="sparkline" sparkTooltips="${','.join([x for x,y in graph])}"> | <span class="sparkline" sparkTooltips="${','.join([x for x,y in graph])}"> |
${','.join([y for x,y in graph])} | ${','.join([y for x,y in graph])} |
</span> | </span> |
</td> | </td> |
</tr> | </tr> |
</py:for> | </py:for> |
</table> | </table> |
</div> | </div> |
<div class="tab-pane" id="browsers_versions"> | <div class="tab-pane" id="browsers_versions"> |
${rickshaw_graph(c.browser_versions_graph,'browser-versions',mode='stack')} | ${rickshaw_graph(c.browser_versions_graph,'browser-versions',mode='stack')} |
<p>Note: Where a browser has a large number of versions, these have been grouped together.</p> | < |