Custom field in flex bar chart - apache-flex

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>

Related

Paint words red in a chat window (spark.components.Label or mx.controls.Text)

I'm trying to change the color of all 4-letter words in a spark.components.Label.
It is a chat-like program, where user enters words into the TextInput field, presses ENTER and the lines are appended to the Label (or Text or TextArea or RichText - whatever is suitable here).
I have prepared this simple test case below, it will run instantly in your Flash Build 4.6 and the code to find the words and their indices is already there.
My problem is to figure out how to change the color of text parts programmatically (i.e. by ActionScript 3) and repeatedly, I just can't figure it out despite reading the docs again and again.
Screenshot:
Test.mxml:
<?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="400" minHeight="300">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private const WORD:RegExp = /\b[a-z]{4}\b/i;
public function chat(event:FlexEvent):void {
var line:String = _input.text;
var start:int = 0;
do {
var rest:String = line.substr(start);
var found:int = rest.search(WORD);
// no more 4-letter words found
if (found < 0)
break;
var word:String = rest.substr(found, 4);
trace('word=' + word + ' # index=' + (start + found));
start += found + 4;
} while (start + 4 <= line.length);
_output.text += (line + "\n");
_input.text = '';
}
]]>
</fx:Script>
<s:Label id="_output" left="4" top="4" right="4" bottom="24" backgroundColor="0xFFFFCC" />
<s:TextInput id="_input" bottom="4" right="4" enter="chat(event)" />
</s:Application>
UPDATE: I'm trying RichText + the code below as suggested by Georgi and see that the pattern replacement has worked (by looking at the trace() output), but get the error:
TypeError: Error #1034: Type Coercion failed: cannot convert "[object TextFlow][object TextFlow]" to flashx.textLayout.elements.TextFlow.
<?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="400" minHeight="300">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import flashx.textLayout.conversion.TextConverter;
private const WORD:RegExp = /\b[a-z]{4}\b/ig;
public function chat(event:FlexEvent):void {
var line:String = _input.text.replace(WORD, '<font color="#FF0000">$&</font>') + '<br>';
trace('line=' + line);
// XXX how to append text here? XXX
_output.textFlow += TextConverter.importToFlow(line, TextConverter.TEXT_FIELD_HTML_FORMAT);
_input.text = '';
}
]]>
</fx:Script>
<s:RichText id="_output" left="4" top="4" right="4" bottom="24" />
<s:TextInput id="_input" bottom="4" right="4" enter="chat(event)" />
</s:Application>
UPDATE 2: If I use _output.textFlow = above then the TypeError goes away. But I need to append the text somehow...
I don't think it's possible with a s:Label component. You may try using s:RichText (which, luckily, isn't very different from s:Label) with appropriate HTML formatting. You'll have to keep the produced HTML and set the textFlow every time, by using TextConverter first. Something like this:
<?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="400" minHeight="300">
<fx:Script>
<![CDATA[
import flashx.textLayout.conversion.TextConverter;
import mx.events.FlexEvent;
private const WORD:RegExp = /\b([a-z]{4})\b/ig;
private var output:String = "";
public function chat(event:FlexEvent):void {
output += _input.text.replace(WORD, '<font color="0xFF0000">$1</font>') + '<br>';
_output.textFlow = TextConverter.importToFlow(output, TextConverter.TEXT_FIELD_HTML_FORMAT);
_input.text = "";
}
]]>
</fx:Script>
<s:RichText id="_output" left="4" top="4" right="4" bottom="24" backgroundColor="0xFFFFCC" />
<s:TextInput id="_input" bottom="4" right="4" enter="chat(event)" />
</s:Application>
The code above is not working perfectly, but seems enough to demonstrate the concept.
Edit:
Note the "g" flag in the regex to match all the four-letter words.

Problem with displaying AS3 code in Flex

I have AS3 script bitfade.text.steel returning type Sprite. It works in Flash environment but not in FLEX. In Flex it displays nothing. No errors appear. It looks like the attached code also works. I use Flex SDK 4.5
Can you give me a clue what the problem with this code might be?
English is not my native language.
If there are any errors please correct me.
Chris
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication 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="creationComplete();" >
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import bitfade.text.steel;
import flash.display.Sprite;
import mx.core.UIComponent;
function creationComplete(){
var textSteel = new steel("config.xml");
if(textSteel is Sprite){
trace("it is a sprite");
}
//var textSteelName:String = getQualifiedClassName(textSteel);
//trace(textSteelName);
textSteel.x = 150;
trace("this is visible on the screen");
var sprite:Sprite = new Sprite();
sprite.graphics.beginFill(0xFFCC00);
sprite.graphics.drawCircle( 40, 40, 40 );
sprite.graphics.endFill();
var wrapper:UIComponent = new UIComponent();
wrapper.addChild(sprite);
wrapper.addChild(textSteel);
animationStage.addElement(wrapper);
}
]]>
</fx:Script>
<s:Group id="animationStage" visible="true" x="50" y="50">
<s:Label text="test">
</s:Label>
</s:Group>
</s:WindowedApplication>
If I switch your custom class to a Sprite, and draw something on it, it shows up. Therefore I Believe there is a bug within your steel class. A sprite won't have any size until something is inside it with a size. There is no indication of the code you've shown what happens inside your steel class.
My sample:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication 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="creationComplete();">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
// import bitfade.text.steel;
import flash.display.Sprite;
import mx.core.UIComponent;
public function creationComplete():void{
var textSteel : Sprite = new Sprite();
if(textSteel is Sprite){
trace("it is a sprite");
}
//var textSteelName:String = getQualifiedClassName(textSteel);
//trace(textSteelName);
textSteel.x = 150;
// JH Code added new
textSteel.graphics.beginFill(0xFFCC00);
textSteel.graphics.drawRect(0,0,100,100);
textSteel.graphics.endFill();
trace("this is visible on the screen");
var sprite:Sprite = new Sprite();
sprite.graphics.beginFill(0xFFCC00);
sprite.graphics.drawCircle( 40, 40, 40 );
sprite.graphics.endFill();
var wrapper:UIComponent = new UIComponent();
wrapper.addChild(sprite);
wrapper.addChild(textSteel);
animationStage.addElement(wrapper);
}
]]>
</fx:Script>
<s:Group id="animationStage" visible="true" x="50" y="50">
<s:Label text="test">
</s:Label>
</s:Group>
</s:WindowedApplication>
I think you need to set the width and height of the wrapper UIComponent instance.
UIComponents don't automatically resize to their content so it's showing up with a width and height of 0.

LineChart data tip won't display with single data point?

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>

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)];
}
}
}

Using AS3 to apply color to dynamically created spark rectangles

in FlashBuilder I want to dynamically generate approximately 1200 rectangles from a CSV file (these are all different colours) which will perform an action on Click.
What is the best way to go about doing this? I've read that the drawing API on Air and Android is not a good idea, and am thinking about using the Spark Rectangle class, but I can't seem to work out how to apply a colour to it if I'm generating them dynamically using AS?
After reading in your CSV, loop through the elements and call a function something like so:
private function addRect(color:uint, xPos:Number, yPos:Number, width:Number, height:Number):void {
var rect:Rect = new Rect();
rect.x = xPos;
rect.y = yPos;
rect.width = width;
rect.height = height;
var fillColor:SolidColor = new SolidColor(color);
rect.fill = fillColor;
var obj:Group = new Group();
obj.addElement(rect);
obj.addEventListener(MouseEvent.CLICK, this.onClick);
this.addElement(obj);
}
private function onClick(e:Event):void {
trace("clicked");
}
Hope that helps.
You can do the entire UI declaratively. Parse the CSV into data structures, and pop it into an ArrayCollection. In this example, I just threw together three samples.
Then, create a DataGroup and set the dataProvider="rectangles" and then create an itemRenderer.
This example works well, IMO:
<?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">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
var rectangles:ArrayCollection = new ArrayCollection([
{color: 0x00FF00, x: 5, y: 10, width: 30, height: 40},
{color: 0xFF0000, x: 50, y: 100, width: 300, height: 400},
{color: 0x0000FF, x: 55, y: 10, width: 30, height: 40},
]);
]]>
</fx:Script>
<s:DataGroup dataProvider="{rectangles}" itemRenderer="RectangleRenderer" />
</s:Application>
Then, the itemRenderer looks like this:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="true"
click="whenClicked()"
x="{data.x}" y="{data.y}"
width="{data.width}" height="{data.height}">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private function whenClicked():void {
Alert.show("clicked");
}
]]>
</fx:Script>
<s:Rect width="100%" height="100%">
<s:fill>
<s:SolidColor color="{data.color}" />
</s:fill>
</s:Rect>
</s:ItemRenderer>

Resources