I use a SELECT drop down box to choose a new JSON data source for a force network graph. The first graph draws correctly: Nodes draw on top of edges and mouseovers work as expected.
When I select the second data source, the edges draw on top of the nodes and I have lost my mouseovers. If I go back to selection "A", the same is true except for the last node.
A jsfiddle showing this problem is here:
http://jsfiddle.net/NovasTaylor/e6qjubaa/
Obligatory stack overflow code inclusion:
//EXIT
edges.exit().remove();
nodes.exit().remove();
I expect this is a problem with my ENTER/UPDATE/EXIT and perhaps the keys I am using to exit the elements? Please see the code in the fiddle.
Any advice would be greatly appreciated. My next step is to add edge labels so I want to ensure I get the nodes and edges and working first.
Tim
So just add some lines to the combobox:
d3.selectAll('#familytreecontentsvg .node')
.each(function (d) {
d.fixed = false;
})
.classed("fixed", false)
And I moved the svg object into the drawings while just initializing it empty above. Also I created an id for the SVG itself. Hope it helps. Please tell me if that is fixing your troubles.
Updated fiddle: http://jsfiddle.net/xg9fjze3/9/
Related
I'm backend developer for several years but a newbie in frontend issues.
I used "graphviz" (using d3.js) to draw an SVG graph from DOT notation.
Everything is working fine but one thing I don't get in my mind:
If I "open" another (or the same one) graph its starting position is the
same as this from the previous drawn graph even if I completely remove
the whole node content from the dom as follows:
var svg = d3.selectAll("svg");
var otherBelow = svg.selectAll("*");
otherBelow.remove();
// svg.remove();
Doing this and checking the page source the nodes below SVG are realy dropped
but drawing the new graph it has exactly the position of the previously
moved graph in "transform" attribute. Doing a work around by resetting the
position bevore solves this problem but then the problem remains for the
"moving on mousedown" capability. Then the graph immediately "jumps" to the old
ones position. But therefor I can't even get an information about somewhere
in the page source. Really the generated page code is 100% the same (with
diff tool) but has a different behaviour. Don't understand how this is possible.
So now my question: Is there a kind of caching? Or is there perhaps the
browser cache used somehow internally? How to fix this?
P.s. if I remove the SVG node itself I get a completely courious behaviour.
Then the newly drawn graph is not movable at all.
This (ugly) workaround does it for me.
// Snipped to render a new graph and reset its position
// #graph -> id of d3-graphviz div-container
document.getElementById('graph').innerHTML = ''
setTimeout(() => {
d3.select("#graph").graphviz()
.dot(yourDotData)
.render()
}, 50)
Explanation/Assumption why this works:
It seems that the deletion of the old graph with .innerHTML = ''and the creation of the new one should not happen in the same rendering phase/at the same time, therefore the timeout function.
The second part of the workaround is to use a new graphivz-instance to render the new graph, therefore the
d3.select(...) within the timeout function.
The graphviz renderer is still present on the element it was created on and has all its data still intact.
Removing the svg and then reuse the renderer is not a valid use case. Nico's answer is probably correct, but there are better ways to do it, but in order to tell you how you should do it instead I would need so see all of your code so I can understand what you really want to do.
I have created a dynamically built force graph in D3. When I click on one of the links I want to only show that and all the connected links/nodes.
This Plunkr is a simplified version of what I have: http://plnkr.co/edit/TiKKmvydqXNipe103juL?p=preview (EDIT: I have updated this and is now a complete solution).
As you can see there are 3 separate 'groups' of connected nodes, in my real data set there are several hundred nodes and I want to be able to isolate an individual 'group' and only show that when the link which is part of that group is clicked on (it can't be the node that is clicked on as this shows a pop-up with more info).
I have been able to colour/hide connected links by pre-processing my data and using a rather complicated and long winded algorithm to determine whether the links are in the same connected group.
I have also been able to change the node that is clicked on or all the nodes/links by changing the dragstart function, this feels like I am getting close, but I don't think it recognises any link relationships.
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
// Changes all nodes/links
d3.select("circle").classed("others",true).style("display","none");
// Trying different ways to hide only 'other' nodes
d3.selectAll("circle").classed("others",true).style("display","none");
d3.selectAll("line").classed("others",true).style("display","none");
d.fx = d.x;
d.fy = d.y;
}
(I am aware of this question/answer how to highlight(change color) of all connected(neighbours) nodes and links in a d3 force directed graph but I don't think it really helps).
Any help would be appreciated.
OK, this might be beyond me, but I think you somehow need to group your links into the same sorts of groups as your nodes. If you could somehow add the "group" attribute of the source node to the link, then when you click on the link something like this might work:
d3.selectAll("line")function fade(){if
(group = "selected", "opacity" = 1)
else
("opacity" = 0)
};
alternatively, if you can sort the links into groups before the data is loaded (in your PHP etc. script), then you could append 3 (or n) groups of lines with separate classes.
Sorry, JS isn't my strongsuit, hopefully someone more experienced will sort that out for us...
I am new to d3 and I am trying to do something like this. Here is what I have done so far JSFiddle, but I don't know how to align the lines to put them like in the picture and also how to put an information box below the chart.
var x=d3.scale.linear().domain([0,r]).range([0,w])
var y=d3.scale.linear().domain([r,0]).range([h,0])
center_group.append('line').attr("x1",x(r/4)).attr("y1",0);
center_group.append('line').attr("x1",x(-r/4)).attr("y1",0);
center_group.append('line').attr("x1",0).attr("y1",x(25));
center_group.append('line').attr("x1",0).attr("y1",x(-r/4));
Thanks!
If I understand correctly, you're trying to align the reticle lines within the circle. I've created a fiddle which should demonstrate a solution to the two issues in your original fiddle.
//circle svg drawn above this point...
center_group.append('line').attr("x1",x(r/6)).attr("y1",0).attr("x2",x(r/5.1));
center_group.append('line').attr("x1",x(-r/6)).attr("y1",0).attr("x2",x(-r/5.1));
center_group.append('line').attr("x1",0).attr("y1",x(19.7)).attr("y2",x(r/6));
center_group.append('line').attr("x1",0).attr("y1",x(-r/6)).attr("y2",x(-r/5.1));
//then include table, as shown here: http://bl.ocks.org/gka/17ee676dc59aa752b4e6
The first issue is that the lines were being drawn before the (white-filled) circle (so any line within the circle was covered). Second issue was that the lines were unbounded, so i added x2 and y2 attributes where needed. See picture link for results.
Regarding the information box, you could simply append a text element under the chart and drop your data in there, but for something more robust, you could include a table, as shown in the example linked in my code above (only two links allowed apparently).
I'm having a problem updating nodes in my force layout. I have used some help from another stackoverflow post for updating nodes. This worked out fine until I realized that everything(circle svg, lines, text, etc) were under their own "g" tag.
So that means that I cannot manipulate any of the text like I did before. If you compare this with this you can see that in the first fiddle, I can't increase the text size based on the click. d3.select(this).select("text") does not work since the "g" tags do not include a circle and a text together.
So I need to be able to manipulate the text in correspondence to the node. The second fiddle handles that but it has a problem updating the nodes. If you hit the update button, it updates all the nodes but it does not remove existing nodes. For the first fiddle, update works fine but i can't manipulate the text like I mentioned earlier. So for a solution, I need to either find a way to manipulate the text in the first fiddle, or for the second fiddle, I need to somehow have it properly update all the nodes on exit(). I would say the second fiddle would be more natural to work with since the nodes are set out in a structured layout. i.e, each circle and it's corresponding text are in "g" tags just like what you would group in divs.
I'm working on a d3.js cluster diagram for a short time.
It's able to add new elements to clusters and move those elements across clusters.
I have added labels to elements but I didn't realize, how to make those labels move with the elements, if it is a new element.
My source is here: http://bl.ocks.org/heal25/9888263
If you add a new element, it's label doesn't works.
Can someone help me out?
Thank you!
I found a bug, that causes not to move a text with the element. In line 183. it must be
label = svg.selectAll("text.node")
and not
var label = svg.selectAll("text.node")