var blarg = [[[{"title":"1","data":[{"x":1,"y":1},{"x":2,"y":2},{"x":3,"y":3},{"x":4,"y":4}]}, {"title":"2","data":[{"x":1,"y":1},{"x":2,"y":4},{"x":3,"y":9},{"x":4,"y":16}]}], [{"title":"3","data":[{"x":1,"y":1},{"x":2,"y":8},{"x":3,"y":27},{"x":4,"y":64}]}]], [[{"title":"4","data":[{"x":1,"y":2},{"x":2,"y":20},{"x":3,"y":40},{"x":4,"y":65}]}]]]; //For testing date purposes var currenttime = new Date().getTime(); var blargtime = [[[{"title":"1","data":[{"x":new Date(currenttime - (60 * 1000 * 1)),"y":1},{"x":new Date(currenttime - (60 * 1000 * 2)),"y":2}, {"x":new Date(currenttime - (60 * 1000 * 3)),"y":3},{"x":new Date(currenttime - (60 * 1000 * 4)),"y":4}]}, {"title":"2","data":[{"x":new Date(currenttime - (60 * 1000 * 1)),"y":1},{"x":new Date(currenttime - (60 * 1000 * 2)),"y":4}, {"x":new Date(currenttime - (60 * 1000 * 3)),"y":9},{"x":new Date(currenttime - (60 * 1000 * 4)),"y":16}]}], [{"title":"3","data":[{"x":new Date(currenttime - (60 * 1000 * 1)),"y":1},{"x":new Date(currenttime - (60 * 1000 * 2)),"y":8}, {"x":new Date(currenttime - (60 * 1000 * 3)),"y":27},{"x":new Date(currenttime - (60 * 1000 * 4)),"y":64}]}]], [[{"title":"4","data":[{"x":new Date(currenttime - (60 * 1000 * 1)),"y":2},{"x":new Date(currenttime - (60 * 1000 * 2)),"y":20}, {"x":new Date(currenttime - (60 * 1000 * 3)),"y":40},{"x":new Date(currenttime - (60 * 1000 * 4)),"y":65}]}]]]; //holder for plots d3.select("body").append("div") .attr("class","plots") .attr("style","float:right;width:600px;"); //div to hold plots //clickable link for updating data d3.select("body").append("a") .attr("onclick","javascript:dateredraw(blargtime[Math.round(Math.random())]);") .html("click me"); function dateredraw(d){ var blarg = timeSeriesChart(); d3.select("body div.plots").datum(d).call(blarg);} //The reusable chart function function timeSeriesChart() { //////////// //Defaults// //////////// var margin = {top: 25, right: 25, bottom: 25, left: 25}, width = 350, height = 200, legendWidth = 150, legendColorSide = 15, title = function(d){ return d.title;}, xValue = function(d) { return d.x; }, yValue = function(d) { return d.y; }, xScale = d3.time.scale(), yScale = d3.scale.linear(), xDomain = function(data){return d3.extent([].concat.apply([],data.map(function(e){return [].concat.apply([],e.map(function(d){return d3.extent(d.data,xValue)}))})))}, yDomain = function(data){return d3.extent([].concat.apply([],data.map(function(e){return [].concat.apply([],e.map(function(d){return d3.extent(d.data,yValue)}))})))}, xMin = function(data){return xDomain(data)[0]}, //assumes data is an array of objects xMax = function(data){return new Date()}, //i.e. [{"title": "blarg" "data":[{}...]},{...}] yMin = function(data){return yDomain(data)[0]}, yMax = function(data){return yDomain(data)[1]}, xAxis = d3.svg.axis().scale(xScale).orient("bottom").tickSize(-height), yAxis = d3.svg.axis().scale(yScale).orient("left").tickSize(-width), colors = d3.scale.category10(); // check that ymin and ymaxs are different if (yMin == yMax){ var yeps = Math.pow(10,Math.floor(Math.log(yMin) / Math.LN10)); yMin = yMin - yeps; yMax = yMax + yeps;}; /////////////// //Plot/Replot// /////////////// function chart(selection) { selection.each(function(data) { // Update the x-scale. xScale .domain([xMin(data),xMax(data)]) .range([0, width]); // Update the y-scale. yScale .domain([yMin(data),yMax(data)]) .range([height, 0]).nice(); xAxis.scale(xScale); yAxis.scale(yScale); ////////// //Enters// ////////// // Select the svg element, if it exists. var svg = d3.select(this).selectAll("svg").data(data); //.data([data]) // Otherwise, create the skeletal chart. var gEnter = svg.enter().append("svg") .append("g"); // Axis gEnter.append("g").attr("class", "x axis"); gEnter.append("g").attr("class", "y axis"); // Cursor indicator var tind = gEnter.append("svg:text") .attr("class","position-indicator") .attr("text-anchor","middle"); // Everything in plotarea will have its position displayed when mouse is over it var plotarea = gEnter.append("svg:g").attr("class","plotarea"); // Display x/y coordinates on hover for everything in plotarea plotarea.on("mouseover",function(d,i){ plotarea.on("mousemove",function(){ var b = d3.svg.mouse(this); if (tind[0][i]) { d3.select(tind[0][i]) .text(dateToString(xScale.invert(b[0])) + " , " + yScale.invert(b[1]).toPrecision(4));}});}) .on("mouseout",function(){ plotarea.on("mousemove",function(){ return false;})}) .append("svg:rect") .attr("class", "plotarea"); ///Legend gEnter.append("svg:g") .attr("class","legend") .append("svg:rect") .attr("class","legend background"); //NOT UPDATING PROPERLY// var lgd = d3.selectAll("g.legend"); var lgddatasets = lgd.selectAll("g.dataset_legend") .data(function(d){console.log(d);return d},function(d){return d.title}); var s = lgddatasets.enter().append("svg:g") .attr("class",function(d){return "dataset_legend " + title(d)}) .attr("transform",function(d,i){return "translate(0," + i*legendColorSide + ")"}); s.append("svg:rect") .attr("width",legendColorSide) .attr("height",legendColorSide) .attr("fill",function(d,i){console.log(i);return colors(i%10)}); s.append("svg:text") .attr("x",legendColorSide) .attr("y",legendColorSide/2) .attr("dy",".35em"); // Datasets //NOT UPDATING PROPERLY// var test = d3.selectAll("g.plotarea"); var ds = test.selectAll("g.dataset") .data(function(d){return d},title); var set = ds.enter().append("svg:g") .attr("class", function(d){return "dataset " + title(d)}) .attr("stroke", function(d,i){return colors(i%10)}); var myline = d3.svg.line() .x(function(b) { return xScale(xValue(b)); }) .y(function(b) { return yScale(yValue(b)); }); set.append("svg:path") .attr("class", function(d){return "line " + title(d)}); var datapoint = set.selectAll("circle.datapoint") .data(function(d){return d.data;},function(d){return +d.x}); datapoint.enter().append("svg:circle") .attr("class", "datapoint") .attr("r", 1.5); ///////////// // Updates // ///////////// // Update the outer dimensions. svg.attr("width", width + margin.left + margin.right + legendWidth) .attr("height", height + margin.top + margin.bottom); // Update the inner dimensions. var g = svg.select("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // Update the axes. g.select(".x.axis") .attr("transform", "translate(0," + yScale.range()[0] + ")") .call(xAxis); g.select(".y.axis") .attr("transform", "translate(0," + xScale.range()[0] + ")") .call(yAxis); // Update cursor indicator g.select("text.position-indicator") .attr("x",width/2) .attr("y",0) .attr("dy","-.71em"); // Update legend var legend = g.select("g.legend") .attr("transform", "translate(" + (margin.right + width - 2) + ",0)"); legend.select("rect.background") .attr("width",legendWidth) .attr("height",height); svg.selectAll("g.dataset_legend text") .text(title); // Update plotarea var pa = g.select("g.plotarea"); pa.select("rect.plotarea") .attr("width",width) .attr("height",height); // Update datasets var dataset = svg.selectAll("g.dataset"); dataset.selectAll("path") .attr("d", function(d){return myline(d.data);}); dataset.selectAll("circle.datapoint") .attr("cx", function(d) { return xScale(xValue(d)); }) .attr("cy", function(d) { return yScale(yValue(d)); }); //////////////// ///TRANSITIONS// //////////////// //TODO// ////////// ///EXITS// ////////// svg.exit().remove(); lgddatasets.exit().remove(); ds.exit().remove(); datapoint.exit().remove(); }); } ///////////// //Accessors// ///////////// chart.margin = function(_) { if (!arguments.length) return margin; margin = _; return chart; }; chart.width = function(_) { if (!arguments.length) return width; width = _; return chart; }; chart.height = function(_) { if (!arguments.length) return height; height = _; return chart; }; chart.legendWidth = function(_) { if (!arguments.length) return legendWidth; legendWidth = _; return chart; }; chart.xMin = function(_) { if (!arguments.length) return xMin; xMin = _; return chart; }; chart.xMax = function(_) { if (!arguments.length) return xMax; xMax = _; return chart; }; chart.yMin = function(_) { if (!arguments.length) return yMin; yMin = _; return chart; }; chart.yMax = function(_) { if (!arguments.length) return yMax; yMax = _; return chart; }; chart.colors = function(_) { if (!arguments.length) return colors; colors = _; return chart; }; chart.x = function(_) { if (!arguments.length) return xValue; xValue = _; return chart; }; chart.y = function(_) { if (!arguments.length) return yValue; yValue = _; return chart; }; return chart; } //Helper functions function dateToString(d){ function pad(n){return n<10 ? '0'+n : n} var theday = ["Sun","Mon","Tues","Wed","Thurs","Fri","Sat"] return theday[d.getDay()]+" " + d.getFullYear()+'-' + pad(d.getMonth()+1)+'-' + pad(d.getDate())+' ' + pad(d.getHours())+':' + pad(d.getMinutes())+':' + pad(d.getSeconds())}