Thursday, March 15, 2007

Reusable Toolbar, Menubar, Component Scroller Control

Instead of using the CSS property "overflow" to show scrollbars, did you ever want to put scroll arrows on your Bindows toolbars? How about your menu bars? Or, how about your tabs? I did.

I love CSS, but sometimes, horizontal scrollbars are pretty ugly especially if all you want to do is scroll a toolbar. Scrollbars are great for scrolling the browser window to see all of the content, but it's pretty much overkill for a single component.

Inspired by the toolbar scrollers found in the browsers, I
created a reusable component called ScrollableComponent.

Use it with a BiComponent and you'll get this in Firefox --

and this in IE --

The component works for all derivatives of BiComponent and you can easily instantiate, set its size and then add it to the containing component like this --

var scrollableComponent = new ScrollableComponent(container);
scrollableComponent.setSize(container.getWidth(), container.getHeight());

Note that the scroll arrows only show up when the width of the component is longer than the width of the browser and when you mouseover the component. It's less intrusive that way, but if you want I'll leave that up to you to change that (maybe have it show up when you're resizing the window, etc.).

Feel free to modify and use it.

Get the ScrollableComponent here and the left and right scroll arrows here and here. See the implementation here. Review the test driver here.

Have fun!

Sunday, March 04, 2007

Bindows 3.0 Beta :: Animating Yahoo's Expanding and Collapsing Tabs

I was fortunate enough to be one of the lucky ones to test drive the Bindows 3.0 Beta. The 3.0 version has some significant new features --

  • An animation library
  • Vector graphics support for all browsers
  • Advanced gauge support for all browsers
  • Enhanced charting capabilities
  • An improved grid panel component for better layout performance
You can read more about it here.

I was most interested in the animation library. I'm a big fan of the UI Design Patterns from Yahoo! and a lot of their patterns involve relocating, resizing and fading control elements. All this required the ability to animate which until now, Bindows lacked.

The example we'll imitate is taken from Yahoo! (they do practice what they preach!). It's the expanding/collapsing grid menu tabs found on the Yahoo! home page. Here's our imitation which I'm sure you'll recognize --

Mouseover the tabs and you'll see the animated expanding and collapseing tabs at work. Note that the tab pane content is static. They're just images, but in reality, they can be any component.

You can find the real version here.

There are three types of component animation found in Bindows 3.0. You can --

  • Resize components
  • Change component location
  • Visually fade components
These animation types correspond to three animator objects --

  • BiSizeAnimator
  • BiLocationAnimator
  • BiOpacityAnimator
All three animators are derived from BiComponentAnimation. Since the grid menu tabs only use the BiSizeAnimator and the BiLocationAnimator. So, we'll only talk about those.

Note that animators aren't components. They animate BiComponents or their derivatives. So, think of animators as objects that provide resizing, relocating and fading behavior to components. We'll see how we use these animators in a minute.

From our implementation, you'll notice that there are three components that are resized and one component that is relocated.

The resized ones include the container for the grid tab menu and the "middle body", the area between the first and the bottom tabs --

It also includes the area below the bottom tabs ("bottom body") --

With that in mind, here's how the grid tab menu behaves.

Mouseover the top menu buttons and the grid tab menu container and the middle body increase in size, while at the same time, the bottom menu buttons move down making way for the middle body.

Mouseover the bottom menu buttons and if the top menu buttons are collapsed, the bottom body and the grid tab menu container increase in size.

If the top menu buttons are expanded, mouseover the bottom menu buttons and the middle body collapses, the bottom menu buttons move up, the bottom body and the grid tab menu container expand.

All of the animation is synchronous meaning that the components move together. This is important because it just wouldn't look right if the animations occurred at different times and rates.

For the three resizeable components ( grid tab menu container, middle and bottom body ), we'll use three BiSizeAnimators. For the bottom menu tab buttons, which we move up and down, we'll use a BiLocationAnimator. Here is the bottom menu tab highlighted within a dashed box --

Here's the code for creating a BiSizeAnimator for the grid tab menu container --

Basically, you pass in the "from" and "to" widths and heights. These make up the first four parameters. The fifth parameter is the speed of the animation. We've chosen to use BiSizeAnimator.SPEED4 which is pretty fast. SPEED1 is the slowest and SPEED5 is the fastest.

The sixth parameter determines whether we want the resizing to autostart. In our case, we don't want that. We'll start the resizing ourselves. So, we set that to false.

The seventh parameter deals with acceleration. We want our acceleration to be constant all the way. So, we've chosen BiComponentAnimation.CONSTANT_SPEED. We could have chosen FAST_TO_SLOW, SLOW_TO_FAST or SLOW_TO_SLOW.

The eighth parameter associates the component with the animation. In this case, we're animating the BiComponent tabMenuContainer.

The final parameter sets frames per second. For this example, setting this value to 100 works nicely.

More information on the BiSizeAnimator can be found here.

We initiate the the grid tab menu container resize when we call the method start() --

It's important that we call start() in the right place and for us, we call it when we expand the middle or the bottom body. Here, for example is the code for expanding the middle body --

The bottom body has something similar (sizeAnimator2) --

The constructor for the BiLocationAnimator is identical to the BiSizeAnimator. They differ only in the value of the fifth parameter. In the BiLocationAnimator, we use the string "fastest" rather than the BiSizeAnimator.SPEEDX primitive constant.

More information on BiLocationAnimator is found here.

I noted earlier that all "the components move together." To do that, we start the animations one after another --

Where sizeAnimator resizes the middle body and as noted earlier, sizeAnimator3 resizes the grid menu tab container. The locationAnimator moves the bottom tab menu up or down.

If you review the BiLocationAnimator constructor for the locationAnimator, you'll notice that it's set to move from top to bottom. However, we don't always want to go in that direction.

We can change when we need to by calling the method setToFrom to go from bottom to top before calling start() --

Notice also that the locationAnimator listens for the "animationend" event. "animationend" is an important animation event because many times, you want to immediately perform an action after an animation.

In our case, we'll display the image in the tab pane using the showContentHandler event handler.

You can review the entire code here. The implementation is found here.

Note that we're using a modified theme based on the "Beige" theme provided in the toolkit. You can review that here. I added the three selector rules at the bottom of the theme.

Also, remember that this example requires Bindows 3.0 Beta. It will not work with earlier versions of Bindows.

As always, feel free to modify, use, comment and improve on the example. If you do use, just let them know where you got it.

Have fun!