Trailing image using HTML canvas and JS

Viewed 79

I am making an interactive animation where bubbles appear on the screen and float around, and when the user moves the cursor a fish image (.png) will trail behind it.

I have gotten the bubbles to appear the way I would like them to, but the fish image will not appear on the screen for some reason.

I'm not sure what I did wrong?

Here is the code:

<body>
  <!--Header explaining how to interact with the code-->
  <div class="background">
  </div>

  <div class="header">
    <h1>Just Keep Swimming</h1>
    <h3>Oh no! The ocean is empty! Move your cursor to fill it with some fishy friends :)</h3>
  </div>
  <!--Canvas to hold all canvas javascript-->
  <canvas id="canvas" width="1435" height="710">
         </canvas>
  <script>
    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");
    //for the bubbles 
    var bubbles = new Array();

    for (var i = 0; i < 50; i++) {

      bubbles[i] = new Array();
      bubbles[i]["size"] = Math.random() * 40 + 10;
      bubbles[i]["xPos"] = Math.random() * 1435;
      bubbles[i]["xDir"] = Math.random() < 0.5 ? 1 : -1;
      bubbles[i]["xVel"] = Math.random() * 5;

      bubbles[i]["yPos"] = Math.random() * 710;
      bubbles[i]["yDir"] = Math.random() < 0.5 ? 1 : -1;
      bubbles[i]["yVel"] = Math.random() * 5;
    }
    //xPos is the x position, xDir is x direction, xVel is x velocity 
    //and that is the same for yPos, yDir, and yVel
    context.lineWidth = 5;
    context.strokeStyle = "#6BCFE5";
    context.fillStyle = "#F5EEDC";
    context.globalAlpha = 0.5;

    function frame(timestamp) {

      context.clearRect(0, 0, 1435, 710);

      for (var i = 0; i < 50; i++) {

        context.beginPath();
        context.arc(bubbles[i]["xPos"], bubbles[i]["yPos"], bubbles[i]["size"], 0, 2 * Math.PI);
        context.stroke();
        context.fill();

        bubbles[i]["xPos"] = bubbles[i]["xPos"] + (bubbles[i]["xVel"] * bubbles[i]["xDir"]);
        if (bubbles[i]["xPos"] > 1425) bubbles[i]["xDir"] = -1;
        if (bubbles[i]["xPos"] < 20) bubbles[i]["xDir"] = 1;

        bubbles[i]["yPos"] = bubbles[i]["yPos"] + (bubbles[i]["yVel"] * bubbles[i]["yDir"]);
        if (bubbles[i]["yPos"] > 1425) bubbles[i]["yDir"] = -1;
        if (bubbles[i]["yPos"] < 20) bubbles[i]["yDir"] = 1;
      }
      //this function allows the browser to animate
      //the frame is gonna draw circle at 0 which is counter and 150 and then ask browser when your ready draw this circle here
      window.requestAnimationFrame(frame);

    };
    frame();
    //for the fish trailing image 
    //load image
    var fish_image = new Image();
    fish_image.src = 'img/fish-are-friends-not-food.png';
    fish_image.onload = function() {}
    // for the image to load when the mouse moves 
    canvas.addEventListener('mousemove', function(event) {

      //get position of the mouse, this position is based on ...
      //browser window, so need to adjust for that position
      var xMouse = event.clientX;
      var yMouse = event.clientY;

      //adjust for the psoition of the canvas 
      xMouse -= (canvas.offsetLeft - canvas.scrollLeft + canvas.clientLeft);
      yMouse -= (canvas.offsetTop - canvas.scrollTop + canvas.clientTop);

      //adjust for the image 
      xMouse -= 65;
      yMouse -= 65;

      context.drawImage(fish_image, xMouse, yMouse);
    });
  </script>

</body>

1 Answers

Here is some code expanding on my comment:

  • On the fish_image.onload we flag that it completely loaded, that way we can draw it
  • Moved the drawing of the image to inside function frame if not we risk it getting cleared
  • On the mousemove we just collect the position to later draw the image
  • Your image only works on your server so I changed this example to src = 'http://i.stack.imgur.com/UFBxY.png' that way we can see something in action

See code below

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var image_ready = false
var mouse_pos = null
var bubbles = new Array();

for (var i = 0; i < 50; i++) {
  bubbles[i] = new Array();
  bubbles[i]["size"] = Math.random() * 40 + 10;
  bubbles[i]["xPos"] = Math.random() * 1435;
  bubbles[i]["xDir"] = Math.random() < 0.5 ? 1 : -1;
  bubbles[i]["xVel"] = Math.random() * 5;

  bubbles[i]["yPos"] = Math.random() * 710;
  bubbles[i]["yDir"] = Math.random() < 0.5 ? 1 : -1;
  bubbles[i]["yVel"] = Math.random() * 5;
}

function frame(timestamp) {
  context.clearRect(0, 0, 1435, 710);
  bubbles.forEach((b) => {
    context.beginPath();
    context.arc(b["xPos"], b["yPos"], b["size"], 0, 2 * Math.PI);
    context.stroke();

    b["xPos"] += (b["xVel"] * b["xDir"]);
    if (b["xPos"] > 1425) b["xDir"] = -1;
    if (b["xPos"] < 20) b["xDir"] = 1;

    b["yPos"] += (b["yVel"] * b["yDir"]);
    if (b["yPos"] > 1425) b["yDir"] = -1;
    if (b["yPos"] < 20) b["yDir"] = 1;
  })

  if (image_ready && mouse_pos) {
    context.drawImage(fish_image, mouse_pos.x - fish_image.width / 2, mouse_pos.y);
  }
  window.requestAnimationFrame(frame);
};
frame();

var fish_image = new Image();
fish_image.src = 'http://i.stack.imgur.com/UFBxY.png';
fish_image.onload = function() {
  image_ready = true
}

canvas.addEventListener('mousemove', function(evt) {
  var rect = canvas.getBoundingClientRect();
  mouse_pos = {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
  };
}, false);
<canvas id="canvas" width="300" height="160"></canvas>

Related