Reputation: 89
I am adjusting this pie chart code - and trying to animate the segment so it juts out like a piece of cake on hover. Not sure why the scope of the mouseover/leave events are not working. I've tried to adjust the radius but its as if its not getting the arc object properly
var color = d3.scale.category20c();
var data = [{"label":"Category A", "value":20},
{"label":"Category B", "value":50},
{"label":"Category C", "value":30},
{"label":"Category A", "value":20},
{"label":"Category B", "value":50},
{"label":"Category C", "value":30},
{"label":"Category A", "value":20},
{"label":"Category B", "value":50},
{"label":"Category C", "value":5}];
var $this = '#chart';
d3.select($this)
.selectAll('svg')
.remove();
const width = 300,
height = 300,
radius = 120,
innerradius = 0;
var arc = d3
.arc()
.outerRadius(radius)
.innerRadius(innerradius);
data.forEach(function(d) {
d.total = +d.value;
});
var pie = d3
.pie()
.sort(null)
.value(function(d) {
return d.total;
});
var svg = d3
.select($this)
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('class', 'piechart')
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
var segments = svg.append('g').attr('class', 'segments');
var slices = segments
.selectAll('.arc')
.data(pie(data))
.enter()
.append('g')
.attr('class', 'arc');
slices
.append('path')
.attr('d', arc)
.attr('fill', function(d, i) {
return color(i);
})
.transition()
.attrTween('d', function(d) {
var i = d3.interpolate(d.startAngle+0.1, d.endAngle);
return function(t) {
d.endAngle = i(t);
return arc(d);
}
});
slices.on('mouseover', function(d) {
console.log("mouseover", radius);
console.log("this", this)
console.log("d3.select(this)", d3.select(this))
let expandArc = d3.arc()
.innerRadius(innerradius)
.outerRadius(radius * 1.2);
/*
d3
.arc()
.outerRadius(radius)
.innerRadius(innerradius)
*/
d3.select(this)
.transition()
.duration(1000)
//.ease('bounce')
.attr('d', expandArc);
});
slices.on('mouseout', function() {
console.log("mouseout");
});
Upvotes: 0
Views: 848
Reputation: 495
The mouse event is bind with slices
, the <g>
element actually.
Then d3.select(this)
is the <g>
instead of the exact path
element. You can see <g>
will have d
attribute after hover, but we need to change the d
of the path
.
Try
slices.on('mouseover', function(d) {
let expandArc = d3.arc()
.innerRadius(innerradius)
.outerRadius(radius * 1.2);
d3.select(this)
.select("path")
.transition()
.duration(1000)
//.ease('bounce')
.attr('d', expandArc);
});
Locate the centroid of the path and translate it when hovered
let offset = 4;// how much do you want to translate from the origin
slices.on('mouseover', function(d) {
d3.select(this)
.transition()
.duration(1000)
.attr('transform', 'translate(' + arc.centroid(d)[0] / offset + ',' + arc.centroid(d)[1] / offset + ')')
});
slices.on('mouseout', function() {
d3.select(this)
.transition()
.duration(1000)
.attr('transform', 'translate(0,0)')
});
Upvotes: 2
Reputation: 68
If I'm understanding you correctly by "pull the slice out", then you want to translate the position of the slice, not change its shape.
The hard part is figuring out where to translate the shape to so that the slice moves from the center along the correct angle. The simplest solution is to use the centroid, the midpoint of the slice and then adjust those values as necessary:
slices.on('mouseover', function(d) {
d3.select(this)
.transition()
.duration(1000)
.attr('transform', 'translate(' + (arc.centroid(d)[0] / 2) + ',' + (arc.centroid(d)[1] / 2) + ')');
});
slices.on('mouseout', function() {
d3.select(this)
.transition()
.duration(500)
.attr('transform', 'translate(0, 0)');
});
Here I divide the centroid x and y values in half so the slices don't go off the SVG area.
PS: var color = d3.scale.category20c();
is d3v3, to do it in d3v4 it would be: var color = d3.scaleOrdinal(d3.schemeCategory20);
. The Fiddle you linked is using both.
Upvotes: 2