Foreword:
In the case of graphics used in our project, the Sanchi diagram is considered an unpopular graphic, but it can meet our needs for a better display of the data flow between multi-level data. For example, in our actual data flow, there is a 1-to-many , in the case of many-to-many, it is inappropriate to use tree. If we use mind map, we can only display the lines, which cannot meet our needs for data visualization.
Realization effect:
Implementation code:
1. Initialization calling method
echarts mount click event: radarChart.getZr().on
echarts automatically adapts to changes in the interface: window.onresize
Source code:
let chartDom = document.getElementById("radar")
let radarChart = echarts.init(chartDom)
//配置属性值
radarChart.setOption(option.value)
//挂载点击事件
radarChart.getZr().on("click", event=> {
// 第三层文字点击事件
if (event.topTarget?.type === "tspan") {
const text = event.topTarget.style.text
if(text.indexOf('/') !== -1){
console.log(event);
console.log(text);
}
}
})
//让echarts随着界面的变动自动适应
window.onresize = () => {
radarEcharts.resize()
}
2. Configuration properties
Note 1: echarts generally uses the grid method to add padding, which is invalid in Sanchi diagrams.
grid: { top: "0", left: "10%", right: "10%", bottom: "0", containLabel: true, }// Special method to add padding in Sanghi diagram
series: { type: "sankey", top: "1%", // distance on distance bottom: "1%", // Distance to the bottom left: "0", // Distance to the left right: "16.5%" , // Follow the right distance
...
Note 2: The text content in the Sanchi diagram can be customized, but the layout is fixed and the generation distance will not be customized.
Note 3: The data of the Sanghi diagram uses the depth field to control which layer it is.
Source code:
option.value = {
tooltip: {
trigger: "item",
triggerOn: "mousemove",
rich: {
"a": {
"fontSize": 14,
"fontWeight": 500,
'color':'#fff',
padding: [0, 0, 5, 0],
}
},
// 鼠标滑上去的展示信息
formatter: function(params) {
if (params.data.source) {
return `${params.data.source}-${params.data.target}:${params.data.value}`;
} else {
return `${params.name}:${params.value}`;
}
}
},
series: {
type: "sankey",
layout: "none",
top: "1%",
bottom: "1%",
left: "0",
right: "16.5%",
draggable: false,
focusNodeAdjacency: 'allEdges', // 鼠标划上时高亮的节点和连线,allEdges表示鼠标划到节点上点亮节点上的连线及连线对应的节点
lineStyle: {
opacity: 0.3,
color: "gradient",
curveness: 0.7,
},
label: {
color: "#000",
fontSize: 15,
formatter: function (params) {
// 一级 硕士研究生 博士研究生
if(params.data.depth === 0 && params.data.name==='本科生') return "{a|" + params.data.name + "\n}" +"{b|" + params.data.value+ "}";
if(params.data.depth === 0 && params.data.name==='硕士研究生') return "{a2|" + params.data.name + "\n}" +"{b2|" + params.data.value+ "}";
if(params.data.depth === 0 && params.data.name==='博士研究生') return "{a3|" + params.data.name + "\n}" +"{b3|" + params.data.value+ "}";
// 二级
if(params.data.depth === 1) return "{c|" + params.data.name + "}" +"{d|" + params.data.value+ "}";
// 三级
if(params.data.depth === 2){
let str = ''
params.data.typeArr.forEach(item=>{
// str += "{e|" + params.data.name + "/"+ item.typeName +"\n}"+"{f|" + item.value+ "\n}"
str += "{m|" + params.data.name + "/"+ item.typeName +"}"+"{n|" + item.value+ "\n}"
})
return str;
}
},
rich: {
"a": {
"fontSize": 14,
"fontWeight": 500,
'color':'#7BA2DF',
padding: [0, 0, 5, 0],
},
"b": {
"fontSize": 24,
"fontWeight": 600,
'color':'#7BA2DF',
padding: [0, 0, 0, 0],
},
"a2": {
"fontSize": 14,
"fontWeight": 500,
'color':'#BA86ED',
padding: [0, 0, 5, 0],
},
"b2": {
"fontSize": 24,
"fontWeight": 600,
'color':'#BA86ED',
padding: [0, 0, 0, 0],
},
"a3": {
"fontSize": 14,
"fontWeight": 500,
'color':'#59DEC6',
padding: [0, 0, 5, 0],
},
"b3": {
"fontSize": 24,
"fontWeight": 600,
'color':'#59DEC6',
padding: [0, 0, 0, 0],
},
"c": {
"fontSize": 16,
"color": "#332D2D",
"lineHeight": 20,
},
"d": {
"fontSize": 16,
"fontWeight": 600,
"lineHeight": 20,
"color": "#332D2D ",
padding: [0, 0, 0, 2],
},
"e": {
"fontSize": 14,
"fontWeight": 500,
'color':'#332D2D',
padding: [0, 0, 5, 0],
},
"f": {
"fontSize": 16,
"fontWeight": 600,
'color':'#332D2D',
padding: [0, 0, 20, 0],
},
"m": {
"fontSize": 14,
"fontWeight": 500,
'color':'#332D2D',
padding: [0, 0, 0, 0],
},
"n": {
"fontSize": 16,
"fontWeight": 600,
'color':'#332D2D',
padding: [0, 0, 0, 10],
},
},
},
// nodeWidth:100,
nodeGap: 20, // 每一组之间的距离
layoutIterations: 0,// 自动优化列表,尽量减少线的交叉,为0就是按照数据排列
emphasis: {
focus: "adjacency",
},
data: allData,
links: allGuideData,
},
}
3. Fill in test data:
// 测试数据1
let allData= [
{ name: "本科生",value:430, itemStyle: { color: "#7BA2DF" }, depth: 0 },
{ name: "硕士研究生",value:60, itemStyle: { color: "#BA86ED" }, depth: 0 },
{ name: "博士研究生",value:60, itemStyle: { color: '#59DEC6' }, depth: 0 },
{ name: "预防医学",value:60, itemStyle: { color: '#5FD981' }, depth: 1 },
{ name: "综合楼",value:60, itemStyle: { color: "#00baff" }, depth: 1 },
{ name: "2022级",typeArr:[{typeName:"本科",value:50},{typeName:"硕士研究生",value:30}], itemStyle: { color: "#f8b551" }, depth: 2 },
{ name: "2021级",typeArr:[{typeName:"硕士研究生",value:50}], itemStyle: { color: "#7ecef4" }, depth: 2 },
{ name: "2023级",typeArr:[{typeName:"博士研究生",value:50}], itemStyle: { color: "#7ecef4" }, depth: 2 },
]
// 测试数据2,连线
let allGuideData = [
// L1→L3 4509
{ source: "本科生", target: "预防医学", value: 800 },
// L2→L3 12196
{ source: "硕士研究生", target: "预防医学", value: 200 },
// L1→L2→L3 2404
{ source: "综合楼", target: "2022级", value: 200 },
{ source: "综合楼", target: "2023级", value: 200 },
{ source: "博士研究生", target: "2022级", value: 300 },
{ source: "预防医学", target: "2021级", value: 400 },
{ source: "预防医学", target: "2023级", value: 100 },
]
4. More, official API:
Official api about Sankeytu apihttps://echarts.apache.org/zh/option.html#series-sankey.type