0

Every time I google this, it gives me answers to the reverse solution - drawing stuff over images. I know how to do this.

My problem is that I want to draw my image over some canvas stuff. No matter what I do, it seems that the drawing always overlaps the image.

Could the problem be that I am doing this in an animation loop, and that is somehow not drawing the image?

You can see my code here. (It's only short).

As you can see, in my draw function I have the image to be drawn AFTER the other stuff is drawn. I checked the image is drawing correctly by commenting out the code and hey presto, the image appears. The drawImage code can be seen below:

var drawCanvasImage = new Image();
drawCanvasImage.src = "https://www.w3.org/html/logo/downloads/HTML5_Logo_256.png";
drawCanvasImage.onload = function(){ 
  ctx.drawImage(drawCanvasImage, 0, 0); 
}

Can anyone provide insight into this? Thanks.

Cameron C
  • 123
  • 1
  • 9
  • Possible duplicate of [html5 - canvas element - Multiple layers](http://stackoverflow.com/questions/3008635/html5-canvas-element-multiple-layers) –  Jan 29 '16 at 16:15

1 Answers1

0

You should do this:

  1. Load all the necessary resources. Images, audio, whatever.

    You can show a "loading" message if you want.

  2. Start painting/reproducing/whatever.

    Since the resources are available, you can use them directly.

    Avoid load event handlers here.

var drawCanvasImage = new Image();
drawCanvasImage.onload = function(){
  animFrame(recursiveAnim);
};
drawCanvasImage.src = "myimage";
function drawScreen() {
  // ...
  ctx.drawImage(drawCanvasImage, 0, 0); 
}

var animFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame    || window.oRequestAnimationFrame      || window.msRequestAnimationFrame     || null ;

window.addEventListener('mousemove', saveMove, false);

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

//Global vars
var clickX, clickY;

//Loops through to draw the graphics
mainLoop = function() {
  drawScreen();
};

//This loops the animation frames
var recursiveAnim = function() {
  mainLoop();
  animFrame(recursiveAnim);//
};
var drawCanvasImage = new Image();
drawCanvasImage.onload = function(){
  animFrame(recursiveAnim);
};
drawCanvasImage.src = "https://www.w3.org/html/logo/downloads/HTML5_Logo_256.png";


function drawScreen() {
  //sky
  ctx.fillStyle="#33ccff";
  ctx.fillRect(0, 0, c.width, c.height);
  //sun
  ctx.beginPath();
  ctx.arc(680, 150, 90, 10, Math.PI, true);
  ctx.closePath();
  ctx.lineWidth = 5;
  ctx.fillStyle = '#ffff33';
  ctx.fill();
  ctx.strokeStyle = '#b2b300';
  ctx.stroke();  
  //grass
  ctx.beginPath();
  ctx.arc(350, 950, 800, 0, Math.PI, true);
  ctx.closePath();
  ctx.lineWidth = 5;
  ctx.fillStyle = '#3fff00';
  ctx.fill();
  ctx.strokeStyle = '#1f8000';
  ctx.stroke();

  ctx.drawImage(drawCanvasImage, 0, 0); 

  //Hey SO, thanks for checking this out! :)
}


// Mouse click stuff #############################################
{
  function saveMove(e) {
    var pos = getMousePos(c, e);
    clickX = pos.x;
    clickY = pos.y;
  }

  function getMousePos(c, evt) {
    var rect = c.getBoundingClientRect();
    return {
      x: evt.clientX - rect.left,
      y: evt.clientY - rect.top
    }
  }  
}
.title {
  font-family: "Helvetica", sans-serif;
}
<canvas id="myCanvas" width="800" height="300" style="border:1px solid #000000"></canvas>
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • Thanks for your answer to this. This looks great, however I am unsure of how to proceed if for example I wanted to load more than one image. I can see that you're saying 'once the image has loaded, start the animation.'. Although I can imagine calling to load the next image being possible from inside the previous image load (basically loading through the whole list), is there a nicer way to do this? Thanks for your help! :) – Cameron C Jan 29 '16 at 17:06
  • I think I've solved it anyway. I basically just did the onload of the last image listed in the code and it loads them all before. Thanks for your help :~) – Cameron C Jan 29 '16 at 17:20
  • @CameronC When you have multiple resources you can load them sequentially (once one is loaded, begin loading the next), or you can begin loading them all simultaneously and when each one is loaded decrease a counter (when it reaches zero, call the main code). Managing this kind of things can be tedious because of the asynchronicity, but some libraries or ES6 promises can help. – Oriol Jan 29 '16 at 21:41