【问题标题】:d3js updates only onced3js 只更新一次
【发布时间】:2016-05-01 20:40:24
【问题描述】:

我有一个可视化任务,我需要使用 d3.js 完成它。这是我的代码。

                var w = 700;
                var h = 500;
                var offset = 100;
                var padding = 20;
                var colors = d3.scale.category10();
                var svg = d3.select("body")
                    .append("svg")
                    .attr("width", w)
                    .attr("height", h);




                var texts = function(ds,ds2){
                    var stack = d3.layout.stack();
                    stack_data = stack(ds);

                    var xScale = d3.scale.ordinal()
                        .domain(d3.range(ds[0].length))
                        .rangeRoundBands([0, w-offset], 0.50);


                    var yScale = d3.scale.linear()
                        .domain([0,             
                            d3.max(stack_data, function(d) {
                                return d3.max(d, function(d) {
                                    return d.y0 + d.y -20;
                                });
                            })
                        ])
                        .range([padding, h-50]);

                    var xAxis = d3.svg.axis()
                        .scale(xScale)
                        .orient("bottom")
                        .ticks(ds[0].length);

                    gs = svg.selectAll("g").data(stack_data);

                    for (var i5 = 0; i5 < ds.length; i5++) {
                        gs.enter()
                        .append("g")
                        .attr("class", "stacked_bars")
                        .attr("fill", function(d, i) {
                            return colors(i);
                        });

                        asd = gs.selectAll("rect").data(function(d) { return d; });

                        asd.enter().append("rect");

                        asd.transition()
                            .duration(1000)
                            .attr("x", function(d, i) {
                                return xScale(i);
                            })
                            .attr("y", function(d) {
                                return h - yScale(d.y0) - yScale(d.y);
                            })
                            .attr("height", function(d) {
                                return yScale(d.y);
                            })
                            .attr("width", xScale.rangeBand())
                            .attr("class", "rectbar");

                    };

                    gs.append("g")  // add a group element to the svg
                        .attr("class", "axis") //Assign class "axis" to group
                        .attr("transform", "translate(0," + (h - padding) + ")")  // shift the axis to bottom
                        .call(xAxis);   // call the axis function 

                    gs.exit().remove();
}


                res = dataGenerator("Europe");
                dataset = res[0];
                dataset2 = res[1];

                texts(dataset,dataset2);

            d3.select("#selector").on("change", function() {
                    cont = d3.select(this).property('value');
                    res = dataGenerator(cont)

                    dataset = res[0]
                    dataset2 = res[1]

                    //svg.selectAll(".sym").remove()

                    texts(dataset,dataset2);


                }); 

它基本上是获取数据并生成堆叠条形图。当用户在页面上使用 select 元素时,它会更新数据并生成新的结果。它成功地获得了第一个结果,当用户选择另一个选项时,它也会发生。但是当用户再次尝试使用选择部分时。它只为数据集的第一项生成条形图。

因此,在这种特殊情况下,我将国家及其数据作为数字,在第一次加载和第一次更新时,它会成功显示所有内容,但在第二次更新时,它只会为数据集中的第一个国家生成条形图。我试图解决这个问题已经有几个小时了。我知道我只有一个小错误,但无法解决。

这里也是代码的 jsfiddle:https://jsfiddle.net/510ep9ux/4/

由于我是 d3.js 的新手,我可能不太了解更新概念。 那么,有什么猜测吗?

【问题讨论】:

  • 你能给我们做个 jsfiddle 吗?如果我可以对代码进行试验,提供答案会更容易。

标签: javascript d3.js data-visualization


【解决方案1】:

已解决,使用两个单独的函数 textsInittextsUpdate

https://jsfiddle.net/qxqdp36x/2/

本质上你需要将初始化和更新逻辑分开,并避免在更新时重新创建元素,这会导致意外行为。

此外,变量 gsasd 需要是全局变量才能被这两个函数访问。

var textsInit = function(ds, ds2) {

    var stack = d3.layout.stack();
    stack_data = stack(ds);

    var xScale = d3.scale.ordinal()
      .domain(d3.range(ds[0].length))
      .rangeRoundBands([0, w - offset], 0.50);


    var yScale = d3.scale.linear()
      .domain([0,
        d3.max(stack_data, function(d) {
          return d3.max(d, function(d) {
            return d.y0 + d.y - 20;
          });
        })
      ])
      .range([padding, h - 50]);

    var xAxis = d3.svg.axis()
      .scale(xScale)
      .orient("bottom")
      .ticks(ds[0].length);
    gs = svg.selectAll("g").data(stack_data);

    bars = gs.enter();
    bars.append("g")
      .attr("class", "stacked_bars")
      .attr("fill", function(d, i) {
        return colors(i);
      });

    asd = gs.selectAll("rect").data(function(d) {
      return d;
    });

    asd.enter().append("rect");

    asd.transition()
      .duration(1000)
      .attr("x", function(d, i) {
        return xScale(i);
      })
      .attr("y", function(d) {
        return h - yScale(d.y0) - yScale(d.y);
      })
      .attr("height", function(d) {
        return yScale(d.y);
      })
      .attr("width", xScale.rangeBand())
      .attr("class", "rectbar");

    gs.append("g") // add a group element to the svg
      .attr("class", "axis") //Assign class "axis" to group
      .attr("transform", "translate(0," + (h - padding) + ")") // shift the axis to bottom
      .call(xAxis); // call the axis function 
  }

还有:

var textsUpdate = function(ds, ds2) {
    var stack = d3.layout.stack();
    stack_data = stack(ds);

    var xScale = d3.scale.ordinal()
      .domain(d3.range(ds[0].length))
      .rangeRoundBands([0, w - offset], 0.50);

    var yScale = d3.scale.linear()
      .domain([0,
        d3.max(stack_data, function(d) {
          return d3.max(d, function(d) {
            return d.y0 + d.y - 20;
          });
        })
      ])
      .range([padding, h - 50]);

    gs.data(stack_data);
        asd = gs.selectAll("rect").data(function(d) { return d; });
      asd.transition()
        .duration(1000)
        .attr("x", function(d, i) {
          return xScale(i);
        })
        .attr("y", function(d) {
          return h - yScale(d.y0) - yScale(d.y);
        })
        .attr("height", function(d) {
          return yScale(d.y);
        })
        .attr("width", xScale.rangeBand())
        .attr("class", "rectbar");
  }

编辑修复了一个小错误,更新了asd 选择的数据。

【讨论】:

  • 非常感谢,但 Eric 的答案更接近我正在寻找的答案,因此我选择了他作为正确答案。
【解决方案2】:

我对您的代码进行了 2 处简单但至关重要的更改。

https://jsfiddle.net/guanzo/510ep9ux/6/ 来自

gs = svg.selectAll("g").data(stack_data);

gs = svg.selectAll("g.stacked_bars").data(stack_data);

轴也包含在 g 元素中,因此您必须确保只选择用于数据的元素,而不是不相关的元素。

来自

gs.append("g")
.attr("class", "axis") 
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);

svg.append("g")
.attr("class", "axis") 
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);

如果您进入浏览器检查器,您会看到每个 stacked_bars 元素都有一个轴元素,显然您只需要 1 个。看起来只有 1 个轴,因为它们绝对定位并堆叠在一起。

我对其进行了更改,以便在创建 svg 时附加轴,并且每次选择新数据时,轴都会自行更新。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-20
    • 2020-10-30
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多