|
function createViz() { |
|
d3.csv("test.csv",type, function (error, data) { |
|
if (error) throw error; |
|
|
|
dataViz(data) |
|
}); |
|
} |
|
|
|
function dataViz(data) { |
|
|
|
//setup tooltip div & nav rect |
|
var tooltip = d3.select("#tooltip") |
|
.style("opacity", 0); |
|
|
|
// Parse the date / time |
|
var formatDate = d3.time.format("%d-%b"), |
|
formatMth = d3.time.format("%m-%d"), |
|
formatYear = d3.time.format("%Y"); |
|
|
|
var bisect = d3.bisector(function(d) { return d.xPos; }).right; |
|
|
|
data.forEach(function(d,i) { |
|
d.xPos = formatMth(d.date); |
|
}); |
|
|
|
var margin = {top: 5, right: 10, bottom: 5, left: 10}, |
|
width = 960 - margin.left - margin.right, |
|
height = 100 - margin.top - margin.bottom; |
|
|
|
//this works as an x domain with range bands |
|
var x = d3.scale.ordinal().rangeRoundBands([0, width], 0.2); |
|
var y = d3.scale.linear().range([0,height]); |
|
|
|
var dataPerYear = d3.nest() |
|
.key(function(d) { return formatYear(d.date);}) |
|
.entries(data); |
|
|
|
|
|
//x.domain(),needs to have "02-29" added manually |
|
//have tried this but it just gets added to the end |
|
//x.domain(data.map(function(d) { return d.xPos, "02-29"; })); |
|
// x.domain(data.map(function(d) { return d.xPos; })); |
|
var leapYearDays = [];// will be populated with all dates |
|
var currentDate = new Date(2016, 0, 1);// the date we'll be incrementing |
|
var safety = 0;// helps prevent infinite looping during development |
|
|
|
while(safety < 400 && currentDate.getFullYear() == 2016) { |
|
leapYearDays.push(formatMth(currentDate)); |
|
currentDate.setDate(currentDate.getDate() + 1); |
|
safety++; |
|
} |
|
|
|
x.domain(leapYearDays.map(function(d) { return d; })); |
|
y.domain([0, d3.max(data, function(d) { return d.rain; })]); |
|
|
|
var svg = d3.select("#chart").selectAll("svg") |
|
.data(dataPerYear) |
|
.enter().append("svg") |
|
.attr("class", "charts") |
|
.attr("width", width + margin.left + margin.right) |
|
.attr("height", height + margin.top + margin.bottom) |
|
.append("g") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
svg.append("text") |
|
.attr("class", "year") |
|
.attr("transform", "rotate(-90)") |
|
.attr("y", 100) |
|
.attr("x",0 - (height / 2)) |
|
.attr("dy", "1em") |
|
.style("text-anchor", "middle") |
|
.text(function(d) { return d.key; }); |
|
|
|
svg.selectAll(".bar") |
|
.data(function(d) {return d.values;}) |
|
.enter().append("rect") |
|
.attr("class", "bar") |
|
.attr("x", function(d) { return x(formatMth(d.date)); }) |
|
.style("fill", function(d) { return d.date.getMonth() == 1 && d.date.getDate() == 29 ? "red" : null}) |
|
.attr("y", 0) |
|
.attr("width", x.rangeBand()) |
|
.attr("height", 0) |
|
.transition() |
|
.duration(1000) |
|
.ease("quad") |
|
.attr("height", function(d) { return y(d.rain); }); |
|
|
|
var focus = svg.append("g"); |
|
focus.style("display", "none"); |
|
|
|
// append the rect at the intersection |
|
focus.append("rect") |
|
.attr("class", function(d) { return "y"+d.key; }) |
|
.style("opacity", 0.5) |
|
.style("fill", "none") |
|
.attr("width", x.rangeBand()) |
|
.attr("height", height); |
|
|
|
// append the rectangle to capture mouse |
|
svg.append("rect") |
|
.attr("width", width + margin.left + margin.right) |
|
.attr("height", height + margin.top + margin.bottom) |
|
.attr("id", function(d,i) { return i; }) |
|
.attr("chartID", function(d,i) { return i; }) |
|
.attr("yearID", function(d) { return d.key; }) |
|
.style("fill", "none") |
|
.style("pointer-events", "all") |
|
.on("mouseover", mouseover) |
|
.on("mouseout", mouseout) |
|
.on("mousemove", mousemove); |
|
|
|
function mousemove() { |
|
//use this for inverting ordinal scale https://stackoverflow.com/questions/20758373/inversion-with-ordinal-scale (sepans in the comments) |
|
var chartID = d3.select(this); |
|
var keyID = chartID.attr("chartID"); |
|
var yearID = chartID.attr("yearID"); |
|
var id = document.getElementById(keyID); |
|
|
|
//for using getBoundingClientRect() http://help.dottoro.com/ljvmcrrn.php |
|
var yPosPerChart = parseInt(id.getBoundingClientRect().top+20); |
|
|
|
var domain = x.domain(), |
|
xpos = d3.mouse(this)[0], |
|
range = x.range(); |
|
|
|
|
|
|
|
var x0 = domain[d3.bisect(range, xpos) - 1], |
|
i = bisect(dataPerYear[keyID].values, x0), |
|
d0 = dataPerYear[keyID].values[i - 1], |
|
d1 = dataPerYear[keyID].values[i]; |
|
d = x0 - d0.date > d1.date - x0 ? d1 : d0; |
|
|
|
|
|
|
|
tooltip.transition() |
|
.duration(50) |
|
.style("opacity", .9); |
|
|
|
tooltip.html("<i>"+formatDate(d.date)+","+yearID+"</i><br>rainfall: "+d.rain+"mm") |
|
.style("left", (d3.event.pageX+20) + "px") |
|
.style("top", (d3.event.pageY+20) + "px"); |
|
|
|
//detect yPos |
|
//.style("top", yPosPerChart + "px"); |
|
|
|
|
|
focus.style("display", null); |
|
|
|
focus.select("rect.y"+yearID) |
|
.attr("transform", |
|
"translate(" + x(formatMth(d.date)) + ",0)") |
|
.style("fill", "pink"); |
|
} |
|
|
|
function mouseover() { |
|
tooltip.style("opacity",.9); |
|
} |
|
|
|
function mouseout(){ |
|
tooltip.style("opacity", 0); |
|
|
|
focus.select("rect") |
|
.style("fill", "none"); |
|
|
|
focus.style("display", "none"); |
|
|
|
} |
|
} |
|
|
|
function type(d) { |
|
//var format = d3.time.format("%d-%b-%Y"); |
|
var format = d3.time.format("%d-%b-%y"); |
|
d.rain = +d.rain; |
|
d.date = format.parse(d.date); |
|
return d; |
|
} |
|
|