//image from google image search

.container
View Compiled
html, body
  width: 100%
  height: 100%

.container
  width: 100%
  height: 100%
  position: relative
  background-image: url(http://www.wildlife-photography-tips.com/images/black-and-white-nature-photography-stag.jpg)
  background-size: cover
  background-repeat: no-repeat
  background-position: center
  
.hot-spot
  width: 20px
  height: 20px
  background-color: #D29A4E
  border-radius: 50%
  position: absolute
  top: 50%
  left: 50%
  transform: translate(-50%, -50%)
  z-index: 1
  opacity: 0.8
  z-index: 1
  &:after
    content: ''
    position: absolute
    top: 50%
    left: 50%
    transform: translate(-50%, -50%)
    border: 2px solid #D29A4E
    width: 20px
    height: 20px
    border-radius: 50%
    opacity: 0
    transition: 0.2s all
  &:hover
    cursor: pointer
    opacity: 1
    &:after
      width: 25px
      height: 25px
      opacity: 1

.speech-bubble
  position: absolute
  width: 150px
  background-color: white
  border-radius: 4px
  text-align: center
  display: none
  z-index: 2
  h1
    font-size: 20px
    margin-top: 12px
    color: #333333
  p
    margin-top: 4px
    margin-bottom: 12px
    font-style: italic
    color: #888888
  &:after
    top: 100%
    left: 50%
    border: solid transparent
    content: " "
    height: 0
    width: 0
    position: absolute
    pointer-events: none
    border-color: rgba(255, 255, 255, 0)
    border-top-color: #ffffff
    border-width: 10px
    margin-left: -10px
View Compiled
var imageWidth = 2048,
    imageHeight = 1364,
    imageAspectRatio = imageWidth / imageHeight,
    $window = $(window);

var hotSpots = [{
  'title': 'Mouth',
  'description': 'scream.',
  'x': -600,
  'y': -180
}, {
  'title': 'Body',
  'description': 'Look at it.',
  'x': 108,
  'y': 20
}, {
  'title': 'Antlers',
  'description': 'They crazy.',
  'x': 40,
  'y': -170
}, {
  'title': 'This Ear',
  'description': 'It can hear things.',
  'x': -265,
  'y': -145
}];

function appendHotSpots() {
  for (var i = 0; i < hotSpots.length; i++) {
    var $hotSpot = $('<div>').addClass('hot-spot');
    $('.container').append($hotSpot);
  }
  positionHotSpots();
}

function appendSpeechBubble() {
  var $speechBubble = $('<div>').addClass('speech-bubble');
  $('.container').append($speechBubble);
}

function handleHotSpotMouseover(e) {
  var $currentHotSpot = $(e.currentTarget),
      currentIndex = $currentHotSpot.index(),
      $speechBubble = $('.speech-bubble'),
      title = hotSpots[currentIndex]['title'],
      description = hotSpots[currentIndex]['description'],
      hotSpotTop = $currentHotSpot.offset().top,
      hotSpotLeft = $currentHotSpot.offset().left,
      hotSpotHalfSize = $currentHotSpot.width() / 2,
      speechBubbleHalfSize = $speechBubble.width() / 2,
      topTarget = hotSpotTop - $speechBubble.height(),
      leftTarget = (hotSpotLeft - (speechBubbleHalfSize)) + hotSpotHalfSize;
  
  $speechBubble.empty();
  $speechBubble.append($('<h1>').text(title));
  $speechBubble.append($('<p>').text(description));
  
  $speechBubble.css({
    'top': topTarget - 20,
    'left': leftTarget,
    'display': 'block'
  }).stop().animate({
    opacity: 1
  }, 200);
}

function handleHotSpotMouseout(){
  var $speechBubble = $('.speech-bubble');
  $speechBubble.stop().animate({
    opacity: 0
  }, 200, function(){
    $speechBubble.hide();
  });
}

function positionHotSpots() {
  var windowWidth = $window.width(),
    windowHeight = $window.height(),
    windowAspectRatio = windowWidth / windowHeight,
    $hotSpot = $('.hot-spot');

  $hotSpot.each(function(index) {
    var xPos = hotSpots[index]['x'],
        yPos = hotSpots[index]['y'],
        desiredLeft = 0,
        desiredTop = 0;

    if (windowAspectRatio > imageAspectRatio) {
      yPos = (yPos / imageHeight) * 100;
      xPos = (xPos / imageWidth) * 100;
    } else {
      yPos = ((yPos / (windowAspectRatio / imageAspectRatio)) / imageHeight) * 100;
      xPos = ((xPos / (windowAspectRatio / imageAspectRatio)) / imageWidth) * 100;
    }

    $(this).css({
      'margin-top': yPos + '%',
      'margin-left': xPos + '%'
    });

  });
}

appendHotSpots();
appendSpeechBubble();
$(window).resize(positionHotSpots);
$('.hot-spot').on('mouseover', handleHotSpotMouseover);
$('.hot-spot').on('mouseout', handleHotSpotMouseout);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js
  2. https://ricostacruz.com/jquery.transit/jquery.transit.min.js