【问题标题】:Dynamically adding/removing Angular components to/from the DOM using D3使用 D3 在 DOM 中动态添加/删除 Angular 组件
【发布时间】:2018-09-15 18:43:59
【问题描述】:

我正在开发一个 Angular 组件 MyGraphComponent,它应该使用 D3 显示一个图形,其中图形由一些 listOfEdges: Edge[] 和一些 listOfNodes: Node[] 给出,它们作为 MyGraphComponent 传递给 @Input s。 listOfNodes 中的每个 individualNode 都应该作为 Angular 组件 <my-node [node]="individualNode"> 显示在画布上,为给定的节点实例提供功能。 (想象一下,例如一个数据库模式编辑器,其中节点是可以编辑的表。)

现在,我想完全控制将节点添加到画布(即图形的 DOM)的方式和时间,因此,我不能只在图形组件的模板中使用 <my-node *ngFor="let node of listOfNodes">。 (例如,我想添加动画,这些动画需要与正在使用 D3 的图形的边缘和其他部分的相应动画同步。)换句话说,我需要生成 MyNodeComponent 的所有实例动态,这样我就可以使用 D3 将它们添加到 DOM(然后在必要时删除它们)。

我找到了大量解释如何动态生成 Angular 组件的资源(参见例如1234,尤其是5),但最后它们都使用 Angular 的 API 将这些组件添加到 ViewContainer。但是,我想做的是使用 D3:

function generateAngularComponent(node: Node): MyNodeComponent {
    // Use Angular's component factory to dynamically create 
    // an instance of MyNodeComponent here and return it. See 
    // the links for code examples.
}

let nodes: Node[] = [node1, node2, node3, ...];
d3.select(".my-canvas").selectAll(".my-node").data(nodes).enter()
    .append(node => {
        let component = generateAngularComponent(node);
        // Somehow return the DOM of the component here, so that 
        // D3 adds it to the canvas
    });

我该如何做到这一点——不破坏我的MyNodeComponent、它的变更检测、依赖注入等等?这可能吗?

【问题讨论】:

    标签: angular d3.js


    【解决方案1】:

    是的,有可能。我为我的应用程序创建了一个旭日形图。我创建了一个带有其类型的图表组件并将其封装在一个模块中。这是结构 -

     |charts.module.ts
     ├──sun-burst/
     |   ├──sun-burst-chart.component.ts
     |   ├──sun-burst-chart.component.html
     |   ├──sun-burst-chart.component.scss
     ├──some-other chart/
     |   ├──...ts
    

    这是我的示例图表组件。我已经删除了不必要的细节。

    import { Component, Input, ElementRef, Renderer, OnChanges } from '@angular/core';
    import * as d3 from 'd3';    
    export class SunburstChartComponent implements OnChanges {
            // inputs
            // objects related to chart like svg
            private htmlElement: HTMLElement;
            public constructor(public renderer: Renderer, public el: ElementRef) {
                this.htmlElement = el.nativeElement;
            }
    
            public ngOnChanges() {
                 // remove previously added element when data changes
                d3.select(this.htmlElement).selectAll('svg').remove();
                this.displayChart();
            }
            public displayChart() {
                // this requires some additional work before chart can be prepared, refer d3 documentation for your component 
                this.svg = d3.select(this.htmlElement).append('svg')
                    .attr('width', this.width)
                    .attr('height', this.height)
                    .append('g')
                    .attr('transform', 'translate(' + this.width / 2 + ',' + (this.height / 2) + ')');
    
            }
            // handle additional functions required for your chart like click, tween etc., refer samples for your component from d3 website.
            private click(d, arc) { 
            }
          }
    

    您需要保留在 d3 组件中添加的某些元素的引用以进行操作。它根据您创建的组件而有所不同。

    我希望这会有所帮助。 如果您遇到任何问题,请在 stackblitz 上创建一个示例并分享。

    【讨论】:

      猜你喜欢
      • 2017-12-09
      • 2020-08-21
      • 2017-11-18
      • 2017-07-19
      • 1970-01-01
      • 1970-01-01
      • 2018-05-17
      • 1970-01-01
      • 2021-09-26
      相关资源
      最近更新 更多