Gravity in the DOM

Dec 18 2008 Published by Eneko Alonso under uncategorized

A couple of days ago I created a demo to simulate planets on a 2D universe interacting each other like Gravity does in our lives. To compute the movements every planet had to be evaluated with each other on every step. Their position will be affected by the other planet position and in proportion to their respective mass. This means the speed of the planets doesn’t impact the attraction between them.

Today I decided to extend this demo a little bit more and I added a few things:

  • Mass parameter to make mass independent from size.
  • Collision detector to merge planets when they meet each other with color effect.
  • Orbit trails

Gravity

The result is very nice. The first option make it possible to create bigger planets with more mass but with a size that fits appropiately on the screen. The second option merged planets that collide, making it more like a real world. Finally, the orbit trails are just some sugar to see the trajectory followed by the plantes. To avoid the screen getting very messy, the trails clean up themselves after 25 seconds.

As you can see, the universe controller uses the Thread class I was talking about few days ago.

See both demos here:
http://dev.enekoalonso.com/research/gravity.php
http://dev.enekoalonso.com/research/gravity-2.php

PS: Please note there is no Canvas involved here. All objects on screen are DOM elements. Of course this is not the best way to do graphic animations on the web, but it is fun!

No responses yet

Threads in Javascript

Dec 14 2008 Published by Eneko Alonso under uncategorized

Well, let’s make it clear: There is no way to create actual threads in Javascript. Javascript code runs on a single thread inside the browser. This is, only one line of code is running at a time. In fact, until Google’s Chrome, all pages/tabs opened on a browser where running on the same system thread.

So what is this about Javascript threads? Well, maybe we cannot create them, but we can emulate them. Since Javascript is an event driven language, we can use an Object Oriented approach and create an object that stays ‘alive’ with the use of a timer. Now we only need a way to control that object and to interact with it.

Thread Class

In order to accomplish this functionality I created this Mootools-based Thread class:

  1. Thread = new Class({
  2.   ClassName: 'Thread',
  3.   Implements: [Options, Events],
  4.  
  5.   threadId: '',
  6.   timer: null,
  7.   stopped: true,
  8.  
  9.   options: {
  10.     interval: 1000,
  11.     autostart: false
  12.   },
  13.  
  14.   initialize: function(options) {
  15.     ThreadController.add(this);
  16.     this.setOptions(options);
  17.     if (this.options.autostart) this.start();
  18.   },
  19.  
  20.   start: function() {
  21.     this.stopped = false;
  22.     this.__setTimer();
  23.     this.fireEvent('start', [this]);
  24.   },
  25.  
  26.   stop: function() {
  27.     this.stopped = true;
  28.     this.__stopTimer();
  29.     this.fireEvent('stop', [this]);
  30.   },
  31.  
  32.   setInterval: function(time) {
  33.     this.__stopTimer();
  34.     this.options.interval = time;
  35.     this.__setTimer();
  36.   },
  37.  
  38.   // For inheritance
  39.   beforeExecute: function() {
  40.     this.fireEvent('beforeExecute', [this]);
  41.   },
  42.  
  43.   // For inheritance
  44.   execute: function() {
  45.     this.fireEvent('execute', [this]);
  46.   },
  47.  
  48.   // For inheritance
  49.   afterExecute: function() {
  50.     this.fireEvent('afterExecute', [this]);
  51.   },
  52.  
  53.   /* ————— */
  54.  
  55.   __setTimer: function() {
  56.     if (!this.stopped) {
  57.       this.timer = setTimeout(function(){
  58.         this.__execute(this);
  59.       }.bind(this), this.options.interval);
  60.     }
  61.   },
  62.  
  63.   __stopTimer: function() {
  64.     if (this.timer != null) {
  65.       clearTimeout(this.timer);
  66.       this.timer = null;
  67.     }
  68.   },
  69.  
  70.   /* This function is called from a timer which doesn't
  71.       know about 'this' */
  72.   __execute: function(self) {
  73.     self.beforeExecute();
  74.     self.execute();
  75.     self.afterExecute();
  76.     self.__setTimer();
  77.   }
  78.  
  79. });

Thread Controller

To make my life easier and prevent me from having to declare one variable for every thread I use, I have created a ThreadController object to which every thread created will subscribe. This thread controller will allow us to find threads of a specific class and start/stop them or delete them.

  1. ThreadController = {
  2.   threadCount: 0,
  3.   threads: [],
  4.   add: function(thread) {
  5.     this.threads.push(thread);
  6.     this.threadCount++;
  7.     thread.threadId = 'Thread-' + this.threadCount;
  8.   },
  9.   count: function() {
  10.     return this.threads.length;
  11.   },
  12.   indexOf: function(ClassName) {
  13.     for (var i=0, l=this.threads.length; i<l; i++) {
  14.       if (this.threads[i].ClassName == ClassName) return i;
  15.     };
  16.     return -1;
  17.   },
  18.   remove: function(index) {
  19.     if (index < 0 || index > this.threads.length-1) return;
  20.     var thread = this.threads.splice(index, 1);
  21.     thread[0].stop();
  22.     delete thread[0];
  23.   }
  24. }

Usage

In order to use the Thread class you can do it in two different ways.

First, you can instantiate threads and use the onStart, onStop, onBeforeExecute, onExecute and onAfterExecute events.

  1. var producer = new Thread({
  2.   onExecute: function(thread) {
  3.     // Do something
  4.   }
  5. }).start();

Or, you can create a subclass and override the start, stop, beforeExecute, Execute and afterExecute methods. I like this option better since it let’s you create your own thread based Objects that you can instantiate later. If you use this option do not forget to call this.parent().

  1. var Producer = new Class({
  2.   ClassName: 'Producer',
  3.   Extends: Thread,
  4.   execute: function() {
  5.     this.parent();
  6.     // Do something
  7.   }
  8. });

Producer / Consumer demo

A good example of Javascript threads interacting with each other is the classic Producer/Consumer problem. A Producer object produces goods at some speed. A Consumer object consumes goods at its own speed. Depending of the speed of producers and consumers and the number of each, more or less goods will be available.

  1. var Producer = new Class({
  2.   ClassName: 'Producer',
  3.   Extends: Thread,
  4.   execute: function() {
  5.     this.parent();
  6.  
  7.     var item = new Element('div');
  8.     item.set('text', ++count).addClass('item');
  9.     item.fade('hide').inject($('container'));
  10.     new Fx.Morph(item, {
  11.       onComplete: function() {
  12.         item.addClass('ready');
  13.       }
  14.     }).start({
  15.       opacity: 1
  16.     });
  17.   }
  18. });
  19.  
  20. var Consumer = new Class({
  21.   ClassName: 'Consumer',
  22.   Extends: Thread,
  23.   execute: function() {
  24.     this.parent();
  25.  
  26.     var item = $('container').getFirst('.ready');
  27.     if (item && item.hasClass('ready')) {
  28.       item.removeClass('ready');
  29.       new Fx.Morph(item, {
  30.         onComplete: function() {
  31.           item.destroy();
  32.         }
  33.       }).start({
  34.         opacity: 0
  35.       });
  36.     }
  37.   }
  38. });
  39.  
  40. new Producer().start();
  41. new Consumer().start();
  42. new Consumer().start();
  43. new Consumer().start();
  44. new Consumer().start();

As you can see, creating new producers and consumers is very easy and they will live and run on their own. Check out this Producer/Cosumer demo with Javascript Threads.

Producer / Consumer demo

Thread Synchronization

Now, guess what? The fact that all these threads are not actual threads plays in our advantage. Since two of this objects cannot execute code at the same time, there is no risk of garbaging the value of a variable while changing it at the same time. For example, if two threads are updating the same DOM element, they will never conflict or crash. But you may still need critical sections if two threads are manipulating the same DOM object, for example. You can use temporary classes on the elements, but that doesn’t guarantee no conflicts.

On the Producer/Consumer demo I am using the class “ready” on goods elements to indicate which ones are ready to be consumed and are not being consumed yet. But if you look at the code carefully, would this class prevent two consumers from consuming the same element? Not really. The problem is than between the time a consumer finds a ready element and the time when marks it as not ready, it is possible than a second consumer has found the same element.

Get the code

Latest version:
http://enekoalonso.com/svn/research/classes/thread.js

No responses yet