LoaderMax: setting array as a container (ImageLoader) - arrays

So, I have a LoaderMax instance loading images from various URLs. I want to add all loaded images to an array.
Here's my code:
var photosArray:Array = new Array(5);
var imageLoadingQueue:LoaderMax = new LoaderMax({name:"mainQueue", onComplete:completeHandler});
for (var g:uint=0; g<5; g++)
{
imageLoadingQueue.append(new ImageLoader("/img" + g + ".jpg", {name:"photo", container:photosArray[g], noCache:false, smoothing:true, width:126, height:126, scaleMode:"proportionalOutside"}));
}
imageLoadingQueue.load();
private function completeHandler(e:LoaderEvent):void
{
trace("finished loading pictures!");
//the next two lines will return an error (saying that photosArray[1] is null)
stage.addChild(photosArray[1]);
photosArray[1].x = 250;
}
A few problems:
If I set the container of the image being loaded to the Array, it won't work. I'm not being able to access the image inside the array because it says it's null.
If I set the container of the image being loaded to "this" (using the container property when appending a new ImageLoader) and, on the completeHandler, set my array equal to event.target.content, it kinda works (but it's not the ideal). The problem is that, by doing so, the images are appearing on the stage as they are loaded, and I do no want them to do so.
Any help would be heavily appreciated.
Thanks!!

David is correct, but I also wanted to mention that the LoaderMax's "content" is actually an array of all of its children's content, so you could just use that for simplicity. Keep in mind that ImageLoaders automatically create a Sprite (technically called a "ContentDisplay") to drop the image into so you probably don't need to create ANOTHER Sprite (a container for the container).
var photos:Array = imageLoadingQueue.content;
stage.addChild(photos[1]);
The other nice thing is that it creates the ContentDisplay Sprites immediately, even before any content is loaded into them, so you can place them and size them however you want while (or before or after) loading occurs.

The container needs to be a DisplayObjectContainer. ImageLoader will try to add the image to the container using addChild(), so obviously this won't work with an empty array. Create a new Sprite for each image and add it into the array first:
for (var g:uint=0; g<5; g++)
{
photosArray[g] = new Sprite();
imageLoadingQueue.append(new ImageLoader("/img" + g + ".jpg", {name:"photo", container:photosArray[g], noCache:false, smoothing:true, width:126, height:126, scaleMode:"proportionalOutside"}));
}

Related

How can I modify an XMP meta of a file?

I'm interested in seeing if I can modify some XMP within an image file. I'm using the following code:
var items = MetadataExtractor.ImageMetadataReader.ReadMetadata(_filename);
foreach (var item in items)
{
if(item.Name == "XMP")
{
var y = new XmpCore.Impl.XmpMeta();
var xmp = item as MetadataExtractor.Formats.Xmp.XmpDirectory;
foreach(var xd in xmp.XmpMeta.Properties)
{
if(xd.Path == "drone-dji:AbsoluteAltitude")
{
var alt = Convert.ToDecimal(xd.Value.Substring(1,xd.Value.Length-1));
alt -= 100;
xmp.XmpMeta.SetProperty(xd.Namespace, xd.Path, alt.ToString());
}
}
xmp.SetXmpMeta(xmp.XmpMeta);
}
}
I know I'm missing something breathtakingly obvious but I don't know this library well enough to figure it out.
No exceptions come up but when I open up the file the XMP field is still the same. When I iterate thru the xmp properties after I set the property it does reflect correctly but when I end the program the file stays the same. I'm sure there's something to do with writing back to the image path but I have no idea where in this library I do that. Any help would be greatly appreciated.
MetadataExtractor doesn't support modifying files. You can update the data structure, as you show, but there's no way to write those changes back to your original file.

Synchronously play videos from arrays using actionscript 3

I am developing an AIR application using Actionscript 3.0. The application loads two native windows on two separate monitors. Monitor 1 will play a video, and monitor 2 will synchronously play an overlayed version of the same video (i.e. infrared). Presently, I am hung up with figuring out the best way to load the videos. I'm thinking about using arrays, but am wondering, if I do, how can I link arrays so to link a primary scene to its secondary overlay videos.
Here is my code so far. The first part of it creates the 2 native full-screen windows, and then you'll see where I started coding the arrays at the bottom:
package
{
import flash.display.NativeWindow;
import flash.display.NativeWindowInitOptions;
import flash.display.NativeWindowSystemChrome;
import flash.display.Screen;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageDisplayState;
import flash.display.StageScaleMode;
public class InTheAirNet_MultiviewPlayer extends Sprite {
public var secondWindow:NativeWindow;
public function InTheAirNet_MultiviewPlayer() {
// Ouput screen sizes and positions (for debugging)
for each (var s:Screen in Screen.screens) trace(s.bounds);
// Make primary (default) window's stage go fullscreen
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
stage.color = 0xC02A2A; // red
// Create fullscreen window on second monitor (check if available first)
if (Screen.screens[1]) {
// Second window
var nwio:NativeWindowInitOptions = new NativeWindowInitOptions();
nwio.systemChrome = NativeWindowSystemChrome.NONE;
secondWindow = new NativeWindow(nwio);
secondWindow.bounds = (Screen.screens[1] as Screen).bounds;
secondWindow.activate();
// Second window's stage
secondWindow.stage.align = StageAlign.TOP_LEFT;
secondWindow.stage.scaleMode = StageScaleMode.NO_SCALE;
secondWindow.stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
secondWindow.stage.color = 0x387D19; // green
}
//Create array of PRIMARY scenes
var primary:Array = ["scene1.f4v", "scene2.f4v"];
//Create array of SECONDARY scenes for scene1
var secondary1:Array = ["scene1A.f4v", "scene1B.f4v"];
//Create array of SECONDARY scenes for scene2
var secondary2:Array = ["scene2A.f4v", "scene2B.f4v"];
}
}
}
EDIT: Users will cycle through overlays using LEFT and RIGHT on the keyboard, and will cycle through the scenes using UP and DOWN.
Use a generic Object for each video, store each in an array, and then store the secondary videos in an array within each object:
var videos:Array = [
{
primary:'video1.mp4',
secondary:[
'overlay101.mp4',
'overlay102.mp4'
]
},
{
primary:'video2.mp4',
secondary:[
'overlay201.mp4',
'overlay202.mp4'
]
}
{
primary:'video3.mp4',
secondary:[
'overlay301.mp4',
'overlay302.mp4'
]
}
]
Then when you to play a video, you can loop through the videos array. Each object has a primary video and its associated secondary videos. You could take it a step further, as well, and use the object to store metadata or store more Objects within the secondary array, rather than strings.
EDIT: Quick response to the first comment
In Object-Oriented Programming (OOP) languages, everything is an object. Every single class, every single function, every single loop, every single variable is an object. Classes generally extend a base class, which is called Object in AS3.
The Object is the most basic, most primitive type of object available — it is simply a list of name:value pairs, sometimes referred to as a dictionary. So you can do the following:
var obj:Object = {hello:'world'};
trace(obj.hello); // output 'world'
trace(obj['hello']); // output 'world'
trace(obj.hasOwnProperty('hello')); //output true (obj has a property named 'hello')
What I did was create one of these objects for each video and then save them to an array. So say you wanted to trace out primary and find out how many videos were in secondary, you would do this:
for (var i:int = 0; i < videos.length; i++) {
var obj:Object = videos[i];
trace('Primary: ' + obj.primary); // for video 1, output 'video1.mp4'
trace('Secondary Length: ' + obj.secondary.length); // for video1, output 2
}
That should show you how to access the values. An dictionary/Object is the correct way to associate data and the structure I supplied is very simple, but exactly what you need.
What we're talking about is the most basic fundamentals of OOP programming (which is what AS3 is) and using dot-syntax, used by many languages (everything from AS3 to JS to Java to C++ to Python) as a way of accessing objects stored within other objects. You really need to read up on the basics of OOP before moving forward. You seem to be missing the fundamentals, which is key to writing any application.
I can't perfectly understand what you're trying to do, but have you thought about trying a for each loop? It would look something like...
prim1();
function prim1():void
{
for each (var vid:Video in primary)
{
//code to play the primary video here
}
for each (var vid:Video in secondary1)
{
//code to play the secondary video here
}
}
Sorry if it's not what you wanted, but what I understood from the question is that you're trying to play the both primary and secondary videos at the same time so that they're in synch. Good luck with your program ^^

Dynamically add forex data points to Shield UI Chart

I need is to dynamically add the points I’ve received from a forex provider to s Shield UI Chart. According to the documentation, there isn’t the possibility for dynamically adding of points At least there is no such method, something like: AddPoint or similar.
How can I still achieve a web page using Shield UI Chart, which to constantly show a couple of exchange rates?
You are right, that there is no addPoints method of the Shield UI Chart. However we can add the incoming data values to an array instead. You might find useful following code:
We need some arrays- as many as we need to show.
var EURUSD = new Array();
var USDCAD = new Array();
var GBPUSD = new Array();
In the body of the function, that will actually display the data we will have the following code:
EURUSD[EURUSD.length] = parseFloat(data.ticks.EURUSD);
USDCAD[USDCAD.length] = parseFloat(data.ticks.USDCAD);
GBPUSD[GBPUSD.length] = parseFloat(data.ticks.GBPUSD);
it will actually put the new data to the designated arrays. You can note, that each time data is received, it has been added to the last index of each array:
EURUSD.length
Since we don’t want our arrays to grow too large, it is good to specify how many points we need to keep. Once that limit is reached, we remove the oldest point:
if (EURUSD.length > 50)
EURUSD = EURUSD.splice(1, 49);
if (USDCAD.length > 50)
USDCAD = USDCAD.splice(1, 49);
if (GBPUSD.length > 50)
GBPUSD = GBPUSD.splice(1, 49);
At the end we need to recreate the chart, referencing the appropriate container:
var containter = $("#EURUSDChart").swidget();
containter.destroy();
and than create the chart again.

flex 3: Can anybody help me optimize this array -> arrayCollection function?

I'm using a parent to pass a multi-dimensional array to a child. Structure of the array, named projectPositions is as follows (with example data):
projectPositions[0][0] = 1;
projectPositions[0][1] = 5;
projectPositions[0][2] = '1AD';
projectPositions[0][3] = 'User name';
I need to take this inherited array and turn it into an arrayCollection so that I can use it as a dataProvider. Currently, my init function (which runs onCreationComplete) has this code in it to handle this task of array -> arrayCollection:
for (var i:int = 0; i < projectPositions.length; i++)
{
tempObject = new Object;
tempObject.startOffset = projectPositions[i][0];
tempObject.numDays = projectPositions[i][1];
tempObject.role = projectPositions[i][2];
tempObject.student = projectPositions[i][3];
positionsAC.addItemAt(tempObject, positionsAC.length);
}
Then, during a repeater, I use positionsAC as the dataprovider and reference the items in the following way:
<mx:Repeater id="indPositions" dataProvider="{positionsAC}" startingIndex="0" count="{projectPositions.length}">
<components:block id="thisBlock" offSet="{indPositions.currentItem.startOffset}" numDays="{indPositions.currentItem.numDays}" position="{indPositions.currentItem.role}" sName="{indPositions.currentItem.student}" />
</mx:Repeater>
This all works fine and returns the desired effect, but the load time of this application is around 10 seconds. I'm 99% sure that the load time is caused by the array -> arrayCollection for loop. Is there an easier way to achieve the desired effect without having to wait so long for the page to load?
The issue your having loading items could be because you are using a repeater instead of a list class.
With a repeater, there will be a block created in memory, and drawn on the screen. So, if you have 100 items in your array, then 100 blocks will be created. this could slow down both initial creation and the overall app.
A list based class focuses on a technique called renderer recycling; which means only the displayed elements are created and rendered on the screen. So, depending on settings, you'd usually have 7-10 'block' instances on the screen, no matter how many items you have in your array.
change
positionsAC.addItemAt(tempObject, positionsAC.length);
to
positionsAC.addItem(tempObject);
addItemAt is causing a reindex of the collection which can greatly slow down the collection.
[EDIT]
Put this trace statement before and after the loop
take the output and subtract one from the other and that will show how many milliseconds the loop has run.
var date:Date = new Date( );
trace( date.getTime())

WPF - is there a way to remove specific child from Canvas.Children?

I am working on a charting control where I am plotting the "analysis range," which is just two vertical lines on the chart. A problem arises when I want to change the analysis range, because I don't know how to remove only the two analysis range lines, so I end up clearing the chart and plotting the actual data values and whatnot again. Is there a way to tag these UI elements (i.e. analysis range is a gridline UI element) so that I can remove them specifically? I suppose I could save the "index" of the UI element somewhere and delete these, but I am wondering if there is a cleaner way of doing this. Thanks a lot.
All UIElements have a UID which is a string. You could set the UID of the range lines to something predictable. Keep in Mind that UID must be unique. Then when you need to remove only the gridlines, you iterate through the Children collection gathering a list of the UI elements that need to be removed, then remove them.
Something like this:
Canvas c = new Canvas();
c.Children.Add( new UIElement() { Uid = "Line1" } );
c.Children.Add( new UIElement() { Uid = "Line2" } );
c.Children.Add( new UIElement() { Uid = "Line3" } );
c.Children.Add( new UIElement() { Uid = "Text1" } ); //This is added as a sample
List<UIElement> itemstoremove = new List<UIElement>();
foreach (UIElement ui in c.Children)
{
if (ui.Uid.StartsWith("Line"))
{
itemstoremove.Add(ui);
}
}
foreach (UIElement ui in itemstoremove)
{
c.Children.Remove(ui);
}
That should work. A quick test of this code in debug shows the Children count at 1, with only the UIElement with Uid of Text1 present in the list.
When you add the two lines to the Canvas, can't you hold a reference to the two lines. That way, when you need to redraw them, just do a Canvas.Children.Remove(line1) and Canvas.Children.Remove(line2). Then update your references for the lines and re-add them to the Canvas. You could even just update the X and Y values of the lines themselves rather than removing and re-adding them. This way, the Chart would just move the lines.
But, basically the key is to maintain a reference to the lines after adding them to the Canvas.

Resources