1

d3.js を使用して動的な力指向のネットワーク マップを作成しました。マップは最初にすべてのネットワーク ノードを取得し、ノードを結合する線として表示されるネットワーク インターフェイスで正しく表示します。これはすべてうまくいきます。

ユーザーが特定のプロジェクトに属するネットワーク インターフェイスをフィルタリングすることを決定した場合、ここで問題が発生します。同じ d3.layout.force インスタンスを再利用し、最初にマップを作成する同じ関数を実行しますが、新しいデータを使用します。物事を単純にするために、質問に関係のないものをすべて削除して、ソースをかなり圧縮しました。

var _this = {
    graphLayout     : d3.layout.force(),
    node : null,
    link : null,
    selectedProject : null,

    /*****************************************************
        Initialize engine
     *****************************************************/
    render : function() {
        // Creates the SVG container, sets up markers and gradients and whatnots
        // unnecessary for me to include here I think.

        // Start simulation
        _this.update();

        // Apply event handling and set up onTick
    },

    /*****************************************************
        Perform a data update. This will read data from an
        external url, and redraw all graphics.
     *****************************************************/
    update : function(project) {
        if (project !== undefined) {
            _this.selectedProject = project;
        }

        url = 'someService'+(!project ? '/GetNodes' : '/GetNodesByProjectId?projectId='+project.ProjectNumber);
        d3.json(url, function(json) {
            // Update nodes based on data
            // Apply data to graph layout
            _this.graphLayout
                .nodes(json.nodes)
                .links(json.links)
                // Even more parameters which are unnecessary for this question
                .start();

            // Join lines config
            _this.link = d3.select(" svg > .lineContainer").selectAll("g.link").data(_this.graphLayout.links());
            var group = _this.link.enter().append("svg:g")
                // More attributes and click event handling for the lines
                .attr('id',         function(d) { return d.InterfaceNumber; });
            group.append("svg:line");
            _this.link.exit().remove();

            // Node rendering config
            _this.node = d3.select(" svg > .nodeContainer").selectAll("g.node").data(_this.graphLayout.nodes());
            group = _this.node.enter().append("svg:g")
                // More attributes and click event handling for the nodes
                .attr('id',         function(d) { return d.Id; });
            group.append("svg:path")
                .attr("d", _this.nodeSVGPath)
                .attr("fill",       function(d) { return "url(#blackGradient)"; });

そして、ここで私の問題に遭遇します:

            // Add label to node
            group.append('svg:text').attr('class', 'label').attr('transform', 'translate(25, 30)').text(function(d,i) { return d.Name; });
            _this.node.exit().remove();
        });
    },

ここで .text に配置された function(d,i) は、update が 2 回目に呼び出されたときに実行されないようです。ここでd3に何かがキャッシュされていますか、それとも何か不足していますか?

ここでの問題は、ノード (または行) に正しいデータオブジェクトが含まれているが、ノードに表示されるテキストが一致しないことです。これにより、d3js は svg オブジェクトを完全に再利用したものの、新しく更新されたオブジェクトとデータを交換したと思われます。 .

4

1 に答える 1

1

はい、あなたはこの 1 つの重要な事実を見逃しています。enter() 関数は、まだ要素がないデータのサブセレクションを作成します。代わりに次のことを行う必要があります。

// Node rendering config
_this.node = d3.select(" svg > .nodeContainer").selectAll("g.node").data(_this.graphLayout.nodes());
group = _this.node.enter().append("svg:g")
// More attributes and click event handling for the nodes
    .attr('id', function(d) { return d.Id; });
group.append("svg:path")
    .attr("d", _this.nodeSVGPath)
    .attr("fill",       function(d) { return "url(#blackGradient)"; });
    // Add label to node
group.append('svg:text').attr('class', 'label').attr('transform', 'translate(25, 30)');

// now set the text for all g.node > g > text elements, new or old
_this.node.select('g > text').text(function(d,i) { return d.Name; });

_this.node.exit().remove();

group は _this.node の enter() サブセレクションであるため、各呼び出しの前に作成された要素が含まれることはありません。最後に、テキストを設定する場所で、グループの代わりに _this.node を使用して、新規または旧式のすべてのテキスト ノードを選択します。それは役に立ちますか?

于 2013-01-31T16:10:20.013 に答える