canto.js: An Improved HTML5 Canvas API

| 9 Comments

I love the <canvas> tag, but its 2D drawing API is intentionally minimal and unfriendly, so I've written a simple wrapper library that improves it.

canto.js defines a single canto() factory function. Pass a canvas element or the id of a canvas element to this function, and it returns a Canto object to you. This Canto object is a drawing context, like the one you'd get by calling getContext('2d') on the canvas element. The Canto object implements the 2D drawing API, so your existing canvas code should work as-is, but it also implements a number of other features.

One of the most important API improvements is that all Canto methods that do not have some other return value return the Canto object. This enables method chaining. For example:

// Draw a triangle
canto("canvas_id").moveTo(100,100).lineTo(200,200,100,200).closePath().stroke();

Notice that the lineTo() method in the code above has four arguments: this is an extension that allows the single method call to draw two line segments.

Another useful API extension is that methods that actually perform drawing operations (such as stroke(), drawImage(), fillText(), etc.) accept a set of graphics attributes to be used for that one operation.

// Draw a colorful triangle with wide lines
canto("canvas_id").moveTo(100,100).lineTo(200,200,100,200).closePath().
    stroke({lineWidth: 15, strokeStyle: "red"});

If you've used SVG you may be familar with the compact path descriptions syntax used in the d attribute of the <path> element. Canto supports this syntax, both with an svgpath() method and with individual single-letter methods like M (moveto), L (lineto), C (curveto) and so on. Here's the SVG version of our triangle:

// Parse an SVG path string
canto("canvas_id").svgpath("M100 100 L200 200 100 200 Z").fill();
// Define path elements with methods with really short SVG-inspired names
canto("canvas_id").M(100,100).L(200,200,100,200).Z().stroke();

Other new API features include relative-coordinate methods like rmoveTo() and rlineTo() and a turtle graphics API. A summary of the API is in the long comment at the top of the canto.js source code.

I've set up a canto-js project at code.google.com and have released it under the MIT license. Comments, bug-reports and contributions are all welcome. Test cases would be particularly nice. I've written a few simple tests myself, and I've run Canto against Phillip Taylor's suite of canvas tests. (Results: in Firefox and Chrome, at least, Canto passes effectively all the tests that the underlying un-canto'ed 2D context pass).

Note that Canto currently uses getters and setters to handle graphics attributes: if you set the lineWidth property on your Canto object, the setter method delegates to the underlying 2D context. IE doesn't support getters and setters, so Canto does not currently work in that browser.

Rough Cut of my JavaScript Book

| 1 Comment

O'Reilly has made a draft of the 6th edition of JavaScript: The Definitive Guide available through their Rough Cuts program. This means that you can buy online access (HTML and PDF) to the current draft of the book today, and then have the print version shipped to you when it is published, for the basic cover price of the book. (See the FAQ for more about how Rough Cuts works).

Online access is through Safari, not directly through O'Reilly, which means that you need to create an account with them in order to do this. But that's a minor hassle if you want the latest version right away.

Part I of the book is finished: complete coverage of ECMAScript 5, along with completely rewritten and modernized chapters on functions, objects and classes.

Part II is being updated for HTML 5 and is still in progress. The first few chapters have been pretty much completely rewritten but a number of chapters are still missing. The Rough Cuts edition will be updated each time I finish a new chapter. If you buy it now you get ongoing access to all the updates.

Java Closures Update

| No Comments

Last Wednesday, I blogged about the fact that closures discussion on the Project Lambda mailing list had petered out.

It appears I spoke too soon: on Friday an Oracle engineer posted a substantive strawman proposal, and followed it up with another significant document on Monday. These have generated much discussion on the Project Lambda mailing lists, and things seem to be moving again.

Yesterday, Neal Gafter "read the tea leaves" and surmised that Oracle has at least three engineers working on closures.

Its nice to know that the project isn't dead. Of course we still don't know whether the Java 7 schedule will slip to accommodate closures or if closures will be postponed for a later release. So the "not likely" assessment from my original post still stands.

Quirks we can forget

| 1 Comment

I've just realized that there is one annoying JavaScript special-case that web developers no longer need to know about, and I don't need to document anymore.

As you know, JavaScript event handlers return false to cancel the browser's default action for the event. Except, that is, for the onmouseover event handler. Because of a bug in Netscape 2.0 (I think) we've always had to return true for that one. Documenting this special case has become a habit for me.

How nice, therefore, to realize that this is now irrelevant. The only default action associated with a mouseover event is to display the destination URL of a link. But to prevent phishing attacks, browsers no longer allow us to cancel this default action (and no longer allow any kind of status line scripting). Since the action can't be cancelled, the return value of onmouseover no longer matters. Hooray!

So I can now just document "return false to cancel". (Of course I still have to document e.preventDefault() for event handlers registered with addEventListener() and e.returnValue=false for event handlers registered with attachEvent(), but this is a step in the right direction.)

Closures in Java 7: Not Likely

| 24 Comments

Five months ago, I posted Closures in Java 7 After All to celebrate the announcement that JDK7 would include closures.

The schedule seemed optimistic at the time, given that Mark Reinhold decided to start with a blank slate rather than adopting one of the existing closure proposals. And sure enough, it was wildly optimistic. The schedule says that JDK 7 will be "feature complete" on June 3rd. But the closures specification being developed by Project Lambda is at version 0.15

Activity on the Project Lambda mailing list has petered out as engineers from Sun/Oracle have become non-responsive. [Update: this has now changed. See my more recent post.] Neal Gafter, one of the hardest-working advocates for closures in Java, has politely and repeatedly asked for clarification of the schedule and of Oracle's commitment to closures.

The only answer he's gotten is from Alex Buckley:

Schedule information for Lambda will be shared when available.

Resourcing decisions are out of scope for this list, but I am sure that any resources assigned to Lambda will be directly or indirectly visible on this list.

It seems that Alex is not permitted to speak openly about this. But given that no activity is directly or indirectly visible through the mailing list, we can infer that there is basically no one at Oracle working on closures. And it makes me wonder: is there anyone one at Oracle with the time and the authority to alter either the release schedule or the feature list for JDK 7?

CSS opacity filter syntax for IE8

| 3 Comments

For a long time, IE's alternative to the CSS opacity property has been the filter property:

filter: alpha(opacity=50);

If you Google "IE8 opacity", you'll find a number of pages (including one at quirksmode.org) telling you that Microsoft removed support for opacity in a preview release of IE8, and then put it back in, but with a new syntax. These pages assert that in order to achieve the same half-transparent effect as above, you must write (note the -ms- prefix and the quoted value):

-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";

As far as I can tell, however, all of these pages are based on preview releases. My (very simple) testing indicates that the old syntax continues to work in IE8, and there is no need to add a second non-standard property to our stylesheets for IE8.

This post at the IE blog backs me up on this (scroll down to the section titled "A Pragmatic Solution") Or at least I think it backs me up. The post tries to explain and justify the initial change to the filter syntax but it just doesn't make much sense.

Someone please correct me if I'm wrong. Are there versions of IE8 in the wild that don't support the old filter syntax?

Mundane Atrocities

| 1 Comment

This post is just a copy of an anti-war letter to the editor I just sent to my local paper.
I think it is one of my better efforts.

ECMAScript 5 Talk Tonight

| 3 Comments

I'll be speaking tonight in Vancouver, BC about the new features of ECMAScript 5.
Details here.

I'll post the slides after I give the talk.

Update: Here are the slides.

March Madness: 7 Years of War in Iraq

| 12 Comments

Its that time of year again!

This is the 7th anniversary of the war the US started with Iraq. The score so far:

Cost to US taxpayers
$713 Billion

US soldiers killed
4385

US soldiers wounded
31616 (though December 2009)

Individually documented Iraqi civilian deaths
About 100,000.

Statistically extrapolated civilian deaths
655,000 deaths (2.5% of the population of the areas surveyed) directly and indirectly caused by the war (through July 2006).

I don't think I can really describe just how angry this makes me.

IE9 will have addEventListener, finally!

| 1 Comment

Microsoft has released a testdrive version of IE9 that includes support for:

  1. addEventListener()
  2. CSS3 Selectors
  3. CSS border-radius style for rounded corners
  4. SVG (no word on <canvas>, as far as I know, however)

Items 2, 3 & 4 are probably bigger news than item 1, but IE's lack of support for addEventListener() has always really irritated me. Finally, more than a decade after it was standardized, IE will support it. That means that by 2015 we can stop writing code that checks for addEventListener() and falls back on attachEvent().

Closures in Java 7 After All

| No Comments

I've been focusing on JavaScript recently, so I missed this when it first came out:
Closures for Java. I think it is interesting that the motivation for finally doing this is to facilitate APIs for concurrency.
Sun will not be using any of the existing closures proposals as a starting point, but their initial ideas are perhaps closest to the FCM (first-class methods) proposal.

There are further details here including the ominous admission by Sun that they don't feel they can get any JSRs (for closures, Project Coin, or Java 7) approved by the JCP until they resolve their dispute with Apache. In the meantime, development of closures and the Coin extensions is happening outside of the JCP in the OpenJDK.

In related news, the schedule for OpenJDK7 has slipped and a final release is now due in September 2010. Note that this is the schedule for the JDK7, not for Java 7.

A module loader with simple dependency management

| 4 Comments

I've written another version require2.js of my CommonJS module loader require() function. This one has two interesting features.

First, you can "pre-load" modules by mapping the module filename to the module function in the require._module_function object. If you do this, then the module will not need to be loaded. For example:

require._module_functions['math.js'] = function(require,exports,module) {
     // Code for the math module goes here
};

Second, this new version of require() has a require._print hook, which, if set to a suitable function, will print out the text of all modules it loads, wrapped in a function and assigned to the require._module_function map as above. You can even define a require._minimize hook if you want to do code minimization on your modules.

I've defined another script display_requirements.js that defines suitable _print and _minimize functions.

So, here's the upshot. For relatively simple applications that load modules statically at start up, use the require2.js script for loading modules. Its inefficient, but works well during the development phase. Then, when you're getting ready to deploy your application, load the display_requirements.js script after loading require2.js but before you actually call require() anywhere. This will cause a big chunk of code to appear at the bottom of your web page--pre-loaded minimized versions of all the modules you used. Cut-and-paste this code into a new file named requirements.js (or even paste it at the bottom of require2.js) and load the requirements.js script in place of the display_requirements.js script. Now you can continue to use require() as you have always done, but it won't have to hit the network to load your modules.

I haven't done much deployment of real-world web applications, and am not qualified to say whether a system like this would actually be helpful in practice. But it was an easy tweak to my existing code, so there it is.

CommonJS Modules implementation

| 11 Comments

I've implemented the CommonJS Modules 1.0 specification with the code in this file. It appears to pass the compliance tests when run in Firefox and Chrome on Linux, and also when run standalone in Tracemonkey, Rhino or V8.

Note that this implementation does not use the namespace probing technique I described in my previous post.

Update: One of the things that really surprised me when testing my implementation was to discover that the CommonJS spec requires (this is not explicit in the specification text, but it is explicit in the conformance tests) the require() function to return the actual exports object of a module, and not make a defensive copy of it.

Suppose a program includes module A which includes modules B and C. Module C can require B and then add, replace, or remove methods from B's API. Later, when the program includes Module B directly, it will get the modified version of B. In order to correctly use this modified module B, the programmer will have to read the documentation for module C!

Update 2: There are great comments to this post, including a link to Luke Smith's blog post that argues that the synchronous nature of CommonJS modules is not a good fit for client-side scripting. In response I wanted to make clear that I posted this code because I thought it was interesting, not because I think that client-side programmers should go out and start using it right away.

Functions as Namespaces, and How to Peek Inside

| 19 Comments

It has become common in modern JavaScript programming to use functions as namespaces. If you put your code inside a function, then your variables and functions are local to the containing function and do not clutter up the global scope.

var value = (function() {  // Wrapper function creates a local scope or namespace
    // your code goes here
    return value;  // Export a value from the namespace
)());  // Invoke the wrapper function to run your code      

Now suppose that you have some JavaScript code as a string--you've just loaded it using XMLHttpRequest, for example. You're going to evaluate the code, and you might want to evaluate it in a namespace so that it doesn't define functions and variables in the global scope. This is easy: just wrap it in a function before evaluating it. In this case, the Function() constructor is even more handy than the eval() function:

var code = ....;  // A string of JS code to evaluate
var f = new Function(code);   // Wrap it in a function
f();    // And run the function

The problem with doing this is that the function creates a sealed namespace and we can't see what is inside. If the code defines something useful like a function or a class, we can't access it, and it does us no good.

Here's a trick I've just discovered. (I'm sure someone else has thought of this, but I haven't seen it used or described elsewhere). Before you wrap your code in a function add this line to it:

return function(s) { return eval(s); };

Now, when you invoke the wrapper function, it returns this evaluator function to you. The returned function evaluates a string in the scope of the namespace, so you can use it to peek into the namespace and extract whatever values you want!

If your string of code defines a constructor function named Set() that you want to use, you can run the code in a namespace and then extract f from the namespace like this:

var code = readFile("Set.js");  // A string of JS code to evaluate
// Define and invoke a wrapper function with special suffix code.
// The return value is a namespace evaluator function and we treat
// it as a namespace object.
var setns = new Function(code + "return function(s) { return eval(s); };")(); 
var Set = setns("Set");  // Import the Set function from the namespace.
var s = new Set();  // Use the class we just imported

And what if there are 3 values you want to extract from the namespace?

// Extract an object containing 3 values from the namespace
var sets = setns('{Set:"Set", BitSet:"BitSet", MultiSet:"MultiSet"}');
var bs = new sets.BitSet();

I've defined a namespace() function for loading code and doing this kind of namespacing automatically:

Google Closure Library and Optimizer

| No Comments

Google has open-sourced the javascript library and optimizer they use in gmail and other web applications. They call it "Closure" and you can read about it here.

While the optimizer looks very cool, I think the library is most impressive. Its a really large code base, and at least some of it has been thoroughly field-tested in gmail and similar applications. You can get the code like this:

svn checkout http://closure-library.googlecode.com/svn/trunk/ closure-library-read-only

The closure library is intended to be used with the closure optimizer which removes unused code, so the APIs are broad with lots of methods--there is no sense that the closure developers were skimping on API in order to pack everything into a small download bundle. Also, and perhaps for the same reason, the code is not full of micro-optimizations. Compared to the jQuery and YUI code (for example) the Closure code is straightforward and easy to understand.

Books

Comprehensive coverage of Ruby 1.8 and 1.9

"The New Most Important Ruby Book"
Peter Cooper,
rubyinside.com

Completely updated for Ajax and Web 2.0

"A must-have reference"
Brendan Eich,
creator of JavaScript

The classic Java quick-reference

Advertising

Pages

Hosted By

Powered by Movable Type 4.21-en