Travels

Tuesday, July 22, 2008

Acessibility in AS3

I've recently finished up a batch of Flash projects that were written using AS3 and needed to be 508 compliant (government-mandated accessibility). Since virtually everything I make at work must be accessible, I made a class to make adding accessibility much easier. Over the past couple of months I've been using it and refining it to handle all the problems I've come across. Now in hopes of encouraging accessibility and simplifying the process of learning how to do it, I'm making my accessibility class open source (GNUv3 license). You can download the accessibility class at:
http://code.google.com/p/accessible/

I've also included some great links are there for finding most anything you might need to know about accessibility. Documentation is also available on the wiki and as a .pdf in the download.

You can see my earlier post on Accessibility for some information on doing accessibility in As2.

If you want to get started in accessibility I highly recommend reading Bob Regan's whitepaper.
It covers AS2 but the issues with accessibility are pretty much the same. Then download my Accessible class for AS3 and look through the links on my wiki. Finally if you need to look up something specific try my Flash Developer Search, it only searches sites with Flash related content and is one of my favorite tools as a Flash Developer.

As far as the features I've given the Accessible class, my favorite is automatic assignment and organization of tabIndexes. It also will format text to be read properly by a screen reader and provides tools such as keyTrace which make looking up key codes very simple. I wrote this class to reduce the problem of spaghetti code that often is created by adding accessibility to existing projects. It does a good job of reducing the lines I need to write but always take time to thoroughly test your projects using a screen reader and the keyboard for navigation. Often it is when I turn of my monitor and try to play one of my games I realize how adding simple things like audio cues can make a game much more easy to play.
You can see some of my accessible projects at the MedlinePlus interactive world map and the games for the National Library of Medicine's exhibit "Against the Odds". Without a screen reader you will be able to navigate using a keyboard, and with an active screen reader you will hear audio cues and descriptions to help you play the games.

Friday, July 11, 2008

WeatherBug API Part 2: A lesson in Regular Expressions

Since my last post I've been working on a WeatherBug widget. I had some extra time to work on it so I thought I'd do something cool and make a series of particle behaviors to illustrate different weather patterns. You can see the finished product here: http://www.sizzlepopboom.com/open_source/weatherBug_2.html

This widget animates the weather patterns, allows you to change location by entering in a zip code, links to the forecast page for that area, and in the event of a weather alert, a button will appear which when clicked will open a page for the weather alerts in that area. (I've been using the recent California fires to test the alert system.) This widget is also accessible to the vision and mobility impaired (still testing to ensure ease of use).

Once I created my particles and their behavior patterns, I needed some way to parse through the 176 documented types of weather conditions that were published by WeatherBug and create appropriate behavior for each condition.

I did this by using a series of regular expressions. I made a dictionary set of regular expressions and the results I wanted them to return if there was a positive match. Then I made a function that goes through each expression in a specific order to test the weather. When it tests positive it stops the testing. This is important because changing the order will change which weather pattern is chosen when certain words are searched for. For example if there is a thunderstorm, I want rain and lightning, while if there is a chance of storms I would want rain alone. To make sure thunderstorm is chosen before my rain behavior I put its regular expression before the one for rain. If no matches are found, I default to sunny weather.


Here is a snippet of code:

//tells what type of particles to make
var behavior:String;
//store the search expressions
var tests = new Dictionary();
tests["snowReg"] = /(snow|sleet|freez|frozen|flurr|snowstorm)/i;
tests["snowReg"].result = "snow";
tests["sunReg"] = /(sun|clear|fair)/i;
tests["sunReg"].result = "sunny";
tests["thunderReg"] = /(thunder|lightning)/i;
tests["thunderReg"].result = "thunder";
tests["rainReg"] = /(rain|storm|drizzle|hurricane)/i;
tests["rainReg"].result = "rain";
tests["cloudReg"] = /(cloud|smoke)/i;
tests["cloudReg"].result = "cloudy";
tests["windReg"]= /(wind)/i;
tests["windReg"].result = "windy";
tests["fogReg"] = /(fog)/i;
tests["fogReg"].result = "fog";
tests["hazyReg"] = /(haz)/i;
tests["hazyReg"].result = "hazy";

//store the order you want to test for weather
var testList = new Array("sunReg","thunderReg","rainReg","snowReg","cloudReg","hazyReg","windReg","fogReg");

for (var i = 0; i<testList.length; i++) {
if (tests[testList[i]].exec(condition)!=null) {
behavior = tests[testList[i]].result;
break;
//if no matches then use the default sunny behavior
} else {
behavior = "sunny";
}
}


Here is the list of documented weather conditions.

As I was working on this widget I noticed two things. First there are more weather patterns than what is on this list ("Light Thunderstorms" and "Smoke" are not on the list). Second when you are testing weather patterns, Flash may cache the information so that you don't seem to be getting accurate information. I noticed this when I was working on the widget and a thunderstorm began, but the widget said it was partially cloudy. Restarting Flash solved the problem. Remember this while developing; once the widget is online the weather info will not be cached.


Another thing I did to make the widget cooler was to do another testing of the weather condition to see the magnitude of the weather. I set up three different magnitudes: light, average, and heavy. Then I searched through the weather conditions for words that indicated the amount (heavy, chance, light, etc.). Using this information I changed the number of particles to use for each weather pattern and so the animations change to match both the weather and the amount of precipitation. For a few weather patterns I further manipulated the magnitude to ensure a better looking animation.
Here is the code for determining the magnitude:

//now test the amount of precipitation

var strength:String;
var amount:Dictionary = new Dictionary();
amount["mildReg"] = /(light|chance|scatter|partly)/i;
amount["mildReg"].result ="mild";
amount["midReg"] = /(mostly|increas)/i;
amount["midReg"].result = "average";
amount["heavyReg"] = /(heavy|hurricane|smoke)/i;
amount["heavyReg"].result = "heavy";
var magnitude:Array = new Array("mildReg","midReg","heavyReg");
for (var j = 0; j<magnitude.length; j++) {
if (amount[magnitude[j]].exec(condition)!=null) {
strength = amount[magnitude[j]].result;
break;
} else {
strength = "average";
}
}
//adjust the amount of particles to use

var numParticles:uint;
switch (strength) {
case "mild" :
numParticles = 50;
break;
case "average" :
numParticles = 100;
break;
case "heavy" :
numParticles = 300;
break;
default :
numParticles = 100;
}

A widget and my updated open source WeatherBug class are available here:
http://www.sizzlepopboom.com/open_source/weatherbug.zip

For more information on how to use regular expressions in flash check out Adobe's Regex page: at:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/RegExp.html

To learn more about writing regular expressions here is a good reference:
http://www.regular-expressions.info/reference.html

Finally here is an excerpt from an accessibility class I'm working on. This function prepares text for screen readers by stripping out any tags and capitalizing all lone "a"s and "i"s so screen readers will pronounce them correctly.

//remove any html tags from text so the tags will not be read by the screen reader

function stripTags(htmlText:String) {
var parseText = htmlText;
//Capitalize all a and i for screenreader correctness
parseText = parseText.replace(/\sa\s/," A ");
parseText = parseText.replace(/\si\s/," I ");
//strip tags
return parseText.replace(/<.*?>/g,"");

}