D3.js 基础与平行桑基图
1. D3.js 是什么
D3.js(Data-Driven Documents)是一个面向 数据可视化 的前端库,核心能力是:
- 通过数据驱动 DOM / SVG 更新
- 适合做高自由度自定义图表
- 支持动画、交互、布局计算、颜色映射等
和 ECharts 这类图表库不同,D3.js 更像是底层绘图工具箱,适合:
- 标准图表库不容易实现的图
- 图形结构复杂、交互复杂的场景
- 需要精细控制布局和渲染细节的业务图表
2. 基础安装与引入
2.1 安装
|
|
2.2 在 Vue + TS 中引入
|
|
3. D3.js 的基础使用
D3 最核心的思想是:先计算数据与布局,再把结果映射到 SVG 图形上。
常见开发流程:
- 准备容器
- 获取尺寸
- 绑定数据
- 计算坐标 / 路径 / 颜色
- 渲染图形
- 绑定交互
3.1 选择元素
|
|
常见 API:
d3.select():选中单个元素d3.selectAll():选中多个元素.append():追加元素.attr():设置属性.style():设置样式.text():设置文本
3.2 数据绑定
|
|
常用概念:
.data(data):绑定数据.enter():处理新增元素.exit():处理删除元素.join():统一处理增删改
3.3 比例尺(Scale)
比例尺用于把数据值转成像素值。
常见类型:
d3.scaleLinear():线性映射d3.scaleBand():分类轴d3.scaleOrdinal():离散映射,常用于颜色d3.scaleTime():时间轴
示例:
|
|
3.4 坐标轴
|
|
常见坐标轴:
d3.axisBottom()d3.axisTop()d3.axisLeft()d3.axisRight()
3.5 路径生成
如果图表不是简单矩形,而是折线、面积、弧线、流带,通常会使用路径。
常见工具:
d3.line()d3.area()d3.arc()
平行桑基图,使用的是 自定义 SVG path + 贝塞尔曲线 的方式绘制流带。
4. D3.js 图表常见配置项
D3 本身没有统一 option,但在业务里通常会把影响图形展示的参数整理成配置对象。
4.1 尺寸与边距
|
|
常见作用:
- 给图例、标签、列名预留空间
- 避免图形贴边
4.2 颜色相关
|
|
说明:
colorMap:分类值到颜色的映射paletteColors:默认调色板fontColor:文字颜色borderColor / borderWidth:边框控制
4.3 图例相关
|
|
说明:
- 是否显示图例
- 图例在顶部还是底部
- 左对齐 / 居中 / 右对齐
- 图例文本与颜色
4.4 文本标签相关
|
|
说明:
show:是否显示标签position:左 / 中 / 右overlap:是否允许重叠fontSize/color:样式控制markArray:动态字段定义stateDocHtml:富文本模板
4.5 Tooltip 相关
|
|
说明:
- 支持动态字段展示
- 支持富文本模板替换
- 支持字段别名映射
4.6 图形结构相关
|
|
说明:
curveness:曲线弯曲程度gapRatio:节点之间的间距比例bandOpacity:流带透明度
5. 如何用 D3.js 绘制图表
无论是柱状图、折线图还是桑基图,思路基本一致。
5.1 准备容器
|
|
5.2 获取容器尺寸
|
|
5.3 计算绘图区
|
|
5.4 清空旧图重绘
|
|
5.5 计算布局
布局计算通常包括:
- 节点位置
- 宽高分配
- 路径控制点
- 颜色映射
- 标签位置
5.6 绘制图形元素
常见元素:
rectcirclelinepathtextg
5.7 绑定交互
|
|
5.8 监听变化并自动重绘
|
|
|
|
6. 平行桑基图是什么
本质上是一个 基于 D3 + SVG 实现的 Parallel Sets(平行集图)。
它和传统桑基图类似,但更强调:
- 每一列是一个维度
- 每一列中有多个分类值节点
- 相邻列之间通过流带展示流向关系
- 流带颜色由
colorKey区分
支持:
- 多列维度流向展示
- 颜色分类
- 图例
- Tooltip
- 富文本标签
- Hover 联动高亮
- 点击与右键联动
- 容器 resize 自动重绘
7. 平行桑基图输入结构
核心入参是 props.chartData。
7.1 rows
|
|
含义:
dimensionList:该行经过的各个维度值value:这条路径的数量colorKey:分类颜色键dynamicTooltipValue:Tooltip 附加字段
7.2 columns
|
|
含义:
- 定义每一列代表哪个维度
name用于底部列名渲染
8. 平行桑基图绘制流程
draw() 基本可以拆成以下几个阶段。
8.1 初始化和尺寸计算
主要完成:
- 读取
rows、columns - 读取图例与样式配置
- 获取容器宽高
- 计算绘图区坐标
- 计算每列 X 坐标
重点变量:
svgW/svgHplotTop/plotBottomplotLeft/plotRightcolX
8.2 按列统计节点总量
通过以下结构记录各列数据:
colTotals:每列每个节点值的总量colOrder:首次出现顺序nodeFieldValMap:节点对应字段值映射
这一步的作用是:
- 计算节点高度
- 支撑排序
- 支撑标签字段替换
8.3 为每列节点计算纵向区间
通过 colBandMaps 为每个节点值计算:
y0y1
这表示节点在该列里占据的垂直区间。
这一步很关键,因为后续流带的上下边界都依赖它。
8.4 颜色映射计算
通过:
rowColorKeysallColorKeysrowColors
完成每条路径的颜色归属。
作用:
- 保证相同分类颜色一致
- 支撑图例显示
- 支撑 hover 高亮分组
8.5 构建 flow 数据
最终把中间计算结果整理成 flows,每一项代表一段流带。
核心字段有:
|
|
这些字段控制了:
- 流带从哪一列连到哪一列
- 从哪个值流向哪个值
- 上下边界坐标
- 流带颜色和透明度
- hover 联动路径
- tooltip 扩展内容
8.6 解决跨列连续对齐
核心思路:
- 每列每个节点内部,按
colorKey分配固定偏移区间 - source 端和 target 端尽量保持堆叠顺序一致
- 使用上一段的 target 位置,辅助下一段的 source 排序
- 尽量减少交叉、保证路径连续
这部分主要依赖:
nodeColorOffsetprevTy0ByFlownextTy0ByFlow
这样做的效果是:
- 流带更平滑
- 同一路径视觉更连续
- 不同颜色分类更稳定
- 图更容易读
9. 流带是怎么画出来的
流带用自定义 path 拼出来的。
核心逻辑:
|
|
含义:
- 从 source 上边界开始
- 用贝塞尔曲线连接到 target 上边界
- 再连到 target 下边界
- 再用另一条贝塞尔曲线回到 source 下边界
- 最终闭合为一个带状区域
而 curveness 会决定控制点位置:
|
|
也就是:
curveness越小,越接近直线curveness越大,曲线越柔和
10. 组件交互设计
10.1 Hover 高亮
通过 pathKey 做了路径级别联动:
- hover 当前流带时,不只高亮这一段
- 同一路径的其他段也会一起高亮
- 非相关流带降低透明度
这比单段高亮更符合平行集图的阅读习惯。
10.2 Tooltip 跟随鼠标
通过:
mouseentermousemovemouseleave
控制 tooltip 的显示、位置更新和隐藏。
10.3 Click 联动
点击流带时会:
- 找到匹配的原始数据行
- 收集
dimensionList中的字段值 - 通过
emit('click', valueObj)抛给外层
这很适合做图表联动筛选。
10.4 右键菜单
实现了:
|
|
这样外层就可以基于点击位置弹出菜单,例如:
- 查看明细
- 跳转页面
- 追加筛选条件
11. 标签实现方式
这一部分做得也很完整。
11.1 普通文本标签
普通标签使用 SVG text 绘制,适合:
- 纯文本
- 样式简单
- 性能要求更高
11.2 富文本标签
富文本标签没有直接画进 SVG,而是放到了覆盖层:
ps-rich-labels-layerps-rich-label
这样做的优点:
- 不受 SVG
overflow限制 - 更容易支持 HTML 富文本
- 更容易兼容编辑器输出内容
11.3 标签配置能力
当前支持:
- 是否显示标签
- 左 / 中 / 右位置
- 是否允许重叠
- 字号与颜色
- 动态字段占位
- ProseMirror / HTML 模板替换
这已经属于比较完整的标签系统了。
12. Tooltip 实现方式
Tooltip 分成两种模式:
12.1 默认模式
展示:
sourceValue -> targetValue- 分类
colorKey - 数值
value
12.2 自定义字段模式
如果配置了 tooltipConfig.markArray,则会:
- 从
dynamicTooltipValue里取字段值 - 按字段配置格式化
- 支持富文本模板
prosemirrorDOM
也就是说,Tooltip 已经不是静态提示,而是一个可配置的业务信息面板。
15. 总结
从项目角度看,D3.js 的意义主要在于:
- 适合复杂自定义图表
- 能精细控制布局和交互
- 能很好地和 Vue 组件化结合
平行桑基图实现,具备完整业务组件能力,覆盖了:
- 数据聚合
- 列节点布局
- 流带路径计算
- 图例渲染
- 标签渲染
- Tooltip 渲染
- Hover / Click / 右键联动
- Resize 自适应