
Mac OS X Tiger introduced Dashboard and Quartz
Composer, and these two exciting technologies can
be brought together to create graphically rich Dashboard widgets.
Dashboard transforms your desktop into a canvas of small,
single-purposed applications called widgets, that are always just a
button-click away. You create Dashboard widgets using a mix of
HTML, CSS, and JavaScript programming. Quartz Composer is a visual
development tool that can turn most any data into amazing, live-action
graphics and animations, using a programming model that is easy to
understand and work with.
This article shows you how to use the stunning graphics abilities of
Quartz Composer along with the easy development of Dashboard to create
fun, beautiful widgets that attract attention and display information
with rich visual content.
Dashboard Widgets: Beyond Web Technologies
Because it is based on HTML, CSS, and JavaScript, Dashboard is easy
for many developers to use right away. If you know how to create a
webpage, you know how to create a widget. However, neither HTML nor the JavaScript
language works well for creating advanced graphical effects.
The good news is, you can achieve impressive results by
embedding Quartz Composer compositions in Dashboard widgets, thereby leveraging the
advanced graphical technologies of Mac OS X Tiger, including Core Image and OpenGL.
You can use Quartz Composer in many different ways in widgets. This article focuses on
one example: using Quartz Composer to animate the transition between two pictures.
The widget in the example downloads pictures from a website and shows them one by one.
The transition between two pictures is animated with a Quartz Composer composition.
Note: If you need
the Apple Developer Tools, including Xcode and the Quartz Composer application, you can install them from your Tiger Installation CD, or download them from
the Developer Tools download page. You can also download the Beta version of Dashcode, a tool for building Dashboard widgets from templates, including a Quartz Composer template. Using Dashcode, you can
simply drop your Quartz Composer composition in the widget without the need to write any code.
Meet Quartz Composer
Start by creating a simple Quartz Composer application that displays a picture downloaded
from the Internet. Assuming that you've installed the developer tools, you'll find the
Quartz Composer application in /Developer/Applications/Graphics Tools. When
the application starts, you must choose a composition template; select Basic Composition,
then choose a destination directory and file name.
Two windows appear—the Editor and the Viewer. The Editor contains a set of patches,
shown in Figure 1 as green and pink rectangles. Green patches indicate data processors,
whereas pink patches indicate data renderers. All the patches come from the Patch
Library located on the left side of the Editor window. Patches provide inputs and outputs,
located in the left and right columns of the rectangles, respectively, which you can connect
to pass data from one patch to another. Figure 1 shows, for instance, the Image output of
the Image Importer patch is linked to the Image input of the Billboard patch.

Figure 1: Quartz Composer Composition's Data Processing and Rendering Patches
The Viewer window shows the real-time rendering of your composition. You can stop the
rendering at any time by clicking the Stop button, as Figure 2 shows.

Figure 2: Rendering the Composition in Real Time
To better understand the inner working of Quartz Composer, you must learn how to use
patches. Start by selecting all the patches in Editor, either with the mouse or by
pressing Command-A, and then delete them, either with the mouse or by pressing the
Delete key. Both the Editor and Viewer windows should now be blank.
You must load an image into your composition before rendering it. Find the patch called
Image Downloader in the Generator category, and drag it onto the Workspace. This patch
can download an image from a URL and pass it to another patch through its Image output.
Select the patch by clicking it, and bring up the Inspector (Command-I). From the
pull-down menu at the top, select Input Parameters, and then enter the image URL of
your choice; for example:
http://images.apple.com/macbook/gallery/images/macbook1white20061108.jpg
as Figure 3 shows.

Figure 3: Setting the Input URL for an Image Download Patch
To render the downloaded picture on screen, you need to transmit it to a rendering patch.
Drop a Billboard patch from the Renderer category in the composition. A billboard
renders an image that always faces the camera—remember that a composition is rendered
in a 3D space. Click the Image output in the Image Downloader patch,
and drag a connection to the Image input of the Billboard renderer. This creates a
connection that transmits the image downloaded from Image Downloader to
the Billboard, which can now render it on screen. Figure 4 shows the
result. When you're finished, the Viewer should automatically display the picture.

Figure 4: Using Two Patches to Render an Image on Screen
As this example demonstrates, you can obtain results quickly with Quartz Composer. However,
the composition you just created is a bit dull. You can use animation to add some style.
Creating a Composition for Picture Transitions
Close your composition, and then choose File > New From Template to create a new
one. This time, select the Parameterized Composition template. The newly created
composition is different from the previous one, as it contains macro patches, which
are aggregates of regular patches. A macro patch is defined in the Editor by a
rectangle with straight corners (as opposed to other patches, shown as rounded
rectangles). The composition contains two macro patches, Background Slide
and Transitioning Slides, as Figure 5 shows.

Figure 5: Using Macro Patches to Create Complex Compositions
Some patch inputs are filled in black. Black inputs are published inputs that can
be accessed from outside the composition. The same holds true for outputs. Such
inputs play an important role when you embed a Quartz Composer composition in a
widget, because they act as communication channels.
The Viewer window contains only a black screen, because the published inputs of
the macro patches don't have a value. You can set the value of the published
inputs by clicking the Parameters button in the Viewer, as Figure 6 shows.
Choose a picture for both the source and the destination, click the Stop
button, and then click the Run button to see the animated transition. The
source picture should fade to the destination picture.

Figure 6: Setting the Published Inputs Values from the Viewer Window
Before you use this composition in a widget, you must make some changes. First,
the black background that the composition displays isn't very handy, even though
you can change its color with a published input. Because the widget will be
embedded in an HTML widget, it's easier to make it transparent to get better
control over the background. To do so, while in the Viewer window, choose
View > Enable Background Erasing. Then go back to the Editor window and
remove the Clear rendering patch. The Viewer now displays a checkerboard pattern
in the background, indicating that the composition doesn't have a background of
its own.
Play the composition again. The result is quite different from the first run because
of the way in which the pictures are rendered on screen. Double-click the Background
Slide macro patch to edit its content, select the Billboard renderer, and then
bring up the Inspector window. In the Input Parameters, change the Blending mode from
Add to Over. Go back to the root level of the composition by clicking
the Edit Parent button in the toolbar, then double-click the Transitioning Slide patch.
Finally, edit the Billboard like you just did. The transition now plays perfectly.
Using the Source and Destination Inputs in Your Widget
Even though the source and destination inputs are published, they can't be used in
a widget. Indeed, JavaScript code can't send an image to a Quartz Composition. To
fix this, you must use Image Downloader patches and publish the image URL instead,
as Figure 7 shows. Add two Image Downloader patches to the composition. Right-click
the patch, and then choose Published Input > Image URL to publish the input.
When asked for the input name, type in imageSource for the Background
Slide and imageTarget for the Transitioning Slide.

Figure 7: Modifying the Composition for Inclusion in a Widget
Enter two URLs as parameters of the composition, and click Run in the Viewer. This
time, you'll see the target image appear directly, without any transition. The reason
for this is that the animation is driven in the composition by the green Patch Time
rectangle. As soon as you play the composition, this patch outputs the elapsed time
and sends it to the macro patches. Unfortunately, the composition must download the
images first—or at least load them from the cache—and this operation
lasts longer than the animation.
If you look closely at the Image Downloader patches, you'll notice a Done Signal
output. This output emits a Boolean value, set to False by default. When the image
is done loading, the output becomes True. Beware, however: As the name suggests,
it's just a signal. Therefore, the output reverts back to False right after True
has been sent. This composition must provide a way to start the animation when
both images are loaded. The first step in doing this is to hand over control of
the animation to an external source. Instead of using an internal clock provided
by Patch Time, which starts at the same time as the composition, the composition
will rely on an external clock. Right-click Patch Time, and then choose
Timebase > External. A new input appears. Publish it under the time name.
Look at the Viewer window, and display the parameters. Run the composition; when
you can see the source image, start changing the time value to play the animation
manually. Figure 8 shows a transition halfway between a white MacBook and a black
MacBook.

Figure 8: Controlling the Animation Time Externally
Determining When Images Are Available for Display
One last problem remains. You can control the animation externally, but there's
no way to know when both images are available for display. The easiest way to do
this would be to publish the Done Signal outputs. Unfortunately, as explained
earlier, these outputs don't retain their value; when True has been sent, the
output reverts back to False. Fortunately, there's another way to achieve the
same result. Simply count the number of signals; when the sum equals two, the
images are ready for download. Figure 9 shows the patches used to compute this
result.

Figure 9: When the Number of Signals Received is 2, Both Images Are Ready for Display
The counter patch increases a numeric value by 1 every time a signal is received
on the Increasing Signal input. Because only one signal output can be associated
at a time on the Increasing Signal input, two counters are necessary. The Math
patch simply adds the Count outputs of both Counter patches. The Conditional
patch checks whether the result of the addition is 2. The Result output is True
when both image have been loaded.
After you have added all the patches in the scene, select them and create a macro
path by choosing Editor > Create Macro. Publish the Increasing Signal input
and the Result output. Then, link the Done signals from the Image Downloader
patches to the new macro patch. Finally, publish the Result output of the macro
patch under the name imagesLoaded, as Figure 10 shows.

Figure 10: The Composition Indicates When the Animation Can Be Played
The composition is now ready to be embedded in a widget. The full example adds a
few more features to the composition. The transition not only fades the pictures
but also animates a blur on the target picture to make the effect more interesting.
Also, the imagesLoaded output is computed in a more complicated
fashion. Instead of sending True when the sum of the counters is 2, it sends True
when the sum of the counters is divisible by 2. When you change the compositions
inputs without stopping the composition, the Done signals are sent again, but the
counters aren't reset. The counters could thus add up to values larger than 2,
and the imagesLoaded output would never be True again, even when the
new images are actually ready.
Embedding the Composition in a Widget
You can embed a Quartz Composer composition in any Dashboard widget. All you need
is one HTML tag: <embed />. The code below is the HTML source
code of the example widget:
<embed id="composition" name="composition"
type="application/x-quartzcomposer"
width="150px" height="100px"
src="Image%20Transition.qtz"
autoplay="true" opaque="false">
</embed>
The most important attributes are src, which points to the Quartz
Composer composition file, and type, which defines the nature of
the embedded object. The last two attributes are specific to Quartz Composer
compositions. The first one, autoplay, runs the composition as
soon as it's loaded. Should you fail to set this attribute to True, you would
need to start the composition with the following JavaScript snippet:
// you can also invoke pause() and stop()
document.getElementById("composition").play();
The second attribute is called opaque. When set to False, Quartz Composer
renders the composition with respect to the alpha channel of its elements. When set
to True, transparent areas are rendered as solid. Because the composition you created
doesn't contain a solid background, you want to set this attribute to False to make
sure the HTML elements located beneath the composition will be visible. Figure 11
shows the widget with the composition embedded; Figure 12 shows the widget without
the composition.

Figure 11: Using the Composition's Transparent Background to Make the Underlying HTML Image Visible

Figure 12: The Solid-Colored Background Belongs to the Widget Itself, Not the Composition
Another useful attribute, not shown here, is above. When this
attribute is set to False, the composition is rendered below the HTML elements
located within the composition's bounds. By default, this attribute is set to
True. Thus, for instance, if you want to easily add a button over the
composition, set the above attribute to False.
You can read in-depth explanations about all the attributes discussed here and
a few more in the Quartz Composer Programming Guide.
Manipulating the Composition from the Widget
You can manipulate the composition easily by using JavaScript code in your widget.
As you saw in the previous section, you can play, pause, and stop a composition.
You can also query the state of the composition using one of the following methods:
var c = document.getElementById("composition");
c.playing(); // true after play() is called, false after stop()
c.paused(); // true after pause() is called
c.loaded(); // true when the composition is ready
It's also possible to work with the published values. In the case of the example
widget, set the values of imageSource and imagesLoaded.
Then check the value of imagesLoaded until it's True to make sure
that the images are ready for the transition. Finally, animate the transition
by changing the time input.
The following code snippet demonstrates how to set input values on a composition:
function startTransition() {
imageSource = imageTarget;
// photos is an array of URL from Flickr
imageTarget = photos.pop();
composition.setInputValue("time", 0);
composition.setInputValue("imageSource", imageSource);
composition.setInputValue("imageTarget", imageTarget);
window.setTimeout(checkPicturesLoaded, 500);
}
The call to setInputValue() contains the name of the published input
and the value you want to send. When you set the image URL on the composition,
the widget must wait until the images are loaded. To do so, the
checkPicturesLoaded() method is invoked every 500 milliseconds (ms)
and reads the value of the imagesLoaded output:
function checkPicturesLoaded() {
if (!composition.getOutputValue("imagesLoaded")) {
window.setTimeout(checkPicturesLoaded, 500);
} else {
startTime = new Date();
tick();
}
}
When the pictures are available, you can start the animation. The tick()
method drives the animation by repetitively changing the time input over a
period of 2 seconds:
function tick() {
var currentTime = new Date();
var delay = currentTime.getTime() - startTime.getTime();
composition.setInputValue("time", delay / 1000);
// animate transition for 2 seconds
if (delay < 2000) {
window.setTimeout(tick, 16);
// show next picture in 5 seconds
} else {
window.setTimeout(startTransition, 5000);
}
}
When the transition is done, the widget waits for 5 seconds before loading
the next picture.
Working with a composition you have created is relatively easy. However, when
you have to work with a composition created by someone else, you can query its
published values to see how you can manipulate it from your widget:
// shows all published outputs
alert(composition.outputKeys());
// shows all published inputs
alert(composition.inputKeys());
You will find a detailed explanation of all the composition JavaScript methods
in the Quartz Composer WebKit Plug-in JavaScript Reference.
Install the example widget in your Dashboard to witness how manipulating
compositions from a widget can bring you new opportunities to create
stunning widgets with only a few lines of code.
Faster, Easier Development with Dashcode
Creating widgets and embedding compositions manually is fairly easy. However,
a new visual tool has been designed to make this process even easier and
much faster. WIth Dashcode, you can
build widgets visually in a WYSIWYG fashion. It also provides a JavaScript debugger
and other niceties, such as pre-built HTML components. Using Dashcode, you can
simply drop your Quartz Composer composition in the widget without writing a single
line of code. Note that Dashcode is going to ship with Leopard, but is available now as Beta software.
For More Information
Posted: 2007-02-13
|