<figure class="plane">
  <img class="image" src="https://images.unsplash.com/photo-1492370284958-c20b15c692d2?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=387&q=80" alt="">
  
  <svg class="svg-overlay" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 387 501">
    <path class="polygon mustache-polygon" d="M216,146c11-8,60.5,17.5,68.5,27.5S245,197,236,192c-7-3.89-24-36.84-24-40C212,149,216,146,216,146Zm-12,0c-5.25-4.74-47.61,14.87-50,28-2,11,8,22,16,22,7.28,0,33.34-40.5,35-43A5.31,5.31,0,0,0,204,146Z" />
    <path class="polygon paws-polygon" d="M185.5,234.5c-4,29,16,121,16,140s-4,21-8,30,0,20,7,21,25,0,25,0,11,6,19,6,15,1,16-6-4-23,0-41,23-73,25-81,0-25,1-31,6-26,7-29S188.11,215.57,185.5,234.5Z" />
    <path class="polygon tail-polygon" d="M166.5,327.5c-7.82-2-63.41-2.08-68,22-4,21,15.14,22.63,22,24,10,2,16-1,17-5,1.71-6.86-13-12-4-15,9.53-3.18,32,2,35-1S170.5,328.5,166.5,327.5Z" />
  </svg>
</figure>

<div class="tooltips">
  <div class="tooltip mustache-tooltip">Mustache</div>
  <div class="tooltip paws-tooltip">Paws</div>
  <div class="tooltip tail-tooltip">Tail</div>
</div>
body {
  margin: 0;
  font-family: sans-serif;
}

.plane {
  position: relative;
}

.image {
  display: block;
  width: 100%;
}

.svg-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.polygon {
  fill: #2fff11;
  stroke: #2fff11;
  stroke-width: 1;
  fill-opacity: 0.2;
  stroke-opacity: 0.5;
  vector-effect: non-scaling-stroke;
  transition: fill 0.5s, stroke 0.5s;
}

.polygon-show {
  fill: #00bcd4;
  stroke: #00bcd4;
}

.tooltip {
  position: fixed;
  top: 0;
  left: 0;
  background-color: #f44336;
  color: #fff;
  padding: 5px 10px;
  border-radius: 9999px;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  will-change: transform, opacity;
  transition: opacity 0.5s;
}

.tooltip-show {
  visibility: visible;
  opacity: 1;
}
const plane = document.querySelector(".plane");

const parts = ["mustache", "paws", "tail"].reduce((acc, name) => {
  const polygon = document.querySelector(`.${name}-polygon`);
  const tooltip = document.querySelector(`.${name}-tooltip`);
  acc.set(polygon, tooltip);
  return acc;
}, new Map());

const state = {
  activeTooltip: null,
  activePolygon: null,
  clientX: 0,
  clientY: 0
};

window.addEventListener("mousemove", (e) => {
  if (state.activeTooltip && state.activePolygon) {
    state.activeTooltip.classList.remove("tooltip-show");
    state.activePolygon.classList.remove("polygon-show");
  }

  let x, y, polygon;
  if (e.detail) {
    polygon = e.detail.target;
    x = state.clientX;
    y = state.clientY;
  } else {
    polygon = e.target;
    x = e.clientX;
    y = e.clientY;
  }

  state.clientX = x;
  state.clientY = y;

  const tooltip = parts.get(polygon);
  if (!tooltip) {
    state.activeTooltip = null;
    state.activePolygon = null;
    return;
  }

  polygon.classList.add("polygon-show");
  tooltip.classList.add("tooltip-show");
  tooltip.style.transform = `translate(${x + 10}px, ${y}px)`;

  state.activeTooltip = tooltip;
  state.activePolygon = polygon;
});

function forceMouseMoveOnScroll(e) {
  const target = document.elementFromPoint(state.clientX, state.clientY);
  const event = new CustomEvent("mousemove", { detail: { target } });
  window.dispatchEvent(event);
}
window.addEventListener(
  "scroll",
  _.debounce(forceMouseMoveOnScroll, 200, { leading: true })
);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.19/lodash.min.js