Flex Stacked Chart: Display custom dataTip total value

Once you use a custom dataTip (dataTipFunction = “myDataTipFunction”) in a stacked chart, its not possible to directly access the total value of items in a column/bar.

This means that your custom dataTips will be without the % and total values that appear (as a default) on Flex stacked charts. This problem is now solved in a simple manner!

Custom DataTip - with % and Total

The function below gets around this problem, and gives one access to a custom dataTip’s ‘total’ value for stacked columns/bars. Complete mxml code is in the full article.

private function myDataTipFunction(hitData:HitData):String
{
	var itemsDictionary:Dictionary = new Dictionary();
	var total:Number = 0;

	//hitData.item holds name value pairs for each of the
	//dataProvider's rows(sales array in this case)
	for(var property:Object in hitData.item){
		itemsDictionary[property] = hitData.item[property];
	}

	// Have to get instance of hitData.element (a ColumnSeries) to
	// access element.series.stacker.series which holds the yField
	// values e.g. toys. Note: needed as hitData.element.
	// series.stacker is not accessible directly.
	var series:ColumnSeries = ColumnSeries(hitData.element);
	for( var key:Object in itemsDictionary)
	{
		for( var i:int = 0; i < series.stacker.series.length; i++){
			// Need to check that we only add yField values, as "period-Q1"
			// is also in hitData.item along with "toys-900" etc
			if(series.stacker.series[i].yField == key.toString()){
				total += itemsDictionary[key];
			}
		}
	}

    var item:ColumnSeriesItem = ColumnSeriesItem(hitData.chartItem);
    var quarter:Object = xAxis.formatForScreen(item.xValue);
    var value:Number = Number(item.yValue) - Number(item.minValue);
    // want 2 decimal place precision
    var percent:Number = Math.round(value / total * 1000) / 10;

    return  "<b>" + series.displayName + "</b>\n" +
			"<b>------------------</b>\n" +
			"" + quarter + "\n" +
			"<b>------------------</b>\n" +
			"<b>Value:\t\t</b>" + value + " \n" +
			"<b>Percent:\t</b>" + percent + "% \n" +
			"<b>Total:\t\t</b>" + total;
}

For the full .mxml example class code…..

The code below is based on an example on Graham Odds blog which solves the same problem in a different way (ive been using it for a few months: you create a custom ColumnSet class that extends mx.charts.series.ColumnSet, and it has a function to return stackedMaximum). The solution below does not require custom classes.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="horizontal"
    width="400"
    height="300"
    backgroundGradientColors="[0xffffff, 0xffffff]"
    viewSourceURL="srcview/index.html"
>
    <mx:Script>
        <![CDATA[
            import mx.charts.series.items.ColumnSeriesItem;
            import mx.charts.series.ColumnSeries;
            import mx.charts.HitData;
            import mx.collections.ArrayCollection;

            [Bindable]
            public var sales:ArrayCollection = new ArrayCollection([
                 {period: "Q1", toys: 900, electronics: 300, clothes: 400},
                 {period: "Q2", toys: 200, electronics: 600, clothes: 450},
                 {period: "Q3", toys: 500, electronics: 300, clothes: 200},
                 {period: "Q4", toys: 800, electronics: 100, clothes: 300}
            ]);

            /**
             *
             */
            private function myDataTipFunction(hitData:HitData):String
            {
            	var itemsDictionary:Dictionary = new Dictionary();
		    	var total:Number = 0;

		    	//hitData.item holds name value pair for each of the
		    	//dataProvider's rows(sales array in this case)
		    	for(var property:Object in hitData.item){
					itemsDictionary[property] = hitData.item[property];
		    	}

		    	// Have to get instance of hitData.element (a ColumnSeries) to
		    	// access element.series.stacker.series which holds the yField
		    	// values e.g. toys. Note: needed as hitData.element.
		    	// series.stacker is not accessible directly.
		    	var series:ColumnSeries = ColumnSeries(hitData.element);
		    	for( var key:Object in itemsDictionary)
		    	{
		    		for( var i:int = 0; i < series.stacker.series.length; i++){
		    			// Need to check that we only add yField values, as "period-Q1"
		    			// is also in hitData.item along with "toys-900" etc
		    			if(series.stacker.series[i].yField == key.toString()){
		    				total += itemsDictionary[key];
		    			}
		    		}
		    	}

                var item:ColumnSeriesItem = ColumnSeriesItem(hitData.chartItem);
                var quarter:Object = xAxis.formatForScreen(item.xValue);
                var value:Number = Number(item.yValue) - Number(item.minValue);
                // want 2 decimal place precision
                var percent:Number = Math.round(value / total * 1000) / 10;

                return  "<b>" + series.displayName + "</b>\n" +
						"<b>------------------</b>\n" +
						"" + quarter + "\n" +
						"<b>------------------</b>\n" +
						"<b>Value:\t\t</b>" + value + " \n" +
						"<b>Percent:\t</b>" + percent + "% \n" +
						"<b>Total:\t\t</b>" + total;
            }
        ]]>
    </mx:Script>

    <mx:ColumnChart
        dataProvider="{sales}"
        width="100%"
        height="100%"
        showDataTips="true"
        dataTipFunction="myDataTipFunction"
    >
        <mx:horizontalAxis>
            <mx:CategoryAxis id="xAxis" categoryField="period" />
        </mx:horizontalAxis>
        <mx:verticalAxis>
            <mx:LinearAxis id="yAxis" />
        </mx:verticalAxis>
        <mx:series>
            <mx:ColumnSet id="columnSet" type="stacked">
                <mx:ColumnSeries yField="toys" displayName="Toys" />
                <mx:ColumnSeries yField="electronics" displayName="Electronics" />
                <mx:ColumnSeries yField="clothes" displayName="Clothes" />
            </mx:ColumnSet>
        </mx:series>
    </mx:ColumnChart>

</mx:Application>

Advertisements

Tags: , , , , ,

11 Responses to “Flex Stacked Chart: Display custom dataTip total value”

  1. bishoponvsto Says:

    Its been asked of me if recalculating the total value on each dataTip event might affect performance in extreme cases.

    Would be interesting if one created a stacked chart with a much larger number of series to test this out, but I dont think there would be any noticable difference.

  2. Venkat Says:

    I am using flex 3.4 SDK, It complains HitData was not found. Please suggest.

    • bishoponvsto Says:

      I presume you got this sorted out?

      Theres definetly no issue with 3.4 and hitData. At the very least get one of the Adobe Livedocs examples working, and make sure that the HitData object is returning something, then take it from there.

  3. Victor Says:

    I don’t think you need to calculate the percentage, it should just be the item’s yValue.

    From reading the data vis PDF:

    In the following example, the yValue of the ColumnSeriesItem represents the percentage which a series takes up in
    a 100% chart:

    public function myDataTipFunction(e:HitData):String {
    var s:String;
    s = “” + ColumnSeries(e.element).displayName + “\n”;
    s += “Income: $” +
    e.item.Income + “\n”;
    s += “Expenses: $” +
    (e.item.Income – e.item.Profit) + “\n”;
    s += “————————\n”;
    s += “Profit: $” + e.item.Profit + “\n”;
    // The value of the Income will always be 100%,
    // so exclude adding that to the DataTip. Only
    // add percent when the user gets the Profit DataTip.
    var percentValue:Number =
    Number(ColumnSeriesItem(e.chartItem).yValue);
    if (percentValue < 100) {
    s += "Profit was equal to about ” +
    Math.round(percentValue) + “
    % of the income.\n”;
    }
    return s;
    //return e.item.Month + “:$” + e.item.Profit + ““;
    }
    >

  4. improve website traffic Says:

    improve website traffic…

    […]Flex Stacked Chart: Display custom dataTip total value « Bishop On Development[…]…

  5. LA video production Says:

    When someone writes an article he/she retains the image of a user in his/her
    mind that how a user can be aware of it. Thus
    that’s why this article is outstdanding. Thanks!

  6. Bridgett Says:

    I am sure this paragraph has touched all the internet users, its
    really really fastidious paragraph on building up new webpage.

  7. Darrin Says:

    Thanks for sharing your thoughts on acolyte. Regards

  8. Geraldine Says:

    I leave a leave a response whenever I especially enjoy a post on a blog or if I have something to contribute to the conversation.
    Usually it’s triggered by the passion communicated in the article I looked at. And after this article Flex Stacked Chart: Display custom dataTip total value | Bishop On Development. I was actually excited enough to post a commenta response 🙂 I do have a couple of questions for you if it’s
    allright. Is it only me or does it look like some of these comments look as if they are written by
    brain dead visitors? 😛 And, if you are writing at other places, I would like to follow you.
    Would you list all of your public pages like your Facebook page, twitter
    feed, or linkedin profile?

  9. Johnf835 Says:

    Good blog! I really love how it is easy on my eyes and the data are well written. I am wondering how I could be notified whenever a new post has been made. I have subscribed to your feed which must do the trick! Have a nice day! bkdegebdedbg

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: