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(""+formatDate(d.date)+","+yearID+"
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; }