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
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
@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
@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
Is this free to use?
4. Ken, April 26th, 2011 at 10:45 pm
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
^^ Same, even right clicking and going to save as produces an invalid zip file
6. Dees, April 30th, 2011 at 7:09 pm
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
@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
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