How to download data based on current selection only?

  Kiến thức lập trình

I have a simple chart I built with d3.js. There’s a dropdown to filter between different views of the data, and want the user to be able to download the associated data based on their selection.

Using fileSaver.js, I’m able to make the download happen. However, after switching from the default selection (apples) to something else (like pears), multiple CSVs are downloaded. Is it possible to get the data only from the current selection?

var margin = { top: 50, right: 20, bottom: 30, left: 60 },
      width = 1000 - margin.left - margin.right,
      height = 550 - margin.top - margin.bottom;

    var x = d3.scaleTime().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);

    var xAxis = d3.axisBottom(x)
      .ticks(5)
    const parseTime = d3.utcParse("%Y");

    var yAxis = d3.axisLeft(y).ticks(5);

    var line = d3.line()
      .x(function (d) { return x(d.year); })
      .y(function (d) { return y(d.value); })
      .curve(d3.curveBasis);

    var color = d3.scaleOrdinal()
      .range(['royalblue', 'green', 'pink']);

    var svg = d3.select("#chart")
      .append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform",
        "translate(" + margin.left + "," + margin.top + ")");

    d3.csv("https://raw.githubusercontent.com/sprucegoose1/sample-data/main/fruit.csv").then(function (csv) {

      csv.forEach(function (d) {
        d.value = +d.value;
        d.year = parseTime(d.year);
      });

      x.domain(d3.extent(csv, function (d) { return d.date; }));

      initData = csv.filter(function (d) { return d.produce == 'apples' })
      updateGraph(initData)

      d3.select('#inds')
        .on("change", function () {
          var sect = document.getElementById("inds");
          var section = sect.options[sect.selectedIndex].value;

          data = csv.filter(function (d) { return d.produce == section })

          data.forEach(function (d) {
            d.value = +d.value;
            d.active = true;
          });
          updateGraph(data);

        });

      data = csv.filter(function (d) { return d.produce == 'apples' })
      updateGraph(data);
    });

    function updateGraph(data) {

      x.domain(d3.extent(data, function (d) { return d.year; }));
      y.domain([d3.min(data, function (d) { return d.value; }), d3.max(data, function (d) { return d.value; })]);

      let dataNest = d3.group(data, d => d.state)

      let dataNestArray = Array.from(dataNest.keys());

      var state = svg.selectAll(".line")
        .data(dataNest, function (d) { return d[0] });

      state.enter().append("path")
        .attr("class", "line");

      state.transition()
        .style("stroke", "#333")
        .attr("d", d => {
          d.line = this;
          return line(d[1]);
        })
        .style("stroke", d => color(d[0]))

      state.exit().remove();

      var legend = d3.select("#legend")
        .selectAll("text")
        .data(dataNest, function (d) { return d.key });

      svg.selectAll(".axis").remove();

      svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

      svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

      downloadData('download', data, 'data.csv')

    };

    function downloadData(buttonID, data, filename) {

      let a = document.getElementById(buttonID);
      a.addEventListener('click', function (e) {

        let blob = new Blob([d3.csvFormat(data)],
          { type: "text/csv;charset=utf-8" });
        saveAs(blob, filename);
      })
    }
body {
      font: 12px Arial;
    }

    path {
      stroke: #ccc;
      stroke-width: 2;
      fill: none;
    }

    .axis path,
    .axis line {
      fill: none;
      stroke: grey;
      stroke-width: 1;
      shape-rendering: crispEdges;
    }

    #legendContainer {
      position: absolute;
      top: 60px;
      left: 10px;
      overflow: auto;
      height: 490px;
      width: 110px;
    }

    #legend {
      width: 90px;
      height: 200px;
    }

    .legend {
      font-size: 12px;
      font-weight: normal;
      text-anchor: left;
    }

    .legendcheckbox {
      cursor: pointer;
    }

    input {
      border-radius: 5px;
      padding: 5px 10px;
      background: #999;
      border: 0;
      color: #fff;
    }

    #inds {
      position: absolute;
      top: 10px;
      left: 10px;
    }

    #download {
      margin-top: 30px;
      margin-left: 30px;
      text-decoration: underline;
      color: darkred;
      cursor: pointer;
    }
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/FileSaver.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.0/d3.min.js"></script>
<select id="inds">
    <option value="apples" selected="selected">apples</option>
    <option value="pears">pears</option>
    <option value="tomatoes">tomatoes</option>
  </select>
  <div id="chart"></div>
  <div id="download">Download Data</div>

LEAVE A COMMENT