LineChart data tip won't display with single data point? - apache-flex

In Flex 3, I have a line chart.
My data provider for the line chart contains only one item.
When I draw the line chart, it plots the point. But it doesn't show the data tip.
It works if more than one item is present in dataprovider.
How can I make a data tip visible for line chart with dataprovider containing a single data item?

Use PlotSeries instead of LineSeries when you only have one point. You will get a nice round point with its dataTip. How to do it exactly depends on how your data is built - if the data doesn't change after being assigned to the dataProvider, you can choose which type of series to use at that moment.

try the following code,
in actionscript,
lineSeries.setStyle("itemRenderer", new ClassFactory(mx.charts.renderers.CircleItemRenderer));
in mxml,
<mx:LineSeries yField="Y" itemRenderer="mx.charts.renderers.CircleItemRenderer" xField="X" dataProvider="{lineDataProvider}">

There is a workaround to show the datatip. We need to add ROLL_OVER and ROLL_OUT mouse event listeners to the line series which has single datapoint.
<?xml version="1.0"?>
<!-- Simple example to demonstrate the LineChart and AreaChart controls. -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.charts.HitData;
import mx.charts.renderers.*;
import mx.charts.series.items.LineSeriesItem;
import mx.collections.ArrayCollection;
[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection( [
{ Month: "Jan", Profit: 2000 } ]);
private function lineseriesRollOverHandler(event:MouseEvent):void
{
linechart.showAllDataTips = true;
}
private function lineserieRollOutHandler(event:MouseEvent):void
{
linechart.showAllDataTips = false;
}
private function dataTipFunction(hitData:HitData):String
{
if(hitData && hitData.item)
{
var s:String = "";
if(hitData.element is LineSeries)
{
if(expensesAC.length <=1)
hitData.x = 56;
var lsi:LineSeriesItem = hitData.chartItem as LineSeriesItem;
if(lsi == null)
return "";
s += "<b>" + (hitData.element as LineSeries).displayName + "</b><br />";
s += lsi.xValue + "<br />";
s += lsi.yNumber;
}
return s;
}
return "";
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<mx:Panel width="100%" height="100%" layout="horizontal" title="Single point LineChart Example">
<mx:LineChart id="linechart" width="45%" height="100%" dataProvider="{expensesAC}"
paddingLeft="5" paddingRight="5" showDataTips="true" dataTipFunction="dataTipFunction">
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="Month"/>
</mx:horizontalAxis>
<mx:series>
<mx:LineSeries displayName="Profit" form="curve"
itemRenderer="mx.charts.renderers.CircleItemRenderer"
legendMarkerRenderer="mx.charts.renderers.BoxItemRenderer"
rollOut="lineserieRollOutHandler(event)"
rollOver="lineseriesRollOverHandler(event)" yField="Profit"/>
</mx:series>
</mx:LineChart>
<mx:Legend dataProvider="{linechart}"/>
</mx:Panel>
</s:Application>

Related

Flex Spark TextArea pinch&zoom?

My 1st question here...
Spark component TextArea does have a gestureZoom event property, but it seems that it has no functionality?
I would like to implement a simple zoom feature in my TextArea, which simply increases or decreases fontSize property, making text appear larger or smaller.
After implementing all the necessary code (and it works if instead of TextArea I use Image), pinch&zoom does not trigger the gestureZoom event on TextArea object.
Any suggestions? (I don't insist on using pinch&zoom, it just seems appropriate...)
Here 's the code:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
applicationComplete="application1_applicationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.binding.utils.BindingUtils;
import mx.events.FlexEvent;
[Bindable]
public var currFontSize:int = 24;
protected function application1_applicationCompleteHandler(event:FlexEvent):void {
Multitouch.inputMode = MultitouchInputMode.GESTURE;
if(Multitouch.supportsGestureEvents){
txtbox.addEventListener(TransformGestureEvent.GESTURE_ZOOM, onGestureZoom);
} else {
status.text="gestures not supported";
}
}
// THIS NEVER GETS CALLED?
private function onGestureZoom( event : TransformGestureEvent ) : void {
info.text = "event = " + event.type + "\n" +
"scaleX = " + event.scaleX + "\n" +
"scaleY = " + event.scaleY;
// Zomm in/out simply by increasing/decreasing font size
if (event.scaleX <1 || event.scaleY <1){
if (currFontSize > 12) currFontSize -=2;
}
else{
if (currFontSize < 64) currFontSize +=2;
}
}
protected function button1_clickHandler(event:MouseEvent):void {
info.text = "";
currFontSize = 24;
}
]]>
</fx:Script>
<s:Label id="status" top="10" width="100%" text="Transform Gestures on TextArea"
textAlign="center"/>
<s:HGroup left="12" right="12" top="40">
<s:TextArea id="info" width="100%" height="117" editable="false"/>
<s:Button label="Reset" click="button1_clickHandler(event)"/>
</s:HGroup>
<s:TextArea id="txtbox" left="12" right="12" bottom="12" height="400"
fontSize="{currFontSize}"
gestureZoom="onGestureZoom(event)"
text="Here is some sample text I want enlarged or shrunk."/>
</s:Application>
If the TextArea doesn't need to be editable.. see if you can use a Label. that should work with the pinch and zoom.

Custom field in flex bar chart

I am using floating bar charts to represent schedule in flex. Data is defined like this:
public var schedule:ArrayCollection = new ArrayCollection([
{task:"task1",start:6,end:9},
{task:"task2",start:11,end:12},
{task:"task3",start:14,end:17}
]);
start and end here stands for the time that task begins and finishes.
My question is the xField (time) always start from 0, so that I will have quite a large empty space and the chart doesn't look nice. I want it start from 6, as the start time of task "task1". How can I do it? Please help.
Just use the properties "minimum" and "maximum" of LinearAxis. To get the actual min und max values you can search them in the data provider.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600" creationComplete="init()">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
[Bindable]public var schedule:ArrayCollection = new ArrayCollection([
{task:"task1", start:6, end:9},
{task:"task2", start:11, end:12},
{task:"task3", start:14, end:17}
]);
[Bindable]private var minTime:Number = 24;
[Bindable]private var maxTime:Number = 0;
protected function init():void
{
for each (var task:Object in schedule)
{
if (task.start < minTime)
minTime = task.start;
if (task.end > maxTime)
maxTime = task.end;
}
}
]]>
</fx:Script>
<mx:BarChart
dataProvider="{schedule}"
showDataTips="true">
<mx:verticalAxis>
<mx:CategoryAxis
dataProvider="{schedule}"
categoryField="task"/>
</mx:verticalAxis>
<mx:horizontalAxis>
<mx:LinearAxis minimum="{minTime}" maximum="{maxTime}"/>
</mx:horizontalAxis>
<mx:series>
<mx:BarSeries
xField="end"
minField="start"/>
</mx:series>
</mx:BarChart>
</s:Application>

Timeline in Flex

Trying to build a timeline in Flex, Have a horizontal slider when i slide the slider there should be a line on the linechart as a needle moving with respect to value of slider,I Tried using gridlines to achieve this but the grid lines are visible across all the values of x axis,But I want to show only single gridline with respect to value of slider. Is there a way to hide few grid lines and show specific gridlines.
Here's something I created in about 30 minutes. It's very rudimentary, and has some issues that I will leave for you to solve (or you can post a new question specific to the remaining issues). It's likely you'll need to modify this to suit your application anyway, so I didn't bother looking at the remaining issues.
I've assumed you're using Date objects for the horizontal axis of the chart. As such you need to convert the date object to it's corresponding numerical value (in epoch time). This allows you to work with the slider component, which expects numbers.
If you do have further questions, I recommend trying to post whatever code you're using (or a simple version of it), that others can run. That way the answers you get will be specific to your case, and not generic like this one :)
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="onCreationComplete()">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import spark.primitives.Line;
[Bindable] private var chartData : ArrayCollection =
new ArrayCollection(
[
{ sales: 101000, month: new Date( '01/01/2013' ) },
{ sales: 350000, month: new Date( '02/01/2013' ) },
{ sales: 475000, month: new Date( '03/01/2013' ) },
{ sales: 425000, month: new Date( '04/01/2013' ) }
] );
private var line:Line;
private function onCreationComplete():void
{
line = new Line();
line.height = chart.height;
line.stroke = new SolidColorStroke(0x0000FF, 2);
chartContainer.addElement(line); }
private function getDateInEpochTime(date:Date):Number
{
return date.time;
}
private function dataTipFormatFunction(value:Number):Object
{
return new Date(value).toString();
}
private function onSliderChange():void
{
line.x = convertSliderValueToXCoordinate();
}
private function convertSliderValueToXCoordinate():Number
{
var min:Number = slider.minimum;
var max:Number = slider.maximum;
var adjustedValue:Number = slider.value - min;
var range:Number = max - min;
var percentOfRange:Number = adjustedValue/range
var xCoordinate:Number = slider.width * percentOfRange;
var thumbWidth:Number = slider.thumb.width;
if (percentOfRange > .5)
xCoordinate = xCoordinate - (thumbWidth * (percentOfRange - .5));
else if (percentOfRange < .5)
xCoordinate = xCoordinate + (thumbWidth * (.5 - percentOfRange));
return xCoordinate;
}
]]>
</fx:Script>
<s:Group id="chartContainer" width="800" height="600">
<mx:LineChart id="chart" dataProvider="{chartData}" left="0" right="0" top="0" bottom="20">
<mx:horizontalAxis>
<mx:DateTimeAxis id="hAxis" dataUnits="months" alignLabelsToUnits="true" displayLocalTime="true"/>
</mx:horizontalAxis>
<mx:series>
<mx:LineSeries displayName="Sales by Month" yField="sales" xField="month">
<mx:lineStroke>
<s:SolidColorStroke color="0xFF0000" />
</mx:lineStroke>
</mx:LineSeries>
</mx:series>
</mx:LineChart>
<s:HSlider id="slider" left="0" right="0" bottom="0"
dataTipFormatFunction="dataTipFormatFunction"
minimum="{getDateInEpochTime(chartData.getItemAt(0).month)}"
maximum="{getDateInEpochTime(chartData.getItemAt( chartData.length -1 ).month)}"
change="onSliderChange()"/>
</s:Group>
</s:Application>

Flex chart with multiple series and multiple axes giving weird results

There is a serious issue I am facing with flash builder charts.
When I load the chart the first time I get this -
But if I refresh the page immediately in the same browser, I get this -
The second one is the expected one. This issue just repeats if I close the browser window and open it in a new browser window.
For explaining properly, I am attaching the source code here -
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:defaultstatistics="services.defaultstatistics.*"
xmlns:mx="library://ns.adobe.com/flex/mx" width="800" height="800"
xmlns:Examples="Examples.*"
creationComplete="start();" >
<!--<fx:Style source="styles/Golibaje.css"/>-->
<fx:Script>
<![CDATA[
import CustomEvents.ChartLoadedEvent;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.rpc.events.ResultEvent;
import mx.utils.object_proxy;
import org.axiis.core.AxiisSprite;
import org.axiis.data.DataSet;
private var ds:DataSet = new DataSet();
public var loaded:Boolean = false;
//Set this variable to the appropriate time period used by the data.
[Bindable]
public var timeIncrement:String = "month";
[Bindable]
private var performanceData:ArrayCollection = new ArrayCollection([
{month:"January", correct:100, correctOutsideBase:50,
incorrect:50, skipped:25},
{month:"February", correct:110, correctOutsideBase:40,
incorrect:50, skipped:30},
{month:"March", correct:120, correctOutsideBase:40,
incorrect:25, skipped:30},
{month:"April",correct:110, correctOutsideBase:45,
incorrect:20, skipped:20},
{month:"May", correct:135, correctOutsideBase:25,
incorrect:25, skipped:15},
{month:"June", correct:150, correctOutsideBase:15,
incorrect:15, skipped:5},
{month:"July", correct:155, correctOutsideBase:10,
incorrect:10},
{month:"August", correct:160, correctOutsideBase:5,
incorrect:15},
{month:"September",correct:170, correctOutsideBase:5,
incorrect:10}
]);
[Bindable]
private var pointsData:ArrayCollection = new ArrayCollection([
{month:"January", points:1000},
{month:"February", points:1200},
{month:"March", points:1400},
{month:"April",points:1500},
{month:"May", points:1600},
{month:"June", points:1650},
{month:"July", points: 1800},
{month:"August", points: 2000},
{month:"September", points: 2500}
]);
public function start():void
{
var t:Timer = new Timer(2000, 1);
t.addEventListener(TimerEvent.TIMER_COMPLETE, fireChartLoaded);
t.start();
}
private function fireChartLoaded(event){
loaded = true;
dispatchEvent(new Event("chartLoaded"));
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<mx:CartesianChart id="PerformanceTimeChart" dataProvider="{performanceData}"
showDataTips="true" width="800" height="700"
verticalCenter="0" horizontalCenter="0">
<mx:verticalAxisRenderers>
<mx:AxisRenderer placement="left" axis="{columnAxis}"/>
<mx:AxisRenderer placement="right" axis="{pointsAxis}"/>
</mx:verticalAxisRenderers>
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="{timeIncrement}"/>
</mx:horizontalAxis>
<mx:series>
<mx:ColumnSet type="stacked">
<mx:verticalAxis>
<mx:LinearAxis id="columnAxis" title="Result"/>
</mx:verticalAxis>
<mx:ColumnSeries
yField="correct"
displayName="Correct"
verticalAxis="{columnAxis}"/>
<mx:ColumnSeries
yField="correctOutsideBase"
displayName="Outside Base"
verticalAxis="{columnAxis}"/>
<mx:ColumnSeries
yField="incorrect"
displayName="Wrong Answer"
verticalAxis="{columnAxis}"/>
<mx:ColumnSeries
yField="skipped"
displayName="Skipped Question"
verticalAxis="{columnAxis}"/>
</mx:ColumnSet>
<mx:LineSeries
dataProvider="{pointsData}"
yField="points"
displayName="Points">
<mx:verticalAxis>
<mx:LinearAxis id="pointsAxis" title="Points"/>
</mx:verticalAxis>
</mx:LineSeries>
</mx:series>
</mx:CartesianChart>
<mx:Legend dataProvider="{PerformanceTimeChart}" direction="horizontal"/>
</s:Group>
Anyone has any ideas why this might be happening?
When ColumnSet are used within CartesianChart, there is a bug in Flex Charting SDK regarding setting elements to dataTranform object of ColumnSeries embraced by ColumnSet.
As a workaround for this issue, I set elements by myself to dataTransform object in extended ColumnSeries class:
public class GroupedColumnSeries extends ColumnSeries
{
override protected function commitProperties():void
{
super.commitProperties();
if (this.parent is ColumnSet)
{
dataTransform.elements=[ColumnSet(this.parent)];
}
}
}

Filtering data shown on linechart in flex

i am working on a line chart on flex which enable me to view the progress of data according to the year. I have tried using a slider to filter but it doesn't seemed to work. any help please?
i am not exactly filtering the dataprovider, but the alpha. My function will retrieve all the information from my array collection, but set the alpha to 0, so when user drags the slider, if the year falls below that particular year, it will display the data, which i then set the alpha to 100.
The data is there, the axis are all set, alpha is set to 0. but the problem is, it doesn't display the information line by line as what i wanted it to be, instead, it display the whole graph only until i drag the slider to the end...
these are my codes
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
[Bindable]
public var expenses:ArrayCollection = new ArrayCollection([
{Year:"1990", Profit:2000 },
{Year:"1991", Profit:1000 },
{Year:"1992", Profit:1500 },
{Year:"1993", Profit:2100 },
{Year:"1994", Profit:2500 },
{Year:"1995", Profit:1500 },
{Year:"1996", Profit:1900 },
]);
private function init():void {
expenses.filterFunction = sliderFilterFunc;
expenses.refresh();
}
private function sliderFilterFunc(item:Object):Boolean{
var result:Boolean = true;
pro.alpha=0;
if(item.Year<=slider.value || item.Year==slider.value)
{
pro.alpha=100;
return result;
}
return result;
}
]]></mx:Script>
<mx:VBox horizontalCenter="0" top="10" horizontalAlign="center" height="100%">
<mx:HSlider id="slider" minimum="1990" maximum="1996" value="220" liveDragging="true" change="init()" width="570" snapInterval="1" dataTipPrecision="0" labels="['1990','1996']" tickInterval="1" themeColor="#000000" borderColor="#FFFFFF" fillAlphas="[1.0, 1.0, 1.0, 1.0]" fillColors="[#000000, #000000, #FFFFFF, #1400D1]" height="48" styleName="myDataTip"/>
<mx:Panel title="Line Chart with One Shadow">
<mx:LineChart id="myChart" dataProvider="{expenses}" showDataTips="true" >
<mx:seriesFilters>
<mx:Array/>
</mx:seriesFilters>
<mx:horizontalAxis>
<mx:CategoryAxis
dataProvider="{expenses}"
categoryField="Year"
/>
</mx:horizontalAxis>
<mx:series>
<mx:LineSeries id="pro" alpha="0"
yField="Profit"
displayName="Profit"
/>
</mx:series>
</mx:LineChart>
<mx:Legend dataProvider="{myChart}" />
</mx:Panel>
</mx:VBox>
</mx:Application>
sorry for the messiness.:(
You seem to be using dates as your x axis, the slider can "slide" between numeric values.
What I would do is make my expenses ArrayCollection to:
public var expenses:ArrayCollection = new ArrayCollection([
{Year: new Date(1990), Profit:2000 },
{Year: new Date(1991), Profit:1000 },
...
Then for your filter function:
private function sliderFilterFunc(item:Object):Boolean {
pro.alpha = item.Year.getTime() <= slider.value ? 100 : 0;
return true;
}
Also, are you sure you want to set the alpha to 0 instead of just filtering out the data points? If you would like to shrink your ArrayCollection (don't worry this shrinks the ArrayCollection, not the source, the Array), you could just do:
private function sliderFilterFunc(item:Object):Boolean {
return = item.Year.getTime() <= slider.value;
}
Finally, you should also set your own dataTipFunction for the slider so instead of seeing numbers they see the actual date.
i created a Flex Library (DataFilterLib) that take care of all the filtering process, completly in MXML.
This library is free, you can find the project details there:
http://code.google.com/p/flex-datafilterlib/
If you want to have a look at the examples, they are all in the project's page (source available):
Check the examples online if you want to see how to filter on multiple criterias, using different Flex UI Components (CheckBox, Slider, List, ...).
Using these filters with a Slider (2-thumbs), you can easily filter your data and it will be automatically reflected on your Chart.
Thanks,
Fabien

Resources