0

How do you draw an image into the canvas without it printing a bunch of the same image smearing across. The platforms stick together not separating from each other. For some reason you have to clear the whole RECT and than everything is gone???

Anybody have any ideas?

Code:

//////////////////////////////////////////////////////////
//
// MOVE PLATFORMS

var cFunc = 0;
var setRand = 1;
function setR() {
    setRand = setTimeout(setR, 10);
    cTAdd = Math.floor(Math.random() * 100 + 1);
}

var block00;
var block01; // ADD SEPERATION BLOCK(BLOCK HOLE)
var block02;
var block03;
var block04; // ADD SEPERATION BLOCK(BLOCK HOLE)
var block05;

function landT() {
    setThis = setTimeout(landT, 10);

    var canvas = document.getElementById("canvas");
    var context = canvas.getContext('2d');

    ///////////////////////////////////////////////
        //
        // X POSITION OF (BLOCK HOLE)

        ///////////////////////////////////////////////////////////////////////////
        //
        // BOTTOM ROW

        block00 = document.createElement("img");
        block01 = document.createElement("img");
        block02 = document.createElement("img");

        if (cTAdd > 0 && cTAdd < 40) {
            block00.src = "images/sep2.png";
            context.drawImage(block00, moveBlock1, 315, 400, 28);
        }

        if (cTAdd > 40 && cTAdd < 80) {
            block01.src = "images/sep1.png"; // ADD SEPERATION BLOCK(BLOCK HOLE)
            context.drawImage(block01, moveBlock2, 315, 200, 28);
        }

        if (cTAdd > 80 && cTAdd < 100) {
            block02.src = "images/platform00.png";
            context.drawImage(block03, moveBlock3, 315, 158, 28);
        }


        ///////////////////////////////////////////////////////////////////////////
        //
        // BLOCK02 GET X POS OF ADDED BLOCK 

        if (getX1 == 0) { //////////////////////////////////////////// SET (BLOCK HOLE) X
            var doc2 = block02.getBoundingClientRect();
            gX1 = doc2.left;
            getX1 = 1;
        }


        ///////////////////////////////////////////////////////////////////////////
        //
        // TOP ROW

        block03 = document.createElement("img");
        block04 = document.createElement("img");
        block05 = document.createElement("img");

        if (cTAdd > 0 && cTAdd < 40) {
            block03.src = "images/sep2.png";
            context.drawImage(block03, moveBlock1, 165, 400, 28);
        }

        if (cTAdd > 40 && cTAdd < 80) {
            block04.src = "images/sep1.png"; // ADD SEPERATION BLOCK(BLOCK HOLE)
            context.drawImage(block04, moveBlock1, 165, 200, 28);
        }

        if (cTAdd > 80 && cTAdd < 100) {
            block05.src = "images/platform00.png";
            context.drawImage(block05, moveBlock1, 165, 158, 28);
        }

}

//////////////////////////////////////////////////////////
//
// MOVE PLATFORMS 

var thisSet = 1;
var cPlayer = 1;
var moveSpeed = 5;
var xPos = 50;
var yPos = 380;
function moveLand() {

    var canvas = document.getElementById("canvas");
    var context = canvas.getContext('2d');

    thisSet = setTimeout(moveLand, 30);

    if (xPos >= 350 && moveL == 1) {
        moveBlock1 = moveBlock1 - 15;
    }

    if (gX1 > 0 && moveL == 1 && xPos >= 350) {
        gX1 = gX1 - 15;
    }
    if (getX1 == 1 && gX1 == 0) {
        getX1 = 0;
    }
    if (gX1 < 0) {
        gX1 = 0;    
    }


    console.log("X1: " + gX1); // CONSOLE/LOG gX1 

    if (moveBlock1 <= -1500) {
        moveBlock1 = 1000;
        moveBlock2 = 1300;
        moveBlock3 = 1600;
        context.clearRect(0, 0, 1023, 300); 
    }

}
SNLippold
  • 27
  • 6
  • Please describe a little more what you are trying to achieve. By reading your code it seems like you want to animate a shape moving on a canvas. Canvases are flat surfaces; to draw a shape and then remove it to draw it elsewhere requires first making a copy of what's already in that space on the Canvas. This is possible to do. – Brian A. Henning Nov 06 '15 at 19:49
  • In other words, the basic process is (1) copy the rectangle where you want to put the shape (2) draw the shape (3) draw the copied rectangle to "erase" the shape (4) repeat – Brian A. Henning Nov 06 '15 at 19:52
  • I have these platforms that you jump on, and when I draw the image it will draw it but won't erase the old one it drew to the canvas. It just keeps making copies over and over without clearing the old images. Trying to make it seem the plat forms are moving, but it just looks like it smears, because it draws so many images without erasing them as it goes. – SNLippold Nov 06 '15 at 19:53
  • How do I clear just that one shape, like targeting it? – SNLippold Nov 06 '15 at 19:54
  • 1
    You can't. Canvases are flat. Once you draw something, it ceases to exist on its own; all knowledge of what was in the space before is gone. Hence (as described in my answer) the need to use getImageData to capture what was there before, and putImageData to put it back. – Brian A. Henning Nov 06 '15 at 19:57

3 Answers3

1

Canvas has no memory, so yes, when you clear it, everything would have disappeared.

But canvas is very fast. So if you don't have complex image's filter operation (that would imply the use of the slow getImageData()/putImageData), make your script in a way it will be able to redraw it at each frame :

var ctx = canvas.getContext('2d');

function draw(){
  drawBackground();
  player.draw();
  requestAnimationFrame(draw);
  }

var drawBackground= function(){
  ctx.clearRect(0,0,canvas.width,canvas.height);
  ctx.fillStyle="#CCC";
  ctx.fillRect(0,0,canvas.width, canvas.height);
  ctx.fillStyle="#000";
  ctx.fillRect(0,canvas.height-50,canvas.width, 50);
  ctx.beginPath();
  ctx.fillStyle="orange";
  ctx.arc(25,25,12,0,2*Math.PI,0);
  ctx.fill()
  }

var player = new Player();
function Player(){
  var that = this;
  that.img = new Image;
  that.img.onload=draw;
  (that.init = function(){  
    that.img.src='http://lorempixel.com/50/50?121';
    that.x=canvas.width/2;
    that.y=canvas.height/2;
    that.width = 22;
    that.height = 22;
    })()
  that.update = function(){
    that.x += Math.random()*3-1.5;
    that.y += Math.random()*3-1.5;
    if(that.x-(that.width/2)<=0)that.x=that.width/2;
    if(that.x+(that.width/2)>=canvas.width)that.x=canvas.width-that.width/2;
    if(that.y-(that.height/2)<=0)that.y=that.height/2;
    if(that.y+(that.height/2)>=canvas.height-50)that.y=canvas.height-50-that.height/2;
    }
  that.draw = function(){
    console.log(that.x)
    that.update();
    ctx.drawImage(that.img, that.x, that.y, that.width, that.height);
    }
  return that;
  }
<canvas id="canvas"></canvas>

Now, if you really do some complex operations on the background, and that you just want to draw at some point something moving on it, you can create a clone of your canvas, use drawImage() method to make a copy of your canvas on the clone, then on each frame redraw your saved canvas and the moving object :

// save the original
var cloned = canvas.cloneNode(true).getContext('2d');
cloned.drawImage(canvas, 0,0);

// Then after in the draw loop
ctx.clearRect(0,0,canvas.width, canvas.height);
ctx.drawImage(cloned.canvas, 0,0);
drawYourMovingObject();
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • but I have the y position in one place and x is the only one that moves. It's platforms that move from right to left. – SNLippold Nov 07 '15 at 03:10
  • The idea is the same, background can be foreground, just call it after. Or if it is easier for you to implement, you can even create layers : each layer will be a different canvas, and at the end of your main loop, you draw every layers on the main, visible, canvas in the back to front order. – Kaiido Nov 07 '15 at 03:25
  • You claim getImageData/putImageData is very slow; do you have references to cite? – Brian A. Henning Nov 09 '15 at 21:53
0

This is how i did it in Tryit editor from w3schools.com. This moves the image across the canvas without repeat.

<!DOCTYPE html>
<html>
<body onLoad = "getII()">

<canvas id="myCanvas" width="1200" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

<script>
var inum = 10;



var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var imgData = ctx.createImageData(2000, 2000);
var target_area = ctx.getImageData(10, 10, 2000, 2000);

var i;
for (i = 0; i < imgData.data.length; i += 4) {
    imgData.data[i+0] = 255;
    imgData.data[i+1] = 0;
    imgData.data[i+2] = 0;
    imgData.data[i+3] = 255;
}


function getII() {
var setThis = setTimeout(getII, 100);
inum = inum + 10;

ctx.putImageData(target_area, 10, 10);
ctx.fillRect(inum, 10, 100, 100);
target_area = context.getImageData(10, 10, 2000, 2000);
ctx.putImageData(target_area, 10, 10);
ctx.fillRect(inum, 10, 100, 100);
}


</script>

</body>
</html>
SNLippold
  • 27
  • 6
-1

To do animation of a shape on a Canvas, you have to first copy the portion of the canvas where you want to draw the shape, then draw the shape. When it comes time to move the shape, draw the area you copied (to erase the shape) and repeat the process in the new location. Have a look at Canvas.getImageData() and putImageData() described on this w3cschools page

I have used this method to make a shape on a canvas follow the mouse; it definitely works.

Here's some sample code to illustrate.

var context = myCanvas.getContext("2d");

// Copy the current area of the canvas
var target_area = context.getImageData(10, 10, 50, 50);

// draw a rectangle there
context.fillRect(15, 15, 40, 40);

// Draw the copied portion back to "erase" just the rectangle
context.putImageData(target_area, 10, 10);

// Copy another area
target_area = context.getImageData(10, 15, 50, 50);

// Draw the rectangle there
context.fillRect(15, 20, 40, 40);

// draw back the copied image to "erase" just the rectangle
context.putImageData(target_area, 10, 15);

// and so on and so on
Brian A. Henning
  • 1,374
  • 9
  • 24