http://blockbuilder.org/zeffii/c2bae16a2b385f0d784a
Charting sleep periods over the course of a number of days.
- vertical axis day
- horizontal time of day
milestones
- each day gets unique track
http://blockbuilder.org/zeffii/c2bae16a2b385f0d784a
Charting sleep periods over the course of a number of days.
milestones
/* | |
whenever I don't use d3.js regularly I forget how to do simple things, like nested selections, and time.formatting of ticks. | |
This is an effort to future proof myself, and will later hopefully include a link to a more | |
d3js-style solution - to contrast and compare. (my knuckle dragging approach vs using prewritten+tested functions of the d3 library) | |
For now this is moderately light usage of d3.js - maybe to the chagrin of more weathered | |
d3.js users - simply to illustrate a problem i'm facing. | |
*/ | |
function get_ratio_from_time(time_str){ | |
// this function converts a time_str into how far into the day it is | |
// f.ex 12:00 => 0.5 06:00 => 0.25 | |
var time_parts = time_str.split(':'); | |
var a = +time_parts[0]; | |
var b = +time_parts[1]; | |
return (1/1440*((a*60) + b)) | |
} | |
var svg = d3.select("svg") | |
var format_day = d3.time.format("%d/%m/%Y"); | |
var format_hours = d3.time.format("%H:%M"); | |
var formatTime = d3.time.format("%m / %d"); // formatTime(new Date); // "June 30, 2015" | |
d3.json("times.json", function(error, times) { | |
if (error) throw error; | |
times = json_preprocessor(times); | |
draw_graph(times); | |
}); | |
function times_preprocessor(t){ | |
var ts = t.split(','); | |
var emb = []; | |
for (var k of ts){ | |
var abl = k.split('->'); | |
if (abl.length === 2){ emb.push(abl); } | |
} | |
return emb; | |
} | |
function json_preprocessor(p){ | |
var new_object_array = []; | |
for (var key in p) { | |
if (p.hasOwnProperty(key)) { | |
var day_datum = format_day.parse(key); | |
var processed_times = times_preprocessor(p[key]); | |
new_object_array.push({day: day_datum, times: processed_times}); | |
} | |
} | |
return new_object_array; | |
} | |
function draw_graph(times){ | |
var margin = {top: 20, right: 80, bottom: 30, left: 50}, | |
width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
svg | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom); | |
var main_group = svg.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var tracks = main_group.append('g').classed('tracks', true) | |
var yindex = 0; | |
var begin_time, end_time; | |
var bar_height = 10; | |
var vertical_skip = 12; | |
for (var item of times){ | |
var mg = tracks.append('g'); | |
for (var time_slot of item.times){ | |
begin_time = get_ratio_from_time(time_slot[0]); | |
end_time = get_ratio_from_time(time_slot[1]); | |
var rec = mg.append('rect'); | |
rec.attr("width", (end_time - begin_time) * width) | |
rec.attr("height", bar_height) | |
rec.style({fill: "#badcfc"}) | |
rec.attr("transform", function(d){ | |
return "translate(" + [ | |
begin_time * width, | |
yindex * vertical_skip | |
] + ")" | |
}) | |
} | |
yindex += 1; | |
mg.append('text') | |
.text(formatTime(item.day)) | |
.attr("transform", "translate(-21," + (yindex * vertical_skip - 3) + ")") | |
.attr({'text-anchor': "middle", "font-size": 10, "font-family": "sans-serif"}) | |
} | |
var indicat = main_group.append('g').classed('indications', true); | |
var ditimes = ["00","03","06","09","12","15","18","21","24"]; | |
for (var tick of ditimes){ | |
tick = tick + ":00"; | |
var tgl = indicat.append('g'); | |
var tl = tgl.append('line'); | |
var xpostime = Math.floor(get_ratio_from_time(tick) * width); | |
tl.attr('x1', xpostime) | |
tl.attr('x2', xpostime) | |
tl.attr('y1', 0) | |
tl.attr('y2', height) | |
tl.style({"stroke-width": 1, stroke: "#aabfd4"}) | |
var tcl = tgl.append('circle'); | |
tcl.attr('cx', Math.floor(get_ratio_from_time(tick) * width)) | |
tcl.attr('cy', height/2); | |
tcl.attr('r', 16); | |
tcl.style({fill: "#e0eeff"}) | |
var txl = tgl.append('text'); | |
txl.attr({'text-anchor': "middle", "font-size": 17, "font-family": "sans-serif"}) | |
txl.attr('transform', 'translate(' + [Math.floor(get_ratio_from_time(tick) * width),(height/2)+5 ] + ')') | |
txl.style({'fill': "#7c7c7c"}) | |
txl.text(tick.slice(0,2)) | |
} | |
} |
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
<script src="https://d3js.org/d3-time.v0.2.min.js"></script> | |
<link rel="stylesheet" type="text/css" href="style.css" /> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
svg { width:100%; height: 100% } | |
</style> | |
</head> | |
<body> | |
<svg></svg> | |
<script src="dillitant.js"></script> | |
</body> |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.axis text { | |
font: 10px sans-serif; | |
} | |
{ | |
"21/03/2016": "10:30->12:00,13:45->15:00,16:21->17:30,21:15->22:15,22:25->24:00", | |
"22/03/2016": "00:00->01:00,01:05->02:00,02:05->03:53,04:05->05:30,09:45->12:00,14:20->16:45,19:45->22:00,22:40->24:00", | |
"23/03/2016": "00:00->01:15,01:20->07:12,09:45->12:00,16:00->17:45,20:15->22:00,22:15->24:00", | |
"24/03/2016": "00:00->05:10,05:20->07:00,09:40->11:10,13:52->16:00,19:30->21:30,22:30->24:00", | |
"25/03/2016": "00:00->07:00,09:22->11:15,12:45->14:40,17:30->17:50,20:00->20:53,22:20->24:00", | |
"26/03/2016": "00:00->07:00,09:20->11:45,14:15->17:30,22:10->24:00", | |
"27/03/2016": "00:00->07:00,10:00->11:45,13:20->14:52,16:30->17:00,19:00->20:44,22:15->24:00", | |
"28/03/2016": "00:00->07:00,22:15->24:00", | |
"29/03/2016": "00:00->07:30,17:00->19:50,22:00->24:00", | |
"30/03/2016": "00:00->07:30,09:30->11:30,15:30->18:15,22:00->24:00", | |
"31/03/2016": "00:00->05:30,08:00->10:30,11:15->13:00,15:20->16:20,17:20->17:45,20:30->22:45,23:15->24:00", | |
"01/04/2016": "00:00->07:00,15:20->18:30,23:00->24:00", | |
"02/04/2016": "00:00->07:00,07:15->08:00,09:30->12:45,16:05->17:45,20:30->21:00,21:45->24:00", | |
"03/04/2016": "00:00->06:30,08:10->11:30,14:30->18:30,21:00->22:50,23:00->24:00", | |
"04/04/2016": "00:00->07:00,09:00->11:30,15:30->17:30,22:00->24:00", | |
"05/04/2016": "00:00->06:50,09:20->12:00,13:50->15:30,21:50->24:00", | |
"06/04/2016": "00:00->07:00,10:00->" | |
} |