Exploding pie charts, part 2

In one of my first blogs I demoed a pie chart that made each of the wedges from the pie explode out the way when its item in the legend was rolled over by the mouse.
The pie chart also had a nice effect when it was shown in that it filled up in a circular manor.

You can check out the app here.

After a comment/question from the previous post asking about something I didn’t explain, I thought that it deservered its own post rather than just an edit of the original.

So the question was how do you get the circular effect, and how do you do ‘(… %)’ in the legend?

The effect

Firstly set up the effect

<mx:SeriesInterpolate id="doughnut" duration="1000" />

Then whatever ID you have given your pie series you’d do the following (I called my one ‘seriesOne’)

seriesOne.setStyle('showDataEffect', doughnut);

(I did this set up in the script block on creation complete or show + I nulled the effect/DP’s on hide so that you get the full effect each time)

If you wish to get the full opening of the circle effect then the data must be empty to start with as the effect just changes between the current and the new values.

The second part of the question was to do with the labels on the legend.  This one is all to do with how you set up your dataprovider for the pie chart.

The label

I start of with loading in the data from an XML file (if you use some HTTP tool you should be able to see the data).  It goes something like the following

<chartOne>
  <chartName>blah</chartName>
  <data>
    <section>
      <name>item 1</name>
      <value>37.55</value>
    </section>
    <section>
      <name>item 2</name>
      <value>13.33</value>
    </section>               
  </data>
</chartOne>

As you’ll see from the data there is no ‘%’. So what I do is when I load the data I construct an object VO (value object).

This VO contains the name, item and a label.  The label is just the name + ‘(‘ + value +’%)’.  Then the arrayCollection I use for the dataprovider is just a collection of these object VO’s.

Essentially my VO is this,

var obj : Object =new Object();
obj.name = 'item 1';
obj.value = 37.55;
obj.label = obj.name + '(' + obj.value +'%)';

The legend looks at the data for the pie chart and sees the label property and uses that as it is.

This may make you ask about the datatip for the actual pie chart as it doesn’t contain the brackets. Well for that I had to implement a dataTipFunction.

This function took the form,

private function returnToolTip(hitData:HitData):String {
    return hitData.item.name + ' ' +hitData.item.value + '%';
}

and you just can set this in the MXML of the pie chart.

Well hopefully thats explained in a reasonable way, I’d love to open the entire source for this but without reworking it (commercial reasons) I can’t.

Check out part one of the blog here.

[ad name=”ad-1″]

Exploding Pie Charts

Flex is good, but see trying to get that last few bits out of it at times can be a pain. Take pie charts and the legends. What was required was a simple pie chart with the middle cut out (doughnut chart) and when you moused over the appropriate legend item it would expand the matching item in the pie chart. Surely that would be simple, yeah. Nope, it wasn’t and what I’ve done feels like a hack, but it works.

I’m not going to cover the creation of pie charts, if you want to know that then check out

http://blog.flexexamples.com/2007/10/13/creating-donut-shaped-pie-charts-using-the-innerradius-style/

and

http://blog.flexexamples.com/2007/11/06/exploding-wedges-in-a-flex-piechart-control/

So how did I do the exploding and keep it smooth?

Well first you must make sure the Lengend is listening for the itemMouseOver and Out event

<mx:Legend width="205"
      direction="vertical"
      backgroundColor="0xffffff"
      id="legendOne"
      dataProvider="{chartOne}"
      verticalCenter="0" 
      verticalAlign="middle" 
      left="168"
      itemMouseOver="explode(event)"
      itemMouseOut="implode(event)"
      >
</mx:Legend>

After that you implement the over and out functions. Although you can get the itemMouseOver event you do not actual get a reference/index to what you have just moused over that you can use, so you have to go through the PieSeries data and check its labels against the label that comes with the event. Once you have that you can set the wedge explode radius (perWedgeExplodeRadius).

I also change the alpha value just to make things look a bit better. I also set a over flag so that if you mouse over the label/marker then mouse over it again you stop any flickering. If you mouse over the marker -> label this will result in a item mouse out & over event even though its the same item.

At the same time if an itemMouseOut event occurs i start a short timer before resetting the exploded radius. Again this just helps things look a little smoother.
 

private var pieSeries : PieSeries;
 
//Boolean value to make sure that the animation is smooth and that the correct item is exploded.
//the item out event gets fired when the mouse moves from label to the marker
private var over : Boolean = false;
//explode the section of the chart that was just moused over in the legend
private function explode(event : LegendMouseEvent) : void {
  if(delayTimer){//this will stop the legend, pie chart flickering as the user moves mouse from the label to the marker
     delayTimer.stop();
     delayTimer.removeEventListener(TimerEvent.TIMER, callAfterDelay);
  }
 
  var len : Number = PieSeries(event.item.source).legendData.length;
  var index : Number = 0;
  var arr:Array = new Array(len);
  if(over){
    event.item.alpha = 0.70;
  } else {
    event.item.alpha = 0.70;
    for(var i : Number = 0; i < len ; i++){
      //set the explode radius on the item that fired the over event
      //and make sure that the rest of the exploded radii are 0
      if(event.item.label == event.item.source.legendData[i].label){
        index = i;
        arr[i] = 0.1;
      }else {
	arr[i] = 0;
      }
    }
    PieSeries(event.item.element).perWedgeExplodeRadius = arr;
    over = true;//set the flag to true
  }
}
 
//on the mouse out event this gets called, start a timer in case the user is just moving from label to marker or vice-versa
private function implode(event : LegendMouseEvent) : void {
  delayTimer = new Timer(200, 1);
  delayTimer.addEventListener(TimerEvent.TIMER, callAfterDelay, false, 0, true);
  delayTimer.start();
  pieSeries = PieSeries(event.item.element);
  over = false;//if you don't reset this then when the user moves the mouse down the list nothing will happen
}
 
//This gets called if the timer has finished (mouse has been of legend for a set amount of time)
private function callAfterDelay(event : TimerEvent) : void {
  var arr : Array = [];
  pieSeries.perWedgeExplodeRadius = arr;
}

Thats it, hopefully that will help someone.

Check out part 2 of this explanation here. Part 2 explains the circular effect and how to do the labels for the legend.

[ad name=”ad-1″]