I had a customer asking how he could make the lines in a LineSeries have a sensitivity to mouse proximity similar to the datapoints.
Here is what I came up with:

The essence of the solution was to extend the LineRenderer and draw an additional line with alpha=0, but of specified width, to the graphics object that the visible line is drawn on. That way mouse events will be dispatched by this line.

I figured the most logical place to specify the lineSensitivity attribute would be on the “Stroke” object, so I added that property to an extension of the Stroke class that I then access in my custom LineRenderer.

Here is the Stroke extension:

package
{
    import mx.graphics.Stroke;

    public class MyStroke extends Stroke
    {
        public function MyStroke(color:uint=0.0, weight:Number=0.0, alpha:Number=1.0, pixelHinting:Boolean=false, scaleMode:String="normal", caps:String=null, joints:String=null, miterLimit:Number=0.0)
        {
            super(color, weight, alpha, pixelHinting, scaleMode, caps, joints, miterLimit);
        }
       
        private var _lineSensitivity:Number=50;
   
        [Inspectable(category="General")]
   
        public function get lineSensitivity():Number
        {
            return _lineSensitivity;
        }
       
        /**
         *  @private
         */

        public function set lineSensitivity(value:Number):void
        {
            _lineSensitivity = value;
        }      
       
    }
}
 

Here is my custom LineRenderer:

package
{
    import mx.charts.renderers.LineRenderer;
    import mx.charts.chartClasses.GraphicsUtilities;
    import mx.graphics.Stroke
    import mx.graphics.IStroke;
    import mx.charts.series.LineSeries;

    public class MyLineRenderer extends LineRenderer
    {
        public function MyLineRenderer()
        {
            super();
        }
   
        override protected function updateDisplayList(unscaledWidth:Number,
                                                      unscaledHeight:Number):void
        {
            super.updateDisplayList(unscaledWidth, unscaledHeight);
           
            // default lineSensitivity – can be set by using MyStroke when defining lineSeries Stroke
            var lineSensitivity:int=50;

            var tStroke:IStroke = getStyle("lineStroke");      
            if((tStroke as MyStroke).lineSensitivity){
                lineSensitivity=(tStroke as MyStroke).lineSensitivity;
            }
           
            var stroke:Stroke = new Stroke(0,lineSensitivity);

            stroke.alpha = 0;
            var form:String = getStyle("form");
   
            GraphicsUtilities.drawPolyLine(graphics, data.items,
                                           data.start, data.end + 1,"x","y",
                                           stroke,form);

        }
   
    }
}
 

Here is the app that puts it all together and demos the new functionality:

<?xml version="1.0"?>
<!– charts/BasicLineStroke.mxml –>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*">
  <mx:Script><![CDATA[
     import mx.collections.ArrayCollection;
     [Bindable]
     public var expenses:ArrayCollection = new ArrayCollection([
        {Month:"Jan", Profit:2000, Expenses:1500, Amount:450},
        {Month:"Feb", Profit:1000, Expenses:200, Amount:600},
        {Month:"Mar", Profit:1500, Expenses:500, Amount:300}
     ]);
     
     
  ]]></mx:Script>
  <mx:Panel title="Line Chart With Strokes">
     <mx:LineChart id="myChart"
        dataProvider="{expenses}"
        showDataTips="true" mouseSensitivity="50">
        <mx:horizontalAxis>
           <mx:CategoryAxis
                dataProvider="{expenses}"
                categoryField="Month"
            />
        </mx:horizontalAxis>
        <mx:series>
           <mx:LineSeries
            yField="Profit"
            displayName="Profit"
            lineSegmentRenderer="MyLineRenderer"
            mouseOver="ta.text+=’Line 1 mouseOver \n‘" mouseOut="ta.text+=’Line 1 mouseOut \n‘">
            <mx:lineStroke>
                <MyStroke
                    color="0x0099FF"
                    lineSensitivity="80"
                />
            </mx:lineStroke>                
           </mx:LineSeries>
           <mx:LineSeries
            yField="Expenses"
            displayName="Expenses"
            mouseOver="ta.text+=’Line 2 mouseOver \n‘" mouseOut="ta.text+=’Line 2 mouseOut \n‘"
           >
            <mx:lineStroke>
                <mx:Stroke
                    color="0x0044EB"
                />
            </mx:lineStroke>                
           </mx:LineSeries>
        </mx:series>
     </mx:LineChart>
     <mx:Legend dataProvider="{myChart}"/>
     
     <mx:TextArea id="ta" width="300" height="200"/>
   
  </mx:Panel>
</mx:Application>
 

You can see in the text area in the app where I trace out interaction (mouseOver, mouseOut events) with the 2 lines in the chart, 1 where I have set the sensitivity to a large amount, and the other where I am not using my custom solution.


Here is a link to a Flex Builder 2.0.1 project
(compiled with SDK hotfix2) containing a sample demonstrating the solution described above.

Share and Enjoy:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis



No Comments »