为什么d3.js饼图转换不起作用?

时间:2016-05-03 12:50:23

标签: javascript python d3.js charts

今天我在简单的饼图上使用d3.js。

我使用教程here来构建我的第一个饼图,但我想稍微自定义它,所以我的代码看起来不一样。

我在处理第6步时遇到问题,为我的图表添加了一些交互性。

如图here所示,饼图应该允许我点击其图例来切换一些数据。但是,如果悬停工具正在处理我的代码(切换有效地改变了悬停框内的值),则图表本身不会改变。

切换时,我的浏览器控制台会抛出该错误:

d3.v3.js:5737 Uncaught TypeError: Cannot use 'in' operator to search for 'data' in undefined

经过一些测试后,我意识到由于javascript的那部分错误发生了错误:

  var path = g.data(pie(data));

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

与演示中的相同。因此,我的其余代码可能会出现错误,但我不知道是什么导致错误。

这是我到目前为止所做的:

样式:

#chart {
  height: 360px;
  margin: 0 auto;
  position: relative;
  width: 360px;
}


.tool {
  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;
}

/* replace bootstrap css */
.label {
    color: #000000
}

/* css for the legend*/
.legend {
    font-size: 12px;
  }

rect {
    cursor: pointer;
    stroke-width: 2;
  }

rect.disabled {
  fill: transparent !important;
}

脚本:

// var definition
var legendRectSize = 18;
var legendSpacing = 4;

// defines chart boundaries
var width = 960;
var height = 500;
var radius = Math.min(width, height) / 2;
var DonutWidth = 80;

// defines a charter of colors for the chart
var color = d3.scale.ordinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

// defines graphical attributes for the chart
var arc = d3.svg.arc()
    .outerRadius(radius - 10)
    .innerRadius(radius - DonutWidth);

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


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

// add the chart to the html doc
var svg = d3.select('#chart').append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

// add objects needed for the hover tool
var tool = d3.select('#chart')
  .append('div')
  .attr('class', 'tool');

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

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

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

// loads data
d3.json("/media/Storage/bar_chart.json", function(data) {
    // creates a variable to know if a column will be displayed or not
  data.forEach(function(d) {
     d.TST = +d.TST;
     d.enabled = true;
  });
    // creates the pie chart from data
  var g = svg.selectAll(".arc")
      .data(pie(data))
    .enter().append("g")
      .attr("class", "arc");

    g.append("path")
      .attr("d", arc)
      .attr("fill", function(d, i) { return color(d.data.OPCODE); })
      .each(function(d){this._current = d;});

    // displays data on hover
    g.on('mouseover',function(d){
    var total = d3.sum(data.map(function(d) {
    return (d.enabled) ? d.TST : 0;
  }));

    var percent = Math.round(1000 * d.data.TST / total) / 10;

    tool.select('.label').html(d.data.OPCODE);
    tool.select('.count').html(d.data.TST);
    tool.select('.percent').html(percent + '%');
    tool.style('display', 'block');
  });

  // toggles off hoverbox
  g.on('mouseout', function(d){
      tool.style('display', 'none');
  });


  // add the legend to the chart
  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)
   // function which toggles data to exclude of display
  .on('click', function(OPCODE){
      var rect = d3.select(this);
      var enabled = true;
      var totalEnabled = d3.sum(data.map(function(d) {
          return (d.enabled) ? 1 : 0;
      }));
      if (rect.attr('class') === 'disabled') {
         rect.attr('class', '');
      } else {
          if (totalEnabled < 2) return;
          rect.attr('class', 'disabled');
          enabled = false;
          }
      // defines a new way to retrieve data for the chart, selecting only enabled data
      pie.value(function(d) {
        if (d.OPCODE === OPCODE) d.enabled = enabled;
        return (d.enabled) ? d.TST : 0;
        });

      //incriminated part of the script
      var path = g.data(pie(data));

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


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

非常感谢你的帮助。

编辑:

Link to a JSFiddle

由于我正在使用json文件,我在我的应用程序中本地加载,这里我不得不使用我的JSON放置的局部变量,但它显然效率低下并带来了其他错误......

1 个答案:

答案 0 :(得分:0)

您在此行this._current处未定义var i = d3.interpolate(this._current, d);修复此问题,剩下的就足够了。而不是this.current尝试使用可在代码中的任何位置访问的temp var。如果new dataold data尝试two sets of json and onClick不同,您只能看到过渡{1}}传递新的json数据。

相关问题