【问题标题】:D3.js various link distanceD3.js各种链接距离
【发布时间】:2021-10-25 09:49:57
【问题描述】:

我需要实现各种链接距离。我在力/模拟的初始化过程中添加了一个函数调用。不过,看起来设置被忽略了。我想添加另一个非常接近的节点,几乎没有一根头发可以放在它们之间。这甚至可能吗?

我注意到 stackoverflow 上有一个similar question 但这需要另一个插件,而且这个问题是 4 年前创建的。也许 vanilla d3.js 已经添加了该功能。

            var graph = {
                "nodes": [
                    {
                        "id": 0
                    },
                    {
                        "id": 1
                    },
                    {
                        "id": 2
                    },
                    {
                        "id": 3
                    }
                ],
                "links": [
                    {
                        "source": 0,
                        "target": 1,
                        "distance": 0.1
                    },
                    {
                        "source": 0,
                        "target": 2,
                        "distance": 150
                    },
                    {
                        "source": 0,
                        "target": 3,
                        "distance": 20
                    }
                ]
            }

            var svg = d3.select("svg")
                .attr("class", "canvas")
                .attr("width", window.innerWidth)
                .attr("height", window.innerHeight)
                .call(d3.zoom().on("zoom", function (event) {
                    svg.attr("transform", event.transform)
                }))
                .append("g")

            var linksContainer = svg.append("g").attr("class", linksContainer)
            var nodesContainer = svg.append("g").attr("class", nodesContainer)
            var sourceNode;

            var force = d3.forceSimulation()
                //.force("link", d3.forceLink().id(function (d) { return d.id }).distance(80))
                .force("link", d3.forceLink().distance(linkDistance).strength(0.1))
                .force("charge", d3.forceManyBody().strength(-100))
                .force("center", d3.forceCenter(window.innerWidth / 2, window.innerHeight / 2))
                .force("collision", d3.forceCollide().radius(90))

            function linkDistance(d) {
                console.log(d.distance)
                return d.distance;
            }


            initialize()

            function initialize() {

                link = linksContainer.selectAll(".link")
                    .data(graph.links)
                    .join("line")
                    .attr("class", "link")
                    .style("stroke", "black")
                    .style("stroke-width", 1)

                node = nodesContainer.selectAll(".node")
                    .data(graph.nodes, d => d.id)
                    .join("g")
                    .attr("class", "node")
                    .call(d3.drag()
                        .on("start", dragStarted)
                        .on("drag", dragged)
                        .on("end", dragEnded)
                    )
                    .on("click", addNode)

                node.selectAll("circle")
                    .data(d => [d])
                    .join("circle")
                    .attr("r", 30)
                    .style("fill", "whitesmoke")

                node.append("text")
                    .attr("dominant-baseline", "central")
                    .attr("text-anchor", "middle")
                    .attr("font-size", 15)
                    .attr("pointer-events", "none")
                    .text(function (d) {
                        return d.id
                    })

                force
                    .nodes(graph.nodes)
                    .on("tick", ticked);

                force
                    .force("link")
                    .links(graph.links)
            }

            function ticked() {
                // update link positions
                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;
                    });

                // update node positions
                node
                    .attr("transform", function (d) {
                        return "translate(" + d.x + ", " + d.y + ")";
                    });
            }

            function dragStarted(event, d) {
                if (!event.active) force.alphaTarget(0.3).restart();
                d.fx = d.x;
                d.fy = d.y;

                PosX = d.x
                PosY = d.y
            }

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

            function dragEnded(event, d) {
                if (!event.active) force.alphaTarget(0);
                d.fx = undefined;
                d.fy = undefined;
            }

            function addNode(event, d) {
                const nodeId = graph.nodes.length

                graph.nodes.push({id: nodeId})
                graph.links.push({source: d, target: nodeId, distance: 1})

                initialize()
            }
        body {
            height: 100%;
            background: #e6e7ee;
            overflow: hidden;
            margin: 0px;
        }

        .faded {][1]
            opacity: 0.1;
            transition: 0.3s opacity;
        }

        .highlight {
            opacity: 1;
        }
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- d3.js framework -->
        <script src="https://d3js.org/d3.v6.js"></script>
        <!-- fontawesome stylesheet https://fontawesome.com/ -->
        <script src="https://kit.fontawesome.com/39094309d6.js" crossorigin="anonymous"></script>
    </head>

    <style>
    </style>

    <body>
        <svg id="svg"></svg>
    </body>

【问题讨论】:

    标签: d3.js


    【解决方案1】:

    distance 函数已正确设置和指定。

    问题来自forceCollide,它设置为半径为 90,无论指定距离如何都会将节点推开。

    减小forceCollide 的半径可以解决问题,如下图所示:)

    var graph = {
                    "nodes": [
                        {
                            "id": 0
                        },
                        {
                            "id": 1
                        },
                        {
                            "id": 2
                        },
                        {
                            "id": 3
                        }
                    ],
                    "links": [
                        {
                            "source": 0,
                            "target": 1,
                            "distance": 0.1
                        },
                        {
                            "source": 0,
                            "target": 2,
                            "distance": 150
                        },
                        {
                            "source": 0,
                            "target": 3,
                            "distance": 20
                        }
                    ]
                }
    
                var svg = d3.select("svg")
                    .attr("class", "canvas")
                    .attr("width", window.innerWidth)
                    .attr("height", window.innerHeight)
                    .call(d3.zoom().on("zoom", function (event) {
                        svg.attr("transform", event.transform)
                    }))
                    .append("g")
    
                var linksContainer = svg.append("g").attr("class", linksContainer)
                var nodesContainer = svg.append("g").attr("class", nodesContainer)
                var sourceNode;
    
                var force = d3.forceSimulation()
                    //.force("link", d3.forceLink().id(function (d) { return d.id }).distance(80))
                    .force("link", d3.forceLink().distance(linkDistance).strength(.1))
                    .force("charge", d3.forceManyBody().strength(-100))
                    .force("center", d3.forceCenter(window.innerWidth / 2, window.innerHeight / 2))
                    .force("collision", d3.forceCollide().radius(9))
    
                function linkDistance(d) {
                    console.log('distance: ', d.distance)
                    return d.distance;
                }
    
    
                initialize()
    
                function initialize() {
    
                    link = linksContainer.selectAll(".link")
                        .data(graph.links)
                        .join("line")
                        .attr("class", "link")
                        .style("stroke", "black")
                        .style("stroke-width", 1)
    
                    node = nodesContainer.selectAll(".node")
                        .data(graph.nodes, d => d.id)
                        .join("g")
                        .attr("class", "node")
                        .call(d3.drag()
                            .on("start", dragStarted)
                            .on("drag", dragged)
                            .on("end", dragEnded)
                        )
                        .on("click", addNode)
    
                    node.selectAll("circle")
                        .data(d => [d])
                        .join("circle")
                        .attr("r", 30)
                        .style("fill", "whitesmoke")
    
                    node.append("text")
                        .attr("dominant-baseline", "central")
                        .attr("text-anchor", "middle")
                        .attr("font-size", 15)
                        .attr("pointer-events", "none")
                        .text(function (d) {
                            return d.id
                        })
    
                    force
                        .nodes(graph.nodes)
                        .on("tick", ticked);
    
                    force
                        .force("link")
                        .links(graph.links)
                }
    
                function ticked() {
                    // update link positions
                    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;
                        });
    
                    // update node positions
                    node
                        .attr("transform", function (d) {
                            return "translate(" + d.x + ", " + d.y + ")";
                        });
                }
    
                function dragStarted(event, d) {
                    if (!event.active) force.alphaTarget(0.3).restart();
                    d.fx = d.x;
                    d.fy = d.y;
    
                    PosX = d.x
                    PosY = d.y
                }
    
                function dragged(event, d) {
                    d.fx = event.x;
                    d.fy = event.y;
                }
    
                function dragEnded(event, d) {
                    if (!event.active) force.alphaTarget(0);
                    d.fx = undefined;
                    d.fy = undefined;
                }
    
                function addNode(event, d) {
                    const nodeId = graph.nodes.length
    
                    graph.nodes.push({id: nodeId})
                    graph.links.push({source: d, target: nodeId, distance: 1})
    
                    initialize()
                }
    body {
        height: 100%;
        background: #e6e7ee;
        overflow: hidden;
        margin: 0px;
    }
    
    .faded {][1]
        opacity: 0.1;
        transition: 0.3s opacity;
    }
    
    .highlight {
        opacity: 1;
    }
    <!-- d3.js framework -->
    <script src="https://d3js.org/d3.v6.js"></script>
    <!-- fontawesome stylesheet https://fontawesome.com/ -->
    <script src="https://kit.fontawesome.com/39094309d6.js" crossorigin="anonymous"></script>
    <svg id="svg"></svg>

    【讨论】:

      猜你喜欢
      • 2017-04-13
      • 2012-10-11
      • 1970-01-01
      • 2013-05-10
      • 1970-01-01
      • 2016-11-10
      • 1970-01-01
      • 2017-01-07
      • 1970-01-01
      相关资源
      最近更新 更多