Simple D3 pie chart - animate (grow) arc/slice on mouseover

14,007 views
Skip to first unread message

Mark Bridgett

unread,
Feb 8, 2012, 2:11:24 AM2/8/12
to d3-js
Well playing with D3 is a baptism of fire for sure - Seems like there
are some very simple examples, and then they jump straight to chord
diagrams visualising genomes! I'm really surprised there arent any
tutorials for achieving day to day simple tasks.

Basically, i have a pie chart which i can now draw (using some hacked
code examples), and also got a mouseover event firing when a user
mouseovers on a slice/arc.

Can anyone show me how i can 'grow' this arc as a mouseover animation
(and shrink on mouseout). I'm drawing a blank here!

Code (which works currently) is below :

var w = 300, //width
h = 300, //height
r = 100, //radius
color = d3.scale.ordinal().range(["#ff5200", "#ff8f00",
"#ffc200", "#fff500", "#beea00", "#1dd100", "#ff5200", "#ff8f00",
"#ffc200"]);

var vis = d3.select("#rep_code1_update_categories")
.append("svg:svg")
.data([suData])
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + r + "," + r + ")");

var arc = d3.svg.arc()
.outerRadius(r);

var pie = d3.layout.pie()
.value(function (d) { return d.PostCount; });

var arcs = vis.selectAll("g.slice")
.data(pie)
.enter()
.append("svg:g")
.attr("class", "slice")
.on("mouseover", function (d, i) {
//Mouse over code here
// CAN I ACCESS THE SLICE/WEDGE/ARC here and then animate it
writeDebug('entered : ' + suData[i].CategoryName);
});

arcs.append("svg:path")
.attr("fill", function (d, i) { return color(i); })
.attr("d", arc);

var key = $("#rep_code1_update_categories_key");
for (var f = 0; f < suData.length; f++) {
key.append($('<div id=rep_code1_status_categories_legend_' +
suData[f].CategoryName + ' style=background-color:' + color(f) + ';>'
+ suData[f].CategoryName + '</div>'));
}
Message has been deleted
Message has been deleted

Jason Davies

unread,
Feb 8, 2012, 4:43:32 AM2/8/12
to d3...@googlegroups.com
On Tue, Feb 07, 2012 at 11:11:24PM -0800, Mark Bridgett wrote:
> Well playing with D3 is a baptism of fire for sure - Seems like there
> are some very simple examples, and then they jump straight to chord
> diagrams visualising genomes! I'm really surprised there arent any
> tutorials for achieving day to day simple tasks.

There are more and more on the Wiki:

https://github.com/mbostock/d3/wiki

But we're always open to suggestions. :)

> Can anyone show me how i can 'grow' this arc as a mouseover animation
> (and shrink on mouseout). I'm drawing a blank here!

I'm not sure exactly what you mean by "grow", but if you mean in the "r"
direction (along the radius), this is quite trivial to do.

You can set up another arc generator for the "grown" arcs:

var arcOver = d3.layout.arc()
.outerRadius(r + 10);

Then, your mouseover and mouseout handlers will look like:

var arcs = vis.selectAll("g.slice")
.data(pie)
.enter()

.append("g")


.attr("class", "slice")

.on("mouseover", function(d) {
d3.select(this).select("path").transition()
.duration(1000)
.attr("d", arcOver);
})
.on("mouseout", function(d) {
d3.select(this).select("path").transition()
.duration(1000)
.attr("d", arc);
});

arcs.append("path")


.attr("fill", function (d, i) { return color(i); })
.attr("d", arc);

If you wanted to grow in the angular direction, then you might need a custom
tween function e.g. see:

http://bl.ocks.org/1098617

Another tip: namespaces are optional as of D3 v2.6.0, so the vast
majority of the time you don't need them. Less typing, and easier to
read! The way it determines the namespace is:

- If the element name matches a namespace prefix that it understands
(currently: svg, xhtml, xlink, xml, xmlns) then it is given that
namespace. So you can do vis.append("svg") instead of "svg:svg".
- Otherwise, it inherits the namespace of the parent element. So
appending SVG elements to <svg> and its children don't need
namespaces.

Normally you'll only find yourself needing a namespace prefix when you
want to use something like xlink:href, or if you want to append HTML to
a <foreignObject>.

--
Jason Davies, http://www.jasondavies.com/

Mark Bridgett

unread,
Feb 8, 2012, 6:27:42 AM2/8/12
to d3-js
Thank you so much jason - that worked! And it also helped me get a
better understanding of how this all works - Amazingly powerful for
sure, but somewhat of a learning curve i'm not used to!

Only thing i had to do, was change

var arcOver = d3.layout.arc()
.outerRadius(r + 10);

to

var arcOver = d3.svg.arc()
.outerRadius(r + 10);


.... and it worked.

Brilliant stuff, thanks again :)

Jason Davies

unread,
Feb 8, 2012, 6:42:31 AM2/8/12
to d3...@googlegroups.com
On Wed, Feb 08, 2012 at 03:27:42AM -0800, Mark Bridgett wrote:
> Only thing i had to do, was change
>
> var arcOver = d3.layout.arc()
> .outerRadius(r + 10);
>
> to
>
> var arcOver = d3.svg.arc()
> .outerRadius(r + 10);

Oops, yes. Good catch. :)

David Rea

unread,
Jun 11, 2014, 1:18:15 PM6/11/14
to d3...@googlegroups.com
Stumbled across the thread and it was almost exactly what I wanted to do, except for one thing: I want to to also grow the pie slice from another related chart.  I replaced 'select(this)' with 'selectAll(<my search string>)' and it worked for 'this' but not for the other one in the selection.

Previously I had done this:

.attr("mouseover", mouseOver )

with an external function:
function mouseOver(d,i) {
   var searchString = some search terms
   d3.selectAll( searchString )
       .attr( "stroke", "white" )
}

then in mouseOut() I changed stroke back to transparent.

That worked GREAT...both wedges of both pie charts got outlines on mouseover (helping to illustrate the relationship between the charts). So I know that my search string works.  To confirm, I assigned the selection to a variable and then output it to console. Uh-oh! When I use the search string from the external function it returns size == 2, but when I use it from inside my constructor it only returns size == 1.

I think I understand vaguely why the solution in this post doesn't apply to both...it only works for "this" because it's inside the d3 constructor. But I don't understand conceptually why the internal selectAll only returns one pie slice.

Any solutions?
Reply all
Reply to author
Forward
0 new messages