Archive for the ‘Javascript’ Category

Introducing js3ds – a Javascript parser for .3ds

Wednesday, January 27th, 2010

Came home very tired today and saw this tweet by @Sirokos. Now, that of course was a challenge!

In the near future I’m planning to do some experiments with WebGL and Javascript. Of course I need to be able to load some cool 3DS models then. So… started coding an hour ago and presto! Basics are done within the hour! I admit: I’ve done a Actionscript version some years ago (coded it for Papervision).

The javascript version is very basic still: only meshes (vertices, faces and uv’s) for now. Materials etc. will follow if I find time.

Again: have fun!

Crossdomain JSON troubles: JSONCrossdomainRequest

Friday, December 5th, 2008

This week I was doing some work on a crossdomain JSON request. This was a pitty, because I had in mind, Ajax requests could be made between subdomains, but that wasn’t the case, therefore I had to come up with a solution.

Solution 1: Server-side proxy
One option we had, was a server-side proxy, but I didn’t like this solution. If you are proxying your crossdomain request through a webserver that has to handle a lot of requests per second, these requests can block other requests, because proxying is always a slow process.

Solution 2: JSONP
Then there is the JSONP method, which includes a script on the fly in the browser and this script is then evaluated. The problem however with this approach is that your JSON resources have to be rewritten as a evaluation. This evaluation is then executed and your JSON loaded in a variable.

Instead of:

{"somejsonobject":1}

you have to write:

var jsonobject = {"somejsonobject":1};
someCallback(jsonobject);

This is not very clean, because you have to decide in your remote JSON file what the variable will be named. JSONP is a method in which you give a variable and callback in the url and then the JSON will be rewritten. This solution is just not the right way, as we programmers all know why it is better to isolate logic from real data.

Solution 3: Crossdomain through flash
Then I looked at another solution that does crossdomain Ajax requests through a flash proxy. These solutions all gave a lot of problems, cause the encoding of characters was not handled properly by the Flash ExternalInterface compononent, which sended the JSON string it received to Javascript.

Solution 4: Parsing the JSON by flash
I then tried to make a solution myself that doesn’t send JSON string to Javascript, but (thanks for the idea Gert-Jan) sends the objects to Javascript. So the JSON is parsed into an object at the Actionscript side and it now all works. The project is opensourced under a MIT license and called: JSONCrossdomainRequest. It is a js file which includes a swf file in your page that can handle the requests. Please come over to GitHub and read more about how to install and use this project. The Actionscript project is also included. Good luck if you are going to use it and if you have any modifications let me know, it is a work in progress and we appreciate any help!

Project location:
http://github.com/japetheape/jsoncrossdomainrequest/tree/master

Generating thumbnails

Wednesday, November 26th, 2008

I would like to thank you all for helping us build our thumbnail database!
I presume this statement might be in need of some clarification, so bear with me when I go into the technical details on this one.

For every design that is saved on Floorplanner, we create a thumbnail in JPEG format. We use these thumbnails for the gallery, and now we have included them on everyone’s dashboard. However, for various reasons, we do not have a thumbnail available for every design. However, with your help, we are improving the thumbnail database while you our browsing the site!

The thumbnail images are stored on Amazon AWS S3. We know the URL that a thumbnail of a design should have, but we do not know if it actually is available. In the latter case, the result is a nasty image not found placeholder on the dashboard. This of course is not acceptable! We cannot know if a thumbnail exists other than doing a request to the URL and see whether we get an image back from Amazon, or a HTTP 404 status. This is a very time-consuming procedure to run server side so we chose to find a client-side solution.

We found that javascript can be used to check if an image exist. An AJAX call cannot be used, because cross-site calls are not supported. However, the javascript Image object can be used for this purpose.

var img = new Image();
img.onload = function(event) {
  // image was found and loaded successfully
  document.getElementById('img-tag').src = img.src;
};
img.onerror = function(event) {
  // An error occured while loading the image
  document.getElementById('img-tag').src = '/images/thumb-unavailable.jpg';
}
 
// Setting the src property will trigger the events.
img.src = 'http://link.to.amazon.s3/design/thumbnail.jpg';

A nice thumbnail not available image will be shown if the thumbnail file cannot be found on S3. This is much nicer, and the check is completely done client-side! However, we found a way this could even be better by changing the onerror event handler. Instead of displaying a thumbnail not available image, we can simply load a small instance of the Floorplanner application to display a small version of the design. Moreover, we can instruct it to generate a thumbnail JPEG and save it to S3!

So, every time you see a small Floorplanner loading on your dashboard, you are creating a missing thumbnail. Next time, the thumbnail will be available on S3 and there will be no need to start the Floorplanner application. A nice example of distributed computing, mixed with a hint of SETI@home. I like it!

Drag’n'drop from HTML to Flash

Thursday, November 6th, 2008

Last week we released a new Floorplanner account, the Enterprise account. With it, companies can have an online Floorplanner solution completely branded to their wishes. It includes the Roomplanner module and a custom library of their own furniture elements.  Steelcase and Maxon are the first to have an active Enterprise account.

The interesting part of this release, from a tech point of view, is the new drag-and-drop functionality. The Roomplanner is running in the Flash Player. However, the library of furniture elements is in HTML. We chose to build the furniture library in the HTML sidebar for a couple of reasons. It’s not in the Roomplanner, so there is more space left to design. It gives us more freedom in the page layout. All items on the page are indexed and things like sorting and tags we’re easier to build in Ruby on Rails than in Flash.

Now we only needed a way to get the furniture from the sidebar to the Roomplanner. That’s where the drag’n'drop comes in, drag from HTML and drop in Flash. To drag an image of a furniture element in HTML we used the fantastic JavaScript script.aculo.us framework. The next step was to swap the image to an element in the Roomplanner and to update the position of the element while moving the cursor on the Flash content. For this we used ExternalInterface to communicate between JavaScript and ActionScript. That’s all there is to it. The theory is actually quite simple, but in practice it was very (I repeat, VERY) difficult to get it working in all the main browsers. All those nitty gritty browser details…

At this moment everything seems to work just fine, so please take a look at Steelcase and/or Maxon and let me know what you think!

Using setInterval in a JavaScript class

Wednesday, July 16th, 2008

I just figured out how to use setInterval in a JavaScript class. This little snippet shows how I used setInterval in a recursive way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function MyClass() {}
 
MyClass.prototype.doNext = function( pArray ) {
	clearInterval( this.interval );
 
	if( pArray.length > 0 ) {
		// do something with the array record
		this.doSomething( pArray.pop() );
 
		// call this function again in a couple of milliseconds
		var scope = this;
		var milliseconds = 100;
		this.interval = setInterval( function(){ scope.doNext( pArray ) }, milliseconds );
	} 
} 
 
MyClass.prototype.doSomething = function( pRecord ) {
	// do something
}
 
var myObj = new MyClass();
myObj.doNext( myArray );

Mousewheel events in Flash on OS X

Wednesday, May 7th, 2008

The Flash Player on OS X currently lacks support for mousewheel events. This means that users cannot use their mousewheel on OS X, in the Floorplanner we use the mousewheel to easily zoom in to your Floorplan. After reading this post from pixelbreaker, I was inspired to implement this in the Floorplanner which was, in fact, very easy. I decided to only use the JavaScript class of pixelbreaker, which sends the mousewheel events to the Flash Player (on the Mac). In the Floorplanner ActionScript this event is handled by our own internal Event management system, which sends the Event to the reponsible part of the code. So thumbs up for pixelbreaker, for making this really easy to implement!

JSON Validator

Tuesday, April 15th, 2008

I’m currently working on a JSON export from the Floorplanner and I’m glad I found the excelent JSON Validator made by arc90 lab. They made the debugging process a lot easier. Thanks guys!

Consume SOAP web service from Javascript

Wednesday, April 2nd, 2008

I wanted to get some data from a web service using Javascript. I looked at several Javascript classes (like this), but because the web service was running on another server it got a little troublesome. As a solution I tried to call the web service through a proxy, but that didn’t make it any easier.

Jaap suggested to take a look at NuSOAP, a -kinda old- SOAP toolkit for PHP. With an AJAX request I could call a PHP page that uses NuSOAP to consume the web service. It was actually easier then I thought it would be.

To make the AJAX call from Javascript I used Prototype and this script:

  function doRequest() {
    var url = "ajax/consume_webservice.php";
    var param1 = "value1";
    var param2 = "value2";
    var params = "param1="+ param1 +"&param2="+ param2;
 
    new Ajax.Request ( url, { method: 'POST', parameters: params,
      onComplete: onResult } );
  }
 
  function onResult( result ) {
    alert( result.responseText );
  }

The PHP file consume.php looks something like this:

< ?php
 
  $param1 = isset( $POST_['param1'] ) ? $POST_['param1'] : false;
  $param2 = isset( $POST_['param2'] ) ? $POST_['param2'] : false;
 
  // this is the only file I used from the NuSOAP project
  require_once( "nusoap.php" );
 
  $url = webserviceurl;
  $params = array( "param1" => $param1, "param2" => $param2 );
 
  $soap = new nusoap_client( $url, true, false, false, false, false, 0, 60 );
  $proxy = $soap->getProxy();
  $proxy->functionname( $params );
 
  echo $proxy->response;
 
?>

That’s all. Do a AJAX request from Javascript to a PHP page. Then the PHP page uses NuSOAP to consume the web service and returns the result. Back in Javascript you can do whatever you want with the given data.

Rounding errors in practice

Friday, March 28th, 2008

In college I followed a course in numerical analysis. The main point of the course was to be careful with floating point arithmetic, because it is vulnerable to rounding errors that can significantly influence the result of complex computations. Until yesterday I never had encountered such a problem. Now that I have lost my innocence in this matter, I would like to share my tale of nasty debugging and frustration.

After receiving some bug reports of Floorplanner designs that failed to save properly, we dove into the code to see what was going wrong. After some time, we found that the errors were caused by the script that loads the design after it has been saved with a unique name. This unique name is passed to the script to be able to find the design. We used the current timestamp as a unique name for the design. The current timestamp simply is the number of seconds passed since January 1, 1970 and looks something like this: 1206712028. As a design name, this number was passed to different scripts, both client-side and server-side. However, at some point in this chain of scripts, the number was changed slightly to 1206712030 and because of this the associated design could not be found, resulting in an error.

At first, we investigated the possibility that the stored timestamp was overwritten by a newer timestamp, as this could explain the slight increase in the number. However, we were not able to find this anywhere in the code and sometimes, the number was decreased a bit instead of being increased.

Finally, we monitored the data being sent between the different scripts, and we found that ActionScript automatically converted the numeric design name into a number in scientific notation. In our case, this would be 0.1206712028 x 10^10. Unfortunately, this number was rounded to 0.120671203 x 10^10 because computers use floating point arithmetic to store numbers in scientific notation. This number would eventually be converted back to normal notation, but it was now 1206712030 because of the rounding error.

We fixed it by putting an ‘a’ in front of the timestamp, preventing the automatic conversion to a number. Not very elegant, but it works!

Encoding UTF-8 in Javascript

Tuesday, March 25th, 2008

I had to make a call from Javascript to a SOAP web service (more on that later). The data I had to send to the web service was in a XML format that contained non ASCII characters (for example: é). I tried to use the standard escape() function, but that one couldn’t handle the special characters.

Thanks to ecmanaut I found a very simple solution: encodeURIComponent() (with decodeURIComponent() as its counterpart).