【问题标题】:Dynamically updating d3 bar chart动态更新 d3 条形图
【发布时间】:2016-11-13 07:19:21
【问题描述】:

此函数在页面加载时运行,并且在表单中输入数据时运行。它在页面加载时可以很好地绘制图形,但在提交新信息时不会重绘。

当我在数据连接后记录元素时,它会显示数据数组的更新长度和更新的元素数量,但它们不会重绘。任何想法,只需扫描此代码?感觉差不多了,但是数据更新过程的步骤我没看懂。

这是基于基本条形图教程let's make a bar chart,它使用 div 而不是 svg 元素,但我认为这不重要。

this.render = function(self){
  if(self.data){
    self.x = d3.scaleLinear()
               .domain([0, d3.max(self.data.map(function(d) {
                   return parseInt(d.daily_count);
                 }))
               ])
               .range([0, 500]);

    var bars = d3.select("#chart")
                 .selectAll("div")
                 .data(self.data)
                 .enter().append('div')
                   .attr('class', 'bar-container row');

    console.log('chart', d3.select("#chart").data(self.data));

    bars.append('div')
          .attr('class', 'label four columns')
          .text(function(d) {return d.date_string; });

    bars.append("div")
          .attr('class', 'bar eight columns')
          .style('background-color', function(d){
            return (d.daily_count == 0 ? 'white' : '#1EAEDB')
          })
          .style('color', function(d){
            return (d.daily_count == 0 ? 'red' : 'white')
          })
          .style("width", function(d) {
            return self.x(d.daily_count) + "px";
          })
          .text(function(d) {
            return (d.daily_count == 0 ? 'closed' : d.daily_count)
          });
  }

编辑:尝试使用 .merge() 和 .each() 创建和更新图表。我不知道如何动态更新每个栏是一个包含两个实际显示数据的子 div 的 div。这仍然不能动态工作,尽管它像上面一样呈现:

this.render = function(self){
  if(self.data){
    self.x = d3.scaleLinear()
               .domain([0, d3.max(self.data.map(function(d) {
                   return parseInt(d.daily_count);
                 }))
               ])
               .range([0, 500]);

    var chart = d3.select("#chart");

    var bars = chart.selectAll("d")
                 .data(self.data)

    bars.enter().append('div')
        .attr('class', 'bar-container row')
        .each(function(d) {
          d3.select(this).append('div')
            .attr('class', 'label four columns');
          d3.select(this).append('div')
            .attr('class', 'bar eight columns');
        })
        .merge(bars)
        .each(function(d){
          d3.select(this).selectAll('div.label')
            .text(function(d) {return d.date_string; });
          d3.select(this).selectAll('div.bar')
            .style('background-color', function(d){
              return (d.daily_count == 0 ? 'white' : '#1EAEDB')
            })
            .style('color', function(d){
              return (d.daily_count == 0 ? 'red' : 'white')
            })
            .style("width", function(d) {
              return self.x(d.daily_count) + "px";
            })
            .text(function(d) {
              return (d.daily_count == 0 ? 'closed' : d.daily_count)
            });
        })

    bars.exit().remove();

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    您的render 函数需要正确的“进入”、“更新”和“退出”选项。除此之外,请记住,您链接的 Bostock 示例使用 d3 版本 3.x,而您使用的是 d3 版本 4.x。

    在下面的演示中,这会绑定数据:

    var bars = body.selectAll("div")
        .data(data);
    

    之后,“进入”+“更新”选择,带有merge

    bars.enter().append("div")
        .attr("class", "row")
        .merge(bars)
        .style('background-color', function(d){
            return (d.daily_count == 0 ? 'white' : '#1EAEDB')
        })
        .style('color', function(d){
            return (d.daily_count == 0 ? 'red' : 'white')
        })
        .style("width", function(d) {
            return x(d.daily_count) + "px";
        })
        .text(function(d) {
            return (d.daily_count == 0 ? 'closed' : d.daily_count)
        });
    

    以及退出选择:

    bars.exit().remove();
    

    这是一个基于您的代码的演示(仅使用daily_count,因为我不知道您如何定位其他 div):

    var dataset = [{daily_count: 19},
    {daily_count: 29},
    {daily_count: 13},
    {daily_count: 45},
    {daily_count: 22},
    {daily_count: 42},
    {daily_count: 9}];
    
    render(dataset)
    
    d3.select("#btn").on("click", function(){
    	var newDataset = [];
    	var length = Math.ceil(Math.random()*20);
    	for (var i = 0; i < length; i++){
    		newDataset.push({daily_count: Math.floor(Math.random()*50)})
    	}
    	render(newDataset);
    })
    
    function render(data){
    
        x = d3.scaleLinear()
                   .domain([0, d3.max(data.map(function(d) {
                       return parseInt(d.daily_count);
                     }))
                   ])
                   .range([0, 300]);
    							 
    		var body = d3.select("body");
    
        var bars = body.selectAll("div")
                     .data(data);
    
        bars.enter().append("div")
    		 .attr("class", "row")
              .merge(bars)
              .style('background-color', function(d){
                return (d.daily_count == 0 ? 'white' : '#1EAEDB')
              })
              .style('color', function(d){
                return (d.daily_count == 0 ? 'red' : 'white')
              })
              .style("width", function(d) {
                return x(d.daily_count) + "px";
              })
              .text(function(d) {
                return (d.daily_count == 0 ? 'closed' : d.daily_count)
              });
    					
    		bars.exit().remove();
    
    }
    .row {
      font: 10px sans-serif;
      text-align: right;
      padding: 3px;
      margin: 2px;
      color: white;
    }
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <button id="btn">Click</button>

    【讨论】:

    • 非常感谢您的深入回答。当我只是在数据集中的每个项目中显示一个 div 中的数据时,我可以让它工作,但我一直试图让它与多个元素一起工作,其中数据集中的每个项目都显示为一个 div和两个子 div(一个标签和一个栏)。我将我更新后的最佳尝试放在我上面的原始答案的编辑中,尝试使用 .each(),它可以正确呈现,但仍然没有更新。我在这里还缺少什么?
    • 例如,您将如何在代码 sn-p 中更新具有两个子 div 的 div?添加额外的元素让我失望。
    • 请不要编辑您的问题来提出另一个问题。如果我的回答对您有所帮助,请通过接受/支持来确认,并在您的新问题中发布 another 问题。请记住,在我的回答中,我只处理了 1 个 div,因为我不知道您的数据。因此,在新问题中,也要发布数据样本。
    • 我的错?我不认为这是一个单独的问题,我也不打算在评论中发布代码。在这里,有你的观点......
    猜你喜欢
    • 2012-05-06
    • 1970-01-01
    • 1970-01-01
    • 2014-02-28
    • 2019-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多