错误使用`d3.legend`:未捕获TypeError:node.getAttribute不是函数

时间:2017-12-28 22:39:50

标签: node.js reactjs d3.js charts legend

我正在尝试在我的圆环图中添加一个D3图例,我按照这里的示例:http://bl.ocks.org/ZJONSSON/3918369。甜甜圈图表很好。

但是,我遇到了以下错误:

在d3.legend()函数中,我收到此错误' Uncaught TypeError:node.getAttribute不是函数'和' Uncaught TypeError:this.querySelectorAll不是函数'。

我不确定为什么......有什么想法?

// Alerts.js
renderBody() {
    const {list, currentProgram} = this.props
    const width = 260;
    const height = 260;
    const radius = width/2; // 130

    // arc & label generator
    let arc = d3.arc()
      .outerRadius(radius - 10)
      .innerRadius(90)
      .padAngle(0.02);

    let labelArc = d3.arc()
      .outerRadius(radius + 60)
      .innerRadius(radius - 90);

    // pie generator
    let pie = d3.pie()
      .sort(null)
      .value( d => { return d; });

    // define svg
    let svg = d3.select('.enrolled-statistics-svg').append('svg')
      .attr('width', width)
      .attr('height', height)
      .append('g') // group similar elements together
      .attr('transform', 'translate(' + width/2 + ', ' + height/2 + ')');

    // append g elements (arc)
    const g = svg.selectAll('.arc')
      .data(pie(testData))
      .enter().append('g')
      .attr('class', 'arc');

    // append the path of the arc
    g.append('path')
      .attr('d', arc)
      .attr('data-legend', val => {
        return val.data;
      })
      .attr('data-legend-pos', (val) => {
        return val.index;
      })
      .style('fill', val => {
        return COLOR_ARRAY[val.index];
      });

    // append with label
    g.append('text')
      .attr('transform', d => {
        return 'translate(' + labelArc.centroid(d) + ')';
      })
      .attr('dy', '0.35em')
      .text( val => {
        return (val.data / testResp.data.enrolledStatistics.total) * 100 + '%';
      });

    // define d3.legend()
    d3.legend = (g) => {

      g.each(() => {
        let g = d3.select(this);
        console.log('------- g: ', g);

        let items = {};
        let svg = d3.select(g.property('nearestViewportElement'));
        let legendPadding = g.attr('data-style-padding') || 5; // ERROR: Uncaught TypeError: node.getAttribute is not a function
        let legendBox = g.selectAll('.legend-box').data([true]); // ERROR: Uncaught TypeError: this.querySelectorAll is not a function
        let legendItems = g.selectAll('.legend-items').data([true]);

        legendBox.enter().append('rect').classed('legend-box', true);
        legendItems.enter().append('g').classed('legend-items', true);

        svg.selectAll('[data-legend]').each(() => {
          let self = d3.select(this)
          items[self.attr('data-legend')] = {
            pos: self.attr("data-legend-pos") || this.getBBox().y,
            color: self.attr("data-legend-color") != undefined ? self.attr("data-legend-color")
              : self.style("fill") != 'none' ? self.style("fill") : self.style("stroke")
          }
        });

        items = d3.entries(items).sort(function (a, b) {
          return a.value.pos - b.value.pos
        });

        console.log('------- items: ', items);

        legendBox.selectAll('text')
          .data(items, val => val.key)
          .call(val => {
            val.enter().append('text')
          })
          .call(val => {
            val.exit().remove()
          })
          .attr('y', (val, i) => {
            return `${i}em`
          })
          .attr('x', '1em')
          .text(val => val.key);

        legendItems.selectAll("circle")
          .data(items, function (d) {
            return d.key
          })
          .call(val => val.enter().append("circle"))
          .call(val => val.exit().remove())
          .attr('cy', (val, i) => `${i - 0.25}em`)
          .attr('cx', 0)
          .attr('r', '0.4em')
          .style('fill', val => {
            console.log(val.value.color);
            return val.value.color
          });

        // Reposition and resize the box
        let lbbox = li[0][0].getBBox();

        lbbox.attr("x", (lbbox.x - legendPadding))
          .attr("y", (lbbox.y - legendPadding))
          .attr("height", (lbbox.height + 2 * legendPadding))
          .attr("width", (lbbox.width + 2 * legendPadding));
      });

      return g;
    }

    // define legend svg
    let padding = 20;
    let legx = radius + padding;
    let legendSVG = d3.select('.enrolled-statistics').append('svg')
      .attr('width', 150)
      .attr('height', 150)
      .append('g')
      .attr('class', 'legend')
      .attr('transform', 'translate(' + legx + ', 0)')
      .style('font-size', '12px')
      .style('fill', 'blue')
      .call(d3.legend);

     return(....)
    }

1 个答案:

答案 0 :(得分:3)

您正在使用箭头功能来定义each回调。这会更改this关键字更多信息here)的范围。所以基本上d3.select(this)没有选择你期望的。此外,您在两种不同的方法中使用g作为变量,这可能会导致意外行为(我认为;我建议使用不同的名称制作变量以避免混淆)。