Flex: Show chart datatips if mouse is anywhere on the chart

As I’ve read in many forums on the web, the Flex charting compounds lack the support of showing DataTips all the time a user moves the mouse arround over a chart. Since there is no official solution or hint by Adobe, and even Flex 4 doesn’t offer a solution I went the stony road to do it all myself.

Here are my steps:

  1. Set up the mouse handlers on the chart compound – the most important is the mouseMove event since it is fired everytime the user moves the mouse upon the chart. the over and out Handlers are only for switching the visibility of the DataTip or other objects. I don’t mention them further
    mouseMove="mouseChartHandler(event)" mouseOver="mouseInHandler(event)" mouseOut="mouseOutHandler(event)"
  2. Setup functions to hande the events
    private function mouseChartHandler(event:MouseEvent):void { .... }
    private  function mouseInHandler(event:MouseEvent):void { .... }
     private function mouseOutHandler(event:MouseEvent):void { .... }
  3. Inside the mouseMove handler function do the following steps:
    1. Define a vertical strip (e.g. 5 px broad) from the top to the bottom with the actual mouse x coordinate
    2. Use the chart series findDataPoints function to capture the item beneath or above the mouse pointer
    3. Use the resulting HitItem to instantiate a DataTip instance (or whatever you need)

That’s it. Easy if one has digged through the bunch of class and function definitions…

Ok, let’s give some code for practical reasons 😉 – so here is the code for the mouseMove handler

		private function mouseChartHandler(event:MouseEvent):void {
			// define a region for the findDataPoint function
			var sensitiveRegion:Rectangle = new Rectangle( event.stageX-5, 0, 10, this.document.height);   

            var hitItems:Array = new Array();

            if (event.currentTarget.name =! "lineChart") return;

            for each ( var chartItem:ChartItem in lineChart.getItemsInRegion( sensitiveRegion ) ) {
            	if ( chartItem.element.name == "seriesMean" ) {
            		var item:LineSeriesItem = chartItem as LineSeriesItem;

            		var xTime:Date = item.xValue as Date;
            		var yVal:Number = item.yValue as Number;

            		var dataPoints:Array = seriesMean.findDataPoints( item.x, item.y, 2 );

            		var hitItem:HitData = dataPoints[0];//new HitData( new Date().getMilliseconds()*Math.random(), 1, item.x, item.y, chartItem);

			if (hitItem) {
                  		hitItems.push( hitItem );

						// Add DataTip to stage if not existing
						if ( !this.stageFlyout ) {
							this.stageFlyout = this.addChild( flyout );
						} 

	            		flyout.x = hitItem.x + 60;
	            		flyout.hitData = hitItem;

					}

            	}
            }

Remark: I use a custom DataTip renderer which I instanciated previous as this.stageFlyout

Now you have a DataTip showing everytime the mouse is moving on the chart. To avoid showing both the custom triggered DataTip and the chart’s provided you can either switch the visibility to false if the chart’s built-in DataTip handler shows his info or you simply turn the showDataTips property of the chart compound of ( in MXML showDataTips=“false“ ).

So please tell me if I should explain the solution further. Or perhaps you have another one – I would be pleased to add it here ;). Simply use the comment function.

[amazon_search design=“2″ width=“256″ market_place=“US“ color_theme=“White“ default_search_term=“Flex“ search_index=“Books“ columns=“1″ rows=“3″ outer_background_color=“#FFFFFF“ inner_background_color=““ background_color=““ border_color=““ header_text_color=“#000000″ linked_text_color=““ body_text_color=““ shuffle_products=“True“ show_image=“True“ show_price=“True“ show_rating=“True“ rounded_corners=“False“/]

8 Kommentare

  1. FlexCoder
    | Permalink

    Thanks for this really good example! Just one question to fully understand, what is flyout?

    • Mike
      | Permalink

      Sorry for the wording. Flyout simply means DataTip. In the project for which I’ve written the code we talked about flyouts instead of DataTips or tooltips, since it has been unterstood better by the non-programmers.

  2. FlexCoder
    | Permalink

    Mike,

    Would you please give an example on how you instantiate your datatips? I have complilation errors when trying the following:

    this.stageFlyout = this.addChild( myDataTip);

    myDataTip.hitData = hitItem;

    Thanks!

    • Mike
      | Permalink

      Since a DataTip has a simple constructor, you could instanciate it like this:
      public var myDataTip:DataTip = new DataTip();

      But in order to avoid two DataTips been displayed at one time it’s usefull to extend the DataTip class by your own and introduce a flag to distinguish your manually callen DataTip from the automatically displayed (by the chart itself). This could be done like this:

      public class DataTipFlyout extends DataTip {
      public function DataTipFlyout( isNotMisc:Boolean=true ) {
      ....
      }
      }

      If you extended the class you would instanciate it this way:

      public var myDataTip:DataTip = new DataTip( false );

      And by the way, don’t forget to tell the chart compound to use your extended class as DataTip renderer with the attribute dataTipRender:
      <mx:LineChart mouseMove="mouseChartHandler(event)" mouseOver="mouseInHandler(event)" mouseOut="mouseOutHandler(event)" showDataTips="true" dataTipMode="single" dataTipRenderer="{DataTipFlyout}"

      With the flag isNotMisc you can handle the different DataTips and e.g. supress the display of your manually instanciated DataTip if the chart shows one itself (if the mouse is near/over a chart item).

  3. FlexCoder
    | Permalink

    Thanks Mike,

    Actually, that’s what I am doing, but I am getting the compile error message as hitData is not a property of datatip (in Flex 3.0).

    var dataTip:MyDataTip = new MyDataTip();
    dataTip.hitData = hitItem; >> Access of possibly undefined property hitData through a reference with static type MyDataTip

    Any guess on this?

    • Mike
      | Permalink

      Oh, I see, I used a propretiary setter of my class extension. Just try to use dataTop.data = hitItem and it should work (hopefully).

  4. Yayo
    | Permalink

    Hi,

    I’ve Question in this line:

    if (event.currentTarget.name =! „lineChart“) return;

    What is „lineChart“? is it ID of the chart?

    thanks
    rgd
    Yayo

    • Mike
      | Permalink

      Hello Yayo,

      yes it’s the same, although id and name are separate propoerties of a UIComponent.

      Mike

Einen Kommentar hinterlassen

Ihre E-Mail wird niemals veröffentlicht oder weitergegeben. Erforderliche Felder sind mit * markiert

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*
*

Ich stimme der Datenschutzerklärung zu

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.