【问题标题】:Reloading (updating) d3.js force-directed graph holds onto old JSON data重新加载(更新)d3.js 强制导向图保留旧的 JSON 数据
【发布时间】:2015-04-29 03:19:46
【问题描述】:

所以我有一个 d3.js 强制导向图,它显示来自 JSON 提要的数据。当我单击一个节点时,我请求根据所单击的节点更新 JSON 提要。

返回的 JSON 是正确的。但是图表中显示的内容并不能反映 JSON 中保存的数据。我有一种感觉,图表正在保留以前的图表数据。

这是一个快速 gif,应该有助于可视化问题。

这里是 JSFiddle,让您了解如何绘制当前的图表。 而 Javascript 本身就是这个问题的底部。

更详细一点。当您单击一个节点时,它会将与该节点关联的词传递到 URL 的查询字符串中。然后我使用这个新的“点击”网址运行 d3.json 并运行更新函数来重新创建图形。

这是一个错误的例子。因此,如果您进入 JSFiddle 并单击名为“piercingly”的节点,您会发现加载的下一个图甚至没有“piercingly”一词,并且仍然具有与苦味相关的标签(原始搜索)。但是,如果您将 JS 顶部的变量更改为“刺耳”,则会加载一个不同但正确的图形。

节点数正确。但是完整版(不是 JSFiddle 上的版本)中的标签和其他属性不正确。

任何帮助将不胜感激。

$wordToSearch = "bitter";

var w = 960,
    h = 960,
    node,
    link,
    root,
    title;

var jsonURL = 'http://desolate-taiga-6759.herokuapp.com/word/basic/' + $wordToSearch;

d3.json(jsonURL, function(json) {
    root = json.words[0]; //set root node
    root.fixed = true;
    root.x = w / 2;
    root.y = h / 2 - 80;
    update();
});

var force = d3.layout.force()
    .on("tick", tick)
    .charge(-700)
    .gravity(0.1)
    .friction(0.9)
    .linkDistance(50)
    .size([w, h]);

var svg = d3.select(".graph").append("svg")
    .attr("width", w)
    .attr("height", h);



//Update the graph
function update() {
    var nodes = flatten(root),
    links = d3.layout.tree().links(nodes);

    // Restart the force layout.
    force
        .nodes(nodes)
        .links(links)
        .start();

    // Update the links…
    link = svg.selectAll("line.link")
        .data(links, function(d) { return d.target.id; });

    // Enter any new links.
    link.enter().insert("svg:line", ".node")
        .attr("class", "link")
        .attr("x1", function(d) { return d.source.x; })
        .attr("y1", function(d) { return d.source.y; })
        .attr("x2", function(d) { return d.target.x; })
        .attr("y2", function(d) { return d.target.y; });

    // Exit any old links.
    link.exit().remove();

    // Update the nodes…
    node = svg.selectAll(".node")
        .data(nodes);

    var nodeE = node
        .enter();

    var nodeG = nodeE.append("g")
        .attr("class", "node")
        .call(force.drag);

    nodeG.append("circle")  
        .attr("r", 10)
        .on("click", click)
        .style("fill", "red");

    nodeG.append("text")
        .attr("dy", 10 + 15)
        .attr("text-anchor", "middle")
        .text(function(d) { return d.word });

    node.exit().remove();

}

function tick() {
    link.attr("x1", function(d) { return d.source.x; })
        .attr("y1", function(d) { return d.source.y; })
        .attr("x2", function(d) { return d.target.x; })
        .attr("y2", function(d) { return d.target.y; });

    node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}




/***********************
*** CUSTOM FUNCTIONS ***
***********************/

//Request extended JSON objects when clicking a clickable node
function click(d) {
    $wordClicked = d.word;

    var jsonURL = 'http://desolate-taiga-6759.herokuapp.com/word/basic/' + $wordClicked;
    console.log(jsonURL);

    updateGraph(jsonURL);
}

// Returns a list of all nodes under the root.
function flatten(root) {
    var nodes = [], i = 0;

    function recurse(node) {
        if (node.children) node.size = node.children.reduce(function(p, v) { return p + recurse(v); }, 0);
        if (!node.id) node.id = ++i;
        nodes.push(node);
        return node.size;
    }

    root.size = recurse(root);
    return nodes;

}

//Update graph with new extended JSON objects
function updateGraph(newURL) {
    d3.json(newURL, function(json) {
        root = json.words[0]; //set root node
        root.fixed = true;
        root.x = w / 2;
        root.y = h / 2 - 80;

        update();
    });
}

function getUrlParameter(sParam)
{
    var sPageURL = window.location.search.substring(1);
    var sURLVariables = sPageURL.split('&');
    for (var i = 0; i < sURLVariables.length; i++) 
    {
        var sParameterName = sURLVariables[i].split('=');
        if (sParameterName[0] == sParam)  {
            return sParameterName[1];
        }
    }
} 

编辑: 所以我尝试在将单词添加到文本元素时将其注销。在第一次加载时,所有单词都被记录为分配给他们尊重的文本元素的 get。但是当您单击节点时,它们不会。 (请参见下面的 gif)。这很奇怪,因为我在点击时调用了更新功能。因此(理论上)应该为该节点再次获取单词。但它没有。

【问题讨论】:

    标签: javascript jquery json d3.js force-layout


    【解决方案1】:

    在手机上很难掌握,但我认为原因可能是因为它对新数据感到困惑。默认情况下,data() 函数使用项目的索引来加入 DOM。

    您需要做的是将另一个函数传递给您对data() 的调用,这被描述为一个关键函数。在这里你可能只需要返回这个词。

    .data(nodes, function(d) { return d.word; })

    查看 API 文档 https://github.com/mbostock/d3/wiki/Selections 中的数据函数。有几次我错过了一个关键功能的复杂案例。

    【讨论】:

    • 所以我想你可能刚刚得到了一个灌篮。在标记为答案之前,我将对其进行彻底的测试。快速提问,如果还有 d.word,例如,d.group。我只会返回d?通过检查您手机上的 Stack-overflow,我为您的承诺鼓掌。谢谢
    • @Oliver Evans 我不会只返回d。组合字符串或返回一个新的轻量级对象是我的做法
    猜你喜欢
    • 2014-09-18
    • 2013-08-14
    • 2013-08-16
    • 1970-01-01
    • 1970-01-01
    • 2018-08-03
    • 2015-09-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多