My Weather Widget

23 Aug
2009

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.

Comment Form

top