views:

1883

answers:

7

I draw a line on a Canvas object with the moveTo and lineTo graphics methods. If one end of the line lies outside the Canvas, the line spills out and is drawn over or under other elements in the application.

How do I make the Canvas keep the line contained within itself?

Thanks!

+4  A: 

I had a similar problem some time ago. You need to embed another container inside the canvas, and draw the primitive graphics in that instead. I believe this is because the Canvas component only clips child components, and not primitive graphics.

Example here: http://www.adobe.com/cfusion/webforums/forum/messageview.cfm?forumid=60&catid=585&threadid=1421196. It includes some sample code about half way down the page.

seanhodges
That links doesn't work for me, maybe you mean this thread:http://forums.adobe.com/message/47864#47864
Tom
A: 

Hi,

I have the same problem, the example URL not work, can you update it.

thank's.

+1  A: 
<mx:Canvas id="canvas" top="0" right="51" left="0" bottom="32">
<mx:Canvas x="-1" y="0" width="0" height="0"> <!-- This is a HACK to make the canvas clip -->
</mx:Canvas>
</mx:Canvas>
A: 

Looks like this might be useful:

http:// forums.adobe.com/message/199071#199071

(format damage because "new users aren't allowed to add hyperlinks")

A: 

Set ClipToBounds property of the Canvas to true:

<Canvas ClipToBounds="True">... Content ...</Canvas>
Kirill Chilingarashvili
+1  A: 

The link in the recommended answer is broken. I solved the problem by placing another canvas inside my canvas that is larger than the outer canvas.

Example:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="onComplete()">
    <mx:Script><![CDATA[
        private function onComplete():void
        {
            canvas.graphics.lineStyle(1);
            canvas.graphics.moveTo( -100, -100);
            canvas.graphics.lineTo(400, 400);
        }
    ]]></mx:Script>
    <mx:Canvas  id="window"
                height="300" 
                width="300" 
                clipContent="true" 
                horizontalScrollPolicy="off" 
                verticalScrollPolicy="off" 
                backgroundColor="white">
        <mx:Canvas id="canvas" width="301" height="301">
        </mx:Canvas>
    </mx:Canvas>
</mx:Application>

If the window Canvas is going to be resized at runtime, add a resize event listener to resize the canvas Canvas also.

mauvo
A: 

I have just developed a Flex Box component, which acts as a regular component container, but draws a rounded rectangle background, with another rounded rectangle indicated a fill-level. For that I needed to clip the upper section that should not get filled. Drawing the fill rectangle to the fill height was no option since the rounded corners would not match.

What I learned:

  • I created a Canvas component just for drawing the fill-level with bounds 0/0 and width/height of the Box
  • I added that canvas to the Box at index 0 via addChildAt()
  • I set the includeInLayout property to false for that canvas since it should not take part in the layouting of the Box itself but rather act as some floating drawing pane on top
  • I then added another Canvas as the mask to that fill-canvas (addChild(), and set mask property)

Here is some code:

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
    // super
    super.updateDisplayList(unscaledWidth, unscaledHeight);

    // prep
    var g:Graphics = this.graphics;
    var fgColor:int = this.getStyle("fillColor");
    var bgColor:int = this.getStyle("backgroundFillColor");
    var radius:int = this.getStyle("cornerRadius");

    // clear
    g.clear();

    // draw background
    g.beginFill(bgColor, 1);
    g.drawRoundRect(0, 0, unscaledWidth, unscaledHeight, radius, radius);
    g.endFill();

    // draw fill level
    if (this._fillLevel > 0) {
        var fillHeight:int = int(unscaledHeight * this._fillLevel);

        // extra component for drawing fill-level, so we can apply mask just to this
        if (this._fillLevelCanvas == null) {
            this._fillLevelCanvas = new Canvas();
            this._fillLevelCanvas.x = 0;
            this._fillLevelCanvas.y = 0;
            this._fillLevelCanvas.includeInLayout = false;
            this.addChildAt(this._fillLevelCanvas, 0);
        }
        this._fillLevelCanvas.width = unscaledWidth;
        this._fillLevelCanvas.height = unscaledHeight;

        // mask
        if (this._fillLevelMask == null) {
            this._fillLevelMask = new Canvas();
            this._fillLevelMask.x = 0;
            this._fillLevelMask.y = 0;
            this._fillLevelCanvas.addChild(this._fillLevelMask);
            this._fillLevelCanvas.mask = this._fillLevelMask;
        }
        this._fillLevelMask.width = this.width;
        this._fillLevelMask.height = this.height;
        this._fillLevelMask.graphics.beginFill(0xFFFFFF); 
        this._fillLevelMask.graphics.drawRect(0, this.height-fillHeight, this._fillLevelMask.width, this._fillLevelMask.height); 
        this._fillLevelMask.graphics.endFill();                 

        this._fillLevelCanvas.graphics.beginFill(fgColor, 1);
        this._fillLevelCanvas.graphics.drawRoundRect(0, 0, unscaledWidth, unscaledHeight, radius, radius);
        this._fillLevelCanvas.graphics.endFill();
    }
}
Tom