Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added a calendar view to the default report

  • Loading branch information...
commit 4c449b484ff543d90dde6c6bf1ffd9f4c304a856 1 parent eb2def8
@koraktor authored
View
3  .gitmodules
@@ -0,0 +1,3 @@
+[submodule "reports/default/javascripts/d3"]
+ path = reports/default/javascripts/d3
+ url = git://github.com/mbostock/d3.git
View
4 reports/default.rb
@@ -10,12 +10,14 @@ class Default < self
@@assets = %w{
images/favicon.png
+ javascripts/d3/d3.min.js
+ javascripts/d3/d3.time.min.js
stylesheets/default.css
}
@@name = :default
- @@views = [ :index ]
+ @@views = [ :index, :calendar ]
end
1  reports/default/javascripts/d3
@@ -0,0 +1 @@
+Subproject commit 402c2e49221ceca40fa43ca542ba8b0d9ac03632
View
20 reports/default/stylesheets/default.css
@@ -10,6 +10,20 @@ body {
width: 980px;
}
+a {
+ font-weight: bold;
+}
+
+a:hover, a.active {
+ color: #aa5;
+}
+
+a, em {
+ color: #f95;
+ font-style: normal;
+ text-shadow: #000 1px 1px 1px;
+}
+
div#content {
border: 2px solid #ffb;
border-radius: 5px;
@@ -21,7 +35,6 @@ div#content {
-webkit-box-shadow: #000 4px 4px 4px;
}
-
div#content div {
padding: 0.5em 0.5em 1em 0.5em;
}
@@ -48,11 +61,6 @@ div#most_significant_commits th {
width: 87%;
}
-em {
- color: #f95;
- font-style: normal;
-}
-
em, h1, h2, h3 {
font-family: Bevan, serif;
}
View
271 reports/default/templates/calendar.mustache
@@ -0,0 +1,271 @@
+<html>
+ <head>
+ <title>{{title}}</title>
+
+ <link rel="icon" href="./images/favicon.png" type="image/png" />
+ <link rel="stylesheet" href="./stylesheets/default.css" type="text/css" charset="utf-8" />
+ <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Bevan:regular" type="text/css" />
+
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <meta name="date" content="{{meta_now}}">
+ <meta name="description" content="Metior report for {{repo_name}}" />
+ <meta name="generator" content="Metior {{version}}" />
+
+ <script src="./javascripts/d3/d3.min.js" type="text/javascript"></script>
+ <script src="./javascripts/d3/d3.time.min.js" type="text/javascript"></script>
+
+ <style type="text/css">
+ #calendar {
+ fill: #ffb;
+ font: 9pt sans-serif;
+ }
+
+ .day, .month {
+ shape-rendering: crispEdges;
+ }
+
+ .day {
+ fill: #ffd;
+ stroke: #ccc;
+ }
+
+ .month {
+ fill: none;
+ stroke: #000;
+ stroke-width: 2px;
+ }
+
+ .nothing { fill: #fff; }
+
+ .add-0 { fill: rgb(229,245,224) }
+ .add-1 { fill: rgb(199,233,192) }
+ .add-2 { fill: rgb(161,217,155) }
+ .add-3 { fill: rgb(116,196,118) }
+ .add-4 { fill: rgb(65,171,93) }
+ .add-5 { fill: rgb(35,139,69) }
+ .add-6 { fill: rgb(0,109,44) }
+ .add-7 { fill: rgb(0,68,27) }
+
+ .del-0 { fill: rgb(254,224,210) }
+ .del-1 { fill: rgb(252,187,161) }
+ .del-2 { fill: rgb(252,146,114) }
+ .del-3 { fill: rgb(251,106,74) }
+ .del-4 { fill: rgb(239,59,44) }
+ .del-5 { fill: rgb(203,24,29) }
+ .del-6 { fill: rgb(165,15,21) }
+ .del-7 { fill: rgb(103,0,13) }
+ </style>
+ </head>
+ <body>
+ <h1>Calendar for <em>{{repo_name}}</em></h1>
+ <h4>generated by Metior {{version}}</h4>
+
+ <p style="font-size: 10pt">
+ The following calendar shows the history of the repository over
+ the years. Each big block represents one year. The big sections of
+ a year represent months while the small squares represent single
+ days. If a day is green it means code has been added overall. A red
+ day means there has been more code deleted than added. The darker
+ the color, the more code has been changed compared to the rest of
+ the repository's history.
+ </p>
+
+ <p>
+ <a id="show-impact" href="javascript:showImpact()">Show Impact</a> –
+ <a id="show-commits" href="javascript:showCommits()">Show Commits</a> –
+ <a id="show-change" href="javascript:showChange()">Show Line Changes</a>
+ </p>
+
+ <div id="calendar"></div>
+
+ <script type="text/javascript">
+ var w = d3.select('body')[0][0].offsetWidth,
+ pw = 14,
+ z = ~~((w - pw * 2) / 53),
+ ph = z >> 1,
+ h = z * 7;
+
+ var calendar = {
+ format: d3.time.format("%m/%d/%Y"),
+ dates: function(year) {
+ var dates = [],
+ date = new Date(year, 0, 1),
+ week = 0,
+ day;
+ do {
+ dates.push({
+ day: day = date.getDay(),
+ week: week,
+ month: date.getMonth(),
+ Date: calendar.format(date)
+ });
+ date.setDate(date.getDate() + 1);
+ if (day === 6) week++;
+ } while (date.getFullYear() === year);
+ return dates;
+ },
+ months: function(year) {
+ var months = [],
+ date = new Date(year, 0, 1),
+ month, firstDay, firstWeek, day, week = 0;
+ do {
+ firstDay = date.getDay();
+ firstWeek = week;
+ month = date.getMonth();
+ do {
+ day = date.getDay();
+ if (day === 6) week++;
+ date.setDate(date.getDate() + 1);
+ } while (date.getMonth() === month);
+ months.push({
+ firstDay: firstDay,
+ firstWeek: firstWeek,
+ lastDay: day,
+ lastWeek: day === 6 ? week - 1 : week
+ });
+ } while (date.getFullYear() === year);
+ return months;
+ }
+ };
+
+ var vis = d3.select("#calendar")
+ .selectAll("svg")
+ .data(d3.range({{first_year}}, {{last_year}} + 1))
+ .enter().append("svg:svg")
+ .attr("width", w)
+ .attr("height", h + ph * 2)
+ .append("svg:g")
+ .attr("transform", "translate(" + pw + "," + ph + ")");
+
+ vis.append("svg:text")
+ .attr("transform", "translate(-6," + h / 2 + ")rotate(-90)")
+ .attr("text-anchor", "middle")
+ .text(function(d) { return d; });
+
+ vis.selectAll("rect.day")
+ .data(calendar.dates)
+ .enter().append("svg:rect")
+ .attr("x", function(d) { return d.week * z; })
+ .attr("y", function(d) { return d.day * z; })
+ .attr("class", "day")
+ .attr("width", z)
+ .attr("height", z);
+
+ vis.selectAll("path.month")
+ .data(calendar.months)
+ .enter().append("svg:path")
+ .attr("class", "month")
+ .attr("d", function(d) {
+ return "M" + (d.firstWeek + 1) * z + "," + d.firstDay * z
+ + "H" + d.firstWeek * z
+ + "V" + 7 * z
+ + "H" + d.lastWeek * z
+ + "V" + (d.lastDay + 1) * z
+ + "H" + (d.lastWeek + 1) * z
+ + "V" + 0
+ + "H" + (d.firstWeek + 1) * z
+ + "Z";
+ });
+
+ var data = {{data}};
+ var dayChange = d3.values(data).map(function(d) { return d.additions - d.deletions })
+ var dayCommits = d3.values(data).map(function(d) { return d.commits })
+ var dayImpact = d3.values(data).map(function(d) { return d.additions + d.deletions })
+
+ var quantizeAdditions = d3.scale.quantize()
+ .domain([0, d3.max(dayChange)])
+ .range(d3.range(8));
+
+ var quantizeCommits = d3.scale.quantize()
+ .domain([0, d3.max(dayCommits)])
+ .range(d3.range(8));
+
+ var quantizeDeletions = d3.scale.quantize()
+ .domain([0, d3.min(dayChange)])
+ .range(d3.range(8));
+
+ var quantizeImpact = d3.scale.quantize()
+ .domain([0, d3.max(dayImpact)])
+ .range(d3.range(8));
+
+ vis.selectAll("rect.day").append("svg:title")
+ .text(function(d) {
+ var additions, commits, deletions;
+ var dayData = data[d.Date];
+ if(dayData == undefined) {
+ additions = 0;
+ commits = 0;
+ deletions = 0;
+ } else {
+ additions = dayData.additions;
+ commits = dayData.commits;
+ deletions = dayData.deletions;
+ }
+
+ return d.Date + ': ' + commits + ' commits, +' +
+ additions + '/-' + deletions + ' lines';
+ });
+
+ function showChange() {
+ d3.select("#show-change").attr('class', 'active');
+ d3.select("#show-commits").attr('class', '');
+ d3.select("#show-impact").attr('class', '');
+ vis.selectAll("rect.day")
+ .attr("class", function(d) {
+ var dayData = data[d.Date];
+ if(dayData == undefined) {
+ return 'day';
+ }
+ var lines = dayData.additions - dayData.deletions;
+ if(lines == 0) {
+ return 'day nothing';
+ }
+ if(lines < 0) {
+ return 'day del-' + quantizeDeletions(lines);
+ }
+ return 'day add-' + quantizeAdditions(lines);
+ });
+ }
+
+ function showCommits() {
+ d3.select("#show-change").attr('class', '');
+ d3.select("#show-commits").attr('class', 'active');
+ d3.select("#show-impact").attr('class', '');
+ vis.selectAll("rect.day")
+ .attr("class", function(d) {
+ var dayData = data[d.Date];
+ if(dayData == undefined) {
+ return 'day';
+ }
+ var commits = dayData.commits;
+ if(commits == 0) {
+ return 'day';
+ }
+ return 'day add-' + quantizeCommits(commits);
+ });
+ }
+
+ function showImpact() {
+ d3.select("#show-change").attr('class', '');
+ d3.select("#show-commits").attr('class', '');
+ d3.select("#show-impact").attr('class', 'active');
+ vis.selectAll("rect.day")
+ .attr("class", function(d) {
+ var dayData = data[d.Date];
+ if(dayData == undefined) {
+ return 'day';
+ }
+ var impact = dayData.additions + dayData.deletions;
+ if(impact == 0) {
+ return 'day';
+ }
+ return 'day add-' + quantizeImpact(impact);
+ });
+ }
+
+ showImpact();
+ </script>
+
+ <div id="footer">Generated at {{now}}</div>
+ </body>
+</html>
View
74 reports/default/views/calendar.rb
@@ -0,0 +1,74 @@
+# This code is free software; you can redistribute it and/or modify it under
+# the terms of the new BSD License.
+#
+# Copyright (c) 2011, Sebastian Staudt
+
+require 'date'
+
+class Metior::Report::Default
+
+ # @author Sebastian Staudt
+ class Calendar < View
+
+ def data
+ data = {}
+ @report.commits.each do |commit|
+ date = commit.committed_date.send :to_date
+ if data.key? date
+ data[date][:commits] += 1
+ data[date][:additions] += commit.additions
+ data[date][:deletions] += commit.deletions
+ else
+ data[date] = {
+ :commits => 1,
+ :additions => commit.additions,
+ :deletions => commit.deletions
+ }
+ end
+ end
+
+ js_data = []
+ first = @report.commits.last.committed_date.send :to_date
+ last = @report.commits.first.committed_date.send :to_date
+ first.upto last do |current|
+ next unless data.key? current
+ js_data << ("'#{current.strftime '%m/%d/%Y'}': {" <<
+ "'additions': #{data[current][:additions]}," <<
+ "'commits': #{data[current][:commits]}," <<
+ "'deletions': #{data[current][:deletions]} }")
+ end
+
+ "{ #{js_data.join(',')} }"
+ end
+
+ def first_year
+ @report.commits.last.committed_date.year
+ end
+
+ def last_year
+ @report.commits.first.committed_date.year
+ end
+
+ def meta_now
+ now.strftime('%FT%H:%M:%S%z').insert(-3, ':')
+ end
+
+ def now
+ Time.now
+ end
+
+ def repo_name
+ repository.name.empty? ? repository.path : repository.name
+ end
+
+ def title
+ "Calendar for #{repo_name}"
+ end
+
+ def version
+ Metior::VERSION
+ end
+
+ end
+
+end

0 comments on commit 4c449b4

Please sign in to comment.
Something went wrong with that request. Please try again.