D3和图例间距中的折线 [英] Polylines in D3 and Legend spacing

查看:59
本文介绍了D3和图例间距中的折线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用以下示例,希望在饼图之外具有图例,并且还具有用于文本的折线以及每个切片的计数和百分比.

I am using the below example and wanted to have the legend outside the Pie chart and also have the Polyline for the Text and the count and Percentage for each slice.

在当前代码中,我在饼中包含了Pie,当我将鼠标悬停在切片上时,将显示Text和Percentage.

With the current code I have Pie inside the pie and Text and Percentage are showing when I mouse over the slice.

非常感谢您的帮助.

有人不能帮忙,因为我无法前进.

Can some one please help as I am unable to move forward.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <link rel="stylesheet" href="normalize.css">
    <style>
        #chart {
            height: 360px;
            margin: 0 auto; /* NEW */
            position: relative;
            width: 360px;
        }

        .tooltip {
            background: #eee;
            box-shadow: 0 0 5px #999999;
            color: #333;
            display: none;
            font-size: 12px;
            left: 130px;
            padding: 10px;
            position: absolute;
            text-align: center;
            top: 95px;
            width: 80px;
            z-index: 10;
        }

        .legend {
            font-size: 12px;
        }

        rect {
            cursor: pointer; /* NEW */
            stroke-width: 2;
        }

            rect.disabled { /* NEW */
                fill: transparent !important; /* NEW */
            }
        /* NEW */
        h1 { /* NEW */
            font-size: 14px; /* NEW */
            text-align: center; /* NEW */
        }
        /* NEW */
    </style>
</head>
<body>

    <div id="chart"></div>
    <script src="Scripts/d3.v3.min.js"></script>
    <script>
      (function(d3) {
        'use strict';

        var width = 360;
        var height = 360;
        var radius = Math.min(width, height) / 2;
        var donutWidth = 75;
        var legendRectSize = 18;
        var legendSpacing = 4;

        var color = d3.scale.category20(); //builtin range of colors

        var svg = d3.select('#chart')
          .append('svg')
          .attr('width', width)
          .attr('height', height)
          .append('g')
          .attr('transform', 'translate(' + (width / 2) +
            ',' + (height / 2) + ')');

        var arc = d3.svg.arc()
          .innerRadius(radius - donutWidth)
          .outerRadius(radius);

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

        var tooltip = d3.select('#chart')
          .append('div')
          .attr('class', 'tooltip');

        tooltip.append('div')
          .attr('class', 'label');

        tooltip.append('div')
          .attr('class', 'count');

        tooltip.append('div')
          .attr('class', 'percent');

        d3.csv('weekdays.csv', function(error, dataset) {
          dataset.forEach(function(d) {
            d.count = +d.count;
            d.enabled = true;                                         // NEW
          });

          var path = svg.selectAll('path')
            .data(pie(dataset))
            .enter()
            .append('path')
            .attr('d', arc)
            .attr('fill', function(d, i) {
              return color(d.data.label);
            })                                                        // UPDATED (removed semicolon)
            .each(function(d) { this._current = d; });                // NEW

          path.on('mouseover', function(d) {
            var total = d3.sum(dataset.map(function(d) {
              return (d.enabled) ? d.count : 0;                       // UPDATED
            }));
            var percent = Math.round(1000 * d.data.count / total) / 10;
            tooltip.select('.label').html(d.data.label);
            tooltip.select('.count').html(d.data.count);
            tooltip.select('.percent').html(percent + '%');
            tooltip.style('display', 'block');
          });

          path.on('mouseout', function() {
            tooltip.style('display', 'none');
          });

          /* OPTIONAL
          path.on('mousemove', function(d) {
            tooltip.style('top', (d3.event.pageY + 10) + 'px')
              .style('left', (d3.event.pageX + 10) + 'px');
          });
          */

          var legend = svg.selectAll('.legend')
            .data(color.domain())
            .enter()
            .append('g')
            .attr('class', 'legend')
            .attr('transform', function(d, i) {
              var height = legendRectSize + legendSpacing;
              var offset =  height * color.domain().length / 2;
              var horz = -2 * legendRectSize;
              var vert = i * height - offset;
              return 'translate(' + horz + ',' + vert + ')';
            });

          legend.append('rect')
            .attr('width', legendRectSize)
            .attr('height', legendRectSize)
            .style('fill', color)
            .style('stroke', color)                                   // UPDATED (removed semicolon)
            .on('click', function(label) {                            // NEW
              var rect = d3.select(this);                             // NEW
              var enabled = true;                                     // NEW
              var totalEnabled = d3.sum(dataset.map(function(d) {     // NEW
                return (d.enabled) ? 1 : 0;                           // NEW
              }));                                                    // NEW

              if (rect.attr('class') === 'disabled') {                // NEW
                rect.attr('class', '');                               // NEW
              } else {                                                // NEW
                if (totalEnabled < 2) return;                         // NEW
                rect.attr('class', 'disabled');                       // NEW
                enabled = false;                                      // NEW
              }                                                       // NEW

              pie.value(function(d) {                                 // NEW
                if (d.label === label) d.enabled = enabled;           // NEW
                return (d.enabled) ? d.count : 0;                     // NEW
              });                                                     // NEW

              path = path.data(pie(dataset));                         // NEW

              path.transition()                                       // NEW
                .duration(750)                                        // NEW
                .attrTween('d', function(d) {                         // NEW
                  var interpolate = d3.interpolate(this._current, d); // NEW
                  this._current = interpolate(0);                     // NEW
                  return function(t) {                                // NEW
                    return arc(interpolate(t));                       // NEW
                  };                                                  // NEW
                });                                                   // NEW
            });                                                       // NEW

          legend.append('text')
            .attr('x', legendRectSize + legendSpacing)
            .attr('y', legendRectSize - legendSpacing)
            .text(function(d) { return d; });

        });

      })(window.d3);
    </script>
</body>
</html>

推荐答案

您可以将图例分组,然后使用 translate

You can place the legends where ever you wish by making the legends in a group and placing it using the translate

首先制作SVG:

  var s = d3.select('#chart')
    .append('svg')
    .attr('width', width)
    .attr('height', height);

现在创建一个图例组:

  var legend_group = s.append('g').attr('transform',
    'translate(' + (width / 3) + ',' + (height / 1.4) + ')');

使用将其翻译到您选择的位置.我已经将其移动到(width/3,height/1.4)

Use translate it to a place of your choice. I have moved it to (width/3, height/1.4)

组成一个将在其中绘制饼图的组.

Make a group in which the pie chart will be drawn.

  var svg = s.append('g')
    .attr('transform', 'translate(' + (width / 2) +
      ',' + (radius) + ')');

让每个切片产生一条折线:此功能将生成与数据集长度一样多的折线.

Lets make a polyline for each slice: This function will make as many polylines as the dataset length.

function makePolyLines() {
  var polyline = svg.selectAll("polyline")
    .data(pie(dataset), key);

  polyline.enter()
    .append("polyline");
  //hide polyline for which value is 0, a case when legend is clicked.
  svg.selectAll("polyline").style("display", function(d) {
    if (d.value == 0) {
      return "none";
    } else {
      return "block";
    }
  });

  polyline.transition().duration(1000)
    .attrTween("points", function(d) {
      this._current = this._current || d;
      var interpolate = d3.interpolate(this._current, d);
      this._current = interpolate(0);
      return function(t) {
        var d2 = interpolate(t);
        var pos = outerArc.centroid(d2);
        pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1);
        return [arc.centroid(d2), outerArc.centroid(d2), pos];
      };
    });

  polyline.exit()
    .remove();
}

类似地为标签制作文本.

Similarly make text for labels.

function makeTexts() {
  var text = svg.selectAll(".labels")
    .data(pie(dataset), key);

  text.enter()
    .append("text")
    .attr("dy", ".35em")
    .classed("labels", true)
    .text(function(d) {
      return d.data.label + " (" + d.data.count + ")";
    });
  //hide text for which value is 0, a case when legend is clicked.
  svg.selectAll(".labels").style("display", function(d) {
    if (d.value == 0) {
      return "none";
    } else {
      return "block";
    }
  });

  text.transition().duration(1000)
    .attrTween("transform", function(d) {

      this._current = this._current || d;
      var interpolate = d3.interpolate(this._current, d);
      this._current = interpolate(0);
      return function(t) {
        var d2 = interpolate(t);
        var pos = outerArc.centroid(d2);
        pos[0] = radius * (midAngle(d2) < Math.PI ? 1 : -1);
        return "translate(" + pos + ")";
      };
    })
    .styleTween("text-anchor", function(d) {
      this._current = this._current || d;
      var interpolate = d3.interpolate(this._current, d);
      this._current = interpolate(0);
      return function(t) {
        var d2 = interpolate(t);
        return midAngle(d2) < Math.PI ? "start" : "end";
      };
    });

  text.exit()
    .remove();
}

最后调用这两个函数.

1)最初是在提取数据之后.

1) initially after the data is fetched.

2)每当单击图例并更新饼图时.

2) whenever legend is clicked and the piechart is updated.

工作代码此处

这篇关于D3和图例间距中的折线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆