Solution Using Vanilla JavasScript and Canvas
You can embed a complex shape in an object that processes the position and validates. An object might look like this:
Full working demo here
Extract:
The main object is
function wave(ctx, offset, width) { /// the check function which checks point x, y in last path this.isInPath = function(x, y) { getPath(); return ctx.isPointInPath(x, y); } /// this render the object with the set fill color this.draw = function(color) { getPath(); ctx.fillStyle = color; ctx.fill(); ctx.lineWidth = 5; ctx.strokeStyle = "red"; ctx.stroke(); } /// common function to generate just the path. function getPath() { ctx.beginPath(); ctx.moveTo(offset, 0); ctx.bezierCurveTo(50 + offset, 30, 40 + offset, 45, 13 + offset, 89); ctx.bezierCurveTo(offset, 110, offset, 126, 27 + offset, 174); ctx.lineTo(27 + offset + width, 174); ctx.bezierCurveTo(offset + width, 100, offset + width + 0, 126, 27 + offset + width, 65); ctx.bezierCurveTo(43 + offset + width, 40, 40 + offset + width, 25, offset + width, 0); ctx.closePath(); } this.draw('white'); return this; }
Make sure that the path is autonomous, which means that it is a complete form independent of adjacent parts (i.e. without using adjacent lines). This is basically all you need to handle complex shapes.
Render
To make it simple:
for(;i < parts_num; i++) { parts.push( new wave(context, i * part_width, part_width) ); }
Check
How to check if a point is in a part, you can do this:
/// check mouse move in this example canvas.addEventListener('mousemove', hover, false); /// the function to check parts function hover(e) { ///get mouse coord relative to canvas var r = canvas.getBoundingClientRect(); var x = e.clientX - r.left; var y = e.clientY - r.top; ///optimize so we only clear last selected part if (lastPart > -1) { parts[lastPart].draw('white'); lastPart = -1; } for(i = 0 ;i < parts_num; i++) { if (parts[i].isInPath(x, y) === true) { parts[i].draw('green'); lastPart = i; break; //don't need to check more } } }
There is room for optimization (reusing the last path inside an object, caching the form as images, the range of verification of the segment as such), but it shows that in fact it is not so difficult to deal with the use of vanilla canvas and JavaScript.
With this base you can handle clicks, etc.
(Note. I am not too precise with the closing end on the bezier - I will leave it for fine tuning if you decide to use this solution ..).