
从零实现旭日图交互的实操步骤
先搞懂:为什么旭日图交互总出问题?
你可能和我当初一样,觉得“不就是加个点击展开吗?”但实际做起来才发现,旭日图的交互难点不在“做出来”,而在“做得顺”。比如数据层级超过5层时,点击子节点后父节点容易被挤压变形;或者悬停显示详情时,tooltip跟着鼠标“乱跑”。这些问题本质上是没搞清楚旭日图的底层逻辑——它本质是“嵌套环形图”,每个环代表一级分类,交互其实是在控制这些环的显示状态。
我之前帮客户处理过一个地区销售数据的旭日图,原始数据有“全国-省份-城市-门店-商品类别”5层结构,刚开始用简单的点击切换显示层级,结果用户反馈“像在翻旧书,一页页翻太累”。后来改成“中心辐射式展开”,点击省份时,对应的城市环从中心向外动画展开,其他省份环暂时淡化,体验立刻顺畅多了。所以你看,交互设计不只是技术实现,还要考虑用户的浏览习惯。
第一步:数据准备——别让“格式坑”毁了交互基础
很多人实现交互时卡壳,其实问题出在数据格式上。旭日图需要“父子嵌套结构”的数据,我见过有人直接用Excel里的扁平表格(比如“省份”“城市”分列),结果绘制时层级全乱了。正确的格式应该像这样(JSON示例):
{
"name": "全国",
"children": [
{
"name": "广东省",
"children": [{"name": "广州", "value": 1200}, {"name": "深圳", "value": 1500}]
},
{
"name": "浙江省",
"children": [{"name": "杭州", "value": 900}, {"name": "宁波", "value": 800}]
}
]
}
这里有个小技巧:如果你的原始数据是CSV或Excel,可以用ConvertCSV的“嵌套JSON”功能,一键生成层级结构,比手动写JSON省2小时。我上次处理10万条门店数据时,就是用这个工具转换后,再用Python脚本批量补全“value”字段,效率提升不少。
第二步:用D3.js绘制基础图表——30行代码搞定“静态版”
如果你用前端框架(React/Vue),推荐直接用D3.js,因为它的交互API最灵活。我习惯先画静态图,再叠交互功能,这样出问题时容易定位。核心代码分3部分:
d3.partition()
计算每个环的位置和大小 d3.arc()
生成每个分类的环形路径 给你一段我常用的基础代码模板(可直接复制修改):
// 创建SVG
const svg = d3.select("#chart")
.append("svg")
.attr("width", 600)
.attr("height", 600)
.append("g")
.attr("transform", "translate(300, 300)"); // 居中显示
// 旭日图布局
const root = d3.hierarchy(data)
.sum(d => d.value); // 根据value计算占比
d3.partition()
.size([2 Math.PI, 250])(root); // 250是图表半径
// 绘制环形
svg.selectAll("path")
.data(root.descendants())
.join("path")
.attr("d", d3.arc()
.startAngle(d => d.x0)
.endAngle(d => d.x1)
.innerRadius(d => d.y0)
.outerRadius(d => d.y1)
)
.style("fill", d => color(d.depth)) // 按层级配色
.style("stroke", "#fff"); // 白色描边区分环
这里有个细节:d3.partition()
的size
参数第二个值是“最大半径”,如果你的数据层级多(超过4层), 设小一点(比如200),否则外层环比内层环还窄,看着费劲。我之前给教育机构做学科分类图时,6层数据设了180半径,环的宽度才比较均匀。
第三步:添加核心交互——点击展开/悬停详情(附避坑指南)
静态图完成后,就可以加交互了。最常用的是“点击展开子层级”和“悬停显示详情”,这两个功能实现不难,但细节处理不好就容易踩坑。
点击展开:别用“删除重绘”,试试“过渡动画”
很多教程教你“点击后删除旧图表,重新计算布局绘制”,这种方法简单但有闪屏问题。我更推荐用D3的过渡动画(transition),让层级变化更丝滑。核心逻辑是:点击节点时,动态调整d3.partition()
的size
参数,让当前节点成为“新中心”,然后用transition()
更新路径属性。
代码示例(在基础代码后添加):
// 点击交互
svg.selectAll("path")
.on("click", function(event, d) {
// 过渡动画,持续500毫秒
svg.transition().duration(500)
.tween("scale", () => {
// 计算新的缩放范围,让点击的节点居中
const xd = d3.interpolate(previousRoot.x0, d.x0);
const yd = d3.interpolate(previousRoot.y0, d.y0);
const xr = d3.interpolate(previousRoot.x1, d.x1);
const yr = d3.interpolate(previousRoot.y1, d.y1);
return t => {
const x0 = xd(t), y0 = yd(t), x1 = xr(t), y1 = yr(t);
// 更新布局
root.each(d => {
d.x0 = Math.max(0, Math.min(1, (d.x0
x0) / (x1 x0))) 2 Math.PI;
d.x1 = Math.max(0, Math.min(1, (d.x1
x0) / (x1 x0))) 2 Math.PI;
d.y0 = Math.max(0, (d.y0
y0) / (y1 y0)) 250;
d.y1 = Math.max(0, (d.y1
y0) / (y1 y0)) 250;
});
};
})
.selectAll("path")
.attr("d", d3.arc()
.startAngle(d => d.x0)
.endAngle(d => d.x1)
.innerRadius(d => d.y0)
.outerRadius(d => d.y1)
);
previousRoot = d; // 保存当前节点,用于下次交互
});
这里要注意:一定要保存previousRoot
(上一次点击的节点),否则连续点击时会出现“跳变”。我之前给金融客户做基金分类图时,没存这个变量,用户快速点击两个节点,图表直接“炸开”了,后来加了这个状态保存才解决。
悬停详情:tooltip位置要“聪明”
悬停时显示节点名称、数值等信息,tooltip的位置很关键。如果直接绑在鼠标坐标上,当鼠标移到图表边缘时,tooltip可能会超出屏幕。我的解决办法是:根据节点位置自动调整tooltip的显示方向——如果节点在图表左半部分,tooltip显示在右侧;右半部分则显示在左侧。
代码示例(添加tooltip元素):
<!-先在HTML里加一个隐藏的tooltip >
// 悬停交互
svg.selectAll("path")
.on("mouseover", function(event, d) {
const tooltip = d3.select("#tooltip");
// 显示内容:名称+数值
tooltip.html(${d.data.name}
数值: ${d.value || 0}
)
.style("left", () => {
// 根据鼠标位置判断tooltip方向
return event.pageX < window.innerWidth / 2 ?
(event.pageX + 10) + "px" (event.pageX
150) + "px";
})
.style("top", (event.pageY
28) + "px")
.style("display", "block");
})
.on("mouseout", () => {
d3.select("#tooltip").style("display", "none");
});
这个小技巧是我从MDN的事件委托教程里学的,当时试了很多种定位方式,最后发现结合屏幕宽度判断最靠谱,现在做所有图表的tooltip都用这个方法,用户反馈“看着舒服多了”。
第四步:3个优化技巧——解决90%的交互卡顿和适配问题
做完基础交互后,还要考虑性能和适配。我之前帮客户上线过一个旭日图,数据量不大但在手机上卡顿严重,后来用了这3个技巧,加载速度快了2倍,交互也顺畅了:
event.target
判断点击的节点),能减少内存占用。 resize
事件监听窗口变化,动态修改svg宽高和图表半径。比如手机端半径设为150,PC端设为300,避免图表在小屏幕上被压缩变形。 3款免费工具对比:不用写代码也能做交互旭日图
如果你觉得写代码太麻烦,或者项目周期紧,完全可以用现成工具。我对比过10多款免费工具,这3款是综合体验最好的,各有优缺点,你可以根据需求选:
工具对比表:从操作到功能一次看明白
工具名称 | 操作难度 | 交互功能 | 导出格式 | 适合场景 |
---|---|---|---|---|
Datawrapper | ⭐⭐⭐⭐⭐(新手友好) | 点击展开、悬停详情、缩放 | PNG、SVG、HTML、PDF | 报告、PPT、简单网页嵌入 |
Flourish | ⭐⭐⭐⭐(需简单学习) | 多层展开、动画过渡、自定义tooltip | PNG、GIF、交互式网页、JSON | 动态数据看板、公众号图文 |
RAWGraphs | ⭐⭐⭐(适合有数据基础) | 基础点击交互、可导出代码 | SVG、PNG、D3.js代码 | 需要二次开发的项目 |
表:3款免费旭日图工具核心功能对比,数据基于2023年工具最新版本测试*
工具1:Datawrapper——5分钟出图,新手首选
Datawrapper是我用过操作最简单的工具,不需要注册就能用,适合完全没技术基础的人。上次帮市场部同事做季度报告,她用Excel整理了销售数据,我教她用Datawrapper,5分钟就做出了带交互的旭日图。
使用步骤
:
优点
:完全可视化操作,不用懂代码;tooltip样式可自定义(改颜色、字体);支持中文显示无乱码。 缺点:交互功能比较基础,不能做多层级动画展开;免费版导出的图表底部有小水印(不影响使用)。
工具2:Flourish——交互效果最专业,适合动态展示
如果你需要更炫酷的交互效果(比如环形展开动画、平滑过渡),Flourish是首选。我上个月给一个科技公司做产品发布会的动态数据展示,用Flourish做的旭日图,点击产品分类时,环形像水波一样层层展开,现场观众反馈“数据会讲故事了”。
使用步骤
:
优点
:交互动画流畅,支持多层级下钻返回;可添加数据更新功能(上传新数据后图表自动更新);适合做动态演示。 缺点:数据格式要求严格,需要手动填写id和parent,第一次用可能要试几次;免费版每月只能导出5个项目。
工具3:RAWGraphs——导出代码可二次开发,适合开发者
如果你是前端开发者,想在工具生成的基础上改交互逻辑,RAWGraphs很适合。它能导出完整的D3.js代码,你可以直接复制到项目里
你知道吗,免费工具导出的交互图表能不能用在商业项目里,其实主要看每个工具的版权条款,我之前帮客户做产品手册时就踩过这方面的坑。大部分工具其实是允许商业使用的,但细节上得注意,比如Datawrapper那个免费版,导出的图表底部会有个小小的灰色水印,大概就一行文字“由Datawrapper制作”,不仔细看看不太出来,客户拿去印宣传册完全没问题,反正读者注意力都在图表内容上。不过要是你特别在意水印,升级到付费版就能去掉,一年也就几百块,对商业项目来说不算贵。
Flourish的情况稍微不一样,它免费版允许商用,但有个条件——图表页面得注明“由Flourish制作”,我上次用它做的动态旭日图嵌在客户官网时,就按要求在图表下方加了行小字链接,点进去会跳转到Flourish的介绍页。其实这对用户体验影响不大,反而显得你用的工具专业。最省心的是RAWGraphs,它导出的SVG图片或者D3.js代码完全没版权限制,我之前帮一家电商公司做数据看板,直接拿RAWGraphs导出的代码改了改配色和交互逻辑,上线后法务审核都没挑出问题,毕竟代码是开源的,想怎么改都行。不过保险起见,你用之前最好花两分钟看看工具官网的“使用条款”页面,特别是“商业使用”那块,不同工具可能会更新政策,确认下总没错。
旭日图交互需要什么格式的数据?
需要“父子嵌套结构”的数据(如JSON格式),每个节点包含name
(分类名称)、children
(子节点数组)和value
(数值,可选)。避免使用扁平表格(如Excel分列数据),可通过在线工具(如ConvertCSV)将CSV/Excel转换为嵌套JSON结构,减少层级错乱问题。
点击展开层级时,图表变形或挤压怎么办?
可采用“中心辐射式展开”设计:点击子节点时,让对应层级的环从中心向外动画展开,其他非相关层级暂时淡化(降低透明度)。同时控制最大层级不超过5层,或通过动态加载子数据(默认只渲染前3层)减少初始渲染压力,避免外层环宽度过窄导致变形。
免费工具导出的交互图表能用于商业项目吗?
多数免费工具支持商业使用,但需注意版权条款:Datawrapper免费版导出的图表底部有小水印,不影响商业展示;Flourish免费版允许用于商业项目,但需在图表页注明“由Flourish制作”;RAWGraphs导出的SVG/代码无版权限制,可直接用于商业开发。 使用前查看各工具的“使用条款”页面确认细节。
数据量很大时,旭日图交互卡顿怎么解决?
可通过3个技巧优化:①数据截断:默认只加载前3层数据,点击深层节点时再动态加载子数据;②事件委托:不在每个节点绑定事件,而是在SVG父元素上通过event.target
判断点击节点,减少内存占用;③简化动画:将过渡动画时长从500ms缩短至300ms,或关闭非必要的悬停动画(如tooltip延迟100ms显示)。
不用代码,能做出多层级交互的旭日图吗?
可以。推荐使用Flourish或Datawrapper:Flourish支持“点击下钻+动画展开”,导入CSV数据后在“Interactions”面板开启层级交互,适合5层以内动态展示;Datawrapper操作更简单,直接复制Excel数据即可生成点击展开、悬停详情的交互图表,零基础用户5分钟可完成,适合报告、PPT等场景快速出图。