Javascript Clouds Animation with Mootools

by Tim Dupree at 6:14 pm on March 3rd, 2011 | 9 comments

After creating a basic placeholder page for fromthecloudup.com, I decided it would be fun to make some clouds randomly float across the page since there isn’t anything else really exciting going on there. So I wrote some Javascript classes using Mootools and made myself a cloud generator :).

It consists of two clases, a main class called CloudGenerator that orchistrates everything and a Clouds class that governs individual clouds. It requires Mootools 1.3.1 Core & More. It’s pretty simple to get up and running.

You can download all of the source, plus a demo page complete with cloud graphic here: CloudGenerator-1.0.zip

You may view a demo here: Cloud Generator Demo

To get started, first you need to specify some CSS within the <head> tag of your page. Really the only necessary thing here is to specify the #sky element styles.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<style type="text/css">
html, body {
    padding: 0px;
    margin: 0px;    
}
body {
    background-color: #CBEFFA;
}
#sky {
    position: absolute;
    top: 0px;
    left: 0px;
    width: 100%;
    height: 600px;
    overflow: hidden;   
}
</style>

Next, you will need to include a div named “sky” after your body tag in the HTML of your page.

1
<div id="sky"></div>

At the bottom of your page, just before the closing </body> tag, you will need to include the required Javascript files. Here you can see I include Mootools 1.3.1 Core and More in one file which I then compressed with the Google Closure Compiler. Next, I included an uncompressed and commented version of the Cloud Generator classes.

1
2
<script type="text/javascript" src="/js/mootools-1.3.1-complete-gc.js"></script>
<script type="text/javascript" src="/js/cloudGenerator-1.0.js"></script>

After those files are included, you will need to write a snippet of Javascript to create your CloudGenerator and pass in any options you wish to define.

1
2
3
4
5
6
7
8
9
10
11
<script type="text/javascript">
var weatherMachine;
window.addEvent('domready', function(){
    weatherMachine = new CloudGenerator({
        totalClouds: 8,
        cloudScales: [0.8, 0.6, 0.4, 0.2],
        cloudImg: "/images/png/cloud.png"
    });
 
});
</script>

The options for the CloudGenerator class are listed below (note that below are the defaults for each option).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// These are default options for the CloudGenerator class that can be modified
// when creating a new CloudGenerator instance
options: {
    totalClouds:  4,        // Total number of clouds on screen at a given time (int)
    minDuration: 10000,     // Minimum travel time for a cloud across the screen (milliseconds)
    maxDuration: 120000,    // Maximum tracel time for a cloud across the screen (milliseconds)
    checkInterval: 10000,   // The interval used to check if new clouds are needed (milliseconds)
    autoStart: true,        // Automatically starts the cloud generator by default (bool)
    sky: $("sky"),          // Default sky target resides in an element named "sky" (element)
    cloudImg: "cloud.png",  // Define default cloud image (path/url)
    cloudDirection: 0,      // 0 = left to right, 1 = right to left (int)
    cloudWidth: 573,        // Cloud width (px)
    cloudHeight: 262,       // Cloud height (px)
    cloudScales: [1, 0.8, 0.6, 0.4, 0.2],   // Define an array containing the sizes the cloud will be scaled to (%)
    maxAltitude: 600,       // This defines the vertical space you allow clouds to appear within the sky (px)
    cloudTransition: Fx.Transitions.linear  //Define the transition algorithm for the cloud movement
}

When you are all said and done, a basic page with the Cloud Generator installed should look like this:

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
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>My Sweet Animated Clouds Page</title>
<style type="text/css">
html, body {
    padding: 0px;
    margin: 0px;    
}
body {
    background-color: #CBEFFA;
}
#sky {
    position: absolute;
    top: 0px;
    left: 0px;
    width: 100%;
    height: 600px;
    overflow: hidden;   
}
</style>
</head>
<body>
<div id="sky"></div>
 
<!-- Cue the Javascript -->
<script type="text/javascript" src="/js/mootools-1.3.1-complete-gc.js"></script>
<script type="text/javascript" src="/js/cloudGenerator-1.0.js"></script>
<script type="text/javascript">
var weatherMachine;
window.addEvent('domready', function(){
    weatherMachine = new CloudGenerator({
        totalClouds: 8,
        cloudScales: [0.8, 0.6, 0.4, 0.2],
        cloudImg: "/images/png/cloud.png"
    });
});
</script>
</body>
</html>

Have a look at the CloudGenerator and Cloud classes below to get a better understanding of how they work and how to use them.

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
186
187
var CloudGenerator = new Class({
    // Implement the Events and Options utility classes
    Implements: [Events, Options],
 
    // Initialize our defualt values for the class options passed in
    options: {
        totalClouds:  4,        // Total number of clouds on screen at a given time (int)
        minDuration: 10000,     // Minimum travel time for a cloud across the screen (milliseconds)
        maxDuration: 120000,    // Maximum tracel time for a cloud across the screen (milliseconds)
        checkInterval: 10000,   // The interval used to check if new clouds are needed (milliseconds)
        autoStart: true,        // Automatically starts the cloud generator by default (bool)
        sky: $("sky"),          // Default sky target resides in an element named "sky" (element)
        cloudImg: "cloud.png",  // Define default cloud image (path/url)
        cloudDirection: 0,      // 0 = left to right, 1 = right to left (int)
        cloudWidth: 573,        // Cloud width (px)
        cloudHeight: 262,       // Cloud height (px)
        cloudScales: [1, 0.8, 0.6, 0.4, 0.2],   // Define an array containing the sizes the cloud will be scaled to (%)
        maxAltitude: 600,       // This defines the vertical space you allow clouds to appear within the sky (px)
        cloudTransition: Fx.Transitions.linear  //Define the transition algorithm for the cloud movement
    },
 
    cloudCheck: null,           // Initialize the vairable to hold the setInterval declaration
    cloudsInSky: 0,             // Keep track of number of clouds in sky
    cloudSky: null,             // A reference to the cloudSky generated and injected into the sky element
 
 
    // Our constructor for the CloudGenerator class
    // It takes in the options passed to it and uses the implemented Options
    // utility class to modify any defualt options in our options object
    initialize: function(options){
        // Modify any defaults with the passed in options
        this.setOptions(options);
 
        // Create Cloud Sky
        this.cloudSky = new Element('div', {
            id: 'cloudSky',
            src: this.options.cloudImg,
            styles: {
                position: 'absolute',
                width: (sky.getDimensions().x + (2*this.options.cloudWidth)),
                left: -this.options.cloudWidth  
            }
        });
 
        // Place the cloud container within the sky
        // This lets us ensure that the clouds can smoothly enter and exit the 
        // boundaries of the sky element
        sky.grab(this.cloudSky);
 
        // autostat the cloud generator by default
        if(this.options.autoStart){
            this.startGenerator();
        }
    },
 
    // Check if there are less than the max number of clouds in the sky
    // If there is room, deploy another cloud, if not, do nothing
    deploy: function(){
        var cloudScale = (Math.floor(Math.random()*this.options.cloudScales.length));
        cloudScale = this.options.cloudScales[cloudScale];
 
        var cloudDuration = Math.floor(Math.random() * (this.options.maxDuration + 1 - this.options.minDuration)) 
                            + this.options.minDuration;
 
        var cloudAltitude = Math.floor(Math.random() * (this.options.maxAltitude - (cloudScale * this.options.cloudHeight)));
 
        if(this.cloudsInSky < this.options.totalClouds && !this.cloudsFull){
            this.cloudsInSky++;
            new Cloud({
                width: Math.floor(this.options.cloudWidth * cloudScale),
                height: Math.floor(this.options.cloudHeight * cloudScale),
                altitude: cloudAltitude,
                duration: cloudDuration,
                direction: this.options.cloudDirection,
                cloudImg: this.options.cloudImg,
                cloudTransition: this.options.cloudTransition,
                onComplete: function(){
                    this.removeCloud();
                }.bind(this)
            });
        }
    },
 
    // Decrement cloudsInSky variable
    removeCloud: function(){
        if(this.cloudsInSky > 0){
            this.cloudsInSky--;
            console.log("cloud removed");
        }
    },
 
    // Stop the cloudGenerator
    stopGenerator: function(){
        clearInterval(this.cloudCheck);
        return "generator stopped";
    },
 
    // Start the cloudGenerator
    startGenerator: function(){
        this.deploy();
        this.cloudCheck = this.deploy.periodical(this.options.checkInterval, this);
    }
 
});
 
 
var Cloud = new Class({
    // Implement the Events and Options utility classes
    Implements: [Events, Options],
 
    cloudId: "",    // hold a reference to this cloud's DOM id property
 
    options: {
        duration: 4000,         // Duration of the clouds movement across the sky (milliseconds)
        direction: 0,           // Direction of the clouds movement, 0 = left to right and vice versa (int)
        altitude: 200,          // Altitude of the cloud in the sky
        width: 573,             // Width of the cloud (px)
        height: 262,            // Height of the cloud (px)
        cloudImg: "cloud.png",  // Cloud image (path/url)
        sky: $("cloudSky"),     // CloudSky element that the cloud will be injected into (element)
        cloudTransition: Fx.Transitions.linear  //Define the transition algorithm for the cloud movement
    },
 
    initialize: function(options){
        // modify any defaults with the passed in options
        this.setOptions(options);
 
        // create and animate the cloud element
        this.createCloud();
    },
 
    createCloud: function(){
        this.cloudId = 'cloud-' + (new Date().getTime());
 
        // determine if cloud will be moving left to right or right to left
        // the position cloud offscreen to begin movement
        var cloudStyle = { 
            position: 'absolute',
            top: this.options.altitude,
            width: this.options.width,
            height: this.options.height 
        };
 
        var skyPosition = 'upperRight'; // Move the cloud to the right, ignore the 'upper'
        var cloudEdge = 'upperLeft';    // Align the edge of the cloud to the edg edge of the sky
 
        // Determine the direction of the cloud and set styles and positions
        if(this.options.direction === 0){
            cloudStyle.left = (0 - this.options.width);
        }
        else {
            cloudStyle.right = (0 - this.options.width);
            skyPosition = 'upperLeft';
            cloudEdge = 'upperRight';
        }
 
        // Create the image element for the cloud
        var cloud = new Element('img', {
            id: this.cloudId,
            src: this.options.cloudImg,
            styles: cloudStyle
        });
 
        // Add the cloud image element to the cloudSky div
        sky.grab(cloud);
 
        // Move the cloud across the sky
        new Fx.Move(cloud, {
            relativeTo: this.options.sky,
            position: skyPosition,
            edge: cloudEdge,
            offset: {x: 0, y: this.options.altitude}, 
            duration: this.options.duration,
            transition: this.options.cloudTransition,
            onComplete: function(){
                this.complete();
            }.bind(this)
        }).start();
 
    },
 
    complete: function(){
        $(this.cloudId).destroy();  // Remove the cloud element from the DOM
        this.fireEvent('complete'); // fire the onComplete event, this is picked up
                                    // by the CloudGenerator class
    }
});

Comments

9 Responses to “Javascript Clouds Animation with Mootools”
  1. Thanks for the demo.

    I thought you should know that Firefox 3.6.15 is throwing an error for me: sky is not defined line 45 cloudGenerator-1.0.js

    Works OK in IE8

    rp

    1. rp,  March 8th, 2011 at 9:42 am

  2. @rp You’re welcome :) I’ll check out the Firefox issue and get it fixed.

    2. Tim Dupree,  March 9th, 2011 at 12:09 pm

  3. @rp everything should be fixed. You can try clearing your cache and loading up the demo again and it should work. If you need the source code, download the zip file again as the source in there has been updated. Cheers – Tim

    3. Tim Dupree,  March 9th, 2011 at 12:51 pm

  4. Is this free to use?

    4. Ken,  April 26th, 2011 at 10:45 pm

  5. Also… the CloudGenerator-1.0.zip takes you to page with that name and does not download any zip file… thanks

    5. Ken,  April 26th, 2011 at 10:47 pm

  6. ^^ Same, even right clicking and going to save as produces an invalid zip file

    6. Dees,  April 30th, 2011 at 7:09 pm

  7. also would it be possible to get multiple cloud images to be used, rather than the one?

    7. Dees,  April 30th, 2011 at 7:10 pm

  8. @Ken & @Dees, sorry about the zip not downloading. That has been fixed and it is available for download now. I am releasing it under the MIT Open Source License, so you are free to use it and modify it.

    @Dees, I don’t have the time to work on it right now, by you should be able to modify the code to allow multiple images without too much difficulty.

    8. Tim Dupree,  May 2nd, 2011 at 1:07 pm

  9. This is simply beautiful.. I’ve been in search of this for a looooong time and this website came along…
    Very helpful
    My rate: 1000000/100

    9. David,  July 18th, 2012 at 7:54 pm

Leave a Comment