值未在D3条形图使用中动态反映。现有图发生重叠。

时间:2018-08-10 17:44:47

标签: angular d3.js

在此代码中,我使用的是Angular 2和D3 v3.5。每当从Service更改值时,就会在现有图下方显示一个新图,而不是更改现有图的值。这是图创建的一部分。请帮我,如何在单个图表中使其动态?我已经尝试过.exit()和.remove()方法,但是没有解决。

public renderChart() {
    let obj = {
      0: 'Bar 1',
      1: 'Bar 2',
      2: 'Bar 3',
      3: 'Bar 4',
      4: 'Bar 5',
      5: 'Bar 6',
    };

    let data = [
      { xAxis: 0, value: 10 },
      { xAxis: 1, value: 11 },
      { xAxis: 2, value: 12 },
      { xAxis: 3, value: 12 },
      { xAxis: 4, value: 11 },
      { xAxis: 5, value: 10 },
    ];
    let margin = {
      top: 20,
      right: 160,
      bottom: 35,
      left: 0
    };
    let width = 700;
    let height = window.innerHeight / 1.8;
    let fromLeft = 40;

    let svg = d3.select('#barChart')
      .append('svg')
      .attr('width', width + 100)
      .attr('height', height + margin.top + margin.bottom + 2)
      .append('g')
      .attr('transform', 'translate(' + (margin.left + fromLeft) + ',' + margin.top + ')');

    let dataset = d3.layout.stack()(['value'].map((value) => {
      return data.map((d: any) => {
        return { x: obj[d.xAxis], y: d.value };
      });
    }));

    let x = d3.scale.ordinal()
      .domain(dataset[0].map((d) => { return d.x; }))
      .rangeBands([0, width], 1);

    let y = d3.scale.linear()
      .domain([0, d3.max(dataset, (d) => {
        return d3.max(d, (d1) => { return d1.y0 + d1.y; });
      })])
      .range([height, 0]);
    let colors = ['#169fcd', '#f26722'];

    let yAxis = d3.svg.axis()
      .scale(y)
      .orient('left')
      .ticks(10)
      .tickSize(-width, 0, 0)
      .tickFormat(d3.format('.1S'));

    let xAxis = d3.svg.axis()
      .scale(x)
      .orient('bottom');

    svg.append('g')
      .attr('class', 'y axis')
      .call(yAxis);
    svg.append('g')
      .attr('class', 'x axis')
      .attr('transform', 'translate(0,' + height + ')')
      .call(xAxis);

    svg.selectAll('.x')
      .selectAll('text');

    svg.selectAll('.y')
      .selectAll('path')
      .style('display', 'none');

    let groups = svg.selectAll('g.cost')
      .data(dataset)
      .enter().append('g')
      .attr('class', 'cost')
      .style('fill', (d, i) => { return colors[i]; });
    let rect = groups.selectAll('rect')
      .data((d) => { return d; })
      .enter()
      .append('rect')
      .attr('x', (d) => { return x(d.x); })
      .attr('y', height - 1)
      .attr('height', 0)
      .attr('width', '11px')
      .transition()
      .duration(1000)
      .delay(100)
      .attr('y', (d) => { return y(d.y0 + d.y); })
      .attr('height', (d) => { return y(d.y0) - y(d.y0 + d.y); });
  }

2 个答案:

答案 0 :(得分:1)

您必须先清空条形图:

let svg = d3.select('#barChart')
  .html(null)
  .append('svg')

不确定这是否是最有效的方法,但这取决于您:)

答案 1 :(得分:1)

每次运行此功能时,都会创建一个新的svg:

let svg = d3.select('#barChart').append('svg')

此新添加的svg将添加到您创建的最后一个svg之后。您需要选择现有的svg(如果存在),一种简单的方法是手动添加svg并对其进行操作:

<div id="barChart"><svg></svg></div>

let svg = d3.select("#barChart").select("svg");

当然还有其他方法(检查.select("svg")是否为空,甚至使用Enter / Update循环进行检查。)

这会引入一个新问题,您的代码不使用更新选择,它仅适用于enter选择,但是如果您中断了链接,则可以访问enter和更新这方面有很多内容,所以我将不做详细介绍(关键问题是.enter()返回一个新的选择,但是由于您只在第一次输入元素时才每隔一次运行该函数便将其为空)。请记住,如果查看参考,d3v3的更新/输入模式与d3v4 / 5不同。对此进行更正,我们可能会得到类似于以下代码片段(单击以更新):

t();

d3.select("#barChart")
  .on("click",t);


function t() {

    let obj = {
      0: 'Bar 1',
      1: 'Bar 2',
      2: 'Bar 3',
      3: 'Bar 4',
      4: 'Bar 5',
      5: 'Bar 6',
    };

    let data = [
      { xAxis: 0, value: Math.random()*10 },
      { xAxis: 1, value: Math.random()*11 },
      { xAxis: 2, value: Math.random()*12 },
      { xAxis: 3, value: Math.random()*12 },
      { xAxis: 4, value: Math.random()*11 },
      { xAxis: 5, value: Math.random()*10 },
    ];
    let margin = {
      top: 20,
      right: 160,
      bottom: 35,
      left: 0
    };
    let width = 700;
    let height = window.innerHeight / 1.8;
    let fromLeft = 40;

    let svg = d3.select('#barChart')
     .select('svg')
    svg.attr('width', width + 100)
      .attr('height', height + margin.top + margin.bottom + 2)
      .append('g')
      .attr('transform', 'translate(' + (margin.left + fromLeft) + ',' + margin.top + ')');

    let dataset = d3.layout.stack()(['value'].map((value) => {
      return data.map((d) => {
        return { x: obj[d.xAxis], y: d.value };
      });
    }));

    let x = d3.scale.ordinal()
      .domain(dataset[0].map((d) => { return d.x; }))
      .rangeBands([0, width], 1);

    let y = d3.scale.linear()
      .domain([0, d3.max(dataset, (d) => {
        return d3.max(d, (d1) => { return d1.y0 + d1.y; });
      })])
      .range([height, 0]);
    let colors = ['#169fcd', '#f26722'];

    let yAxis = d3.svg.axis()
      .scale(y)
      .orient('left')
      .ticks(10)
      .tickSize(-width, 0, 0)
      .tickFormat(d3.format('.1S'));

    let xAxis = d3.svg.axis()
      .scale(x)
      .orient('bottom');

    svg.append('g')
      .attr('class', 'y axis')
      .call(yAxis);
    svg.append('g')
      .attr('class', 'x axis')
      .attr('transform', 'translate(0,' + height + ')')
      .call(xAxis);

    svg.selectAll('.x')
      .selectAll('text');

    svg.selectAll('.y')
      .selectAll('path')
      .style('display', 'none');

    let groups = svg.selectAll('g.cost')
      .data(dataset);
	  
	  groups.enter().append('g')
      .attr('class', 'cost')
      .style('fill', (d, i) => { return colors[i]; });

    let rect = groups.selectAll('rect')
      .data((d) => { return d; });
	  
	  rect
      .enter()
      .append('rect')
      .attr('x', (d) => { return x(d.x); })
      .attr('y', height - 1)
      .attr('height', 0)
      .attr('width', '11px')
	  
	  rect
      .transition()
      .duration(1000)
      .delay(100)
      .attr('y', (d) => {return y(d.y0 + d.y); })
      .attr('height', (d) => { return y(d.y0) - y(d.y0 + d.y); });

  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<div id="barChart"><svg></svg></div>
<script src="https://d3js.org/d3.v3.min.js"></script>

您还需要确保不要每次运行时都继续添加新标签,就像svg

您可以按照另一个答案中的建议从div中删除所有内容,但是这样就消除了从一组数据过渡到另一组数据的可能性。

对于您尝试使用.exit().remove()的情况,仅当新数据数组的元素少于先前数据数组的元素(多余的元素将在退出选择中)或使用键进行绑定的数据(如果选择中的现有元素在新数据数组中没有匹配的键,则将其退出)。