Sunday 7 November 2010

Week One - Map design and Development

Map Development

Weekly Targets
  • Load the necessary weather RSS feeds used by the Map into flash
  • Edit and store the information extracted from the RSS feeds as a usable format
  • Create a mock up of the major functionality of the Map
  • Design the visual layout \ mock ups of the Map

The first week i spent designing and developing  the map aspect of my project. The map is the link between the different weather conditions which the user grows there garden with. The data used to create the weather conditions is completely dynamic and are representations of  RSS weather feeds from yahoo weather.  The major goal for this week was to load the RSS feeds into flash then use that data to populate the map.


The maps data such as the name of the location and its position on the screen for example is static data and cant be added to or changed dynamically so I've decided to store the data into an array and load the data into flash every time a user visits the site. The current data at this stage includes the locations name, the numerical code that yahoo uses to define each town or city , the X position of the location on the map and the Y position of the location on the map. An example of how the code looks for populating the array is as follows.
userMapArray[0] = ["Aberdeen","10243","10","50"];

Once id populated the array i started to develop the way in which the Map is going to use the the RSS XML feed. The first problem would be to create two conditions, the first which would continually loop the feed loading function , then, stop once all the necessary data had been loaded. Then a second condition to create the movieclips for each location which would be the point of interaction between the map and the user.


The simplest technique would be to run the functions in a for loop. But whilst doing this i noticed that the for loop actually ran quicker than the speed at which flash could load in the data from the RSS feeds even though the for loop would only loop if the RSS feed had completed loading. The major problem with this is that the weather conditions were being applied to the wrong locations ,so, instead of using a for loop i simply incremented a number every time the loading code had been processed.


function loadMap() {

    var weatherUrlLoader:URLLoader = new URLLoader();
    var weatherUrl:URLRequest = new URLRequest("http://weather.yahooapis.com/forecastrss?w="+ userMapArray[u][1]);
    weatherUrlLoader.load(weatherUrl);

    trace(weatherUrl.url);

    weatherUrlLoader.addEventListener(Event.COMPLETE,rssLoaded);

    function rssLoaded(e:Event) {

        var xml:XML=new XML(e.target.data);

        rssXML=xml.channel.item;

        xmlLength=rssXML.length();
      
        //weatherStringTest = rssXML;

        weatherString = rssXML.description;

        var weatherArray:Array = weatherString.split(">");
        weatherArray.splice(0,5);

        weatherString = "";

        weatherString = weatherArray[0];

        weatherArray = weatherString.split(",");

        weatherArray.splice(1,2);

        weatherString = weatherArray[0];

        userMapArray[u][4] = weatherString;

        weatherString = "";

        u++;

        trace(rssXML.description);

        }
    }
}

In the above code the URLRequest loads in a pre set string plus data which is stored in the previously created array. The array is multidimensional so each index in the array has its own secondary array. The number in the first bracket userMapArray[u] is the index in the array with the second number userMapArray[u][1] being its index in its secondary array. The index always starts at 0 so if its 1 it gives us the unique number at which the specific location is defined. For example :

 var weatherUrl:URLRequest = new URLRequest("http://weather.yahooapis.com/forecastrss?w="+ userMapArray[u][1]);
is exactly the same as


 var weatherUrl:URLRequest = new URLRequest("http://weather.yahooapis.com/forecastrss?w="+ 10243);

which gives me the URL of Aberdeens RSS feed. Now that the Rss Feeds were being loaded in i created two very simple if statements which looked like the following:

 if (u == userMapArray.length) {

            addClips();

        }
      
        if (u<userMapArray.length) {

            loadMap();
For the first condition, if the number being incremented ever equals the length of the array it will process a function called addClips which adds movieclips to the map so the user can then interact with the it.

For the second condition, if u is ever less than the length of the array it will always process the load function. As soon as its equal or greater to the length of the array it will ignore it. Both these statements work together just like a for loop but its far slower, giving time for the rss feeds to load appropriately to the correct location.

Now that the feeds had been loaded i needed to manipulate the data from them.  All the information is in one node which made it slightly more difficult to obtain as opposed to them being in  separate individual nodes which i could access by the nodes name. At present the data would look look like the following:
<img src="http://l.yimg.com/a/i/us/we/52/20.gif"/><br />
<b>Current Conditions:</b><br />
Fog, 50 F<BR />
<BR /><b>Forecast:</b><BR />
Sun - Rain. High: 55 Low: 45<br />
Mon - AM Rain. High: 54 Low: 44<br />
<br />
<a href="http://us.rd.yahoo.com/dailynews/rss/weather/Milan__IT/*http://weather.yahoo.com/forecast/ITXX0042_f.html">Full Forecast at Yahoo! Weather</a><BR/><BR/>
(provided by <a href="http://www.weather.com" >The Weather Channel</a>)<br/>
The only part of this data i will need to use is the current condition, in this example its:
Fog
To retrieve the data i wanted to use i firstly stored the RSS feed  into a string and pushed the data into an array. The second step was to search for a pattern within the data, if i could find a pattern within the data i have a point at which to split the data up from. I noticed the data was put into brackets (< />) so using the > as the splitting point i cut the data up from each > and pushed that back into the array, creating a new index for the array which gave me the opportunity to access data i needed.  Finally i spliced the array to remove the data i didn't need which left me with Fog, 50 F<BR />. Using the exact same process but this time using the , as the splitting point i again cut the remaining data up, pushed it back into the array then spliced the array to remove the data i didn't need which left me with fog. All the RSS weather feeds are structured in the same way even though the data is completely different which means that no matter what the weather feed looks like ,when loaded into flash, it will always retrieve the same information. I then stored the weather condition into the appropriate array using the following code

userMapArray[u][4] = weatherString;

Again using the incremented number to pick out the correct index in the array and because there are only 4 levels inside each index this would be added to the 5th level.

Now that i had created all the data i'd need at this stage i was ready to create the movieclips so the user could interact with the map and choose there desired location. Because i now have all the data loaded into flash already, using a simple for loop, i cycled through each index of the array, creating a new movieclip which would be the point of interaction between the user and the map using the details in the array as the movieclips properties such as its x and y properties. Then finally creating an event listener which when clicked would give me the URL of the main RSS feed of the clicked location which will load the data for the weather in the main application.

function addClips() {

    for (var l:int = 0; l<userMapArray.length; l++) {

        areabtn = new Areabtn();
        addChild(areabtn);
        areabtn.x = userMapArray[l][2];
        areabtn.y = userMapArray[l][3];
        areabtn.locationNameTxt.text = userMapArray[l][0];
        areabtn.woeidTxt.text = userMapArray[l][1];
        areabtn.weatherCon.text = userMapArray[l][4];
        areabtn.name = userMapArray[l][1];

        areabtn.addEventListener(MouseEvent.CLICK,grabUrl);

}

The final stage of the process is to create a small visiual representation of the the RSS feed to indicate what the the weather conditions are at the currently selected lcoation. To do this i ,again, used if statements to search the index in the array looking for a pattern of letters. For example:

if (userMapArray[l][4].search("Rain") == true) {

            trace("It is raining in "+areabtn.locationNameTxt.text);

        }

If the pattern in the array was equal to Rain for example it would process the code in the brackets, in this case it traces back a message but my intention for the final version of the map would be flash to load a visual indication such as an image or an animation onto the map.


The finished code for the first protype looked like the following:

var areabtn:Areabtn;

var addLocationArray:Array = [];
var userMapArray:Array = [];
var weatherMapArray:Array = [];

var weatherString:String = "";
var weatherStringTest:String = "";

var rssXML:XMLList = new XMLList();
var xmlLength:Number;
var u:Number = 0;

stage.frameRate = 30;
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;

//UserMapArray Layout = Name,Long\Lat,positionX,positionY

//Scotland

userMapArray[0] = ["Aberdeen","10243","10","50"];
userMapArray[1] = ["Glasgow","21125","90","50"];
userMapArray[2] = ["Edinburgh","19344","170","50"];

//England

userMapArray[3] = ["London","44418","239","559"];
userMapArray[4] = ["Manchester","28218","209","501"];
userMapArray[5] = ["Birmingham","12723","186","547"];
userMapArray[6] = ["Cardiff","15127","490","50"];
userMapArray[7] = ["Leeds","26042","570","495"];
userMapArray[8] = ["Liverpool","26734","195","503"];

//Northern Ireland

userMapArray[9] = ["Dublin","560743","146","502"];
userMapArray[10] = ["Cork","560472","10","150"];

//Republic of Ireland

userMapArray[11] = ["Belfast","44544","158","460"];

//Portugal

userMapArray[12] = ["Lisbon","742676","14","859"];
userMapArray[13] = ["Porto","746203","34","791"];

//Spain

userMapArray[14] = ["Mardid","766273","124","842"];
userMapArray[15] = ["Barcelona","753692","247","817"];
userMapArray[16] = ["Sevilla","774508","64","895"];
userMapArray[17] = ["Zaragoza","779063","186","830"];
userMapArray[18] = ["Valencia","776688","186","865"];

//France

userMapArray[19] = ["Paris","615702","264","625"];
userMapArray[20] = ["Monaco","483301","347","670"];
userMapArray[21] = ["Lyon","609125","309","717"];
userMapArray[22] = ["Bordeaux","580778","202","713"];
userMapArray[23] = ["Nantes","613858","187","660"];

//Belgium

userMapArray[24] = ["Brussels","968019","306","583"];

//Holland

userMapArray[25] = ["Amsterdam","727232","410","250"];
userMapArray[26] = ["Rotterdam","733075","490","250"];

//Switzerland

userMapArray[27] = ["Zurich","784794","570","250"];
userMapArray[28] = ["Geneva","782538","650","250"];

//Italy

userMapArray[29] = ["Naples","719258","730","250"];
userMapArray[30] = ["Rome","721943","10","350"];
userMapArray[31] = ["Milan","718345","90","350"];

//Norway oslo begren

userMapArray[32] = ["Oslo","862592","170","350"];
userMapArray[33] = ["Hammerfest","859348","250","350"];

//Sweden

userMapArray[34] = ["Stockholm","906057","330","350"];
userMapArray[35] = ["Kiruna","895313","410","350"];

//Finland

userMapArray[36] = ["Oulu","568568","490","350"];
userMapArray[37] = ["Helsinki","565346","570","350"];

//Iceland

userMapArray[38] = ["Reykjavík","980389","36","165"];

//Austria

userMapArray[39] = ["Vienna","551801","730","350"];

trace(userMapArray);

loadMap();

function loadMap() {

    var weatherUrlLoader:URLLoader = new URLLoader();
    var weatherUrl:URLRequest = new URLRequest("http://weather.yahooapis.com/forecastrss?w="+ userMapArray[u][1]);
    weatherUrlLoader.load(weatherUrl);

    trace(weatherUrl.url);

    weatherUrlLoader.addEventListener(Event.COMPLETE,rssLoaded);

    function rssLoaded(e:Event) {

        var xml:XML=new XML(e.target.data);

        rssXML=xml.channel.item;

        xmlLength=rssXML.length();
      
        //weatherStringTest = rssXML;

        weatherString = rssXML.description;

        var weatherArray:Array = weatherString.split(">");
        weatherArray.splice(0,5);

        weatherString = "";

        weatherString = weatherArray[0];

        weatherArray = weatherString.split(",");

        weatherArray.splice(1,2);

        weatherString = weatherArray[0];

        userMapArray[u][4] = weatherString;

        weatherString = "";

        u++;

        trace(rssXML.description);

        if (u == userMapArray.length) {

            addClips();

        }
      
        if (u<userMapArray.length) {

            loadMap();

        }
    }
}

function addClips() {

    for (var l:int = 0; l<userMapArray.length; l++) {

        areabtn = new Areabtn();
        addChild(areabtn);
        areabtn.x = userMapArray[l][2];
        areabtn.y = userMapArray[l][3];
        areabtn.locationNameTxt.text = userMapArray[l][0];
        areabtn.woeidTxt.text = userMapArray[l][1];
        areabtn.weatherCon.text = userMapArray[l][4];
        areabtn.name = userMapArray[l][1];

        areabtn.addEventListener(MouseEvent.CLICK,grabUrl);

        if (userMapArray[l][4].search("Rain") == true) {

            trace("It is raining in "+areabtn.locationNameTxt.text);

        } else if (userMapArray[l][4].search("Fair") == true) {

            trace("It is fair in "+areabtn.locationNameTxt.text);

        } else if (userMapArray[l][4].search("Partly Cloudy") == true) {

            trace("It is partly cloudy in "+areabtn.locationNameTxt.text);

        } else if (userMapArray[l][4].search("Mostly Cloudy") == true) {

            trace("It is mostly cloudy in "+areabtn.locationNameTxt.text);

        } else if (userMapArray[l][4].search("Light Rain Shower") == true) {

            trace("It is raining lightly in "+areabtn.locationNameTxt.text);

        } else if (userMapArray[l][4].search("Drizzle") == true) {

            trace("It is drizzling in "+areabtn.locationNameTxt.text);

        } else if (userMapArray[l][4].search("Light Drizzle") == true) {

            trace("It is drizzling lightly in "+areabtn.locationNameTxt.text);

        } else if (userMapArray[l][4].search("Cloudy") == true) {

            trace("It is cloudy in "+areabtn.locationNameTxt.text);

        } else if (userMapArray[l][4].search("Fog") == true) {

            trace("It is foggy in "+areabtn.locationNameTxt.text);

        } else if (userMapArray[l][4].search("Light Rain") == true) {

            trace("It is raining lightly in "+areabtn.locationNameTxt.text);

        } else if (userMapArray[l][4].search("Light Rain/Windy") == true) {

            trace("It is raining lightly in "+areabtn.locationNameTxt.text);

        }

    }
}

function grabUrl(e:MouseEvent):void {

    trace("http://weather.yahooapis.com/forecastrss?w="+e.target.name);
  

}

An image showing the prototypes functionality at its present point ,  loading data from an array and a basic use of the RSS feed on a simple 2d map. Link to the live version here


A dummy run of the map with some basic functionality





Map Design

Some early versions of how i want the map to look. The map is going to be a 3d object which the user rotates by holding down the mouse button and dragging the mouse on the stage. Also shows some basic functionality, in this case, what happens when a location is moused over.




No comments:

Post a Comment