最靠谱的弦图实现方案是d3.js(v6/v7),需用svg容器、方阵数据格式,经d3.chord()转换后由d3.ribbon()和d3.arc()渲染;预处理须构建索引映射并合并重复项,着色应基于source.name而非index或value,响应式需靠viewbox而非动态resize重绘。

Chord diagram 用 D3.js 实现最靠谱
纯 HTML/CSS 做不出真正的弦图(chord diagram),它本质是 SVG 图形 + 数据驱动的弧线与连线计算。浏览器里能稳定落地的方案只有 D3.js(v6/v7),其他库如 Chart.js、ECharts 都不原生支持 chord diagram。
关键不是“怎么画线条”,而是怎么把矩阵数据转成 d3.chord() 能吃的格式,再喂给 d3.ribbon() 和 d3.arc() 渲染。
- 必须用
<svg></svg>容器,不能靠 div + border-radius 模拟 - 数据得是方阵:行和列代表同一组实体(比如国家→国家贸易额),
matrix[i][j]表示从 i 到 j 的流向值 - 别直接传原始数值——
d3.chord()内部会自动归一化角度,但要求所有值 ≥ 0
数据预处理最容易卡在 matrix 格式上
常见错误是把 CSV 或 JSON 扁平列表(如 [{from:"A",to:"B",value:12}])直接塞进 d3.chord(),结果渲染空白或报 Cannot read property 'length' of undefined。
正确做法是先生成索引映射,再填方阵:
const names = ["A", "B", "C"]; const matrix = Array(names.length).fill().map(() => Array(names.length).fill(0)); // 填值:A→B 是 12,就 matrix[0][1] = 12; // 注意:chord diagram 默认显示双向,若只要单向,另一侧留 0
如果原始数据含重复关系(比如 A→B 出现多次),务必先 reduce 合并;否则 d3.chord(matrix) 会把每个重复项当独立扇区,角度炸开。
ribbon 连线颜色不跟着 source 走?检查 fill 属性绑定逻辑
默认 chord diagram 的连线(ribbon)颜色由 source 扇区决定,但很多人写成 .attr("fill", d => color(d.source.index)),结果所有 ribbon 都一个色——因为 d.source 和 d.target 是对象,不是原始索引。
正确取色方式:
.attr("fill", d => color(names[d.source.index])) // 用 names 数组查名
// 或更稳一点:
.attr("fill", d => color(d.source.name || names[d.source.index]))
- 别用
d.source.value上色——那是流向值,不是分类标识 - 如果用了
d3.chord().padAngle(0.02),记得同步调大arc的内半径,否则 ribbon 两端悬空 - 鼠标悬停高亮时,推荐同时过渡 source arc、target arc 和 ribbon,用
d3.transition().duration(300)统一控制
响应式缩放时 chord 图变形?svg viewBox 是关键
直接设 svg.style("width", "100%") 会导致 chord 弧线被拉伸,因为默认 preserveAspectRatio="xMidYMid meet" 在宽高比变化时会裁剪。
解法是固定 viewBox 并让 svg 自适应容器:
const width = 600, height = 600, radius = Math.min(width, height) / 2;
svg.attr("viewBox", `0 0 ${width} ${height}`)
.style("width", "100%")
.style("height", "auto");
后续所有坐标(arc.centroid()、ribbon.centroid())都基于这个 radius 计算,不要用 getBoundingClientRect() 动态读宽高——D3 的比例尺和路径生成器依赖静态尺寸。
真要适配移动端,建议在 CSS 里用 @media 控制 width,而不是在 JS 里监听 resize 重绘——chord diagram 的 layout 计算开销不小,频繁重算会卡顿。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











