Skip to content

Instantly share code, notes, and snippets.

@nterray
Created January 21, 2014 20:13
Show Gist options
  • Save nterray/8547492 to your computer and use it in GitHub Desktop.
Save nterray/8547492 to your computer and use it in GitHub Desktop.
Dirty hack to group activities by categories in hamster (time tracker) exported report. Place this file in ~/.local/share/hamester-applet/ (adjust path accordingly to your distro)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="author" content="hamster-applet" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js"></script>
<link type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/themes/base/jquery-ui.css" rel="stylesheet" />
<title>$title</title>
<style type="text/css">
body {
font-family: "Droid Sans", "Liberation Sans", "Helvetica", "Arial", sans-serif;
font-size: 12px;
padding: 0;
margin: 0;
color: #303030;
background: #eee;
}
#content {
width: 700px;
padding: 24px 12px;
margin:0px auto;
background: #f6f6f6;
border-right: 2px solid #bbb;
border-left: 1px solid #bbb;
}
th, td {
text-align: left;
padding-right: 24px;
}
th {
padding-top: 12px;
}
h1 {margin-top: 0; margin-bottom: 1em;}
h2, h3 {margin-bottom: 4px;}
.even {background-color: #eee;}
.odd {background-color: #fff;}
.by_day_controls {
margin-bottom: 24px;
}
#activity_log {
display: none;
}
table.chart {
border-collapse:collapse;
margin-bottom: 2em;
}
td.bar_col {
width: 100px;
}
.bar {
background-color: #7B8ED7;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
color: #fff;
height: 100%;
}
#date_chart {
width: 100%;
overflow: auto;
overflow-y: hidden;
height: 80px;
}
#date_chart table {
width: 100%;
height: 90%;
border-collapse: collapse;
margin-bottom: 4px;
}
#date_chart table tr {vertical-align: bottom;}
#date_chart table td {
padding: 0;
padding-right: 1px;
}
#date_chart .bar {
width: 100%;
background-color: #ccc;
border-radius: 0;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
#grand_total {
color: #999;
}
#activity_log {
padding: 6px;
margin: 6px;
padding-left: 12px;
border: 1px solid silver;
background: #eee;
}
#date_facts tr:td {
padding-left: 24px;
}
p.template-instructions {
margin-top: 2em;
}
</style>
<style type="text/css" media="print">
div#tabs ul {
display: none;
}
div#tabs {
border: none;
}
div.by_day_controls {
display: none;
}
p.template-instructions {
display: none;
}
</style>
<script type="text/javascript">
var facts = $facts;
function showChartBy(target, data) {
for (var category in data) {
var section = $("<div><h3>" + category + "</h3></div>");
target.append(section);
showChart(section, data[category]);
}
}
function showChart(target, data) {
totals = []
// turn object into a list of tuples and convert durations from seconds to hours
var max_duration = 0;
for (var key in data) {
var duration = data[key] / 60 / 60.0;
totals.push([key, duration]); // hours
max_duration = Math.max(max_duration, duration);
}
// sort by duration descending
totals.sort(function compare(a,b) {return b[1] - a[1]})
// create the HTML
var table = $("<table class='chart' style='width:100%' />")
for (var i=0; i < totals.length; i++) {
var total = totals[i];
var row = $("<tr />");
var label = $("<td />");
label.text(total[0]);
row.append(label);
var duration = Math.round(total[1] * 10) / 10; // round to one decimal
var duration_label = $("<td />");
duration_label.text(duration);
row.append(duration_label);
var bar_col = $("<td class='bar_col' />");
var bar = $("<div class='bar'>&nbsp;</div>");
bar.width(total[1] / max_duration * 100);
bar_col.append(bar);
row.append(bar_col);
table.append(row);
}
target.append(table);
}
$(document).ready(function() {
var categoryTotals = {};
var activityTotals = {};
var tagTotals = {};
var dateTotals = {};
var activitiesByCategories = {};
function addBy(list, key, subkey, value) {
list[key] = list[key] || {};
list[key][subkey] = list[key][subkey] || 0;
list[key][subkey] += value;
}
function add(list, key, value) {
list[key] = list[key] || 0;
list[key] += value;
}
var grandTotal = 0;
for (var i=0; i < facts.length; i++) {
var fact = facts[i];
add(dateTotals, fact.date, fact.delta)
add(categoryTotals, fact.category, fact.delta)
add(activityTotals, fact.activity, fact.delta)
addBy(activitiesByCategories, fact.category, fact.activity, fact.delta)
for (var j=0; j < fact.tags.length; j++) {
add(tagTotals, fact.tags[j], fact.delta)
}
grandTotal += fact.delta;
}
grandTotal = Math.round(grandTotal / 60 / 60 * 10) / 10;
$("#grand_total").text("(" + grandTotal + ")");
showChart($("#category_chart"), categoryTotals)
showChart($("#activity_chart"), activityTotals)
showChart($("#tag_chart"), tagTotals)
showChartBy($("#activity_by_category_chart"), activitiesByCategories)
// create the by-day chart
var startDate = $start_date;
var endDate = $end_date;
var dates = [];
var dateMax = 0;
for (var i=startDate; i <= endDate; i += 24 * 60 * 60) {
var duration = dateTotals[i] || 0;
dateMax = Math.max(dateMax, duration);
dates.push([new Date(i), duration])
}
var table = $("<table />")
var row = $("<tr />");
for (var i=0; i<dates.length; i++) {
var date = dates[i];
var col = $("<td />");
var bar = $("<div class='bar'>&nbsp;</div>");
var bar_height = date[1] / dateMax * 70;
if (bar_height < 1)
bar.height(1);
else
bar.height(bar_height)
col.append(bar);
row.append(col);
}
table.append(row);
$("#date_chart").append(table);
$("#activity_log_link").click(function() {
$("#activity_log").toggle()
})
$("#show_details").click(function() {
if ($(this).attr("checked")) {
$(".by_date_row").show();
} else {
$(".by_date_row").hide();
}
})
$("#show_totals").click(function() {
if ($(this).attr("checked")) {
$(".by_date_total_row").show();
} else {
$(".by_date_total_row").hide();
}
})
populateFactTable();
$(".by_day_controls input").click(function(){
populateFactTable();
});
});
function populateFactTable() {
// fill fact rows
var table = $("#date_facts");
table.empty();
var dateFacts = $date_facts;
// determine if we will be doing any internal counting
var keys = [];
if ($("#show_activities").attr("checked"))
keys.push("activity");
if ($("#show_categories").attr("checked"))
keys.push("category");
if ($("#show_tags").attr("checked"))
keys.push("tags");
for (var i in dateFacts) {
var dateString = dateFacts[i][0];
var dateTotal = 0;
var factTotals = {}
for (var j in dateFacts[i][1]) {
var fact = dateFacts[i][1][j];
fact.tags = fact.tags.join(", ");
if (keys.length > 0) {
var key = [];
for (var k in keys) {
key.push(fact[keys[k]])
}
key = key.join(" - ");
factTotals[key] = factTotals[key] || 0;
factTotals[key] += fact.delta;
}
dateTotal += fact.delta;
}
dateTotal = Math.round(dateTotal / 60 / 60 * 10) / 10;
table.append("<tr><th>" + dateString + "</th><th>" + dateTotal +"</th></tr>");
for (var key in factTotals) {
keyTotal = Math.round(factTotals[key] / 60 / 60 * 10) / 10;
table.append("<tr><td>" + key + "</td><td>" + keyTotal +"</td></tr>");
}
}
}
</script>
</head>
<body>
<div id="content">
<h1>$title <span id="grand_total"></span></h1>
<div id="date_chart"></div>
<a id="activity_log_link" href="javascript: false">Show activity log</a>
<div id="activity_log">
<h2>$activity_log_title</h2>
<table>
<tr>
<th>$header_date</th>
<th>$header_activity</th>
<th>$header_category</th>
<th>$header_tags</th>
<th>$header_start</th>
<th>$header_end</th>
<th>$header_duration</th>
<th>$header_description</th>
</tr>
<all_activities>
<tr>
<td>
<!-- there is also date_iso -->
$date
</td>
<td>$activity</td>
<td>$category</td>
<td>$tags</td>
<td>
<!-- there is also start_iso -->
$start
</td>
<td>
<!-- there is also end_iso -->
$end
</td>
<td>
<!-- there is also duration_decimal and duration_minutes -->
$duration
</td>
<td>$description</td>
</tr>
</all_activities>
</table>
</div>
<table>
<tr style="vertical-align: top">
<td style="width: 100%">
<h2>$totals_by_day_title</h2>
<div class="by_day_controls">
$show_prompt
<input type="checkbox" id="show_activities" checked="checked"></input>
<label for="show_details">$activity_totals_heading</label>
<input type="checkbox" id="show_categories" checked="checked"></input>
<label for="show_totals">$category_totals_heading</label>
<input type="checkbox" id="show_tags" checked="checked"></input>
<label for="show_totals">$tag_totals_heading</label>
</div>
<table id="date_facts"></table>
</td>
<td>
<div>
<h2>Categories</h2>
<div id="category_chart"></div>
</div>
<div>
<h2>Activities</h2>
<div id="activity_chart"></div>
</div>
<div>
<h2>Activities by Categories</h2>
<div id="activity_by_category_chart"></div>
</div>
<div>
<h2>Tags</h2>
<div id="tag_chart"></div>
</div>
</td>
</tr>
</table>
<p class="template-instructions">
<a href="file:///$data_dir/report_template.html">$show_template</a>.
$template_instructions.
</p>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment