Не удается вызвать события мыши на SVG в Angular 7

Я разрабатываю приложение Angular, основанное на интерактивной карте, которая была предоставлена ​​в виде изображения SVG. В некоторых областях карты будут горячие точки, по которым я могу щелкнуть, чтобы вызвать определенные события, такие как увеличение определенной части, когда я нажимаю маркер местоположения.

Однако никакие события мыши не работают. Я могу изменить атрибуты SVG в TypeScript (например, изменить окно просмотра SVG для панорамирования и масштабирования или выделить метку красным цветом при возникновении события), но я не могу инициировать какие-либо события щелчка, прокрутки, наведения и т. д. внутри самого SVG .

До сих пор я пробовал:

  • Добавление атрибутов событий angular в SVG, которые, очевидно, не являются допустимым XML, поэтому браузер не может анализировать их для рендеринга, и;
  • Поиск элемента по его идентификатору (что я могу), а затем присоединение к нему анонимной функции onclick, но она никогда не срабатывает

SVG включается через тег object.

<!--map.component.html-->
<object id = "svg-object" #svgObject type = "image/svg+xml" data = "../../../assets/img/map_large.svg"></object>

В моем компоненте после загрузки SVG я делаю следующее, но ничего не происходит. Он даже не входит в функцию.

// map.component.ts
this.svgDocument = this.svgObject.nativeElement.contentDocument.documentElement;
let el = this.svgDocument.getElementById("zoomToThis");
// this never gets triggered
el.addEventListener("click", function(event)
    {
        event.currentTarget.style.opacity = "1";
    }
);

Это, однако, работает просто отлично. Итак, ясно, что проблема не в доступе к элементам документа.

// map.component.ts
this.svgDocument = this.svgObject.nativeElement.contentDocument.documentElement;
let el = this.svgDocument.getElementById("zoomToThis");
el.style.opacity = "1";

Как я могу это исправить? Я обдумываю идею вырвать все это и использовать ванильный JavaScript в iFrame, но мне сказали, что лид отказывается это делать. Учитывая огромный размер карты, мы также отказываемся от того, чтобы она была встроенной.

Можете ли вы предоставить урезанную демонстрацию (минимальный воспроизводимый пример), которая демонстрирует проблему, пожалуйста?

Paul LeBeau 14.06.2019 14:19

Я сам нашел решение после долгих проб и ошибок. stackoverflow.com/a/56610864/9208795

benanderson89 15.06.2019 15:37
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
2 688
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете использовать HostListener с функцией, которая проверяет, произошло ли событие щелчка на элементе SVG:

// map.component.ts
@ViewChild('svgObject')    svgEl:    ElementRef;
@HostListener('click', ['$event.target'])
clickEvent(target: any) {
    if (target === svgEl.nativeElement) {
        svgEl.nativeElement.style.opacity = '1';
    }
}

Изменить. Другой способ - добавить событие onClick к элементу:

<!--map.component.html-->
<object id = "svg-object" #svgObject (click)=changeOpacity() type = "image/svg+xml"data = "../../../assets/img/map_large.svg"></object>

// map.component.ts
changeOpacity() {
    this.svgDocument = this.svgObject.nativeElement.contentDocument.documentElement;
    let el = this.svgDocument.getElementById("zoomToThis");
    el.style.opacity = "1";
}

К сожалению, это не то, что мне нужно. Как уже говорилось, мне нужно нажимать на горячие точки в SVG, а не на весь SVG.

benanderson89 15.06.2019 15:26
Ответ принят как подходящий

Я ломал голову над этим даже в нерабочее время и нашел то, что работает. Это кажется грязным, но это работает.

Во-первых, я получаю окно содержимого тега объекта, а не документ содержания.

// map.component.ts
let cw = this.svgObject.nativeElement.contentWindow;

Окно содержимого действует аналогично iFrame. Чтобы события щелчка работали внутри SVG, я могу внедрить функцию в окно содержимого.

// map.component.ts
cw.nameOfMyFunction = (event) => { /* do something */ }

Затем внутри самого SVG я могу добавить к элементам обработчики кликов (либо путем непосредственного редактирования XML, либо в программном обеспечении, таком как Inkskape).

<!--map_large.svg-->
<rect onclick = "nameOfMyFunction(event)" />

Я нажимаю прямоугольник, и функция срабатывает, как и ожидалось.

Вы можете использовать метод рендеринга для захвата событий

this.renderer.listen(document.querySelector('svg'),'click',(evt)=>{console.info(evt)});

импортируйте renderer2 и инициируйте его в конструкторе компонентов

private renderer: Renderer2

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

benanderson89 25.02.2021 10:19

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