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

D3.js 如何在Ember应用程序的D3垂直条形图中添加更新标签,d3.js,ember.js,D3.js,Ember.js,我的余烬应用程序中有一个垂直条形图,我正在努力将文本标签附加到条形图的顶部 该图表分为以下功能: 绘制图表的静态元素: didInsertElement() { let svg = select(this.$('svg')[0]); this.set('svg', svg); let height = 325 let width = 800 let padding = { top: 10, bottom: 30, l

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

该图表分为以下功能:

绘制图表的静态元素:

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);
  },
  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();

}
当模型更改时,这将重新绘制图表:

 didUpdateAttrs() {
    this.renderChart();
  },
这将处理图表的绘制:

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);
  },
  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属性返回为未定义。如果我遗漏了什么,请告诉我。

函数(){}
语法转换为箭头函数将允许您维护
this

因此:

变成

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

有关箭头功能的详细信息,请参见: -
-

如果将函数转换为箭头函数,使
上下文与调用方的
上下文保持一致,会怎么样?听起来很有趣。我不太熟悉复杂的箭头符号,正确的语法是什么?我不知道如何编辑注释。将函数更改为(d)=>{返回this.get('xScale')正是正确的做法。我不知道箭头函数保留了“this”!请提交一个我可以接受的答案,并添加upvoteanswer。很高兴事情为您解决:)