How can I add a link to this image with javascript

Question:

estoy desarrollando un proyecto que puede verse aca:

var Elfo = {
  
  heartHeight: 80,
  heartWidth: 50,
  hearts: [],
  heartImage : 'https://dismal.site/demo/elfo/dildo01.png',
  maxHearts: 8,
  minScale: 0.4,
  draw: function() {
    this.setCanvasSize();
    this.ctx.clearRect(0, 0, this.w, this.h);
    for (var i = 0; i < this.hearts.length; i++) {
      var heart = this.hearts[i];
      heart.image = new Image();
      heart.image.style.height = heart.height;
      heart.image.src = this.heartImage;
      this.ctx.globalAlpha = heart.opacity;
      this.ctx.drawImage (heart.image, heart.x, heart.y, heart.width, heart.height);
    }
    this.move();
  },
  move: function() {
    for(var b = 0; b < this.hearts.length; b++) {
      var heart = this.hearts[b];
      heart.y += heart.ys;
      if(heart.y > this.h) {
        heart.x = Math.random() * this.w;
        heart.y = -1 * this.heartHeight;
      }
    }
  },
  setCanvasSize: function() {
    this.canvas.width = window.innerWidth;
    this.canvas.height = window.innerHeight;
    this.w = this.canvas.width;
    this.h = this.canvas.height;
  },
  initialize: function() {
    this.canvas = $('#canvas')[0];

    if(!this.canvas.getContext)
      return;

    this.setCanvasSize();
    this.ctx = this.canvas.getContext('2d');

    for(var a = 0; a < this.maxHearts; a++) {
      var scale = (Math.random() * (1 - this.minScale)) + this.minScale;
      this.hearts.push({
        x: Math.random() * this.w,
        y: Math.random() * this.h,
        ys: Math.random() + 1,
        height: scale * this.heartHeight,
        width: scale * this.heartWidth,
        opacity: scale
      });
    }

    setInterval($.proxy(this.draw, this), 50);
  }
};


$(document).ready(function(){
  Elfo.initialize();
});
body {
  /*Dildo Elfo a Mostrar */
   background-image: url("https://i.ibb.co/wQhz4B2/descarga-1.png");

  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas"></canvas>

I have a question about it, is there a way to place a link in each of the objects that fall randomly? How can I create a function that allows falling objects to be clicked, it doesn't work for the canvas because the entire screen would be a click zone, I'm only looking for what can be done on falling objects, how can I do it using javascript?

Answer:

In an HTML page you can add listeners to the DOM elements, but within a canvas this is not possible. You have to use a detection system that allows you to know what is in the place where it was clicked within the canvas and manually detect if there is something at that point. (That is to say, if you use a library like Phaser or CreateJS this functionality is included).

Assuming we don't use any specific library, you need to know where each clickable image is at all times. Luckily you already have this because you have needed it to be able to move them around the screen.

Then you only have to identify if the click is on the rectangle, knowing the current coordinates of the image and those of the mouse click inside the canvas.

I have taken the liberty of modifying your code to "update" it: I have used classes and the requestAnimationFrame function to optimize the repainting of the canvas, you only need to add the URLs to each image (or have a separate list and simply choose one at random when click on an image), but I let you choose what suits you best:

// Clase que representa cada imagen moviéndose sobre el canvas
class DildoImage {
  constructor(image, initialX, initialY, fallingSpeed,
    width = 50, height = 80, alpha = .5) {
    this.image = image;
    this.x = initialX;
    this.y = initialY;
    this.fall = fallingSpeed;
    this.width = width;
    this.height = height;
    this.alpha = alpha;
  }

  draw(ctx) {
    ctx.globalAlpha = this.alpha;
    ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
  }
}

class Elfo {

  constructor() {
    this.images = [];
    this.maxImages = 8;
    this.minScale = .4;
    this.imageW = 50;
    this.imageH = 80;
    

    this.canvas = document.querySelector('canvas');

    if (!this.canvas.getContext) {
      return;
    }

    this.setCanvasSize();
    this.ctx = this.canvas.getContext('2d');
    //Sólo necesitamos la imagen una vez, se puede reusar para pintarla
    const image = new Image();
    image.src = 'https://dismal.site/demo/elfo/dildo01.png';

    //Cada click en el canvas lo detectaremos
    this.canvas.addEventListener('click', (e) => {
      //click tendrá el índice de la imagen clickada o -1 en caso contrario
      const click = this.clickEnImagen(e.offsetX,e.offsetY);
      if (click > -1) {
        console.log('Has clickado en imagen', click, 'cuando estaba en', this.images[click].x,this.images[click].y);
      }
    });

    //bucle para inicializar las imágenes, usando su constructor
    for (let a = 0; a < this.maxImages; a++) {
      
      const scale = (Math.random() * (1 - this.minScale)) + this.minScale;
      
      let dildo = new DildoImage(image,
          Math.random() * this.w, Math.random() * this.h,
        Math.random() + 1,
        scale * this.imageW, scale * this.imageH,
        scale
      ) 
      this.images.push(dildo);
    }
    this.move(); //iniciamos el movimiento!
  }
  //este método se encarga de detectar si hemos pinchado en una imagen,
  //calculando sus bordes y comprobando que el click ha sido dentro de éstos.
  clickEnImagen(x, y) {
    return this.images.findIndex(image => {
      const left = image.x;
      const right = image.x + image.width;
      const top = image.y;
      const bottom = image.y + image.height;
      return (right >= x && left <= x && bottom >= y && top <= y);
    });
  }

  setCanvasSize() {
    this.canvas.width = window.innerWidth;
    this.canvas.height = window.innerHeight;
    this.w = this.canvas.width;
    this.h = this.canvas.height;
  }

  move() {
    this.ctx.clearRect(0, 0, this.w, this.h);
    this.images.forEach(image => {
      image.y += image.fall;
      if (image.y > this.h) {
        image.x = Math.random() * this.w;
        image.y = -1 * image.height;
      }
      image.draw(this.ctx);
    });
    
    //IMPORTANTE: cada vez que terminamos de mover, 
    //pedimos al navegador que llame de nuevo a esta función.
    //Esto hará que se ejecute 60 veces por segundo (60fps suele ser el refresco)
    requestAnimationFrame(this.move.bind(this));
  }

}

new Elfo();
body {
  /*Dildo Elfo a Mostrar */
   background-image: url("https://i.ibb.co/wQhz4B2/descarga-1.png");

  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
}
<canvas/>
Scroll to Top