Adding dots to D3.js graph

2019-07-26 15:30发布

I am a novice to D3, and need to create a graph of two data sets.

I was able to create this, after adapting code that I found here, and was able to make things work with my JSON data, but have not been able to incorporate dots or the stroke into my version.

I tried to make a "dots" variable in the same fashion as the "lines" variable:

var dots = canvas.selectAll(".dot")
     .data(dataArray, function(d){ return line(d.values);})
    .enter()
    .append("circle")
    .attr("class", "dot")
    .attr("cx", line.x())
    .attr("cy", line.y())
    .attr("r", 3.5);

but ran into problems with what appears to be accessing the individual data arrays in my code.

Any help is appreciated, my entire code is below:

  <!DOCTYPE html>
  <html>
  <head>
  <style>
      body {
        font: 10px sans-serif;
      }

      .axis path, .axis line {
        fill: none;

        shape-rendering: crispEdges;
      }

      .line {

      }

      .area {
        fill: steelblue;
        opacity: 0.5;
      }


      .dot {
        fill: steelblue;
        stroke: steelblue;
        stroke-width: 1.5px;
      }
  </style>  
  </head>
  <body>
  <div id="disp"></div>
  <script src="https://d3js.org/d3.v3.min.js"></script>
  <script>

         var dataArray = [
          {
          category: 'red',
          values: [0, 4, 9, 4, 4, 7]
          },

         {
          category: 'blue',
          values: [0, 10, 7, 1, 1, 11]
         }
      ];

      var canvas = d3.select('#disp')
      .append('svg')
      .attr('width', 400)
      .attr('height', 200);

      var x = d3.scale.linear()
              .domain([0, 8]) 
              .range([0, 700]);

      var y = d3.scale.linear()
              .domain([0, 20])
              .range([200, 0]);  

      var line = d3.svg.line()
          .interpolate("cardinal")
          .x(function(d, i) { return x(i); })
          .y(function(d, i) { return y(d); });

      var area = d3.svg.area()
      .interpolate("cardinal")
      .x(line.x())
      .y1(line.y())
      .y0(y(0));

      var lines = canvas.selectAll('.line')
          .data( dataArray, function(d) {  return d.category; } );  

          lines.enter()
          .append('path')
          .attr('class', 'line')
          .attr("d", function(d) { return line(d.values);})
          .style("stroke", function(d) {return d.category;})
          .attr("class", "area")
          .style("fill",  function(d) {return d.category;})
          .attr("d", function(d) { return area(d.values);});

  </script>
  </body>
  </html>

1条回答
Juvenile、少年°
2楼-- · 2019-07-26 16:15

Break your graph up into the 3 things you want, a filled area, a line on top (of different opacity) and then a collection of circles. Here's some commented and run-able code:

<!DOCTYPE html>
<html>

<head>
  <style>
    body {
      font: 10px sans-serif;
    }
    
    .axis path,
    .axis line {
      fill: none;
      shape-rendering: crispEdges;
    }
    
    .line {
      fill: none;
      stroke-width: 3px;
      
    }
    
    .area {
      fill: steelblue;
      opacity: 0.5;
    }
    
    .dot {
      fill: steelblue;
      stroke: steelblue;
      stroke-width: 1.5px;
    }
  </style>
</head>

<body>
  <div id="disp"></div>
  <script src="//d3js.org/d3.v3.min.js"></script>
  <script>
    var dataArray = [{
        category: 'red',
        values: [0, 4, 9, 4, 4, 7]
      },

      {
        category: 'blue',
        values: [0, 10, 7, 1, 1, 11]
      }
    ];

    var canvas = d3.select('#disp')
      .append('svg')
      .attr('width', 400)
      .attr('height', 200);

    var x = d3.scale.linear()
      .domain([0, 8])
      .range([0, 700]);

    var y = d3.scale.linear()
      .domain([0, 20])
      .range([200, 0]);

    var line = d3.svg.line()
      .interpolate("cardinal")
      .x(function(d, i) {
        return x(i);
      })
      .y(function(d, i) {
        return y(d);
      });

    var area = d3.svg.area()
      .interpolate("cardinal")
      .x(line.x())
      .y1(line.y())
      .y0(y(0));

    var lines = canvas.selectAll('.category')
      .data(dataArray, function(d) {
        return d.category;
      });

    // on enter append a g to hold our 3 parts
    var lE = lines.enter()
      .append('g')
      .attr('class', 'category')
    
    // append a path that's our solid line on top of the area
    lE.append("path")
      .attr('class', 'line')
      .attr("d", function(d) {
        return line(d.values);
      })
      .style("stroke", function(d) {
        return d.category;
      })
      
    //apend a path that's our filled area
    lE.append("path")
      .attr("class", "area")
      .style("fill", function(d) {
        return d.category;
      })
      .attr("d", function(d) {
        return area(d.values);
      });
    
    // create a subselection for our "dots"
    // and on enter append a bunch of circles
    lE.selectAll(".dot")
      .data(function(d){
        return d.values
      })
      .enter()
      .append("circle")
      .attr("r", 3)
      .attr("cx", function(d,i){
        return x(i);
      })
      .attr("cy", function(d){
        return y(d);
      })
      .attr("fill", function(d){
        return d3.select(this.parentNode).datum().category;
      });

  </script>
</body>
  

查看更多
登录 后发表回答