图例在 d3 响应图表中未正确对齐

Legend not aligned properly in d3 responsive chart

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <title>Testing Pie Chart</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
     <style type="text/css">

     #container {
        margin: 20px;
      }

     #chart {  
        position: absolute;  
        background-color: #eee;                                          
      }
      #chart legend{  
        position: absolute;  
        margin: 100px;                                        
      }                                                                 
      .tooltip {                                                        
        background: #eee;                                               
        box-shadow: 0 0 5px #999999;                                    
        color: #900C3F;                                                    
        display: inline-block;                                                  
        font-size: 12px;                                                
        left: 600px;                                                    
        padding: 10px;                                                  
        position: absolute;                                             
        text-align: center;                                             
        top: 95px;                                                      
        width: 150px;                                                    
        z-index: 10;  
        opacity: 1;                                                 
    }                                                                 
    rect {
       stroke-width: 2;
    }
    path {
        stroke: #ffffff;
        stroke-width: 0.5;
    }
    div.tooltip {
    position: absolute;
    z-index: 999;
    padding: 10px;
    background: #f4f4f4;
    border: 0px;
    border-radius: 3px;
    pointer-events: none;
    font-size: 11px;
    color:  #080808;
    line-height: 16px;
    border: 1px solid #d4d4d4;
    }

     </style>
      </head>
  <body>

    <div id="container">
    <svg id="chart" width="600" height="300" viewBox="0 0 600 300" perserveAspectRatio="xMinYMid">
    <div id="toolTip" class="tooltip" style="opacity: 0;"></div>
    <script type="text/javascript">

var div = d3.select("#toolTip");

var data = [
      {"IP":"192.168.12.1", "count":20}, 
      {"IP":"76.09.45.34", "count":40}, 
      {"IP":"34.91.23.76", "count":80},
      {"IP":"192.168.19.32", "count":16}, 
      {"IP":"192.168.10.89", "count":50}, 
      {"IP":"192.178.34.07", "count":18},
      {"IP":"192.168.12.98", "count":30}];

var width = 300,
    height = 300;
var margin = {top: 15, right: 15, bottom: 20, left: 40},
    radius = Math.min(width, height) / 2 - 10;
var legendRectSize = 18,
    legendSpacing = 4;
            

        var color = d3.scale.category20b();

        var arc = d3.svg.arc()
            .outerRadius(radius);
          
          var arcOver = d3.svg.arc()
                .outerRadius(radius + 5);

        var pie = d3.layout.pie()
            .sort(null)
            .value(function(d) { return d.count; });

        var labelArc = d3.svg.arc()
            .outerRadius(radius - 40)
            .innerRadius(radius - 40);
          
        var svg = d3.select("#chart").append("svg")
            .datum(data)
            .attr("width", width)
            .attr("height", height)
            .append("g")
            .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

        var arcs = svg.selectAll(".arc")
            .data(pie)
            .enter().append("g")
            .attr("class", "arc");
          
         var arcs2 = svg.selectAll(".arc2")
            .data(pie)
            .enter().append("g")
            .attr("class", "arc2");

          
        arcs.append("path")
            .attr("fill", function(d, i) { return color(i); })
            .on("mouseover", function(d) {
                var htmlMsg="";
                div.transition()        
                    .style("opacity",0.9);
                var total = d3.sum(data.map(function(d) {                   
                    return d.count;                                           
                })); 
                var percent = Math.round(1000 * d.data.count / total) / 10;         
                div.html(
                 "IP :"+ d.data.IP +""+"<br/>"+
                 "Count : " +  d.data.count +"<br/>" + 
                 "Percent: " + percent + '%'+ htmlMsg)
                .style("left",  (d3.event.pageX) + "px")
                .style("top",  (d3.event.pageY) + "px");    

                svg.selectAll("path").sort(function (a, b) { 
                    if (a != d) return -1;               
                    else return 1;                             
                });
          
                var endAngle = d.endAngle + 0.1;
                var startAngle = d.startAngle - 0.1;
                var arcOver = d3.svg.arc()
                    .outerRadius(radius + 10).endAngle(endAngle).startAngle(startAngle);
                        d3.select(this)
                        .attr("stroke","white")
                        .transition()
                        .ease("bounce")
                        .duration(1000)
                        .attr("d", arcOver)             
                        .attr("stroke-width",6);
                    })

            .on("mouseout", function(d) {
                div.transition()        
                .duration(500)      
                .style("opacity", 0); 
                    d3.select(this).transition()            
                       .attr("d", arc)
                       .attr("stroke","none");
                })
                .transition()
                .ease("bounce")
                .duration(2000)
                .attrTween("d", tweenPie);

        function tweenPie(b) {
          b.innerRadius = 0;
          var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
          return function(t) { return arc(i(t)); };
        }

        var k=0;
        arcs2.append("text")
        .transition()
            .ease("elastic")
            .duration(2000)
            .delay(function (d, i) {
                return i * 250;
            })
              .attr("x","6")
              .attr("dy", ".35em")
              .text(function(d) { if(d.data.count >0){ k = k+1; return d.data.count;} })
              .attr("transform", function(d) { if (k >1){return "translate(" + labelArc.centroid(d) + ") rotate(" + angle(d) + ")";} else{return "rotate(-360)";} })
              .attr("font-size", "10px");
        

        function type(d) {
          d.count = +d.count;
          return d;
        }
        function angle(d) {
              var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
              return a > 90 ? a - 180 : a;
        }

 var legend = d3.select("#chart")
    .append("svg")
    .attr("class", "legend")
    .attr("width", radius+50)
    .attr("height", radius * 2)
    .selectAll("g")
    .data(color.domain())
    .enter()
    .append("g")
    .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });

 legend.append('rect')
    .attr('width', legendRectSize)
    .attr('height', legendRectSize)                                   
   .style('fill', color)
   .style('stroke', color);
  
  legend.append('text')
    .attr('x', legendRectSize + legendSpacing)
    .attr('y', legendRectSize - legendSpacing)
    .data(data)
    .text(function(d,i) { return d.IP; });

  </script>   
  </svg>
  </div>

  <script type="text/javascript">
var chart = $("#chart"),
    aspect = chart.width() / chart.height(),
    container = chart.parent();
$(window).on("resize", function() {
    var targetWidth = container.width();
    chart.attr("width", targetWidth);
    chart.attr("height", Math.round(targetWidth / aspect));
}).trigger("resize");
</script>

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

你好,我是D3.js的新手。我在构建响应式饼图时遇到问题。该图表是响应式的,还附有工具提示。但是当我尝试将图例附加到图表时,图例与图表重叠。请帮我。我卡住了。如何将图例放在饼图旁边。这是我到目前为止尝试过的代码。 提前感谢您的帮助。

这可以通过 3 种方式解决:

  1. 图表宽度:

    在这里,饼图对于给定的尺寸来说太大了。因此,传说重叠。您可以尝试将 width: 300 更改为 width: 700

  2. 圆的半径:

    如果不能改变宽度,可以减小饼图的半径。目前,它选择 width/height 中的最小值并除以二减去 10 作为余量。 radius = Math.min(width, height) / 2 您可以另外指定 radius = Math.min(width, height) / 2 - 50 以进一步减小半径像素。

  3. 中心变换:

    或者您也可以将饼图的中心进一步向右移动。目前,它位于尺寸的一半。 .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")。你可以说是宽度的 3/4 和高度的 40% .attr("transform", "translate(" + width * 3 / 4 + "," + height * 2 / 5 + ")")

我已经使用了您代码段中的所有三种方式:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <title>Testing Pie Chart</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
     <style type="text/css">

     #container {
        margin: 20px;
      }

     #chart {  
        position: absolute;  
        background-color: #eee;                                          
      }
      #chart legend{  
        position: absolute;  
        margin: 100px;                                        
      }                                                                 
      .tooltip {                                                        
        background: #eee;                                               
        box-shadow: 0 0 5px #999999;                                    
        color: #900C3F;                                                    
        display: inline-block;                                                  
        font-size: 12px;                                                
        left: 600px;                                                    
        padding: 10px;                                                  
        position: absolute;                                             
        text-align: center;                                             
        top: 95px;                                                      
        width: 150px;                                                    
        z-index: 10;  
        opacity: 1;                                                 
    }                                                                 
    rect {
       stroke-width: 2;
    }
    path {
        stroke: #ffffff;
        stroke-width: 0.5;
    }
    div.tooltip {
    position: absolute;
    z-index: 999;
    padding: 10px;
    background: #f4f4f4;
    border: 0px;
    border-radius: 3px;
    pointer-events: none;
    font-size: 11px;
    color:  #080808;
    line-height: 16px;
    border: 1px solid #d4d4d4;
    }

     </style>
      </head>
  <body>

    <div id="container">
    <svg id="chart" width="600" height="300" viewBox="0 0 600 300" perserveAspectRatio="xMinYMid">
    <div id="toolTip" class="tooltip" style="opacity: 0;"></div>
    <script type="text/javascript">

var div = d3.select("#toolTip");

var data = [
      {"IP":"192.168.12.1", "count":20}, 
      {"IP":"76.09.45.34", "count":40}, 
      {"IP":"34.91.23.76", "count":80},
      {"IP":"192.168.19.32", "count":16}, 
      {"IP":"192.168.10.89", "count":50}, 
      {"IP":"192.178.34.07", "count":18},
      {"IP":"192.168.12.98", "count":30}];

var width = 400,
    height = 300;
var margin = {top: 15, right: 15, bottom: 20, left: 40},
    radius = Math.min(width, height) / 2 - 50;
var legendRectSize = 18,
    legendSpacing = 4;
            

        var color = d3.scale.category20b();

        var arc = d3.svg.arc()
            .outerRadius(radius);
          
          var arcOver = d3.svg.arc()
                .outerRadius(radius + 5);

        var pie = d3.layout.pie()
            .sort(null)
            .value(function(d) { return d.count; });

        var labelArc = d3.svg.arc()
            .outerRadius(radius - 40)
            .innerRadius(radius - 40);
          
        var svg = d3.select("#chart").append("svg")
            .datum(data)
            .attr("width", width)
            .attr("height", height)
            .append("g")
            .attr("transform", "translate(" + width * 3 / 4  + "," + height * 2/ 5 + ")");

        var arcs = svg.selectAll(".arc")
            .data(pie)
            .enter().append("g")
            .attr("class", "arc");
          
         var arcs2 = svg.selectAll(".arc2")
            .data(pie)
            .enter().append("g")
            .attr("class", "arc2");

          
        arcs.append("path")
            .attr("fill", function(d, i) { return color(i); })
            .on("mouseover", function(d) {
                var htmlMsg="";
                div.transition()        
                    .style("opacity",0.9);
                var total = d3.sum(data.map(function(d) {                   
                    return d.count;                                           
                })); 
                var percent = Math.round(1000 * d.data.count / total) / 10;         
                div.html(
                 "IP :"+ d.data.IP +""+"<br/>"+
                 "Count : " +  d.data.count +"<br/>" + 
                 "Percent: " + percent + '%'+ htmlMsg)
                .style("left",  (d3.event.pageX) + "px")
                .style("top",  (d3.event.pageY) + "px");    

                svg.selectAll("path").sort(function (a, b) { 
                    if (a != d) return -1;               
                    else return 1;                             
                });
          
                var endAngle = d.endAngle + 0.1;
                var startAngle = d.startAngle - 0.1;
                var arcOver = d3.svg.arc()
                    .outerRadius(radius + 10).endAngle(endAngle).startAngle(startAngle);
                        d3.select(this)
                        .attr("stroke","white")
                        .transition()
                        .ease("bounce")
                        .duration(1000)
                        .attr("d", arcOver)             
                        .attr("stroke-width",6);
                    })

            .on("mouseout", function(d) {
                div.transition()        
                .duration(500)      
                .style("opacity", 0); 
                    d3.select(this).transition()            
                       .attr("d", arc)
                       .attr("stroke","none");
                })
                .transition()
                .ease("bounce")
                .duration(2000)
                .attrTween("d", tweenPie);

        function tweenPie(b) {
          b.innerRadius = 0;
          var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
          return function(t) { return arc(i(t)); };
        }

        var k=0;
        arcs2.append("text")
        .transition()
            .ease("elastic")
            .duration(2000)
            .delay(function (d, i) {
                return i * 250;
            })
              .attr("x","6")
              .attr("dy", ".35em")
              .text(function(d) { if(d.data.count >0){ k = k+1; return d.data.count;} })
              .attr("transform", function(d) { if (k >1){return "translate(" + labelArc.centroid(d) + ") rotate(" + angle(d) + ")";} else{return "rotate(-360)";} })
              .attr("font-size", "10px");
        

        function type(d) {
          d.count = +d.count;
          return d;
        }
        function angle(d) {
              var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
              return a > 90 ? a - 180 : a;
        }

 var legend = d3.select("#chart")
    .append("svg")
    .attr("class", "legend")
    .attr("width", radius+50)
    .attr("height", radius * 2)
    .selectAll("g")
    .data(color.domain())
    .enter()
    .append("g")
    .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });

 legend.append('rect')
    .attr('width', legendRectSize)
    .attr('height', legendRectSize)                                   
   .style('fill', color)
   .style('stroke', color);
  
  legend.append('text')
    .attr('x', legendRectSize + legendSpacing)
    .attr('y', legendRectSize - legendSpacing)
    .data(data)
    .text(function(d,i) { return d.IP; });

  </script>   
  </svg>
  </div>

  <script type="text/javascript">
var chart = $("#chart"),
    aspect = chart.width() / chart.height(),
    container = chart.parent();
$(window).on("resize", function() {
    var targetWidth = container.width();
    chart.attr("width", targetWidth);
    chart.attr("height", Math.round(targetWidth / aspect));
}).trigger("resize");
</script>

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