block by zeffii c2bae16a2b385f0d784a

sleep_tkd - nested

Full Screen

sleep over time

http://blockbuilder.org/zeffii/c2bae16a2b385f0d784a

Charting sleep periods over the course of a number of days.

milestones

index.html

<!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>

dillitant.js

/*
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))
    }
}

style.css

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.axis text {
  font: 10px sans-serif;
}

times.json

{
  "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->"
}