Reputation: 822
I creating Fimily Tree, it all seems works fine, except links. They did not updated when i drag node. Link end just mode to different direction and did not follow node.
Also when i click on node it stroke changes, but also changes text strokes, that inside rect, i need to change only rect stroke.
I prepare Feedly
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<script>
var margin = {top: 100, right: 50, bottom: 50, left: 50},
width = 1800 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom,
boxWidth = 140,
boxHeight = 80;
boxHSpace = 200,
boxVSpace = 70,
links = [];
var svg = d3.select("body")
.attr("bgcolor", "#2c2c2c")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var datas;
datas = setPositions(buildDataAssocArray(getData()));
var node = svg.selectAll(".node")
.data(d3.entries(datas))
.enter()
.append("g");
function dragmove(d) {
var x = d3.event.x;
var y = d3.event.y;
d3.select(this).attr("transform", "translate(" + x + "," + y + ")");
console.log(d);
datas[d.key].x=x;
datas[d.key].y=y;
link.attr("d", connect);
}
// Define drag beavior
var drag = d3.behavior.drag()
.on("drag", dragmove)
.origin(function() {
var t = d3.transform(d3.select(this).attr("transform"));
return {x: t.translate[0], y: t.translate[1]};
});
node.call(drag)
.on("click", click);
var selected;
function click(){
if(!selected){
selected = this;
d3.select(selected).style('stroke', 'white');
}
else {
d3.select(selected).style('stroke', 'black');
selected = this;
d3.select(selected).style('stroke', 'white');
}
}
node.append("rect")
.attr("width", boxWidth)
.attr("height", boxHeight)
.attr("fill", "tan")
.attr("x", function(d) { return d.value.x - 70; })
.attr("y", function(d) { return height - d.value.y - 40; })
.style("cursor", "pointer");
node.append("text")
.attr("font-size", "16px")
.attr("fill", "black")
.attr("x", function(d) { return d.value.x; })
.attr("y", function(d) { return height - d.value.y - 15; })
.style("text-anchor", "middle")
.text(function(d) { return d.value.name; })
var link = svg.selectAll(".link")
.data(getLinks())
.enter()
.insert("path", "g")
.attr("fill", "none")
.attr("stroke", "#000")
.attr("stroke", "#000")
.attr("shape-rendering", "crispEdges")
.attr("d", connect);
function connect(d, i) {
console.log(d);
return "M" + d.source.x + "," + (height - d.source.y)
+ "V" + (height - (3*d.source.y + 4*d.target.y)/7)
+ "H" + d.target.x
+ "V" + (height - d.target.y);
};
function getLinks() {
return links ;
}
function setPositions(datas)
{
var fams=getFamily();
var x=200 ,y=100;
fams.forEach(function(item, i, arr) {
item.childs.forEach(function(child, i1, arr1) {
console.log(child);
datas[child].x = x;
datas[child].y = y;
links.push({"source" : datas[child], "target" : datas[item.husb]});
links.push({"source" : datas[child], "target" : datas[item.wife]});
});
x+=100;
y+=100;
datas[item.husb].x = x-100;
datas[item.husb].y = y+100;
datas[item.wife].x = x+100;
datas[item.wife].y = y+100;
x+=100;
y+=100;
});
return datas;
}
function getFamily() {
return [
{
"husb": "003",
"wife": "002",
"childs": ["001"]
}
];
}
function buildDataAssocArray(adatas) {
var datas = adatas;
var dArray = [];
datas.forEach(function(item, i, arr) {
item.x=0;
item.y=0;
dArray[item.id] = item;
});
return dArray;
}
//console.log(buildDataAssocArray());
function getData() {
return [
{
"id" : "001",
"name": "Алтунин Василий",
"mother" : "002",
"father" : "003",
"child" : null,
},
{
"id" : "002",
"name": "Алтунина Елена",
"mother" : "004",
"father" : "005",
"child" : "001",
},
{
"id" : "003",
"name": "Алтунин Владимир",
"mother" : "006",
"father" : "007",
"child" : "001",
},
];
};
</script>
</body>
</html>
SOLVED:
Here result feedle
Upvotes: 2
Views: 2183
Reputation: 4467
You can directly access the rect
as a childNodes
object:
function click() {
if (!selected) {
selected = this;
d3.select(selected.childNodes[0]).style('stroke', 'white');
} else {
d3.select(selected.childNodes[0]).style('stroke', 'black');
selected = this;
d3.select(selected.childNodes[0]).style('stroke', 'white');
}
}
Upvotes: 1
Reputation: 32327
In your drag function:
Register the drag x and y inavriable dx and dy respectively.
function dragmove(d) {
var x = d3.event.x;
var y = d3.event.y;
d3.select(this).attr("transform", "translate(" + x + "," + y + ")");
datas[d.key].dx =d3.event.x;
datas[d.key].dy =d3.event.y;
link.attr("d", connect);
}
Now when you make the d attribute for the line consider the dx and dy computed in the drag function.
function connect(d, i) {
var dsx=d.source.dx ? d.source.dx:0;
var dsy=d.source.dy ? d.source.dy:0;
var dtx=d.target.dx ? d.target.dx:0;
var dty=d.target.dy ? d.target.dy:0;
return "M" + (d.source.x + dsx) + "," + (height - d.source.y +dsy)
+ "V" + (height - (3*(d.source.y+dsy) + 4*(d.target.y +dty))/7)
+ "H" + (d.target.x+dtx)
+ "V" + (height - (d.target.y- dty));
};
however i suggest you to use d3.interpolate rather than doing the calculation in connect function.
working code here
Upvotes: 4