I need to highlight a puzzle piece on mouse hover. Each puzzle is a div, masked by an SVG. I figured out how to determine a mask bounding rectangle and check within it, but I can't figure out how to check events within complex SVG shape (Codepen — https://codepen.io/alexchekanov/pen/Yzjymgq):
<style>
.tt-puzzle-container {
position: relative;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
width: 500px;
height: 500px;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
-ms-flex-pack: end;
justify-content: flex-end;
pointer-events: auto; /* added */
}
.tt-puzzle-piece {
position: absolute;
width: 100%;
height: 50%;
padding-right: 0px;
padding-bottom: 0px;
background-color: #ff0606;
-webkit-transform-origin: 50% 0%;
-ms-transform-origin: 50% 0%;
transform-origin: 50% 0%;
-webkit-transition: background-color 200ms ease;
transition: background-color 200ms ease;
}
.tt-puzzle-piece:hover {
background-color: #50ff06;
}
.tt-puzzle-piece._2 {
z-index: 10;
-webkit-transform: rotate(72deg);
-ms-transform: rotate(72deg);
transform: rotate(72deg);
mask: var(--mask-url);
}
.tt-puzzle-piece._3 {
z-index: 20;
-webkit-transform: rotate(144deg);
-ms-transform: rotate(144deg);
transform: rotate(144deg);
mask: var(--mask-url);
}
.tt-puzzle-piece._4 {
z-index: 30;
-webkit-transform: rotate(216deg);
-ms-transform: rotate(216deg);
transform: rotate(216deg);
mask: var(--mask-url);
}
.tt-puzzle-piece._5 {
z-index: 40;
-webkit-transform: rotate(288deg);
-ms-transform: rotate(288deg);
transform: rotate(288deg);
mask: var(--mask-url);
}
</style>
<body>
<div class="tt-puzzle-container">
<div class="w-embed">
<style>
:root {
--mask-url: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 238.5 209.5"><path d="M0.3,170.6c-0.5,0.7-0.3,1.6,0.4,2.1c14.8,10.1,30.8,18.3,47.5,24.3c0,0,0.1,0,0.1,0.1c1.1,0.4,2.1,0.8,3.2,1.1c0.3,0.1,0.6,0.2,0.9,0.3c0.9,0.3,1.8,0.6,2.7,0.9c0.6,0.2,1.1,0.4,1.7,0.5c0.7,0.2,1.3,0.4,2,0.6c1.3,0.4,2.6,0.8,3.8,1.1c1.4,0.4,2.8,0.8,4.2,1.1c0.5,0.1,1,0.2,1.5,0.4c0.5,0.1,1.1,0.3,1.6,0.4c0.5,0.1,1.1,0.3,1.6,0.4c1.6,0.4,3.2,0.7,4.8,1.1c0.5,0.1,1.1,0.2,1.6,0.3c1.1,0.2,2.2,0.4,3.2,0.6c0.5,0.1,1.1,0.2,1.6,0.3c1.1,0.2,2.2,0.4,3.3,0.6c0.6,0.1,1.1,0.2,1.6,0.3c1.6,0.2,3.2,0.5,4.8,0.7c0.6,0.1,1.2,0.2,1.8,0.2c0.4,0.1,0.8,0.1,1.3,0.1c0.4,0.1,0.9,0.1,1.3,0.1c0.7,0.1,1.3,0.1,1.9,0.2c0.2,0,0.4,0,0.6,0.1c30,2.8,60-0.9,87.9-10.5c12.1-4.1,23.7-9.4,34.9-15.7c3.5-2,6.9-4,10.3-6.2c1.8-1.1,3.5-2.3,5.3-3.5c0.7-0.5,0.9-1.4,0.4-2.1l-25.1-34.6c-0.8-1.1-2.5-1.1-3.2,0.1c-1.2,2-2.8,3.8-4.8,5.2c-0.8,0.5-1.6,1-2.4,1.5c-7.6,3.9-16.9,1.8-22.1-4.9c-3-3.8-4.2-8.6-3.6-13.4c0.7-4.8,3.2-9,7.1-11.9c2-1.4,4.1-2.4,6.4-2.9c1.3-0.3,1.9-1.9,1.1-3l-29.4-40.4c-0.5-0.6-1.3-0.8-2-0.4c0,0,0,0,0,0c-0.5,0.3-0.9,0.6-1.4,0.9c-0.4,0.2-0.8,0.4-1.1,0.7c-0.8,0.5-1.6,0.9-2.4,1.3c-0.3,0.1-0.5,0.3-0.8,0.4c-9.7,5-20.4,7.8-31.2,8.4c-0.3,0-0.6,0-0.9,0.1c-1,0-2,0.1-2.9,0.1c-0.4,0-0.9,0-1.3,0c-13.7-0.2-27.4-3.9-39.7-11.5c0,0-0.1,0-0.1,0c-0.1-0.1-0.3-0.2-0.4-0.2c-0.8,0.2-1.2,0.2-2,0.4l-34.5,47.5c-1.5,2.1-4.2,2.8-6.5,2c-0.5-0.2-1-0.4-1.4-0.8c-1.6-1.2-2.5-3.4-2.3-5.9c0-0.2,0-0.4-0.1-0.7c-3.4-9.2-14.2-9.1-18-2.1c-1.9,3.4-1.4,7.7,1.1,10.7c2.5,2.9,6.2,4.1,9.8,3.2c1.9-0.5,3.9-0.2,5.2,0.8c0.5,0.3,0.8,0.7,1.2,1.1c1.5,1.9,1.6,4.7,0.1,6.8L0.3,170.6z"/></svg>');
}
.tt-puzzle-piece {
-webkit-mask: var(--mask-url) center/contain no-repeat;
mask: var(--mask-url) center/contain no-repeat;
}
</style>
</div>
<div class="tt-puzzle-piece"></div>
<div class="tt-puzzle-piece _2"></div>
<div class="tt-puzzle-piece _3"></div>
<div class="tt-puzzle-piece _4"></div>
<div class="tt-puzzle-piece _5"></div>
</div>
</body>
<script>
const puzzleContainer = document.querySelector(".tt-puzzle-container");
const puzzlePieces = document.querySelectorAll(".tt-puzzle-piece");
function isEventWithinPuzzlePiece(event) {
// Get the bounding rect of the puzzle container
const puzzleContainerRect = puzzleContainer.getBoundingClientRect();
// Check if the event occurred within the puzzle container rect
return (
event.clientX >= puzzleContainerRect.left &&
event.clientX <= puzzleContainerRect.right &&
event.clientY >= puzzleContainerRect.top &&
event.clientY <= puzzleContainerRect.bottom
);
}
function isEventWithinMask(event, puzzlePiece) {
// Get the bounding rect of the mask
const maskRect = puzzlePiece.getBoundingClientRect();
// Check if the event occurred within the mask rect
return (
event.clientX >= maskRect.left &&
event.clientX <= maskRect.right &&
event.clientY >= maskRect.top &&
event.clientY <= maskRect.bottom
);
}
puzzleContainer.addEventListener("click", (event) => {
// Check if the event occurred within a puzzle piece
if (!isEventWithinPuzzlePiece(event)) {
return;
}
// Get the element under the mouse
const elementUnderMouse = document.elementFromPoint(
event.clientX,
event.clientY
);
if (!elementUnderMouse) {
return;
}
// Check if the element under the mouse is a puzzle piece
const puzzlePiece = elementUnderMouse.closest(".tt-puzzle-piece");
if (!puzzlePiece) {
return;
}
// Check if the event occurred within the mask of the puzzle piece
if (isEventWithinMask(event, puzzlePiece)) {
// Prevent the event from being handled
event.stopPropagation();
}
});
</script>