Techblog

Tech Blog

Our latest geek adventures!

Archive for the ‘Floorplanner’ Category

22 October Printing & Big Bitmaps

Last week I started working on a new version of the print functionality in Floorplanner. The problem with the previous version was that it didn’t print shadows, it was impossible to rotate the plan to landscape and textures didn’t look very well. Overall it produced a very mediocre image compared to the visual quality of a plan on the screen. As can be seen below:

Old print output

Old print output

For printing we use the AS2 PrintJob class, which works really easy, with a small disadvantage: it doesn’t print Floorplans properly. I tried all kinds of settings for this class, with as input just a MovieClip with a drawing of the plan on it. I tried setting the printAsBitmap to true and false, both giving the exact same result. So although being stuck with it, the printAsBitmap boolean inspired me to investigate the Bitmap thing. We already had an image export utility, which produces images of a Floorplan with the same quality as it is shown in the FlashPlayer. The funny thing is that when I printed this exported image, the print quality was really good, at least a lot better than our own printing functionality. So for some reason, even if I used the printAsBitmap functionality, it still didn’t produce the same quality as using a real bitmap.
Of course we could have stopped here and just tell the users of Floorplanner to print the exported image. But since we are Floorplanner, we didn’t want to introduce another step requiring user action in the printing process, after all, we are the “easiest way” :-).
So I decided to use the same BitmapData created for the image export as basis for the printing. The first results where rather disappointing, I attached the created BitmapData to a MovieClip which in turn was given to the PrintJob. The produced print was of really low quality, you could easily see pixels all over the place. I tried using more pixels but now I bumped into the pixel limit of BitmapData (2880×2880 pixels). To work around this I invented the BigBitmapData class, this is a wrapper class that mimics the functionality of the BitmapData class, but which doesn’t have an upper limit of the number of pixels which can be used. When an instance of BitBitmapData is created which is bigger than 2880 by 2880, it creates additional BitmapDatas to store the additional pixels needed. So in fact the BigBitmapData internally stores an two dimensional array of BitmapDatas to bypass the pixel limit.
So with this new class I was able to scale up the created image to unprecedented sizes. I did a lot of printing experiments with scaling of the input, I tried scaling settings from 2 times to more than 10 times! This huge bitmap was attached to a MovieClip which in turn had to be scaled to fit on one single page of the printer. These values did give a better result, but still not good enough. It turned out that I had to take the DPI of the printer into account. The optimal scale factor turned out to be (1 / 72) * 300. The 72 is the DPI of the screen, and the 300 is the DPI of the printer. Furthermore a ‘point’ (print unit of measurement) is 1/72 inch, while the size of a pixel (screen unit of measurement) is dependent on the resolution of the screen.
So what this method actually does is creating a big image (which is resized to the paper contents) with enough quality to be printable on a 300 DPI printer.

New print output

New print output

So as you can see in the second image above, the new print looks a lot better, and since the new print uses bitmaps it is really easy to rotate it to always produce a print that tries to fill the entire paper.

A disadvantage of this method is that it takes quite some computational power to compute all the pixels for the bitmap that is created in memory, so as a result the FlashPlayer and sometimes even the browser freezes for a moment. Although this isn’t very good, we thought this behavior is acceptable since the quality of the prints is much better than the previous ones and the freeze time is actually really short. If you are not convinced by the images (which is understandable since the quality difference can only be seen on paper), just check it out!

No Comments - Tags: , ,

14 July Welcome back!

Posted by Gert-Jan in Floorplanner

Welcome to our brand new Floorplanner tech blog! Here we will be posting all our little technical adventures while working on the Floorplanner. This blog focusses mainly on the technical side of the Floorplanner, so you can expect stories about Flash/Flex, Ruby on Rails, Papervision 3D, JavaScript and all other kinds of thingies we run into on a daily basis. 

You might know that we did a similar thing at a tech blog on Suite75, but a couple of things have changed over the last year. As Suite75 we developed rich internet applications for all kinds of clients. Instead of doing a lot of different projects for clients, we wanted to build and sell our own product. Our mission: to be the easiest, quickest and best looking way to create and share interactive floor plans online. Floorplanner was born.

Along with the mission came a huge amount of technical challenges in the world that is know as the World Wide Web. It will be our pleasure to tell you about all the technical problems (and hopefully the solutions) we had to overcome to achieve our goal. So buckle up and join us on the bumpy road!

No Comments -

7 May Mousewheel events in Flash on OS X

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!

No Comments -

15 April JSON Validator

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!

No Comments -

3 April Finding the correct IP address in Rails

Today, I have added a server switch to Floorplanner.com. Now, it will load the floorplanner elements from the server that is nearest to you, which can yield a significant improvement in the initial loading time of your floorplans.

To determine your location, your IP address is matched against a table of locations. This worked fine in our development version, but it didn’t work at all on the production server. After some searching, I found that our server configuration was causing this. We use Apache as our web server, which uses mod_proxy to send the request to our Mongrel cluster. This intermediary step caused the IP address that Rails would receive to always be the IP address of the Apache server: 127.0.0.1. Therefore, the location matching did not work.

However, I found that mod_proxy adds an additional header to the request with the original IP address: HTTP_X_FORWARDED_FOR. This header can be used for our purpose. Now, I use the following function to determine the correct IP address:

1
2
3
4
5
def determine_ip(request)
  # use HTTP_X_FORWARDED_FOR if available
  # otherwise fall back to default header
  request.env["HTTP_X_FORWARDED_FOR"] || request.remote_addr
end

On a related note: to match an IP address against ranges of IP addresses in our location table, it must be converted from a string (”1.2.3.4″) to a number (16909060). I use the following oneliner, which uses some nice functional programming tricks and an application of bit-shifting:

1
2
3
4
def numeric_ip(ip_str)
  ip_str.split('.').inject(0) { |ip_num, part|
            ( ip_num << 8 ) + part.to_i }
end

Yes, I am really proud if this function! :-)

UPDATE: I just found out that request.remote_ip does the same as my determine_ip-function. Unfortunately, it only works in Rails 2.0.

1 Comment - Tags: , ,

8 February Loading swf’s faster

Last week we wanted to see if we could speed up the loading of the Floorplanner Flash app. The Flash app (AS2) consists of 1 main app that loads several swf forms (the windows you see, like the library). The library itself holds a lot of furniture elements, which are separate swf files that are loaded one by one.

When a user creates a floor plan and adds furniture to it, it’s not strange that the design holds more than 50 furniture elements. Though all elements are small swf files, it takes a lot of time to handle all resource requests on our server. We thought it would be nice if we didn’t have to load all the elements one by one, but that we could bundle them into one big swf file. Then the generated bundle-swf is loaded into the flash app and the furniture elements are loaded from the bundle-swf.

We looked at Swfmill and Ming, and we did manage to create a setup that could dynamically bundle the furniture elements into one big swf. The problem was that it didn’t work for all our furniture elements. Almost 10% failed.

In the Flash app we also experienced some unexpected issues. You can only add mc’s (furniture elements) from the library to the stage by using attachMovie(). That means that all elements must have the same parent mc (AS2). So you can only use one bundle-swf, because if you load another, your attached mc’s will be removed.

With all the issues we encountered we decided to keep things as they are right now, and tackle this issue when we’re upgrading to AS3.

No Comments -

5 November We are hiring!

Our Floorplanner is gaining momentum! Since the release last April more than 200.000 users have registered and every day more and more new users are signing up.

And consumers are not the only ones interested. A lot of companies have found their way to us with requests for custom work. Various internet portals, broadcasting firms and real estate agents are just a few of the interested parties. They all are looking for a custom version of the Floorplanner with things like custom furniture libraries, a different look & feel or advertising opportunities.

To keep up with the demand, and to create all the other stuff we can think of, we want to expand our development team. So if you are a Flash guru, a PHP or Ruby on Rails super star and you want to work at a highly innovative and creative internet startup in Rotterdam, the Netherlands drop me a line!

No Comments -

12 October Flash player crashing in IE

For the project V-Factor we integrated a couple of Floorplanner widgets into their site. We used iframes to embed the widgets into the pages. You can click on the link next to the widget to get a better view of the floor plan. A new window with a full screen Floorplanner is opened.

On Firefox and Safari everything runned like a charm, but when we tested it on Internet Explorer it sometimes crashed. And it crashed hard, IE shuts down completly (after it alerts that Flash9d.ocx is to blame). Stange that the Flash Player can crash IE…

Anyway, we still havn’t figured out the exact cause. We have two theories. The first is that IE doesn’t like embeded Flash content via an iframe in multiple windows. The other theory is that IE doesn’t like different ways of embedding Flash content in multiple windows. The page contains more Flash content then our widgets. It has a banner and some animated buttons. We use SWFObject but the banner and the buttons are using the old skool object-tag.

Phew… we kind of solved the problem by opening the full screen floor plan in the same window as the widgets. That way we don’t have multiple windows open with flash content. But it’s not a real solution of course.

To be continued…

2 Comments -

7 September SQL chart query

Posted by Gert-Jan in Floorplanner

Last week I wanted to make a small chart to display the number of users that signed up at Floorplanner per month. This is easily done by using query with a GROUP BY statement:

SELECT MONTH(created_on), COUNT(*)
  FROM users
  GROUP BY MONTH(created_on)

It returns a result with rows like this: [month number,number of accounts that month]. Since we have different kind of users (free and a couple of paid accounts) I thought it would be nice to put them in the equation too. After a while I came up with this query (actually not very different from the first one):

SELECT MONTH(created_on), account_type_id, COUNT(*)
  FROM users
  GROUP BY MONTH(created_on), account_type_id

Now it returns a result with rows like this: [month number, account type id, number of accounts that month for this type]. With some filtering I made it into a nice chart but I have the feeling that there is an easier solution.

Suggestions anyone?

1 Comment -

7 May SWF’s, Javascript and subdomains

Today I had (actually I still have) an issue with subdomains, SWF’s and Javascript. For the Floorplanner we communicate with our Flash application via Javascript (using ExternalInterface). On www.floorplanner.com everything works fine, but when I tried to use a subdomain (like whatever.floorplanner.com) an error appeared. First I thought it was a Javascript error, but it turned out to be the Flash Security Sandbox blocking the communication.

To solve this I added the following line to the Flash app:

System.security.allowDomain('http://whatever.floorplanner.com/');

It did the trick, but the thing is that every (paying) user can create and use its own subdomain, so i needed something like this:

System.security.allowDomain('http://*.floorplanner.com/');

That didn’t work. After trying all kinds of different things like crossdomain.xml, I settled with

System.security.allowDomain('*');

This feels like a really nasty hack, but it’s all I can come up with. There has to be a better way…

4 Comments -