d3.js Checking/Count series chart

后端 未结 1 994
孤城傲影
孤城傲影 2021-01-02 01:42

I am working on an application that uses foursquare data.

//this is the series chart that has had some delving into - but there are some bugs still running around h

相关标签:
1条回答
  • 2021-01-02 02:17

    I'm not sure I understand what is your problem but I've decided to try to create that chart from you screenshot with sample data from your plunker. Here is my result:

    My script is making sure that smaller circle is always on top of the rage one so both circles are always visible. Here you can find my code:

    <!DOCTYPE html>
    
    <head>
      <meta charset="utf-8">
      <script src="https://d3js.org/d3.v5.min.js"></script>
      <style>
        html {
          font-family: sans-serif;
        }
      </style>
    </head>
    
    <body>
      <div id="container">
    
      </div>
    
      <script>
        const data = [{
          "name": "Twitter",
          "vists": "15 billion",
          "unit": "per day",
          "layer1value": 15000000,
          "layer2value": 450
        }, {
          "name": "Facebook",
          "vists": "5 billion",
          "unit": "per day",
          "layer1value": 4000000,
          "layer2value": 5000000
        }, {
          "name": "Google",
          "vists": "5 billion",
          "unit": "per day",
          "layer1value": 5000000,
          "layer2value": 25000
        }, {
          "name": "Netflix",
          "vists": "10 billion",
          "unit": "per day",
          "layer1value": 3000000,
          "layer2value": 2200
        }, {
          "name": "Ebay",
          "vists": "8 billion",
          "unit": "per day",
          "layer1value": 2500000,
          "layer2value": 4900000
        }, {
          "name": "Klout",
          "vists": "2 billion",
          "unit": "per day",
          "layer1value": 1000000,
          "layer2value": 45
        }];
    
        /*
         * Finding max and min layer size
         */
        const values = data.reduce((acumulator, datum) => [...acumulator, datum.layer1value, datum.layer2value], []);
        const maxValue = Math.max(...values);
        const minValue = Math.min(...values);
    
        /*
         * Creating scale based on the smallest and largest layer1value or layer2value
         */
        const radiusScale = d3.scaleLinear()
          .domain([minValue, maxValue])
          .range([10, 150]); // min and max value of the circle
    
        const width = 900;
        const height = 500;
        const orangeColour = '#ffb000';
        const blueColour = '#00a1ff';
    
        // Creating svg element
        const svg = d3.select('#container').append('svg').attr('width', width).attr('height', height);
    
        let xPos = 0; // position of circle
        /*
         * iterate over each datum and render all associated elements: two circles, and two labels with pointer lines
         */
        for (let i = 0; i < data.length; i++) {
          const d = data[i]; // current data point
          const currMaxRadius = radiusScale(Math.max(d.layer1value, d.layer2value)); // get largest radius within current group of two layers
          xPos += currMaxRadius; // add that radius to xPos
    
          // create group element containing all view elements for current datum
          const group = svg.append('g')
            .attr('transform', `translate(${xPos}, ${height / 2})`);
    
          group.append('circle')
            .attr('r', radiusScale(d.layer1value))
            .style('fill', blueColour);
          group.insert('circle', d.layer2value > d.layer1value ? ':first-child' : null) // if layer2value is larger than layer1value then insert this circle before the previous one
            .attr('r', radiusScale(d.layer2value))
            .style('fill', orangeColour);
          xPos += currMaxRadius * 0.9;
    
          /*
           * ADDING LABEL UNDERNEATH THE CIRCLES
           */
          group.append('text')
            .text(d.name)
            .attr('dy', radiusScale(maxValue) + 40) // add 40px of padding so label is not just bellow the circle
            .style('text-anchor', 'middle');
    
          group.append('line')
            .attr('y1', radiusScale(d.layer2value))
            .attr('y2', radiusScale(maxValue) + 20) // add 20px of padding so the pointer line is not overlapping with label
            .style('stroke', orangeColour);
    
    
          /*
           * ADDING LABEL AT THE ANGLE OF 45deg RELATIVE TO THE CIRCLES
           */
          // we are creating new group element so we can easily rotate both line and label by -45deg
          const rotatedLabelGroup = group.append('g').style('transform', 'rotate(-45deg)');
          rotatedLabelGroup.append('line')
            .attr('x1', radiusScale(d.layer2value))
            .attr('x2', radiusScale(maxValue) + 20)
            .style('stroke', orangeColour);
          rotatedLabelGroup.append('text')
            .text(d.vists)
            .attr('dx', radiusScale(maxValue))
            .attr('dy', -5); // this way label is slightly above the line
        }
      </script>
    </body>

    0 讨论(0)
提交回复
热议问题