如何在Ember应用程序的D3垂直条形图中添加更新标签

时间:2018-10-01 16:24:07

标签: d3.js ember.js

我的Ember应用程序中有一个垂直条形图,我正在努力在条​​形图的顶部附加文本标签。

该图表分为以下功能:

绘制图表的静态元素:

didInsertElement() {
    let svg = select(this.$('svg')[0]);
    this.set('svg', svg);
    let height = 325
    let width = 800


    let padding = {
      top: 10,
      bottom: 30,
      left: 40,
      right: 0
    };
    this.set('barsContainer', svg.append('g')
      .attr('class', 'bars')
      .attr('transform', `translate(${padding.left}, ${padding.top})`)
    );
    let barsHeight = height - padding.top - padding.bottom;

    this.set('barsHeight', barsHeight);
    let barsWidth = width - padding.left - padding.right;

    // Y scale & axes
    let yScale = scaleLinear().range([barsHeight, 0]);
    this.set('yScale', yScale);
    this.set('yAxis', axisLeft(yScale));
    this.set('yAxisContainer', svg.append('g')
      .attr('class', 'axis axis--y axisWhite')
      .attr('transform', `translate(${padding.left}, ${padding.top})`)
    );

    // X scale & axes
    let xScale = scaleBand().range([0, barsWidth]).paddingInner(0.15);
    this.set('xScale', xScale);
    this.set('xAxis', axisBottom(xScale));
    this.set('xAxisContainer', svg.append('g')
      .attr('class', 'axis axis--x axisWhite')
      .attr('transform', `translate(${padding.left}, ${padding.top + barsHeight})`)
    );


    // Color scale
    this.set('colorScale', scaleLinear().range(COLORS[this.get('color')]));

    this.renderChart();
    this.set('didRenderChart', true);
  },

这会在模型更改时重新绘制图表:

 didUpdateAttrs() {
    this.renderChart();
  },

这处理图表的绘制:

  renderChart() {
    let data = this.get('data');
    let counts = data.map(data => data.count);

    // Update the scales
    this.get('yScale').domain([0, Math.max(...counts)]);
    this.get('colorScale').domain([0, Math.max(...counts)]);
    this.get('xScale').domain(data.map(data => data.label));

    // Update the axes
    this.get('xAxis').scale(this.get('xScale'));
    this.get('xAxisContainer').call(this.get('xAxis')).selectAll('text').attr("y", 0)
    .attr("x", 9)
    .attr("dy", ".35em")
    .attr("transform", "rotate(40)")
    .style("text-anchor", "start");
    this.get('yAxis').scale(this.get('yScale'));
    this.get('yAxisContainer').call(this.get('yAxis'));


    let barsUpdate = this.get('barsContainer').selectAll('rect').data(data, data => data.label);
    // Enter
    let barsEnter = barsUpdate.enter()
    .append('rect')
    .attr('opacity', 0);
    let barsExit = barsUpdate.exit();
    let div = select('body')
    .append("div")
    .attr("class", "vert-tooltip");

    // Update
    let rafId;
    barsEnter
    .merge(barsUpdate)
    .transition()
    .attr('width', `${this.get('xScale').bandwidth()}px`)
    .attr('height', data => `${this.get('barsHeight') - this.get('yScale')(data.count)}px`)
    .attr('x', data => `${this.get('xScale')(data.label)}px`)
    .attr('y', data => `${this.get('yScale')(data.count)}px`)
    .attr('fill', data => this.get('colorScale')(data.count))
    .attr('opacity', data => {
      let selected = this.get('selectedLabel');
      return (selected && data.label !== selected) ? '0.5' : '1.0';
    })
    .on('start', (data, index) => {
      if (index === 0) {
        (function updateTether() {
          Tether.position()
          rafId = requestAnimationFrame(updateTether);
        })();
      }
    })
    .on('end interrupt', (data, index) => {
      if (index === 0) {
        cancelAnimationFrame(rafId);
      }
    });


    // Exit
    barsExit
      .transition()
      .attr('opacity', 0)
      .remove();

}

我删除了一些提示和单击事件以保持清晰度。

要添加标签,我尝试在renderChart()函数中添加以下内容:

barsEnter.selectAll("text")
        .data(data)
        .enter()
        .append("text")
        .text(function (d) { return d.count; })
        .attr("x", function (d) { return xScale(d.label) + xScale.bandwidth() / 2; })
        .attr("y", function (d) { return yScale(d.count) + 12; })
        .style("fill", "white");

使用上面的代码,我收到一条错误消息,指出未找到xScale和yScale,因为它们不在此函数范围内。如果我使用:

.attr("x", function (d) { return this.get('xScale')(d.label) + this.get('xScale').bandwidth() / 2; })
.attr("y", function (d) { return this.get('yScale')(d.count) + 12; })

我生成的'this.get'不是函数错误,并且'this'的上下文成为具有(d)值的对象。

如果我将X和Y标度添加为该函数的变量,例如:

let xScale = this.get('xScale')
let yScale = this.get('ySCale')

...

        .attr("x", function (d) { return xScale(d.label) + xScale.bandwidth() / 2; })
        .attr("y", function (d) { return yScale(d.count) + 12; })

然后将x和y属性返回为未定义。请让我知道是否错过了任何事情。

1 个答案:

答案 0 :(得分:1)

Converting the function() {} syntax into arrow functions will allow you to maintain the this.

So:

function(d) { return this.get('xScale'); }

becomes

(d) => this.get('xScale')

or

(d) => {
  return this.get('xScale');
}

For more information on arrow functions: - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions - https://hackernoon.com/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4