无法在D3.JS和Angular Typescript中显示节点之间的链接

时间:2017-12-18 17:31:07

标签: angular typescript d3.js

我正在使用基于简单角度CLI的项目和d3-ng2-service,我已经创建了一个组件来尝试使用强制布局。在执行代码时,节点会显示,但它们之间的链接不会显示。

d3component.html

<p>
  test-d3-component works!
</p>

d3component.css

.links line {
  stroke: #999;
  stroke-opacity: 0.6;
}

.nodes circle {
  stroke: #fff;
  stroke-width: 1.5px;
}

d3component.component.ts

import { Component, OnInit, ElementRef} from '@angular/core';
import { D3Service, D3, Selection } from 'd3-ng2-service';

@Component({
  selector: 'app-test-d3-component',
  templateUrl: './test-d3-component.component.html',
  styleUrls: ['./test-d3-component.component.css']
})
export class TestD3ComponentComponent implements OnInit {
  private d3: D3;
  private parentNativeElement: any;
  svg;     // for dynamic svg addition to component
  link;    // link creation
  node;    // node creation
  simulation;  // force simulation
  color;  // color of nodes

  constructor(element: ElementRef, d3service: D3Service) {
    this.d3 =  d3service.getD3(); // get D3Service....
    this.parentNativeElement = element.nativeElement; // parent native component
  }

  ngOnInit() {
    // add the SVG graphic
    this.svg = this.d3.select(this.parentNativeElement).append('svg');
    // height, width, color selection
    this.svg.attr('width', 1000).attr('height', 800);
    this.color = this.d3.scaleOrdinal(this.d3.schemeCategory20);

    // Force Layout Simulation for D3
    this.simulation = this.d3.forceSimulation()
      .force("link", this.d3.forceLink().id(function(d: {id: string, group: number})
       { return d.id; }))
      .force('charge', this.d3.forceManyBody())
      .force('center', this.d3.forceCenter(1000/2, 800/2));
      // call the rendering function with a fix json for now..
      this.render({
        'nodes': [
        {'id': 'Alice', 'group': 1},
        {'id': 'Bob', 'group': 2},
        {'id': 'Cathy', 'group': 3}
      ],
      'links': [
        {'source': 'Alice', 'target': 'Bob', 'value': 1},
        {'source': 'Bob', 'target': 'Cathy', 'value': 2},
      ]
    });

  }

  ticked() {
    this.link
      .attr("x1", (d) => { return d.source.x; })
      .attr("y1", (d) => { return d.source.y; })
      .attr("x2", (d) => { return d.target.x; })
      .attr("y2", (d) => { return d.target.y; });

  this.node
      .attr("cx", (d) => { return d.x; })
      .attr("cy", (d) => { return d.y; });
  }


 /*
      Rendering Function
  */

  render(graph): void {
    this.link = this.svg.append('g')
        .attr('class', 'links')
        .selectAll('line') // from the CSS file
        .data(graph.links)
        .enter().append('line')
        .attr("stroke-width", (d) => { return Math.sqrt(d.value); });

    this.node = this.svg.append('g')
        .attr('class', 'nodes')
        .selectAll('circle') // from the CSS file
        .data(graph.nodes)
        .enter().append('circle')
        .attr('r', 10)
        .attr('fill', (d: any) => {
          return this.color(d.group);
        })
        .call(this.d3.drag()
          .on('start', (d) => {return this.dragStarted(d);})
          .on('drag', (d) => {return this.dragged(d);})
          .on('end', (d) => {return this.dragEnd(d);})
        );
        this.node.append('title')
          .text( (d) => { return d.id});
          this.simulation
      .nodes(graph.nodes)
      .on("tick", ()=>{return this.ticked()});

    this.simulation.force("link")
      .links(graph.links);
    }

  dragged(d): void {
    d.fx = this.d3.event.x;
    d.fy = this.d3.event.y;
  }

  dragEnd(d): void {
    if (!this.d3.event.active) this.simulation.alphaTarget(0);
    d.fx = null;
    d.fy = null;
  }

  dragStarted(d):void {
    if (!this.d3.event.active) this.simulation.alphaTarget(0.3).restart();
    d.fx = d.x;
    d.fy = d.y;
  }

  ngAfterViewInit() {}



}

输出渲染

enter image description here

我不确定为什么links未在此处呈现,因为我的代码基于答案中的SE ThreadRelated Plunker

即使使用给定的miserables.json,渲染也会提供节点而不是链接

miserables data

2 个答案:

答案 0 :(得分:1)

这可能会对其他人有所帮助。

我遇到了同样的问题并通过在链接描边添加颜色来修复它。尝试添加:

.attr("stroke", (d)=> { return "#D3D3D3"; });

之后:

.attr('stroke-width', (d) => Math.sqrt(d['value']))

答案 1 :(得分:0)

解决方案

我发现了一个相当simple repository for the same graph on GitHub的安装 d3 库并将其直接导入角度组件文件。我认为 v4.x D3 包含的内容。因此代码如下:

<强> d3component.component.html

<p>
  test-d3-component works!
</p>

<svg width="800" height="1000"></svg>

<强> d3component.component.ts

import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import * as d3 from 'd3';
import { miserables, test } from './miserables';
@Component({
  selector: 'app-test-d3-component',
  templateUrl: './test-d3-component.component.html',
  styleUrls: ['./test-d3-component.component.css'],
  encapsulation: ViewEncapsulation.None // this is new...
})

export class TestD3ComponentComponent implements OnInit {
 // kept the code same according to the Thread
  svg;
  width;
  height;
  color;
  simulation;
  link;
  node;

  ngOnInit() {
      console.log('D3.js version:', d3['version']);

      this.loadForceDirectedGraph();
    }
  // Rendering 

  loadForceDirectedGraph() {
      this.svg = d3.select('svg');
      this.width = +this.svg.attr('width');
      this.height = +this.svg.attr('height');
      this.color = d3.scaleOrdinal(d3.schemeCategory20);

      this.simulation = d3.forceSimulation()
        .force('link', d3.forceLink().id((d) => d['id']))
        .force('charge', d3.forceManyBody())
        .force('center', d3.forceCenter(this.width / 2, this.height / 2));

      this.render(test);
  }

  render(data): void {
      this.link = this.svg.append('g')
        .attr('class', 'links')
        .selectAll('line')
        .data(data['links'])
        .enter()
        .append('line')
        .attr('stroke-width', (d) => Math.sqrt(d['value']));

      this.node = this.svg.append('g')
            .attr('class', 'nodes')
            .selectAll('circle')
            .data(data['nodes'])
            .enter()
            .append('circle')
            .attr('r', 10)
            .attr('fill', (d) => this.color(d['group']))
            .call(d3.drag()
              .on('start', (d) => {return this.dragStarted(d);})
              .on('drag', (d) => {return this.dragged(d);})
              .on('end', (d) => {return this.dragEnded(d);})
            );
      this.node.append('title')
          .text( (d) => { return d.id});
      this.simulation
      .nodes(data.nodes)
      .on("tick", ()=>{return this.ticked()});

    this.simulation.force("link")
      .links(data.links);
  }
  ticked() {
      this.link
        .attr('x1', function(d) { return d['source'].x; })
        .attr('y1', function(d) { return d['source'].y; })
        .attr('x2', function(d) { return d['target'].x; })
        .attr('y2', function(d) { return d['target'].y; });

    this.node
      .attr('cx', function(d) { return d['x']; })
      .attr('cy', function(d) { return d['y']; });
  }

  dragStarted(d): void {
    if (!d3.event.active) { this.simulation.alphaTarget(0.3).restart(); }
    d.fx = d.x;
    d.fy = d.y;
  }

  dragged(d): void {
    d.fx = d3.event.x;
    d.fy = d3.event.y;
  }

  dragEnded(d): void {
    if (!d3.event.active) { this.simulation.alphaTarget(0); }
    d.fx = null;
    d.fy = null;
  }
}

<强> miserables.ts

export let test = {
  'nodes': [
    {'id': 'Alice', 'group': 2},
    {'id': 'Bob', 'group': 3},
    {'id': 'Cathy', 'group': 4}
  ],
  'links': [
    {'source': 'Alice', 'target': 'Bob', 'value': 2},
    {'source': 'Bob', 'target': 'Cathy', 'value': 4},
    {'source': 'Cathy', 'target': 'Alice', 'value': 6},
  ]
}

<强>输出

Output

推断

我认为 d3.js v4.x 提供了Typescript支持,因此可以使用

轻松安装和使用
npm install --save d3

如果正在使用angular-cli,则无需在整个项目中设置d3文件夹。