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