Search code examples
canvasapache-flexgraphicsdrawing

Can't draw after clearing graphics object in Flex


I have a small drawing application that I built some time ago. I just re-opened the project to add some improvements, but now whenever I call graphics.clear() I cannot draw again. I have reversed everything I have changed, but to no avail. Here is the relevant code from my custom drawing component (based on s:Group):

private var prevX:Number = 0;
private var prevY:Number = 0;

private function startDrawing(event:MouseEvent):void {
    addEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove, false, 0, true);
}

private function stopDrawing(event:MouseEvent):void {
    prevX = 0;
    prevY = 0;
    removeEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove, false);
}

private function handleMouseMove(event:MouseEvent) {
    //Set line style using graphics.lineStyle()

    graphics.moveTo(prevX, prevY);
    graphics.lineTo(event.localX, event.localY);

    prevX = event.localX;
    prevY = event.localY;
}

public function clearCanvas():void {
    //After I call this I can no longer draw.
    graphics.clear();
}

Any help would be appreciated, thanks!

Edit: Some additional info: startDrawing is called on MouseDown, stopDrawing is called on MouseUp, and clearCanvas is called from a button press. I also went from Flash Builder 4.6 to 4.7, not sure if there was an SDK change.

Edit: I worked on the code a bit today, and here is what I came up with. I can see the line when I click and drag, but for some reason can't redraw it onto the main canvas on the MouseUp. When I trace the code, it is transferring and apparently drawing everything correctly (although the smoothing mode is not working yet).

<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:mx="http://www.adobe.com/2006/mxml"
         xmlns:local="*" 
         xmlns:s="library://ns.adobe.com/flex/spark" 
         mouseEnabledWhereTransparent="true"
         mouseDown="startDrawing(event)" 
         mouseUp="stopDrawing(event)">
    <mx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.containers.Canvas;

            //########## Public Variables ##########

            public var __DrawingColor:uint = 0x000000;
            public var __DrawingWidth:Number = 4;
            public var __DrawingAlpha:Number = 1;
            public var __DrawingSmoothing:Boolean = false;

            //########## Private Variables ##########

            private static const ___SMOOTHING_AMOUNT:Number = 5;

            private var _History:ArrayCollection;
            private var _CurrentPoints:Array;
            private var _LiveCanvas:Canvas;
            private var _LiveObject:Object;
            private var _PrevX:Number = 0;
            private var _PrevY:Number = 0;

            //########## Public Functions ##########

            public function init():void{
                _History = new ArrayCollection();
            }

            public function clearAll():void {
                graphics.clear();
                _History = new ArrayCollection();

                graphics.beginFill(0xffffff, 0);
                graphics.drawRect(0, 0, width, height);
                graphics.endFill();
            }

            public function clearLast():void {
                if (_History.length > 0) {
                    _History.removeItemAt(_History.length - 1);
                    drawLines(_History);
                }
            }

            //########## Private Functions ##########

            private function startDrawing(event:MouseEvent):void {
                addEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove, false, 0, true);
                _CurrentPoints = new Array();

                _LiveCanvas = new Canvas();
                addElement(_LiveCanvas);
                _LiveCanvas.x = 0;
                _LiveCanvas.y = 0;
                _LiveCanvas.width = this.width;
                _LiveCanvas.height = this.height;

                _LiveCanvas.setStyle("backgroundColor", 0xFFFFFF);
                _LiveCanvas.setStyle("backgroundAlpha", "0");
            }

            private function handleMouseMove(event:MouseEvent):void {
                if (_PrevX != 0 && _PrevY != 0) {
                    _CurrentPoints.push(new Point(event.localX, event.localY));
                    _LiveCanvas.graphics.lineStyle(__DrawingWidth, __DrawingColor, __DrawingAlpha);
                    _LiveCanvas.graphics.moveTo(_PrevX, _PrevY);
                    _LiveCanvas.graphics.lineTo(event.localX, event.localY);
                }
                _PrevX = event.localX;
                _PrevY = event.localY;
            }

            private function stopDrawing(event:MouseEvent):void {
                _CurrentPoints.push(new Point(event.localX, event.localY));

                _PrevX = 0;
                _PrevX = 0;
                this.removeElement(_LiveCanvas);
                _LiveCanvas = null;

                if (__DrawingSmoothing) {
                    _CurrentPoints = smoothPoints(_CurrentPoints);
                }

                var addItem:Object = new Object();
                addItem.color = __DrawingColor;
                addItem.width = __DrawingWidth;
                addItem.alpha = __DrawingAlpha;
                addItem.lines = pointsToLines(_CurrentPoints);

                _History.addItem(addItem);
                drawLines(_History);
                removeEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove, false);
            }

            private function smoothPoints(points:Array):Array {
                var len:uint = points.length;
                var p:Point;
                var ret:Array = new Array();
                var t:Number = 1 / ___SMOOTHING_AMOUNT;
                while (t < 1) {
                    p = getPoint(t, points);
                    ret.push(p);
                    t += 1 / ___SMOOTHING_AMOUNT;
                }
                return ret;
            }

            private function pointsToLines(points:Array):Array {
                var ret:Array = new Array();
                var lineObject:Object = new Object();
                for (var i:Number = 0; i < points.length; i++) {
                    if (!lineObject.hasOwnProperty("x1")) {
                        lineObject.x1 = Point(points[i]).x;
                        lineObject.y1 = Point(points[i]).y;
                    } else if (!lineObject.hasOwnProperty("x2")) {
                        lineObject.x2 = Point(points[i]).x;
                        lineObject.y2 = Point(points[i]).y;
                    } else {
                        ret.push(lineObject);
                        lineObject = new Object();
                        lineObject.x1 = Point(points[i]).x;
                        lineObject.y1 = Point(points[i]).y;
                    }
                }
                return ret;
            }

            private function drawLines(lines:ArrayCollection):void {
                graphics.clear();
                graphics.beginFill(0xFFFFFF, 0);
                graphics.drawRect(0, 0, width, height);
                graphics.endFill();
                var currentPoints:Object;
                for (var x:Number = 0; x < lines.length; x++) {
                    currentPoints = lines[x];
                    graphics.lineStyle(currentPoints.width, currentPoints.color, currentPoints.alpha);
                    for (var i:Number = 0; i < currentPoints.lines.length; i++) {
                        graphics.moveTo(currentPoints.lines[i].x1, currentPoints.lines[i].y1);
                        graphics.lineTo(currentPoints.lines[i].x2, currentPoints.lines[i].y2);
                    }
                }
            }

            private function getPoint(t:Number, points:Array):Point {
                var x:Number = 0;
                var y:Number = 0;
                var n:uint = points.length-1;
                var factn:Number = factoral(n);
                for (var i:uint=0;i<=n;i++) {
                    var b:Number = factn/(factoral(i)*factoral(n-i));
                    var k:Number = Math.pow(1-t, n-i)*Math.pow(t, i);
                    x += b*k*points[i].x;
                    y += b*k*points[i].y;
                }
                return new Point(x, y);
            }

            private function factoral(value:uint):Number {
                if (value==0)
                    return 1;
                var total:Number = value;
                while (--value>1)
                    total *= value;
                return total;
            }

        ]]>
    </mx:Script>
</s:Group>

Solution

  • Finally figured it out, the working code is posted below if anyone is interested. Thanks!

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
             xmlns:local="*" 
             xmlns:s="library://ns.adobe.com/flex/spark" 
             mouseDown="startDrawing(event)" 
             mouseUp="stopDrawing(event)">
        <mx:Script>
            <![CDATA[
                import mx.collections.ArrayCollection;
    
                //########## Public Variables ##########
    
                public var __DrawingColor:uint = 0x000000;
                public var __DrawingWidth:Number = 4;
                public var __DrawingAlpha:Number = 1;
                public var __DrawingSmoothing:Boolean = false;
    
                //########## Private Variables ##########
    
                private var _History:ArrayCollection;
                private var _CurrentPoints:Array;
                private var _LiveObject:Object;
    
                //########## Public Functions ##########
    
                public function init():void{
                    _History = new ArrayCollection();
                }
    
                public function clearAll():void {
                    graphics.clear();
                    _History = new ArrayCollection();
    
                    graphics.beginFill(0xffffff, 0);
                    graphics.drawRect(0, 0, width, height);
                    graphics.endFill();
                }
    
                public function clearLast():void {
                    if (_History.length > 0) {
                        _History.removeItemAt(_History.length - 1);
                        drawLines(_History);
                    }
                }
    
                //########## Private Functions ##########
    
                private function startDrawing(event:MouseEvent):void {
                    addEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove, false, 0, true);
                    _CurrentPoints = new Array();
                    _CurrentPoints.push(new Point(event.localX, event.localY));
                    _LiveCanvas.visible = true;
                    _LiveCanvas.graphics.clear();
                    _LiveCanvas.graphics.beginFill(0xFFFFFF, 0);
                    _LiveCanvas.graphics.drawRect(0, 0, width, height);
                    _LiveCanvas.graphics.endFill();
                    _LiveCanvas.graphics.moveTo(event.localX, event.localY);
                }
    
                private function handleMouseMove(event:MouseEvent):void {
                    _CurrentPoints.push(new Point(event.localX, event.localY));
                    _LiveCanvas.graphics.lineStyle(__DrawingWidth, __DrawingColor, __DrawingAlpha);
                    _LiveCanvas.graphics.lineTo(event.localX, event.localY);
                }
    
                private function stopDrawing(event:MouseEvent):void {
                    removeEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove, false);
                    _CurrentPoints.push(new Point(event.localX, event.localY));
    
                    _LiveCanvas.graphics.clear();
                    _LiveCanvas.visible = false;
    
                    if (__DrawingSmoothing) {
                        _CurrentPoints = smoothPoints(_CurrentPoints);
                    }
    
                    var addItem:Object = new Object();
                    addItem.color = __DrawingColor;
                    addItem.width = __DrawingWidth;
                    addItem.alpha = __DrawingAlpha;
                    addItem.points = _CurrentPoints;
    
                    _History.addItem(addItem);
                    drawLines(_History);
                }
    
                private function smoothPoints(points:Array):Array {
                    var len:uint = points.length;
                    var p:Point;
                    var ret:Array = new Array();
                    var t:Number = 1 / (points.length);
                    while (t < 1) {
                        p = getPoint(t, points);
                        ret.push(p);
                        t += 1 / (points.length);
                    }
                    return ret;
                }
    
                private function drawLines(lines:ArrayCollection):void {
                    graphics.clear();
                    graphics.beginFill(0xFFFFFF, 0);
                    graphics.drawRect(0, 0, width, height);
                    graphics.endFill();
                    var currentPoints:Object;
                    for (var x:Number = 0; x < lines.length; x++) {
                        currentPoints = lines[x];
                        graphics.lineStyle(currentPoints.width, currentPoints.color, currentPoints.alpha);
                        if (currentPoints.points.length > 0) {
                            graphics.moveTo(Point(currentPoints.points[0]).x, Point(currentPoints.points[0]).y);
                            for (var i:Number = 0; i < currentPoints.points.length; i++) {
                                graphics.lineTo(currentPoints.points[i].x, currentPoints.points[i].y);
                            }
                        }
                    }
                }
    
                private function getPoint(t:Number, points:Array):Point {
                    var x:Number = 0;
                    var y:Number = 0;
                    var n:uint = points.length-1;
                    var factn:Number = factoral(n);
                    for (var i:uint=0;i<=n;i++) {
                        var b:Number = factn/(factoral(i)*factoral(n-i));
                        var k:Number = Math.pow(1-t, n-i)*Math.pow(t, i);
                        x += b*k*points[i].x;
                        y += b*k*points[i].y;
                    }
                    return new Point(x, y);
                }
    
                private function factoral(value:uint):Number {
                    if (value==0)
                        return 1;
                    var total:Number = value;
                    while (--value>1)
                        total *= value;
                    return total;
                }
    
            ]]>
        </mx:Script>
        <mx:Canvas id="_LiveCanvas" left="0" right="0" top="0" bottom="0" backgroundAlpha="0" backgroundColor="0xFFFFFF"/>
    </mx:Canvas>