Kurz nach der Veröffentlichung der neuen Google-Analytics-API gibt es jetzt das gem garb, welches die Kommunikation damit erheblich vereinfacht. In diesem Beispiel frage ich die Werte visits, pageviews, etc. für den letzten Monat ab und übergebe sie dem jQuery-Plugin flot, das diese Daten auf eine recht hübsche interaktive Weise darstellt:

Hier folgen die Ergänzungen zu einer leeren Rails-2.3.2-Instanz. Das gesamte Projekt habe ich zum Clonen und Spielen auf Github eingestellt (s.u.).
Die Umgebung
Das gem wird aufgerufen (> 0.2), aus einem YAML-File werden die Accountinformationen eingelesen und eine Session mit Google etabliert.
In config/environment.rb:
1 2 3 4 5 6 7 8 9 10 |
... Rails::Initializer.run do |config| ... config.gem "vigetlabs-garb", :lib => "garb" ... end google_path = File.join(RAILS_ROOT,"config","google.yml") @@google_config = YAML.load(File.read(google_path))[RAILS_ENV] Garb::Session.login(@@google_config['login'], @@google_config['password']) |
Anmeldedaten
Das File config/google.yml enthält die Domaindaten:
1 2 3 4 5 6 7 8 9 |
development: domain: rnotes.bm.net login: me@bm.net password: p4ssw0rd production: domain: rnotes.bm.net login: me@bm.net password: p4ssw0rd |
Controller-Code
Wenn der Welcome-Index aufgerufen wird, wird die Datenabfrage im Controller assembliert und aufgerufen. Einer sauberen MVC-Kultur folgend, sollte man dies in einem richtigen Projekt vielleicht in ein Modell geben.
app/controllers/welcome_controller.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class WelcomeController < ApplicationController def index profile = Garb::Profile.all.select {|p| p.title == @@google_config['domain']}.first report = Garb::Report.new(profile, :start_date => 4.weeks.ago, :end_date => Time.now ) report.metrics :pageviews, :visits, :visitors, :new_visits report.dimensions :date report.sort :date result = report.results @visitors = result.map(&:visitors) @visits = result.map(&:visits) @newvisits = result.map(&:new_visits) @pageviews = result.map(&:pageviews) @dates = result.map {|d| d.date.to_time.to_i * 1000 } @domain = @@google_config['domain'] end end |
Hier ist bemerkenswert, wie die Datumsformate “CCYYMMDD”, die von Google als String kommen in Javascript-Timestamps umgerechnet werden, wie flot sie erwartet.
Die Diagrammdarstellung
Im Index werden die Ergebnisse ein ein Javascript eingefügt, das letztlich flot benutzt. Weitere Beispiele mit verschiedenen Optionen findet man auf der Website des Plugins.
Das app/views/welcome/index.html.erb-File:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
<h1><%= @domain -%></h1>
<p><br /></p>
<div id="placeholder" style="width:600px;height:300px"></div>
<div id="overview" style="margin-left:200px;margin-top:20px;
width:400px;height:50px"></div>
<script id="source" language="javascript" type="text/javascript">
$(function () {
var d1 = [<%= i = -1; @visitors.map {|v| i += 1;
"[#{@dates[i]}, #{v}]" }.join(", ") -%>];
var d2 = [<%= i = -1; @visits.map {|v| i += 1;
"[#{@dates[i]}, #{v}]" }.join(", ") -%>];
var d3 = [<%= i = -1; @pageviews.map {|v| i += 1;
"[#{@dates[i]}, #{v}]" }.join(", ") -%>];
var d4 = [<%= i = -1; @newvisits.map {|v| i += 1;
"[#{@dates[i]}, #{v}]" }.join(", ") -%>];
var d = [ { label: 'Visitors', data: d1 }, { label: 'Visits', data: d2 },
{ label: 'Pageviews', data: d3 }, { label: 'New visits', data: d4 } ];
// helper for returning the weekends in a period
function weekendAreas(axes) {
var markings = [];
var d = new Date(axes.xaxis.min);
// go to the first Saturday
d.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 1) % 7))
d.setUTCSeconds(0);
d.setUTCMinutes(0);
d.setUTCHours(0);
var i = d.getTime();
do {
// when we don't set yaxis the rectangle automatically
// extends to infinity upwards and downwards
markings.push({ xaxis: { from: i, to: i + 2 * 24 * 60 * 60 * 1000 } });
i += 7 * 24 * 60 * 60 * 1000;
} while (i < axes.xaxis.max);
return markings;
}
var options = {
xaxis: { mode: "time" },
selection: { mode: "x" },
legend: { position: 'sw' },
points: { show: true },
lines: { show: true },
grid: { markings: weekendAreas }
};
var plot = $.plot($("#placeholder"), d, options);
var overview = $.plot($("#overview"), [d1, d2, d3, d4], {
lines: { show: true, lineWidth: 1 },
shadowSize: 0,
xaxis: { ticks: [], mode: "time" },
selection: { mode: "x" }
});
$("#placeholder").bind("plotselected", function (event, ranges) {
// do the zooming
plot = $.plot($("#placeholder"), d,
$.extend(true, {}, options, {
xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to }
}));
// don't fire event on the overview to prevent eternal loop
overview.setSelection(ranges, true);
});
$("#overview").bind("plotselected", function (event, ranges) {
plot.setSelection(ranges);
});
});
</script> |
Javascripts und JRails
flot selbst benötigt jQuery. Eine elegante und schnelle Art der Einbettung ist es, das jRails-plugin zu installieren – es bringt jQuery mit:
script/plugin install http://ennerchi.googlecode.com/svn/trunk/plugins/jrails
Das fügt die rechten Files in public/javascripts ein. Es fehlt nur noch das jquery.flot.js:
- jrails.js
- jquery-ui.js
- jquery.flot.js
- jquery.js
das html-Layout
Zum Schluss müssen die Scripte im Layout aktivert werden – app/views/layouts/application.html.erb:
1 2 3 4 |
... <%= javascript_include_tag :defaults %> <%= javascript_include_tag 'jquery.flot' %> ... |