Archive for the ‘JavaScript/DHTML’ Category

Rhino+Dashboard… it’s like crack

Monday, February 27th, 2006

If you are a JavaScript junkie who is in constant need of a fix… here’s a little Dashboard trick I like to use to keep an interactive JavaScript prompt available at all times.

(works for Python and Ruby junkies too)

Dashboard+Rhino crack

  1. Download the WidgetTerm Dashboard Widget. WidgetTerm is basically like Terminal.app in Widget form (although I believe it’s actually based on the open source iTerm application).
  2. Download Rhino 1.6… Mozilla’s Java-based implementation of JavaScript 1.5 + E4X + JS interactive interpreter + JS-2-Java bridge.
  3. After unpacking Rhino, put its js.jar file on your classpath. If you’re not a Java developer, this is easy… just drop js.jar in ~/Library/Java/Extensions.
  4. Now edit this file: ~/.bashrc in your text editor of choice. If it doesn’t exist, just create it. Place the following line in that file:
    
    alias js='java org.mozilla.javascript.tools.shell.Main'
    
    

    Quit and restart Terminal.app (or just source .bashrc). You now have access to a command-line interactive JavaScript interpreter just like the ones provided by Python and Ruby. All you have to do is open a Terminal.app window and type js. BAM… live JavaScript interpreter.

  5. Now then… You have installed WidgetTerm right? Good. Activate Dashboard and drag a new WidgetTerm Widget out from the Widget Bar onto the screen. Type js.

There you have it. Now accessing a live JavaScript interpreter is as easy as activating Dashboard.

Since Python and Ruby both have interactive interpreters by default, you can use this trick for them too… I like to have a Python and a JavaScript WidgetTerm open at all times. :)

Style tip for OO JavaScript

Monday, January 30th, 2006

Here’s a coding style tip for writing more readable object-oriented JavaScript… What follows is a technique for writing OO JavaScript that is a bit more similar to what you see in more purely OO languages like Java or Python. This technique can (sometimes) lead to more sensible, readable JavaScript code.

To some of you this will be old news, as its certainly not an original idea. The first time I saw this technique was a few years back in some Gecko JavaScript source code, and I was pretty blown away. It had never occurred to me to write JavaScript this way… and I thought it was neat.

So we all know that JavaScript has a literal syntax for arrays and objects (very similar to Python arrays and dictionaries).

Arrays:


var myArray = [1, 2, 3];

Objects (JavaScript terminology for dictionary, associative array, or name-value pair):


var myObject = {name: "Tod" };

Note that unlike Python dictionaries, with JavaScript objects you do not place quotes around the names in name-value pairs… a small, but important distinction.

Also note that like Python, JavaScript functions are data… and also have a literal syntax. Therefore you can add them to your object literal instances:


var myObject = {name: "Tod", toString: function () { return "Person ( " + this.name + " )";} };

This object literal syntax can be very useful for one-off objects. However, if you plan on creating multiple object instances from a single "prototype", you’re probably better off defining a JavaScript "class" using a constructor function and some instance methods on the constructor function’s prototype:


function Person(name) {
	this.name = name;
}

Person.prototype.toString = function () {
	return "Person ( " + this.name + " )";
};

So there you have your typical JavaScript "class definition". It just looks a little weird, doesn’t it? It’s kinda hard to tell just by glancing that the toString method is an instance method of the class who’s constructor is placed above. But that’s just the way JavaScript works.

Actually, there is something of an alternative to this syntax. But the alternative has its benefits and drawbacks. Remember our object literal syntax above? How about we add some whitespace and make it look a little more Java-esque?


var myObject = {

    name: "Tod", 

    toString: function () {
        return "Person ( " + this.name + " )";
    } 

};

One problem with this change is that our object is now a one-off instance of its type… we have no constructor function, and no means of creating additional instances. That’s ok… we can fix that too, by breaking the object into a constructor function and a prototype definition. That way, we get most of the readability benefits of the more Java-like class syntax, but still have a constructor for creating additional instances later:


function Person(name) {
	this.name = name;
}

Person.prototype = {

    toString: function () {
        return "Person ( " + this.name + " )";
    },

    getName = function () {
        return name;
    },

    someOtherMethod = function () {
        ...
    }

};

var me = new Person("Tod");

I don’t know if anyone else is impressed by this, but the first time I came across it, I was pretty psyched. Note the important commas (,) after every instance variable or instance method. You will need those to avoid a JavaScript syntax error.

There are, however, drawbacks to this technique… Including the Person class in a type hierarchy is not possible with this syntax AFAIK (would love to be proved wrong there). Normally, to declare a subtype of an existing type in JavaScript, you do this:


Developer.prototype = new Person();
// next line fixes a little known problem in JS hierarchies...
// saw this explained in O'Reilly ActionScript book
Developer.prototype.constructor = Developer;

function Developer(faveLang) {
    this.faveLang = faveLang;
}

Developer.prototype.getFaveLang = function () {
    return this.faveLang;
};

Now Developer is a subtype of Person. I don’t know of anyway to achieve both the alternative syntax displayed above (in the Person class) and the subclassing functionality shown here with Developer on line 1. Any ideas?

(keep in mind that i’m not necessarily advocating the use of accessor methods in JavaScript here… the code is just meant to be an example)

Anyway… again, I know this is old news to many of you JavaScript bad-asses out there… but I hope that some of you guys can use this technique to make OO JavaScript a little more fun.

WebKit Freakshow: CanvasUML

Sunday, January 15th, 2006

Update: Having had a chance to test CanvasUML on some other Macs, I’ve determined that it’s a flaming pile of crap, and doesn’t actually work right now. I’ll repost a working version in the near future. Until then, don’t bother downloading it… just wait.

CanvasUML IconI’m somewhat frightened to announce my latest Cocoa app: CanvasUML 0.1.

The rest of my Cocoa apps (mostly developer tools) at Scandalous Software.

CanvasUML is a technology preview of a basic UML class-diagramming app implemented using an unholy mix of Apple’s WebKit, HTML, JavaScript, Cocoa, CSS, the <canvas> tag, contentEditable, and Safari JavaScript Drag n Drop that runs on Mac OS X Tiger.

Yup. That’s right. A UML diagramming app built mostly in DHTML and <canvas>. Ooooh… the FILTH of it!

CanvasUML is barely alpha-quality software and should not be used for mission critical work (as if there were such a thing as mission critical UML diagramming?). It should be thought of as an exploration of what is possible using the above technologies rather than a solid app. Moving forward, CanvasUML will most likely be refactored into a pure Cocoa/Objective-C application rather than continue with JavaScript/WebKit.

Warning there are bugs!

Implementation Details

The main window in a CanvasUML document consists of a WebView (basically like a Safari window) filled by a large, resizable <canvas> tag. The class/instance boxes are DHTML <div>s with nested contentEditable <div>s for the title, attribute, and operations sections. The association lines and the shadows behind the class boxes are, of course, drawn by the <canvas> tag. CanvasUML saves its doucuments as HTML files which link against a shared CSS stylesheet and JavaScript library stored in the CanvasUML app bundle (take a look if you’re curious).

If you’re still reading… I know what you’re thinking…

WHY?

Why create a Cocoa UML diagramming app using a WebView and the <canvas> tag?

Well… creating CanvasUML has been much more about experimenting with WebKit and Apple’s proprietary WebKit-related extensions to see what is possible, than it has been about building a sensible, maintainable, production-ready application.

Like the title of this post says… it’s a Freakshow, not an application.

I also liked the idea of possibly porting CanvasUML to the web entirely as a web-based UML diagramming application useable by <canvas>-enabled browsers. I may still pursue this later.

After doing the work, I am really eager to take what I’ve learned and re-implement the application using pure Cocoa/Objective-C. Building a full application such as CanvasUML largely in DHTML is really not a good idea… the code is messy and hard to maintain… the desired effects are often hard to achieve… there’s no support for undo/redo… and performance is poor.

All that said, I have to admit my surprise with how well CanvasUML has turned out (for what it is). It seems that the concept is totally possible (although not without its problems).

DHTML Showcase: iZoom in JavaScript

Sunday, January 8th, 2006

In late 2004, I released a free Java/Swing app called iZoom for cropping and resizing photos (It may look like a Cocoa app, but I assure you… it’s pure Swing with MANY custom UI controls painstakingly customized to look like Aqua widgets… god Swing is a pain in the ass).

I’m still working occasionally on porting iZoom over to Cocoa. I’ve gotten off-track with it several times now… I really enjoy creating developer tools (specifically of the XML-variety) like XML-RPC Client or XML Nanny more than I enjoy building consumer-targeted apps like iZoom.

Anyhow… today I ported the iZoom UI to the Web! All I’ve done is create main UI minus the actual cropping features. The example uses DHTML - XHTML/CSS/JavaScript to offer a highly-dynamic image resizing UI. Maybe I’ll actually do something with this soon.

iZoom for the web.

Works in IE 6/Win, IE 5.5/Win, IE 5.0/Win(!). Firefox/Moz/NN, Safari, Opera, OmniWeb, Camino, etc.

OmniGraffle/Visio with the Canvas Tag!

Saturday, January 7th, 2006

How’s this for a <canvas> tag example?

OmniGraffle/Visio subset using the <canvas> tag!

Awwwwww yeah!

Works best in Safari, and only works in <canvas> tag-enabled browsers:

  • Safari 2
  • Firefox 1.5
  • Opera 9

If you’re on a Mac and using Firefox or Opera, you really should try this with Safari… Safari’s <canvas> tag implementation supports drop shadows while Firefox and Opera do not :( .

IE users should Upgrade immediately.

Canvas tag screenshot

Canvas Tag Scribble Pad

Wednesday, January 4th, 2006

Werd… check out my <canvas> Tag Scribble Pad example!

Large scribble pad available on its own page.
Update : Another cool example.

This scribble pad is implemented entirely in JavaScript using Apple’s <canvas> tag API. The <canvas> tag is supported by Safari 2, Firefox 1.5, and Opera 9.

Here’s the source code:


<html>
<head>
    <title>Canvas Scribble</title>
    <style type="text/css">
    /* <![CDATA[ */

    body {
        -khtml-user-select:none;
        -moz-user-select:none;
    }

    #canvas {
        border:1px solid silver;
    }

    #button {
        width:750px;
        text-align:center;
    }

    /* ]]> */
    </style>
    <script type="text/javascript">
    /* <![CDATA[ */

    var canvas, context;
    var x1, y1, x2, y2, dx, dy;

    function windowLoaded() {
        canvas  = document.getElementById("canvas");
        debug   = document.getElementById("debug");
        context = canvas.getContext("2d");

        canvas.addEventListener("mousedown",mousePressed ,false);
        canvas.addEventListener("mouseup"  ,mouseReleased,false);

        context.lineCap        = "round";
        context.lineJoin       = "round";
        context.lineWidth       = 2;
        context.shadowBlur       = 3;
        context.shadowColor   = "#ff0000";
        context.shadowOffsetX = 2;
        context.shadowOffsetY = 2;
    }

    function mousePressed(evt) {
        canvas.addEventListener("mousemove",mouseDragged,false);
        context.beginPath();
        x1 = evt.pageX;
        y1 = evt.pageY;
    }

    function mouseDragged(evt) {
        x1 = x2;
        y1 = y2;
        x2 = evt.pageX;
        y2 = evt.pageY;
        context.beginPath(); // necessary for Opera 9.0beta. why???
        context.moveTo(x1,y1);
        context.lineTo(x2,y2);
        context.stroke();
    }

    function mouseReleased(evt) {
        canvas.removeEventListener("mousemove",mouseDragged,false);
        context.closePath();
    }

    function clearCanvas() {
        context.clearRect(0,0,
                          canvas.getAttribute("width"),
                          canvas.getAttribute("height"));
    }

    /* ]]> */
    </script>
</head>
<body onload="windowLoaded();">

<canvas width="750"
        height="500"
        id="canvas">
</canvas>

<input type="button"
       id="button"
       onclick="clearCanvas();"
       value="Clear"/>

</body>
</html>

More good Todd news

Tuesday, December 6th, 2005

Very cool news… I’ve been given the opportunity to be a technical reviewer for a single chapter in the upcoming 5th edition of O’Reilly and Associates JavaScript: The Definitive Guide by David Flanagan.

It’s the chapter on scripting client-side graphics with JavaScript.

This is a huge honor for me, and particularly special, as the 3rd edition of this very book was my first ‘programming’ book. David is an amazing author, and he taught be how to program. When he contacted me to do the review, I was totally blown away.

I’ve turned in my humble work, and received some positive feedback, so I’m really excited to see the book in print!

BTW, the chapter that I reviewed was fantastic! It moved quickly, yet coherently through several advanced and interesting techniques for producing graphics with JavaScript in modern browsers — a feat that has traditionally been very difficult to achieve in JavaScript.

I consider myself an expert in this area (apparently some others do too), but I was still amazed by the number of new (to me) concepts David shows in this chapter. Impressive!

JS: TDG has always been my preferred JS reference… If you are into JavaScript, or looking to jump on the Ajax bandwagon, you need to check this book out when it arrives.

Wha? JavaScript SAX API? Cool!

Friday, December 2nd, 2005

Although I’ve seen XML for <script> before… I never looked too closely.

Why didn’t anyone tell me they have a wonderful JavaScript SAX API!!!! I guess I can take that item off my list of possible personal projects. Way to go guys!