Search code examples
javascriptjqueryhtmlimageimagemap

How can I remove the associated image when an image map area is clicked in JavaScript (jQuery)?


I created a simple 'whack-a-mole' game where the same image appears in the gamespace in random positions and at random times and if you click the image it disappears, no problem. To make the game more difficult I added an image map so that you have to click a certain part of the image and now I can't figure out how to remove the associated image after a click. I have read lots of related questions on this site and the closest that I found was the answer by FiLeVeR10 that used hover but it was too slow and only worked for about 20% of the clicks playing the game at speed.

The closest other way that worked is adding an .on click to the image map area. This method is running my IncrementScore() function just fine, but what can I use on the next line to remove the associated image? I have tried at least a hundred different things and none of them work. Adding an onclick attribute to the area behaved the same and would increment the score, but I still had the same problem removing the underlying image.

The only place that I can even see the image is in offsetParent, but all of the images in the gamespace were in there as well and not just the one that I want to remove, so I couldn't figure out how to select the right one. The relevant code is below.

$(document).ready(function() {
  $('#molemap').on('click', function(e) {
    incrementScore(); //This works perfectly
    $(this).I.have.tried.hundreds.of.things.here; //And I can't figure it out
  });
});

function addMole() {
  $('#gamespace').append('<img src="img/simole.png" class="mole" usemap="#molemap" id="mole-image" style="left: ' + imgXPos + 'px; top: ' + imgYPos + 'px;" />');
}
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
<div id="content">
  <map name="molemap">
          <area id="molemap" coords="25,163,56,139,48,125,44,108,45,92,8,82,4,100,5,118,9,133,15,146" shape="poly"/>
      </map>
  <div id="gamespace">

  </div>
</div>


Solution

  • You'll need to create a different map for each image, otherwise you won't be able to tell which image was clicked.

    This markup assigns a data-mole attribute to the area, so you'll be able to associate it with the matching image upon click:

    <!-- map for mole 1 -->
    <map name="mm1">
      <area shape="rect" data-mole="1" coords="20, 20, 60, 60" href="#" />
    </map>
    <!-- image for mole 1 -->
    <img id="mole1" src="your/mole/img.png" usemap="#mm1"
      style="left: 10px; top: 20px;" />
    

    A working example with 3 images.

    const gameSpace = document.getElementById('gamespace');
    
    // listen for clicks within the gamespace
    gamespace.addEventListener('click', evt => {
      const area = evt.target;
      const map = area.parentElement;
    
      // determine if click was within a mole's area
      const iMole = area.dataset.mole;
      if (iMole) {
        let moleImg = document.getElementById(`mole${iMole}`);
        // remove image, area, map
        moleImg.remove();
        area.remove();
        map.remove();
      } else {
        alert('you missed!');
      }
    });
    #gamespace {
      background-color: green;
      width: 400px;
      height: 180px;
    }
    
    img {
      height: 80px;
      width: 80px;
      position: absolute;
    }
    <div id="gamespace">
      <map name="mm1">
         <area shape="rect" data-mole="1"
           coords="20, 20, 60, 60" href="#" />
        </map>
      <img id="mole1" src="https://picsum.photos/80/80" usemap="#mm1" style="left: 10px; top: 20px;" />
    
      <map name="mm2">
         <area shape="rect" data-mole="2"
           coords="20, 20, 60, 60" href="#" />
        </map>
      <img id="mole2" src="https://picsum.photos/80/80" usemap="#mm2" style="left: 100px; top: 40px;" />
    
      <map name="mm3">
         <area shape="rect" data-mole="3"
           coords="20, 20, 60, 60" href="#" />
        </map>
      <img id="mole3" src="https://picsum.photos/80/80" usemap="#mm3" style="left: 200px; top: 18px;" />
    </div>