oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Extending the Dashboard Virtual Earth Widget
Pages: 1, 2, 3, 4

CSS Layout

Our goal with the CSS layout was to produce a container that, when resized, would scale gracefully. I started off by designing most of the layout in a test HTML file that I opened with Safari. Once it looked reasonable in there, I moved everything into the widget directory.

The CSS is quite lengthy, and for the most part repetitive, but you can see it here.

Rather than examine it line by line, I shall extract the major lessons I learned when writing it.

First, everything must be position: absolute for maximum control. There is no real need to use relative placement, or even floats. If you want to have something stuck to the left of your widget, you set left: 0px. If you want it on the right, right: 0px. Absolute positioning was definitely easier. You can sometimes fine-tune the positions using negative margins.

The disadvantage of absolute positioning is that it's difficult to go back and change the size of your original images. Say you weren't happy with how you sliced it up in Photoshop; going back and changing all the per-pixel sizes in your CSS file will be a pain. So try to settle on good image slices early on.

Then, use background images against your divs. Give them a height, a width, and a background image. It's important to specify the width and height, otherwise your divs won't be visible. To control the layering of these divs, you must use z-index. For example, I set all of my divs to a z-index of 1, but the inner_contents div to z-index: 0. This enabled the pleasing inner shadow effect we designed in Photoshop earlier.

Next, your widget should scale relative to one major div. In my case, it's the inner_contents div. If I change its height and width, I want all the other divs to organize themselves around it automatically. This is important for later when we look at the JavaScript that controls resizing--we would like to make as few calculations and change as few divs as possible.

Finally, remember to place the resize handle and info buttons. The resize handle will be marked as an -apple-dashboard-region like our main Virtual Earth canvas. The resize handle should of course always be placed in the lower right-hand corner of the widget.

Hooking Up the Resize Code

We have everything in place now for a nice-looking widget, but we need to write a small amount of code to actually make our resize handle function. Recall that when we declared the resize image in HTML, we hooked up the onMouseDown handler to the mouseDown function ...

function mouseDown(event)
    document.addEventListener("mousemove", mouseMove, true);
    document.addEventListener("mouseup", mouseUp, true);

    growboxInset = {x:(window.innerWidth - event.x), y:(window.innerHeight - event.y)};


This function is pretty straightforward, and is lifted pretty much directly from Apple's Dashboard Developer documentation. First we declare two handlers for mouseMove and mouseUp events. These correspond to a drag event and releasing the mouse button, respectively. We then initialize growboxInset, which will capture the current size of the window. Finally, some cleanup code to stop event propagation.

Naturally, what will happen next is a drag event as the user moves the resize handle. At this point, our mouseMove event is invoked:

function mouseMove(event)
    var x = event.x + growboxInset.x;
    var y = event.y + growboxInset.y;

    if (x < 555) x = 555;
    if (y < 450) y = 450;

    // set the attributes for the front of the widget
    document.getElementById("front").style.width = x;
    document.getElementById("front").style.height = y;

    // set the attributes for the inner contents div, minus 
    // the width of the border
    document.getElementById("inner_contents").style.width = x-40;
    document.getElementById("inner_contents").style.height = y-40;

    // resize the main widget window

    // resize the virtual earth control
    map.Resize(x-40, y-40);


This function is again lifted mostly from the Dashboard Developer documentation, but we've had to make a few changes to customize it. We start off by calculating the size of the resized box in variables x and y. We then have a small amount of code to guarantee the box does not size any smaller than 555x450. These are more or less arbitrary numbers that take into account the minimum size of the Virtual Earth control.

Now there are several elements that we must change to ensure the widget resizes smoothly. First, we resize the front div, making its dimensions equal to the new size. Then we resize the inner_contents div, which corresponds to the actual Virtual Earth control. When we adjust its dimensions, we pay attention to the thickness of the borders too.

Finally, we resize the entire widget window itself, followed by the actual map control. This final step is important so that the internal Virtual Earth control code is aware that its dimensions have changed; it isn't aware of a resize event just because its parent div has changed size. Again, we consider the border thickness of the widget by subtracting 40 pixels.

To conclude, we perform some important cleanup when the user releases the mouse button. Namely, we destroy the two event handlers that have been calling our functions.

// when we release the resize handle ...
function mouseUp(event)
    document.removeEventListener("mousemove", mouseMove, true);
    document.removeEventListener("mouseup", mouseUp, true); 


And now our widget resizes correctly!

Pages: 1, 2, 3, 4

Next Pagearrow