XML Driven Pie Chart
Description: Data is grabbed from an XML file and displayed as a pie chart with a data table
Author: John Bezanis
Added: December 10th 2008
Version: Flash 8
This script grabs data from an XML file and displays it as a pie chart with a data table. This entire project is actionscript driven.
Before working on the flash file, we need to set up the xml file containing the data. The main node is chartdata and each entry is a child named entry. Each enty has a label and a count. Optionally, the chart can have a title, which is given using a title node instead of an entry node. This file is saved as chartdata.xml, but you can specify any url by adding ?xmlfile=yourdatafile.xml after both occurences of .swf in the html. XML file example:
<?xml version="1.0"?>
<chartdata>
<title>Favorite Video Games Amongst The Staff</title>
<entry><label>Halo 3</label><count>20</count></entry>
<entry><label>Final Fantasy VII</label><count>15</count></entry>
<entry><label>Call of Duty 4</label><count>10</count></entry>
<entry><label>World of Warcraft</label><count>8</count></entry>
<entry><label>Gran Turismo 3: A-Spec</label><count>4</count></entry>
<entry><label>Nintendogs</label><count>1</count></entry>
</chartdata>
This first bit of code imports two classes, sets a few variables, and receives the xml file.
- //These two classes are used for changing the alpha values of a slice of the pie when moused over
- import flash.geom.ColorTransform;
- import flash.geom.Transform;
- //Radius of the pie chart. Also effects the x position of the table
- pieradius = 100;
- //Amount to scale pie slices when moused over
- mouseoverscale = 110;
- //X position of the center of the pie chart
- xpos = 150;
- //Y position of the center of the pie chart
- ypos = Stage.height/2;
- //Initialize hte chart's title to blank
- var charttitle:String = "";
- //Create an array to store the pie data
- var piearray:Array = new Array();
- //Grab pie chart data from an xml file
- //if the get parameter "xmlfile" is not set, change the xml file to load the data to a default name
- if (_root.xmlfile == undefined || _root.xmlfile == "") {
- //default name for the xml feed
- _root.xmlfile = "chartdata.xml";
- }
- //Create an XML object to hold the xml data
- var myXml:XML = new XML();
- //Ignore white space
- myXml.ignoreWhite = true;
- //Load the xml file
- myXml.load(_root.xmlfile);
- //run when the xml file has loaded
- myXml.onLoad = function() {
- //parse the xml file and load in the chart data
- loadChartData();
- };
Parse the data from the xml file. Store the title into a variable and the entries into an array.
- //this function loads the chart data from the xml file into an array
- function loadChartData() {
- //loop through child nodes of <chartdata> within the xml file
- for (chartIndex=0; chartIndex<myXml.childNodes[0].childNodes.length; chartIndex++) {
- //if the node is an entry, add it to the pie slices
- if(myXml.childNodes[0].childNodes[chartIndex].nodeName=="entry"){
- //add the pie slice info into the array
- piearray.push([myXml.childNodes[0].childNodes[chartIndex].childNodes[0].childNodes[0].nodeValue,
- Number(myXml.childNodes[0].childNodes[chartIndex].childNodes[1].childNodes[0].nodeValue)]);
- //else if the current node is title, set the title of the pie chart
- }else if(myXml.childNodes[0].childNodes[chartIndex].nodeName=="title"){
- //update the charttitle variable, which will be displayed above the table
- charttitle=myXml.childNodes[0].childNodes[chartIndex].childNodes[0].nodeValue;
- }
- }
- //draw the pie chart and data table
- drawChart();
- }
This function creates a movieclip for each slice and draws it into the data table.
- //This function draws the pie chart and the data table
- function drawChart() {
- //this is a sum of all of the slices combined, initialized to 0
- totalcount = 0;
- //loop through all of the data in the array, adding the count of each slice to the total
- for (curpos=0; curpos<piearray.length; curpos++) {
- //add to the total
- totalcount += piearray[curpos][1];
- }
- //now we loop through all of the slices, and update the count as we progress.
- //this is used to determine how much to rotate each slice
- curcount = 0;
- //keep track of the width of the widest text entry. Used to draw the right side of the data table
- widesttext = 0;
- //Create a movieclip to hold the data table graphic
- this.createEmptyMovieClip('datatable', this.getNextHighestDepth());
- //loop through all of the data, drawing each piece of the pie and adding it to the table
- for (curpos=0; curpos<piearray.length; curpos++) {
- //attach a movie clip to hold an individual slice of the pie
- this.createEmptyMovieClip("piece"+curpos, this.getNextHighestDepth());
- //calculate the percentage of the pie the piece takes up
- eval("piece"+curpos).piecepercent = piearray[curpos][1]/totalcount;
- //calculate the rotation in percentage
- eval("piece"+curpos).startpercent = curcount/totalcount;
- //set the x position according to xpos set at the top of this script
- eval("piece"+curpos)._x = xpos;
- //set the y position according to ypos set at the top of this script
- eval("piece"+curpos)._y = ypos;
- //the info for the slice has been set, so now we draw the piece into its movieclip
- drawPiece(eval("piece"+curpos));
- //the piece has been drawn, now add the text showing the percentage of the pie it takes up
- labelangle = (eval("piece"+curpos).startpercent+eval("piece"+curpos).piecepercent/2);
- //hold the piece number, used for coloring in the box in the data table
- eval("piece"+curpos).piecenumber = curpos;
- //create the textfield to hold the percentage
- this.createTextField("piecetext"+curpos, this.getNextHighestDepth(), xpos+Math.cos(labelangle*Math.PI*2-(Math.PI/2))*(pieradius*mouseoverscale/100+12)-20,
- ypos+Math.sin(labelangle*Math.PI*2-(Math.PI/2))*(pieradius*mouseoverscale/100+12)-10, 40, 20);
- //set this text to not selectable
- eval("piecetext"+curpos).selectable = false;
- //set the actual text
- eval("piecetext"+curpos).text = Math.round(eval("piece"+curpos).piecepercent*1000)/10+"%";
- //create a new text formatting to center the text
- var textfmt:TextFormat = new TextFormat();
- //set the text formatting to centered
- textfmt.align = 'center';
- //apply the text format
- eval("piecetext"+curpos).setTextFormat(textfmt);
- //add to total amount that has already been drawn
- curcount += piearray[curpos][1];
- //Create a new movieclip in the data table to hold the piece's text info
- datatable.createEmptyMovieClip('box'+curpos, datatable.getNextHighestDepth());
- //Draw a box to the left of the piece's text. This line sets the style for the border
- eval("datatable.box"+curpos).lineStyle(0, 0x000000, 100, false, "none", "round", "miter", 1);
- //set the color and opacity of the box fill
- eval("datatable.box"+curpos).beginFill(eval('piece'+curpos).randomcolor, 80);
- //draw a line to 10,0 from 0,0
- eval("datatable.box"+curpos).lineTo(10, 0);
- //draw a line to 10,10 from 10,0
- eval("datatable.box"+curpos).lineTo(10, 10);
- //draw a line to 0,10 from 10,10
- eval("datatable.box"+curpos).lineTo(0, 10);
- //draw a line to 0,0 from 0,10
- eval("datatable.box"+curpos).lineTo(0, 0);
- //set the x position a bit left of the text
- eval("datatable.box"+curpos)._x = -12;
- //move the y position according to its position in the pie and the total number of pieces
- eval("datatable.box"+curpos)._y = curpos*20-(piearray.length*20)/2+4;
- //create a text field that holds the text for a slice in the data table. It shows the name and the count
- datatable.createTextField("piecedata"+curpos, this.getNextHighestDepth(), 0, curpos*20-(piearray.length*20)/2, 200, 20);
- //set the text with the name of the current slice and its count
- eval("datatable.piecedata"+curpos).text = piearray[curpos][0]+' ('+piearray[curpos][1]+')';
- //make this text field not selectable
- eval("datatable.piecedata"+curpos).selectable = false;
- //adjust the textfield's width according to the text length.
- //This is used to determine the width of the pie data box
- eval("datatable.piecedata"+curpos).autoSize = "left";
- //if this is the longest text field, update the width. Used when the border box is drawn
- if (widesttext<eval("datatable.piecedata"+curpos)._width) {
- //update the width to this width
- widesttext = eval("datatable.piecedata"+curpos)._width;
- }
- }
- //All of the pieces and the data table has been drawn, now add a border around the data table
- //set the linestyle of the data table's border
- datatable.lineStyle(0, 0x000000, 100, false, "none", "round", "miter", 1);
- //y position changes according to how many pieces are in the pie
- datatable.moveTo(-20, -(piearray.length*20)/2-4);
- //move a bit right of the widest text field
- datatable.lineTo(widesttext+8, -(piearray.length*20)/2-4);
- //move to the bottom right corner of the data table, with some spacing
- datatable.lineTo(widesttext+8, (piearray.length*20)/2+4);
- //move to the bottom left corner of the data table, with some spacing
- datatable.lineTo(-20, (piearray.length*20)/2+4);
- //move back to the top left corner of the data table
- datatable.lineTo(-20, -(piearray.length*20)/2-4);
- //create a text field above the data table to display the title of the pie chart
- datatable.createTextField("charttitletext", datatable.getNextHighestDepth(), -20, -(piearray.length*20)/2-28, 300, 20);
- //set the text according to the variable grabbed in the xml file.
- //if none is set in the xml file, the title is blank
- datatable.charttitletext.text = charttitle;
- //make the title not selectable
- datatable.charttitletext.selectable = false;
- //move the data table to the right of the pie chart with some spacing
- datatable._x=xpos+pieradius+70;
- //move the datatable's y position according to ypos set at the top of this script
- datatable._y=ypos;
- }
This function draws out an individual piece of the pie.
- //this function draws a piece of the pie to the screen.
- //it also adjusts its appearance when moused over/out and underlines a piece in the data table when moused over
- function drawPiece(piece) {
- //The curveto function uses a Quadratic Bezier curve, so we can only draw one eighth of a circle at a time without distortion.
- //Determine how much of the piece is left over after cutting out every full 1/8th of a circle from the piece
- lastsection = (2*Math.PI*piece.piecepercent)%(Math.PI/4);
- //generate a random color for the piece's fill
- piece.randomcolor = (Math.floor(Math.random()*255)+Math.floor(Math.random()*255)*255+Math.floor(Math.random()*255)*255*255);
- //give the piece a black border
- piece.lineStyle(0, 0x000000, 100, false, "none", "round", "miter", 1);
- //apply the fill color to the piece
- piece.beginFill(piece.randomcolor, 80);
- //determine the number of eigths of a circle that fit within the piece
- extraeighths = Math.floor((2*Math.PI*piece.piecepercent)/(Math.PI/4));
- //if the piece is larger than 1/8th of the pie, draw out each of the 1/8ths until less than an eighth is left
- switch (extraeighths) {
- //full pie. move to the center-right of the circle and draw a curve 1/8th of the way clockwise
- case 8 :
- piece.moveTo(pieradius, 0);
- //draw a curved line 1/8th of the circle. The third and fourth parameters are the end x and y positions.
- //the first two parameters tell the line how much to curve
- piece.curveTo(pieradius, Math.tan(Math.PI/8)*pieradius, Math.sin(Math.PI/4)*pieradius, Math.sin(Math.PI/4)*pieradius);
- //piece is at least 7/8ths of the pie. move 45 degrees clockwise from three o'clock and curve to the six o clock position
- case 7 :
- piece.lineTo(Math.sin(Math.PI/4)*pieradius, Math.sin(Math.PI/4)*pieradius);
- piece.curveTo(Math.tan(Math.PI/8)*pieradius, pieradius, 0, pieradius);
- //piece is at least 6/8ths of the pie. move to the six o'clock position and curve to 45 degrees past the six o clock position
- case 6 :
- piece.lineTo(0, pieradius);
- piece.curveTo(-Math.tan(Math.PI/8)*pieradius, pieradius, -Math.sin(Math.PI/4)*pieradius, Math.sin(Math.PI/4)*pieradius);
- //piece is at least 5/8ths of the pie. move 45 degrees clockwise from six o'clock and curve to the nine o clock position
- case 5 :
- piece.lineTo(-Math.sin(Math.PI/4)*pieradius, Math.sin(Math.PI/4)*pieradius);
- piece.curveTo(-pieradius, Math.tan(Math.PI/8)*pieradius, -pieradius, 0);
- //piece is at least 4/8ths of the pie. move to 9 o'clock position and curve to 45 degrees past the nine o'clock position
- case 4 :
- piece.lineTo(-pieradius, 0);
- piece.curveTo(-pieradius, -Math.tan(Math.PI/8)*pieradius, -Math.sin(Math.PI/4)*pieradius, -Math.sin(Math.PI/4)*pieradius);
- //piece is at least 3/8ths of the pie. move 45 degrees clockwise past nine o'clock and curve to the 12 o clock position
- case 3 :
- piece.lineTo(-Math.sin(Math.PI/4)*pieradius, -Math.sin(Math.PI/4)*pieradius);
- piece.curveTo(-Math.tan(Math.PI/8)*pieradius, -pieradius, 0, -pieradius);
- //piece is at least 2/8ths of the pie. move to 12 o'clock position and curve to 45 degrees past the 12 o'clock position
- case 2 :
- piece.lineTo(0, -pieradius);
- piece.curveTo(Math.tan(Math.PI/8)*pieradius, -pieradius, Math.sin(Math.PI/4)*pieradius, -Math.sin(Math.PI/4)*pieradius);
- //piece is at least 1/8th of the pie. move 45 degrees clockwise past 12 o'clock and curve to the 3 o'clock position
- case 1 :
- piece.lineTo(Math.sin(Math.PI/4)*pieradius, -Math.sin(Math.PI/4)*pieradius);
- piece.curveTo(pieradius, -Math.tan(Math.PI/8)*pieradius, pieradius, 0);
- }
- //draw a line to the three o'clock position. If the slice is under 1/8th of the pie, a line is drawn from 0,0. Otherwise, there is 0 length to the line
- piece.lineTo(pieradius, 0);
- //curve from the three o'clock position to the remainder after all full 1/8th slices have been removed
- piece.curveTo(pieradius, Math.tan(lastsection/2)*pieradius, Math.cos(lastsection)*pieradius, Math.sin(lastsection)*pieradius);
- //draw a final line back to 0,0
- piece.lineTo(0, 0);
- //rotate the piece according to the percentage of the pie the slice takes up
- piece._rotation = extraeighths*45+piece.startpercent*360-90;
- //store a variable holding the current coloroffset
- //this variable changes when the mouse moves over or off of the slice.
- piece.coloroffset = 0;
- //do not show the hand cursor when moused over the slice
- piece.useHandCursor = false;
- //when the user mouses over the slice, underline the text in the data table that corresponds to the slice
- //also, start growing the piece and incxreasing its alpha value
- piece.onRollOver = function() {
- //create a text formatting
- var piecetextformat:TextFormat = new TextFormat();
- //set the formatting to underline
- piecetextformat.underline = true;
- //apply the text formatting
- eval("datatable.piecedata"+piece.piecenumber).setTextFormat(piecetextformat);
- //create an interval to start growing the piece and increasing its alpha value
- fadeininterval(this);
- };
- //when the user mouses out from the slice, remove the underline from the text in the data table that corresponds to the slice
- //start shrinking the piece back to its original size and decrease the alpha
- piece.onRollOut = function() {
- //create a new text formatting
- var piecetextformat:TextFormat = new TextFormat();
- //set underline to false
- piecetextformat.underline = false;
- //apply the formatting to the piece
- eval("datatable.piecedata"+piece.piecenumber).setTextFormat(piecetextformat);
- //create an interval to restore the shape to its original shape and opacity
- fadeoutinterval(this);
- };
- }
The next two functions are triggered when the user moves over a piece. A function is called every 10 milliseconds until the piece grows to a certain scale and hits 100% opacity
- //This function sets up an interval triggered every 10 milliseconds that grows a moused over piece and increases its opacity
- function fadeininterval(piece) {
- //if there is already an interval with the selected piece, clear it so we can set up a new one
- if (piece.intervalid) {
- //clear the current interval
- clearInterval(piece.intervalid);
- }
- //create an interval with piece that calls the fadeinstep function every 10 milliseconds
- piece.intervalid = setInterval(this, "fadeinstep", 10, piece);
- }
- //this function increases the scale and opacity of the selected piece
- function fadeinstep(piece):Void {
- //add 10 to the coloroffset variable, with a max of 255. coloroffset is going to specify the alpha offset
- piece.coloroffset = Math.min(255, piece.coloroffset+10);
- //create a color transform object
- var colorTrans:ColorTransform = new ColorTransform();
- //set the alpha offset to the coloroffset set in the piece
- colorTrans.alphaOffset = piece.coloroffset;
- //associate the color transform with the piece
- var trans:Transform = new Transform(piece);
- //apply the color transform to the transform object
- trans.colorTransform = colorTrans;
- //increase the x and y scale by .5, with a max of mouseoverscale (110)
- piece._xscale = Math.min(mouseoverscale, piece._xscale+.5);
- piece._yscale = Math.min(mouseoverscale, piece._xscale+.5);
- //if the piece is fully opaque, remove the interval
- if (piece.coloroffset == 255) {
- //piece is fully opaque, stop calling this function
- clearInterval(piece.intervalid);
- }
- }
The next two functions are triggered when the user moves off of a piece. A function is called every 10 milliseconds until the piece returns to its original size and opacity
- //this function creates an interval to fade a piece back to its original scale and opacity
- function fadeoutinterval(piece) {
- //if there is already an interval established with this piece, remove it
- if (piece.intervalid) {
- //remove the interval associated with this piece
- clearInterval(piece.intervalid);
- }
- //create an interval fired every 10 milliseconds that calls fadeoutstep, which returns a piece to its original scale and opacity
- piece.intervalid = setInterval(this, "fadeoutstep", 10, piece);
- }
- //this function slightly returns a piece to its original size and opacity each time it is called
- function fadeoutstep(piece):Void {
- //decrease the coloroffset variable by 10, with a minimum of 0
- piece.coloroffset = Math.max(0, piece.coloroffset-10);
- //create a new colortransform
- var colorTrans:ColorTransform = new ColorTransform();
- //set the alpha offset to the piece's coloroffset
- colorTrans.alphaOffset = piece.coloroffset;
- //associate the colortransform with the piece
- var trans:Transform = new Transform(piece);
- //apply the colortransform
- trans.colorTransform = colorTrans;
- //decrease the x and y scale by .5, with a minimum of 100
- piece._xscale = Math.max(100, piece._xscale-.5);
- piece._yscale = Math.max(100, piece._xscale-.5);
- //if the piece's coloroffset is back to 0, remove this interval
- if (piece.coloroffset == 0) {
- //remove the interval associated with this piece
- clearInterval(piece.intervalid);
- }
- }
Example html for this project:
<object data="/swfspot/resources/51-piechart.swf?xmlfile=http://www.bezzmedia.com/swfspot/resources/chartdata.xml"
type="application/x-shockwave-flash" width="600" height="300" >
<param name="movie" value="/swfspot/resources/51-piechart.swf?xmlfile=http://www.bezzmedia.com/swfspot/resources/chartdata.xml" />
</object>The source file is available below for download:
Download Source File
Download Demo SWF
Comments
Excellent program for someone who really needs a fast and easy chart. I wish there was an instruction how to change the fonts or color or the size of the pie.
December 16th 2008 01:12AM - George
Thanks alot!!!!!!!! It's excellent.
March 10th 2009 07:03AM - AnhTuan
good chart however i am having problems changing the fonts color managed to change the numbers colors however can not seem to change text color what am i missing
best aaron
best aaron
July 23rd 2009 01:07PM - aaron Robson
Not sure if I can figure out what you are asking there George. Do you mean who to change the colour of each pie segment? Thats set to random colour at present.
October 13th 2009 09:10AM - go go hamsters
Yes, quite fast and easy. Functions are triggered when the user moves over a piece. But yes, would be good if colors were not random and could be selected.
November 4th 2009 01:11PM - volkswagen jetta
wow, that's exactly what I was looking for, thank you so much!
November 4th 2009 05:11PM - dave
like it
November 6th 2009 09:11AM - vigrx
loveing
November 6th 2009 10:11AM - vigrx
Great!! Thanks
I have a question.
How to change the "piece.randomcolor" with constant color. I mean I need every time when the pie is loaded to be with blue, green and red color! not random! Can You help me?
Thanks in advance!
I have a question.
How to change the "piece.randomcolor" with constant color. I mean I need every time when the pie is loaded to be with blue, green and red color! not random! Can You help me?
Thanks in advance!
November 20th 2009 03:11PM - vizin
Very cool. Is there a way to construct the chart by hand and not using action script???
December 8th 2009 05:12PM - sea
Thanks a lot man for this wonderful post
December 13th 2009 01:12AM - Masum Kabir
That is an awesome cube, thanks for sharing.
December 13th 2009 07:12AM - dental
Not sure if I can figure out what you are asking there George. Do you mean who to change the colour of each pie segment? Thats set to random colour at present.
December 18th 2009 08:12AM - Online MP3
Thanks you for sharing
December 19th 2009 08:12AM -
Thank you for sharing
December 19th 2009 08:12AM - radioonline
Thanks alot!!!
December 19th 2009 08:12AM - nakhontoday.com
That's a nice one - I can think of a lot of uses for this script.
December 19th 2009 03:12PM - Money From Home
you have shared very nice post. Thanks for sharing guy!
December 22nd 2009 06:12AM - PHP Web Development
Thanks alot!! I am happy to find many useful information
December 28th 2009 08:12AM - radioonline
Thanks alot It's excellent
December 28th 2009 08:12AM - game
I read all code of this pie chart and their comments and I have 1 question. How to fix the pie chart colors?
January 4th 2010 02:01AM - jobs
great article! thanks for sharing. ;)
January 6th 2010 09:01AM - scorched
Thanks you for sharing
January 11th 2010 06:01PM - Acai Berry
thanks
January 14th 2010 10:01AM - projeksiyon
Buy wellbutrin online now! No prescription needed!
January 14th 2010 05:01PM - Buy Wellbutrin SR
Thanks for sharing these info with us! I was reading something similar on another website that i was researching. I will be sure to look around more. thanks...
January 15th 2010 08:01PM - evening dresses
Nice tutorial in flash it very helpful because you provide step by step process from beginning to end. Thank you for sharing.
January 16th 2010 05:01AM - Php Web Development
Thanks, I will share it on our website
January 17th 2010 05:01AM - desktop tools
Great post.
January 18th 2010 08:01PM - presentation folder
This is the great Pie Chart. It can random colors.
January 18th 2010 09:01PM - book
XML File of this pie chart make me wonder. I need much time to understand it.
January 18th 2010 09:01PM - film
I think the pie chart's XML File is difficult to understand.
January 18th 2010 09:01PM - film
I partially understand this thing
January 19th 2010 08:01AM - Ares
I totally don't get this. i like pies though!
January 19th 2010 03:01PM - Wii Fit Plus in Stock
The fact that something as simple as XML drives the chart makes it possible for even a novice to work with it.
January 20th 2010 08:01PM - SEO
good code for xml. downloaded
January 21st 2010 01:01PM - War Airplanes Spot
This is the great Pie Chart. It can random colors.
January 24th 2010 02:01AM - livescore
Thanks for sharing,it's really good and need some update.
January 24th 2010 02:01AM - 7m
Buy wellbutrin online now! No prescription needed!
January 24th 2010 02:01AM - polball
TTAST
January 24th 2010 06:01AM - evening dresses
Good code, thanks
February 4th 2010 09:02AM - art man
Special thank for good post.
February 5th 2010 09:02PM - โหลดเพลงà
Thank for the information
February 6th 2010 07:02AM - โหลดเพลงm
Need more such scripts :)
February 9th 2010 04:02AM - Acai Berry 13
Special thank for good post.
February 10th 2010 04:02AM - โหลดเพลงà
Special thank for good post.
February 10th 2010 08:02AM - โหลดเพลงà
Very nice, thanks for the post
February 11th 2010 11:02AM - Purple Shower Curtain
Add a Comment





