【问题标题】:D3 horizontal stacked bar chart add and remove dataD3水平堆积条形图添加和删除数据
【发布时间】:2014-07-21 19:40:55
【问题描述】:

我有一个简单的水平 D3 堆叠条形图。我使用下拉菜单选择不同的数据集以更新图表值。

如果 ds1 和 ds2 具有相同数量的数据,即 ds1 有 2 个数据点,ds2 有 2 个数据点,则过渡是平滑的,并且我的值会很好地更新。

但是,如果我有两个数据点数量不同的数据集,即 ds1 有 3 个数据点,而 ds2 只有 2 个或可能 4 个数据点,我无法让 Enter、Update 和 Exit 正常工作。

我认为这与 D3 堆栈函数有关,该函数将值转换为不构成 D3 中更新和退出方法的一部分的对象。

如果你能告诉我我应该做什么,将不胜感激?我的完整代码粘贴在下面。

<!DOCTYPE html>

    <html>
        <head>
            <title>Update horizontal stacked bar chart</title>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width">   
            <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    </head>

    <body>
             <div >
                  <select id="dropdown" onchange="updateData()">

                      <!--need blank value in order to have title in selection-->

                      <option value="ds1">ds1</option>
                      <option value="ds2">ds2</option>
                      <option value="ds3">ds3</option>
                      <option value="ds4">ds4</option>
                  </select>
              </div>        


      <script type="text/javascript">

            var w = 1500,
                    h = 300;

                var rectW = 100 * 5;

                var color = d3.scale.ordinal()
                            .range(["#1459D9", "#daa520","#F7C319"]);


    var ds1 = [[{x:0,y:15}],[{x:0,y:85}]];
    var ds2 = [[{x:0,y:35}],[{x:0,y:65}]];
    var ds3 = [[{x:0,y:10}],[{x:0,y:20}],[{x:0,y:70}]];
    var ds4 = [[{x:0,y:60}]];

        //Set up stack method
        var stack = d3.layout.stack();

        //Data, stacked
        stack(ds1);

        var canvas = d3.select("body") 
                .append("svg") 
                .attr("width",w)
                .attr("height",300)        
        ;


        var appending = canvas.selectAll("q") 
                .data(ds1)                           
                .enter()                    
                .append("g")
                .style("fill", function(d,i){return color(i);})
        ;


        appending.selectAll("stackrect") 
                .data(function (d){return d;}) 
                .enter()
                .append("rect") 
                .attr("id","recth")
                .attr("x",function (d){return  (w *.50 - (rectW/2)) + d.y0 * 5 ;}) 

                .attr("y",90)
                .attr("width",function (d){return (d.y * 5 );})
                .attr("height",50);       




        function updateData() {

        stack(eval("("+dropdown.value+")")); 

        appending.data(eval("("+dropdown.value+")"));


        //ds1 and ds2 equal number of datum. Update works fine.
        appending.selectAll("#recth") 
                .data(function (d){return d;})
                .transition().duration(600)
                .style("opacity", 0.5)
                .transition().duration(600)
                .style("opacity", 1.0)    
                .attr("x",function (d){return  (w *.50 - (rectW/2)) + d.y0 * 5 ;}) 
                .attr("y",90)
                .attr("width",function (d){return (d.y * 5 );})
                .attr("height",50);

        //update method not working
        appending.selectAll("#recth")
             .data(function (d){return d;})
             .enter()
             .append("rect")
                .transition().duration(600)
                .style("opacity", 0.5)
                .transition().duration(600)
                .style("opacity", 1.0)    
                .attr("x",function (d){return  (w *.50 - (rectW/2)) + d.y0 * 5 ;}) 
                .attr("y",90)
                .attr("width",function (d){return (d.y * 5 );})
                .attr("height",50);               


       //exit method not working
        appending.selectAll("#recth")
        .data(function (d){return d;})     
        .exit()
        .transition().duration(600)
                .style("opacity", 0.5)
                .transition().duration(600)
                .style("opacity", 1.0)    
                .attr("x",function (d){return  (w *.50 - (rectW/2)) + d.y0 * 5 ;}) 
                .attr("y",90)
                .attr("width",function (d){return (d.y * 5 );})
                .attr("height",50)               
        .remove();        
        }

        </script>

    </body>
</html>

【问题讨论】:

  • @ckersch 是正确的,您应该使用 class 而不是 idHERE 是 HTML5 规范所说的,这几乎是所有其他 HTML 规范所说的,它应该是独一无二的。您“发现 id 在其他示例中工作得非常好”这一事实仅意味着您很幸运能够使用能够容忍呈现无效标记的浏览器。
  • 我同意你所说的两个。但是,由于在上面的示例中我只调用了一个元素,所以使用 id 就可以了。上课也试过了,还是不行。

标签: javascript html d3.js


【解决方案1】:

我没有看完整个东西,但我注意到了一些错误:

1) 不要将 ID 用作多个事物的选择器。 ID 应该是唯一的,如果您有多个具有相同 ID 的东西,选择器可能无法正常工作。改用类。

2) 添加数据时,请确保添加的内容与您在初始 selectAll() 方法中使用的选择器匹配。例如,如果您有.selectAll('.rectClass'),请确保提供您创建类rectClass 的所有元素,否则选择器和数据结构可能无法正常工作。

一旦这些都被修复,这个例子展示了更新/进入/退出模式是如何工作的:example

【讨论】:

  • 感谢您的帮助。但是,我发现 id 在我尝试过的其他示例中运行良好。我认为问题在于堆栈函数,因为它不允许正确附加数据,因为堆栈函数基于第一个数据集创建了一组初始对象。例如,如果第一个数据集有 4 个数据项,那么将创建 4 个对象,然后无论更新过程如何,它们都会保持不变。
  • 即使它们看起来工作正常,你也不应该使用它们。 ID 被设计为唯一的,大部分 javascript 核心都假定它们是唯一的。有些东西最终会破裂。 stack 是一个函数,所以它不关心过去用在什么上面。
  • 我也不确定这应该做什么:appending.selectAll("#recth").data(function (d){return d;})
  • 选择所有id为recth的矩形。然后返回他们的数据。因此,如果您选择 ds1,它会返回用于更新图表的 ds1 的数据。如果您从下拉列表中选择 ds2,它会从 ds2 中选择数据并更新图表。当第二个 ds(在我的示例中为 ds3 和 4)具有与 ds1 不同数量的数据点时,事情就不起作用了。把代码放到浏览器上玩玩吧。
猜你喜欢
  • 1970-01-01
  • 2020-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-15
  • 1970-01-01
相关资源
最近更新 更多