This is a weather widget I created using weather.com’s XML feed. It was done for an AS3 class where welearned how to parse an XML file and display the information. There is no code on the time line with the exception of one stop(); command. For some reason the flash embed does not seem to work here but if you click the link above you will be able to see the widget in all its glory. Just give it a few seconds for the XML data to load.
I am sharing my code below. If you have no idea about how object-oreinted programming works this might be a little difficult for you but the idea of parsing XML is a basic concept that is generally covers in any basic AS3 book. So I am not going to go into details about how that is done. Also I am using TweenLite for the dropdown. You need to know how to attach a document class to the stage and then object classes to the individual components.
I think that covers the requirements. Lets get to the code.
First of all the Document Class:
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | package widget { import flash.display.*; import flash.net.URLLoader; import flash.events.*; import flash.net.URLRequest; import gs.TweenLite; import gs.easing.*; public class WeatherWidget extends MovieClip { private var feedLoader : URLLoader = null; private var weatherFeed : XML = null; private const feedToLoad : String = "weather.php"; //private const feedToLoad : String = "proxy.php"; // private const feedToLoad : String = "http://xoap.weather.com/weather/local/CAXX0504?cc=*&dayf=5&unit=m&link=xoap&prod=xoap&par=1131389620&key=50635f6dc63ea5c3"; //private const feedToLoad : String = "weather.xml"; current :CurrentCond; forecast_mc:MovieClip; private var origY:Number; private var dayItems:Array=[]; private var date2:Date; public function WeatherWidget() : void { feedLoader = new URLLoader(); feedLoader.addEventListener( Event.COMPLETE, feedLoaded ); feedLoader.addEventListener( IOErrorEvent.IO_ERROR, xmlLoadError ); var feedRequest : URLRequest = new URLRequest( feedToLoad ); feedLoader.load( feedRequest ); stage.addEventListener(Event.ENTER_FRAME, refreshTimes); } private function feedLoaded( evt : Event ) { //trace( "*** " + this + " : Finished Loading RSS Feed *** " ); //trace( feedLoader.data ); weatherFeed = new XML( feedLoader.data ); weatherFeed.ignoreWhite = true; weatherFeed.prettyPrinting = true; callCurrentCond(); weatherForecast(); origY = forecast_mc.y; } private function callCurrentCond( evt : Event = null ) : void { date2 = new Date(); var cc = weatherFeed..cc; var currentTemp="NA"; var currentWeather = "NA"; var currentIcon = "N/A"; var currentWindSpeed = "N/A"; var currentWindDir = "N/A"; if ( cc.length >= 0 ) { currentTemp = cc.tmp; currentWeather = cc.t; currentIcon = cc.icon; currentWindSpeed = cc.wind.s; currentWindDir = cc.wind.t; } current.conditions = currentWeather; current.wind= "Wind Speed: "+currentWindSpeed+" km/h "+currentWindDir; current.temp = currentTemp; current.icon = currentIcon; current.date = date2.toDateString(); //current.time = "<b><i>"+hh+":"+mm+" "+ampm+"</i></b>"; addChild(current); } private function weatherForecast():void { forecast_mc.addEventListener(MouseEvent.CLICK, popDown); for(var i:Number=0; i < weatherFeed..day.length();i++ ) { var currentXPos:Number = 10; dayItems[ i ] = new DayItem(); forecast_mc.addChild( dayItems[ i ] ); forecast_mc.buttonMode=true; var date = weatherFeed..day[ i ].@dt; var hiTemp = weatherFeed..day[ i ].hi; var loTemp = weatherFeed..day[ i ].low; var dayIcon = weatherFeed..day[ i ].part.(@p=="d").icon; dayItems[ i ].date = date; dayItems[ i ].hitemp = hiTemp; dayItems[ i ].lotemp = loTemp; dayItems[ i ].icon = dayIcon; dayItems[ i].y= 10; dayItems[ i ].x = currentXPos+((dayItems[i].width+10)*i); } } private function xmlLoadError( e : IOErrorEvent ) { //trace( "*** Error Loading File : " + e.text ); } private function popDown(evt:MouseEvent):void { TweenLite.to(forecast_mc, 1.5, {y:origY+150, ease:Bounce.easeOut}); forecast_mc.more_txt.text="less"; forecast_mc.removeEventListener(MouseEvent.CLICK, popDown); forecast_mc.addEventListener(MouseEvent.CLICK, popUp); } private function popUp(evt:MouseEvent):void { TweenLite.to(forecast_mc, 0.5, {y:origY}); forecast_mc.more_txt.text="more"; forecast_mc.removeEventListener(MouseEvent.CLICK, popUp); forecast_mc.addEventListener(MouseEvent.CLICK, popDown); } private function refreshTimes(evt:Event):void { var date:Date = new Date(); var hourZero:String = new String(); var minuteZero:String = new String(); var secondZero:String = new String(); var h:Number = date.getHours(); var m:Number = date.getMinutes(); var s:Number = date.getSeconds(); if (s < 10) { secondZero = "0"; } else { secondZero = ""; } if (m < 10) { minuteZero = "0"; } else { minuteZero = ""; } if (h < 10) { hourZero = "0"; } else if(h>=10) { hourZero = ""; } var ampm:String = ""; if(h<12) { ampm="AM"; } else if (h==12) { ampm="PM"; } else { h=h-12; ampm="PM"; } var displayTime:String = (hourZero + h + ":" + minuteZero + m + ":" + secondZero + s+" "+ ampm); current.time = displayTime; } } } |
The weather.com feed (which you have to sign up for if you want a 5-day forecast) contains information about both the current conditions and the next 5 day forecast. As you can see the functions are divided individually into separate components. The main two being the callCurrentCond() and the weatherForecast() functions. Inside these two functions we also call their individual object classes called CurrentCond and DayItem respectively. Just to make things easier I actually dragged the Movie Clip attached to the Current Cond class onto the stage as well as the container into which we shall call the individual DayItem Classes. They have been identified in the document class definition by their instance names.
Also for the icons I am using a movie clip called icon_mc which contains all the respective icons in individual frames (I got the icons from here, but you can easily design your own and even use animated movie clips). The XML file actually uses numbers AND strings to tell us about the weather condition so I am just using the number part to jump to that respective frame number in the icon_mc movie clip. If you are using strings then the other easy way to do it would be to use labels on the individual frames and using a
gotoAndStop()
with the frame label.
Here are is the CurrentCond class:
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 45 46 47 48 49 50 51 52 53 54 55 56 | package widget { import flash.display.* import flash.events.Event; import gs.TweenLite; import gs.easing.*; import flash.text.TextField; public class CurrentCond extends MovieClip { date_txt : TextField; temp_txt:TextField; cond_txt:TextField; wind_txt:TextField; time_txt:TextField; icon_mc:MovieClip; public function CurrentCond() : void { date_txt.text = ""; temp_txt.text = ""; cond_txt.text = ""; } public function set date( data : String) : void { date_txt.text = data; } public function set temp ( data : String) : void { temp_txt.text = data; } public function set time ( data : String) : void { time_txt.htmlText = data; } public function set conditions( data : String) : void { cond_txt.htmlText = data; } public function set wind( data : String) : void { wind_txt.htmlText = data; } public function set icon(data:String):void { icon_mc.gotoAndStop(data); } } } |
Here are is the DayItem class:
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 | package widget { import flash.display.* import flash.events.Event; import flash.text.TextField; public class DayItem extends MovieClip { date_txt : TextField; hitemp_txt:TextField; lotemp_txt:TextField; icon_mc:MovieClip; public function DayItem() : void { date_txt.text = ""; hitemp_txt.text = ""; lotemp_txt.text = ""; } public function set date( data : String) : void { date_txt.text = data; } public function set hitemp ( data : String) : void { hitemp_txt.text = data; } public function set lotemp ( data : String) : void { lotemp_txt.text = data; } public function set icon(data:String):void { icon_mc.gotoAndStop(data); } } } |
One of the major issues that came up is that in line 15 of the Document class where you specify your feed I originally had the actual link to the XML file but Adobe Flash has some kind of resotriction so that you cannot get data from a domain different than your own. Thank fully Adobe did provide a work around to this issue here. All you need to do is download that proxy.php file (or asp depending on your server) edit it so that it points to your url and then upload it to your server. Make sure that in line 15 of your Document Class you provide the correct path to the proxy.php file or it will not work. You could test the proxy.php file after uploading it by going to that file with your browser. You should get the data you want displayed on the page and if you view source you will see the XML code. Make sure that the code is strictly XML and that there are no other language elements there. My host automatically put a piece of javascript into all my pages and I was unable to get the widget working untill i manage to turn off that script and now it works fine.
So thats about it. If anyone needs me to elaborate on any other code feel free to contact me.