D3 Sankey图表自定义:如何调整节点高度并实现节点垂直居中
D3 Sankey 图表自定义节点高度+垂直居中实现方案
实现逻辑
D3 的 sankey 布局默认会根据节点流量权重自动计算节点高度,要实现需求可以按以下步骤操作:
- 覆盖节点高度默认计算逻辑,自定义节点高度规则(固定高度或自定义权重计算均可)
- 将同列节点分组,基于画布可用高度计算顶部偏移量,实现整列节点垂直居中
- 同步更新链路坐标,保证链路和节点正确衔接
核心代码示例
// 依赖版本建议d3-sankey v7+ import { sankey, sankeyLinkHorizontal } from 'd3-sankey'; // 基础配置可按需调整 const width = 800; const height = 500; const CUSTOM_NODE_HEIGHT = 30; // 自定义节点固定高度 const NODE_PADDING = 15; // 节点垂直间距 // 初始化sankey布局实例 const sankeyInstance = sankey() .nodeWidth(20) .nodePadding(NODE_PADDING) .extent([[20, 20], [width - 20, height - 20]]); // 传入原始节点、链路数据生成初始布局 const layoutData = sankeyInstance({ nodes: yourNodeData, links: yourLinkData }); // 按x坐标把节点分到对应列 const columnGroups = {}; layoutData.nodes.forEach(node => { const columnKey = node.x0; if (!columnGroups[columnKey]) columnGroups[columnKey] = []; columnGroups[columnKey].push(node); }); // 逐列调整节点位置 Object.values(columnGroups).forEach(columnNodes => { // 计算当前列所有节点+间距的总高度 const totalColumnContentHeight = columnNodes.length * CUSTOM_NODE_HEIGHT + NODE_PADDING * (columnNodes.length - 1); // 计算垂直居中需要的顶部偏移 const availableHeight = sankeyInstance.extent()[1][1] - sankeyInstance.extent()[0][1]; const topOffset = (availableHeight - totalColumnContentHeight) / 2; // 重写每个节点的y坐标和高度 columnNodes.forEach((node, index) => { node.y0 = topOffset + index * (CUSTOM_NODE_HEIGHT + NODE_PADDING); node.y1 = node.y0 + CUSTOM_NODE_HEIGHT; }); }); // 更新链路布局适配新节点位置 sankeyInstance.update(layoutData); // 后续渲染节点示例 svg.selectAll('.sankey-node') .data(layoutData.nodes) .join('rect') .attr('class', 'sankey-node') .attr('x', d => d.x0) .attr('y', d => d.y0) .attr('width', d => d.x1 - d.x0) .attr('height', d => d.y1 - d.y0) .attr('fill', '#2196F3'); // 后续渲染链路示例 svg.selectAll('.sankey-link') .data(layoutData.links) .join('path') .attr('class', 'sankey-link') .attr('d', sankeyLinkHorizontal()) .attr('fill', 'none') .attr('stroke', '#90CAF9') .attr('stroke-opacity', 0.5) .attr('stroke-width', d => Math.max(1, d.width));
效果对比
默认D3 Sankey图表效果:
调整后目标效果:
注意事项
- 如果需要非固定的自定义节点高度,只需要修改
CUSTOM_NODE_HEIGHT的计算逻辑,按规则给每个节点设置不同的y1 - y0差值即可。 - 如果你使用的是v4/v5版本的旧版d3-sankey,没有内置的
update方法,可以手动遍历链路调整坐标:每个链路的y0设置为源节点的垂直中间位置加上对应流量的偏移,y1设置为目标节点的垂直中间位置加上对应流量的偏移即可。
内容的提问来源于stack exchange,提问作者Руслан Більмаковський
相关产品推荐
相关产品推荐

