简体   繁体   English

如何通过 Angular ViewChildren 访问 SVG 元素

[英]How to reach SVG elements by Angular ViewChildren

I have an svg loaded as an object:我有一个 svg 作为对象加载:

<object data="assets/img/states.svg" type="image/svg+xml" id="map"></object>

This svg contains a big png map and several rect and text elements.这个 svg 包含一个大的 png 地图和几个矩形和文本元素。

<rect
     y="224.72084"
     x="644.87109"
     height="231.68137"
     width="101.08391"
     id="RECT_TO_GET" />

I'd like to get all the rect elements in an array just like I do with normal html elements like this:我想获取数组中的所有rect元素,就像我处理普通 html 元素一样:

@ViewChildren('rect') rects !: QueryList<any>;
this.rects.forEach(r=> {
            console.log(r);
        });

The problem is that the rects array is always empty.问题是 rects 数组始终为空。 I have tried to get them in ngViewAfterInit() and in ngAfterViewChecked() without success.我试图在ngViewAfterInit()ngAfterViewChecked()获取它们但没有成功。 How can I reach the elements of an svg?我怎样才能到达 svg 的元素?

I haven't tried to get them by getElementsById() yet, I'd like to do it the angular way if it's possible.我还没有尝试通过getElementsById()获取它们,如果可能的话,我想以有角度的方式进行。

The whole thing is just about giving contextual colors of each rect elements once I get them.整个过程就是在我得到每个 rect 元素后给出它们的上下文颜色。

ViewChild or ViewChildren cannot support CSS selectors ViewChildViewChildren不支持 CSS 选择器

https://angular.io/api/core/ViewChild https://angular.io/api/core/ViewChild

Supported selectors include:支持的选择器包括:

  • any class with the @Component or @Directive decorator任何带有 @Component 或 @Directive 装饰器的类
  • a template reference variable as a string (eg query with@ViewChild('cmp')`)作为字符串的模板引用变量(例如使用@ViewChild('cmp')` 查询)
  • any provider defined in the child component tree of the current component (eg @ViewChild(SomeService) someService: SomeService)当前组件的子组件树中定义的任何提供者(例如@ViewChild(SomeService) someService: SomeService)
  • any provider defined through a string token (eg @ViewChild('someToken') someTokenVal: any)通过字符串标记定义的任何提供者(例如@ViewChild('someToken') someTokenVal: any)
  • a TemplateRef (eg query with @ViewChild(TemplateRef) template;)一个 TemplateRef(例如使用 @ViewChild(TemplateRef) 模板查询;)

you can get the HtmlElement from a template reference variable and start trying to manipulate it after Object Element Resource Loaded您可以从模板引用变量中获取 HtmlElement 并在加载对象元素资源后开始尝试操作它

online example 在线示例

html html

  <object #mySvg data="./assets/new.svg" type="image/svg+xml" id="map"></object> 

component成分

  @ViewChild('mySvg') mySvg;

  ngOnInit() {
      const objElm = (this.mySvg.nativeElement as HTMLObjectElement);
    objElm.onload = () => {
        const paths = objElm.contentDocument.querySelectorAll('path');

        paths.forEach((path,index) => {
          console.log(`path:${index} , d=${path.getAttribute("d")}`);
        })

    }    
  }

Did some more research and found the solution below.做了一些更多的研究,找到了下面的解决方案。 The fun part is that this code is in the ngAfterViewInit method of my angular component and it still needs the window.onload eventlistener to work.有趣的是,这段代码在我的 angular 组件的 ngAfterViewInit 方法中,它仍然需要 window.onload eventlistener 才能工作。 Why?为什么?

window.addEventListener("load", function() {
    var svgObject = document.getElementById('map').contentDocument;
    var svg = svgObject.getElementById('svg48152');
    console.log(svg);
    const rects = svg.querySelectorAll('rect');
    console.log(rects);
    rects.forEach(r => {
        console.log(r);
    });
});

The key components are the contentDocument property and the onload eventlistener.关键组件是contentDocument属性和onload侦听器。 Some useful info for future reference: Using Javascript with SVG一些有用的信息供将来参考: Using Javascript with SVG

I just wanted to add one small thing to the answer that @Chunbin Li gave (I don't have enough reputation to comment at the moment sadly).我只是想在@Chunbin Li 给出的答案中添加一件小事(遗憾的是,我目前没有足够的声誉发表评论)。 Anyways, in the comments section, @Perrier said that this.rects is still an empty nodes list.无论如何,在评论部分,@Perrier 说this.rects仍然是一个空的节点列表。 This can be fixed by using a different lifecycle method.这可以通过使用不同的生命周期方法来解决。

When using ViewChild , it's common to utilize the lifecycle method ngAfterViewInit() .使用ViewChild ,通常使用生命周期方法ngAfterViewInit() In @Chunbin Li's answer, the function is being called in ngOnInit() , so most likely the SVG hasn't had enough time to render.在@Chunbin Li 的回答中,该函数是在ngOnInit()调用的,因此很可能 SVG 没有足够的时间进行渲染。 If you call the function inside ngAfterViewInit() instead, it would give the DOM enough time to fully render the SVG, and the SVG's properties will be accessible.如果您在ngAfterViewInit()调用该函数,它将为 DOM 提供足够的时间来完全呈现 SVG,并且可以访问 SVG 的属性。

For further reading, check out the angular docs on ViewChild .如需进一步阅读,请查看ViewChild上的 angular 文档。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM