简体   繁体   中英

Strange behaviour with html5 canvas and javascript

I have made some canvas on which i'm drawing a circle and many other shapes. I've made a _rotate() function which is intended to clear (delete the contents) of the canvas and call a function which would be drawing a square. The problem is that after clicking on rotate not just the square is drawed but the circle and the rectangle too. I don't have any clue what could be possibly wrong with the code so i'm taking any suggestions. The actual code:

var c = document.getElementById("canv");
var canvas = c.getContext("2d");
//ciarka
function _rotate() {

canvas.clearRect(0, 0, 600, 400);
stvorec(Math.random());
return;
}


function stvorec(param) {
canvas.rotate(param*Math.PI/180);
canvas.fillStyle="green";
canvas.fillRect(350,50,50,50);
canvas.stroke();
}

function ciarka() {
canvas.beginPath();
canvas.moveTo(10,10);
canvas.lineTo(50,30);
canvas.lineTo(100,10);
canvas.lineTo(150,30);
canvas.lineTo(200,10);
canvas.lineTo(250,30);
canvas.lineTo(300,10);
canvas.lineTo(350,30);
canvas.lineTo(400,10);
canvas.lineTo(450,30);
canvas.lineTo(500,10);
canvas.lineTo(550,30);
canvas.lineTo(590,10);
canvas.stroke();
}


//obdlznik
function obdlznik() {
canvas.rect(150,150,100,50);
canvas.strokeStyle="black";
canvas.stroke();
}

//kruh
function kruh() {
canvas.beginPath();
canvas.arc(200,80,50,0,2.0*Math.PI);
canvas.stroke();
}
//stvorec

stvorec();
ciarka();
kruh();
obdlznik();

$("body").on("click", "#rot", function() {
   _rotate(); 
});

Jsfiddle for reference: jsfiddle

I see some glitches in your code:

  • do beginPath() for every stroke/fill.
  • do closePath() on your arc to make it a circle rather than a 360 degree arc.
  • be sure you set the rotation point using .translate before doing a .rotate
  • stvorec(Math.random()) is only producing a degree angle from 0-1 degree.

Not a glitch, but just a naming strangeness: you called your context variable canvas . The context variable is often called context or ctx

I don't know your design requirements but here is some refactored working code:

http://jsfiddle.net/m1erickson/5PuW9/

<!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>
<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>
<script>
$(function(){

    var c = document.getElementById("canv");
    var canvas = c.getContext("2d");

    //ciarka
    function _rotate() {
        canvas.clearRect(0, 0, 600, 400);
        stvorec(Math.random()*360);
    }

    function stvorec(param) {
        canvas.save();
        canvas.beginPath();
        canvas.translate(350,50);
        canvas.rotate(param*Math.PI/180);
        canvas.fillStyle="green";
        canvas.fillRect(-25,-25,50,50);
        canvas.restore();
    }

    function ciarka() {
        canvas.beginPath();
        canvas.moveTo(10,10);
        canvas.lineTo(50,30);
        canvas.lineTo(100,10);
        canvas.lineTo(150,30);
        canvas.lineTo(200,10);
        canvas.lineTo(250,30);
        canvas.lineTo(300,10);
        canvas.lineTo(350,30);
        canvas.lineTo(400,10);
        canvas.lineTo(450,30);
        canvas.lineTo(500,10);
        canvas.lineTo(550,30);
        canvas.lineTo(590,10);
        canvas.stroke();
    }

    //obdlznik
    function obdlznik() {
        canvas.beginPath();
        canvas.rect(150,150,100,50);
        canvas.strokeStyle="black";
        canvas.stroke();
    }

    //kruh
    function kruh() {
        canvas.beginPath();
        canvas.arc(200,80,50,0,2.0*Math.PI);
        canvas.closePath();
        canvas.stroke();
    }

    //stvorec
    stvorec();
    ciarka();
    kruh();
    obdlznik();

    $("#test").click(function() {
       _rotate(); 
    });

}); // end $(function(){});
</script>
</head>
<body>
    <button id="test">Test</button><br>
    <canvas id="canv" width=600 height=400></canvas>
</body>
</html>

[ Added explanation of beginPath and negative coordinates ]

About context.beginPath()

Think of beginPath() and fill()/stroke() as required parentheses around the context path drawing commands.

If you don't do beginPath with each new set of path drawing commands, all the previous path drawing commands will be re-executed when the next fill()/stroke() is called.

For example:

// circle#1

context.beginPath();
context.arc(100,100,10,0,Math.PI*2);
context.closePath();
context.fillStyle=”green”;
context.fill();

// circle#2  -- Note: no beginPath here

context.arc(200,200,10,0,Math.PI*2);
context.closePath();
context.fillStyle=”green”;
context.fill();

In this example, the circle#1 will be drawn. But since there is no beginPath in the code for circle#2, the circle#1 will be redrawn along with circle#2.

Both circles will be green because you are allowed only 1 styling per beginPath (the last fillStyle=”green” will be used and the red styling will not be used).

About rotation and negative coordinates

To rotate, you should tell the context which coordinate point you want to rotate around.

This is called setting the rotation point. By default, context will set the rotation point at the top left of the canvas so every subsequent drawing will be rotated around the top left of the canvas.

To set your own rotation point, you do context.translate(myCenterX,myCenterY).

Then all subsequent draws will be around myCenterX,myCenterY.

Think of this as holding a pencil-point on a piece of paper. The paper rotates around the pencil-point.

Now draw the rectangle.

Since context draws the rectangle from the top-left corner of the rectangle, the rectangle will rotate around its own top-left corner.

To rotate around the rectangle's center, you must use negative coordinates to pull the rectangle leftward and upward until the rectangle is centered on the rotation point.

This means you must fillRect( -rectWidth/2, -rectHeight/2 ) to center the rectangle over the rotation point.

Here is a simple fix:

//obdlznik
function obdlznik() {
    canvas.save();
    canvas.beginPath();               // add this and you're good to go!
    canvas.rect(150, 150, 100, 50);
    canvas.strokeStyle = "black";
    canvas.stroke();
    canvas.restore();
}

Modified fiddle here

(save/restore is strictly not necessary here either).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM