Relaxing introduction to the DOM. Great for starters, but also interesting for experienced JS programmers
-
Categories
About Me
Relaxing introduction to the DOM. Great for starters, but also interesting for experienced JS programmers
Update
While you can improve minification by following below description, you might experience a negative performance impact, especially if you have a lot private functions since all these functions are hold within the closure of the anonymous function. I’m not sure how bad that really is, but I for myself went back to build an object directly, not using the closure of the anonymous function.
Like jQuery, I’m using the Google Closure Compiler to minify the code of my Image Color Picker plugin.
When I looked over the minified code, I noticed that quite a few function names don’t get minified.
Let’s take a closer look at the v0.1 version of ImageColorPicker.js (github):
$.widget("ui.ImageColorPicker", { options: {}, _create: function() { }, destroy: function() { }, selectedColor: function() { }, _d2h: function(d) { }, _h2d: function(h) { }, _createImageColorPicker: function() { } });
option, _create, destroy, selectedColor and all the other function names don’t get minified. Everything within these function gets minified pretty well. The reason for this is that the Closure Compiler regards all these functions and objects as public. Since they are public the compiler does not know whether another, external library uses one or more of the functions. In order not to break external libraries or, more generally, code that depends on our code, the Closure compiler does not touch the names.
In case you have quite a few “private” functions and / or use them heavily, it can become pretty space wasting to not minify them. So how to fix this?
The solution is: Use a Javascript Closure. By using closures you can make functions truly private, compared to marking them private by using the underscore convention. This is ImageColorPicker.js after the refactoring (github):
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 | var uiImageColorPicker = function(){ var _d2h = function(d) { }; var _h2d = function(h) { }; var _createImageColorPicker = function(widget) { }; return { options: {}, _create: function() { }, destroy: function() { }, selectedColor: function() { } }; }(); $.widget("ui.ImageColorPicker", uiImageColorPicker); |
In line 1 a function is assigned to uiImageColorPicker. But not really. Take a closer look at line 27. It’s directly executed. Therefore the value which is assigned to uiImageColorPicker is not a function, but the object which is returned by the function. This object is supposed to contain all public functions of your plugin and option, _create and destroy, since these are expected by the jQuery UI Widget implementation.
All private functions go to the function body, outside of the object. After the outer function ran, they won’t be accessible any more, but if you use them in functions of the returned object they are bound through a closure and thus can be used by the object’s functions even after the outer function finished execution.
When doing such thing, there are two things I can think of which require a little extra attention:
A bonus: In case you ever forget to remove a private function which you don’t use anymore it will be removed entirely by the Closure Compiler in the minified version of your plugin ;-)
Measuring the result
After refactoring the code, I ran the Closure Compiler again. Before the minified version of the plugin had 3729 bytes. After the refactoring it had 3475 bytes. That’s about 8% smaller. Hm, not quite a lot you’d say. But:
Today I’m releasing my first jQuery plugin :-)
Read more about it here: Image Color Picker or check out the demo.
You can find the code on Github.
Today I played a bit with Canvas and getImageData. What I tried to figure out was how to get the color of a certain pixel. The solution is easy to find via Google. The code looks somewhat like this:
var ctx = document.getElementById('canvas').getContext('2d'); var img = new Image(); img.onload = function(){ ctx.drawImage(img, 0, 0); var objImageData = ctx.getImageData(0, 0, img.width, img.height) alert("Pixel at (0,0): rgba("+objImageData.data[4]+", "+objImageData.data[5]+", "+objImageData.data[6]+","+objImageData.data[6]+")") } img.src = 'test.jpg';
If you run this locally in Firefox. It will show the image, but it won’t show the popup. Instead, you’ll see this exception in the Firebug console:
Security error" code: "1000 var objImageData = ctx.getImageData(0, 0, img.width, img.height)
Here is why:
One way to handle the exception is to catch it, enable the appropriate browser permission and retry.
try { try { var objImageData = ctx.getImageData(0, 0, img.width, img.height) } catch (e) { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); var objImageData = ctx.getImageData(0, 0, img.width, img.height) } } catch (e) { throw new Error("unable to access image data: " + e) } alert("Pixel an (0,0): rgba("+objImageData.data[4]+", "+objImageData.data[5]+", "+objImageData.data[6]+","+objImageData.data[6]+")");
Now, that works, at least in Firefox, but it is ugly, because the user will get a security warning and he has to decide whether to grant the script the requested additional permission.

The only “nice” way of getting the code to work, without browser specific try / catch statements and without security warnings is to host the images on the same domain as the script. Luckily Amazon S3 supports that through Virtual Hosting of Buckets.
If anyone knows about additional solutions for this, I’m happy to hear about it.
Most information I got from this article on Aaron’s blog.
Say the HTML is this
<div id="mydiv" style="border:10px solid #ff0000;">Hello World</div>
then you get the width of the border with this:
var borderWidth =($("#mydiv").outerWidth() - $("#mydiv").width()) / 2;