You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在D3.js中独立设置连线的起点与终点位置?

解决方法

要让连线从盒子右侧出发,连接到子盒子的左侧,你可以直接为连线的起点(源节点)和终点(目标节点)定义不同坐标,替代统一的x()和y()方法:

修改连线部分的代码:

svg.append('g') // link
    .attr('fill', 'none')
    .attr('stroke', 'black')
    .attr('stroke-width', 0.1)
    .selectAll()
    .data(root.links())
    .join('path')
    .attr('d', d3.linkHorizontal()
        // 起点:源节点盒子的右侧(x坐标加上盒子宽度)
        .source(d => [d.source.depth * box_spacing + box_width, d.source.data.y])
        // 终点:目标节点盒子的左侧(使用原始x坐标)
        .target(d => [d.target.depth * box_spacing, d.target.data.y])
    );

原理说明

  • d3.linkHorizontal()的source()和target()方法可接收每个连线对象(包含source父节点和target子节点),直接返回对应点的[x, y]坐标数组。
  • 源节点起点偏移盒子宽度(box_width),对应盒子右侧边缘;目标节点直接使用原始x坐标,对应盒子左侧边缘。

修改后的完整代码:

<!DOCTYPE html>
<div id="container"></div>
<script type="module">
import * as d3 from 'https://cdn.jsdelivr.net/npm/d3@7/+esm';

const data = { name: 'a', y: 2, children: [
    { name: 'b', y: 1 },
    { name: 'c', y: 3, children: [
        { name: 'd', y: 2 },
        { name: 'e', y: 4 },
    ]}
]}

const root = d3.hierarchy(data);
const width = 400;
const height = 200;
const box_width = 3;
const box_spacing = 5;

const svg = d3.create('svg')
            .attr('width', width)
            .attr('height', height)
            .attr('viewBox', [0, 0, 20, 10])
            .attr('style', 'max-width: 100%; height: auto; font: 1px mono;');

const node = svg.append('g')
    .selectAll()
    .data(root.descendants())
    .join('g')
    .attr('transform', (d) => `translate(${d.depth * box_spacing},${d.data.y})`);

node.append('rect')
    .attr('width', box_width)
    .attr('height', 1)
    .attr('fill', '#ccc')
    .attr('y', -0.5);

node.append('text')
    .text((d) => d.data.name)
    .attr('y', 0.4);

svg.append('g') // link
    .attr('fill', 'none')
    .attr('stroke', 'black')
    .attr('stroke-width', 0.1)
    .selectAll()
    .data(root.links())
    .join('path')
    .attr('d', d3.linkHorizontal()
        .source(d => [d.source.depth * box_spacing + box_width, d.source.data.y])
        .target(d => [d.target.depth * box_spacing, d.target.data.y])
    );

container.append(svg.node());
</script>

内容的提问来源于stack exchange,提问作者roipoussiere

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 17:42:46