1

我正在使用 d3 创建一个可视化,它将有 60 个顶部和 60 个底部矩形。每个矩形将包含大约 100-150 个圆圈。数据通过 websocket 流式传输。如果没有过滤,更新非常耗时。我正在尝试通过选择性更新来优化它。但是,看起来我并不完全理解 .filter()。这是处理矩形的代码部分的 jsFiddle

http://jsfiddle.net/vjaT2/1/

正如您可以从函数 updateRect 中的 js 注释中注意到的那样,我尝试了几种方法。1. 在 .data 中过滤 2. 创建一个 id 并在 id 上执行 selectAll。

但是这两种方法都不起作用。

关于我遗漏或做错了什么的任何帮助?

    var bottom_rects = 1;
var top_rects = 1;
var rects = [];

function generate_rect(){
    var created = '';

    // 6(*10) top rectangles & 6(*10) bottom rectangles 

    if(bottom_rects <= top_rects-1) {
        new_rect = {"name":"rect_bottom_"+bottom_rects,"location":"bottom","minx":0,"miny":Math.floor((2*h)/3),"maxx":0,"maxy":h};
        rects.push(new_rect);
        //fix x values
        var step  = Math.floor(w/bottom_rects);
        var x = 0;
        for (var i = 0; i < rects.length; i++) {
            var item = rects[i];
            if (item.location == "bottom"){
                    item.minx = x;
                    item.maxx = x+step;
                    x=x+step;
            }

        }
        bottom_rects++;
        created = "bottom";
    } else {
        new_rect = {"name":"rect_top_"+top_rects,"location":"top","minx":0,"miny":0,"maxx":0,"maxy":Math.floor(h/3)};
        rects.push(new_rect);
        //fix x values
        var step  = Math.floor(w/top_rects);
        var x = 0;
        for (var i = 0; i < rects.length; i++) {
            var item = rects[i];
            if (item.location == "top"){
                    item.minx = x;
                    item.maxx = x+step;
                    x=x+step;
            }
        }
        top_rects++;
        created = "top";
    }
    updateRect(created);
}

var w = 1200,
    h = 760;

var vis = d3.select("#chart").append("svg:svg")
    .attr("width", w)
    .attr("height", h);

function updateRect(location) {
    //var allrects = vis.selectAll("rect")
    var allrects = vis.selectAll(".rect_"+location)
        //.data(rects.filter(function(d)  { return d.location == location; }))
        .data(rects)
            //update
            .attr("x", function(d)      {  return d.minx;        })
            .attr("y", function(d)      {  return d.miny;        })
            .attr("width",function(d)   {  return d.maxx-d.minx; })
            .attr("height", function(d) {  return d.maxy-d.miny; })
            //create
        .enter().append("rect")         
            .attr("x", function(d)      {  return d.minx;        })
            .attr("y", function(d)      {  return d.miny;        })
            //.attr("id", "rect_"+location)
            .attr("width",function(d)   {  return d.maxx-d.minx; })
            .attr("height", function(d) {  return d.maxy-d.miny; })
            .attr("fill", "blue")
            .attr("stroke", "black")
            .style("stroke-width", 2)
            .style("fill-opacity", 0.2)
        .exit().remove();
}   

for(var i =0; i < 12; i++) setTimeout(generate_rect,(i+1)*200);
4

1 回答 1

2

有两种不同的filter()功能。第一个是可以应用于任何数组的Javascriptfilter,与 D3 无关。第二个是D3filter,您可以将其应用于选择。

对于选择性更新,原则上您可以同时使用两者。在第一种情况下,您在将数据传递给之前过滤数据.data()(正如您已经尝试过的那样),然后对与现有 DOM 元素匹配的内容进行操作。这里重要的是,您几乎肯定需要提供一个函数来.data()告诉它如何将数组中的数据与 DOM 元素匹配。文档中有更多内容。

对于您想要做的事情,我建议使用.filter()对选择进行操作的其他功能。也就是说,您可以像在通常情况下一样进行选择,然后从该选择中过滤元素。对于您的示例,代码看起来像这样。

vis.selectAll("rect")
   .filter(function(d) { return d.location == location; });

或者,您可以使用按类选择的第三种方法(您也尝试过),但是您不需要任何其他过滤器功能。但是,如果您想将新数据绑定到这些元素,则必须注意仅将用于此特定元素子集的数据传递给它,即您需要在将数据传递给之前过滤数据.data()。实际上,这可能是最不直观的方式,因为您需要在多个位置对数据进行分区。

于 2013-09-21T09:13:12.270 回答