Created
April 4, 2012 21:33
-
-
Save chrisbrich/2305872 to your computer and use it in GitHub Desktop.
Data inheritance problem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Line Chart</title> | |
<link type="text/css" rel="stylesheet" href="test.css"></script> | |
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.0.0"></script> | |
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.time.js?2.0.0"/></script> | |
</head> | |
<body> | |
<script type="text/javascript" src="test.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
font: 10px sans-serif; | |
} | |
.gridlines line { | |
shape-rendering: crispEdges; | |
stroke-width: 1.5px; | |
fill: none; | |
} | |
.gridlines line.line { | |
stroke: #eee; | |
} | |
line.edge { | |
stroke: gray; | |
stroke-linecap: square; | |
shape-rendering: crispEdges; | |
stroke-width: 1.5px; | |
fill: none; | |
} | |
.line{ | |
stroke-width: 1.5px; | |
fill: none; | |
} | |
circle.datapoint { | |
fill: #fff; | |
} | |
rect.uiholder{ | |
stroke: #000; | |
fill: steelblue; | |
} | |
rect.plotarea { | |
stroke: #000; | |
stroke-linejoin: miter; | |
fill: white; | |
fill-opacity: 0.0; | |
} | |
rect.background.legend{ | |
stroke: #000; | |
stroke-linejoin: miter; | |
fill: white; | |
fill-opacity: 0.0; | |
} | |
div.plot{ | |
float: left; | |
} | |
div.testplot{ | |
float: left; | |
} | |
.axis { | |
shape-rendering: crispEdges; | |
} | |
.axis line, .axis path { | |
fill: none; | |
stroke: lightgrey; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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())} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment