JSFiddle - React, Tailwind, and code Playground
HTML
<div id="hit">false</div>
<section id="ages">
<a class="year20" href="#1993" data-map="524,232,521,203,505,153,485,114,459,81,428,52,403,35,373,20,342,8,310,1,277,0,250,0,229,1,198,7,169,18,110,48,102,53,73,78,45,107,22,144,8,176,1,216,0,240,3,282,17,326,33,366,57,408,68,424,87,444,117,466,147,482,177,495,192,502,227,510,254,511,288,510,327,502,365,489,407,462,431,446,462,410,486,374,503,336,515,295,521,260,524,232"><span></span></a>
<a class="year19" href="#1994" data-map="512,241,510,202,501,166,491,140,472,112,447,80,422,58,382,35,343,19,295,11,243,10,203,16,172,28,155,37,133,46,112,61,83,85,56,112,38,141,27,166,20,192,15,219,14,245,15,268,18,287,28,323,39,349,54,379,73,408,92,430,108,444,131,459,146,466,169,477,183,486,214,495,259,499,302,494,344,484,386,465,421,439,450,410,472,378,491,338,503,297,509,264,512,241"><span></span></a>
<a class="year18" href="#1995" data-map="500,239,499,203,493,172,479,140,464,116,446,95,426,76,404,60,380,48,352,35,316,25,275,19,230,23,193,31,160,45,120,67,101,80,76,108,58,129,43,157,31,189,26,217,24,257,27,278,40,325,55,362,76,397,103,426,142,456,157,463,172,468,187,477,237,488,292,486,345,474,390,451,425,420,455,384,477,348,487,315,496,278,500,239"><span></span></a>
<a class="year17" href="#1996" data-map="491,244,490,206,484,171,471,140,451,110,426,84,399,65,375,52,346,40,303,30,264,27,220,32,180,45,152,58,135,67,117,81,103,91,83,112,64,143,54,162,39,216,37,235,42,289,48,313,61,344,79,376,107,412,136,436,176,459,223,472,279,475,335,466,379,444,420,410,454,366,471,335,484,292,488,270,491,244"><span></span></a>
<a class="year16" href="#1997" data-map="481,249,481,215,477,186,469,157,448,124,427,100,400,78,376,62,354,51,326,43,299,39,265,38,231,40,201,46,170,58,137,77,118,90,85,127,65,162,51,209,48,249,51,283,59,315,73,347,93,378,116,405,147,428,183,450,225,461,274,465,330,457,362,442,396,420,425,391,446,361,463,329,475,292,481,249"><span></span></a>
<a class="year15" href="#1998"...
CSS
#hit
{
border: solid 1px black;
padding: 2px;
position: absolute;
left: 0;
top: 0;
}
#ages
{
width: 524px;
height: 513px;
position: absolute;
left: 20px;
top: 20px;
}
#ages > a
{
display: block;
position: absolute;
}
JavaScript
var pointInPolygon = function(point, vs)
{
// ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
var x = point[0], y = point[1];
var inside = false;
for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
var xi = vs[i][0], yi = vs[i][1];
var xj = vs[j][0], yj = vs[j][1];
var intersect = ((yi > y) != (yj > y))
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
};
var mapToPolygon = function(map)
{
var split = map.split(',');
var points = [];
var point = [];
for (var i = 0; i < split.length; i++)
{
// Push point to points.
point.push(parseInt (split[i]));
// If two points inside "the point". Push and start a new one.
if (point.length === 2)
{
points.push(point);
point = [];
}
}
return points;
};
$(function()
{
var ages = $('#ages');
var layers = $('a[data-map]', ages);
var hit = $('#hit');
// Get polygon data.
layers.each(function()
{
var $layer = $(this);
var map = $layer.data('map');
var polygon = mapToPolygon(map);
$layer.data('polygon', polygon);
var canvas = $(document.createElement('canvas'));
canvas.appendTo(ages);
canvas.attr('width', ages.width()).attr('height', ages.height()).css({
position : 'absolute',
left : 0,
top : 0,
pointerEvents : 'none'
});
var ctx = canvas[0].getContext('2d');
ctx.beginPath();
ctx.moveTo(polygon[0][0], polygon[0][1]);
for (var i = 1; i < polygon.length; i++)
{
ctx.lineTo(polygon[i][0], polygon[i][1]);
}
ctx.strokeStyle = 'red';
ctx.stroke();
});
var polygon = layers.eq(0).data('polygon');
...