[D3] Drawing path in D3

Here we have a force layout with three nodes. 

In the example, we will link three nodes with line and path:

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

const nodesData = [
    {name: 'Alice', id: 0},
    {name: 'Eve', id: 1},
    {name: 'Bob', id: 2}
];

const linksData = [
    {source: 0, target: 1},
    {source: 1, target: 2},
    {source: 2, target: 0}
];

export default class SimpleExample extends Component {

    componentDidMount() {

        const {width, height} = this.props;
        // Create svg inside container
        const svg = d3.select(this.refs.mountSvg)
            .append('svg')
            .attr('width', width)
            .attr('height', height);
        // Create Force layout
        const simulation = d3.forceSimulation()
            .force("link", d3.forceLink().id(function (d) {
                return d.id;
            }))
            .force("charge", d3.forceManyBody())
            .force("center", d3.forceCenter(width / 2, height / 2));



        // Create node
        const nodes = svg
            .append('g')
            .attr('class', 'nodes')
            .selectAll('circle')
            .data(nodesData)
            .enter().append('circle')
            .attr('r', width * 0.05)
            .attr('fill', '#c3c3c3')
            .call(d3.drag()
                .on('start', dragstarted)
                .on('drag', dragged)
                .on('end', dragended));
        simulation
            .nodes(nodesData)
            .on('tick', ticked);

        // Create link
        const link = svg
            .append('g')
            .attr('class', 'links')
            .selectAll('line')
            .data(linksData)
            .enter().append('line')
            .attr('stroke', '#c2c2c2')
            .attr('stroke-width', d => Math.sqrt(d.value));

        const path = svg
            .append('g')
            .selectAll('path')
            .data(linksData)
            .enter().append('path')
            .attr('fill', 'none')
            .attr('stroke', '#777')
            .attr('stroke-width', '2px')
            .attr('class', 'link');

        simulation
            .force('link')
            .distance(height / 2)
            .links(linksData);

        function ticked() {
            link
                .attr('x1', (d) => d.source.x)
                .attr('y1', (d) => d.source.y)
                .attr('x2', (d) => d.target.x)
                .attr('y2', (d) => d.target.y);
            nodes
                .attr('cx',(d, i)=> d.x)
                .attr('cy',(d, i)=> d.y);

            path
                .attr('d', (d, i) => {
                    const dx = d.target.x - d.source.x;
                    const dy = d.target.y - d.source.y;
                    const dr = Math.sqrt(dx * dx + dy * dy);
                    return `M${d.source.x},${d.source.y}A${dr},${dr} 0 0,1 ${d.target.x},${d.target.y}`;
                })
        }

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

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

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

    render() {
        const {width, height} = this.props;
        const style = {
            width,
            height,
            border: '1px solid black',
            margin: '10px auto'
        };
        return (
            <div style={style} ref="mountSvg"></div>
        );
    }
}

原文地址:https://www.cnblogs.com/Answer1215/p/7451185.html