没有力模拟的d3 v4图

时间:2017-05-25 11:08:47

标签: javascript reactjs d3.js

我使用d3创建了一个带有图形可视化的React / Redux应用程序。 我尝试在没有强制模拟的情况下绑定图形中的节点和链接,但是我无法在onDrag函数中获取路径属性(实现链接),我在其中处理节点拖动。

我是d3中的新手,可能是一个糟糕的图表实现。使用force实现的大多数节点/链接示例,其中节点和链接之间的绑定是隐式的。我找到了thatthat,但它使用了旧的d3 v3和links.each(...)在我的应用中无效。

所以,这是我的React组件的代码:

import React,{Component} from 'react';
import * as d3 from "d3";

class MapPanel extends Component {

  constructor(props) {
    super(props);
    this.state = {
      data: {
        nodes: [
          {id: 'A', x: 100, y: 100},
          {id: 'B', x: 200, y: 100},
          {id: 'C', x: 100, y: 200},
          {id: 'D', x: 200, y: 200},
        ],
        links: [
          { source: 'A', target: "B" },
          { source: 'A', target: "C" },
          { source: 'B', target: "C" },
          { source: 'C', target: "D" },
        ]
      }
    };
  }

  componentDidMount() {
    const chart = d3.select(this.chartRef)
      .attr('width', window.innerWidth-100)
      .attr('height', 500)
      .attr("id", "svg");

    chart.append('defs').selectAll('marker')
      .data(['end'])
      .enter()
      .append('marker')
      .attr('id', "arrowhead")
      .attr('refX', 22)
      .attr('refY', 0)
      .attr('orient', "auto")
      .attr('markerWidth', 25)
      .attr('markerHeight', 25)
      .attr('markerUnits', "strokeWidth")
      .attr('xoverflow', "visible")
      .attr('viewBox', "0 -5 15 15")
      .append('path')
      .attr('d', 'M0,-5L10,0L0,5')
      .attr('fill', '#f00');

    const links = chart.selectAll('link')
      .data(this.state.data.links);

    links
      .enter()
      .append('path')
      .attr('marker-end','url(#arrowhead)')
      .attr("stroke", "black")
      .attr('d', (d, i) => {
        let sourceNode = this.state.data.nodes.find(node => node.id === d.source);
        let targetNode = this.state.data.nodes.find(node => node.id === d.target);
        return 'M ' + (sourceNode.x + 25) + ' ' + (sourceNode.y + 25) + ' L ' + (targetNode.x + 25) + ' ' + (targetNode.y + 25);
      });

    const rects = chart.selectAll('rect')
      .data(this.state.data.nodes);

    rects
      .enter()
      .append('rect')
      .attr('x', (d, i) => d.x)
      .attr('y', (d, i) => d.y)
      .attr('width', 50)
      .attr('height', 50)
      .attr('rx', 10)
      .attr('ry', 10)
      .merge(rects) //merges enter() and update()
      .call(
        d3.drag()
          .on('start', this.onDragStart)
          .on('drag', this.onDrag(links))
          .on('end', this.onDragEnd)
      );

    rects
      .exit()
      .transition()
      .attr('r', 0)
      .remove();
  }

  onDragStart() {
    d3.select(this)
      .raise() //move dragged element to last position in nodes list to layer element ontop other similar elements
      .classed('active', true);
  }

  onDrag(links) {
    return function (d, i) {
      d3.select(this).attr("x", d.x = d3.event.x).attr("y", d.y = d3.event.y);
      /*links.attr('d', function(link, linkIndex) {
        if(link.source === d.id) return 'M 10 10 L 100 100';
      });*/
    }
  }

  onDragEnd() {
    d3.select(this).classed('active', false);
  }


  render = () =>(
    <svg className="cognitive-map" ref={(r) => this.chartRef = r}></svg>
  );
}

export default MapPanel;

0 个答案:

没有答案