Matt RaibleMatt Raible is a Java Champion and Developer Advocate at Okta. developer.okta.com

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

Scaling Flash Movies to match Browser Zoom Levels

Recently I was tasked with figuring out how to scale the Flash assets in the web application I'm working on. In the app, there's two different Flash assets: a Spotlight (cycles through images) and a Video Player. Before I started working on the issue, our assets would stay the same fixed size no matter what the browser zoom level. You can see this issue in action by going to Hulu or Fancast and zooming in/out (Command +/- on Mac, Control +/- on Windows). The Flash assets don't scale with the browser's text.

I found a lot of references for how to trap and handle resizing in JavaScript, so that's the initial path I took. I ended up having issues trapping the resize event in IE, as well as persisting the appropriate zoom level on page reload. Because of this, I ended up using a pure ActionScript solution that works much better. This article shows how I implemented both solutions.

Regardless of implementation, the first change I had to make was to move the height and width from the Flash asset (object/embed/JS) to its surrounding tag (<section> in our app). Then I changed the height/width to 100% on the Flash asset.

JavaScript Implementation
To allow zooming in ActionScript, I modified our main class to expose a "zoom" method to JavaScript:

ExternalInterface.addCallback("zoom", _zoom);

...

private function _zoom(scale:Number):void {
    _view.scaleX = _view.scaleX * scale;
    _view.scaleY = _view.scaleY * scale;
}
In the code above, _view refers to the container that holds all the items in the player. To call this method in JavaScript, I added the following code:

var windowHeight;
var documentHeight;

$(document).ready(function() { 
    ...
    windowHeight = $(window).height();
    documentHeight = $(document).height();

    $(window).resize(resizeWindow);
}

// Resize Flash assets when page is zoomed
function resizeWindow() {
    var newWindowHeight = $(window).height();
    var newDocumentHeight = $(document).height();
    // if document height hasn't changed, it's a browser window resize
    // event instead of a text zoom - don't change anything
    if (newDocumentHeight === documentHeight) {
        return;
    } else {
        documentHeight = newDocumentHeight;
    }
    var scale = (windowHeight / newWindowHeight); 

    var player = getFlashMovie('playerId');
    if (player && player.zoom) {
        player.zoom(scale);
    }
    var spotlight = getFlashMovie('spotlightId');
    if (spotlight && spotlight.zoom) {
        spotlight.zoom(scale);
    }

    windowHeight = newWindowHeight;
}

This seemed to work well in Firefox, Safari and Opera, but not in IE. I found this explanation about why it might not work, but I was unsuccessful in getting IE to recognize a resize/zoom event.

To fix scaling in our Spotlight asset, I used a similar solution. However, since the Spotlight didn't have all its elements in a container (they were being added directly to the stage), I had to refactor the code to add a SpotlightView (extends Sprite) that contains the bulk of the code.

Browsers persist the zoom level you've set for a site. The problem with the solution used here is it only scales up and down properly if you start from scale = 1 and revert to scale = 1 before leaving the site. If you zoom in and close your browser, when you come back the flash movies will be scale = 1 while the rest of the site is zoomed in. To solve this problem, I attempted to save the scale value in a cookie. This worked, and I was able to read the cookie in the *.as files to scale the movie correctly. However, I experienced some issues with this approach and didn't like having to delete cookies when I wanted the Flash assets to scale correctly.

ActionScript Implementation
After discovering issues with the JavaScript implementation, I did some research to see if it was possible to listen for the browser resize event in ActionScript. The Flash Fluid Layouts and Stage Resize in AS3 tutorial clued me in that the stage could listen for a resize event.

stage.addEventListener(Event.RESIZE, resizeListener); 

After adding the above line in the initialization, I added a resizeListener function that scales based on the default dimensions. It also ensures no scaling happens in full screen mode.

private function resizeListener(e:Event):void {
    // don't scale if entering full screen mode
    if (stage.displayState == StageDisplayState.FULL_SCREEN)  {
        _view.scaleX = 1;
        _view.scaleY = 1;
    } else {
        _view.scaleX = stage.stageWidth / 964;
        _view.scaleY = stage.stageHeight / 586;
    }
}

For the Spotlight asset, there are a number of different layouts (home, featured and news). The main class has a resizeListener function that scales accordingly to which layout type is being used.

private function resizeListener(e:Event):void {
    var type:String = _view.getLayoutType();

    if (type == "featured") { 
        _view.scaleX = stage.stageWidth / 958;
       _view.scaleY = stage.stageHeight / 180;
   } else if (type == "home") { 
        _view.scaleX = stage.stageWidth / 964;
        _view.scaleY = stage.stageHeight / 428;
    } else if (type == "news") {
        _view.scaleX = stage.stageWidth / 964;
        _view.scaleY = stage.stageHeight / 189;
    }
}

Because the layout type isn't set until the XML is loaded, I listen for that event in my URLLoader.

xmlLoader.addEventListener(Event.COMPLETE, resizeListener);

With the pure ActionScript implementation, the zoom level is automatically persisted. The Event.RESIZE event is fired by the Flash plugin when the page first loads if the dimensions are not the default.

That's it! Special thanks to James Ward for clueing me into scaleX and scaleY. Hopefully Hulu and Comcast can use this tutorial to scale their video players too. ;-)

Posted in The Web at Jul 13 2010, 12:18:42 PM MDT 9 Comments
Comments:

Hi Matt, it's been a while.

Hulu is based on OVP (an sf.net project) to which I am a committer, and I'd like to patch it. I do trust you that you found a problem. Trouble is I don't understand the problem, when you say "The Flash assets don't scale with the browser's text."

Do you have a screen shot you can email me of the problem.

.V

Posted by vic cekvenich on July 18, 2010 at 11:40 AM MDT #

Vic - it has been awhile, good to hear from you again. To reproduce, go to Hulu and zoom out using Ctrl- (on Windows) or Cmd- (on Mac). The Flash asset stays the same size. Same thing if you zoom in.

I uploaded a zoomed out screenshot to Flickr.

BTW, how do you know Hulu is based on OVP?

Posted by Matt Raible on July 19, 2010 at 10:09 AM MDT #

some cut and paste error in your post, I believe. You posted the action script snippet in the "javascript implementation" and vice versa.

Posted by A.L. on August 19, 2010 at 11:54 AM MDT #

A.L. - I believe the confusion was caused by the two ActionScript Implementation headings. I removed the first one. The JavaScript implementation uses JS to manipulate size, the ActionScript implementation uses AS (with no JS) and works much better.

Posted by Matt Raible on August 19, 2010 at 11:59 AM MDT #

Matt, What is the _view reference to -- is it a movieclip, or textfield, or something else?

Posted by Daniel on September 16, 2010 at 12:49 PM MDT #

I'm sorry, I see that _view refers to the container that holds all the items in the player. How is this container referenced in AS3?

Posted by Daniel on September 16, 2010 at 12:52 PM MDT #

@Daniel - In my main class, there's a private var that holds the view and then it's instantiated in the class's initialization. The view class extends Sprite.

Posted by Matt Raible on September 30, 2010 at 03:07 PM MDT #

I had the same problem, but I fixed it by using scale="exactFit" from the embed tag in HTML.

Posted by Samah on February 17, 2011 at 12:05 AM MST #

Thanks for your posting. Any suggestions for full browser flash? http://stackoverflow.com/questions/5024493/browser-viewport-size-in-device-pixels

Posted by erik on February 22, 2011 at 10:01 PM MST #

Post a Comment:
  • HTML Syntax: Allowed