2

d3.js を使用して多数の svg:ellipse 要素 (~5000) を作成しています。最初のレンダリングの後、データ項目の一部をバックエンド経由で更新できます (どの項目かはわかります)。これらの楕円の色を変更したい (たとえば)。

データ項目に関連付けられた DOM 要素をすばやく復元する方法はありますか? データのサブセットを使用して DOM 要素の完全なセットで結合を再計算する場合の明白な手法以外は?

var myData = [{ id: 'item1'}, { id: 'item2' }, ... { id: 'item5000' }];
var create = d3.selectAll('ellipse).data(myData, function(d) { return d.id; });
create.enter().append('ellipse').each(function(d) {
    // initialize ellipse
});

// later on

// this works, but it seems like it would have to iterate over all 5000 elements
var subset = myData.slice(1200, 1210); // just an example
var updateElements = d3.selectAll('ellipse').data(subset, function(d) { return d.id; });
updateElements.each(function(d) {
    // this was O(5000) to do the join, I _think_
    // change color or otherwise update
});

私は毎秒複数回更新をレンダリングしています (実際には可能な限り高速です)。一握りの要素を更新するのは O(5000) のようです。

私は次のようなことを考えていました:

create.enter().append('ellipse').each(function(d) {
    d.__dom = this;
    // continue with initialization
});

// later on

// pull the dom nodes back out
var subset = myData.slice(1200, 1210).map(function(d) { return d.__dom; });
d3.selectAll(subset).each(function(d) {
    // now it should be O(subset.length)
});

これは機能します。しかし、これは一般的なパターンのように思われるので、この問題を解決する標準的な方法があるかどうか疑問に思っていますか? 実際には複数のレンダリングでデータを使用したいので、お互いにつまずかないようにもっと賢くする必要があります。

基本的に、d3 は DOM からのマップを提供することを知っています -> domElement を介したデータ。__data__. 自分で手動で値をキャッシュする以外に、リバース マップを計算するための高速で簡単な方法はありますか?

データから取得する必要があります-> DOM。

4

1 に答える 1

4

d3 選択参照を維持している限り (このcreate例では)、D3 はマップを使用してデータ キーを更新の DOM ノードにマップしているため、実際には O(log n) です。

サブセットに対して、D3 update /data operator メソッドと loop メソッドを使用していくつかのテストを行うことができます。

var d3UpdateMethod = function() {
    svg.selectAll("ellipse").data(subset, keyFunc)
        .attr("style", "fill:green");
}
var loopMethod = function() {
    for (var i=0; i < subset.length; i++) {
        svg.selectAll(".di" + i)
        .attr("style", "fill:green");
    }
}
var timedTest = function(f) {
    var sumTime=0;
    for (var i=0; i < 10; i++) {
        var startTime = Date.now();
        f();
        sumTime += (Date.now() - startTime);
    }
    return sumTime / 10;
};
var nextY = 100;
var log = function(text) {
    svg.append("text")
        .attr("x", width/2)
        .attr("y", nextY+=100)
        .attr("text-anchor", "middle")
        .attr("style", "fill:red")
        .text(text);
};

log("d3UpdateMethod time:" + timedTest(d3UpdateMethod));
log("loopMethod time:" + timedTest(loopMethod));

また、あなたがここでやろうとしていることを理解するために、フィドルを作成しました。


サブセット内のノードを追跡しやすくするもう 1 つの方法は、サブセットに CSS クラスを追加することです。例えば:

var ellipse = svg.selectAll("ellipse").data(data, keyFunc).enter()
    .append("ellipse")
    .attr("class", function (d) { 
        var cl = "di" + d.i;
        if (d.i % 10 == 0)
            cl+= " subset"; //<< add css class for those nodes to be updated later
        return cl;
    })
    ...

「サブセット」クラスが、後で更新されるサブセット内にあることがわかっているノードにのみ追加されることに注意してください。その後、次の方法で更新するために後でそれらを選択できます。

svg.selectAll("ellipse.subset").attr("style", "fill:yellow");

このテストも含めるようにフィドルを更新しましたが、directMethod とほぼ同じくらい高速です。

于 2013-02-16T07:30:40.850 に答える