I'm working a graph visualization in D3 where each node represents a person working on multiple projects collaborating with multiple people. So, I customized the nodes as pie charts where portions of pie charts represents % of time the person is allocating for different projects. The radius of the pie varies based on some weight given to each node.
Due to this varying radius some nodes are so small that one cannot see them as pie charts. So, I wanted to create a mouse over effect that can magnify a node on hovering mouse over it. My intention is not to animate each portion of a pie but to animate whole pie chart as if it is a simple circle.
The code that I added to animate the arcs of the hovered pie chart is not working. When I hover on a node I'm getting below error
Error: <path> attribute d: Expected number, "MNaN,NaNA12.80000…".
(anonymous) @ d3.v3.min.js:5
a @ d3.v3.min.js:3
Rn @ d3.v3.min.js:1
Tn @ d3.v3.min.js:1
Here is the code snippet that I have -
<!DOCTYPE html>
<html lang="en">
<script src="http://d3js.org/d3.v3.min.js"></script>
<style>
.link {
fill: none;
stroke: #000000;
stroke-width: 1.5px;
stroke-opacity: 0.8;
}
div.tooltip {
position: absolute;
text-align: center;
min-width: 100;
width: auto;
min-height:25;
height: auto;
padding: 2px;
font: 10px sans-serif;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<body bgcolor="#A9A9A9">
<script type="text/javascript">
graph = { "nodes":[{"proportions": [{"group": 1, "value": 1},
{"group": 2, "value": 2},
{"group": 3, "value": 3}],"Weight": "2","name":"abc1"},
{"proportions": [{"group": 1, "value": 2},
{"group": 2, "value": 1},
{"group": 3, "value": 5}],"Weight": "3","name":"abc2"},
{"proportions": [{"group": 1, "value": 7},
{"group": 2, "value": 1},
{"group": 3, "value": 3}],"Weight": "4","name":"abc3"},
{"proportions": [{"group": 1, "value": 5},
{"group": 2, "value": 3},
{"group": 3, "value": 4}],"Weight": "2","name":"abc4"},
{"proportions": [{"group": 1, "value": 2},
{"group": 2, "value": 7},
{"group": 3, "value": 3}],"Weight": "1","name":"abc5"}],
"links":[{"source": 0, "target": 1, "width": 1},
{"source": 1, "target": 2, "width": 1},
{"source": 1, "target": 3, "width": 1},
{"source": 2, "target": 3, "width": 1},
{"source": 0, "target": 2, "width": 1},
{"source": 4, "target": 2, "width": 1}]
}
var width = 960,
height = 500,
radius = 25,
color = d3.scale.category10(),
rscale = d3.scale.linear().range([5,20]);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.value; });
var arc = d3.svg.arc()
.outerRadius(radius)
.innerRadius(0);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.charge(-90)
.gravity(0.09)
.distance(100)
.size([width, height]);
force
.nodes(graph.nodes)
.links(graph.links)
.start();
rscale.domain(d3.extent(graph.nodes,function(d){ return d.Weight; }))
var div = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link");
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.on("mouseover", function(d) {
var hoverArc=d3.svg.arc()
.outerRadius(50)
.innerRadius(0);
d3.select(this).select("path").transition()
.duration(250)
.attr("d", hoverArc);
div.transition()
.duration(200)
.style("opacity", .9);
div .html(d.name)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
.call(force.drag);
node.each(function(d){
arc = arc.outerRadius(rscale(d.Weight));
d3.select(this)
.selectAll("path")
.data(function(d) {return pie(d.proportions); })
.enter().append("path")
.attr("d", arc)
.style("fill", function(d,i) { return color(d.data.group); });
});
force.on("tick", function() {
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('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; });
});
</script>
</body>
</html>
I hope the above sample helps to give an idea of what I'm dealing with. I would highly appreciate any help that puts me in right direction, I'm still a novice in D3.
Instead of select
, it has to be selectAll
:
d3.select(this).selectAll("path").transition()
.duration(250)
.attr("d", hoverArc);
Because this
is a group element and all the paths in a given pie are children of that group.
Here is your updated code:
graph = {
"nodes": [{
"proportions": [{
"group": 1,
"value": 1
}, {
"group": 2,
"value": 2
}, {
"group": 3,
"value": 3
}],
"Weight": "2",
"name": "abc1"
}, {
"proportions": [{
"group": 1,
"value": 2
}, {
"group": 2,
"value": 1
}, {
"group": 3,
"value": 5
}],
"Weight": "3",
"name": "abc2"
}, {
"proportions": [{
"group": 1,
"value": 7
}, {
"group": 2,
"value": 1
}, {
"group": 3,
"value": 3
}],
"Weight": "4",
"name": "abc3"
}, {
"proportions": [{
"group": 1,
"value": 5
}, {
"group": 2,
"value": 3
}, {
"group": 3,
"value": 4
}],
"Weight": "2",
"name": "abc4"
}, {
"proportions": [{
"group": 1,
"value": 2
}, {
"group": 2,
"value": 7
}, {
"group": 3,
"value": 3
}],
"Weight": "1",
"name": "abc5"
}],
"links": [{
"source": 0,
"target": 1,
"width": 1
}, {
"source": 1,
"target": 2,
"width": 1
}, {
"source": 1,
"target": 3,
"width": 1
}, {
"source": 2,
"target": 3,
"width": 1
}, {
"source": 0,
"target": 2,
"width": 1
}, {
"source": 4,
"target": 2,
"width": 1
}]
}
var width = 600,
height = 400,
radius = 25,
color = d3.scale.category10(),
rscale = d3.scale.linear().range([5, 20]);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.value;
});
var arc = d3.svg.arc()
.outerRadius(radius)
.innerRadius(0);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.charge(-90)
.gravity(0.09)
.distance(100)
.size([width, height]);
force
.nodes(graph.nodes)
.links(graph.links)
.start();
rscale.domain(d3.extent(graph.nodes, function(d) {
return d.Weight;
}))
var div = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link");
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.on("mouseover", function(d) {
var hoverArc = d3.svg.arc()
.outerRadius(50)
.innerRadius(0);
d3.select(this).selectAll("path").transition()
.duration(250)
.attr("d", hoverArc);
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.name)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
var hoverOutarc = d3.svg.arc()
.outerRadius(rscale(d.Weight))
.innerRadius(0);
d3.select(this).selectAll("path").transition()
.duration(250)
.attr("d", hoverOutarc);
div.transition()
.duration(500)
.style("opacity", 0);
})
.call(force.drag);
node.each(function(d) {
arc = arc.outerRadius(rscale(d.Weight));
d3.select(this)
.selectAll("path")
.data(function(d) {
return pie(d.proportions);
})
.enter().append("path")
.attr("d", arc)
.style("fill", function(d, i) {
return color(d.data.group);
});
});
force.on("tick", function() {
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('transform', function(d) {
return 'translate(' + d.x + ',' + d.y + ')';
});
});
.link {
fill: none;
stroke: #000000;
stroke-width: 1.5px;
stroke-opacity: 0.8;
}
div.tooltip {
position: absolute;
text-align: center;
min-width: 100;
width: auto;
min-height: 25;
height: auto;
padding: 2px;
font: 10px sans-serif;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>