Sunday, December 24, 2006

Wet and Dry UI

I use screen wipes to clean my monitors. These are the wet/dry systems that you find at your local office supply store. I typically do it every week and I don't look forward to it.

It's not because it's messy or that it takes a lot of time. It's because I have to figure out which one is the "wet" and the "dry" pad. The two pad system is very frustrating because even though I've been doing a lot, I still have trouble figuring it out.

It's best to show you what the two pad system looks like --

Which one is the wet and which one is the dry?

Well, if you look closely, the one on the right is the wet (actually, the resolution is horrible, but take my word for it. The wet one is on the right). Right before the French instructions, you'll see the words "Wet Wipe."

It's the same for the dry.

The problem with the "UI" is that the font is way too small -- for everything. Second, in the area where differential occurs (i.e. "Wet" and "Dry"), these areas look identical.

Where visual differences are required to provide distinction, it's best to make them stand out. Especially when you're relying on typography to guide the user, it's best to highlight the areas where you want your users to look (and act).

People look for visual clues to do things. By making the font properties identical (size, weight, color, etc.), you leave the impression that the two wipes have the same importance and that order doesn't matter when in fact they do.

The wet pad is on the right. If that pad is used first, shouldn't that pad be on the left? At least for the U.S., that makes sense.

When we design UI, we need to think about how we can make it easier for our users to do what they need to do. For the screen cleaning system, the most basic of that is letting the user know, "Hey, the pad on the left is the wet one. Use that first."

It's not to switch the order of things and make the font super tiny so that its difficult to read. Screen wipes are supposed to be easy to use.

Tuesday, December 19, 2006

Cool Blue Nile Sliders

One of the most successful luxury consumer sites is Blue Nile. Who would have thought that buying diamonds was something that people would want to do on the internet, but they do.

One of the really cool things about Blue Nile is that they have some really innovative ways to filter data (in this case - diamonds). The filtering is asynchronous (AJAX), but it's their filtering control that we'll be looking at.

Here it is --

Here's the link to their filtering widget.

With the Bindows 2.5 or 3.0 Toolkit, we'll build a reusable component like what Blue Nile has. Here are a few of them built with our component -- FilterSlider --

The first thing we notice is that the Bindows library doesn't offer a slider with two thumbs. BiSlider only has one thumb, but we can set a property to make it a vertical or a horizontal slider.

What we'll do is take two of these vertical sliders and stack them on top of each other. We'll set the maximum and the minimum value to be the same. In fact, they'll be the same in almost everything (size, location, etc.), but the value. This way one of them is the top and the other is the bottom thumb.

The code looks complicated, but it really isn't. The sliders are placed inside a slider body which is nothing more than a BiComponent. Inside the FilterSlider, we also have two "odometers" which are BiLabels that display slider values. These change dynamically as the slider value changes.

Last but not least, we have a "topBg" and a "bottomBg." These are the backgrounds for the thumbs. That is, when we slide the thumb, the background expands and collapses depending on the direction that we're going.

The other important piece is how we select the thumb. Because the sliders are on top of each other, we have to first determine the position of the pointer and then from that determine which thumb we're on. We can't simply have the slider listen for the "change" event.

Whenever we dispatch a mousemove or a mousedown event in FilterSlider, we determine where we are. If we are over a thumb, we set that thumb to have a higher z-index than the other thumb.

The thumb with the higher z-index "wins" and so, that thumb listening for the change event (i.e. slide, maximum or minimum value change) will react.

With a little styling we get this.

The implementation is found here and the test driver is here. To get the images, just view the source and follow the links.

Feel free to use and improve on the code. Just let them know where you got it from.

Enjoy and Happy holidays!

Monday, December 11, 2006

Custom Bindows View Port

I was surfing for UI design patterns besides those offered by the great Bill Scott and his team at Yahoo and found Jenifer Tidwell's Designing Interfaces . Her book describes a number of design patterns one which we all use a lot -- "Overview Plus Detail."

You might not have known the name, but if you've used Google or Yahoo! Maps, you're using this pattern.

The way that the pattern works is that the map is the detail part and the little view port located at the lower right or the upper left is the overview part of the pattern. You use this pattern when there is a large amount of spatial information, but you can't see it all. So, thru the view port, you navigate to specific parts of the data.

Jenifer has a great description of it here.

As of this writing (I am using Bindows 2.5), Bindows doesn't have a BiViewPort, but we can easily create one. We'll use it to navigate a randomly generated graph created from the Bindows graphical API.

Let's look at the design details.

First, let's decide how large we want our virtual view area to be. The virtual area is the place where we'll put the graph. Let's make it 5000x5000 pixels. Obviously, we won't be able to see the graph in its entirety (at least with any meaning; besides, how many people have monitors capable of displaying a graph that size!), but we'll be able to see a portion of the graph as wide and as high as the screen.

Then, we'll need a way to navigate the virtual area. This is where the overview window comes in.
We'll need an overview window and then a little viewport to navigate the virtual area.

Basically, the overview window is the virtual area in miniature. Likewise, the viewport is a little miniature "screen." Because they're miniatures, we have to properly scale them so they look and react proportionally just like the real thing.

The overview window and the viewport are pretty simple. They're just BiComponents. The viewport is added to the overview window. Here's the code --

Notice that we've hardcoded a size to the overview window (ex. overview.setSize(200, 200)). This is fine as long as the viewport is properly scaled based on the overview and the graph size. This is what we're doing with the function getMultiple() --

The function returns the number of times that the graph is bigger than the overview. We use the multiple to scale down the viewport like this --

Now, here comes the really important part. We need to take care of navigation. This means that we need to move the viewport and once we're done moving the view port, we move the graph.

For the first part, the viewport listens for the dragstart event. Once that event fires, a number of things happen --

- The viewport is made movable (i.e. added as BiMoveHandle)
- The movable component listens for the moveend event

When the move ends, we take the location of the viewport and then scale up to match the position of the virtual area so that the screen can display the same nodes found in the viewport. Here's what all this looks like --

The linkMgr is the BiLinkManager. In other words, it's the graph container. We're moving this entire component which contains all the elements that make up a graph (nodes and edges).

We're done!

One thing you'll notice is that I didn't talk about creating graphs. The folks at Bindows have some terrific tutorials, examples and documentation on that. You can also review my source.

When you do, you'll also note that I use two additional components which I didn't mention -- originalPos and navWinInfo. The first one is just a BiComponent which marks the position that the viewport was at (that's the gray box which you'll see in the prototype). The second one is just a BiLabel which displays current xy coordinates.

You can find the prototype here (be sure and maximize your browser - F11). Feel free to study and use the source. If you do, let them know where you got it.

Enjoy and have fun!