0

ノードのデータをグラフに非同期的に入力しようとしています。

非同期にフェッチされたデータが実際にグラフにバインドされ、準備ができたらレンダリングされるようにするにはどうすればよいですか?

まず、グラフ構造、ノード、およびリンクをレンダリングします。次に、データの準備ができたら、データをノードのプロパティとしてレンダリングします。新しいノードは、親のノードと対話することによって動的に追加でき、ノードのプロパティの完了を待ちたくありません。

Vivagraph.js ライブラリを使用していることに注意してください。graphはライブラリで作成されたオブジェクトでaddLinks()ありgetNode()、その関数のプロパティです - Vivagraph demoのデモを参照してください。私はそれを私の試みの下書きとして使用しています。

私が経験した問題は、ノードが追加されるとすぐにノードがグラフにレンダリングされることです - addNode()またはaddLinks(node1, node2)関数 - 一方、ノードのプロパティは非同期的にフェッチされます - getNode(node).property = updatedValue - 結果はundefinedです。

EDITED -コメントに基づく簡略化されたコード

以下に、この (素晴らしい) ライブラリの作成者である @Anvaka が提供するチュートリアルに基づいた、実用的なモックアップ バージョンを含めます。

私の目標は、グラフをすぐにレンダリングして対話を可能にし、サード パーティから取得している間にデータを更新することです。

// attempt 1: fetch data async
var fetchInfo = function (graph, nodeId) {
    var root = 'http://jsonplaceholder.typicode.com';

    $.ajax({
        url: root + '/photos/' + nodeId,
        method: 'GET'
    }).then(function (data) {
        graph.getNode(nodeId).data = data.thumbnailUrl;
        console.log(graph.getNode(nodeId));
    });
};

// attempt 2: defer ajax directly
var fetchInfo_2 = function (graph, nodeId) {
    var root = 'http://jsonplaceholder.typicode.com';

    return $.ajax({
        url: root + '/photos/' + nodeId,
        method: 'GET'
    });
};

function main() {
    // As in previous steps, we create a basic structure of a graph:
    var graph = Viva.Graph.graph();

    graph.addLink(1, 2);
    fetchInfo(graph, 1); // updated data is undefined when graph is rendered 
    fetchInfo(graph, 2); // updated data is undefined when graph is rendered 

    /* trying a different outcome by deferring whole ajax
    graph.getNode(1).data = fetchInfo_2(1).done(function(data) {
      data.thumbnailUrl;
    }); // the whole object is deferred but cannot fetch data

    graph.getNode(2).data = fetchInfo_2(2).done(function(data) {
      data.thumbnailUrl;
    });  // the whole object is deferred but cannot fetch data
    */


    var graphics = Viva.Graph.View.svgGraphics(),
        nodeSize = 24,
        addRelatedNodes = function (nodeId, isOn) {
            for (var i = 0; i < 6; ++i) {
                var child = Math.floor((Math.random() * 150) + nodeId);
                // I add children and update data from external sources
                graph.addLink(nodeId, child);
                fetchInfo(graph, child);
            }
        };


    // dynamically add nodes on mouse interaction
    graphics.node(function (node) {
        var ui = Viva.Graph.svg('image')
            .attr('width', nodeSize)
            .attr('height', nodeSize)
            .link(node.data);

        console.log('rendered', node.id, node.data);

        $(ui).hover(function () {

            // nodes are rendered; nodes' data is undefined 
            addRelatedNodes(node.id);
        });
        return ui;
    }).placeNode(function (nodeUI, pos) {
        nodeUI.attr('x', pos.x - nodeSize / 2).attr('y', pos.y - nodeSize / 2);
    });

    graphics.link(function (link) {
        return Viva.Graph.svg('path')
            .attr('stroke', 'gray');
    }).placeLink(function (linkUI, fromPos, toPos) {
        var data = 'M' + fromPos.x + ',' + fromPos.y +
            'L' + toPos.x + ',' + toPos.y;

        linkUI.attr("d", data);
    })

    var renderer = Viva.Graph.View.renderer(graph, {
        graphics: graphics
    });
    renderer.run();
}

main();
svg {
    width: 100%;
    height: 100%;
}
<script src="https://rawgit.com/anvaka/VivaGraphJS/master/dist/vivagraph.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

4

1 に答える 1

1

コメントで述べたように、非同期プロセスの結果として行う作業は、コールバックで行う必要があります。これには、すべてのレンダリング作業が含まれます。

jQuery の deferred (Ajax 呼び出しの結果など) の場合、コールバックは.thenまたはを介し​​て定義され.done、リソースを取得する操作をそのリソースの操作から切り離すことができます。

イメージ ソースの設定はレンダリング作業なので、コールバックで行う必要があります。以下は、画像をフェッチして延期された結果を返す関数で、nodeコールバック関数はそれを使用して独自の作業を行います。

function fetchInfo(id) {
    var root = 'http://jsonplaceholder.typicode.com';
    return $.getJSON(root + '/photos/' + id);
}

function main() {
    var graph = Viva.Graph.graph(),
        graphics = Viva.Graph.View.svgGraphics(),
        nodeSize = 24,
        addRelatedNodes = function (nodeId, count) {
            var childId, i;
            for (i = 0; i < count; ++i) {
                childId = Math.floor(Math.random() * 150) + nodeId;
                graph.addLink(nodeId, childId);
            }
        };
    
    graphics
        .node(function (node) {
            var ui = Viva.Graph.svg('image')
                .attr('width', nodeSize)
                .attr('height', nodeSize)
                .link('http://www.ajaxload.info/images/exemples/24.gif');
            
            $(ui).dblclick(function () {
                addRelatedNodes(node.id, 6);
            });

            // render when ready
            fetchInfo(node.id).done(function (data) {
                ui.link(data.thumbnailUrl);
            });

            return ui;
        })
        .placeNode(function (nodeUI, pos) {
            nodeUI.attr('x', pos.x - nodeSize / 2).attr('y', pos.y - nodeSize / 2);
        })
        .link(function (link) {
            return Viva.Graph.svg('path')
                .attr('stroke', 'gray');
        })
        .placeLink(function (linkUI, fromPos, toPos) {
            var data = 
                'M' + fromPos.x + ',' + fromPos.y +
                'L' + toPos.x + ',' + toPos.y;

            linkUI.attr("d", data);
        });

    graph.addLink(1, 2);

    Viva.Graph.View.renderer(graph, {
        graphics: graphics
    }).run();
}

main();
svg {
    width: 100%;
    height: 100%;
}
img {
    cursor: pointer;
}
<script src="https://rawgit.com/anvaka/VivaGraphJS/master/dist/vivagraph.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

残念ながら、StackSnippets では動作しないようですが、jsFiddle では動作します: http://jsfiddle.net/tL9992ua/

于 2015-08-03T15:17:11.833 に答える