The Power of prototyping

Unfortunately a lot of people in our industry underestimate the power of prototyping – if you want a good example just take a look at the death star; brilliant in concept but what about that thermal exhaust port – a classic interaction design flaw and probably based on a conversation along the lines of “well, they’ll never spot that, especially if we don’t bring any attention to it, like popping lots of extra guns around it”. Famous last words.
If only they had built a prototype and performed some basic x-wing fighter user testing beforehand.
But, in all seriousness, why on Alderaan do we bother to prototype? It costs money, takes valuable time away from project delivery and ultimately will probably just get trashed at the end.
Let’s first look at a new system going into play without a prototype; we have our scamps, designs, entity relationship diagrams, functional and technical specifications, schemas, user flows and a whole load of other documentation depending on which methodology we are using – good golly, it’s a vast library of documentation, surely that has to be enough ? And the answer in many cases, like fairly static web sites, would be a yes. Where this model falls down is on interaction, and any system that relies on human computer interaction to complete complex processes needs a human to test that interaction.
Prototyping provides us with many insights for any project, by collating our thoughts and processes into a solution structure we suddenly experience clarity in the flow of the design as well as discovery of the flaws and points of pain in the various journeys that will be experienced by using it. We start to see where questions will arise and this allows us to address any stumbling blocks within the context of our flow.
One example of this was with a project I joined where they were building an ecommerce process flow and about to go into production and I asked the lead developer what would happen if a visitor hit the back button on their browser because they were experiencing a fairly common hesitation dilemma prior to purchase. The answer should have been along the lines that the system would maintain state, bring the visitor into the CRM flow and try to address the reason for the hesitation with access to peer reviews and FAQ’s. The answer I actually got, after a swift huddle of technical brilliance, was that system would break and probably end up with a 500 error state due to their ecommerce implementation. My point here is that by never investing in actual human testing, they were blindly following a process chart without taking into account the core humanity of the end user.
We should never lose focus of the fact that the end solution of your project is not for your personal use, it’s not being driven by the business and their goals, even though they exist and must be followed. At the end of the day there will be a real human being whose tech saviness may vary from jedi master all the way down to a clone asking us how to use the mouse (and yes, I have seen that one before in research. Several times) As a consequence of this, the sooner we put some real crash test dummies into the driving seat we will not be able to understand how the solution drives. (Or indeed if it will crash and burn)
As for the cost of doing this research – yes, of course you can hire specialist consultancies to do it all for you; develop the personas, recruit your victims, write the scripts, conduct the interviews and pay off the “volunteers”, usually at around 20K a pop for a really fancy report with lots of pretty graphs and videos. This has been known to make more than the occasional client gulp and apparently lose much of the blood supply to their head. As an alternative, why not take your prototype down to the local Costa and buy a few free cappuccinos and go pure guerrilla UX, it’s not as fancy as doing it full on but you will still end up with invaluable research findings. Also, it doesn’t cost the planetoid to create your own UX testing centre, all you really need is a room, a camera, someone vaguely empathic and good at interviewing and a few bits of screen capture software.
Let’s look briefly at the flipside here and imagine the cost of taking a project through to development without prototyping and suddenly realising that the model doesn’t work and is essentially unusable. Your first indication of this will probably be the marketing department screaming down one end of the phone about conversion and retention numbers heading for the deepest darkest basement, and of course the fix is probably months away at that point. This scenario is usually frightening enough that pointing out the reality of not going ahead with user testing on prototypes as a risk exercise can quite often provide the clarity and will needed to open up the purse strings a bit.
If you have been fortunate enough to be able to watch user research testing first hand through one of those cool one way mirrors (yes, we do pull faces at them) then you will understand how powerful this method of research can be, provided you have enough of a sample and that your sample is representative of your target personas. It is quite an astonishing experience watching actual visitors stumbling over your brilliantly intuitive design and navigation, throwing their hands in the air when they come to a complete standstill in your fluid data flow and completely missing the emphatic calls to action you have placed with such loving care and diligence.
If you have an opportunity to do so, I would highly recommend visiting these sessions for all designers and techies at least once in order to see real visitors in action. Not only is it a complete education as to how people react to and use systems, it is incredibly insightful in helping you to design and build better interactive systems.
What technology should we use and what’s all this nonsense about record players? This question seems to crop up almost daily in the various UX forums out there and the answer is whichever one works best for you and for the intended audience. Here at Rufus Leonard we have a variety of prototyping technologies we use in different scenarios – low fidelity (low-fi) for basic scamps and annotated wireframes using tools like Balsamiq, Omnigraffle and Visio, to slightly more interactive wireframes with basic behaviours and clickthroughs with Axure and then going a step further with technology like flash and AIR to rapidly create higher fidelity (hi-fi) prototypes for multiple devices which range from simple clickthroughs to fully functional solutions that emulate HTML/javascript as well as backend functionality but at a 20th of the time cost.
Typically, for the business process and requirements gathering we will stay at a low-fi level to ensure that the basic data capture and delivery methods are in place and to ensure essential navigation is functional and intuitive. Paper prototyping can be very effective and cheap here.
More advanced prototyping with software like Axure can be used to provide a more holistic low-fi system experience and can also then be used as an evolutionary stage toward design with basic capture of interaction and behaviours.
When it comes to testing a new product on the public though, our experience has shown us that low-fi just doesn’t cut it. The impact of a design on functionality is a make it or break it game plan and there is just no way to predict which way it will go, hence low-fi prototyping will not provide the required insight without the impact of skinning a design on to the solution. At the end of the day a failure can be based on something as simple as the colour and placement of a call to action. Many UX bods out there will rave and rant about their preferred level of fidelity, the vast majority opting for a low-fi solution, however, one thing I have found during my many years of prototyping (almost 22 years) is that the preferred choice of prototype fidelity is very often directly linked to the ability and skills of the person proposing it. Just colour me cynical I suppose.
SO, what kind of effort will this nonsense take? The answer leads us back to that wonderful dimensionless piece of string and this in turn can be a real drawback to selling the idea of prototyping and UX research.
Time-boxing your efforts – This is a classic pitfall area in a lot of prototype development and really it comes down to what you are trying to achieve and for whom. Many UI developers will just not be able to “let it lie”, constantly tweaking and adding to the prototype and losing focus on the fact that it isn’t meant to be a final solution, it IS meant to be a flawed representation and its power comes from the speed and hence low cost versus impact on the final interaction design. In the cases where your audience attempts to stray from their allotted path during testing, a simple “These are not the processes you are looking for!” and a wave of the hand will usually work and allow you to shift their focus back to the areas being tested
As a general rule, I will have a very clear plan of what a prototype must demonstrate, usually from workshops developing scamps or wireframes, as well as the intended audience and how long I have to create it before touching any code at all. This will be driven by the business needs, the exposure type and the final audience and required interaction level of the prototype.
When you are developing the prototype spiral in towards your solution, in classic rapid prototyping methodology we start at the outer edge of the spiral and just like an oil painting we begin with enormous brush strokes to bring the canvas together, gradually bringing more and more detail to the picture. Typically this translates as overall page hierarchy and navigation, to page details and down to interaction levels of forms and widgets and then to final design considerations. If you are lucky enough to have access to a good designer you should be able to create a simple click-through prototype of pages within a few hours.
Most important is to have fun with prototyping as you get to throw away all of the rules and standards for coding; it is the purest form of speed hacking possible, where we don’t have to worry about multiple browsers and accessibility; we just need something that works. Prototypes are quite often thrown away after their use when they have provided the final changes in requirements during the UX design iterations.
Another option is an evolutionary prototype which will be continuously enhanced until we get a final solution – this can work very well for mobile apps with small teams running in an agile environment but falters somewhat for larger scale projects. The technology used for this will evolve into the final solution so more care is required and a lot more time needed to get this off the ground.
And prototyping doesn’t just stop with UX; not only is it a brilliant tool for client presentation and pitch work, it is also the best way to learn new technology and to get something working. I make sure I have at least an hour or two of playtime every week in order to look at new tech and trends in the development world and try out any wacky ideas I might have had in the framework of a solution. Again, by time-boxing my efforts, I can usually get a small example or a widget fully working within a small amount of time. Very often it is the many acts of failure that helps us to learn and understand new technology. Edison put it best when he said “I have not failed. I’ve just found 10,000 ways that won’t work”
And so at the end of the day our advice is this: don’t build a death star without testing it, prototype fast and furious within your budget and timeframes and to the required audience and, most importantly, remember not to laugh/cheer/cry too loudly behind the one way mirrors during user research testing as they are never sound proofed as much as you would like them to be.

Posted in Flash | Leave a comment

Around the world with 80 lemons

Well, not even 80 to be honest. Just in the process of creating a new mobile AIR game and wanted to create a new blog post at the same time, seeing as I have been too busy for the last two years to do anything on this blog at all.

it’s here to preview, the new Lemonade stand, and it’s a project I have wanted to get around to for quite a while. Tree management, Population statistical engine, minions and of course the lemonade machines. This is still quite a basic format – more bells and whistles coming soon.

p.s. If you are a designer then please accept my apologies.

a simpe screenshot of the prototype machine

Posted in Flash | Tagged , , , | Leave a comment

Spinny Things are Good things

This is just going to be a fun little post, and a nice little takeaway to boot. The main reason why I did this was that I needed a new delay icon .. and for some reason I really love the facebook one on my android.

It’s just quite stylish!

The spinner is just a circular collection of 16 assets that we are going to turn into a phased spinny train around the circumference. This looks very different from just spinning the complete asset, it means one asset starts at full visibility then we phase it to invisible but when it reaches a certain % opacity we start the next one off and so on.The assets are sitting on top of static vector versions so the effect is … well, it’s spinny.

So whats the big deal you ask? There isn’t one really, I could probably have made this in about 20 minutes with a few timeline tweens or just used some Greensock tweens on a yoyo. But NO I say, NO GODAMMIT ! I wanted to do it this way, fully configurable, so I did, plus it’s much more fun.

As for most of these posts I am going to work on the timeline for speed, and of course I do urge you to make an OOP version of this too.

The spinny will have a start method and a stop method which will also phase the whole spinner in and out. And finally I wanted to add a bit of extra goodness by throwing in a custom event to mark to completion of the spinner. OOh, that’s exciting!

There are hundreds of samples of custom events out there so mine will be very brief and to the point. To create a custom event for an object we need to do 3 things. THREE !

1. Create the event – give it a name
2. listen for the event being dispatched by the object
3. Dispatch the event when we need to to be caught by the listener.

Now, how easy is that? You have got to love the event model!

1. var MyNewSexyEvent:Event=new Event("finished",false,false); // the other two args are for bubbling and cancelling

I have a new event inside my spinny clip, it is called “finished”

2. spinny.addEventListener("finished", fin)
The parent of the spinner is given a listener to wait for this event, where it will run a function called fin.

3. dispatchEvent(MyNewSexyEvent); // really that’s all it takes and the parent will pick it up and run the code assigned

Some people might be saying – why bother, whats the big deal ? I could do that just by calling the function directly when I need to, couldn’t I ? And the answer is yes, as always there are with flash many many ways to accomplish the same tasks. I personally like the cleaness of events, I am not hardcoding a particular requirement for a function somewhere instead I am sending out an event that might be picked up in many different places for many different reasons.

An example might be where we want to despatch an event in a battle game the event being “HitByArrow” from our main character and we want the UI to catch this to say “Ow !!!” but we also want the scores component to catch the event too so I can decrease my health, so I despatch the event after having set up two listeners and they will pick it up. If I later want to listen for the arrow again, to see if my armour plating has been dented I can quickly listen for the event …. WIthout having to go back in and change the code inside my man object ever again – ahhhhhhh the mist lifts, the light shines in.

You can also do other stuff with these, custom arguments, but I don’t really bother, within the listener defined function when the event is dispatched the function passes over a reference to the events object and we can access this via event.target and pick up any values we might need from there.

Back to the spinner – the example fla file is pretty simple: The root, the buttons MC and the spinner MC. The but MC has three stages in frames Start/Stop/waitForEnd, start is the first framer and is the start button, this just runs the start function on the spinner and then moves the button interface to the next “Stop” frame. Clicking Stop does the same sort of thing, tells the spinner to stop and then goes to the third empty frame to wait for the completion of the spinner.

Frame three also sets up a listener to wait for the spinner complete event and then traces out a message and moves the but MC back to the start position again. Just as an example I have set up 2 listeners for the event and one demonstrates grabbing an entity form the event.target reference.

So that’s it then …. what? You want to know about the spinner too ?

I have commented the code and it should be pretty clear what is happening here. So go and play and figure it out and maybe start to think of your own spinner designs.

` `

You can find the FLA and SWF here

Server date and time is: Friday, February 27, 2015 at 16:47:05

Posted in AS3, Flash | Tagged , | Leave a comment

Connecting flash to PHP and MYSQL – 2 – the database stuff

What a bizarre tutorial – you are probably thinking – he’s meant to be showing me php and mysql and I haven’t even had them mentioned yet. This is true, and yet this will almost always be the case. Database application development follows fairly similar routes and stages, almost always you will need to have some basic structures in place in the flash file before you start to think about connecting the two. As you get more experienced you may be able to get some old code and hack through it, but, you will benefit from setting up locally by not having to test every aspec of your interface on a live database, and time is everything.

This section of the tutorial will concentrate on setting up your database environment. Yey! And also to let you create the skeleton PHP files.

In order for this to work you will obviously need access to a server with MYSQL on it and have access to a database as well as PHP. If you haven’t got these then the rest of the MYSQL / PHP tutorial will be tricky for you and probably a bit pointless. So looking on the positive side I am going to guess you have access to these things.

Every database will have a name, it will need a user (with privelidges to read/write/delete) and the user will have a password. There is also the host of the database, localHost simply means this server. These details should all be obvious as well as how to find your PHPMYADMIN tool. This tool is a database development environment allowing you to fully interact with databases, their tables and just about anything you need to do with them. Its very good and intuitive. Usually these basic connection details are kept in a simple file on your server and included into all of your scripts. Give the file a name like include300368.php something memorable but impossible to guess. Justa quick note on security here, php is mostly a safe language, anybody trying to access the php inside will not be able to as it is parsed by the server prior to being served to a visitors browser. In the case below, these are temporary php variables and are not served to the visitor ever. Saying that, things change, right now there could be an 11 year old git who has figured how to get access to the raw code.

$DBhost = "localhost";
$DBuser = "mkbatman_mk";
$DBpass = "batman";
$DBName = "mkbatman_sms";

?>

This is the building block of your PHP files and will give you the necessary login access to your database.

Next we need to set up a table for our work. Go to your phpMyAdmin page, you may have to log in, and access the database you want to work with. If you only have 1 database then this will be preselected otherwise look on the far left column. When the database start page is open there will be an option to”Create new table on database DATABASENAME” call your new tavle phpexampleData. Or don’t. You can call it purpleElephants if you want to but typically its good to hold to logical naming standards.

For this simple example we need an ID, a title and a position value, so name your columns and select INT, STRING, INT for the types and remember to click AUTO_INCREMENT for the id, do not end your column names with numbers, why will become apparent later. The ID is your primary index and auto incrementing it means it will always be a unique value.

Now we are going to do an insert on the table. In fact we are going to action all of the tasks we need our PHP to use later and copy them. Open up notepad for somewhere to store the information. Click the insert table and insert a row use 1,2,3

Clicking go executes the request and the screen should have the SQL statement on the screen, copy this and paste it into notepad then change it to look like the one below:

$sql = "INSERT INTO `mkbatman_sms`.`phpExampleData` (`x`, `y`, `z`) VALUES (NULL, '$x1', '$x2');";

notice I have changed the values to be $x1 and $x2 these are PHP variables. Also I changed the value going into the id field to a NULL, this says have a look at the highest current ID and autoincrement that. The double quotes in PHP is special and in this case it will look inside the double quoted string for any PHP variables and it will replace them with their values.

Next lets update the row we just created, click the pencil icon on the new row on screen and update the title field and click go. You should see the SQL statement, change it to the one below

$sql = "UPDATE`mkbatman_sms`.`xxxx`SET `y`='$x1' WHERE `x`='$x2';"; again the actual change and the id have been replaced by php variables.

Next the get, we will be wanting to select a sorted data set, so very quickly insert another row of test data and then when it returns click on the title of the third column, here its z, because there are 2 rows in there this becomes clickable to sort. Clicking on it will execute a get and a sort, grab the code and change it to the one below

$sql = "SELECT * FROM `xxxx` ORDER BY `z`ASC;";

and now the final statement delete, should look like:

$sql = "DELETE FROM `mkbatman_sms`.`xxxx`WHERE`xxxx`.`x`='$x1';";

and again I have replaced the actual ID by the php variable.

Great, we are now ready to create some PHP files. In this instance we are going to use HTTP GET variables which allows us to test the scripts directly on the browser and not have to wait for our integration with the flash. Let’s start with the add a row script.

require 'include3003.php';

mysql_pconnect($DBhost,$DBuser,$DBpass);
mysql_select_db("$DBName");

$x1 = $_GET["x1"];
$x2 = $_GET["x2"];

$ins_str = "INSERT INTO `items` (`lID` ,`title` ,`pos` ) VALUES (NULL , '$x1', '$x2');";

if (!mysql_query ($ins_str)) {
$msg = 'problem';
} else {
$msg = "good";
}

echo 'msg='.$msg.'&bull=1';

?>

looks pretty simple, we include out credentials file, we look at the url to get our arguments to be inserted, we make a p-connection to the databse (p = persistant) and we choose the database we want to work with. Next we create the query string SQL using the arguments, action the SQL and if it inserted we get a good, otherwise we get a bad, this is then echoed to the screen.

Note also the end of the status statement has bull = 1, this is a dummy end argument and I use it from the old days to ensure that there isn’t any extra items tagged to the end of the returning statement. It can happen. The other reason is that one of the variables I usually send to the script is bull=0. By checking on the return that bull =1 I can confirm the script was ran.

Save this text as insertNew.php and send it to the server. next enter the URL of the file into the browser and add at the end “?x1=test&x2=5″ which will populate our GET variables. Hit return to send it and you should see “msg=good&bull=1″ on the screen. If there are errors double check each statement has a “;” terminating it and just look around for an error, its a simple script so should be easy to find.

Next to confirm the action go back to phpMyAdmin, select the table and confirm the addition.

The other three actions are very similar and should be tested in the same format. Once you have confirmed they all work change the GET to a POST in the script and leave them. They should look like the following:

1. GET does the select and order and then parses the results and sends them back along with the total number of results

require 'include.php';

mysql_pconnect($DBhost,$DBuser,$DBpass);
mysql_select_db("$DBName");

$qr = mysql_query("SELECT * FROM `items` ORDER BY `pos` ASC ;");

$r_string = 'n='.mysql_num_rows ($qr);

$i = 0;
while ($row = mysql_fetch_assoc ($qr)) {
while (list ($key, $val) = each ($row)) {
$r_string .= '&' . $key . $i . '=' . urlencode($val) ;
}
$i++;
}

echo $r_string.'&last=z';

?>

2. DELETE

require 'include.php';
mysql_pconnect($DBhost,$DBuser,$DBpass);
mysql_select_db("$DBName");

$idd = $_POST["idd"];

$del_str = "DELETE FROM `items` WHERE `lID`='$idd'";

if (!mysql_query ($del_str)) {
$msg = 'Record could not be deleted';
} else {
$msg = 'Record was deleted. Refreshing display...';
}

echo "statusD=d";

?>

3. UPDATE ROW

require 'include.php';

mysql_pconnect($DBhost,$DBuser,$DBpass);
mysql_select_db("$DBName");

$xx1 = $_POST["x1"];
$xxI = $_POST["idd"];

$query = "UPDATE `items` SET `title` = '$xx1' WHERE `lID` ='$xxI' ;";

$result = mysql_query($query);

echo "StatusU=UpdateD";

?>

4. REORDER THE LIST – need to do this when we re-order the list in flash

require 'include.php';

mysql_pconnect($DBhost,$DBuser,$DBpass);
mysql_select_db("$DBName");

$qr = mysql_query("SELECT `lID` FROM `items` ORDER BY `pos` ASC ;");

$nn = mysql_num_rows ($qr);

$i = 1;

while ($row = mysql_fetch_assoc($qr)) {

$iiid = $row['lID'];

$query = "UPDATE `items` SET `pos` = '$i' WHERE `lID` ='$iiid' ;";

$result = mysql_query($query);

$i++;

}

echo $r_string.'&last=z';

?>

that’s more than enough for one session. We have set up the database table, actioned the main tasks within phpMyAdmin and using those created our primary PHP files which we tested using HTTP GET variables directly on the browser.

After fully testing the scripts and checking the table amends were correct we can convert the variables back to HTTP POST for the integration.

As always the teaser is still there on the server if you want reminded of what we are aiming at

Posted in SQL | Tagged , , , | Leave a comment

Opening up a CSV file in AS3

This is going to be a simple post, based on a request, and it’s all about CSV files. Comma seperated value files are exactly what they sound like, a file of rows and in each row are a set of values seperated…by commas. Another aspect you may not be aware of is that XLS or excel files from the Office (the boring not funny type) can also be saved directly as CSV files.

Very often you will also see XML files being used as data sources for files, and to be honest they are a slightly more advanced solution allowing very structured data and not restricted to just a single nxm 2 dimensions. On the down side they are complicated to look at, can be very easy to break and are not something we would let a client loose on, as opposed to giving them a spreadsheet.

As a consequence, for simple data updates to a site or tool where we don’t want the customer to have to have to ring us up every 5 minutes just to change the contents of a dropdown we might give them some very somple instructions along the lines of:

1. open the local version of the file in excel
2. make changes / add / remove etc
3. save the file and close it (more on this)
4. Use the upload protocol to place the file onthe server

And bang the customer has updated the tool without having to ring you up with annoying questions.

So, how is it done ? REALLY simple but witha few caveats to remember. The base premise relies on a standard

var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, dataLoaded);

var request:URLRequest=new URLRequest("data.csv");

loader.load(request);

couldn’t be easier, could it. This will load the entire file into the data entity of the loader and then we can parse it and get the values back pout again and into some data structures. So, let’s talk about that first.

You will need to create the data source suitable for your project and most of the time you would probably just read the file and store the data in arrays as they are read in. For this example I am going to introduce a slightly more advanced structure which I use a lot and is based on good old fashioned linked lists. While we will store our data in arrays, we are going to use a seperate array structure to store the indices of the structure and then whenever we need to move, add, change or delete an item row we are going to use this indice structure.

a simple example might be indice[i] holding the indices and data[j] holding the data. look at the structure below.

x[0] = 1, x[1] = 5, x[2] = 14, x[3] = 16 and then data[1] = bob, data[5] = susan, data[14] = mickey, data[16] = john

now let’s say we want to move the order a bit and place susan in from of bob. We never touch the data[] structure and instead just swap the index values of the indice array so we now have:

x[0] = 5, x[1] = 1, x[2] = 14, x[3] = 16 and data remains the same at data[1] = bob, data[5] = susan, data[14] = mickey, data[16] = john

Next let’s say we want to remove mickey from the list, we wouldn’t need to touch the data array at all, just clear the index element:

x[0] = 5, x[1] = 1, x[2] = 16 there are array methods to help you do this like unshift, splice, pop, push and others. They are worth taking a look at and playing with. In this case x.pop() would clear the last element.

Why on Gods green earth would anyone want to do this you are probably asking. The example is for a simple 1 tier structure, but imagine if there were 20 columns for each row, this method still only changes the indexing array as opposed to having to move and change all 20 arrays.

In the example for this post the excel spreadsheet csv file has three columns so the folowing code makes up the structure.

var Data_ID:Array = new Array();
var Data_name:Array = new Array();
var Data_sort:Array = new Array();

The allRows stores the id’s only of all the rows in the right order – which would then give us access to the data

var allRows:Array=new Array()

then as we read them in we assign the id to the index array and place the data in the data arrays at the id index (I can use ID here as it is always unique – if it were not unique I would need to make up a new index key with a numeric stepper)

Next we need to load the data from the loader class.

loader.load(request);

and then in the completion function set up earlier we can start to parse the information in the file.

function dataLoaded(evt:Event):void {

var myData:String=loader.data; // contains the data
var myDataRows:Array=myData.split("\r"); // splits the rows into a seperate array

var smallArray:Array;
var newID:int;

for (var ii:int = 0; ii< myDataRows.length0; ii++) {
smallArray = new Array();
smallArray=myDataRows[ii].split(","); // splits the individual elements by the seperator comma

newID=smallArray[0]; // this is the indexer value
allRows[ii]=newID; // assign the indexer to the indexing array in order

// next place the data into the data arrays at the position of the indexer, which is the id

Data_ID[newID]=int(smallArray[0]);
Data_name[newID]=String(smallArray[1]);
Data_sort[newID]=int(smallArray[2]);
}
}

and that's it, simple.

A few small caveats that you need to think about finally. If you are going to include headers for your customer you would start the for loop at 1 not zero but remember to offset in the allArray by subtracting 1 from the loop index. Make sure when you are testing locally that the CSV file is not still open

in excel as this will cause an error. Sometimes excel saves an extra row or rows of empty cells at the bottom of the CSV file. You need to play with this and test and then adjust your code to make sure it works, all to do with end of file markers.

The simple rule is to build it and then test it to death to make sure it works. Enjoy the sample file in rar format

Posted in AS3, Flash | Tagged , , | Leave a comment

Site Implementation, Evolution, Rollback and Sandbox

This tutorial is going to talk about setting up your flash microsite on the web server and how to handle any changes to the site. So let’s say your project is finished and the client is happy; you slap the swf up on the server with SWFObject and an HTML file and that’s it right ? Right ? No. That’s never it.

All web projects evolve, some more, some less, but the amount of times I have created a solution on the server and have never ever changed can be counted on the fingers of one hand. In fact, I could count them without the hand, because the answer is ZERO ! Nada, Not a single one. It just doesn’t happen, ever.

So what’s the big deal, make the changes, slap em up, refresh your cache and bingo, new working version. But here’s the rub, you can’t guarantee the client or the customers are going to do that. In fact with browsers like firefox that automatically cache, you can instead guarantee the opposite. And you can’t just expect them to figure it out. You need a solution. And just to top it off, let’s imagine another scenario, you send up a new solution that has added some new functionality, but theres a huge glaring bug in it that managed to slip past your QA process. Same thing, all those visitors who accessed the buggy version are now cached on it, you need some mechanism to roll back the solution to the previously working version.

The following set-up is a simple solution that I have used hundreds of times, it works with swfaddress deep linked sites, it works with roll back. It just works.

For starters we always use a loader swf – the smaller the better, say about 5k optimum. Just because you have a loader doesn’t mean you have to let the visitor know theres a loader, it’s just a mechanism to solve cacheing.

Because we are evolving the site, the main SWF file, let’s call it ActualSite.SWF is not good enough, so we are going to assign a delivery number to the file, now we have ActualSite23.swf for the 23rd evolution. The way we know how to discover this unique file name is by loading a file from the server that contains it. You don’t have to use an XML file, a straight text file will do, but I prefer XML as it means I can add other stuff to it if I want to. Before you get too excited though, the XML file itself can get cached to so we need to employ a cache BUSTER mechanism. This means making the browser imagine that it is a new file every single time it loads the file. We do this by adding a HTTP GET variable to the URL of the XML file. As in filename.xml?cacheBusterVariable=231154, here the number is a time stamp of when the operation occurs delivered programmatically via action script. Then the next time you load it it will be filename.xml?cacheBusterVariable=231543 as the time has increased, therefore always loading a new version. But hang on, I hear you say, why all these extra hoops, can’t we just use this mechanism to always load the SWF fresh each time. Yes, we could indeed, except that cacheing isn’t evil, we WANT to cache as much as possible so that when a user returns to a site they have less waiting.

Here are the steps that occur now:

  1. The HTML file loads up SWFObject
  2. HTML then creates a SWFObject object in the page
  3. SWFObject checks to see if the customer has the correct player
  4. If the player version is correct, the no-flash DIV content is replaced and we load the Loader.swf
  5. The Loader.swf loads very quickly and immediately loads the site.xml file with a dateTime cachebuster
  6. The site.xml file reveals the name of the latest project SWF e.g. ActualSite23.swf
  7. A loader loads in the ActualSite23.swf (optionally giving %Load)
  8. We add the content of the loader to the stage and lose the loader resources
  9. The ActualSite23.swf is on the screen and the onStageAdded event is fired.

NB: Another real advantage of this is that the site will not suffer any down time during upoad, the XML file is the only aspect that is changing and because its so tiny the chances of anyone failing to load the site during the upload is virtually zero.

Now lets look at our two situations mentioned earlier. First, we have an evolution to the file, we increment the delivery number so we now have ActualSite24.swf (which has of course been fully tested and QA’d on a seperate server – more about this later) Here are the steps required to “up” the evolution.

  1. Send the new ActualSite24.swf to the server
  2. Edit the site.xml file and place the new delivery number in it
  3. Send up the new XML file
  4. Test the new evolution to make sure it is working live

That’s it. But wait, while testing it you spot a new bug out of nowhere, what to do, panic? Run around the room cursing Vishnu and evil ways (insert deity of choice there) No, all we need to do is perform a rollback which is simply:

  1. Edit the site.xml file and place the previous delivery number in it
  2. Send up the new XML file
  3. Test the older version to make sure it is working live. Done

Can you ask for anything simpler?

Are there any pitfalls? Well one minor issue is the cache buster URL will not work in the player if you are publish previewing. Either comment out the bit of code that adds the new ending when testing locally or if you wanted an elegant solution you would pass up a local flashvars variable in the HTML file SWFObject to say use the cache buster and if that variable didnt exist (like when testing just in player) don’t use the cache buster extension.

Now, finally I am just going to mention quickly another extension to this method, sandboxing. I did ask you earlier if you had fully tested the new evolution, and you may have an identical setup development server with exactly the same configuration, in which case fine and dandy. If you don’t have that, then you need to test from the live server. For a sandbox configuration all you need is what we described above already – a seperate loader swf sandbox.swf, which loads in a seperate XML file – siteSandbox.xml and a copy of the HTML file which references the new loader SWF, call it sandbox.html.

Now the process has a few extra steps, for the new evolution of the mainsite24.swf. First we update the siteSandbox.xml file with the new delivery number, then we upload the new mainsite24.swf and the siteSandbox.xml to the server and test away.

As soon as the tests are finished and we are happy, then all we need to do is update the site.xml with the new delivery number and hey presto, it all works.

Posted in Flash | Tagged | Leave a comment

Full lifecycle Madness (Part 4)

In part 3 we were getting very thin on time, but the objective was in sight.

We are getting near the end of the development phase now, so its time to pull out all the stops. We have an image local load from server, we have it placed and resized inside a second degree holder, we also have a ability to save the image to the server as a JPG using PHP. Next step is image manipulation.

To start with we want a drag and drop operation on the image holder. I personally never use native drag’n’drop, as I prefer a bit more control. The method is simple, define the start of the drag operation in this case MOUSE_DOWN on the image holder. At which point we set a Boolean which is checked in an ENTER_FRAME function. The drop operation will either be a MOUSE_UP on the holder clip or a MOUSE_OUT on the main content holder, in which case we clear the boolean and stop the ENTER_FRAME and start to listen for the next drag operation again. We also take a snapshot of where the mouse is in the holder when we start dragging and then in the ENTER_FRAME we know when the mouse moves how far to move the picture (we can’t look at the mouse position inside the image holder because we will be scaling this clip)

pt.pp.addEventListener(MouseEvent.MOUSE_DOWN, msdwn);
var mdown:Boolean=false;

var baseMX:Number=0;
var baseMY:Number=0;

pt.mouseEnabled = true

function msdwn(me:MouseEvent) {
pt.pp.removeEventListener(MouseEvent.MOUSE_DOWN, msdwn);
baseMX=pt.bm.mouseX;
baseMY=pt.bm.mouseY;
addEventListener(Event.ENTER_FRAME, moveOEF);
pt.addEventListener(MouseEvent.MOUSE_UP, mseup);
pt.pp.addEventListener(MouseEvent.MOUSE_OUT, mseup);
mdown=true;
}

function moveOEF(ee:Event) {

if (mdown) {
pt.pp.x=pt.pp.x+pt.bm.mouseX-baseMX;
pt.pp.y=pt.pp.y+pt.bm.mouseY-baseMY;
baseMX=pt.bm.mouseX;
baseMY=pt.bm.mouseY;
}
}

function mseup(me:MouseEvent) {

mdown=false;
pt.pp.addEventListener(MouseEvent.MOUSE_DOWN, msdwn);
removeEventListener(Event.ENTER_FRAME, moveOEF);
pt.removeEventListener(MouseEvent.MOUSE_UP, mseup);
pt.pp.removeEventListener(MouseEvent.MOUSE_OUT, mseup);
}

Next we have scaling, I want to be able to focus in and out on areas of the image and I decided for speed to use a Slider component for this [NB: If I had more time I would stay away from components simply because they bring HUGE overhead with them which I cannot control, it's always best to use your own tested components as you know how to skin them and customize their behavious. TIP: whenever I complete a project I always have a look inside and if there are any groovy component clips I can use later, I copy them to a new fla file inside my components directory and then name the file very well]

The slider in this case is going to do two types of operation, zoom in to 500% and zoom out, let’s say to about 1%. SO I drag an instance to the stage, resize it, use the component inspector to set a min and max from 0 – 1 and the tick value same as step to 0.01. I have added labels to show what it will do, namely at the halfway point (value = 0.5 as default) we shall have 100% [of the resized image!]

The SliderEvent.CHANGE event is activated when the slider changes, and here we want to return a scaling factor to change the parent image holder. If the value is 0 – 0.5 we want to return 0-1, simple, factor it by 2. If the value is 0.51 – 1 then we want to return a factor of 1.01 – 5 on a linear scale. A simple piece of algebra (remember y=mx+c) will yield the equation to use to provide the sliding scale.

var factor:Number = 1;

import fl.events.SliderEvent;

sld.addEventListener(SliderEvent.CHANGE, sldCH);

function sldCH(sl:SliderEvent) {
var tval:Number = sld.value
factor = (tval<=0.5)?2*tval:7.959*tval-2.959
var MCMidX:Number = MovieClip(parent).pt.pp.x+MovieClip(parent).pt.pp.width/2
var MCMidY:Number = MovieClip(parent).pt.pp.y+MovieClip(parent).pt.pp.height/2

MovieClip(parent).pt.pp.scaleX = MovieClip(parent).pt.pp.scaleY = factor
MovieClip(parent).pt.pp.x = MCMidX-MovieClip(parent).pt.pp.width/2
MovieClip(parent).pt.pp.y = MCMidY-MovieClip(parent).pt.pp.height/2

txtVS.text = String(Math.round(factor*10)/10)
}

Notice I have also centred the scaling effect (look at midpoint before, then adjust after the scale for the new width and height to always keep the operation centred) NOTE: remember I mentioned re-using work, in this case the slider and centreing operation is useful, so stick the whole thing in a clip and save it as a seperate fla document after commenting what is happening. TIme is vanishing and I want to add some more options – bingo – just remembered a wonderful download I have in my library which uses Grant Skinners colourMatrix class (www.gskinner.com), find it, slot it in, connect it and test. Wow.

AhhHA! I hear you say, he is cheating. Me? Cheat ? Absolutely ! Every day I cheat, I re-use, I hack, that’s what flash development is. In this case I highly recommend looking at the code Grant kindly supplied, play with it and understand it.

Now the last development stage is the notification, I am going to do a simple version here and just start a fileReference download operation. For all the smug people out there who will mention the exisitng methods of automatically creating the file download of jpg and png formats from a bitmapData object, yes we could use these also, however for this example, I also wanted to keep a server version and that’s why I am using the GD library. By having it on the server we can do many things, send links to it, create galleries, ooh, lot’s of things.

“The Adobe actionscript 3 help system is your friend”, repeat this mantra every day at least three times. Nobody keeps every bit of AS3 in their heads, it’s not possible. Use the help system. In this case I know for a fact that theres is a very simple FileReference.download example in the help system, drag and drop, change the URL and wham, bang, thankyou maam. Now the bad news, it will not work. And this is where experience comes into play. A security check put in place will stop flash 9 player published files from running this script UNLESS it comes from a button press. So attach the download operation to a button and you are in business.

I also quickly threw in some workflow code here as well. Once the PHP is called, remove the CONVERT and RESET buttons. Once the PHP returns add the DOWNLOAD button. Once the download finishes we need to access some functionality to remove the DOWNLOAD button, remove the image and reset the controls and add back in the UPLOAD button. This function also does the same functionality as the cancel button, so tie that in to. And we end up with the following:


var downloadURL:URLRequest;
var file:FileReference;
var filename:String;

//filename already defined on the php save

dlb.addEventListener(MouseEvent.CLICK,FileReference_download);

function FileReference_download(me:MouseEvent) {

downloadURL = new URLRequest();
downloadURL.url=”images/”+filename;
file = new FileReference();
statust.text=”Download Ready – “+filename+” click download button to receive”;

file.addEventListener(Event.CANCEL, FDcancelHandler);
file.addEventListener(Event.COMPLETE, completeHandler);
file.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
file.addEventListener(Event.OPEN, openHandler);
file.addEventListener(ProgressEvent.PROGRESS, progressHandler);
file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
file.addEventListener(Event.SELECT, selectHandler);

file.download(downloadURL, filename);
}

function FDcancelHandler(event:Event):void {

}

rss.addEventListener(MouseEvent.CLICK, reset);

function reset(me:MouseEvent) {
onReset(null);
ub.visible=true;
dlb.visible=false;
cv.visible=false;
rss.visible=false;
this.pt.pp.removeChild(image);
ub.addEventListener(MouseEvent.CLICK, ImbrowseHandler);
}

function completeHandler(event:Event):void {
statust.text=”completed download – resetting”;
reset(null);
}

function ioErrorHandler(event:IOErrorEvent):void {

}

function openHandler(event:Event):void {

}

function progressHandler(event:ProgressEvent):void {
var file:FileReference=FileReference(event.target);
}

function securityErrorHandler(event:SecurityErrorEvent):void {
}

function selectHandler(event:Event):void {
var file:FileReference=FileReference(event.target);
}

This is IT ! IT WORKS! Halleluljah, praise baby Jesus etc. But, no, sorry, you forgot the steps. My clock now has 45 minutes left before deadline and I still have a lot to do. So far the system has no design to it, we haven’t tested, or QA’d the application and the copy is missing.

So I am happy with the application technology, time for some quick designy stuff – I literally threw this on in 10 minutes – gave the app a background, placed text on the app with a description and instructions (the copy), changed the watermark on the image, played with the layout of the components, added some button states etc. Fast!

Normally, I would never suggest that a developer do any system testing aside from unit testing – ie taking a specific sub section of an application and doing black box testing (running through all possible sequences from input to output with no regard for what is happening) followed by specific code testing, looking for structural weak points where errors may occur in either the input to a subsystem, the processing or the output.

HOWEVER – many times you will be in a situation where there is nobody else available and time she is a creeping. It’s going to be hard, try and train yourself to be objective and to behave as though you were a user, click all buttons like mad, try and break it, put silly values in text fields, tab, go nuts on the app. What should be tested:

  • Unit Testing – black box and structured – during the development and at completion of sub-system
  • System Testing – all sub-systems, integration, rollback, flow, CPU overload
  • Browser testing – I know its all the same player, but some times browser behaviour does differ – at least do IE, firefox and Safari
  • Player Testing – It’s useful if you have two machines to keep a browser with an older player version for backwards compatability
  • Usability – a curious item, but this is more for feeling and intuitiveness off the application, but very important

If you encounter problems or bugs, fix them immediately as theres always the possibility of follow through, ie later bugs being thrown by the first. Also make sure you are running on a debug player so you will see errors as they occur. It is quite astounding how often when browsing the net on the debug version how often you will see flash applications break apart due to lack of testing.

For such a simple app, I managed to fully test it in about 20 minutes, finding several problems, one of which was the fact that after downloading one image successfully, the second image was an identical copy to the first image, this was because the pixels array containing the ARGB pixel values was populated with a push statement and this was never reset. ANother item was the workflow, buttons were still active and pressable when they shouldn’t have been, cancel options and tech were missing, a few little things really. For a larger project I would recommend doing this more formally and tasking the activity out to a mid level user with a scripted test scenario containing expected and actual results.

Final stages are implementation delivery and maybe training. In such a simple case the implementation is already there, just need to inform the customer of the URL, training ? Well, it’s such a simple system process, you can talk them through it once. Usually there are quite a few extra steps for larger systems, but that’s not really in the scope of this tutorial. Briefly some of the extra stages that would occur are items like code optimisation (applying an OOP structure, checking all standard code optimisations are in place), a big step is documentation – highly underated and very necessary, code should be commented in logical blocks, a system design document should be written, a flow diagram showing all modules, data sources and communication scripts, and a use case study should have been made identifying the user roles and responsibilities (interestingly this document leads directly to the user test script!)

In reality, all we have really accomplished here is a prototype, and that’s OK, but anything larger would need a lot more work putting into the project in order to produce a valid outcome with respect to planning, time and budget. So remember that when you start a client project the steps taken here. Where normally you might just start hacking, remember the steps taken here and that we only started playing with the keyboard AFTER we had determined how long we had and the steps we would need to accomplish the task.

Hope you enjoyed the journey. I have included a zip of the files so you can have a play and maybe grab some stuff you didnt have before. If you are looking to take this forward why not create a second page of thumnails (create a much smaller jpg) of all the user uploads, maybe add mail notification via PHP, add some more image manipulation tools, hell, why not stick in user registration and have accounts. Just out of curiosity I decided to do a quick version 2 of the application, visible here, which uses the Adobe JPGEncoder.as class, the change to the code took about 20 minutes and provides an instant solution as the whole operation is happening locally on the client machine. Just for your benefit it you are trying this, the difference is that the class takes the bitMapData as input and returns a byteArray, then you will need to change the fileReference.download to a fileReference.save. Why not try that too, or use the PNGEncoder.

source files from the tutorial

NB Just out of curiosity I also made an android 10.1 version of this too. So if you have an android phone have a quick look. Obviously when developing for the mobile we have to be a lot more careful about the UI and how the options for the mouse (in reality a finger) will work. The app works pretty well on the mobile, I also added some custom easing to the drag operation as this works better with a finger. You can find it here: abdroid 10.1 image manipulator tool

Posted in AS3, Flash | Tagged , | Leave a comment

Full lifecycle Madness (Part 3)

In part 2 we had managed to upload an image from the local file system, resized it and placed it on the screen inside a holder, about 30% of the main functionality. Next we need to create a JPG of the holder image.

Part 3 has arrived. Yey. Let’s just start with what actually happened when I got to this stage in the project; it didn’t work, to put the matter simply, my 30ish minute slot turned into a 120 minute slot, and that’s exactly why we have the fuckup factor, it’s just impossible to know when these situations will occur. The good news is that we factored for this to happen. The problem was that I didn’t type cast an array into a string before passing it to the PHP. The problem is identifying why these things happen, in this case trace and reporting fields before and after the PHP call identified the problem.

The next stage is of course the one where we create a bitmap object of an image and then create a new jpeg based on this image on the server using PHP and the GD library. I mentioned earlier about not integrating the elements in an application too early and so, while we are working on the same fla (incremented naturally) we are now using a seperate layer to do the next phase.

Note: The requirements for this project were to create a server version of the new image. This is quite a lengthy process due to the hoops we have to run through as well as moving the data from the flash to the PHP. As an alternative I also made a version of the tool which uses the JpegEncoder class and which is instant – can be viewed and tested here

As a set up I have created a copy of the holder movieclip structure, which inside has a mask on top for the correct dimensions and then another layer for some vector graphics (watermark) and at the bottom of the pile is a backgound vector and above that is the holder with our bitmap in it. For the test case I just uploaded a small graphic into this. The size of the jpg I will be creating for the test case is quite small, 50×50, and thats because I want this to run fast during the development process. And we also need a button to start the process, called cv. The clip called pt is the holder containing the mask, the vector layer, the backgound and the bitmap holder. [NB I replaced the test code with actual here]

var snap:BitmapData=new BitmapData(450,350);
var aa:Number=0; //used as the chunking variable

cv.addEventListener(MouseEvent.CLICK, capture);

function capture(me:MouseEvent) {
snap.draw(pt);
aa=0;
addEventListener(Event.ENTER_FRAME,oefcp);
}

The next code when run will loop through the (x,y) pixel coordinates of the clip (the top one) and will record the pixel ARGB values for the clip and store them in an array of hexadecimal values e.g. 0xffe456. So for a 50×50 image this is 2500 operations, which is not that many. However, the final image is going to be about 450×350 = 157500 operations. I dont want to just overload the comiler so I am going to chunk the operations into blocks of 10X50 (this will be 10×350 in the final version) and I am going to use an EnterFrame operation to do this.

var pixels:Array = new Array();
var tmp:String;
var w:Number=450;
var h:Number=350;

function oefcp(ee:Event) {

for (var a:int = aa; a<(aa+10); a++) {

for (var b = 0; b<=h; b++) {
var alpha:String = (snap.getPixel32(a, b) >> 24 & 0xFF).toString(16);
var red:String = (snap.getPixel32(a, b) >> 16 & 0xFF).toString(16);
var green:String = (snap.getPixel32(a, b) >> 8 & 0xFF).toString(16);
var blue:String = (snap.getPixel32(a, b) & 0xFF).toString(16);
if (alpha.length==1) {
alpha="0"+alpha;
}
if (red.length==1) {
red="0"+red;
}
if (green.length==1) {
green="0"+green;
}
if (blue.length==1) {
blue="0"+blue;
}
tmp="0x"+red+green+blue;
pixels.push(tmp);
}
}
statust.text="loop "+aa+" "+w;

aa+=10;
if (a>w) {
statust.text="pl "+pixels.length;
removeEventListener(Event.ENTER_FRAME,oefcp);
aa=0;
sendUSERrq();
}
}

The PHP function requires the data to be delivered from top left image pixel then all the way to the bottom, next is top left + 1 then all the way down again. So the loop I have is starting with a base value of 0, base + loop 0-9, then loop 0 to height, do a getPixel32, grab the RGB values (important sep here as this can cause problems, if its a single value hex that comes back, say 0xa then we need to add a leading zero) and then we are going to make up a hex value string in the format the PHP is expecting and add it to an array. After the process is finished I increment my base by 10 and check against the expected width to see if it’s finished. NB this function is NOT optimised, in fact its the opposite thereof, by about a factor of 10. Usually this would be changed later but it works well as an illustration.

The next function is a good illustration of how to access a PHP file with arguments and then call the return function on return. Re optimisation its bad, for a 120K data set I am in reality sending 10x that amount.

function sendUSERrq() {

var phpTG:String="show.php";

var requestO:URLRequest=new URLRequest(phpTG);
requestO.method=URLRequestMethod.POST;

var loaderO:URLLoader=new URLLoader(requestO);
loaderO.addEventListener(IOErrorEvent.IO_ERROR, serverDirectoryIOError);
var variables:URLVariables = new URLVariables();

variables.nname = String(new Date().getTime());
variables.img=String(pixels);
variables.width=w;
variables.height=h;

requestO.data=variables;

loaderO.addEventListener(Event.COMPLETE,afterCreateJPG);
loaderO.load(requestO);
}

function serverDirectoryIOError(ee:Event) {
// in case we can't find the php file
}

Above we are then set up to pass the full array along with the width and height to the PHP and use GD to make an image from it. I also passed up the new filename, which was just the current time in ms (if this were a generic tool I would add in a username coefficient to the filename, but in this case current time is sufficient. The following PHP file handles the creation of the JPG file

$data = explode(",", $_POST['img']);

$width = $_POST['width'];
$height = $_POST['height'];
$nn = $_POST['nname'];

$image=imagecreatetruecolor( $width ,$height );

imagefill($image, 0, 0, 0x000000);

$i = 0;
for($x=0; $x<=$width; $x++){
for($y=0; $y<=$height; $y++){
$r = hexdec("0x".substr( $data[$i] , 2 , 2 ));
$g = hexdec("0x".substr( $data[$i] , 4 , 2 ));
$b = hexdec("0x".substr( $data[$i++] , 6 , 2));
$color = imagecolorallocate($image, $r, $g, $b);
imagesetpixel ($image,$x,$y,$color);
}
}

imagejpeg($image, "images/".$nn.".jpg", 100);
imagedestroy( $image );

echo 'hh='.$height.'&ww='.$width.'&fin=1';

?>

Finally the PHP comes back and we check the checksum return values to make sure its all in place. Where did my mistake from earlier come in? I forgot to typecast the array being sent to the php as a string value. That’s all, and the whole thing went tits up. The trace statement is your friend here, and also some dummy textfields on the screen. Unfortunately you can never really be sure what is happening in the php, but you can set the return to tell you if variables were calculated correctly.

function afterCreateJPG(event:Event):void {

var vars:URLVariables=new URLVariables(event.target.data);

var UOLv:int=vars["fin"];
var hh:int=vars["hh"];
var ww:int=vars["ww"];
statust.text="finished "+UOLv+" "+ww+" "+hh;
}

NB: An interesting thing here is we can do our own bitmap filtering of each pixel if we do so require, its completely up to you, orphasing images together. Because the image we are looking at is a composite we can add a vector watermark to all images, or text or anything really – just play away

Once I had this working for the small version, all I needed to do was to point the bitmapdata at the other widget created earlier to load an image from the fileserver and then change the width and height settings and it was all a gogo – the test now lets me load in a graphic and then another button analyses the composite and resized image and creates a brand new jpeg on the server with the PHP, pretty cool if I say so myself.

As a test I looked on my drive and found a 5.46 mb image which was 3648px by 2736px. I hit the load button and brought it to the browser with no timelag (remember its NOT uploading!) and resized to 450×350. I then hit the create button and the process from start to finish took 30 seconds and the image was 96kb for a full complex image.

Just to upload the original in another test, took me just under 3 minutes alone. Also I created the image to 100% quality with the PHP, a quick test with photoshop and it couldnt reduce that number.

So where are we now? About 4.5 hours in, 2.5 hours left! The good news is as we have been going on we have been unit testing and also we have integrated the two main development objectives. What’s left to do ? On the Flash development side we still have image manipulation, notification or save to local, and a restart option – thats about an hour budgeted. The rest is doing design on the UI, writing some copy, system test. All together we might just make it as long as there aren’t any new catastrophic failures. (which there probably will be)

Posted in AS3, Flash | Tagged , | Leave a comment

Full lifecycle Madness (Part 2)

In part 1 of this post we were given a project, we defined it, scoped it, allocated resources, talked to the client, planned the work and created a simple development environment. Now we start hacking.

Here we go, part 2, and on time still, development directory locally and on server, version 1 of the swf is up and functioning in a centred deployment. Next, we are going to do a load from local file server to the web browser, this means using a button to browse for images which activates a filereference.load. The result (data) of the load is going to be a byteArray (Note: This is a localised operation, nothing is on the server at this point, we haven’t uploaded anything) containing the image data.

var ImageRef:FileReference;

function StartImageLoad() {

ub.addEventListener(MouseEvent.CLICK, ImbrowseHandler);

ImageRef = new FileReference();
ImageRef.addEventListener(Event.SELECT, IMselectHandler);
ImageRef.addEventListener(ProgressEvent.PROGRESS,IMprogressHandler);
ImageRef.addEventListener(Event.COMPLETE, ImcompleteHandler);
}
function ImbrowseHandler(event:MouseEvent):void {
ub.removeEventListener(MouseEvent.CLICK, ImbrowseHandler);
ImageRef.browse(ImgetTypes());
}

function ImgetTypes():Array {
var allTypes:Array=new Array(getImageTypeFilter());
return allTypes;
}
function getImageTypeFilter():FileFilter {
return new FileFilter("Images", "*.jpg;*.gif;*.png");
}

var newImageEnd:String;

function IMselectHandler(event:Event):void {
ImageRef.load();
}

function IMprogressHandler(event:ProgressEvent):void {
var up1:int=int(Math.floor(event.bytesLoaded/1024));
var up2:int=int(Math.floor(event.bytesTotal/1024));
trace("file uploading - "+up1+" / "+up2+" KB");

}

function ImcompleteHandler(event:Event):void {
trace("File was successfully loaded.");
doneLoad();
}

Next, we need a loader to convert the image data into a bitmapData object and then to a bitmap and to the screen inside a holder. Actually, lets make that a holder in a holder in a holder. One holder for the lot (tip: this is really useful when you want to add a component movieclip to another project, or if you want to make the layout liquid, never ever code UI to the root, always encase.) So, we will have a main holder for everything, then a holder for the final image, inside which we have a holder for the loaded image (more on this later, but basically we will want options inside the top holder like texts, background colour etc) and a button of course. We are going to use the loadBytes method of the loader to bring in the byteArray, and set an event listener to tell us when this has completed.

Now the content of the loader is in reality a bitmapdata object, it just doesnt know that yet, so we create one and pass the information into it. Finally, we have our bitmap, remember that this is still all working locally and we have the original size of the picture, so we now need to resize this and position it on the screen inside our holder.

var my_loader:Loader = new Loader();

function doneLoad():void {
my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, getBitmapData);
my_loader.loadBytes(ImageRef.data);
}

var image:Bitmap;
var BMPData:BitmapData;

function getBitmapData(ee:Event) {
var Lcontent:* =my_loader.content;
BMPData=new BitmapData(Lcontent.width,Lcontent.height);
BMPData.draw(Lcontent);
trace(Lcontent.width+" "+Lcontent.height);
image=new Bitmap(BMPData);
resizeandPlace();
}

Resizing a picture to fit a space can be done in two ways, either you decide to stretch to fit or you will have to max either the height or width to fit (and optionally centre) Stretch only works if you know the aspect ratio will be the same or very close. If this isn’t the case, we have to re-scale the image and that means finding the optimal scaling factor. To do this we need to first look at the aspect ratio of the image versus the frame, which just means is it longer in the height or the width. In your mind visualise the space the image will be going into then the image and now slowly reduce the scale of the image until it fits either exactly to the height or exactly to the width.

function resizeandPlace() {

var mcW:Number=image.width;
var mcH:Number=image.height;

var basex:Number=0;
var basey:Number=0;

var basewid:Number=pt.width-2;
var basehgt:Number=pt.height-2;

var f1:Number=Math.floor(100*mcH/basehgt)/100;
var f2:Number=Math.floor(100*mcW/basewid)/100;

var f3:Number;
var f41:Number;
var f42:Number;

var tNx:Number;
var tNy:Number;

var newScale:Number=1;

if (f1>=f2) {
f3=1/f1;
image.scaleY=image.scaleX=f3/1;
f41 =(basehgt-(f3*mcH))/2;
f42 =(basewid-(f3*mcW))/2;

} else {

f3=1/f2;
image.scaleY=image.scaleX=f3/1;
f41 =(basehgt-(f3*mcH))/2;
f42 =(basewid-(f3*mcW))/2;

}

image.y=basey+f41+1;
image.x=basex+f42+1;

this.pt.pp.addChild(image);
}

This code does the biz. If you want to understand it, try it on paper and figure out what it’s doing. So, we now have about 50% of the functionality, so we will stop part 2 here. In the next section I will add the functionality to resize and move the image about and also add background colour. After that we need to work out how to make an actual image from flash data with PHP.

Posted in AS3, Flash | Tagged , | Leave a comment

Full lifecycle Madness (Part 1)

So friday fun time arrived for me last week and I decided to make a full 1-day application and also tute the results, so lets get going. The tutorial will be split into 4 sections just to give you a chance to have a break and wash and eat and stuff. Section 1 looks at defining the project and getting the basics set up.

Stage 1: I have a dream – actually, I don’t, I have about 7 hours and an idea for an application, I don’t even know if the idea is reasonable, so lets do that first, we will map out the idea a bit more and see what we shall see.

The basic idea then is a little system that lets me upload a photo, resize it, maybe play with some filters and even add a caption, the system will then save the new photo and notify the user or send the new photo to the user. Sounds simple enough. What else? We could register users, allow them a gallery of their own before and after images, let them zoom, move, crop, add a background colour. Notifications could be with email, sms, or directly on screen … whoa, there, boy. Lets stop this before we get silly.

First things first, ROI (thats return on investment – a crucial concept. If it’s not there for the client you shouldn’t be working the project), in this case it’s easy, my client (the better half) needs to manipulate lots of photos from her SLR 10mb files into something she can distribute on the web, sometimes she needs minor manipulations too. My other client (me) gets tasked with this many times during a month and this ‘time’ is what we will be saving, the return quality has been identified. Is the return sufficient – easy to find out, lets say 100 photos pa, which need to be collaborated on with input from client A, the time of the manipulation from client B (5 minutes) and then the return of the new info to client A. All in all about 8 mins per photo, which means about 800 minutes per year of client B, me, so anything I knock up in 7 hours is well worth it. Cool

Next, technology, obviously we need flash, the wrapper HTML and JS, PHP GD for the jpeg creation, email functionality, possibly a database if we want users to have an account. OK, all the technology is there and we have as our major constraint the time.

Now lets estimate what we can achieve in the time allowed. We have a delivery to client due at 5pm, that means 6 hours to go through the process. In that time we need to sort out the technology, the design, the UI controls, the back end PHP work, the wrapper, the copy, training copy, test it, deliver it! That’s a lot for 6 hours. Break it down again using our experience of how long these tasks usually take, minus the development.

  • Project Management – this! – 30 mins
  • Architecture of solution – 10 mins
  • Development (Flash) – this is the unknown
  • Design UI – 1 hr
  • Development of wrapper – 15 minutes
  • Back end development (PHP GD) – 1.5 hrs
  • Integration of technologies – 15 mins
  • Make some copy for the app – 30 mins
  • Testing of application with fixes – 30 mins
  • Deployment and training – 5 mins
  • The fuckup factor – 10% – 45 mins

Re-read this list a few times, just to make sure you haven’t forgotten anything. This should now really frighten us because we have 7 hours total and suddenly all the little stuff is 5 hours giving us only 2 hours to develop the solution with flash. Fortunately, there is some wiggle room in our plan, so let’s say 2.5 hours. Never leave out the fuckup factor! Internal developers tend to be very optimistic estimators, they almost never go the other way. On the other hand external developers tend to go the other way – either through experience or because they want to charge more for the work than it’s going to take, this second option I have seen a lot and is usually the case where the project manager has no technical background. Be warned.

In the time alotted we have to code the following main tasks:

  • Upload a graphic from the users hard drive (20)
  • Load the graphic into a holder to be manipulated (10)
  • Provide a UI for the image manipulation (45 + **)
  • Create the correct data as argument to the PHP (15)
  • Access the back-end PHP to convert the new graphic (10)
  • Load the new image in (with option to revert) (10)
  • Either notify with the new graphic, or regress some steps (10)
  • Allow an option to repeat the process (5)

Notice the image manipulation gets a **, this is where we want to add as much extra stuff as possible, so this will be the 2nd evolution (if there is time) of the application after everything else is in place and functional. In reality, we have been doing this in our head and on the doodle pad in front of the client and at this point we need to go back and discuss this, with an emphasis on increasing the time limit to provide extra options on the image manipulation. Let’s assume for the exercise that we cannot change the timescales.

Next, let’s make a quick check on risks – here’s the main list for this project – time / resources / quality / cost – time here is the main objective and so we need to really make sure we are keeping to schedule. If at any point we start to eat into our fuckup factor it’s probably worthwhile communicating this with the client, maybe try to apply some more resource. The resource could get sick, in which case again we need to then think about replacing me and as always talk to the client. Quality is a possible escape hatch as its an internal project so it doesnt have to be sooper pretty. In other words we will leave pretty to last and see how it all goes which means a possible saving on the design allocated time.

So, here we are. We have a defined project with tasks and a timeline, a possible two sprints, the client has ROI, the resources and technology is in place. Let’s sign this baby up and get to work.

TO start with, because we are going to be uploading to the server, lets get that baby sorted out first, I am going to do a fixed screen 900×600 just for ease, so we can get started by creating a directory, the wrapper and the flash file imagemanip1.fla (always always always use numbered incarnations, as many as you want but in reality as soon as you reach a point where you are about to start a new phase, or something works, save and increment, usually once every 30 minutes for me. I also create a new incarnation at the start of every day as well) Also, as a quick tip I always develop using microsoft IE, as it’s the weakest browser, but also becuase theres a really handy option to never cache anything in the settings which means we know we will always be working on the latest version online. Part of the testing phase will be browser compatability as well as flash player compatability – but later on this.

Create a local directory, create a target directory on the server. Create (or copy) an index.html file to work with, create the start flash file imagemanip1.fla and let’s set the publish settings correctly (no HTML req’d) to the flash 9 player and set it to a different swf filename – say swf1.swf – that way we can increment the fla as much as we want for backups but never need to reset the swf name in publish settings as we are developing. Stick a copy of SWFObject in there too, I use version 2.1 as its very stable and also has good compatability with swfaddress. Finally, we need to look at the html file to make sure it’s set up correctly.

In this case as we are working on a fixed size of swf file we will most probably want to centre it on the browser screen. There are tools out there and many sites offering loads of different methods for doing this. I even have a javascript function somewhere which I wrote that dynamically resizes as well as centres (check out the pupu game on the portfolio and look at the index.html source to see this) and re-scales the flash if the screen is smaller than the swf. In this case the client’s screen size is known, so a centre operation will do. My method to centre is very simple, I have the SWFObject which if successful will replace a simple text or image DIV with the swf. This content is surrounded by an HTML table of 3x3x3 cells all of which have a non-blank space in apart from the middle which is our content. The centre cell has an align on it to centre the content and that’s it, that simple.

The development environment I am using is going to be on the CS4 IDE (because I am working in front of the TV on the laptop and not in the batcave) on the timeline and its going to be dirty. At the concept stage of any project we are not worried about clean code, optimisation, extendability, design patterns or OOP principles. The only thing that concerns us is the technology of the solution and getting it to work. For much larger projects we will of course need to think about these things, but not at the start, all of your focus should be on the problems and not the packaging. Another reason for this is that whilst you are hacking away at the prototype solution, patterns will begin to emerge, clearly defined objects and abstract layers and singletons. Another tip is to create all of the prototype functionality on the same SWF, but keep the code seperate to begin with on seperate layers with titles so you know where everything is.

This is a good stopping point for stage 1, allow you the chance to grab some food, set up your environment and when you are ready we can start hacking into part 2.

Posted in AS3, Flash | Tagged , | Leave a comment