chamara
chamara

Reputation: 12711

Drawing shapes on canvas

Using the below code i'm able to draw lines with mouse points on the canvas. I need to detect when the drawing lines completes a shape and fill it with some color.

<script language="javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

<script type="text/javascript">
    $(document).ready(function () {
        var worksheetCanvas = $('#worksheet-canvas');

        var context = worksheetCanvas.get(0).getContext("2d");
        var clicked = false;
        // The array of stored lines
        var storedLines = [];

        // The object for the last stored line
        var storedLine = {};
        var mouse = {
            x: -1,
            y: -1
        }

        var parentOffset = $('#canvas-holder').parent().offset();
        worksheetCanvas.click(function (e) {
            clicked = true;

            mouse.x = e.pageX - parentOffset.left;
            mouse.y = e.pageY - parentOffset.top;

            context.moveTo(mouse.x, mouse.y);

            // Push last line to the stored lines

            if (clicked) {
                storedLines.push({
                    startX: storedLine.startX,
                    startY: storedLine.startY,
                    endX: mouse.x,
                    endY: mouse.y
                });

            }

            // set last line coordinates

            storedLine.startX = mouse.x;
            storedLine.startY = mouse.y;

            $(this).mousemove(function (k) {
                // clear the canvas

                context.clearRect(0, 0, 960, 500);
                context.beginPath();
                context.strokeStyle = "rgb(180,800,95)";

                // draw the stored lines

                for (var i = 0; i < storedLines.length; i++) {
                    var v = storedLines[i];
                    context.moveTo(v.startX, v.startY);
                    context.lineTo(v.endX, v.endY);
                    context.stroke();
                }
                context.moveTo(mouse.x, mouse.y);
                context.lineTo(k.pageX - parentOffset.left, k.pageY - parentOffset.top);
                context.stroke();


                context.closePath();


            })

        })

    });
</script>
</head>
<body>
 <div id="canvas-holder">

 <canvas id="worksheet-canvas" width="960" height="500" style="background:black;">

                    </canvas>

                </div>


</body>
</html>

Upvotes: 1

Views: 2333

Answers (2)

markE
markE

Reputation: 105015

[Edit after clarification by Poster]

This code will draw/continue a polyline to where ever a user clicks next.

If the user clicks back in the green circle where they started, the polylines are filled.

Here is code and a Fiddle: http://jsfiddle.net/m1erickson/qwd2a/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<!--[if lt IE 9]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->

<style>
    body{ background-color: ivory; padding:10px; }
    canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var canvasMouseX;
    var canvasMouseY;
    var canvasOffset=$("#canvas").offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    var storedLines=[];
    var startX=0;
    var startY=0;
    var radius=7;

    ctx.strokeStyle="orange";
    ctx.font = '12px Arial';

    $("#canvas").mousedown(function(e){handleMouseDown(e);});

    function handleMouseDown(e){
      canvasMouseX=parseInt(e.clientX-offsetX);
      canvasMouseY=parseInt(e.clientY-offsetY);

      // Put your mousedown stuff here
      if(hitStartCircle(canvasMouseX, canvasMouseY)){
          fillPolyline();
          return;
      }
      storedLines.push({x:canvasMouseX,y:canvasMouseY});
      if(storedLines.length==1){
          startX=canvasMouseX;
          startY=canvasMouseY;
          ctx.fillStyle="green";
          ctx.beginPath();
          ctx.arc(canvasMouseX, canvasMouseY, radius, 0 , 2 * Math.PI, false);
          ctx.fill();
      }else{
          var c=storedLines.length-2;
          ctx.strokeStyle="orange";
          ctx.lineWidth=3;
          ctx.beginPath();
          ctx.moveTo(storedLines[c].x,storedLines[c].y);
          ctx.lineTo(canvasMouseX, canvasMouseY);
          ctx.stroke();
      }
    }

    function hitStartCircle(x,y){
        var dx=x-startX;
        var dy=y-startY;
        return(dx*dx+dy*dy<radius*radius)
    }
    function fillPolyline(){
        ctx.strokeStyle="red";
        ctx.fillStyle="blue";
        ctx.lineWidth=3;
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.beginPath();
        ctx.moveTo(storedLines[0].x,storedLines[0].y);
        for(var i=0;i<storedLines.length;i++){
            ctx.lineTo(storedLines[i].x,storedLines[i].y);
        }
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
        storedLines=[];
    }

    $("#clear").click(function(){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        storedLines=[];
    });

}); // end $(function(){});
</script>

</head>

<body>
    <p>Click to draw lines</p>
    <p>Click back in the green circle to close+fill</p><br/>
    <canvas id="canvas" width=300 height=300></canvas><br/>
    <button id="clear">Clear Canvas</button>
</body>
</html>

[Previous answer based on less information]

It looks like you are trying to:

  • Have the user click at points on the canvas.
  • Collect those points in storedLines[].
  • Later, use storedLines[] to draw lines + fill with color.
  • (I assume you don't want to draw lines immediately as the user clicks because you say "I need to detect when the drawing lines completes...".) If you do want to draw immediately as the user clicks, leave me a comment and I can help you with that alternative too ;)

If I may suggest a couple of cleanups in your code:

This is a good way to get the mouse position on your canvas:

    // before you begin listening for mouseclicks, 
    // get the canvas’  screen position into offsetX/offsetY
    var canvasOffset=$("#canvas").offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;

    // then when a mousedown event occurs
    // use e.clientX/Y (not e.pageX/Y) to get the mouse position on the canvas
    canvasMouseX=parseInt(e.clientX-offsetX);
    canvasMouseY=parseInt(e.clientY-offsetY);

When you are actually drawing the path with the context and storedLines:

  • To close a path, put context.closePath() before context.stroke() and context.fill().
  • Set a fillStyle and strokeStyle.
  • Do context.fill() and context.stroke() -- if you don't fill(), you won't get color fill.

    // close a path
    context.closePath();
    context.fillStyle=”blue”;
    context.strokeStyle=”rgb(180,80,95)”;
    context.fill();
    context.stroke();
    

Here is code and a Fiddle: http://jsfiddle.net/m1erickson/zYsQh/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<!--[if lt IE 9]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->

<style>
    body{ background-color: ivory; padding:10px; }
    canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var canvasMouseX;
    var canvasMouseY;
    var canvasOffset=$("#canvas").offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    var storedLines=[];

    ctx.strokeStyle="orange";
    ctx.font = '12px Arial';

    $("#canvas").mousedown(function(e){handleMouseDown(e);});

    function handleMouseDown(e){
      canvasMouseX=parseInt(e.clientX-offsetX);
      canvasMouseY=parseInt(e.clientY-offsetY);

      // Put your mousedown stuff here
      storedLines.push({x:canvasMouseX,y:canvasMouseY});
      var count=storedLines.length;
      var X=canvasMouseX-(count<10?4:7);
      ctx.strokeStyle="orange";
      ctx.fillStyle="black";
      ctx.lineWidth=1;
      ctx.beginPath();
      ctx.arc(canvasMouseX, canvasMouseY, 8, 0 , 2 * Math.PI, false);
      ctx.fillText(storedLines.length, X, canvasMouseY+4);
      ctx.stroke();
    }

    $("#draw").click(function(){
        ctx.strokeStyle="red";
        ctx.fillStyle="blue";
        ctx.lineWidth=3;
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.beginPath();
        ctx.moveTo(storedLines[0].x,storedLines[0].y);
        for(var i=0;i<storedLines.length;i++){
            ctx.lineTo(storedLines[i].x,storedLines[i].y);
        }
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
        storedLines=[];
    });

    $("#clear").click(function(){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        storedLines=[];
    });

}); // end $(function(){});
</script>

</head>

<body>
    <p>Click to create storedLines[]</p>
    <p>Then press the Draw button to fill the path</p><br/>
    <canvas id="canvas" width=300 height=300></canvas><br/>
    <button id="clear">Clear Canvas</button>
    <button id="draw">Draw</button>
</body>
</html>

Upvotes: 3

Prasath K
Prasath K

Reputation: 5018

If your storedLines array consists of exact copy of all values in it then you have drawn a shape otherwise you haven't yet ...

Example:

You draw a triangle by drawing three lines

  1. Line1 - (0,0) to (10,0)

  2. Line2 - (10,0) to (5,10)

  3. Line3 - (5,10) to (0,0)

So that, all points has a copy of it.

Upvotes: 1

Related Questions