D3.js打字稿forceSimulation

时间:2019-08-22 12:18:28

标签: typescript d3.js

我正在尝试在D3.js中实现有向图。我对d3.forceSimulation()。on('tick')有问题。这是我的源代码:

    export class Graph {

      g;

      svg;

      //lines: SimLink[] = [];
      //nodes: SimNode[] = [];


      constructor(g) {
        this.g = g;
        this.prepareGraph();
      }

      prepareGraph() {
        this.svg = d3.select('svg');

        this.render(this.nodes, this.lines);
      }

      render(nodes, lines) {
        const width = +this.svg.attr('width');
        const height = +this.svg.attr('height');

        const color = d3.scaleOrdinal(d3.schemeCategory10);

        const simulation = d3.forceSimulation(this.nodes)
          .force('charge', d3.forceManyBody())
          .force('link', d3.forceLink().links(this.lines).id((d: SimNode) => d.id))
          .force('center', d3.forceCenter(width / 2, height / 2));

        const link = this.g
          .attr('class', 'links')
          .selectAll('line')
          .data(lines)
          .enter().append('line')
          .attr('stroke-width', d => Math.sqrt(d.value))
          .attr('stroke', d => '#D3D3D3');

        const node = this.g
          .attr('class', 'nodes')
          .selectAll('circle')
          .data(nodes)
          .enter().append('circle')
          .attr('r', 2)
          .attr('fill', d => color(d.group))
          .call(d3.drag()
            .on('start', (d) => dragstarted(d))
            .on('drag', (d) => dragged(d))
            .on('end', (d) => dragended(d)));

        node.append('title')
          .text(d => d.id);

        simulation
          .nodes(nodes);
          // .on('tick', ticked);

        function ticked() {
          link
            .attr('x1', (d: SimulationLinkDatum<SimulationNodeDatum>) => (d.source as SimulationNodeDatum).x)
            .attr('y1', (d: SimulationLinkDatum<SimulationNodeDatum>) => (d.source as SimulationNodeDatum).y)
            .attr('x2', (d: SimulationLinkDatum<SimulationNodeDatum>) => (d.target as SimulationNodeDatum).x)
            .attr('y2', (d: SimulationLinkDatum<SimulationNodeDatum>) => (d.target as SimulationNodeDatum).y);
          node
            .attr('cx', (d: SimulationNodeDatum) => d.x)
            .attr('cy', (d: SimulationNodeDatum) => d.y);
        }

        function dragged(d) {
          console.log('dragged', d);
          d.fx = d3.event.x;
          d.fy = d3.event.y;
        }

        function dragended(d) {
          console.log('dragended', d);
          if (!d3.event.active) {
            simulation.alphaTarget(0);
          }
          d.fx = null;
          d.fy = null;
        }

        function dragstarted(d) {
          console.log('dragstarted', d);
          if (!d3.event.active) {
            simulation.alphaTarget(0.3).restart();
          }
          d.fx = d.x;
          d.fy = d.y;
        }
      }

    }

示例数据:

      nodes: [
        { id: '1' },
        { id: '2' },
        { id: '3' },
        { id: '4' },
      ],
      lines: [
        { source: '1', target: '2' },
        { source: '2', target: '3' },
        { source: '3', target: '4' },
      ]

on(“打勾”,打勾)在控制台中引发以下错误:

    Error: <line> attribute x1: Expected length, "NaN"

当我注释这行代码时,它只画了我一个点。 为什么链接或节点没有X或Y属性?

有什么想法吗?我在做什么错了?

1 个答案:

答案 0 :(得分:-1)

我已经设法解决了我的问题。这是解决方案:

prepareGraph(link, node) {
const g = this.g;
const width = this.g.attr('width');
const height = this.g.attr('height');

const colors = d3.scaleOrdinal(d3.schemeCategory10);

g.append('defs').append('marker')
  .append('svg:path')
  .attr('d', 'M 0,-5 L 10 ,0 L 0,5')
  .attr('fill', '#999')
  .style('stroke', 'none');

const simulation = d3.forceSimulation()
  .force('link', d3.forceLink().id((d: any) => d.id).distance(100).strength(1))
  .force('charge', d3.forceManyBody())
  .force('center', d3.forceCenter(width / 2, height / 2));

update(this.links, this.nodes);

function update(links, nodes) {
  link = g.selectAll('.link')
    .data(links)
    .enter()
    .append('line')
    .attr('class', 'link')
    .attr('stroke-width', d => Math.sqrt(d.value))
    .attr('stroke', d => '#D3D3D3')
    .attr('marker-end', 'url(#arrowhead)');

  node = g.selectAll('.node')
    .data(nodes)
    .enter()
    .append('g')
    .attr('class', 'node')
    .call(d3.drag()
      .on('start', dragstarted)
      .on('drag', dragged));

  node.append('circle')
    .attr('r', 5)
    .style('fill', (d, i) => colors(i));

  node.append('title').text(d => d.id);

  node.append('text').attr('dy', -3).text(d => d.name);

  simulation
    .nodes(nodes)
    .on('tick', ticked);

  simulation.force<any>('link')
    .links(links);
}