Aug 8

Dynamically Resizing a Flash Application Vertically

Category: Right-Brain, Flash, Solution

Recently I’ve had the pleasure of developing a new dynamic navigation piece for the University we work for. This currently consists of a collection of somewhere around 300 separate Flash movies, and is obviously a challenge to maintain.

When originally tossing around ideas to complete this task, we rejected a javascript / css approach because the font we were required to use wasn’t standard. The navigation for the school’s site is enormous and complex, so an image solution is obviously a no-go as well. So, the (questionable) wisdom of our crew and The Whole Brain (Left and Right hemispheres, UNITE! Geek powers ACTIVATE! Form of a MICROPROCESSOR!) dictated that we go with a solution using Flash for the nav interface, our existing Postgres database to store all the info, and a Ruby on Rails application to populate the DB and serve the menu contents to the Flash navigation via XML. Yay! Sounds great…

Whooped my tired ass to implement. Let me tell you why, one problem at a time.

1.) Flash movies cannot resize from within.

I needed this thing to dynamically resize itself vertically. I didn’t even give this a second thought initially, and that was a mistake. (though not a big unrepairable one, also known as a “you’re fired” bug. Hate those. ) I thought this was going to be the most rudimentary ActionScript api call ever. I was wrong. So I scoured the web, no answers. Found a few people saying things along the lines of “can’t”, but with all the disparate technologies we have to work with on the web, I just wasn’t accepting this. So I pulled out my thinking cap, my JavaScript Super-Bible 9000, and got to work.

Long story short for everyone who got bounced here from Google and need the quick answer: yes, you can do this, but it requires a little bit of weirdness, and if you can stand a little “flash” when your movie loads (think camera flash, not Macrodobe Flash), it gets simplified. If you’re a perfectionist as we tend to be around these parts, well, it gets even a little more kludgy. But, it works, and the people upstairs could really care less about how kludgy I think my solution is… With that nice wordy intro behind us, here’s how to make it happen.

On the page that needs this resizing movie, I have one single JavaScript function call, and two external JavaScript files pulled in. One has all my code, and the other is a nice little library that is located here:

http://blog.deconcept.com/swfobject

Grab the download over there, and yank out swfobject.js and throw it in your working dir.

If you are dealing with Flash, this script makes movie deployment to the page way more pleasurable, but even more than that, it gets rid of the Internet Explorer issue that requires users to click the movie before it starts doing anything (ooooh, I feel so… protected. Trojan, eat your heart out.) AND gets rid of that ridiculous border with no user intervention. For the price (free!) you can’t beat it. It does some other neat stuff too, so check it out.

As of now, we have our .html file (or whatever variant: php, asp, rhtml, it really makes no difference), our custom js file (which I named flash.js), and our swfobject.js file from deconcept. If you need code for this, fine, be that way you lazy monkey. Here’s what should be in your <HEAD> somewhere:

1
2
<script src="/javascripts/swfobject.js" type="text/javascript"></script>
<script src="/javascripts/flash.js" type="text/javascript"></script>

See, that’s not so bad! (yet…)

The next thing you want to do, is set up a DIV element on your page where you want your movie to show up. Using a DIV keeps the area flexible, easy to target, and just so happens to be the way swfobject.js is designed to work. Within that DIV, we are going to put the single call to our super-do-it-all function. We will also give our DIV an id of our choosing. I choose “dynamovie”! Here’s the code, add it to your HTML file.

1
2
3
4
<p id="dynamovie">
<script type="text/javascript">
  showMovie();
</script>

See, that was easy as well! (for now.)

For our purposes, our work with the HTML file is complete. Now we move on to the meat, the flash.js file.

This is where we start to get naughty. What we’re going to make happen here is this: the Flash movie loads, by the time it’s done, it knows what it’s height should be. At this point we call to the JavaScript super function from within our Flash movie using getURL, and build it all over again, but this time, displayed at the correct size. Neat huh? The only problem is, this reload is what causes that flash (think lightning) I warned you about. Lets start with our custom flash.js script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
var DESTINATION_DIV_TAG = "dynamovie";
 
function randomXDigitNumber(size) {
 
    return Math.floor(Math.random() * (Math.pow(10,size)));
 
}
 
function whack(str_to_whack, num_chars_to_whack) {
 
    if (str_to_whack.length &lt;= num_chars_to_whack) {
        return "";
    }
 
    return str_to_whack.substr(0, str_to_whack.length - num_chars_to_whack);
 
}
 
function showMovie(height) {
 
    // Fake default args.
 
    var height = (height == null) ? 0 : height;
 
    // set a flag as to whether this is the first time through (with no height)
    // or the second (with height already calculated and passed back in.)
 
    flag = "true";
 
    if (height == 0) {
 
        flag = "false";
 
    }
 
    random = randomXDigitNumber(6);
 
    var movie_url = "/dynamovie.swf?r=" + random + "&amp;flag=" + flag;
 
    var so = new SWFObject(movie_url, DESTINATION_DIV_TAG, 150, height, "6", "#0F1D4E");
 
    so.write(DESTINATION_DIV_TAG);
 
}

We have three functions in this file, two are just helpers, but the one we are concerned is showMovie(). If you’ll scroll to showMovie() function, we can go over it a bit.

The first thing we deal with is default arguments for this function. This basically makes things simple on our web page by allowing us to not think about parameters for this function when we don’t need them. If you have no idea what’s going on with that, do a search for “JavaScript default function arguments” and you’ll get enlightened. In short, it sets things up so that if no argument is passed in, our “height”argument will have zero, just like you had passed it in yourself. We do need this argument, because when we re-call this function from WITHIN the Flash movie, we need to let it know that we actually DO have the height, so use it, and DON’T call the function recursively again, because that would just get us stuck in a loop, right? And enough of life is already like that…

The next portion is just some simple code to set up a flag that we use to decide if we should call in again later. (Yes, this could be written more simply. For the couple bytes it takes, it keeps it clean and understandable. It’s like comment-in-code, know what I’m sayin’? :-))

Next, we generate a random 6 digit number just to make sure that when our Flash movie is re-called from our Function, it actually applies our params, and doesn’t just reshow us the same movie from cache. (Which in my case, caused it to NOT reload it’s XML from the server.) Depending on your circumstances, you may be able to remove that if you really don’t want it, but all it’s harming is a couple bytes of ram and a minute number of cpu cycles.

Next we build up a string pointing to the location of our Flash movie on the server. We then use a function from our magical swfobject.js script to build, then display our movie. Simple enough, right?

Now, here’s the big, silly trick. This stuff runs, and your Flash movie gets called and revved up. I built this up in 99% actionscript, and as I’m building my dynamic movie in code (working from the top of the movie down), I’m using a variable to keep track of the height of the movie. By the time I’m done creating my nav, I have the exact height my movie is! (albeit a little late, as the HTML is already built that states how big my movie is, so that’s what we’re gonna try to square up now).

Now, the last part of this rig is the code to use in your ActionScript, which is super-simple. The (slightly) challenging part will be for you to develop your movie so you know the actual height when you’re done. This is beyond the scope of our problem here, and there is a lot of great ActionScript info out there, go exploring. In the past few months quite a few good ActionScript 3 and Flex books have hit the shelves as well, don’t be afraid to poke around those either.

So in the bottom of your Flash movie ActionScript code, you want to do something like this:

1
2
3
4
5
6
7
8
// if the height of our movie doesn't equal what we thought it should have been, we need to
// re-call our function and redisplay...
actual_y = Math.round(actual_y);
 
if (actual_y != navheight) {
  // this javascript function stores the new height, then redisplays.
  getURL("javascript:showMovie(" + actual_y + ")");
}

The navheight variable is what got passed in to Flash from the movie URL. The first time through, this is going to be zero, the default JavaScript param, remember that? We check to see if that is equal to what our calculations decided the size of this movie REALLY is, and if it isn’t, it means we need to call back out to our JavaScript function again, and feed it our calculated height, and it will redisplay. If it IS the same, then we know we’re done! All the magic here happens thanks to our good buddy, the getURL() Flash API call.

The first time through, when the movie displays, it will not have the correct height, but it WILL display some of the movie. When the JS function gets called again, there is that quick blink I told you about, but it’s really fast, and not too bothersome in most situations, especially for quick jobs that not too many people will see, like back end applications.

That’s about it for part one of this series. That’s a decent amount to digest! The whole key to dynamic resizing is understanding the reasoning behind the recursive showMovie() function, and what’s happening in the Flash movie. This is NOT a complete example, there are lots of holes to fill in to make this code run, but I’m sure you understand the philosophy of what I’m doing with this now.

Good luck, and I’ll c-ya in the next article where I show you how I used this solution, a field in a database, and a little touch of Ruby on Rails to eradicate that bothersome blink! (Go ahead and try to figure it out yourself if you need it right now, you know it’d be a great exercise, and I gave you all the clues you need!)

Until next time, keep on keyboardin’ code soldiers!

1 Comment so far

  1. vinh August 28th, 2007 10:24 am

    I have a flash that starts out as 100px height, then expands to 400px height when an action is clicked. It would be great if the flash knew what size it is so it doesn’t take up 400px of space when it is only 100px.
    However, this is not the case. The flash is always 400px. I am thinking of using JavaScript to fix this problem with some fancy expand/collapse function done on the JavaScript side. ( without modifying the flash )
    Do you think this is possible, or do I have to eventually modify the flash like you did.
    Great write-up. I am thinking I will probably have to cave and use your method. Thanks!

Leave a comment

*
To prove that you're not a bot, enter this code
Anti-Spam Image