Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Contact ADC

Enhance Your Dashboard Widgets with Quartz Composer Compositions

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.

Quartz Composer Compositions Logic and Rendering Patches

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.

Rendering the Composition in Real Time

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.

Setting the Input URL for an Image Download Patch

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.

Using Two Patches to Render an Image on Screen

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.

Using Macro Patches to Create Complex Compositions

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.

Setting the Published Inputs Values from the Viewer Window

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.

Modifying the Composition for Inclusion in a Widget

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.

Controlling the Animation Time Externally

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.

When the Number of Signals Received is 2, Both Images Are Ready for Display

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.

The Composition Indicates When the Animation Can Be Played

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.

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

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

The Solid-Colored Background Belongs to the Widget Itself, Not the Composition

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