megfletch
megfletch

Reputation: 1

Animation is not working for d3 line chart

I am not experienced with d3. I only recently learned the basics of the language. As a student journalist, I'm really only fluent in HTML and CSS. I'm trying to make an animated line chart for school.

When I add the animation code, it does not work. I made sure all the names (not sure if that's the term) match and I have pored over others' animated line chart code to find what's going wrong. What's more is that when I try to reorder the code to put the axes below the animation, the chart completely disappears, leaving only the HTML header and footer text.

<!-- container for the visualization -->
<!DOCTYPE html>
<head>
    <!-- Load d3.js -->
    <script src="https://d3js.org/d3.v4.js"></script>
    <link href="/Users/megfletch/Desktop/line-chart-draft/src/style.css" type="text/css" rel="stylesheet" />
</head>
<header>
<h1 class="text">Proactive Community Testing — <b class="highlight">Students</b></h1>
<h4 class="text">Since school started the week of Aug. 23, proactive community testing has fluctuated.</h4>
</header>
<body>
  <svg class="viz" id="viz" width="1000" height="325">
    <div  class="viz"></div>
    <script id="chart">
      const data = [
        { date: "8/23/2020", test: 975},
        { date: "8/30/2020", test: 1841},
        { date: "9/6/2020", test: 2316},
        { date: "9/13/2020", test: 1481},
        { date: "9/20/2020", test: 1415},
        { date: "9/27/2020", test: 3076},
        { date: "10/4/2020", test: 2146},
      ];

      const margin = {
        top: 20,
        right: 20,
        bottom: 20,
        left: 20,
      };

      const width = 700 - (margin.left + margin.right);
      const height = 350 - (margin.top + margin.bottom);

        // time parse
      var parseTime = d3.timeParse("%m/%d/%Y");
              data.forEach(function (d) {
                  d.date = parseTime(d.date);
              });
        // create svg
      const svg = d3
        .select('#viz')
        .append('svg')
        .attr('viewBox', `0 0 ${width + (margin.left + margin.right)} ${height + (margin.top + margin.bottom)}`)
        .attr('width', width)
        .attr('height', height);
        const grp = chart
          .append("g")

      // include the visualization in the nested group
      const path = svg
        .append('g')
        .attr('transform', `translate(${margin.left} ${margin.right})`);

      // describe the scales for the line chart
      // x-axis: time scale using the dates
      const xScale = d3
        .scaleTime()
        .domain([new Date(data[0].date), new Date(data[data.length - 1].date)]) 
        .range([0, width])
        .nice();

      // y-axis: linear scale using the percentages
      const yScale = d3
        .scaleLinear()
        .domain(d3.extent(data, ({ test }) => test)) /
        .range([height, 0]) 
        .nice();
        
      const line = d3
        .line()
        .x(({ date }) => xScale(new Date(date))) 
        .y(({ test }) => yScale(test));

      // include the axes based on the defined scales
      const xAxis = d3
        .axisBottom(xScale);
      path
        .append('g')
        .attr('transform', `translate(0 ${height})`)
        .call(xAxis);
      const yAxis = d3
        .axisLeft(yScale);
      path
        .append('g')
        .call(yAxis);

        // add a path element using the line function
     path
          .append('path')
          .attr('d', line(data))
          .attr('fill', 'none')
          .attr('stroke', '#f5842e')
          .attr('stroke-width','3');
          
        // add a animation
        const pathLength = path.node().getTotalLength();
        const transitionPath = d3
            .transition()
            .duration(2500);
        path
          .attr("stroke-dashoffset", pathLength)
          .attr("stroke-dasharray", pathLength)
          .transition(transitionPath)
          .attr("stroke-dashoffset", 0);
      </script>
</body>
<footer>
    <h5 class="text">Source: UT Austin COVID-19 Dashboard</h5>
    </footer>

Upvotes: 0

Views: 322

Answers (1)

Tom Shanley
Tom Shanley

Reputation: 1787

  1. This line has a "/" which needs to be removed

    .domain(d3.extent(data, ({ test }) => test)) /

  2. You were using "path" which is a group for many elements. In the example below, I've created a new pathD for the path you want to animate, so that .path()getTotalLength() works on an actual path element

  const data = [
        { date: "8/23/2020", test: 975},
        { date: "8/30/2020", test: 1841},
        { date: "9/6/2020", test: 2316},
        { date: "9/13/2020", test: 1481},
        { date: "9/20/2020", test: 1415},
        { date: "9/27/2020", test: 3076},
        { date: "10/4/2020", test: 2146},
      ];

      const margin = {
        top: 20,
        right: 20,
        bottom: 20,
        left: 20,
      };

      const width = 700 - (margin.left + margin.right);
      const height = 350 - (margin.top + margin.bottom);

        // time parse
      var parseTime = d3.timeParse("%m/%d/%Y");
              data.forEach(function (d) {
                  d.date = parseTime(d.date);
              });
        // create svg
      const svg = d3
        .select('#viz')
        .append('svg')
        .attr('viewBox', `0 0 ${width + (margin.left + margin.right)} ${height + (margin.top + margin.bottom)}`)
        .attr('width', width)
        .attr('height', height);
        const grp = svg
          .append("g")

      // include the visualization in the nested group
      const path = svg
        .append('g')
        .attr('transform', `translate(${margin.left} ${margin.right})`);

      // describe the scales for the line chart
      // x-axis: time scale using the dates
      const xScale = d3
        .scaleTime()
        .domain([new Date(data[0].date), new Date(data[data.length - 1].date)]) 
        .range([0, width])
        .nice();

      // y-axis: linear scale using the percentages
      const yScale = d3
        .scaleLinear()
        .domain(d3.extent(data, ({ test }) => test))
        .range([height, 0]) 
        .nice();
        
      const line = d3
        .line()
        .x(({ date }) => xScale(new Date(date))) 
        .y(({ test }) => yScale(test));

      // include the axes based on the defined scales
      const xAxis = d3.axisBottom(xScale);
      path
        .append('g')
        .attr('transform', `translate(0 ${height})`)
        .call(xAxis);
      const yAxis = d3
        .axisLeft(yScale);
      path
        .append('g')
        .call(yAxis);

        // add a path element using the line function
     let pathD = path
          .append('path')
          .attr('d', line(data))
          .attr('fill', 'none')
          .attr('stroke', '#f5842e')
          .attr('stroke-width','3');
          
        // add a animation.
        const pathNode = pathD.node();
        const pathLength = pathNode.getTotalLength();
        const transitionPath = d3
            .transition()
            .duration(2500);
        pathD
          .attr("stroke-dashoffset", pathLength)
          .attr("stroke-dasharray", pathLength)
          .transition(transitionPath)
          .attr("stroke-dashoffset", 0);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.0.0/d3.min.js"></script>
<!-- container for the visualization -->
<!DOCTYPE html>
<head>
    <!-- Load d3.js -->
    <script src="https://d3js.org/d3.v4.js"></script>
    <link href="/Users/megfletch/Desktop/line-chart-draft/src/style.css" type="text/css" rel="stylesheet" />
</head>
<header>
<h1 class="text">Proactive Community Testing — <b class="highlight">Students</b></h1>
<h4 class="text">Since school started the week of Aug. 23, proactive community testing has fluctuated.</h4>
</header>
<body>
  <svg class="viz" id="viz" width="1000" height="325">
    <div  class="viz"></div>

</body>
<footer>
    <h5 class="text">Source: UT Austin COVID-19 Dashboard</h5>
    </footer>

Upvotes: 1

Related Questions