如何在Angular2中动态创建SVG组件?

时间:2016-08-02 14:03:14

标签: svg angular

我正在创建一个使用SVG的Web应用程序。 我创建了由SVG元素组成的组件,并将它们放入根svg元素中。 它们有属性选择器,因为SVG / XML文档树是严格的所以我不能使用元素选择器。 他们的模板以svg:g标记开头:

@Component({
  selector:'[foo]',
  template: '<svg:g>...</svg:g>',
})

在应用程序中,我想在用户按下按钮时创建一个组件, 并同时开始拖动它。 我认为可以通过使用ComponentResolver动态创建组件来实现:

  @ViewChild('dynamicContentPlaceHolder', {read: ViewContainerRef})
  protected dynamicComponentTarget: ViewContainerRef

  private componentResolver: ComponentResolver

  onMouseDown() {
    this.componentResolver
      .resolveComponent(FooComponent)
      .then((factory) => {
        const dynamicComponent = this.dynamicComponentTarget.createComponent(factory, 0)
        const component: FooComponent = dynamicComponent.instance
        const element = dynamicComponent.location.nativeElement
        // add event listener to start dragging `element`.
      })
  }

组件是在调用onMouseDown()时创建的,但其DOM元素为div,因此它是svg文档中的非法元素,无法显示。

我尝试使用selector='svg:g[foo]',然后创建g元素,但其命名空间不适用于SVG(http://www.w3.org/2000/svg),而是普通的HTML命名空间(http://www.w3.org/1999/xhtml)和它的类是HTMLUnknownElement&gt; g

我还尝试使用selector='svg:svg[foo]',然后创建svg:svg元素并显示它。但是svg:svg无法使用transform属性移动,因此这对我的应用程序来说效果不佳。

如何为属性选择器组件动态创建svg:g元素?

我使用的是Angular2:2.0.0-rc4。

3 个答案:

答案 0 :(得分:3)

您确定了g元素不会呈现为svg的命名空间问题。不幸的是,将节点作为svg元素附加是唯一可行地使组件正确命名的方法。

然而,这并不意味着这不会起作用。如果将拖动功能作为指令添加到模板中的g元素上,它将与您的组件一起编译,并且您可以将逻辑偏移到该指令中。顶级svg将被正确命名,并且模板将相应地继承它。

import {Component, Input} from '@angular/core';

@Component({
  selector: 'svg:svg[customName]', // prevent this from hijacking other svg
  template: '<svg:g dragDirective>...</svg:g>', // note the directive added here
  style: []
})
export class GComponent {

  constructor() { }

}

这可能不太理想,但在https://github.com/angular/angular/issues/10404解决之前,没有其他选择。

答案 1 :(得分:0)

我没有尝试使用Component Resolver创建组件到视图,而是改为使用。

  • 创建一个对象,其属性与您要传递给SVG组件的属性相匹配。
  • 将此对象附加到数组(ex.svgItems)。
  • 在svgItems&#34;中添加* ngFor =&#34; svgItem要动态创建的SVG组件。

希望它清楚并解决你的问题。

答案 2 :(得分:0)

我不确定我的解决方案是否正确,但是它对我有用(即使使用 ivy ):

@Component({
...
})
class ParentComponent {
    constructor(
        private injector: Injector,
        private appRef: ApplicationRef,
        private componentFactoryResolver: ComponentFactoryResolver,
    ) {}

    createDynamicComponent() {
        let node = document.createElementNS("http://www.w3.org/2000/svg", "svg");
        let factory = this.componentFactoryResolver.resolveComponentFactory(DynamicComponent);
        let componentRef = factory.create(this.injector, [], node);

        this.appRef.attachView(componentRef.hostView);
    }
}

此后,您必须手动将node附加到DOM中。