组织机构图、echart树图
1. echart实现树图
1.1 要求
- 展开折叠自定义图片,根据状态显示不同的图片。
- 文字点击和图片点击分开处理,点击图片实现节点的展开折叠,点击文字实现其他自定义业务需求。
1.2 效果
1.3 代码
直接copy浏览器看效果 (说明:1. 只能监听mousedown,监听click无效。2.数据上设置标记值。3. 图片用的dataurl形式)
<!DOCTYPE html>
<html style="height: 100%">
<head>
<meta charset="utf-8">
</head>
<body style="height: 100%; margin: 0">
<div id="container" style="height: 100%"></div>
<script type="text/javascript" src="https://lib.baomitu.com/echarts/5.3.0/echarts.min.js"></script>
<script type="text/javascript">
let expandIcon = "image://data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAVFJREFUOE+t1btKXUEUxvHf6TWFT+Cx0MILgppGEGysTGGhVbTUZ7D2FWy0NKliIyGNNjbBgJfGC0QhxAewipZCZMGMbIdz8cAe2OzZa9b6M+tba2Y3dB9TiOcZ57jsFNJosziGLcxhoPB5wC9s46iMbwVcx07heJt2OFrYv2CtaiuB/yuLu9hLKT4mex8msInFiu8rpwqM4NXkNI2LSsBgmt9XbMv4lr43EBuQgQs4TIsr2C9S+5u+m4U9ihWFijGO6wz8jk/4kd6l1lmKVpqH3qH7AZaywx8MYRYnLSrfCRgxPxFyNAMYQmfR+/HUIzBi/qWYDwGMnrvCTZoP4ytmuvT8GT7jDr8xgslWwKjoMXJl23EjxfmU6htg7SnHDmotSgBrb5tujX2ahPz43sYOv05HLyofIyqaR8ejl51qvRwytNbrK0NrvWDLRu7pF/ACLKZcjfX9d0sAAAAASUVORK5CYII=";
let closeIcon = "image://data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAASZJREFUOE+11T8rhWEYx/HPiWLA4B1gMPjTCYsMVgPpDM5o5A1YvAarhZGNkkEps0hR8qcYlBdgwkBRunXfOj3hcep211NP1/O7vl3/7uupKD+jCM8bTnHxm0vlh499WMEkuguaBxxjFQdF/++ANewUhLcxwoGCfRPzjbYicB9TUbCOjZjiU7R1YBjLmG4AfXEagUsxzaAbw1lJeeewFTWLCAFIwBGcoBV1bJf36lMRmhUaFc4QrhJwF7PYw8wfYUm2hgUERi0B79CLCRw1CQw+h7hHTwCGQqeid+IZbWgpAb/jFcHnMWq7AnAQl7iO79U4Z+0lwBeM4xw36Ef1X4DZUw6ZZW1KAGYfm+yDHaLMevXShGRdDgmadX0laNYFW7wgTf0CPgDlolaNpq0FgQAAAABJRU5ErkJggg==";
let dom = document.getElementById("container");
let myChart = echarts.init(dom);
let app = {};
let data = {
"name": "root",
"children": [{
"name": "AText", "symbol": closeIcon, "expand": 1,
"children": [
{
"name": "CText",
"symbol": expandIcon,
"expand": 0,
"children": [
{
"name": "DText",
"value": 1
}, {
"name": "EText",
"value": 2
}]
}, {
"name": "FText",
"symbol": expandIcon,
"expand": 0,
"children": [
{
"name": "GText",
"value": 3
}, {
"name": "HText",
"value": 4
}]
}, {
"name": "LText", "symbol": expandIcon, "expand": 0,
"children": [{
"name": "MText",
"value": 5
}]
}]
}, {
"name": "BText",
"symbol": closeIcon,
"expand": 1,
"children": [
{
"name": "NText",
"value": 6
}, {
"name": "PText",
"symbol": expandIcon,
"expand": 0,
"children": [{
"name": "QText",
"value": 7
}, {
"name": "RText",
"value": 8
}]
}, {
"name": "YText",
"value": 9
}, {
"name": "XText",
"value": 10
}]
}]
};
option = null;
myChart.setOption(option = {
tooltip: {
trigger: 'item',
triggerOn: 'mousemove'
},
series: [{
type: 'tree',
data: [data],
bottom: '20%',
symbolSize: 16,
orient: 'vertical',
expandAndCollapse: true,
label: {
normal: {
position: 'top',
verticalAlign: 'middle',
align: 'center',
fontSize: 16
}
},
leaves: {
label: {
normal: {
position: 'bottom',
// rotate: -90,
}
}
},
animationDurationUpdate: 750
}]
});
if (option && typeof option === "object") {
myChart.setOption(option, true);
myChart.on('mousedown', (e) => {
const name = e.data.name;
const curNode = myChart._chartsViews[0]._data.tree._nodes.find(item => {
return item.name === name;
});
let culling = e.event.target.culling;
if (culling) {
curNode.isExpand = !curNode.isExpand;
if (e.data.expand) {
e.data.symbol = expandIcon;
e.data.expand = 0;
} else {
e.data.symbol = closeIcon;
e.data.expand = 1;
}
} else {
//todo 文字点击自定义事件处理
}
curNode.isExpand = !curNode.isExpand;
})
}
</script>
</body>
</html>
2. CSS+HTML实现
样式,动画手搓,需要的效果自己加,没什么说的。
2.1 效果
说明:原生的话,直接拼html片段,react或Vue,抽个组件,递归下,但是递归后对于节点的事件,比如点击折叠、展开,最方便就是把数据放全局状态下,监听点击节点的变化,在全量数据下做数据处理。
2.2 代码
直接copy浏览器看效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>结构图</title>
<style>
.container {
width: 900px;
height: 400px;
padding: 10px 0;
margin: 50px auto 50px;
overflow-x: auto;
border: solid 1px #aaa;
}
.wrap {
display: flex;
padding: 10px 20px 10px 10px;
}
.child {
display: flex;
flex-direction: column;
align-items: center;
}
.main {
display: flex;
justify-content: center;
}
.item-container {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
}
.item {
position: relative;
display: inline-flex;
width: 110px;
height: 74px;
margin: 20px;
background: #eee;
border-top: 2px solid dodgerblue;
border-radius: 1px 1px 0 0;
justify-content: center;
flex: none;
}
.item-top-node {
width: 200px;
height: 74px;
background-image: linear-gradient(135deg, #57A5FF 0%, #3B7BFF 100%);
border-top: none;
border-radius: 2px;
box-shadow: 0 2px 10px 0 #ddd;
}
.item-line-top:before {
position: absolute;
top: -22px;
left: 50%;
display: block;
width: 1px;
height: 20px;
background: #d8d8d8;
content: " ";
}
.item-line-bottom:after {
position: absolute;
top: 74px;
left: 50%;
display: block;
width: 1px;
height: 20px;
background: #d8d8d8;
content: " ";
}
.item-line-l:before {
position: absolute;
left: 50%;
display: block;
width: 50%;
height: 1px;
background: #d8d8d8;
content: " ";
}
.item-line-m:before {
position: absolute;
display: block;
width: 100%;
height: 1px;
background: #d8d8d8;
content: " ";
}
.item-line-r:before {
position: absolute;
right: 50%;
display: block;
width: 50%;
height: 1px;
background: #d8d8d8;
content: " ";
}
</style>
</head>
<body>
<div class="container">
<div class="wrap">
<div class="child">
<div class="main">
<div class="item-container">
<div class="item item-line-bottom item-top-node"></div>
<div class="inline">
<div class="child">
<div class="main">
<div class="item-container item-line-l">
<div class="item item-line-top"></div>
<div class="inline">
</div>
</div>
<div class="item-container item-line-m">
<div class="item item-line-top item-line-bottom"></div>
<div class="inline">
<div class="child">
<div class="main">
<div class="item-container item-line-l">
<div class="item item-line-top"></div>
<div class="inline">
</div>
</div>
<div class="item-container item-line-m">
<div class="item item-line-top"></div>
<div class="inline">
</div>
</div>
<div class="item-container item-line-r">
<div class="item item-line-top"></div>
<div class="inline">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="item-container item-line-r">
<div class="item item-line-top item-line-bottom"></div>
<div class="inline">
<div class="child">
<div class="main">
<div class="item-container item-line-l">
<div class="item item-line-top"></div>
<div class="inline">
</div>
</div>
<div class="item-container item-line-m">
<div class="item item-line-top"></div>
<div class="inline">
</div>
</div>
<div class="item-container item-line-r">
<div class="item item-line-top"></div>
<div class="inline">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>