Flex / Adobe Air - Chart legend/Axis fontsize too small - actionscript-3

I'm adding a chart to my AIR App. Here is how:
private function CountersChart(container:VGroup):void {
var arr:Array = [];
var dt:Date = new Date();
var counters:Counters = Constants.srv.getCounters(dt.fullYear, dt.month);
var goals:ArrayCollection = Constants.srv.getGoals();
var index:int = 0;
var found:Boolean = false;
var now:Date = new Date();
while (!found) {
var goal:Goals = goals[index];
if (now.month+1==goal.month && now.fullYear==goal.year) {
found=true;
break;
} else
index++;
}
arr.push({label:"Calls", x:"Calls", y:counters.phone, y1:goals[index].calls});
arr.push({label:"Text", x:"Text", y:counters.sms, y1:goals[index].sms});
arr.push({label:"Email", x:"Email", y:counters.email, y1:goals[index].emails});
arr.push({label:"Marketing Tools", x:"Marketing Tools", y:counters.marketing, y1:goals[index].sendMarketingTools});
arr.push({label:"Meetings", x:"Meetings", y:counters.meeting, y1:goals[index].meetings});
arr.push({label:"Home Presentations Invites", x:"Home Presentations Invites", y:counters.homePresentationInvite, y1:goals[index].homePresentations});
arr.push({label:"Business Presentation Invites", x:"Business Presentation Invites", y:counters.businessPresentationInvite, y1:goals[index].businessPresentations});
// Create a column chart object
var stackedColumnChart:ColumnChart = new ColumnChart();
stackedColumnChart.dataProvider = arr;
stackedColumnChart.showDataTips = true;
stackedColumnChart.dataTipFunction = myDataTipFunction;
stackedColumnChart.percentWidth = 100;
// Set the horizontal axix category
var xAxis:CategoryAxis = new CategoryAxis();
xAxis.categoryField = "x";
stackedColumnChart.horizontalAxis = xAxis;
// ColumnSet.series is an array which contains
// an array of ColumnSeries objects.
var columnSet:ColumnSet = new ColumnSet();
columnSet.type = "stacked";
// Each item in seriesDetails becomes a different segment of
// a column in the stacked chart i.e. each item represents a series.
var seriesDetails:ArrayCollection = new ArrayCollection([
{YField:"y", DisplayName:"Actual"},
{YField:"y1", DisplayName:"Planned"},
]);
// Create a ColumnSeries, and an array to be
// populated with dynamically generated columnSeries objects
var columnSeries:ColumnSeries;
var seriesArray:Array = new Array();
var xr:AxisRenderer = new AxisRenderer();
xr.setStyle("fontSize",40);
//columnSeries.verticalAxis = xr;
// Generate an array of ColumnSeries objects
// which are then be applied to the ColumnSet series.
for(var i:int = 0; i < seriesDetails.length; i++){
columnSeries = new ColumnSeries();
columnSeries.yField = seriesDetails[i].YField;
columnSeries.displayName = seriesDetails[i].DisplayName;
columnSeries.setStyle("fill",fillsArray[i]);
seriesArray.push(columnSeries);
}
columnSet.series = seriesArray;
// c.series could take an array of column sets
// for displaying mixed charts i.e. c.series = [columnSet1, columnSet2];
stackedColumnChart.series = [columnSet];
//stackedColumnChart.showAllDataTips();
stackedColumnChart.showDataTips = true;
stackedColumnChart.id = "chart";
var legend:Legend = new Legend();
legend.direction = "horizontal";
legend.setStyle("fontSize",30);
legend.dataProvider = stackedColumnChart;
stackedColumnChart.setStyle("horizontalAxisRenderers", xr);
stackedColumnChart.addEventListener(MouseEvent.CLICK,function(event){return});
//Add chart to the display list.
container.addElement(stackedColumnChart);
container.addElement(legend);
}
The result draws the chart nicely BUT: The font size of the legend and the x/y axis are soooo small, Can't even read them.
I've tried to set the legend.setStyle("fontSize",fs) or to set the legend minHeight (as suggested here: Flex chart labels way too small, how to resize axis?
But to no avail :-(
How can I modify the font size for them?
Thanks

You need to provide the css for LegendItem class and ColumnChart class, and then it will pick up the style for it:
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
#namespace mx "library://ns.adobe.com/flex/mx";
mx|LegendItem
{
fontSize:20;
}
mx|ColumnChart
{
fontSize:15;
}
</fx:Style>
Providing setStyle to Legend does not work.
Please let me know if it works for you.

Related

Make movieclips appear randomly in AS3

Right now I have six mice places in spesific places on the stage. These mice move based on adjustments made on the timeline inside the movieclip itself. What I aim to do is to start these six movieclips randomly based on a timer. This task im currently struggeling with..
Here is my code;
var clipArray:Array = new Array();
clipArray[0] = musx0_mc;
clipArray[1] = musx1_mc;
clipArray[2] = musx2_mc;
clipArray[3] = musx3_mc;
clipArray[4] = musx4_mc;
clipArray[5] = musx5_mc;
var i:int = 0;
var musTimer:Timer = new Timer(100);
musTimer.addEventListener(TimerEvent.TIMER, playMus);
function playMus(event:TimerEvent):void
{
for(i=0; i<clipArray.length; i++)
{
var randomMus:Number = Math.floor(Math.random()*100);
clipArray[randomMus].play();
}
}
musTimer.start();
It seems that you want to get 0 to 5 random number.
//var randomMus:Number = Math.floor(Math.random()*100); // returns 0 to 99
var randomMus:int = Math.floor(Math.random()*6); // returns 0 to 5
Maybe this code works.
var clipArray:Array = new Array();
clipArray[0] = musx0_mc;
clipArray[1] = musx1_mc;
clipArray[2] = musx2_mc;
clipArray[3] = musx3_mc;
clipArray[4] = musx4_mc;
clipArray[5] = musx5_mc;
var musTimer:Timer = new Timer(100);
musTimer.addEventListener(TimerEvent.TIMER, playMus);
function playMus(event:TimerEvent):void
{
//for(i=0; i<clipArray.length; i++) // What is this loop??
//{
//var randomMus:Number = Math.floor(Math.random()*100);
var randomMus:int = Math.floor(Math.random()*6);
clipArray[randomMus].play();
//}
}
musTimer.start();

Displaying multipe Array-type attributes of sharedObject.data property in a single list

I have various food category pages (such as "Carbohyrates", "Meat", "Vegetables" etc) that have 3 comboboxes on each page where a user can select 3 different ingredients from each category (i.e. on the "Meat" page, a user can select 3 different types of meat). I write these 3 meats to a sharedObject as an Array like so:
Here is my saveMeat() function as an example so you can understand how I am forming my arrays:
function saveMeat(event:MouseEvent):void
{
_categoryMeat.btn_goback.removeEventListener(MouseEvent.CLICK, saveMeat);
removeChild(_categoryMeat);
if (meatDisableCheckBox.selected == true)
{
stop();
}
if (myComboBoxMeat.selectedLabel != null)
{
so.data.meat1 = myComboBoxMeat.selectedLabel;
trace(so.data.meat1);
}
if (myComboBoxMeat2.selectedLabel != null)
{
so.data.meat2 = myComboBoxMeat2.selectedLabel;
trace(so.data.meat2);
}
if (myComboBoxMeat3.selectedLabel != null)
{
so.data.meat3 = myComboBoxMeat3.selectedLabel;
trace(so.data.meat3);
}
var meat_items_array:Array = new Array(so.data.meat1, so.data.meat2, so.data.meat3);
so.data.meatItems = meat_items_array;
so.flush();
trace(so.data.meatItems);
}
There are several of these functions for each of the category pages (in all 6 different functions). They are all pretty similiar except for the fact the checkboxes and comboboxes differ.
I have a list function called dataLoaded that loads items from the sharedObject into the scrolling list:
private function dataLoaded():void
{
var i:Number;
for (i=0; i < so.data.meatItems.length; i++) {
_item = new Item();
// creates the var itemTextField //
_itemTextField = new TextField();
_itemTextField.text += '' + so.data.meatItems[i].toString();
//adds textfield to displaylist//
_item.addChild(_itemTextField);
}
}
As you can see, the for loop inputs the toString() representation of one of my attributes of my sharedObject (so.data.meatItems) into the TextField but I want to input all instances inside of my sharedObject no matter what sub-attribute they have. Also notice that I'm evaluating the length of the meatItems array in the for loop conditional, when I would want to be evaluating all items in the sharedObject
How can I do this?
EDIT: I implemented the below solution but am receiving this error:
TypeError: Error #1010: A term is undefined and has no properties.
at RecipeMatcher/dataLoaded()[/Users/adambull/Desktop/RecipeMatcherSO/RecipeMatcher.as:893]
at RecipeMatcher/displayList()[/Users/adambull/Desktop/RecipeMatcherSO/RecipeMatcher.as:212]
at RecipeMatcher/hideSplashScreen()[/Users/adambull/Desktop/RecipeMatcherSO/RecipeMatcher.as:192]
at Function/http://adobe.com/AS3/2006/builtin::apply()
at SetIntervalTimer/onTimer()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
Here is my attempt at implementing the below (I have included my full function this time just in case there is something else in my function causing problems)
private function dataLoaded():void
{
// parsing of each ingredient//
// instantiation of mcItem (the stage for each item)
for (var item:* in so.data)
{
if (so.data[item] !=null)
{
if (so.data[item] is Array)
{
var a:Array = so.data[item];
for (var i:uint = 0 ; i < a.length;i++ )
{
_item = new Item();
// sets //over// layer to invisible / transparent //
_item.item_btn_over.alpha = 0;
// creates the var itemTextField //
_itemTextField = new TextField();
// _itemTextField visual attributes //
_itemTextField.x = _textFieldXPosition + _textFieldPaddingLeft;
_itemTextField.y = _textFieldYPosition;
_itemTextField.selectable = true;
_itemTextField.wordWrap = true;
itemTextField.width = _textFieldWidth;
_itemTextField.height = _textFieldHeight;
_itemTextField.embedFonts = true;
_defaultFormat.color = 0x111112;
_defaultFormat.font = _arialRounded.fontName;
_defaultFormat.size = 18;
_itemTextField.defaultTextFormat = _defaultFormat;
_itemTextField.appendText( so.data[item][i].toString() );
//adds textfield to displaylist//
_item.addChild(_itemTextField);
//vertical positioning//
_item.y = i * _itemPosition;
_item.btn_delete.visible = false;
_item.buttonMode = true;
_item.mouseChildren = false;
//adds items to container displaylist//
_container.addChild(_item);
}
}
}
}
// Input Mask//
_mask = new Shape();
_mask.graphics.beginFill(0xFF0000);
_mask.graphics.drawRect(0, 0, _maskWidth, _maskHeight);
_mask.graphics.endFill();
// Positioning of input mask//
// horizontal centering of input mask//
_mask.x = stage.stageWidth / 2 - _container.width / 2;
_mask.y = _paddingTop;
// adds the mask onto the stage//
addChild(_mask);
// assigns the above mask to the container //
_container.mask = _mask;
// Positioning of container with the mask//
// horizontal centering of container //
_container.x = stage.stageWidth / 2 - _container.width / 2;
// vertical position of container //
_container.y = _paddingTop;
//Container background stylings//
_background = new Shape();
_background.graphics.drawRect(0, 0, _container.width, _container.height);
_container.addChildAt(_background, 0);
//End of container background stylings//
_item.parent.addEventListener( MouseEvent.CLICK, itemClicked );
_container.addEventListener(MouseEvent.MOUSE_OVER, movingOver);
_container.addEventListener(MouseEvent.MOUSE_OUT, movingOut);
}
(I have tried adding an extra if to evaluate whether the content of each shared object attribute is empty or not - because I believe that if an array is empty this may cause another error?)
If I understood well you question, here is an example. It browse so.data, looks for arrays and then iterates on each one.
import flash.net.SharedObject;
var my_so = SharedObject.getLocal("superfoo");
// fill some fake values
var ar:Array = [1, 2, 3, 4, 5]
var ar2:Array = ['a1', 'a2', 'a3', 'a4']
my_so.data.array1 = ar;
my_so.data.array2 = ar2;
my_so.data.notarray = 'I m not an array';
my_so.flush();
// browse the so and find arrays
var my_so2 = SharedObject.getLocal("superfoo");
for (var item:* in my_so2.data) {
if (my_so2.data[item] is Array) {
var a:Array = my_so2.data[item];
for(var i:uint = 0 ; i<a.length;i++ ) {
trace('my_so2.data[' + item + '][' + i + ']=' + a[i])
}
}
}
Ouput (it skips items that are not Arrays in so.data)
my_so2.data[array2][0]=a1
my_so2.data[array2][1]=a2
my_so2.data[array2][2]=a3
my_so2.data[array2][3]=a4
my_so2.data[array1][0]=1
my_so2.data[array1][1]=2
my_so2.data[array1][2]=3
my_so2.data[array1][3]=4
my_so2.data[array1][4]=5

Actionscript Child within parent within parent

I am trying to make a calculator where a user can select from a list of items. If a user clicks say "ITEM1", it should add the item to a "CONTAINER_MC". The problem i have is all my data is set inside an array containing names and prices like the code below.
var menuNames:Array = [
"Item1",
"Item2",
"Item3",
"Item4",
"item5",
"item6"
];
//price array
var menuPrices:Array = [
"0.99",
"1.99",
"2.99",
"5.99",
"6.99",
"10.99"
];
Now i have a sprite which creates a menu for each of these items by the use of a movie clip containing 2 input fields which i setup like the code below.
var menuSprite:Sprite = new Sprite();
var totalItems:Number = menuNames.length;
var item:menuItem; //new item field
var btn:add_btn;
for(var i = 0; i < totalItems; i++) {
item = new menuItem();
btn = new add_btn();
menuSprite.addChild(item);
item.addChild(btn);
item.x = 0;
item.y = i * 80;
btn.y = 45;
item.itemName.text = menuNames[i];
item.itemPrice.text = "$" + menuPrices[i];
}
addChild(menuSprite);
This all works fine so far, the problem is that i have a button inside my item and i need to add even listeners for these buttons, the problem is how to target these buttons. Since these buttons are added through the for loop they are not given instance names so notice how i targetted the input fields stored within the "item", i used itemName but how would i do it to the buttons stored inside item.
Thank you, really appreciate any help possible.
Something like this:
var menuSprite:Sprite = new Sprite();
var totalItems:Number = menuNames.length;
var item:menuItem; //new item field
var btn:add_btn;
for(var i = 0; i < totalItems; i++) {
item = new menuItem();
btn = new add_btn();
btn.addEventListener(MouseEvent.CLICK,clickHndlr);
menuSprite.addChild(item);
item.addChild(btn);
item.x = 0;
item.y = i * 80;
btn.y = 45;
item.itemName.text = menuNames[i];
item.itemPrice.text = "$" + menuPrices[i];
}
addChild(menuSprite);
public function clickHndlr(event:MouseEvent):void
{
((event.currentTarget as add_btn).parent as menuItem).itemName.text="Any of changes";
}
But also I'd like to change arrays to Dictionary instance, like this:
var menuData=new Dictionary();
//filling our Dictionary instead of weird arrays
for(var i:int=0;i<10;i++)
menuData["Item"+i]=Math.round(Math.random()*100);
var menuSprite:Sprite = new Sprite();
var item:menuItem; //new item field
var btn:add_btn;
for(var menuName:Object in menuData)
{
item = new menuItem();
btn = new add_btn();
btn.addEventListener(MouseEvent.CLICK,clickHndlr);
menuSprite.addChild(item);
item.addChild(btn);
item.x = 0;
item.y = i * 80;
btn.y = 45;
var menuPrice:int=menuData[menuName] as Number;
item.itemName.text = menuName as String;
item.itemPrice.text = "$" + menuPrice.toString();
}
addChild(menuSprite);
public function clickHndlr(event:MouseEvent):void
{
((event.currentTarget as add_btn).parent as menuItem).itemName.text="Any of changes";
}
And if to be very honest, I'll put away Flash, and prefer yo use Flex+Catalyst to create great code with great UI.
Ask more if you need more information.
Regards
Eugene

Closure problem? - passing current value of a variable

I'm trying to pass the current value of a variable when an a dynamically generated navigation 'node' is clicked. This needs to just be an integer, but it always results in the last node's value.. have tried some different methods to pass the value, a custom event listener, a setter, but I suspect it's a closure problem.. help would be appreciated ;-)
function callGrid():void {
for (var i:Number = 0; i < my_total; i++) {
var gridnode_url = my_grid[i].#gridnode;
var news_category= my_grid[i].#category;
var newstitle = my_grid[i].#newstitle;
var news_content = my_grid[i]..news_content;
var news_image = my_grid[i]..news_image;
var gridnode_loader = new Loader();
container_mc.addChild(gridnode_loader);
container_mc.mouseChildren = false;
gridnode_loader.load(new URLRequest(gridnode_url));
gridnode_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, gridLoaded);
gridnode_loader.name = i;
text_container_mc = new MovieClip();
text_container_mc.x = 0;
text_container_mc.mouseEnabled = false;
var textY = text_container_mc.y = (my_gridnode_height+18)*y_counter;
addChild(text_container_mc);
var tf:TextSplash=new TextSplash(newstitle,10,0,4 );
container_mc.addChild(tf);
tf.mouseEnabled = false;
tf.height = my_gridnode_height;
text_container_mc.addChild(tf);
var text_container_mc_tween = new Tween(text_container_mc, "alpha", Strong.easeIn, 0,1,0.1, true);
gridnode_loader.x = (my_gridnode_width+5) * x_counter;
gridnode_loader.y = (my_gridnode_height+15) * y_counter;
if (x_counter+1 < columns) {
x_counter++;
} else {
x_counter = 0;
y_counter++;
}
}
}
function gridLoaded(e:Event):void {
var i:uint;
var my_gridnode:Loader = Loader(e.target.loader);
container_mc.addChild(my_gridnode);
_xmlnewstarget = my_gridnode.name;
//||||||||||||||||||||||||||||||||||||||||
//when a particular grid node is clicked I need to send the current _xmlnewstarget value to the LoadNewsContent function...
//||||||||||||| ||||||||||||||||||||||||
my_tweens[Number(my_gridnode.name)]=new Tween(my_gridnode, "alpha", Strong.easeIn, 0,1,0.1, true);
my_gridnode.contentLoaderInfo.removeEventListener(Event.COMPLETE, gridLoaded);
my_gridnode.addEventListener(MouseEvent.CLICK, loadNewsContent);
}
function loadNewsContent(e:MouseEvent):void {
createNewsContainer();
getXMLNewsTarget();
news_category = my_grid[_xmlnewstarget].#category;
var tfnews_category:TextSplash=new TextSplash(news_category,20,16,32,false,false,0xffffff );
tfnews_category.mouseEnabled = false;
newstitle = my_grid[_xmlnewstarget].#newstitle;
var tftitle:TextSplash=new TextSplash(newstitle,20,70,24,false,false,0x333333 );
news_container_mc.addChild(tftitle);
tftitle.mouseEnabled = false;
news_content = my_grid[_xmlnewstarget]..news_content;
var tfnews_content:TextSplash=new TextSplash(news_content,20,110,20,true,true,0x333333,330);
news_container_mc.addChild(tfnews_content);
tfnews_content.mouseEnabled = false;
news_image = my_grid[_xmlnewstarget].#news_image;
loadNewsImage();
addChild(tfnews_category);
addChild(tftitle);
addChild(tfnews_content);
var news_container_mc_tween = new Tween(news_container_mc, "alpha", Strong.easeIn, 0,1,0.3, true);
news_container_mc_tween.addEventListener(Event.INIT, newsContentLoaded);
}
I'm not going to try to read your code (try to work on your formatting, even if it's just indenting), but I'll provide a simplified example:
for (var i = 0; i < my_total; i++) {
var closure = function() {
// use i here
}
}
As you say, when closure is called it will contain the last value of i (which in this case would be my_total). Do this instead:
for (var i = 0; i < my_total; i++) {
(function(i) {
var closure = function() {
// use i here
}
})(i);
}
This creates another function inside the loop which "captures" the current value of i so that your closure can refer to that value.
See also How does the (function() {})() construct work and why do people use it? for further similar examples.
Umm, as mentioned above, the code is a bit dense, but I think you might have a bit of type conversion problem between string and integers, is the "last value" always 0? try making these changes and let me know how you get on.
// replace this gridnode_loader.name = i;
gridnode_loader.name = i.toString();
// explictly type this as an int
_xmlnewstarget = parseInt(my_gridnode.name);
// replace this: my_tweens[Number(my_gridnode.name)] = new Tween(......
my_tweens[parseInt(my_gridnode.name)] = new Tween();
Oh and I think it goes without saying that you should massively refactor this code block once you've got it working.
Edit: after further study I think you need this
//replace this: my_gridnode.addEventListener(MouseEvent.CLICK, loadNewsContent);
var anonHandler:Function = function(e:MouseEvent):void
{
loadNewsContent(_xmlnewstarget);
};
my_gridnode.addEventListener(MouseEvent.CLICK, anonHandler);
Where your loadNewsContent has changed arguements from (e:MouseEvent) to (id:String)
Firstly, you do not need to call addChild for the same loader twice (once in callGrid) and then in (gridLoaded). Then you can try putting inside loadNewsContent: news_category = my_grid[int(e.target.name)].#category;instead of news_category = my_grid[_xmlnewstarget].#category; As _xmlnewstarget seems to be bigger scope, which is why it is getting updated every time a load operation completes.

Creating multiple TextInput fields in for loop

I need to loop through an array and for each element create a textfield. My problem is how to create a new identifier for each new TextInput
this is my code;
var count:Number = 0;
for (var i:String in columnsData)
{
var myTI:TextInput = new TextInput();
myTI.width = 70;
myTI.height = 25;
myTI.text = columnsData[i];
myTI.name = "myTI" + count;
addChild(myTI);
count++;
}
all this does however is overwrite the previously created TextInput field, any ideas?
Try this:
var count:uint = 0,
textInputs:Array /* of TextInputs */ = [];
for(var i:String in columnsData){
textInputs[count] = new TextInput();
// Customize textInput[count] instead of myTI
addChild(textInputs[count]);
count++;
}
Outside of this loop, you should be able to look inside the textInputs array for references to each of your new TextInputs. Note that, inside the loop, you probably want to change the x/y coordinates for each TextInput so they don't overlap.