我有一个基于项目的一堆节点的d3图表。当我点击其中一个节点时,图表会根据点击的节点重新加载数据。
我使用这样的URL结构: http://siteurl.com/index.html?item=
单击某个节点时,我有一个使用新URL再次运行d3.json(
函数的函数,然后再次执行更新函数。
我最近更改了代码,以便节点字出现在节点下方。 现在我在的代码行上出现'undefined is not a function'错误
编辑:@ Elijah的答案修正了问题,但未解决我的问题。 node.exit().remove();
因此,当我点击某个节点时,会删除链接,然后重新生成链接,但上一个图表中的节点仍然存在。
这是我的一些JS
$wordToSearch = "bitter";
var w = 960,
h = 960,
node,
link,
root,
title;
var jsonURL = 'http://desolate-taiga-6759.herokuapp.com/word/' + $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)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 10)
.on("click", click)
.style("fill", "red");
node.append("text")
.attr("dy", 10 + 15)
.attr("text-anchor", "middle")
.text(function(d) { return d.word });
svg.selectAll(".node").data(nodes).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/' + $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];
}
}
}
有没有人有任何想法,为什么那不起作用?
编辑:根据@Elijah的回答更新了我的JS。
答案 0 :(得分:2)
你的问题在于:
node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
您将node
定义为svg.selectAll(".node").enter()
,这意味着您的变量现在引用选择输入行为而不是选择本身。因此,当您尝试使用:node.exit().remove();
..您正在尝试访问.exit()
行为,而不是选择行为的.enter()
行为。将其替换为:
svg.selectAll(".node").data(nodes).exit().remove();
这应该可以解决你的问题。可能还有其他事情发生,但这肯定会引发问题。
编辑添加:
您还应该更新刻度函数,使其不会引用现在分配给node
的{{1}},而不是引用选择,而是引用选择:
#selection.enter()
答案 1 :(得分:2)
处理3个州的进入,退出和更新,彼此分开:
node = svg.selectAll(".node")
.data(nodes); // base data selection, this is the update
var nodeE = node
.enter(); // handle the enter case
var nodeG = nodeE.append("g")
.attr("class", "node")
.call(force.drag); // add group ON ENTER
nodeG.append("circle")
.attr("r", 10)
.on("click", click)
.style("fill", "red"); // append circle to group ON ENTER
nodeG.append("text")
.attr("dy", 10 + 15)
.attr("text-anchor", "middle")
.text(function(d) { return d.word }); // append text to group ON ENTER
node.exit().remove(); // handle exit
更新小提琴here。