Chew Kah Meng
Chew Kah Meng

Reputation: 227

How to toggle data points on and off along with lines in multi-line chart

I am trying to toggle data points in my line chart when the legend is clicked. Here is the link to my fiddle. From my fiddle, when the legend is clicked, the lines and the corresponding axis will be toggled on and off but the points do not. The relevant code is as follows.

    //************* Lines and Data Points ***************
    var colors = ["blue", "red"];

    var thisScale;

    var line = d3.line()
      .x(d => x(d.x))
      .y(d => thisScale(d.y))
      .curve(d3.curveLinear);

    var paths = g.selectAll("foo")
      .data(data)
      .enter()
      .append("path");

    paths.attr("stroke", function (d,i){return colors[i]})
      .attr("d", d => {
        thisScale = yScale[d.yAxis]
        return line(d.data);
      })
      .attr("stroke-width", 2)
      .attr("id", function (d,i){return "line" + i})
      .attr("fill", "none");

    var pointsGroup = g.selectAll(null)
      .data(data)
      .enter()
      .append("g")
      .attr("fill", function(d, i) {
        local.set(this, yScale[i])
        return colors[i];
      });

    var points = pointsGroup.selectAll(null)
      .data(function(d) {
        return d.data
      })
      .enter()
      .append("circle")
      .attr("cx", function(d) {
        return x(d.x);
      })
      .attr("cy", function(d, i) {
        return local.get(this)(d.y);
      })
      .attr("r", 3)
      .attr("class", function(d, i) {
        return "dots" + i;
      })
      .attr("clip-path", "url(#clip)")
      .on("mouseover", mouseover)
      .on("mouseleave", mouseleave)

    //************* Legend ***************
    var legend = svg.selectAll(".legend")
    .data(data)
    .enter().append("g")

    legend.append("rect")
      .attr("x", width + 65)
      .attr("y", function(d, i) {
      return 30 + i * 20;
    })
      .attr("width", 18)
      .attr("height", 4)
      .style("fill", function(d, i) {
      return colors[i];
    })

    legend.append("text")
      .attr("x", width + 60)
      .attr("y", function(d, i) {
      return 30 + i * 20;
    })
      .attr("dy", ".35em")
      .style("text-anchor", "end")
      .text(function(d, i) {
      return "Value" + (i + 1);
    })
      .on("click", function(d, i) {
      // Determine if current line is visible
      let opacity = d3.select("#line" + i).style("opacity");
      let newOpacity;
      if (opacity == 0) {
        newOpacity = 1;
      }else {
        newOpacity = 0
      }
      d3.select("#line" + i).style("opacity", newOpacity);
      d3.selectAll("dots" + i).style("opacity", newOpacity);
      d3.select("#ySecAxis" + i).style("opacity", newOpacity);
      d3.select("#yAxisLabel" + i).style("opacity", newOpacity);            
    });

I have attributed the class to my points .attr("class", function(d, i) { return "dots" + i; }) and tried to allow the points to be toggled by using d3.selectAll("dots" + i).style("opacity", newOpacity); However, it is not working, anyone knows what could be the issue?

Upvotes: 0

Views: 111

Answers (1)

Tom Shanley
Tom Shanley

Reputation: 1787

you need to make 2 changes

1 - Assign the dots class to the parent g element, so the i variable is only iterated per group of dots. Don't use assign class on the dots themselves.

var pointsGroup = g.selectAll(null)
  .data(data)
  .enter()
  .append("g")
  .attr("class", function(d, i) {
    return "dots" + i
  })
  .attr("fill", function(d, i) {
    local.set(this, yScale[i])
    return colors[i];
  });

2 - Select the dots class by including "." in the selection name

d3.selectAll(".dots" + i).style("opacity", newOpacity);

Upvotes: 1

Related Questions