$( function() { var csv_text = '\ 2011-01-13T15:42:08 0000t 108\n\ 2011-01-14T15:42:08 0000t 108\n\ 2011-01-15T15:42:08 0000t 108\n\ 2011-01-16T15:42:08 0000t 108\n\ 2011-01-17T15:42:08 0000t 108\n\ 2011-02-15T20:58:25 0000t 121\n\ 2011-02-16T20:58:25 0000t 121\n\ 2011-02-17T20:58:25 0000t 121\n\ 2011-02-18T20:58:25 0000t 121\n\ 2011-02-19T20:58:25 0000t 121\n\ 2011-02-20T20:58:25 0000t 121\n\ 2011-02-21T20:58:25 0000t 121\n\ 2011-03-08T16:55:07 0000t 100\n\ 2011-03-08T18:29:12 0000t 91\n\ 2011-03-08T19:30:37 0000t 94\n\ 2011-03-08T21:34:27 0000t 126\n\ 2011-03-09T08:38:01 0000t 242\n'; var json = [ ]; json = d3.tsv.parseRows(csv_text, fix_row); // json.forEach(fix_row); var url = './sugars.txt'; myChart.draw_graph(json); d3.text(url).get(function (err, data) { json = d3.tsv.parseRows(data, fix_row); myChart.update_data(json); }); } ); // make these things debuggable from console // var my = { }; function create ( ) { function my ( ) { } var zoomer, x, y ; var width; my.width = function (_) { if (!arguments.length == 0) return width; width = _; return my; } my.prev = function ( ) { var ex = x.domain( ); var end = ex[0]; var start = ex[0] - (ex[1] - ex[0]); x.domain([start, end]); zoomer.x(x); my.render( ); }; my.next = function ( ) { var ex = x.domain( ); var start = ex[1]; var end = new Date(start.getTime( ) + (ex[1] - ex[0])); x.domain([start, end]); zoomer.x(x); my.render( ); }; my.draw_graph = draw_graph; my.update_data = update_data; return my; function draw_graph(data) { var results, chart, dots, margin = 100, w = 8, h = 500, width = $('#lab').width( ), xAxis, yAxis zoom = 40 ; var scaleExtent = [ 0, 200 ]; // allow some granularity between our notion of scale and d3's // my.zScale = d3.scale.linear( ).domain(scaleExtent).rangeRound( [0, 1000] ); // but force only 8 layout switches // my.zSwitching = d3.scale.linear( ).domain([0,1000]).rangeRound([0,8]); console.log( $('#lab'), $('#lab').width( ) ); $('#lab #test').remove( ); $('#lab').append( $('#clone').clone(true).attr('id', 'test') ); chart = d3.select( '#test' ).append( 'svg' ) .attr( 'class', 'chart' ) .attr( 'width', width ) .attr( 'height', h ) .append('g'); d3.select('svg g') .attr('class', 'container') .attr('transform', 'translate(50, 50)'); var last = d3.time.day.round(data.slice(-1)[0].date), first = d3.time.day.round(d3.time.day.offset(last, -7)) ; my.first = first; my.last = last; my.range = d3.time.day.range(first, last); console.log(first, last); x = d3.time.scale() .domain( [first, last] ) .range( [0, width - margin] ) ; // y = d3.scale.linear() y = d3.scale.log() .domain( [30, d3.max( data, function( d ) { return d.sugar; } )] ) .rangeRound( [1, h - margin] ); ; my.x = x; my.y = y; // safety bars var safeties = { low: 70, high: 140, x: x.range()[0], y: (h - margin) - y(140) + .5, width: (width), height: y(140) - y(70) + .5 }; var upper = { low: 140, high: 180, x: x.range()[0], y: (h - margin) - y(180) + .5, width: (width), height: y(180) - y(140) + .5 }; var bars = chart.append('g') .attr('class', 'safety'); bars.append('rect') .attr('class', 'safe-sugar') ; bars.append('rect') .attr('class', 'upper') ; // Bars dots = chart.append('g') .attr('class', 'dots'); dots.selectAll( 'circle' ) .data( data ) .enter().append( 'circle' ) .attr( 'r', '.5ex') .append('title') .attr('class', 'values') // .attr( 'width', w ) // .attr( 'height', function( d ) { return y( d.population ) } ) ; // Axis xAxis = d3.svg.axis() .scale(x) .ticks(my.range.length) .tickSize(12, 1, 1) ; // .tickFormat(d3.time.format('%m/%d/%y')) //.tickSize(25, 18); yAxis = d3.svg.axis() .scale( d3.scale.log() .domain( [30, d3.max( data, function( d ) { return d.sugar || 0; } )] ) .rangeRound( [h - margin, 1] ) .base(12) ) .tickValues([36, 40, 60, 70, 80, 120, 160, 180, 200, 220, 260, 300, 350, 400]) .tickFormat(d3.format("d")) .tickSize(6, 3, 1) .orient('right'); chart.append('g') .attr('class', 'x axis') .attr('transform', 'translate(0, ' + (h - margin) + ')'); chart.append('g') .attr('transform', 'translate('+ (width - margin) + ', 0)') .attr('class', 'y axis'); zoomer = d3.behavior.zoom() // By supplying only .x() any pan/zoom can only alter the x scale. y // scale remains fixed. .x(x) .scaleExtent( scaleExtent ) // .scale( 2 ) .on("zoom",render) ; d3.select("svg").call(zoomer); function extent_lines (selection) { // var begin = x.invert(x(x.invert(width)) - width + margin); // var begin = x.domain( )[0]; var begin = x.invert(0); var end = x.invert(width - margin); var length = y.domain( ); d3.select('.start').text(begin); var diff = moment(begin).from(moment(end)).replace(' ago', ''); d3.select('.range').text(diff); d3.select('.end').text((end)); selection.selectAll('line.begin-line') .data([{x: 0, begin: begin}]) .enter( ) .append('line') .attr('class', 'begin-line') ; selection.select('line.begin-line') .attr('x1', 0) .attr('x2', 0) .attr('y1', y(length[0])) .attr('y2', y(length[1])) .style('stroke-dasharray', '3, 3') .attr('stroke', 'grey') ; selection.selectAll('line.end-line') .data([{x: 0, end: end}]) .enter( ) .append('line') .attr('class', 'end-line') ; selection.select('line.end-line') .attr('x1', width - margin) .attr('x2', width - margin) .attr('y1', y(length[0])) .attr('y2', y(length[1])) .style('stroke-dasharray', '3, 3') .attr('stroke', 'grey') ; return selection; } function render() { // if the zoom level changes, consider resizing the scales. // var old_zoom = zoom; d3.select('.container').call(extent_lines); if (d3.event) { // zoom = my.zScale( d3.event.scale ); // var i = my.zSwitching(zoom); } bars.selectAll("rect.safe-sugar") .attr( 'x', safeties.x) .attr( 'y', safeties.y) .attr( 'width', safeties.width - (margin * .5)) .attr( 'height', safeties.height) ; bars.selectAll("rect.upper") .attr( 'x', upper.x) .attr( 'y', upper.y) .attr( 'width', upper.width - (margin * .5)) .attr( 'height', upper.height) ; dots.selectAll("circle") .attr( 'cx', function( d, i ) { return x( d.date ) - .5; } ) .attr( 'cy', function( d ) { return (h - margin) - y( d.sugar ) + .5 } ) ; dots.selectAll("title.values") .text( function (d) { return [d.date, d.sugar].join(' '); }); chart.select(".x.axis").call(xAxis); chart.select(".y.axis").call(yAxis); } my.render = render; // Call this to place initially render(); } function update_data(rows) { // console.log('XXX', this, arguments); if (rows) { // rows.forEach(fix_row); draw_graph(rows); } } } function fix_row (line, i) { var row = { }; row.date = d3.time.format.iso.parse(line[0]); if (!row.date) { console.error(line, row); return null; } row.sugar = parseInt(line[2]); return row; }