2008-04-10

Expensive, yet responsive, live interaction

Let's say you have a slider widget that users can drag to filter a largeish table so it only shows rows where some column is greater than the a threshold, defined by the slider. That's an application with rather strict real-time constraints, but filtering the table is expensive; a naïve solution that refilters the table with every drag event you get, or even just every event that changes your threshold value, will still be too slow for the interface to feel responsive.

I just came up with a rather elegant solution for that problem, which makes sure that your expensive code won't make the interface feel sluggish, by postponing calls to it that come in a more rapid succession than the time it would have taken for it to run. Or, to be precise, the time it took last time it was called. It's a simple wrapper function you can reuse anywhere:

// returns a function that only runs expensive function
// fn after no call to it has been made for n ms, or
// 100, if not given, or the time fn took last time, if
// it has been run at least once and no n was given.
function expensive(fn, n) {
function run() {
fn.timeout = null;
var timer = n || new Date;
fn();
if (!n) duration = (new Date) - timer;
}
var duration;
return function postpone() {
if (fn.timeout)
clearTimeout(fn.timeout);
fn.timeout = setTimeout(run, n || duration || 100);
};
}


You might of course want to add some argument and this re-binding to it, for cases where the callback isn't self-contained, but then it gets a bit more cluttered, and I really just wanted to show the principle here. Typical usage is replacing your node.addEventListener("mousemove", callback, false) with the wrapped node.addEventListener("mousemove", expensive(callback), false) version, and suddenly, the UI is not only bearable, but probably even rather pleasant to use.

2008-03-10

Google site index bookmarklet

The bookmarklet first, for anyone who wants to opt out of the verbiage: I call mine @site, which fits snugly in my bookmarks toolbar. It searches Google for any page Google has indexed on the site you are presently visiting, and presents them in Google's usual interface which you learn how to navigate once, and can then use for the rest of your life, pretty much without ever thinking about it.

I am well aware that one of the things that made the web so hugely popular with content producers, is its very anarchic non-standardization of the user facing interface. Yes, your graphics and interaction designers are at full liberty to devise pretty much any user interface and interaction scheme they damn well want to, and they happily do so, too. The same applies to DVD menus too, though, thankfully, the dvd consortium at least recognized that their medium was one of entertainment primarily (or, through dumb luck) and somewhat constrained the technical possibilities a little.

Web sites are fairly unconstrained about their navigation (im)possibilities, though, and as every web site ever made is a country of its own with conventions of their own (most -- thankfully -- even shared with or at least inspired by others, modeled from similar components, and so on), so lots of features you might want the medium to provide, like "show me the most popular pages of this site" have to be found, when they exist, identified as such, and learned, before you can use them, once per site, or even once per content producer and site, when shared between several.

That most of the web imitates most of the rest doesn't change the fact that visitors still have a level of interface burden that is not associated with media like books, where every language has a common convention for which order you flip the pages, where to start reading, and so on, and, even across languages, most agree on left to right, top to bottom. The web could have conventions like these, but has not evolved to that stage yet (and might never do). There is some consolation in that browsers have a set of basic functionality for finding text within a page, scrolling it and the like, which is rarely intruded upon by web pages (but little prevents them from doing so).

While I don't know the particular sort criteria Google uses for open searches like the one this bookmarklet does, it often does seem to list the more popular pages first, at least on web sites like Alertbox, some of the first hits are the basic sections of the site. Reading Jacob Nielsen's top-10 application-design mistakes, how many perceive the web as one application? I do. I think most naïve, non-technical users who could not care less about the detail inner life workings of the web, do too.

And I think you should, too, despite knowing a lot more about it than that. Your web sites and design thoughts will surely benefit from it. I am rarely happier than when taming the web to behave more like one single, internally consistent, application, that responds to my actions in the same way, regardless of whichever of its zillion dialogs I happen to interact with. Try not to waste their brain power on working your part of that application, if you can. Yes, it is more fun for your own ego to have them adapt to your whims than you to their expectations and there are counter-examples to every rule, but those account for miniature fractions of a percentage, and it is pretty safe to assume that your application is not one of them.

That said, most of my web sites and hacks venture far into the territory of doing things backward, one way or another. I can assure you that the visitor appeal of said hacks, measured in raw numbers, are inversely proportional to their obscurity. The same is true of my obscure writing.

2008-03-07

JSEnv live XPath visualizer

I've had some productive hack weekends recently -- last weekend, among other things, I took a plunge into the Firebug 1.1 beta, both to re-apply a rather useful feature patch I submitted upstreams a year ago (which was lost, and found, and lost and found again -- might make 1.2) and to add some handy keyboard shortcuts to the HTML view (deleting nodes with delete and backspace, and both folding/unfolding and stepping up/down the DOM tree with arrow left and right).

Anyway, I ended up excavating Firebug's highlight-a-node code to turn it into a tiny lib and then use that lib for beefing up Jesse Ruderman's jsenv bookmarklet with a live edit XPath field highlighting all matches in the page as you type:

screenshot of the live XPath visualizer

It tells you what the expression matches in the title bar of the jsenv window, and signals some additional colour coded info via the XPath input field's border:

  • red for illegal expressions,
  • green for matching nodes,
  • gray for 0 matched nodes,
  • yellow for a string,
  • blue for a number and
  • magenta for a boolean value.
Ah, one more feature -- you move the focus node you see with arrow up and down in the input field, or scroll wheel up/down when hovering it.

The ideal spot for this feature would probably be as an extra feature to toggle on and off in Firebug's HTML view -- to filter the view by, for instance. The more I think of it, the more useful this feature would be in that shape. I hope the Firebug Working Group is as open to additional community developers as it seems to aim for.

Anyway, here is the XPath jsenv; enjoy!