Diogo Freire 01 Apr 2009
With the good bandwidth from nowadays, finding a beautiful Flash site with lots of cool features and animations is a joy. However the reality for many users with low bandwidth is unmanageable load times and frustrating experiences when trying to access the Flash enabled functionality.
In factn Flash can offer a solution to the problem. By taking a sample of the user's download speed it can decide whether to show an application or not. A simplified way of doing this is described below. You may have to adapt the formula on a case-to-case basis.
import flash.external.ExternalInterface;
var time:Number = 5; //the amount of time we want to measure the connection
var bandwidthLimit:Number = 60; //in Kbps (Kbits/second)
//function to calculate the kbps
function getkbps(elapsedTime,sizeInBytes) {
//bandwidth on internet are measured in bits/second, so we convert bytes to bits
//then we divide for 1024 and convert it to Kbits
var sizeInKBits = sizeInBytes * 8 / 1024;
//TCP/IP uses around 7% of the bandwidth to manage itself, so we take it off.
var kbps = (sizeInKBits/elapsedTime) * 0.93 ;
return kbps;
}
//Start all variables just once, as we have a 2 stages preloader working on the timeline when this example was written
if ((typeof startTime) == "undefined") var startTime = getTimer();
//exclude what is already loaded (out of the beginning of the timer) from the math
if ((typeof initialLoad) == "undefined") var initialLoad = stage.loaderInfo.bytesLoaded;
if ((typeof keepgetkbps) == "undefined") var keepgetkbps=true;
//get variable from the root to check if we want to load the preloader anyway or not
var flashvars:Object = LoaderInfo(this.root.loaderInfo).parameters;
var letLoad:String = flashvars['letLoad'];
//Event handler
function checkBW(event) {
if(keepgetkbps && letLoad != "true") {
if(stage.loaderInfo.bytesLoaded < stage.loaderInfo.bytesTotal){ // not yet loaded
//get time difference from the start of the swf loading and now
var elapsedTimeMS:Number = getTimer() - startTime;
//get time comes in miliseconds so we convert it
var elapsedTime:Number = elapsedTimeMS/1000;
var kbps=getkbps(elapsedTime,stage.loaderInfo.bytesLoaded-initialLoad);
//if we reached the time limit for testing...
if(elapsedTime>time) {
//stop measuring (fall back in case flash already piped another call to checkBw)
keepgetkbps=false;
//remove event
removeEventListener(Event.ENTER_FRAME, checkBW);
//if the detected bandwidth is less then what we want, take care with javascript
if(kbps<bandwidthLimit) {
ExternalInterface.call("loadAlternateFlashContent");
}
}
} else {
//if it's loaded already remove the event
removeEventListener(Event.ENTER_FRAME, checkBW);
}
}
}
//add the event if we don't want to load it anyway
if(letLoad!="true") addEventListener(Event.ENTER_FRAME, checkBW);
The comments next to the code make it pretty straight forward to understand. The JavaScript function "loadAlternateFlashContent()" completes the deal by loading the alternate lighter content for the user. Additionally we can add a cookie to the users browser so we never load the flash again (unless the user wants too!)
The JavaScript handler can be applied like this:
var contentBeforeFlash;
//here using the old swfObject
//and considering the #flash_wrapper is our div of choice to hold the flash (and the alternate content!)
//function to load the flash
function loadFlash(reloading) {
//check if the cookie is not set or the user is not forcing the flash load
if(readCookie("lowbandwidth")!="true" || reloading==true) {
//save the old div content
contentBeforeFlash = document.getElementById("flash_wrapper").innerHTML;
//clean the cookie
eraseCookie("lowbandwidth");
//load the flash
var flashLoader = new SWFObject("flashWithBWDetection.swf", "flash_wrapper", "200", "220", "9", "#000000");
//if we're forcing reload we let flash know so it doesn't use the bandwidth measurement
if(reloading!=undefined && reloading==true) flashLoader.addVariable("letLoad", "true");
flashLoader.write("flash_wrapper");
}
}
//auxiliar function if you have a button like "Load Flash anyway, event though my connection is slow" on your alternate content
function reloadFlash() {
loadFlash(true);
return false;
}
//function called by the flash
function loadAlternateFlashContent() {
//set the cookie
createCookie("lowbandwidth","true");
//reset the content
document.getElementById("flash_wrapper").innerHTML = contentBeforeFlash;
}
//from quirksmode
function createCookie(name,value,days) {
if (days!=undefined) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function eraseCookie(name) {
createCookie(name,"",-1);
}
Improving and tweaking all the code for your application should make it work better and look more beautiful, getting the right kind of connection with the right content. You can even choose which features to apply inside Flash itself. Just find the bit of function you need and boost it up.
See you all next time!
Read the next post - Choosing a JavaScript framework - will it fly?