Nutkraker
Nutkraker

Reputation: 113

How to Draw a "Wavy Line" Using the Cursor / Mouse

I have now been asked by a client to draw a wavy line with the cursor/mouse such as the following:

Wavy Line
(source: endeavoursportsgroup.com)

I have the following code below which draws a line with the cursor/mouse, but I am stuck on how to make the line "wavy". This is actually modified code from drawing a dashed line I was working on earlier, so there may be some left over code from that which I will remove later.

Can someone help me achieve the Wavy Line that I have been asked to create with my code below or suggest another way to achieve this?

Thanks in advance!

package
{
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.net.FileReference;
import flash.utils.ByteArray;

import mx.core.UIComponent;
import mx.events.FlexEvent;
import mx.graphics.codec.PNGEncoder;

public class DrawingArea extends UIComponent
{
    private var isDrawing:Boolean = false;
    private var x1:int;
    private var y1:int;
    private var x2:int;
    private var y2:int;
    private var LastX:int = 0;
    private var LastY:int = 0;

    public var drawColor:uint = 0x0000FF;

    public function DrawingArea()
    {
        super();

        var p1:Point = new Point();
        var p2:Point = new Point();

        p1.x = 0;
        p1.y = 0;
        p2.x = 200;
        p2.y = 200;

        addEventListener(FlexEvent.CREATION_COMPLETE, function(event:FlexEvent):void {
            graphics.clear();

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

        addEventListener( MouseEvent.MOUSE_DOWN, mouseDown );
        addEventListener( MouseEvent.MOUSE_MOVE, mouseMove );
        addEventListener( MouseEvent.MOUSE_UP, mouseUp);
    }
    private function mouseDown(event:MouseEvent):void {
        x1 = mouseX;
        y1 = mouseY;
        isDrawing = true;
    }
    private function mouseMove(event:MouseEvent):void {
        if (!event.buttonDown)
        {
            isDrawing = false;
        }

        x2 = mouseX;
        y2 = mouseY;
        if (isDrawing )
        {
            var p1:Point = new Point();
            var p2:Point = new Point();
            p1.x = x1;
            p1.y = y1;
            p2.x = x2;
            p2.y = y2;

            graphics.lineStyle(2,0x00FF00,2);
            graphics.lineStyle(1, drawColor);
            graphics.moveTo(x1, y1);
            graphics.lineTo(x2, y2);
            x1 = x2;
            y1 = y2;
            LastX = x2;
            LastY = y2;
        }
    }
    private function mouseUp(event:MouseEvent):void {
        isDrawing = false;
    }
}
}

Upvotes: 2

Views: 1170

Answers (3)

Igor Borodin
Igor Borodin

Reputation: 1

Another possibility would be spark.Path and a pattern using QuadraticBezier. I believe the documentation gives pretty detailed explanation and examples.

Upvotes: 0

skozin
skozin

Reputation: 3899

Please try the following code. It is not ideal, but it can probably give you some idea.

package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;

    public class CurvedLineTest extends Sprite
    {
        private static const DRAW_STEP:Number = 2;

        private var curveWidth:Number;
        private var curvePeriod:Number;
        private var smoothing:Number;

        private var prevPos:Point = new Point();
        private var curveLength:Number;
        private var smoothedN:Point = new Point();

        public function CurvedLineTest(curveWidth:Number = 10, curvePeriod:Number = 15, smoothFactor:Number = 80)
        {
            this.curveWidth = curveWidth;
            this.curvePeriod = curvePeriod;
            this.smoothing = Math.min(Math.max(smoothFactor, 0), 100) / 100;

            if( stage )
            {
                onAddedToStage();
            }
            else addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);

            // test: simulating fast mouse movements
            moveToPoint(10, 10);
            drawToPoint(15, 15);
            drawToPoint(35, 35);
            drawToPoint(60, 90);
            drawToPoint(150, 190);
            drawToPoint(350, 300);
        }

        private function onAddedToStage(e:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
            stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
            addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
        }

        private function onRemovedFromStage(e:Event):void
        {
            removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
            stage.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
            stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
            addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        }

        private function onMouseDown(e:MouseEvent):void
        {
            moveToPoint(mouseX, mouseY);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
        }

        private function onMouseMove(e:MouseEvent):void
        {
            drawToPoint(mouseX, mouseY);
            e.updateAfterEvent();
        }

        private function moveToPoint(x:Number, y:Number):void
        {
            prevPos.x = x;
            prevPos.y = y;
            curveLength = 0;
            graphics.moveTo(x, y);
        }

        private function drawToPoint(x:Number, y:Number):void
        {
            // displacement vector
            var d:Point = new Point(x - prevPos.x, y - prevPos.y);

            // length of displacement vector
            var dl:Number = Math.sqrt(d.x * d.x + d.y * d.y);

            // normalized displacement vector
            var nd:Point = new Point(d.x / dl, d.y / dl);

            // normal to the displacement vector
            var cn:Point = normal(nd);

            var currentDl:Number = DRAW_STEP;
            while( currentDl <= dl )
            {
                // incrementing base curve length by the length of the step displacement
                curveLength += DRAW_STEP;

                // base curve coords of the current step
                var stepX:Number = prevPos.x + nd.x * DRAW_STEP;
                var stepY:Number = prevPos.y + nd.y * DRAW_STEP;

                // smoothing the normal to prevent ragged lines
                smoothedN.x = smoothing * smoothedN.x + (1 - smoothing) * cn.x;
                smoothedN.y = smoothing * smoothedN.y + (1 - smoothing) * cn.y;

                // wave form
                var wave:Number = curveWidth * Math.sin(Math.PI * curveLength / curvePeriod);

                // adding normal component to the current point of base curve
                var wavedX:Number = stepX + wave * smoothedN.x;
                var wavedY:Number = stepY + wave * smoothedN.y;

                // drawing waved curve
                graphics.lineStyle(1.5, 0);
                graphics.lineTo(wavedX, wavedY);

                // drawing base curve
                graphics.lineStyle(0, 0xBB2233, 0.5);
                graphics.moveTo(prevPos.x, prevPos.y);
                graphics.lineTo(stepX, stepY);

                // drawing normal
                graphics.lineStyle(0, 0x3322BB, 0.2);
                graphics.moveTo(prevPos.x, prevPos.y);
                graphics.lineTo(stepX + wave * smoothedN.x, stepY + wave * smoothedN.y);

                graphics.moveTo(wavedX, wavedY);

                // remembering current base curve point
                prevPos.x = stepX;
                prevPos.y = stepY;

                currentDl += DRAW_STEP;
            }
        }

        /**
         * Calculates normal to the given vector (in clockwise direction).
         */
        private function normal(vec:Point):Point
        {
            var d:Number = Math.sqrt(vec.x * vec.x + vec.y * vec.y);
            return new Point(-vec.y / d, vec.x / d);
        }

        private function onMouseUp(e:MouseEvent):void
        {
            graphics.clear();
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
        }
    }
}

Upvotes: 1

Reafexus
Reafexus

Reputation: 333

It is a Sin(or Cos) Curve. Changing your MouseMove to this should fix it. I am assuming the Points and 'Last' variables were old. This should move the Y coordinate up or down depending on where you are in the curve using your x coordinate as the angle in radians.

    private function mouseMove(event:MouseEvent):void {
    if (!event.buttonDown)
    {
        isDrawing = false;
    }

    x2 = mouseX;
    y2 = mouseY;
    if (isDrawing )
    {
        //var p1:Point = new Point();
       // var p2:Point = new Point();
       // p1.x = x1;
       // p1.y = y1;
       // p2.x = x2;
       // p2.y = y2;

    y2 = Math.Sin(x2)+y2*(HeightOfThe Curve)
        graphics.lineStyle(2,0x00FF00,2);
        graphics.lineStyle(1, drawColor);
        graphics.moveTo(x1, y1);
        graphics.lineTo(x2, y2);
        x1 = x2;
        y1 = y2;
        //LastX = x2;
       // LastY = y2;
    }
}

Negatives should automatically be accounted for.

Again I have NO idea how to make it work on a curved line. It will work fine but it would look funky until you get back to a horizontal(or at least mostly horizontal) movement.

I can't test it on my own at the moment but I think that is all you need to do if you already know how to draw a straight Line.

Upvotes: 0

Related Questions