TextArea auto scroll update
There was a question on the Flex Forum about how to auto-scroll a TextArea. You can set the VerticalScrollPolicy to auto or you can add a little code to valueCommit to move the vertical scroller. Since I lost where I created the example of adding the code to the valueCommit, I decide to remake the example to show the difference. Both text areas are updated every 10 seconds with a random generated sentence, based off of quotes from Mark Twain.
The left TextArea box uses the VerticalScrollPolicy set to “auto”
<s:TextArea id="tmpTxtArea1" width="98%" height="98%" verticalScrollPolicy="auto" />
The right TextArea box uses the valueCommit code to move the verticalScrollBar
<s:TextArea id="tmpTxtArea2" width="98%" height="98%" valueCommit="tmpTxtArea2.scroller.verticalScrollBar.value = tmpTxtArea2.scroller.verticalScrollBar.maximum" />
While the right box doesn’t move the TextArea scroll bar 100%, it does move it.
The current issues I need to update with this example is a better random sentence generator and fix the regular expression that is supposed to remove the commas and periods before creating the word array. That’s probably some sort of project I can do later, so the sentences created are a little bit off, since I don’t remember how I did it in the previous example and the site I got the code idea from is no longer available.
Date Sort in a DataGrid – the easy way
While trying to give suggestions to a post on the Flex Forum, I modified my Simple Data Grid to include a column for a Date. The poster had an issue with sorting the column with dates in it. My guess is, the Date value is actually a String object. It really isn’t very hard to create a Date from a string, just parse out the String and feed the appropriate date times into the Date object. Here is how I create the random date value.
// Create a Random Date var randomMonth:Number = Math.floor(Math.random() * (11)); var randomDay:Number = Math.floor(Math.random() * (27)); var randomHour:Number = Math.floor(Math.random() * (23)); var randomMinute:Number = Math.floor(Math.random() * (59)); var thisDate:Date = new Date(); thisDate.month = randomMonth; thisDate.date = randomDay; thisDate.hours = randomHour; thisDate.minutes = randomMinute;
Since I insert the value into the item Object as a Date object, the sort function knows how to sort for Descending/Ascending. It might take a few more steps to convert a set of String data into objects and insert them into an ArrayCollection, but I think it saves time in the long run, because you work with each value as what they are and not a String that you have to convert to a Number, Int or Date.
Here is the DataGrid example. Not only does sorting by the column header work for the dates, I added a button to sort by the dates. The button switches between Ascending and Descending each time it is clicked.
View Source
[kml_flashembed publishmethod="dynamic" fversion="9.0.0" movie="http://deanlogic.com/demo/Flex/SimpleDataGrid/SimpleArrayCollectionUpdate.swf" width="850" height="500" targetclass="flashmovie"/]
Stacked Column Chart with Line Series
On the Flex Forum, I was attempting to help someone find their issue to a Stacked Column Chart with a Line Series. The y-axes values were not corresponding with the data being provided. This seemed like a glitch and I even attempted a work around by finding the minimum and maximum values. Finally, after looking at the Stacking Columns example and the Multiple Axis Example, reconstructed the chart using the static objects instead of dynamically creating the chart. From there, I recreated the chart items in a function and determined that the first issue the poster was having was building the column series incorrectly into a column set.
// add column series to column set columnset.series = [columnSeries1, columnSeries2];
The second issues is that the created column set and the line series would be the two series added to the chart, not the individual column series.
myChart.verticalAxisRenderers = [verticalAxisRendererRight, verticalAxisRendererLeft]; // column set and linear series to Chart myChart.series = [columnset, lineSeries];
I also added both x-axis and y-axis data column information, so that there would be no mistake as to were the data was coming from. These small changes apparently were the key to getting the axis values to match the column and charts.
var columnSeries1:ColumnSeries = new ColumnSeries();
columnSeries1.dataProvider = acChartData;
columnSeries1.xField = "hourOfDay";
columnSeries1.yField = "greenAppleCount";
columnSeries1.displayName = "Green";
columnSeries1.setStyle("fill", 0x009900);
columnSeries1.verticalAxis = verticalAxisLeft;
I used my apples data creator for this chart, since I already had that available on the other chart.
Another side note of obviousness, you fill columns and stroke lines.
[kml_flashembed publishmethod="dynamic" fversion="9.0.0" movie="http://deanlogic.com/demo/Flex/StackedColumnWithLineSeries/StackedColumnLineChart.swf" width="800" height="500" targetclass="flashmovie" /]
Find minimum or maximum value from Array
Browsing through the questions at the Adobe Flex forum again and came across one about having an issue with the Y-axis display on a dual-Y axis column/line chart. I’m not sure I gave the answer the poster was looking for, but my guess was that the minimum and maximum values for each LinearAxis was not set. You could set them to static values, but that wouldn’t be too useful. So, I did a quick search for some code to find the max value of an array and then modified it for AS3.
private function findMax(sourceArray:Array, sourceValue:String):Number {
var maxNumber:Number = 0;
for (var i:int = 0; i < sourceArray.length; i++) { var tmpNum:Number = new Number((sourceArray[i][sourceValue]).toString()); if(tmpNum > maxNumber) {
maxNumber = sourceArray[i][sourceValue];
}
}
return maxNumber;
}
private function findMin(sourceArray:Array, sourceValue:String, startMax:Number):Number {
var minNumber:Number = startMax;
for (var i:int = 0; i < sourceArray.length; i++) {
var tmpNum:Number = new Number((sourceArray[i][sourceValue]).toString());
if(tmpNum < minNumber) {
minNumber = sourceArray[i][sourceValue];
}
}
return minNumber;
}
— update —
There is apparently even an easier way of finding the minimum and maximum in an array of values using a Math function. However, you still have to split out the particular set of values from the overall array, which I don’t think there is a way to do.
Math.max(Array[]); Math.min(Array[]));
It is pretty straight forward. Go through the array and find the value for a particular column, then check to see if it is smaller or larger than the previous stored value. The only difference between the two, is setting the starting high value for finding the minimum. So, when using these functions, you should find the maximum first and use that value as the startMax in order to find the minimum. This is who it was used in the LinearAxis code.
// VERTICAL AXIS var verticalAxisLeft:LinearAxis = new LinearAxis(); verticalAxisLeft.autoAdjust = true; verticalAxisLeft.maximum = Math.ceil(findMax(SMITH.source, "open")); verticalAxisLeft.minimum = Math.ceil(findMin(SMITH.source, "open", verticalAxisLeft.maximum)); var verticalAxisRight:LinearAxis = new LinearAxis(); verticalAxisRight.autoAdjust = true; verticalAxisRight.maximum = Math.ceil(findMax(DECKER.source, "close")); verticalAxisRight.minimum = Math.ceil(findMin(DECKER.source, "close", verticalAxisRight.maximum));
However, using the right Array, that has higher values than the left, will cause some issues. It is probably best to either use 0 or the smaller minimum value of the two arrays.
- The minimum value for the right and left linear axis are both using 0
- The minimum value for the right linear axis was found using the maximum for the left array
- The minimum value for the right linear axis was found using only the array associated with that axis
Simple DataGrid with Row Background Update
On the Adobe Flex forum, a question was asked about changing the background color for a row to a different color if the user selected it and hit the DELETE key. So, I updated the Simple Data Grid to include this feature. It doesn’t delete the row, but changes the background color to grey.
The first step is to capture the keyboard action. To do this, a listener has to be created and set to listen for a KeyBoard event. I set it for the stage, but doing so requires that the function is called when applicationComplete instead of earlier. An alternative would be to set it to FlexGlobals.topLevelApplication, either way works.
// Add keyboard listener stage.addEventListener(KeyboardEvent.KEY_DOWN, keyHandler);
After you point the listener to your handler, you will need to make the handler look for the key or key press. In my example, I am only looking for the DELETE key, but you can look for any Keyboard key. And you can also check to see if things like the “shift”, “alt” or the “capsLock” is activated when the key is pressed. After the function determines that the key pressed is DELETE, then it updates the ArrayCollection object to set the “isDeleted” value to true. I modified my original data object to include the “isDeleted” boolean value, which I default to false.
private function keyHandler(event:KeyboardEvent):void {
// Handles the keyboard even
// If the keyboard event is DELETE
if(event.keyCode == Keyboard.DELETE) {
debugTxt.text += " \n Key was DELETE";
debugTxt.text += " \n keyCode = " + event.keyCode + "/" + event.charCode;
// If an item on the grid has been selected and isn't the header row
if(myDataGrid.selectedIndex >= 0) {
debugTxt.text += " \n Grid Index = " + myDataGrid.selectedIndex;
// Set the object to isDeleted
var tmpObject:Object = new Object();
tmpObject = myDataGrid.selectedItem;
tmpObject["isDeleted"] = true;
var itemFoundAt:int = myArrayCollection.getItemIndex(myDataGrid.selectedItem);
if(itemFoundAt != - 1) {
myArrayCollection.setItemAt(tmpObject, itemFoundAt);
}
} else {
debugTxt.text += " \n Grid not selected ";
}
} else {
debugTxt.text += " \n " + event.keyCode + "/" + event.charCode;
}
}
After the data is updated, then a physical change needs to take place to the DataGrid to show this change. As in the earlier example, I used an itemRenderer, but I added it to the DataGrid and not to the individual columns. This renderer simply checks the data value for “isDeleted” and sets the alpha and color for the column accordingly. Instead of setting the backgroundColor of the label, the renderer creates a rectangle as the background and the color fill and alpha values are set. I set the alpha to 0 for the false option, because this will allow the alternating rows to continue with the color displayed.
override public function prepare(hasBeenRecycled:Boolean):void {
if(data != null) {
if(data["isDeleted"]) {
bgColor.color = 0xcccccc;
bgColor.alpha = 1;
} else {
bgColor.alpha = 0.0;
}
lblData.text = data[column.dataField];
} else {
return;
}
}
What I haven’t done is the final step to delete the rows highlighted for deletion. This would simply be a function to go through the ArrayCollection and find the isDeleted == true objects and then remove them. I also added the debug text area to show the key listener results.
Select a row and then hit the DELETE key on your keyboard.
View Source
[kml_flashembed publishmethod="dynamic" fversion="9.0.0" movie="http://deanlogic.com/demo/Flex/SimpleDataGrid/SimpleArrayCollectionUpdate.swf" width="750" height="500" targetclass="flashmovie" /]
Simple Chart Overlay
One of the screens I created for work is a “dashboard” type that allows the view to quickly see the current status of service call volume. There are multiple charts on the display, but one of them is a column chart that shows the current day’s numbers vs. the prior week of the same day. By having this information, the viewer can see if the volume of calls is in a “normal” range, because the it fluctuates throughout the day and the week, but is similar based on the day of the week. Friday’s call volume is usually lower than Wednesday volume. When I initially created the display in Flex 3, I had to worry about putting both column charts in the same x and y spot in order for the overlay to work. With the Group component, it makes it much easier, because it automatically puts the items stacked upon each other.
The example creates some random data of the number of red, green and yellow apples picked in an hour. The random data is created for all of the previous day’s hours and then a 15 second timer creates the current day’s hours one by one. In the real chart, the data is update every 15 minutes. The bottom chart is added first, which is the “Yesterday” values and the top chart is added next, which is “Today” values. The “Yesterday” values are slightly hidden by using a alpha setting in the “Today” chart.
// Bottom Chart for "Yesterday" values
<mx:ColumnChart id="countsYesterday" width="100%" height="100%" showDataTips="true" dataProvider="{acChartYesterday}">
// Top Chart for "Today" values
<mx:ColumnChart id="countsToday" width="100%" height="100%" showDataTips="true" dataProvider="{acChartToday}" alpha=".65">
To help with the color offset, I picked colors for the “Yesterday” values that seem to be faded version of the “Today” colors. You could use any colors for the columns, but having less bright values in the back help with contrast. It also helps when the values for “Today” are greater than for “Yesterday”. The only downfall for doing things this way is that the datatips for the bottom chart cannot be seen. But, I’m sure the datatip function could be modified to get both values.
[kml_flashembed publishmethod="dynamic" fversion="9.0.0" movie="http://deanlogic.com/demo/Flex/ChartOverlay/ChartOverlay.swf" width="800" height="500" targetclass="flashmovie"]




