【问题标题】:Last element added to a D3 bar chart doesn't sort添加到 D3 条形图的最后一个元素未排序
【发布时间】:2019-12-05 11:41:23
【问题描述】:

我是一个 D3 / Javascript 菜鸟,我正在尝试创建一个带有添加条形选项的图表(通过更新 > 输入选择),然后重新对它们进行排序。

但是,最后添加的bar拒绝参与重新排序。

谁能告诉我: a) 为什么会发生这种情况 b) 如何解决它

查看 Codepen:https://codepen.io/benjamesdavis/pen/JjodJwy?editors=1010

            //Width and height
            var w = 900;
            var h = 450;

            var array = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
                            11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];

            dataset=[];             
            for(let i=0; i<array.length; i++)
                {dataset[i] = {"key":i, "value": array[i]}}

            var xScale = d3.scaleBand()
                            .domain(d3.range(dataset.length))
                            .rangeRound([0, w])
                            .paddingInner(0.05);

            var yScale = d3.scaleLinear()
                            .domain([0, d3.max(dataset, d=> d.value)])
                            .range([0, h]);

            //Create SVG element
            var svg = d3.select("body")
                        .append("svg")
                        .attr("width", w)
                        .attr("height", h);



            //Create bars
            svg.selectAll("rect")
               .data(dataset)
               .enter()
               .append("rect")
               .attr("x", function(d, i) {
                    return xScale(i);
               })
               .attr("y", function(d) {
                    return h - yScale(d.value);
               })
               .attr("width", xScale.bandwidth())
               .attr("height", function(d) {
                    return yScale(d.value);
               })
               .attr("fill", function(d) {
                    return "rgb(0, 0, " + Math.round(d.value * 10) + ")";
               });




            //On click, update with new data            
            d3.select("#newBar")
                .on("click", function() {

                    //Add one new value to dataset
                    var maxValue = 25;
                    var newNumber = Math.floor(Math.random() * maxValue);
                    newNumber = {"key":dataset.length, "value": newNumber}
                    dataset.push(newNumber);

                    //Update scale domains
                    xScale.domain(d3.range(dataset.length));
                    yScale.domain([0, d3.max(dataset, d=> d.value)]);

                    //Select…
                     bars = svg.selectAll("rect")
                        .data(dataset)

                    //Enter…
                    bars.enter()
                        .append("rect")
                        .attr("x", w)
                        .attr("y", function(d) {
                            return h - yScale(d.value);
                        })
                        .attr("width", xScale.bandwidth())
                        .attr("height", function(d) {
                            return yScale(d.value);
                        })
                        .attr("fill", function(d,i) {
                            return "rgb(0, 0, " + Math.round(d.value * 10) + ")";
                        })
                        .merge(bars)
                        .transition()
                        .duration(500)
                        .attr("x", function(d, i) {
                            return xScale(i);
                        })
                        .attr("y", function(d) {
                            return h - yScale(d.value);
                        })
                        .attr("width", xScale.bandwidth())
                        .attr("height", function(d) {
                            return yScale(d.value);
                        });

                });


            //Re-Sort Bars
            d3.select("#sortBars").on("click",function(){
                d3.shuffle(dataset)

                 bars.data(dataset,d => d.key)
                    .transition(2000)
                    .attr("x", function(d, i) {             
                        return xScale(i);
                    })                                  
                })

【问题讨论】:

  • 我认为这与您的变量“bars”范围有关。
  • 你是对的。如果我在排序代码中将“bars.data”更改为“svg.selectAll("rect").data”,它就可以工作。不是 100% 确定这些选择之间的区别是什么。 //Re-Sort Bars d3.select("#sortBars").on("click",function(){ d3.shuffle(dataset) svg.selectAll("rect").data(dataset,d =&gt; d.key) .transition(2000) .attr("x", function(d, i) { return xScale(i); }) })

标签: javascript d3.js


【解决方案1】:

具体问题是,当您在第 70 行 enter() 选择 bars 并将其合并到第 83 行的 bars 时,您不会将新的合并选择保存回 bars。因此,当您在第 104 行重新排序时,bars 更新选择不包含最新的条。

一般来说,要记住的是,数据绑定选择始终是更新选择,并且选择(从 D3v4 开始)是不可变的,所以当你这样做时

bars.enter()
    .<do stuff to just the enter selection>
    .merge(bars) // merge the update and enter selections together
    .<do more stuff to the merged update+enter selections>

bars 的值仍然是旧的更新选择。如果您以后想用它做更多的事情,您必须明确保存合并的选择。

bars = bars.enter() // note the assignment to bars!
    .<do stuff to just the enter selection>
    .merge(bars) // merge the update and enter selections together
    .<do more stuff to the merged update+enter selections>

【讨论】:

    【解决方案2】:

    我认为这是事实,当你定义bars时,它在add-bars函数的范围内,而不是re-sort函数的范围内,所以首先,你需要每次都进行选择。然后,您需要确保两次都使用该密钥。这是我对您的代码的看法:

    //宽高 变量 w = 500; 变量 h = 200;

        var array = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
                        11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];
    
        dataset=[];     
    
        for(let i=0; i<array.length; i++)
            {dataset[i] = {"key":i, "value": array[i]}}
    
        var xScale = d3.scaleBand()
                        .domain(d3.range(dataset.length))
                        .rangeRound([0, w])
                        .paddingInner(0.05);
    
        var yScale = d3.scaleLinear()
                        .domain([0, d3.max(dataset, d=> d.value)])
                        .range([0, h]);
    
        //Create SVG element
        var svg = d3.select("body")
                    .append("svg")
                    .attr("width", w)
                    .attr("height", h);
    
    
    
        //Create bars
        svg.selectAll("rect")
           .data(dataset)
           .enter()
           .append("rect")
           .attr("x", function(d, i) {
                return xScale(i);
           })
           .attr("y", function(d) {
                return h - yScale(d.value);
           })
           .attr("width", xScale.bandwidth())
           .attr("height", function(d) {
                return yScale(d.value);
           })
           .attr("fill", function(d) {
                return "rgb(0, 0, " + Math.round(d.value * 10) + ")";
           });
    
    
    
    
        //On click, update with new data            
        d3.select("#newBar")
            .on("click", function() {
    
                //Add one new value to dataset
                var maxValue = 25;
                var newNumber = Math.floor(Math.random() * maxValue);
                newNumber = {"key":dataset.length, "value": newNumber}
                dataset.push(newNumber);
    
                //Update scale domains
                xScale.domain(d3.range(dataset.length));
                yScale.domain([0, d3.max(dataset, d=> d.value)]);
    
                //Select…
                 bars = svg.selectAll("rect")
                           .data(dataset,d => d.key) //make sure you use the key here too!
    
    
                //Enter…
                bars.enter()
                    .append("rect")
                    .attr("x", w)
                    .attr("y", function(d) {
                        return h - yScale(d.value);
                    })
                    .attr("width", xScale.bandwidth())
                    .attr("height", function(d) {
                        return yScale(d.value);
                    })
                    .attr("fill", function(d,i) {
                        return "rgb(0, 0, " + Math.round(d.value * 10) + ")";
                    })
                    .merge(bars)
                    .transition()
                    .duration(500)
                    .attr("x", function(d, i) {
                        return xScale(i);
                    })
                    .attr("y", function(d) {
                        return h - yScale(d.value);
                    })
                    .attr("width", xScale.bandwidth())
                    .attr("height", function(d) {
                        return yScale(d.value);
                    });
    
            });
    
    
        //Re-Sort Bars
        d3.select("#sortBars").on("click",function(){
            d3.shuffle(dataset)
            bars =  svg.selectAll("rect").data(dataset,d => d.key) //redefine bars, and use the key
                .transition(2000)
                .attr("x", function(d, i) {             
                    return xScale(i);
                })                                  
            })
    

    【讨论】:

      猜你喜欢
      • 2021-07-10
      • 1970-01-01
      • 2017-06-22
      • 1970-01-01
      • 1970-01-01
      • 2014-05-21
      • 1970-01-01
      • 1970-01-01
      • 2014-01-14
      相关资源
      最近更新 更多