简体   繁体   中英

How to append a circle to each point of each valueline in d3js?

I have created a multiline chart from an array of objects with nested data, however the circles are only appended to 1 line. I am using react on the frontend and getting the data from a rest api, As shown in this image Example The lines are created and the tooltip on the circles works properly but only one line has circles appended.

Object.values(data).forEach(item => {
      var valueline = d3
        .line()
        .x(function(d) {
          return x(d.circuit);
        })
        .y(function(d) {
          return y(+d.points);
        });
      var colorScale = d3
        .scaleSequential(interpolateRainbow) //.scaleSequential(d3.interpolateRainbow)
        .domain([1, 20]);
      console.log(colorScale(1));
      svg
        .append("path")
        .data([item.results])
        .attr("class", "line")
        .style("stroke", colorScale(item.constructor))
        .attr("d", valueline);

        var xScale = d3
        .scaleLinear()
        .domain([0, item.results.length-1]) // input
        .range([0, width]); // output

        var div = d3.select("body").append("div")   
        .attr("class", "tooltip")               
        .style("opacity", 0);
      svg
        .selectAll(".dot")
        .data(item.results)
        .enter()
        .append("circle") // Uses the enter().append() method
        .attr("class", "dot")
        .attr("r", 5) // Assign a class for styling
        .attr("cx", function(d, i) {
          return xScale(i);
        })
        .attr("cy", function(d, i) {

          return y(d.points);
        }).on("mouseover", function(d) {        
         let points = item.results.filter(xd => xd.circuit==d.circuit)[0].points
          div.transition()      
              .duration(200)        
              .style("opacity", .9);        
          div   .html(item.name + "<br/>"  + points)    
              .style("left", (d3.event.pageX) + "px")       
              .style("top", (d3.event.pageY - 28) + "px");  
          })                    
      .on("mouseout", function(d) {     
          div.transition()      
              .duration(500)        
              .style("opacity", 0); 
      });

Try the changes below noting the use of an iterator to differentiate the class/selection of dots for each line. You could use something else like an attribute of the data eg name etc.

Also not i've moved the line and color scale functions out of your forEach loop as they don't need to be declared multiple times. The same applies to your tooltip which could resused instead of adding multiple divs to the DOM.

var valueline = d3
 .line()
 .x(function(d) {
   return x(d.circuit);
 })
 .y(function(d) {
   return y(+d.points);
 });    

var colorScale = d3
    .scaleSequential(interpolateRainbow) //.scaleSequential(d3.interpolateRainbow)
    .domain([1, 20]);
  console.log(colorScale(1));

var div = d3.select("body").append("div")   
    .attr("class", "tooltip")               
    .style("opacity", 0);

Object.values(data).forEach((item,k) => {

  svg
    .append("path")
    .data([item.results])
    .attr("class", "line")
    .style("stroke", colorScale(item.constructor))
    .attr("d", valueline);

    var xScale = d3
    .scaleLinear()
    .domain([0, item.results.length-1]) // input
    .range([0, width]); // output

  svg
    .selectAll(".dot-"+k)
    .data(item.results)
    .enter()
    .append("circle") // Uses the enter().append() method
    .attr("class", "dot-"+k)
    .attr("r", 5) // Assign a class for styling
    .attr("cx", function(d, i) {
      return xScale(i);
    })
    .attr("cy", function(d, i) {

      return y(d.points);
    }).on("mouseover", function(d) {        
     let points = item.results.filter(xd => xd.circuit==d.circuit)[0].points
      div.transition()      
          .duration(200)        
          .style("opacity", .9);        
      div   .html(item.name + "<br/>"  + points)    
          .style("left", (d3.event.pageX) + "px")       
          .style("top", (d3.event.pageY - 28) + "px");  
      })                    
  .on("mouseout", function(d) {     
      div.transition()      
          .duration(500)        
          .style("opacity", 0); 
  });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM