Ограничьте интерактивную область SVG ее содержимым visiblePainted

У меня есть простой SVG, который содержит треугольник и меняет цвет заливки при нажатии:

const toggleFill = (element) => {
  if (element.style.fill === 'silver') {
    element.style.fill = 'grey';
  } else {
    element.style.fill = 'silver';
  }
};
const svg = document.querySelector('svg');
svg.addEventListener('click', () => toggleFill(svg));
svg {
  height: 70px;
  width: 80px;
}
<svg viewBox = "0 0 90 78" style = "fill: silver">
  <polygon points = "0 78, 45 0, 90 78" stroke = "black"/>
</svg>

Проблема в том, что щелчок в любом месте ограничивающей рамки SVG (за пределами треугольника) также вызывает событие click. Я хотел бы ограничить его переключением цвета заливки только при нажатии на сам треугольник, а не на его прозрачный фон.

Согласно этому связанному вопросу , мое желаемое поведение должно быть поведением по умолчанию, поскольку предполагается, что события-указатели по умолчанию соответствуют поведению visiblePainted. Тем не менее, это не то, что я вижу ни в Firefox, ни в Chrome, и даже его явная установка не имеет никакого эффекта.

Рассматривали ли вы привязку событий щелчка к элементам, которые вы рисуете, например. document.querySelector('svg polygon').addEventListener...?

Terry 29.09.2022 23:41

@Terry В моем реальном коде я изменяю содержимое SVG программно, поэтому гораздо удобнее привязать обработчик кликов к самому элементу SVG.

Altay_H 29.09.2022 23:53

Если это так, не могли бы вы проверить e.target, чтобы увидеть, на что нажимают? Если e.target === e.currentTarget (т.е. SVG нажимается), то вы ничего не делаете

Terry 29.09.2022 23:57

Проблема с этим подходом заключается в том, что я разбиваю эти треугольники на мозаику, и их ограничивающие рамки перекрываются, поэтому e.target на самом деле является другим элементом SVG, чем тот, по которому щелкнули.

Altay_H 30.09.2022 00:11

Ваш тестовый пример должен отражать вашу реальную проблему в этом случае, иначе вы получите всевозможные ответы, которые вы не сможете использовать.

Robert Longson 30.09.2022 14:22
Создание фильтров для вашего сайта
Создание фильтров для вашего сайта
Фильтры - удобный инструмент в арсенале веб-дизайнера. Они позволяют изменять элементы на странице с помощью всего нескольких строк кода. Эти...
Анимация SVG-узоров без единой строки CSS
Анимация SVG-узоров без единой строки CSS
Недавно я работал над веб-проектом, который позволил мне поэкспериментировать с шаблонами SVG. С SVG очень приятно работать, как только вы получите...
Как использовать d3.js для рисования 2D SVG-элементов в приложении Angular?
Как использовать d3.js для рисования 2D SVG-элементов в приложении Angular?
D3.js - это обширная библиотека, используемая для привязки произвольных данных к объектной модели документа (DOM). Мы разберем основные варианты...
1
5
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема здесь в том, что элемент <svg> является частью HTML-страницы. Там поведение хит-тестирования не определено:

Эта спецификация не определяет поведение событий указателя на самом внешнем элементе svg для изображений SVG, которые встроены по ссылке или включению в другой документ, например, перехватывает ли самый внешний элемент svg, встроенный в документ HTML, события щелчка мыши; будущие спецификации могут определить это поведение, но для целей этой спецификации поведение зависит от реализации.

Если вы посмотрите pointer-events в контексте HTML, вы не найдете более или менее ничего:

Хотя это свойство изменяет нормальное поведение проверки попадания, эта нормальная проверка попадания в настоящее время не указана. Существует широкая интероперабельность в отношении, казалось бы, очевидных частей этой проблемы, но есть бесчисленное множество нюансов и краеугольных случаев, которые были бы очень полезны от подробной спецификации. CSS-WG будет очень признательна за помощь в написании такой спецификации.

Так что на данный момент кажется, что браузеры относятся к самому внешнему элементу <svg> как к любому другому блоку, и события щелчка фиксируются внутри всего блока рамки.

Но это верно только для самого внешнего элемента <svg>. Вложите внутрь еще один <svg> (или лучше элемент <g>) и прикрепите к нему прослушиватель событий, и ожидаемое поведение paintedVisible по умолчанию будет восстановлено:

const toggleFill = (element) => {
  if (element.style.fill === 'silver') {
    element.style.fill = 'grey';
  } else {
    element.style.fill = 'silver';
  }
};
const g = document.querySelector('svg > g');
g.addEventListener('click', () => toggleFill(g));
svg {
  height: 70px;
  width: 80px;
}
<svg viewBox = "0 0 90 78">
  <g style = "fill: silver">
    <polygon points = "0 78, 45 0, 90 78" stroke = "black"/>
  </g>
</svg>

Или еще проще, добавьте событие клика к полигону и тогда вам не нужен g

Robert Longson 30.09.2022 08:56

@RobertLongson проверьте комментарии к вопросу, ОП отклонил это решение.

ccprog 30.09.2022 14:19

Другие вопросы по теме