Home  >  

Flex Graphics Tricks Part 1: Masks

Author photo
| | Comments (21)
AddThis Social Bookmark Button

One thing that has always fascinated me with Flex/Flash is the power of native graphics APIs built into the Flash player. This is one feature where I have not seen an equal in any other RIA technology, based on ease of use and capability. These graphics APIs allow you to do everything from drawing a line from point A to point B, manipulate images, draw shapes, change image properties, etc... They enable a majority of the functionality in the Flex that makes it both extremely powerful, and unique. These graphics APIs enable dynamic charting, skinning, programmatic drawing, among countless other features, but for now I want to focus on one technique that seems strangely under-used in Flex: Graphics Masks.

Masks can be used for a variety of purposes. As an example, you can take a standard bar chart, and make it look something like this...

barchartmask.jpg

Most developers who have made the transition from Flash into Flex already know what I am talking about. Most developers that I have seen transition from the Java world into Flex do not.

Essentially, a mask is a "hole" (or shape) where the graphics of the masked object are visible. Any DisplayObject can be used as a mask on another display Object. The actual graphics of the masked object will only be displayed in the non-transparent part of the graphics mask.

Masks can be used to achieve some very dynamic interfaces and powerful graphics and visualizations. Some examples of which you will find later on in this post.

A mask can be hard to explain, so let's take a look at an example... If we start with this source image:

chicago.jpg

... apply this mask:

chicago_ciriclemask.jpg

... this is what the result will look like:

chicago_w_ciriclemask.jpg

As I mentioned before, any DisplayObject can be a mask of any other DisplayObject. This includes default Flex components, images, or custom drawing with the drawing API.

Now, lets look at how you do this...

My first example is using a mx:Canvas to create a mask over an image. You can see that the visible area of the canvas is the area of the image that is actually visible within the application, which includes the rounded corners of the image.

<mx:Image source="assets/chicago.jpg" x="518" y="10" mask="{maskCanvas}">
<mx:filters>
<filters:DropShadowFilter />
</mx:filters>
</mx:Image>

<mx:Canvas x="596" y="61" width="344" height="274" backgroundColor="#ff0000" id="maskCanvas" cornerRadius="15" borderStyle="solid"/>

And here is the result...
simplemask.jpg

Notice that the only thing you have to do to mask one object with another is to set the "mask" property.

This is a very simple example, but keep in mind masks can get much more complicated. When a mask object moves on the screen, so does the visible portion of the mask image. When using Image masks, you can actually use the transparency of images (png and gif) to determine the area that mask will show. Notice that the code is actually very simple:

<mx:Image source="assets/chicago.jpg" x="518" y="10" mask="{ maskImage }">
<mx:filters>
<filters:DropShadowFilter />
</mx:filters>
</mx:Image>

<mx:Image source="assets/imageMask.png" x="518" y="10" id="maskImage" cacheAsBitmap="true" /^gt;

There is one distinct, and very important difference in this case. You must set the value of the cacheAsBitmap parameter on the mask object to "true" for this to work properly.

imagemask.jpg

Things get even more interesting when you start using png images that support semi-transparency as masks on your images. The code to do so is almost identical to that above, however you need to make sure that you set cacheAsBitmap='true' on both the mask and the object that is being masked. A simple semi-transparent gradient mask looks something like this.

transparencyImageMask.png

when applied to an image, it will yield a result like this:

semitransparentmask.jpg

You can also use any DisplayObject as a mask on another object. So far, I have mostly focused on using images to mask other images, but what happens if you use an actionscript-rendered objects to mask an object? ... You get interesting results.

Here's an example showing a mask that changes over time. First, take a look at the screenshot:

asmask.jpg

Here's how it is applied; Notice that cacheAsBitmap must be set to true for both teh mask, and the masked object.

<mx:Image source="assets/chicago.jpg" x="518" y="10" mask="{ maskImage }" cacheAsBitmap="true">
<mx:filters>
<filters:DropShadowFilter />
</mx:filters>
</mx:Image>

<components:AnimatedMask id="maskImage" x="518" y="10" width="500" height="375" cacheAsBitmap="true" />

And here is the source of the mask object itself:

public class AnimatedMask extends Container
{
private var count : Number = 0;
public function AnimatedMask()
{
super();
this.addEventListener( Event.ENTER_FRAME, onEnterFrame )
}

private function onEnterFrame( event : Event ) : void
{
if ( this.visible )
{
count++;
var g:Graphics = this.graphics;
if ( count % 250 == 0 ) g.clear();
g.lineStyle( 3, 0, .5 );
g.moveTo( Math.random() * width, Math.random() * height )
g.lineTo( Math.random() * width, Math.random() * height )
}
}
}

The mask actually changes with every enterFrame event. This is a pretty basic example, but these concepts can go a long way. Now, lets look at some real-world scenarios how these techniques can be applied in your applications.

My first example is for creating dynamically color-coded complex objects. This could apply to almost anything, but for now, lets focus on a gear. Let's say that you have a gear in your application that represents part of a workflow process. You want that gear to change color based on data coming into you application. You can easily achieve this kind of effect without having to programmaticly draw every part of that shape. You can just use a mask that is the shape of a gear, and apply it to a Canvas object that has the background color changed at runtime. The results can be very dramatic. Here's an example:

dynamiccolorsmask.jpg

And the code to achieve this is very simple as well:

<mx:Canvas x="10" y="10" width="200" height="200" id="colorCanvas" backgroundColor="#ff0000" mask="{ maskImage }" cacheAsBitmap="true">
<mx:filters>
<filters:DropShadowFilter />
</mx:filters>
</mx:Canvas>
<mx:Image source="assets/gearMask.png" x="10" y="10" id="maskImage" cacheAsBitmap="true" />

To change the color of the rendered gear image, all you need to do is change the color of the canvas that is being masked. This can be done very simply by changing the backgroundColor style property:

colorCanvas.setStyle( "backgroundColor", Math.random() * 0xFFFFFF );

As I said before, any DisplayObject can be used as a mask on any other DisplayObject. Here are a few examples showing you Flex charts that are applied as masks on images. you can create some really wild interfaces with these techniques.

barchartmask.jpg
scatterplotmask.jpg


You can view all of these examples in action at:
http://www.cynergysystems.com/blogs/blogs/andrew.trice/masks/masks.html


All of the source for this application is publicly available at:
http://www.cynergysystems.com/blogs/blogs/andrew.trice/masks/srcview/index.html


You can also check out a cool example using video on my Cynergy blog at:
http://www.cynergysystems.com/blogs/page/andrewtrice?entry=fun_with_masks

Read more from Andrew Trice. Andrew Trice's Atom feed

Comments

21 Comments

ewH said:

Andrew,

Excellent post! Thanks for the great tips and examples. It really does show how easy it is to make things look like you put a lot of time and design into them.

Cheers,
ewH

Daniel said:

Very interesting post! (Coming from someone which never -really- programmed in any flash'esque tool).

Juno said:

Great post! Thanks for sharing with us..great codes and examples

Joseph said:

Thanks... will defenetly give it a try.

Great tutorial. Your examples helped me make some animated masks from flash swfs.

Ajitpal singh said:

That is really nice example.... so could you plz help in finding out???? how to find whether mask is used in project or not!!!! is there is any way to get mask layer name and its object present in that time line

diamondTearz said:

Wow! You really opened my eyes to a wonderful use of just about every DisplayObject I can think of. What's ironic is that I used to use all of these tricks when I first started using Flash but they faded into my subconscious in the years of coding.

Alexandro said:

Great tutorial. I was getiing frustrated as the mask function seemed very straightforward but if you forget to assign the masking object a color then nothing happens.

Maybe you can help me out with something that might be useful to other people aswell.

Say you have an image 100x300 and you apply a blur to it and then mask the left 100x100 part of the image. What happens (I think) is that the image is masked to the 100x100 rect first and then a blur is applied because I get the overflowing of the blur effect over the edges. I want the mask to really clip to the 100x100 area.

How?

Kind regards,

Alexandro

Is possible to use an AS3 Graphic (a circle, or square) drawed by AS3 code, and set as mask over image?

I pretend to make this effect similar:
http://www.flashframing.com/?prod=486

Select any photo to edit it. Select a circle and see the hole printed over shape and image.

How I do this effect using mask and dynamic graphics (my "hole" maybe can be circle, square, star) ????

(Obs: I use Flex3)

Thanks.

anas Boutahar said:

great examples...thanks for sharing

dayg said:

Thanks so much.

Stefan said:

Thanks for these great examples.

I have a strange issue with Animated Mask. In my case it only works with solid shapes created inside a begin/endFill block. If I use lineStyle and simple lines or circles only as in your example, then the mask doesn't get applied.

Are there any hints for masking with simple lines other than setting cacheAsBitmap = true?

Stefan said:

Thanks for these great examples.

I have a strange issue with Animated Mask. In my case it only works with solid shapes created inside a begin/endFill block. If I use lineStyle and simple lines or circles only as in your example, then the mask doesn't get applied.

Are there any hints for masking with simple lines other than setting cacheAsBitmap = true?

Stefan said:

Found the solution to my problem above: The image on which the mask is to be applied needs to reside in a (Flash) Sprite. I had it in a Canvas, in which case masking strokes and alphas are ignored.

Stefan

PS: Sorry for the double post above

Jon Toland said:

I read this when you first wrote it and I was just starting Flex. Recently I wrote a component to generate a BitmapAsset from any DisplayObject. When it was finally hammered out and I wanted to use it as a mask it didn't work :/ You're note about cacheAsBitmap was a gem ... I looked over my problem for hours and don't think I would have figured that out and lost the usefulness of something I spent a couple days writing.

Thx!!!!!

Sam said:

Excellent Tutorial

digitalpbk said:

Thank you for your tutorial, but I am having troubles with compiling your source. Do i have to add any libraries ? Forgive me I am just one day old when it comes to flex.

Amihai said:

Do you know why masking using an image works only when applying a filter to the masked image?
Is there a way for it to work without applying a filter?

Thanks a lot

Naresh said:

Please any body tell how can i apply mask to only text border not to the entire text .
I have a requirement that,
Ex:
MASK TEXT is the text, here i have to apply a pattern like
stitching around the text border not for the text.

Please if any knows about this send me some sample.
thanks
naresh

scott chu said:

filters:DropShadowFilters cause an error 1083 in mxml, the message is 'The prefix 'filters' for element 'filters:DropShadowFilters" is not bound. In Flex, filters only has some legal ements but not DropShadowFilters. Do I have add a filters namespace? What should I put this namespace?

Andrew Trice said:

Scott, These examples were originally done with Flex 2 (or perhaps early Flex 3 builds... i don't remember which). In Flex 3, you can use the mx: prefix.

Leave a comment


Tag Cloud

Question of the Week: Open Source Flex Projects

What would you say are the 5 most prominent open source projects in the Flex world?

Answer

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.