ColumnChartで、選択されたColumnの色を変えるサンプル

デフォルトのままだと、ColumnChartのColumnはデータ系列毎に一色にするしかなく、PieChartのように、選択された箇所だけ動きを変えることができません。ColumnChartで、選択されたColumnの色を変えたくなることがあると思いますが、そのサンプルを紹介します。

f:id:teppei-studio:20090214084241j:image

このサンプルでは、Sample_Chart.mxml、ColumnChartRenderer.as、EventManager.asの3つのクラスを用意しています。Columnの動きを変えるために、まずはColumnSeriesにItemRendererを指定します。

問題はRendererクラスと、Chartをどう連動させるかなんですが、EventManagerというシングルトンクラスを用意しました。ChartのItemClickイベントをEventManagerを踏み台にしてdispatchさせます。Rendererクラスでは、このEventManagerにListenerをセットしておき、イベントが渡ってきたら、自身が持つColumnSeriesItemオブジェクトと、イベントに格納されているhitData.chartItemと一致確認を行い、挙動を変えます。

この別クラス経由でのやりとりというのが微妙なんですが、一番スマートなやり方じゃないかな・・・と。他にいい案があったら是非ご教示ください。

以下サンプルソースです。

Sample_Chart.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application 
	xmlns:mx="http://www.adobe.com/2006/mxml" 
	layout="absolute" 
	applicationComplete="initApp();" 
	pageTitle="ColumnChart">
	
	<mx:Script>
		<![CDATA[
			import managers.EventManager;
			import mx.collections.ArrayCollection;
			[Bindable]
			private var peakData:ArrayCollection = new ArrayCollection();
			
			private function initApp():void
			{
				for(var i:int=0; i<30; i++)
				{
					var obj:Object = new Object();
					obj.yyyymmdd = 20000000 + i;
					obj.count = i;
					peakData.addItem(obj);
				}
			}
		]]>
	</mx:Script>

	<mx:ColumnChart id="peakChart"
        width="100%" height="100%"
        dataProvider="{peakData}"
        showDataTips="true" 
        itemClick="EventManager.getInstance().dispatchEvent(event)">
        <mx:horizontalAxis>
            <mx:CategoryAxis id="ca"
                categoryField="yyyymmdd"
                dataProvider="{peakData}"
            />
        </mx:horizontalAxis>
        <mx:series>
           <mx:ColumnSeries id="peakColumnSeries"
                xField="yyyymmdd"
                yField="count"
                displayName="count"
                showDataEffect="rearrangeData"
                itemRenderer="renderer.ColumnChartRenderer"
                >
                   <mx:fill>
                       <mx:SolidColor color="#ffff99"/>
                   </mx:fill>
           </mx:ColumnSeries>
        </mx:series>
     </mx:ColumnChart>

</mx:Application>


ColumnChartRenderer.as

package renderer
{
    import flash.display.Graphics;
    
    import managers.EventManager;
    
    import mx.charts.events.ChartItemEvent;
    import mx.charts.series.items.ColumnSeriesItem;
    import mx.core.IDataRenderer;
    import mx.skins.ProgrammaticSkin;

    public class ColumnChartRenderer extends ProgrammaticSkin implements IDataRenderer
    {
        private var color:uint = 0xffff99;
        private var _chartItem:ColumnSeriesItem;
       
        public function ColumnChartRenderer()
        {
            EventManager.getInstance().addEventListener(ChartItemEvent.ITEM_CLICK,chartItemClickHandler);
        }
       
        private function chartItemClickHandler(e:ChartItemEvent):void
        {
            if(this._chartItem == e.hitData.chartItem)
            {
                color = 0xFFAE00;
                invalidateDisplayList();
            }
            else
            {
                color = 0xffff99;
                invalidateDisplayList();
            }
        }
       
        public function get data():Object
        {
            return _chartItem;
        }
       
        public function set data(value:Object):void
        {
            _chartItem = value as ColumnSeriesItem;
        }
       
        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            super.updateDisplayList(unscaledWidth, unscaledHeight);
           
            var g:Graphics = graphics;
            g.clear();
            g.beginFill(color);
            g.drawRect(0,0,unscaledWidth,unscaledHeight);
            g.endFill();
        }
       
    }//end of class
}//end of package


EventManager.as

package managers
{
    import flash.events.EventDispatcher;
   
    public class EventManager extends EventDispatcher
    {
        /**
         * インスタンス生成判定フラグ
        **/
        private static var inside:Boolean = false;

        /**
         * GyomuManagerオブジェクト
        **/
        private static var instance:EventManager = null;
       
        public function EventManager()
        {
            if(inside)
            {
                inside=false;
            }
            else
            {
                throw new Error("UseSingleton.geInstance() to get the instance");
            }
        }
       
        public static function getInstance():EventManager
        {
            if(instance==null)
            {
                inside = true;
                instance = new EventManager();
            }
            return instance;
        }
       
    }//end of class
}//end of package