10. The data-date attribute and its corresponding bar element should align with the corresponding value on the x-axis

All my tests are passing except for: 10. The data-date attribute and its corresponding bar element should align with the corresponding value on the x-axis.

I have a feeling it has something to do with the fact that I converted the dates to unix dates in order to scale the bars but on the axis I’m using the years as is. Anyone have any ideas on how to fix this?

My codepen: https://codepen.io/marcods/pen/GejRjM
Here’s my code as it stands:

// Setup
req = new XMLHttpRequest();
req.open("GET", "https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json", true);
req.send();
let data = {};

req.onload = function() {
  // Fetch data
  json = JSON.parse(req.responseText);
  let html = "";
  data = json.data;
  
  // D3
  const h = 800;
  const w = 1000;
  const padding = 40;
  const barWidth = "4px"
  
  const dateRegex = /\d{4}/;
  const dateArray = data.map((item)=> item[0].match(dateRegex));
  const unixArray = data.map((item)=> new Date(item[0]).getTime()/1000);
  data.forEach(item => item.push( new Date(item[0]).getTime()/1000 ));
  console.log(unixArray)
  
  const svg = d3.select(".chart")
                .attr("width", w)
                .attr("height", h)
  
  const xScale = d3.scaleLinear()
                   .domain([ d3.min(dateArray), d3.max(dateArray) ]) 
                   .range([ padding, w - padding ]);
  
  const yScale = d3.scaleLinear()
                   .domain([ 0, d3.max(data, (d)=> d[1] ) ])
                   .range([ h - padding, padding ]);
  
  const unixScale = d3.scaleLinear()
                      .domain([ d3.min(data, (d)=> d[2] ), d3.max(data, (d)=> d[2] ) ])
                      .range([ padding, w - padding ]);
  
  // Create Tooltips
  let tooltip = d3.select("body")
                  .append("div")
                  .attr("class", "tooltip")
                  .attr("id", "tooltip")
                  .style("opacity", 100)
  
  // Create the Bars
  svg.selectAll("rect")
     .data(data)
      .enter()
      .append("rect")
      .attr("class", "bar")
      .attr("fill", "green")
      .attr("x", function(d,i){ return unixScale(d[2]) }) // need to fix
      .attr("y", function(d,i){ return yScale(d[1]) })
      .attr("width", barWidth)
      .attr("height", function(d){ return d[1]/25 + "px" })
      .attr("data-date", (d) => d[0] )
      .attr("data-gdp", (d)=> d[1] )
      .on("mouseover", function(d){
        tooltip.transition()
               .duration(200)
               .style("opacity", 0.9);
        tooltip.html("Date:" + d[0] + "<br>$" + d[1] + " Billion")
               .style("left", d3.event.pageX + 20 + "px")
               .style("top", d3.event.pageY + 20 + "px");
        tooltip.attr("data-date", d[0])
      })
      .on("mouseout", function(d){
        tooltip.transition()
               .duration(400)
               .style("opacity", 0);
      });
  
  // Create bottom axis
  const xAxis = d3.axisBottom(xScale);
  svg.append("g")
    .attr("transform", "translate( 0, " + ( h  - padding ) + ")")
    .attr("id", "x-axis")
    .call(xAxis);
  
  const yAxis = d3.axisLeft(yScale);
  svg.append("g")
    .attr("transform", `translate( ${padding}, 0)`)
    .attr("id", "y-axis")
    .call(yAxis);
}
2 Likes

I finally figured it out. The key was to use d3.scaleTime instead of d3.scaleLinear. It works with unix dates.

3 Likes

I was doing the same mistake by using d3.scaleLinear. Thank you so much for the key. Absurdly I was using a numeric value of 1,947 on my x-axis instead of a YYYY value. Hence using scaleTime instead saved me from all the drama. The price I pay for not being aware of what I am doing.

1 Like