overiding flex candlestick chart itemrenderer - actionscript-3

I am trying to override a candlestick chart item renderer but cannot issue base class rendering on top of my own
from the flex api help:
itemRenderer
Type: mx.core.IFactory CSS Inheritance: No
Language Version: ActionScript 3.0 Product Version: Flex 3 Runtime Versions: Flash9, AIR 1.1
A factory that represents the class the series will use to represent individual items on the chart. This class is instantiated once for each element in the chart. Classes used as an itemRenderer should implement the IFlexDisplayObject, ISimpleStyleClient, and IDataRenderer interfaces. The data property is assigned the chartItem that the skin instance renders.
as file declaration for custom renderer:
package { // Empty package.
import mx.charts.series.items.HLOCSeriesItem;
import mx.core.IDataRenderer;
import mx.core.IFlexDisplayObject;
import mx.styles.ISimpleStyleClient;
import flash.display.Graphics;
import mx.charts.chartClasses.HLOCSeriesBase;
import mx.charts.series.CandlestickSeries;
public class CycleColorRenderer extends HLOCSeriesBase
implements IFlexDisplayObject, ISimpleStyleClient, IDataRenderer {
private var colors:Array = [0xCCCC99,0x999933,0x999966];
private var _chartItem:HLOCSeriesItem;
public function CycleColorRenderer() {
super();
}
public function get data():Object {
return _chartItem;
}
public function set data(value:Object):void {
_chartItem = value as HLOCSeriesItem;
invalidateDisplayList();
}
override protected function
updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
/* var g:Graphics = graphics;
g.clear();
g.beginFill(colors[(_chartItem == null)? 0:0]);
g.drawRect(0, 0, unscaledWidth, unscaledHeight);
g.endFill();
*/
/*
if( _chartItem && _chartItem.index == 0) {
g.beginFill(0xFF0000); // Red line, you can select your own color
// Draw the line across the chart. This is actually a rectangle with height 1.
g.drawRect(-50,0,this.parent.width+50, 1);
g.endFill();
}
*/
}
} // Close class.
} // Close package.
mxml declaration:
<mx:CandlestickSeries
dataProvider="{TICKER}"
openField="open"
highField="high"
lowField="low"
closeField="close"
displayName="TICKER"
itemRenderer="CycleColorRenderer"
>
The chart is being rendered, but instead of default candle sticks theres void in the place of them, but I can retrieve bars properties and render myself - I would just like to issue base renderer from the base class and just draw on top of it. What am I missing?

Related

How to get column width inside AS3 DataGrid CellRenderer?

I have a DataGrid with one column showing picture icon(s). This is done by using a special CellRenderer. Is it possible to find column width inside the CellRenderer? this.width always returns a number that is obviously wrong (152), no matter what the actual column width is. I tried this on PC and on Android.
I need to know the column width to center the picture. It would be probably possible to pass the actual column width to the CellRenderer using a static variable, but I wonder if I'm overlooking something obvious.
import fl.controls.listClasses.CellRenderer;
import flash.geom.Point;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.utils.*;
import flash.events.*;
public class CustomImageCellRenderer extends CellRenderer
{
public function CustomImageCellRenderer()
{
var iconClass : Class = getDefinitionByName("icon") as Class;
var iconMC : MovieClip = new iconClass();
trace("width=" + width); // always returns 152
addChild(iconMC );
}
override protected function drawBackground():void
{
var skin : Object;
if (_listData.index % 2 == 0)
{
skin = CellRenderer_upSkin2;
} else {
skin = CellRenderer_upSkin;
}
setStyle("upSkin", skin);
setStyle("overSkin", skin);
setStyle("downSkin", skin);
setStyle("selectedOverSkin", skin);
setStyle("selectedDownSkin", skin);
setStyle("selectedUpSkin", skin);
super.drawBackground();
}
}
Use this.width in overridden drawBackground method:
override protected function drawBackground():void
{
super.drawBackground();
trace("width=" + this.width);
}
Usually you should do all layout stuff in the updateDisplayList - this is where you should get the correct dimensions:
override protected function updateDisplayList(unscaledwidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
icon.x = int((unscaledWidth - icon.width)/2);
}

An if statement isn't checking if a variable has increased in amount or not

I am programming in AS3 on flash develop. I am using a program called flashpunk that adds in multiple presets for classes that i can use to make it easier to program. I have an if statement that is supposed to add a new graphic when a variable equals 1. If the user presses one on their keyboard then that variable does increase by 1. But when the variable increases by 1 and the if statement is supposed to check if it is one it doesn't add a new graphic like it's supposed too. I do have the if statement and the variable in different classes and i am not sure if i can do that, here is the code. The if statement that doesn't work is the one that is supposed to add a new background1.
Chapter
package
{
import net.flashpunk.Entity;
import net.flashpunk.World;
import net.flashpunk.utils.Input;
import net.flashpunk.utils.Key;
public class Chapter extends World
{
public var mainmenu:MainMenu;
public var background1:Background1;
public function Chapter()
{
mainmenu = new MainMenu();
add(mainmenu);
background1 = new Background1();
if(mainmenu.YesNo == 1)
{
add(background1);
}
}
}
}
MainMenu
package
{
import flash.events.TimerEvent;
import flash.utils.Timer;
import net.flashpunk.Entity;
import net.flashpunk.graphics.Image;
import net.flashpunk.utils.Input;
import net.flashpunk.utils.Key;
import net.flashpunk.FP;
public class MainMenu extends Entity
{
[Embed(source = "net/MainScreen.png")]
private const SPRITE1:Class;
public var YesNo:int = 0
private var sprite1:Image = new Image(SPRITE1);
public function MainMenu()
{
graphic = sprite1;
sprite1.centerOrigin();
x = 200
y = 150
layer = 150
}
override public function update():void
{
if (Input.pressed(Key.DIGIT_1))
{
YesNo = YesNo + 1;
}
trace(YesNo);
}
}
}
The problem is that your code is in a World class constructor. Flashpunk's idea of game objects is that Entities are added to Worlds. Once added, World runs update() method every frame in which it also runs every Entity's update() as well. Yours if statement in a constructor will always yield false as update wasn't yet executed.
If I understand correctly you want to add background entity after user will press 1. You can do it like this:
// in MainMenu class
override public function update():void
{
if (Input.pressed(Key.DIGIT_1))
{
world.add(new Background1());
}
}
If you want to hold reference to this entity you could:
override public function update():void
{
if (Input.pressed(Key.DIGIT_1))
{
Chapter(world).background1 = new Background1(); // note the casting of World to Chapter
world.add(Chapter(world).background1);
}
}

Access of undefined property issues in AS3

I am having a bit of trouble with some AS3. First time using this language and have more experience with web development then OOP so am getting a bit confused.
I am trying to make it so that when someone clicks a 'powerbutton' which is a "movieclip" symbol within flash then another symbol should then become visible. This is all being done within the Kitchen class.
The code for the main class is which i got from a youtube tutorial video i followed;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.events.Event;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
public function DragFood() {
myKitchen = new Kitchen;
originalPosition = new Point (x, y);
buttonMode = true;
addEventListener (MouseEvent.MOUSE_DOWN, down);
}
protected function down (event:MouseEvent):void
{
parent.addChild(this);
startDrag();
stage.addEventListener (MouseEvent.MOUSE_UP, stageUp);
}
protected function stageUp (event:MouseEvent):void
{
stage.removeEventListener (MouseEvent.MOUSE_UP, stageUp);
stopDrag();
if (dropTarget)
{
if(dropTarget.parent.name == "bowl")
{
trace("The " + this.name + " is in the bowl");
this.visible = false;
} else {
returnToOriginalPosition();
}
} else {
returnToOriginalPosition();
}
}
protected function returnToOriginalPosition():void
{
x = originalPosition.x;
y = originalPosition.y;
}
}
}
Within it i call the other class;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
The code for the kitchen class is;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
public class Kitchen extends MovieClip
{
// This is a function. This particular function has the same name as our class and therefore will be executed first
public function Kitchen()
{
// This is a "call" to another function that is defined later in the program.
init();
trace("Hello world");
}
public function init():void
{
// If we want an object (on the screen or otherwise) to be notified about an event we must add a listener for that event to that object.
// We also need to specify what happens everytime the event we are listening for happens.
PowerButton.addEventListener(MouseEvent.CLICK, handleButtonClicks);
}
//This function is called when the oven on button recieves a click.
public function handleButtonClicks(event:MouseEvent):void
{
OvenOn.visible = true;
trace("the oven is being switched on");
}
}
}
The issue i keep getting is that OvenOn and PowerButton are giving me a undefined access issue and im not sure how to fix it. I have found posts on similar subjects like - Access of Undefined property? Actionscript 3
but im not quite sure how to apply it to my issue if anyone could offer any help that would be great.
When you're programming on the timeline, code is referencing the local namespace, and objects you make there (movieclips, textfields, etc.) are automatically instantiated in that namespace so that you can simply call OvenOn.visible = true. However, for each class, their local namespace is whatever is inside the class, so unless you actually created a property on your class called OvenOn, it will most definitely give you Access of Undefined Property errors.
Think of each class as its own island. For them to touch eachother, they need some sort of connection. That connection can be made once the parent instantiates the class in its own namespace. For example...
var foo:String = "Hello!";
var bar:MyClass = new MyClass();
// At this point, whatever code runs inside of MyClass has no concept of foo, or how to access it.
addChild(bar);
// Now that we've added it to the stage, the bar has some properties that have automatically been populated such as "root", "parent", or "stage".
foo.someProperty = "World";
// Since this namespace has a variable pointing to the instance, we can change properties on that class.
Now that we've instantiated MyClass on the stage, we can reference parent properties the class didn't know about. Mind you, this is not necessarily best practice.
package
public class MyClass extends MovieClip {
var someProperty:String = "cheese";
public function MyClass() {
trace(parent.foo) // this will fail
addEventListener(Event.ADDED_TO_STAGE, test);
}
public function test(e:Event):void {
trace(this["parent"].foo); // this will succeed
}
}
}
If you absolutely must change something that is not part of your Kitchen class, pass either the parent of OvenOn or that object specifically as a property of Kitchen. You could do this a couple ways.
with the Constructor...
var something:*;
public function MyClass(someObject:*) {
something = someObject;
}
public function test():void {
something.visible = false;
}
...or by Assigning the Property...
var bar:MyClass = new MyClass();
bar.something = OvenOn;
bar.test(); // will turn off the OvenOn now that 'something' is pointing to it.

Adding eventlisteners in main document class for external classes

I have a small project I'm trying to help learn as3. It is a variation from the book Foundation Game Design with Actionscript 3.0. I am using an fla only to have a document class. All art is loaded within the as files. In the book, he just put all the code in the document class, I followed along and it worked as expected. I am trying to break out the code into separate classes to get a handle on OOP. One class makes a background - Background.as, one makes a character - Character.as, and one makes a button, which I instantiate 6 times for 6 different buttons - GameButton.as. And of course there is GameWorld.as which is the document class. Everything loads and shows up as expected. However when I try and add an eventListener for the buttons, I don't get any response. I have tried putting the eventListener in the GameButton.as and also tried it in the GameWorld.as neither of which has worked. Also I pass a reference to the stage when instantiating the various classes, because when I tried to addChild in the GameWorld.as, nothing would show up. I searched the site and found something similar, but it didn't seem to help. Thank you in advance for any advice you my have. Here is the code:
GameWorld.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.DisplayObject
import flash.events.MouseEvent;
import GameButton;
import Character;
import Background;
[SWR(width = "550", height = "400", backgroundColor = "#FFFFFF", frameRate = "60")]
public class GameWorld extends Sprite
{
//public variables
//Background
public var gameBackground:Background;
//Character
public var catCharacter:Character;
//Buttons
public var upButton:GameButton;
public var downButton:GameButton;
public var growButton:GameButton;
public var shrinkButton:GameButton;
public var vanishButton:GameButton;
public var spinButton:GameButton;
public function GameWorld ()
{
//Add the background to the stage
gameBackground = new Background("../images/background.png", stage);
//Add the character(s) to the stage
catCharacter = new Character("../images/character.png", stage);
//Set initial character position
catCharacter.CharacterPos(225, 150);
//Add the buttons to the stage
upButton = new GameButton("../images/up.png", stage, 25, 25);
downButton = new GameButton("../images/down.png", stage, 25, 85);
growButton = new GameButton("../images/grow.png", stage, 25, 145);
shrinkButton = new GameButton("../images/shrink.png", stage, 425, 25);
vanishButton = new GameButton("../images/vanish.png", stage, 425, 85);
spinButton = new GameButton("../images/spin.png", stage, 425, 145);
//Button event handlers
upButton.addEventListener(MouseEvent.CLICK, upButtonHandler);
}
public function upButtonHandler(event:MouseEvent)
{
trace("You clicked the up button!");
catCharacter.CharacterMove(15);
}
}
}
GameButton.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.MouseEvent;
public class GameButton extends Sprite
{
//public variables
public var stageRef:Stage;
public var urlRequest:URLRequest;
public var gameButtonLoader:Loader;
public var gameButtonSprite:Sprite;
//Constructor
public function GameButton (urlRequest:String, stageRef:Stage, xPos:Number, yPos:Number)
{
this.stageRef = stageRef
this.urlRequest = new URLRequest();
gameButtonLoader = new Loader();
gameButtonSprite = new Sprite();
this.urlRequest.url = urlRequest;
gameButtonLoader.load(this.urlRequest);
gameButtonSprite.addChild(gameButtonLoader);
this.stageRef.addChild(gameButtonSprite);
gameButtonSprite.buttonMode = true;
gameButtonSprite.x = xPos;
gameButtonSprite.y = yPos;
}
}
}
Character.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
public class Character
{
//private variables
private var stageRef:Stage;
private var urlRequest:URLRequest;
private var characterLoader:Loader;
private var characterSprite:Sprite;
//public variables
public var character_x_pos:Number;
public var character_y_pos:Number;
//Constructor
public function Character (urlRequest:String, stageRef:Stage)
{
this.stageRef = stageRef;
this.urlRequest = new URLRequest();
characterLoader = new Loader();
characterSprite = new Sprite();
this.urlRequest.url = urlRequest;
characterLoader.load (this.urlRequest);
characterSprite.addChild (characterLoader);
this.stageRef.addChild (characterSprite);
characterSprite.mouseEnabled = false;
}
//Set the position of the character
public function CharacterPos(xPos:Number, yPos:Number):void
{
characterSprite.x = xPos;
characterSprite.y = yPos;
}
//Move the position of the character
public function CharacterMove( yPos:Number):void
{
characterSprite.y -= yPos;
}
}
}
Background.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
public class Background
{
//Private variables
private var stageRef:Stage;
private var urlRequest:URLRequest;
private var backgroundLoader:Loader;
private var backgroundSprite:Sprite;
//Constructor
public function Background (urlRequest:String, stageRef:Stage)
{
this.stageRef = stageRef;
this.urlRequest = new URLRequest();
backgroundLoader = new Loader();
backgroundSprite = new Sprite();
this.urlRequest.url = urlRequest;
backgroundLoader.load (this.urlRequest);
backgroundSprite.addChild (backgroundLoader);
this.stageRef.addChild (backgroundSprite);
backgroundSprite.mouseEnabled = false;
}
}
}
All art is loaded within the as files.
This is not an approach I recommend. There's a reason God gave us the Flash IDE--and it's not to write code! Any time you're spending on layout and viduals in code is just wasted, unless you have an actual requirement to change the visuals at runtime. The fact that your paths are all hard-coded suggests that you don't have that requirement.
So let's step back and imagine that you have a Symbol that contains 6 Symbols that you've created as just Flash buttons (when you select Button as the Symbol type). These will be SimpleButtons, but in the Class below we're just going to type them as DisplayObject. The Class doesn't care what they are, but using Simplebutton gives them up, over, down and hit states that require no code.
Note that the below assumes you have "automatically declare stage instances" off, which is IMO the best way to do things.
package view {
public class NavBar extends Sprite {
//because you put these on stage in the Symbol, they will be available in the constructor
public var upButton:DisplayObject;
public var downButton:DisplayObject;
public var growButton:DisplayObject;
public var shrinkButton:DisplayObject;
public var rotateButton:DisplayObject;
public var vanishButton:DisplayObject;
//makes it easier to do the same setup on all buttons
protected var allButtons:Vector.<DisplayObject> = <DisplayObject>([upButton, downButton, growButton, shrinkButton, rotateButton, vanishButton]);
public function NavBar() {
super();
for each (var btn:DisplayObject in allButtons) {
btn.buttonMode = true;
btn.mouseChildren = false;
btn.addEventListener(MouseEvent.CLICK, onButtonClick);
}
}
protected function onButtonClick(e:MouseEvent):void {
switch (e.target) {
case upButton:
dispatchEvent(new CharacterEvent(CharacterEvent.UP));
break;
case downButton:
dispatchEvent(new CharacterEvent(CharacterEvent.DOWN));
break;
case growButton:
dispatchEvent(new CharacterEvent(CharacterEvent.GROW));
break;
case shrinkButton:
dispatchEvent(new CharacterEvent(CharacterEvent.SHRINK));
break;
case rotateButton:
dispatchEvent(new CharacterEvent(CharacterEvent.ROTATE));
break;
case vanishButton:
dispatchEvent(new CharacterEvent(CharacterEvent.VANISH));
break;
default:
break;
}
}
}
}
Note that there's zero layout code. This code is dependent on a custom Event Class. I'm going to write that Event Class so that it always bubbles. That way, it can be dispatched anywhere on the display list and received at the top level:
package control {
class CharacterEvent extends Event {
public static var UP:String = 'characterUp';
public static var DOWN:String = 'characterDown';
public static var GROW:String = 'characterGrow';
public static var SHRINK:String = 'characterShrink';
public static var ROTATE:String = 'characterRotate';
public static var VANISH:String = 'characterVanish';
public function CharacterEvent(type:String) {
super(type, true, true);//always bubbles
}
public function clone():Event {
return new CharacterEvent(type);
}
}
}
Now, if you want to manually handle instantiation of the Symbol that has view.NavBar as its base class, it will look like this:
package {
public var navBar:NavBar;
class GameWorld {
public function GameWorld() {
try {
var navClass:Class = getDefinitionByName('NavBarSymbol') as Class;
} catch (e:Error) {
trace('You need to have a Library symbol called NavBarSymbol');
}
if (navClass) {
navBar = new navClass() as NavBar;
//unnecessary layout code here
//Note that this is NOT the responsibility of the child Class!
addChild(navBar);
}
//instantiate character
...
//by listening to the whole Document, you can add other things that
//dispatch Character events on the display list, like a keyboard listener
addEventListener(CharacterEvent.UP, moveCharacterUp);
//listeners for the rest of the character events...
}
public function moveCharacterUp(e:CharacterEvent):void {
//character move logic
}
//other handlers
}
}
Personally, I'd just add the navBar to the stage, and then there's no need to manage it at all (not even reference it with a variable), simply add the event listeners for the various character events.
The root of your problem doesn't seem to be the character code. However, I'm going to give you a few "best practice" pointers about it.
The convention in AS3 is for Class members (properties and methods) to be camel case starting with a lower case letter. So, characterPos() and characterMove().
Your Class already contains character in the name, so really these should just be pos() and move() (though there's no need now to shorten position()).
The only thing your child Classes are doing with their references to the parent are adding themselves. They don't need and shouldn't have a reference to the parent for this purpose. It is the parent's responsibility to add the Children (or the responsibility of the Flash Player if you use the stage).
That said, you could give your Character a reference to the parent Class typed as IEventDispatcher and allow the Character to listen to this channel. This concept is called an event bus.
Note that the reason that so many people do what you're doing is that Adobe failed to document how to properly use OOP with the timeline. Unfortunately, by the time a few of us started documenting that around late 2009/early 2010, the damage was done and everyone assumed that if you wanted to write good code you had to pretend the timeline and stage didn't exist.
I know I've covered a lot of ground, and probably most of what I said directly contradicts what you thought you knew, so please don't hesitate to ask any questions you might have.

Unable to have Flash Component (SWC) access the library in live preview

I am building a set of Flash components with the ability to replace the skin of the component with another one in the library.
Currently, I am able to access the library after running the application, but not during live preview and I'd like to know if it is possible for the component to access the library while running in live preview mode (the mode where you can drag the component around the stage and change its properties in the Component Parameters window)
Here is a simplified code that just looks to see if there is a symbol of the name specified and than instantiates it and adds it as a child.
package
{
import fl.core.UIComponent;
import flash.display.MovieClip;
import flash.system.ApplicationDomain;
/**
* ...
* #author Roy Lazarovich
*/
public class CompTest extends UIComponent
{
private var customfile :String;
public function CompTest()
{
}
override protected function configUI():void
{
}
override protected function draw():void
{
super.draw();
}
private function setCustomFile():void
{
if (ApplicationDomain.currentDomain.hasDefinition(customfile))
{
var c:Class = Class(ApplicationDomain.currentDomain.getDefinition(customfile));
var mc:MovieClip = new c();
addChild(mc);
}
}
[Inspectable(name = "_Custom File", defaultValue = "")]
public function set _customfile(value:String):void
{
customfile = value;
setCustomFile();
drawNow();
}
}
}
Thanks!
I'm not entirely sure what you have already tried to fix this situation. But hopefully this might help.
Right click on the MovieClip in your library, select Linkage and give it a class name, ie. MyThing.
In your code,
newMyThing = new MyThing();
this.addChild(newMyThing);
trace("tada!");
Hope that helps or gets you closer to a solution.
This works for me in LivePreview, as long as I apply it in configUI, and not draw:
public class EditableBitmap extends UIComponent
{
protected var placeholder:String = "None";
protected var bitmap:Bitmap;
protected var scale:Number = 1;
[Inspectable(name = "Placeholder", type = String, defaultValue="None")]
public function set Placeholder($value:String):void
{
placeholder = $value;
configUI();
}
public function get Placeholder():String { return placeholder; }
public function EditableBitmap()
{
//Console.Debug("NEW EditableBitmap");
super();
}
override protected function configUI():void
{
//Console.Debug("EditableBitmap configUI: " + width);
if (!isNaN(width))
{
wDim = width;
hDim = height;
graphics.clear();
graphics.beginFill(0x000000, 0.1);
graphics.drawRect(0, 0, wDim, hDim);
}
if (placeholder != "None" && placeholder != "")
{
var asset:Class = getDefinitionByName(placeholder) as Class;
var data:BitmapData = new asset() as BitmapData;
bitmap = new Bitmap(data);
}
super.configUI();
}
override protected function draw():void
{
if (bitmap)
{
addChild(bitmap);
bitmap.x = off_x * scale;
bitmap.y = off_y * scale;
bitmap.scaleX = bitmap.scaleY = scale;
}
}
}
NOTE: When I'm working on the FLA where I am editing the component, the bitmap is only displayed from the library inconsistenty. Sometimes it works, sometimes it doesn't. But when I export the SWC and then import the component to another movie, it works every time, in LivePreview as well as at runtime.
UPDATE
It seems this doesn't work in CS6 unless the symbol is already embedded in the component .SWC I wanted to see if I could trick it, by embedding one image in the SWC and then replacing it with another of the same name in the destination file. This didn't work, but it did point me to how you can do this:
So, it's a bit laborious, but you could work around this by:
1) Creating a dummy asset for each property in the component SWC.
2) Overriding this using a custom class in the file where you deploy the component
... all of which may be more trouble than it's worth, but which should provide a solution to the problem.