Embedded SVG
August 30th, 2006http://pwdemo.rcode.net/svg_tester
![]()
I know I’m probably late to the game on this one, but I had not realized until recently how well SVG was supported in a lot of browsers. I actually didn’t realize it until I needed it for a visually rich application prototype I’m working on. I really didn’t want to use Flash, so I checked out SVG again. To my suprise, it is fully integrated into Firefox, Opera 9 and some (pre-release?) versions of Safari.
So I started with the SVG example from Mozilla.org. It draws three circles with primary colors that are semi-transparent:
1: <svg xmlns="http://www.w3.org/2000/svg"
2: version="1.1" width="500" height="500"
3: baseProfile="full">
4: <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm">
5: <circle cx="6cm" cy="2cm" r="100" fill="red"
6: transform="translate(0,50)" />
7: <circle cx="6cm" cy="2cm" r="100" fill="blue"
8: transform="translate(70,150)" />
9:
10: <circle cx="6cm" cy="2cm" r="100" fill="green"
11: transform="translate(-70,150)" />
12:
13: </g>
14:
15: </svg>
16:
I thought a modest goal would be to adapt Protowidget so that it could attach widgets to some SVG elements. I could then use the property bindings to make the circles move around. It’s dumb and pretty simple but forms the basis for creating more advanced SVG widgets.
This turned out to be harder than I had expected. The main culprit was that Protowidget wasn’t fully compatible with real XHTML. There’s the normal stuff: no document.write (it was used to bootstrap the system by writing script elements to the header), createElement must use namespaces, etc. It took a little longer than necessary to fix because I still wanted to preserve compatibility with namespaced xml documents and IE when the advanced features were not in use.
So I fixed all of that and added real namespace support so that the Protowidget attributes are now part of their own namespace if using an XHTML document. If working in normal HTML, the pw.* syntax can still be used. There’s even a hack, so that if you use the “pw:” prefix for your namespace, the parser will be able to work around IE’s deficiencies. I then added an SvgWidget to mirror the HTML DOMWidget (which in hindsight should have been named HTMLWidget). It’s basically a light version of the DOMWidget base class which leaves off the CSS class and style processing that does not apply (at least in the same way) to SVG elements.
The end result was to change the example SVG to include some Protowidget attributes:
1: <svg xmlns="http://www.w3.org/2000/svg"
2: version="1.1" width="500" height="500"
3: baseProfile="full">
4: <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm">
5: <circle cx="6cm" cy="2cm" r="100" fill="red"
6: transform="translate(0,50)"
7: pw:type=’Svg.SvgWidget’
8: pw:element.r=’#{`Jitter1`}’/>
9: <circle cx="6cm" cy="2cm" r="100" fill="blue"
10: transform="translate(70,150)"
11: pw:type=’Svg.SvgWidget’
12: pw:element.r=’#{`Jitter2`}’/>
13: <circle cx="6cm" cy="2cm" r="100" fill="green"
14: transform="translate(-70,150)"
15: pw:type=’Svg.SvgWidget’
16: pw:element.r=’#{`Jitter3`}’/>
17: </g>
18: </svg>
19:
What this does is declare the three circle elements to be of Protowidget type “Svg.SvgWidget”. As I mentioned before, this is intended to be a base class for more advanced Svg widgets, but it provides some features that make it useful on its own. For one you can establish bindings between Protowidget models and attributes of the elements. This is what is done with the pw:element.r attributes. They are binding the circle’s radius to the values of “Jitter1″, “Jitter2″ and “Jitter3″ respectively.
What makes this go is a little chunk of code in the header that sets up a timer to set Jitter1, Jitter2 and Jitter3 to random values:
1: PwLoader.inlineExecute(function() {
2: Protowidget.beforeStartup(updateJitter);
3: });
4:
5: function updateJitter() {
6: Protowidget.RootWidget.setAttribute(’Jitter1′, 100+Math.random() * 50);
7: Protowidget.RootWidget.setAttribute(’Jitter2′, 100+Math.random() * 50);
8: Protowidget.RootWidget.setAttribute(’Jitter3′, 100+Math.random() * 50);
9: setTimeout(updateJitter, 100);
10: }
11:
(The couple of lines at the top are necessary for inline scripts that act outside of the module system. It ensures that the script is executed at the proper time in the startup sequence.)
Pretty neat, huh!
Here’s the URL again: http://pwdemo.rcode.net/svg_tester
I’ve tested it with Firefox 1.5 and Opera 9. It should work on Mozilla builds with SVG enabled.
For anyone whose interested, you can get all of this from anonymous svn: https://dev.rcode.net/svn/protowidget/trunk/protowidget
You can also visit the Protowidget Wiki.
IE7 Beta 3 JavaScript DOM Speed
August 15th, 2006For the past several months I don’t think I ever had a positive thing to say in the same sentence as “Internet Explorer”. Well, that has changed now. I’ve been delaying pulling down the IE 7 betas for fear of how difficult my life would become in trying to adapt my JavaScript solutions to the new browser.
I have to say that I was pleasantly surprised. I mean not surprised enough to switch, but surprised enough to chear for the launch of IE7 as a high priority update so that I can actually dream of the day when IE 6 is no more. I don’t have any solid numbers for exactly WHAT is faster, but the whole thing is a LOT snappier. Total operations that I had timed on IE6 to take 7-10 seconds are now taking 300-400ms, which is on par with Firefox and Opera. These operations consist of very heavy DOM manipulation and a good deal of JavaScript parsing.
Maybe its time to take some of those “IE SUCKS” comments out of the body of my if statements that have to do something different for IE6 or subject the user to interminable delays.
So, I am pleasantly surprised, and I haven’t been pleasant or surprised about anything out of Redmond for quite some time!
Somewhat ironically, I did notice that none of the CSS glitches that plagued the site I was testing on IE seem to have been corrected by the upgrade. And this after months of hearing that CSS fixes were the priority and that about all we could expect for JavaScript enhancements was the elimination of the dreaded closure memory leaks. Oh well… CSS I can fix. JavaScript that runs 10-20 times slower on IE than anything else is another matter.
The Effects of JavaScript Compression
August 6th, 2006I’m getting ready to take my first Protowidget application to production, and its time to address one of those things that sometimes makes me wake up at night in a cold sweat: I’m writing all of this JavaScript code and its getting huge. What impact is that going to have on perceived site performance when run over slower links?
Protowidget depends on Prototype; there’s 54KB of JavaScript source right off the top. Protowidget plus the logger adds another 174KB or so. That leaves a total of 228KB of JavaScript to shove across the wire.
Protowidget is divided into a number of modules that are dynamically loaded as needed. In a dev environment, this works fine, but the overhead of having the browser run out to the server a dozen times for JavaScript source files can quickly outstrip the cost of having the browser go out once to fetch all of the core modules combined into one big file.
So with this information in hand, I set out to optimize the problem. My plan of attack had three prongs:
- Pack prototype + logger + all of the core modules into one big JavaScript bootstrap file (the loader stub is still separate for now - it was modified to try loading this bootstrap module before dynamically loading anything else)
- Run JSMin on the bootstrap file and the loader
- Generate gzip pre-compressed versions of the files that mod_gzip or mod_deflate can serve to HTTP 1.1 browsers
The results were pretty astounding. Here is a partial directory listing after the prodedure:
-rw-r--r-- 1 pactimo pactimo 8201 Aug 6 09:06 protowidget.js -rw-r--r-- 1 pactimo pactimo 1461 Aug 6 09:27 protowidget.js.gz -rw-r--r-- 1 pactimo pactimo 136890 Aug 6 09:27 protowidget_bootstrap.js -rw-r--r-- 1 pactimo pactimo 33599 Aug 6 09:27 protowidget_bootstrap.js.gz -rw-r--r-- 1 pactimo pactimo 224963 Aug 6 09:27 protowidget_bootstrap_full.js -rw-r--r-- 1 pactimo pactimo 4492 Aug 6 09:27 protowidget_minify.js
Here is the legend of what’s what:
- protowidget.js - Un-minified Protowidget loader (sets up the module system and dynamically pulls in prototype + logger + core modules)
- protowidget_minify.js - Minified version of the loader
- protowidget.js.gz - Minified and GZIP compressed version of the loader
- protowidget_bootstrap_full.js - Concatenated source file of prototype + logger + core modules
- protowidget_bootstrap.js - Minified version of prototype + logger + core modules
- protowidget_bootstrap.js.gz - Minified and GZIP compressed version of prototype + logger + core modules
You can correlate the numbers from the directory listing, but here they are in brief:
- JSMin reduced the aggregate bootstrap file by 39% (from 220KB to 134KB)
- GZIP reduced the minified aggregate bootstrap file by a further 75% (from 134KB to 33KB)
- For browsers that can accept GZIP compressed content, this is a total savings of 85% (the original version is 6.7 TIMES larger)
The loader file, which remained separate, compressed down with similar results. Overall, this means that the total transfer required to load Protowidget dropped from 228KB down to 34KB for browsers capable of receiving GZIP encodings. Further, the individual number of files to load dropped from 12 to 2. This optimization has reduced the time to load from scratch for some parts of the app from a 10+ second ordeal down to 1 or 2 seconds. Even under dialup a 34KB download is reasonable, especially considering that it is cached and serves a very long-lived part of the application.
One thing to note is that while all modern browsers CAN support GZIP encodings, not all are configured to do so. In particular, I have observed that some corporate installs of IE disable HTTP 1.1 through proxies, thus eliminating GZIP as well. From there, it’s anyone’s guess as to whether the proxy itself requests resources via HTTP 1.1 and can accept the GZIP encoding.
In conclusion, it’s nice to know that only about every 6-7th character I type in a JavaScript source file actually contributes to the total transfer cost. There is still a cost on the browser for pawing through all of that source, though, so the need to write concise JavaScript is still as present as ever.