I've got a d3 force sim and if I were to add nodes as follows:
node = node.data(nodes, function(d) { return d.id;});
node.exit().remove();
node = node.enter().append('circle')
.attr("class", function(d) {return d.type;})
.attr("r", 25)
.merge(node);
everything works fine - the circles are added at their correct places and the rendered html would look like this:
<svg width="1280" height="960">
<g transform="translate(640,480)">
<g stroke="#000" stroke-width="1.5">
<line x1="197.7877989370864" y1="16.96383936157134" x2="113.39655998594978" y2="176.9054238213185"></line>
<line x1="-99.71642802229279" y1="182.82652731678513" x2="-206.38001140055673" y2="35.62690731557146"></line>
<line x1="-111.21899770908817" y1="-104.07607869492837" x2="9.724648489851102" y2="-238.28831674029004"></line>
<line x1="-111.21899770908817" y1="-104.07607869492837" x2="73.66744043019104" y2="-114.11648500001087"></line>
<line x1="197.7877989370864" y1="16.96383936157134" x2="10.328317030872993" y2="37.5171491536661"></line>
<line x1="-99.71642802229279" y1="182.82652731678513" x2="10.328317030872993" y2="37.5171491536661"></line>
<line x1="-111.21899770908817" y1="-104.07607869492837" x2="10.328317030872993" y2="37.5171491536661"></line>
<line x1="197.7877989370864" y1="16.96383936157134" x2="73.66744043019104" y2="-114.11648500001087"></line>
</g>
<g prop="nodes" stroke="#000" stroke-width="1.5">
<circle fill="some_image.png" class="Net" r="25" cx="197.7877989370864" cy="16.96383936157134"></circle>
<circle fill="some_image.png" class="Net" r="25" cx="-99.71642802229279" cy="182.82652731678513"></circle>
<circle fill="some_image.png" class="Net" r="25" cx="-111.21899770908817" cy="-104.07607869492837"></circle>
<circle fill="some_image.png" class="Inst" r="25" cx="113.39655998594978" cy="176.9054238213185"></circle>
<circle fill="some_image.png" class="Inst" r="25" cx="-206.38001140055673" cy="35.62690731557146"></circle>
<circle fill="some_image.png" class="Inst" r="25" cx="9.724648489851102" cy="-238.28831674029004"></circle>
<circle fill="some_image.png" class="Inst" r="25" cx="73.66744043019104" cy="-114.11648500001087"></circle>
<circle fill="some_image.png" class="Internet" r="25" cx="10.328317030872993" cy="37.5171491536661"></circle>
</g>
</g>
</svg>
But if I wanted to add groups (my final design requires background images, labels and all sorts of additional stuff) like so:
node = node.data(nodes, function(d) { return d.id;});
node.exit().remove();
node.enter().append('g')
.attr('class', 'node')
.append('image')
.attr('xlink:href', 'some_image.png')
.append('text')
.text(function(d){return d.text;})
... and so on...
although my code seems to get interpreted correctly (I append the groups, append the images and labels to them), the groups stay static and they remain in the middle of the sim on top of each other. Also it seems the coordinate transformation goes to the images instead to the group, which is what I think is breaking the sim:
<svg width="1280" height="960">
<g transform="translate(640,480)">
<g stroke="#000" stroke-width="1.5">
<line x1="197.77682810226557" y1="16.981901068622136" x2="113.3585440445384" y2="176.90457630748227"></line>
<line x1="-99.99450481197604" y1="182.94091641902205" x2="-206.13047480355274" y2="35.36287517221039"></line>
<line x1="-111.19343747422879" y1="-103.71666033252438" x2="9.543859895654657" y2="-238.10758089494877"></line>
<line x1="-111.19343747422879" y1="-103.71666033252438" x2="73.69734375869983" y2="-114.13138675745854"></line>
<line x1="197.77682810226557" y1="16.981901068622136" x2="10.344170477990337" y2="37.84621823186521"></line>
<line x1="-99.99450481197604" y1="182.94091641902205" x2="10.344170477990337" y2="37.84621823186521"></line>
<line x1="-111.19343747422879" y1="-103.71666033252438" x2="10.344170477990337" y2="37.84621823186521"></line>
<line x1="197.77682810226557" y1="16.981901068622136" x2="73.69734375869983" y2="-114.13138675745854"></line>
</g>
<g prop="nodes" stroke="#000" stroke-width="1.5">
<g class="node"><image xlink:href="some_image.png" x="0" y="0" height="72" width="72" style="z-index: 3;"></image></g>
<g class="node"><image xlink:href="some_image.png" x="-7.373688780783198" y="6.754902942615239" height="72" width="72" style="z-index: 3;"></image></g>
<g class="node"><image xlink:href="some_image.png" x="1.2363864559502138" y="-14.087985964343622" height="72" width="72" style="z-index: 3;"></image></g>
<g class="node"><image xlink:href="some_image.png" x="10.538470205147267" y="13.745568221620495" height="72" width="72" style="z-index: 3;"></image></g>
<g class="node"><image xlink:href="some_image.png" x="-19.694269706308575" y="-3.4836390075862327" height="72" width="72" style="z-index: 3;"></image></g>
<g class="node"><image xlink:href="some_image.png" x="18.866941955758957" y="-12.001604111035421" height="72" width="72" style="z-index: 3;"></image></g>
<g class="node"><image xlink:href="some_image.png" x="-6.358980820385529" y="23.65509169134563" height="72" width="72" style="z-index: 3;"></image></g>
<g class="node"><image xlink:href="some_image.png" x="-12.194453649142762" y="-23.479678451778437" height="72" width="72" style="z-index: 3;"></image></g>
</g>
</g>
</svg>
I'm pretty positive the use of groups messes up everything, but can't wrap my head around it how to properly use them.
Appreciate any help.
Here's the full force layout in snippet form:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Parse tester</title>
<script src="https://d3js.org/d3.v4.min.js" type="text/javascript"></script>
</head>
<body>
<script>
var nodes = [
{id:0 , label:'branch1' , name:'branch1'},
{id:1 , label:'branch2' , name:'branch2'},
{id:2 , label:'branch3' , name:'branch3'},
{id:3 , label:'leaf1' , name:'leaf1'},
{id:4 , label:'leaf2' , name:'leaf2'},
{id:5 , label:'leaf3' , name:'leaf3'},
{id:6 , label:'center' , name:'center'},
{id:7 , label:'leaf23' , name:'leaf23'}
];
var links = [
{source:0 ,target:3, distance:150, weight:1},
{source:1 ,target:4, distance:150, weight:1},
{source:2 ,target:5, distance:150, weight:1},
{source:7 ,target:0, distance:150, weight:1},
{source:7 ,target:1, distance:150, weight:1},
{source:7 ,target:2, distance:150, weight:1},
{source:1 ,target:6, distance:150, weight:1},
{source:2 ,target:6, distance:150, weight:1}
];
//D3 stuff
var width=640, height = 480;
// add a SVG to the body for our viz
var svg=d3.select('body').append('svg')
.attr('width', width)
.attr('height', height);
var simulation = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(-1000))
.force("link", d3.forceLink(links).distance(200))
.force("x", d3.forceX())
.force("y", d3.forceY())
.alphaTarget(1)
.on("tick", ticked);
var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"),
link = g.append("g").attr("stroke", "#000").attr("stroke-width", 1.5).selectAll(".link"),
node = g.append("g").attr("stroke", "#000").attr("stroke-width", 1.5).selectAll(".node");
restart();
function restart() {
// Apply the general update pattern to the nodes.
node = node.data(nodes, function(d) { return d.id;});
node.exit().remove();
node = node.enter()
.append('g')
.append('image')
.attr('xlink:href', 'http://i.imgur.com/Rx4N3wh.png')
.attr('width',25)
.attr('height',25)
.attr('x', function (d) {return d.x;})
.attr('y', function (d) {return d.y;})
.merge(node);
node.enter().selectAll('g').append('text')
.attr('text-anchor', 'middle')
.attr('dy', '.35em')
.attr('y', -40)
.text(function (d) {
return d.label
});
// Apply the general update pattern to the links.
link = link.data(links, function(d) { return d.source.id + "-" + d.target.id; });
link.exit().remove();
link = link.enter().append("line").merge(link);
// Update and restart the simulation.
simulation.nodes(nodes);
simulation.force("link").links(links);
simulation.alpha(1).restart();
}
//*/
function ticked() {
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
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; });
}
</script>