Я разрабатываю приложение Angular, основанное на интерактивной карте, которая была предоставлена в виде изображения SVG. В некоторых областях карты будут горячие точки, по которым я могу щелкнуть, чтобы вызвать определенные события, такие как увеличение определенной части, когда я нажимаю маркер местоположения.
Однако никакие события мыши не работают. Я могу изменить атрибуты SVG в TypeScript (например, изменить окно просмотра SVG для панорамирования и масштабирования или выделить метку красным цветом при возникновении события), но я не могу инициировать какие-либо события щелчка, прокрутки, наведения и т. д. внутри самого SVG .
До сих пор я пробовал:
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, но мне сказали, что лид отказывается это делать. Учитывая огромный размер карты, мы также отказываемся от того, чтобы она была встроенной.
Я сам нашел решение после долгих проб и ошибок. stackoverflow.com/a/56610864/9208795
Вы можете использовать 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.
Я ломал голову над этим даже в нерабочее время и нашел то, что работает. Это кажется грязным, но это работает.
Во-первых, я получаю окно содержимого тега объекта, а не документ содержания.
// 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.
Можете ли вы предоставить урезанную демонстрацию (минимальный воспроизводимый пример), которая демонстрирует проблему, пожалуйста?