3

d3 line 関数にフィードする lineData 配列を変更して、5 秒ごとに一連の線を描画しようとしています。

関連するコードの抜粋を次に示します。

var svg = d3.select("body").append("svg:svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .attr("id", "svgMain")
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
      .call(drag);

var lines = svg.append("g")
      .attr("id", "lines");

function changingLines() {
      lines.selectAll("line")
        .data(lineData)
        .enter().append("line")
        .attr("x1", function(d, i) { console.log(d[0][0]); return d[0][0];})
        .attr("y1", function(d, i) { console.log(d[0][1]); return d[0][1];})
        .attr("x2", function(d, i) { return d[1][0];})
        .attr("y2", function(d, i) { return d[1][1];})
        .style("stroke", "#000")
        .style("stroke-width", "0.5")
        .attr("class", "lines");

     lines.selectAll("line").exit().remove();
     setTimeout(changingLines, 2000);
 }

lineData 配列の異なる値を使用して、関数 changingLines() を 2 秒ごとに呼び出します。

エラーが表示されます: Uncaught TypeError: Object has no method 'exit

私は何を間違っていますか?

4

1 に答える 1

18

実際、このコードには関連する問題がいくつかあります。を呼び出すとchangingLines、属性が更新される唯一の要素は、enterセレクション内の要素です (呼び出しは selection` を.enter()返しますenter)。

デフォルトでは、渡した配列に新しい要素がある場合に.data()のみ要素を選択に追加することに注意してください。enter

// Old data array:
var data = [1, 2, 3, 4];

// New data array:
var newData = [5, 6, 7, 8, 9];

/*
The first 4 elements in newData will replace the first 4 elements of oldData.
The number of new elements (which will be in the enter() selection) is only 1.
*/

すべきことは、data呼び出しによって計算された結合を保存し、それを使用してenterexit、およびupdateセレクションに個別にアクセスすることです。

var linesContainer = svg.append("g").attr("id", "lines");

function changingLines() {

    /* Compute the data join */
    var lines = linesContainer.selectAll("line").data(lineData);

    /* Enter */
    lines.enter().append("line");

    /* Exit */
    lines.exit().remove();

    /* Update */
    lines
         .attr("x1", function(d, i) { console.log(d[0][0]); return d[0][0];})
         .attr("y1", function(d, i) { console.log(d[0][1]); return d[0][1];})
         .attr("x2", function(d, i) { return d[1][0];})
         .attr("y2", function(d, i) { return d[1][1];})
         .style("stroke", "#000")
         .style("stroke-width", "0.5")
         .attr("class", "lines");

    setTimeout(changingLines, 2000);
}

これにより、古い要素が削除され、属性とスタイルが更新される前にline新しい要素が追加されます。line

https://github.com/mbostock/d3/wiki/Selections#wiki-enter

追加または挿入すると、入力選択が更新選択にマージされます。このアプローチにより、入力と更新の間のコードの重複が削減されます。演算子を入力選択と更新選択の両方に別々に適用するのではなく、ノードに入った後で演算子を更新選択に適用できるようになりました。まれに、更新中のノードでのみオペレーターを実行したい場合は、新しいノードに入る前に更新選択でそれらを実行できます。

これにより、 を呼び出せないという問題も解決するはずexit()です。2 回目に呼び出しlines.selectAll("line")たとき、新しいセレクションを作成していたため、前回の結合時に計算されたセレクションにアクセスできませんでした。

この記事を読んで、もう一度読んでください: http://bost.ocks.org/mike/join/

于 2012-12-12T04:57:28.870 に答える