Reputation: 11
I'm creating a webpage that will make a d3 force-layout graph using data from a JSON file, and when a button is pushed the user will be prompted for a name, and a new node will be created with the provided name. The page loads successfully and when the button is pushed an alert asks for a name, but when a name is entered there is an error that says 'Uncaught TypeError: undefined is not a function' and a new node isn't added.
What can I do to fix this error? Using Chrome I know the error is happening in the line where I try to append newNode. Here's my code:
<button onclick="addNode()">Click to add Node</button>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
function addNode() {
var nodeName = prompt("Name of new node:");
var newGroup = Math.floor(Math.random() * 6);
if (nodeName != null) {
var newNode = {"node":{"name":nodeName,"group":newGroup}};
force.nodes.append(newNode);
force.start();
}
}
var width = 960,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("user_interactions(1).json", function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function(d) { return color(d.group); })
.call(force.drag);
node.append("title")
.text(function(d) { return d.name; });
force.on("tick", function() {
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("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});
</script>
Upvotes: 1
Views: 2310
Reputation: 14053
force.nodes
is a function that returns the array of nodes. It's not a property. So force.nodes.append
doesn't make any sense. You probably want to add the new node to the data,
force.nodes(force.nodes().push(newNode));
I'm not certain, however, that D3 will gracefully handle changing the nodes array dynamically.
In any case you'll have to add SVG elements for the new node and specify their attributes in a manner similar to how you're setting the initial properties (r
, fill
, etc.)
Upvotes: 1