So I have the next force layout graph code for setting nodes, links and other elements:
var setLinks = function ()
{
link = visualRoot.selectAll("line.link")
.data(graphData.links)
.enter().append("svg:line")
.attr("class", "link")
.style("stroke-width", function (d) { return nodeStrokeColorDefault; })
.style("stroke", function (d) { return fill(d); })
.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; });
graphData.links.forEach(function (d)
{
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
};
var setNodes = function ()
{
node = visualRoot.selectAll(".node")
.data(graphData.nodes)
.enter().append("g")
.attr("id", function (d) { return d.id; })
.attr("title", function (d) { return d.name; })
.attr("class", "node")
.on("click", function (d, i) { loadAdditionalData(d.userID, this); })
.call(force.drag)
.on("mouseover", fadeNode(.1)).on("mouseout", fadeNode(1));
};
//append the visual element to the node
var appendVisualElementsToNodes = function ()
{
node.append("circle")
.attr("id", function (d) { return "circleid_" + d.id; })
.attr("class", "circle")
.attr("cx", function (d) { return 0; })
.attr("cy", function (d) { return 0; })
.attr("r", function (d) { return getNodeSize(d); })
.style("fill", function (d) { return getNodeColor(d); })
.style("stroke", function (d) { return nodeStrokeColorDefault; })
.style("stroke-width", function (d) { return nodeStrokeWidthDefault; });
//context menu:
d3.selectAll(".circle").on("contextmenu", function (data, index)
{
d3.select('#my_custom_menu')
.style('position', 'absolute')
.style('left', d3.event.dx + "px")
.style('top', d3.event.dy + "px")
.style('display', 'block');
d3.event.preventDefault();
});
//d3.select("svg").node().oncontextmenu = function(){return false;};
node.append("image")
.attr("class", "image")
.attr("xlink:href", function (d) { return d.profile_image_url; })//"Images/twitterimage_2.png"
.attr("x", -12)
.attr("y", -12)
.attr("width", 24)
.attr("height", 24);
node.append("svg:title")
.text(function (d) { return d.name + "\n" + d.description; });
};
Now, the colors and size dependencies changed and I need to redraw the graph circles (+all appended elements) with different color and radius. Having problem with it.
I can do this:
visualRoot.selectAll(".circle").remove();
but I have all the images that I attached to '.circles'
still there.
In any way, any help will be appreciated, let me know if the explanation is not clear enough, I will try to fix it.
P.S. what is the difference between graphData.nodes
and d3.selectAll('.nodes')
?
Your answer will work, but for posterity, these methods are more generic.
Remove all children from HTML:
Remove all children from SVG/HTML:
The
.html("")
call works with my SVG, but it might be a side effect of using innerSVG.in this way, I have resolved it very easily,
and then I just re-added visual elements which were rendered differently because the code for calculating radius and color had changed properties. Thank you.
My first advice is that you should read the
d3.js
API about selections: https://github.com/mbostock/d3/wiki/SelectionsYou have to understand how the
enter()
command works (API). The fact that you have to use it to handle new nodes has a meaning which will help you.Here is the basic process when you deal with
selection.data()
:first you want to "attach" some data to the selection. So you have:
Then you can modify all nodes each times data is changed (this will do exactly what you want). If for example you change the radius of old nodes which are in the new dataset you loaded
Then, you have to handle new nodes, for this you have to select the new nodes, this is what
selection.enter()
is made for:Finally you certainly want to remove the nodes you don't want anymore, to do this, you have to select them, this is what
selection.exit()
is made for.A good example of the whole process can also be found on the API wiki: https://github.com/mbostock/d3/wiki/Selections#wiki-exit
If you want to remove the element itself, just use
element.remove()
, as you did. In case you just want to remove the content of the element, but keep the element as-is, you can use f.ex.instead of
.html("")
(I wasn't sure which element's children you want deleted). This keeps the element itself, but cleans all included content. It the official way to do this, so should work cross-browser.PS: you wanted to change the circle sizes. Have you tried
To remove all element from a node: