Определить нажатие на левой или правой части элемента пути SVG (компонент React)
У меня есть компонент svg, у которого есть обработчик onClick.
Как я могу определить, какая часть этого path была нажата?
Мой path - полукруг, и мне нужно определить часть, по которой щелкнули (слева 1/2 или справа - 1/2)
<svg viewBox="0 0 651 592" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M636.971 285C636.971 322.427 628.927 359.487 613.298 394.065C597.668 428.643 574.76 460.061 545.881 486.525C517.002 512.99 482.718 533.983 444.986 548.306C407.253 562.628 366.812 570 325.971 570C285.13 570 244.689 562.628 206.957 548.306C169.224 533.983 134.94 512.99 106.061 486.525C77.1818 460.061 54.2737 428.643 38.6445 394.065C23.0153 359.487 14.9711 322.427 14.9711 285H110.253C110.253 310.96 115.833 336.666 126.674 360.65C137.515 384.634 153.404 406.427 173.435 424.783C193.467 443.14 217.247 457.701 243.419 467.636C269.591 477.57 297.643 482.684 325.971 482.684C354.3 482.684 382.351 477.57 408.523 467.636C434.695 457.701 458.475 443.14 478.507 424.783C498.538 406.427 514.428 384.634 525.268 360.65C536.109 336.666 541.689 310.96 541.689 285H636.971Z" fill="red"/>
</svg>
Свободный перевод вопроса Detect left or right part was clicked of the path element of SVG (React component) от участника @Drem Edys.
Ответы (2 шт):
Основная идея:
- Поместите фигуру в
<defs> - нарисуйте прямоугольники (r1 и r2) над каждой половиной.
- используйте этот прямоугольник, чтобы построить 2 обтравочных контура (cp1 и cp2)
- используйте фигуру дважды с помощью
<use>и вырежите первую с помощьюcp1,
а вторую - с помощьюcp2. - добавить слушателей событий к обрезанным элементам использования
u1.addEventListener("click",()=>{console.log(u1.id)})
u2.addEventListener("click",()=>{console.log(u2.id)})
<svg viewBox="0 200 651 392" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="shape" d="M636.971 285C636.971 322.427 628.927 359.487 613.298 394.065C597.668 428.643 574.76 460.061 545.881 486.525C517.002 512.99 482.718 533.983 444.986 548.306C407.253 562.628 366.812 570 325.971 570C285.13 570 244.689 562.628 206.957 548.306C169.224 533.983 134.94 512.99 106.061 486.525C77.1818 460.061 54.2737 428.643 38.6445 394.065C23.0153 359.487 14.9711 322.427 14.9711 285H110.253C110.253 310.96 115.833 336.666 126.674 360.65C137.515 384.634 153.404 406.427 173.435 424.783C193.467 443.14 217.247 457.701 243.419 467.636C269.591 477.57 297.643 482.684 325.971 482.684C354.3 482.684 382.351 477.57 408.523 467.636C434.695 457.701 458.475 443.14 478.507 424.783C498.538 406.427 514.428 384.634 525.268 360.65C536.109 336.666 541.689 310.96 541.689 285H636.971Z" fill="red" />
<clipPath id="cp1">
<rect id="r1" x="14.971099853515625" y="285" width="312" height="285"></rect>
</clipPath>
<clipPath id="cp2">
<rect id="r2" x="325.9710388183594" y="285" width="310.99993896484375" height="285"></rect>
</clipPath>
</defs>
<use xlink:href="#shape" clip-path="url(#cp1)" id="u1"/>
<use xlink:href="#shape" clip-path="url(#cp2)" id="u2"/>
</svg>
Можно просто при клике на фигуру проверить координаты клика (clientX) и сравнить их с серединой фигуры (rect.x + rect.width/2). Габариты и положение фигуры получаем при каждом клике методом path.getBoundingClientRect().
const path = document.querySelector('path');
path.addEventListener('click', e => {
let rect = path.getBoundingClientRect();
if(e.clientX < rect.x + rect.width/2){
text.textContent = "LEFT SIDE";
} else if(e.clientX > rect.x + rect.width/2){
text.textContent = "RIGHT SIDE";
} else {
text.textContent = "CENTER!!!";
}
})
<svg viewBox="0 200 651 400" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M636.971 285C636.971 322.427 628.927 359.487 613.298 394.065C597.668 428.643 574.76 460.061 545.881 486.525C517.002 512.99 482.718 533.983 444.986 548.306C407.253 562.628 366.812 570 325.971 570C285.13 570 244.689 562.628 206.957 548.306C169.224 533.983 134.94 512.99 106.061 486.525C77.1818 460.061 54.2737 428.643 38.6445 394.065C23.0153 359.487 14.9711 322.427 14.9711 285H110.253C110.253 310.96 115.833 336.666 126.674 360.65C137.515 384.634 153.404 406.427 173.435 424.783C193.467 443.14 217.247 457.701 243.419 467.636C269.591 477.57 297.643 482.684 325.971 482.684C354.3 482.684 382.351 477.57 408.523 467.636C434.695 457.701 458.475 443.14 478.507 424.783C498.538 406.427 514.428 384.634 525.268 360.65C536.109 336.666 541.689 310.96 541.689 285H636.971Z" fill="red"/>
</svg>
<p id="text" style="position:fixed;top:0;left:0;font-size:30px">
NO CLICK YET
</p>
По сути можно упростить условие до e.offsetX < rect.width/2, что более явно отражает ваши намерения.