Sunday, September 19, 2010

Animating the Canvas part 5: Layers of Paint

Last week we covered the positioning of layers and how to get the real position of the layer. This week we are actually going to draw. To make this class very easy to extend, the drawing of the layer is broken into two separate functions. The drawSelf function simply draws the contents of the layer. No care is given to any children the layer may have. By doing this, we can isolate the drawing of the layer (if any) from dealing with children. This function takes a bounds parameter which indicates which portion of the layer needs to be drawn. The function first looks to see if the bounds that are being drawn are actually part of this layer. This is done by adding a new function to the Rectangle class:  intersects(rect). This is a very simple function that tests if two rectangles intersect with each other. Still, a lot of people seem to find the test confusing so lets go over it in detail:

First we want to make sure that the passed rectangle  is not left of the class rectangle. This is done by taking the class rectangles' x2 coordinate and comparing it to the passed rectangles' x coordinate. If x is greater than x2 is then obviously there can be no overlap so the condition will fail.
    if ( (this.x < (rect.x + rect.width)) &&

Next, we know that the passed rectangle is not to left of the class rectangle so we are now seeing if it is to the right of the rectangle. This can be done by seeing if the class rectangles' x2 coordinate is greater than the passed rectangles' x coordinate.
            ( (this.x + this.width) > rect.x) &&

At this point we know that there is potentially intersection along the x axis so we now need to examine the y axis. This is essentially the same as above except we are checking for top and bottom instead of left and right.

            (this.y < (rect.y + rect.height)) &&
            ( (this.y + this.height) > rect.y) )
        return true;
        return false;

If there is some overlap, we want to get that overlap so a getIntersection function is added to the rectangle to perform this task. It is simply the interior most bounds so no detailed explanation should be necessary.

Once we know what portion needs to be drawn, we simply draws a rectangle in the colour that is contained in the backgroundColor property. Overridden classes may need to do more work to figure out what needs to be drawn and to insure that things are drawn within the clip, you may actually need to formalize the bounds by using canvas clipping operations. It may be a good idea to set a clipping region no matter what as the browser probably has very efficient clipping support so there should be very little overhead.

The other function used for drawing is the render function. This is a very simple function that simply calls the drawSelf function passing the bounds it was passed and then calls the render function for all of the children that belong to this layer.

There is one additional function for painting the display. The renderDirty function is a convenience function that simply calls render for each rectangle in the list of dirty rectangles.  This function will be discussed in a later part as while have a functional system right now, the dirty rectangle management needs to be overhauled to eliminate overlap. We will be starting on this work in the next part.

No comments: