I'm trying to group the circles in the force directed graph layout, so that i could add the path of semi-circle that would make the circle into two semi-circle clickable sides. I managed to make two sides semi-circle clickable with d3 works just like this fiddle. I seems can't wrap d3 concept how to group, and connect the links.
How can i group the circles and the path and make it works with force layout? What are the concepts that i failed to understand to make this work? What did i do wrong?
Two sides clickable Semi-circle code
var vis = d3.select("body").append("svg")
var pi = Math.PI;
var arc = d3.svg.arc()
.innerRadius(0)
.outerRadius(70)
.startAngle(0) //converting from degs to radians
.endAngle(pi) //just radians
var canvas = vis.attr("width", "400").attr("height", "400").append("g");
// Added height and width so arc is visible
canvas.append("circle")
.attr("r", "70px")
.attr("fill","blue")
.attr("cx",400/2)
.attr("cy",400/2)
.on("click", function(d){
console.log("View");
})
.on("mouseover", function(){ d3.select(this).style("fill", "blue");
console.log(d3.select(this.parentNode).select(".view").style("visibility","visible"));
})
.on("mouseout", function(){
d3.select(this).style("fill", "blue");
console.log(d3.select(this.parentNode).select(".view").style("visibility","hidden"));
});
canvas.append("path")
.attr("d", arc)
.attr("fill", "blue")
.attr("transform", "translate(200,200)")
.on("click",function(d){
console.log("Expand");
})
.on("mouseover", function(){ d3.select(this).style("fill", "blue");
console.log(d3.select(this.parentNode).select(".expand").style("visibility","visible"));
})
.on("mouseout", function(){
d3.select(this).style("fill", "blue");
console.log(d3.select(this.parentNode).select(".expand").style("visibility","hidden"));
});
canvas.append("text")
.attr("dx", "190")
.attr("dy","200")
.attr("class","view")
.text("VIEW")
canvas.append("text")
.attr("dx", "190")
.attr("dy","200")
.attr("class","expand")
.text("Expand")
Force Layout that uses circle as node code, inspired by this stackoverflow question
This fiddle
var words = [{
"group": "n",
"word": "main node",
"children": [{
"group": "n",
"name": "sub node 1"
}, {
"group": "n",
"name": "sub node 2"
}, {
"group": "n",
"name": "sub node 3"
}, {
"group": "v",
"name": "sub node 4"
}, {
"group": "s",
"name": "sub node 5"
}, {
"group": "s",
"name": "sub node 6"
}, {
"group": "s",
"name": "sub node 7"
}, {
"group": "s",
"name": "sub node 8"
}, {
"group": "s",
"name": "sub node 9"
}, {
"group": "s",
"name": "sub node 10"
}, {
"group": "s",
"name": "sub node 11"
}, {
"group": "r",
"name": "sub node 12",
"children": [{
"group": "r",
"name": "sub sub node 1"
}, {
"group": "r",
"name": "sub sub node 2"
}, {
"group": "r",
"name": "sub sub node 3"
}]
}]
}]
var w = 600,
h = 600,
radius = 30,
node,
link,
root;
var pi = Math.PI;
var arc = d3.svg.arc()
.innerRadius(0)
.outerRadius(radius)
.startAngle(0) //converting from degs to radians
.endAngle(pi)
var force = d3.layout.force()
.on("tick", tick)
.charge(function(d) {
return -1000;
})
.linkDistance(function(d) {
return d.target._children ? 200 : 120;
})
.size([w, h - 160]);
var svg = d3.select("#viz").append("svg")
.attr("width", w)
.attr("height", h);
root = words[0]; //set root node
root.fixed = true;
root.x = w / 2;
root.y = h / 2 - 80;
update();
function update() {
var nodes = flatten(root),
links = d3.layout.tree().links(nodes);
// Restart the force layout.
force
.nodes(nodes)
.links(links)
.start();
// Update the links…
link = svg.selectAll(".link")
.data(links);
// Enter any new links.
link.enter().insert("svg:line", ".node")
.attr("class", "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;
});
// Exit any old links.
link.exit().remove();
// Update the nodes…
node = svg.selectAll("circle.node")
.data(nodes, function(d) {
return d.name;
})
.style("fill", color);
node.transition()
.attr("r", radius);
// Enter any new nodes.
node.enter().append("svg:circle")
.attr("class", "node")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", radius)
.style("fill", color)
//.on("click", click)
.on("click",function(){
console.log("Click Main Circle")
})
//.call(force.drag);
node.append("title")
.text(function(d) {
return d.name;
});
// Exit any old nodes.
node.exit().remove();
}
function tick() {
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;
});
node.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
}
// Color leaf nodes orange, and packages white or blue.
function color(d) {
if (d._children) {
return "#95a5a6";
} else {
switch (d.group) {
case 'r': //adverb
return "#e74c3c";
break;
case 'n': //noun
return "#3498db";
break;
case 'v': //verb
return "#2ecc71";
break;
case 's': //adjective
return "#e78229";
break;
default:
return "#9b59b6";
}
}
}
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update();
}
// Returns a list of all nodes under the root.
function flatten(root) {
var nodes = [],
i = 0;
function recurse(node) {
if (node.children) node.size = node.children.reduce(function(p, v) {
return p + recurse(v);
}, 0);
if (!node.id) node.id = ++i;
nodes.push(node);
return node.size;
}
root.size = recurse(root);
return nodes;
}
I have tried to group the circles, by grouping the circles and adding the semi-circle path in the group, but the layout breaks.
var arc = d3.svg.arc()
.innerRadius(0)
.outerRadius(30)
.startAngle(0) //converting from degs to radians
.endAngle(pi)
var g = node.enter().append("g")
.attr("class", "node");
g.append("svg:circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", radius)
.style("fill", color)
//.on("click", click)
.on("click",function(){
console.log("Click Main Circle")
})
g.append("path")
.attr("d", arc)
.attr("fill", "blue")
.attr("transform", "translate(200,200)")
.on("click",function(d){
console.log("path");
})