I'm working on a force layout graph that displays relationships of writers. Since there are so many, I tried to implement zooming and dragging. Zooming works fine (with one exception), but when I drag a node it also drags the background. I tried following Mike Bostock's directions here and the StackOverflow question paired with it, but it still won't work. I based most of the code for the graph on this, which works beautifully, but since he used an older version of d3, his dragging breaks in the new version. (I can't just use the older version of d3 because I have some other parts of the graph not shown here that work only with the newer version.)
I think the problem has something to do with my grouping of SVG objects, but I also can't figure out what I'm doing wrong there. This also brings in the one zooming problem; when I zoom in or pan around, the legend also moves and zooms in. If there's an easy fix to make it stay still and sort of "hover" above the graph, that would be great.
I'm very new to coding, so I'm probably making really stupid mistakes, but any help would be appreciated.
var graphData = {
nodes: [
{
id:0,
name:"Plotinus"
},
{
id:1,
name:"Iamblichus"
},
{
id:2,
name:"Porphyry"
}
],
links: [
{
relationship:"Teacher/student",
source:0,
target:1
},
{
relationship:"Enemies",
source:0,
target:2
},
{
relationship:"Family",
source:1,
target:2
}
]
};
var linkColor = d3.scale.category10(); //Sets the color for links
var drag = d3.behavior.drag()
.on("dragstart", function() { d3.event.sourceEvent.stopPropagation(); })
.on("drag", function(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
});
var w = 300,
h = 300;
var vis = d3.select(".graph")
.append("svg:svg")
.attr("width", w)
.attr("height", h)
.attr("pointer-events", "all")
.append('svg:g')
.call(d3.behavior.zoom().on("zoom", redraw))
.append('svg:g');
vis.append('svg:rect')
.attr('width', w)
.attr('height', h)
.attr('fill', 'rgba(1,1,1,0)');
function redraw() {
vis.attr("transform","translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); }
var force = d3.layout.force()
.gravity(.6)
.charge(-600)
.linkDistance( 60 )
.size([w, h]);
var svg = d3.select(".text").append("svg")
.attr("width", w)
.attr("height", h);
var link = vis.selectAll("line")
.data(graphData.links)
.enter().append("line")
.style("stroke", function(d) { return linkColor(d.relationship); })
.style("stroke-width", 1)
.attr("class", "connector");
var node = vis.selectAll("g.node")
.data(graphData.nodes)
.enter().append("svg:g")
.attr("class","node")
.call(force.drag);
node.append("svg:circle")
.attr("r", 10) //Adjusts size of nodes' radius
.style("fill", "#ccc");
node.append("svg:text")
.attr("text-anchor", "middle")
.attr("fill","black")
.style("pointer-events", "none")
.attr("font-size", "9px")
.attr("font-weight", "100")
.attr("font-family", "sans-serif")
.text( function(d) { return d.name;} );
// Adds the legend.
var legend = vis.selectAll(".legend")
.data(linkColor.domain().slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(-10," + i * 20 + ")"; });
legend.append("rect")
.attr("x", w - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", linkColor);
legend.append("text")
.attr("x", w - 24)
.attr("y", 9)
.attr("dy", ".35em")
.attr("class", "legendText")
.style("text-anchor", "end")
.text(function(d) { return d; });
force
.nodes(graphData.nodes)
.links(graphData.links)
.on("tick", tick)
.start();
function tick() {
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("transform", function(d) { return "translate(" + d.x + "," + 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; });
}