September 3rd, 2007 by Kyle
Tags: charting, Flex, flex-charting, graphs, line-sensitivity, linerenderer, mouseout, mouseover, stroke
Posted in: Flex
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:
{
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:
{
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:
<!– 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="0×0099FF"
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="0×0044EB"
/>
</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.










