echart tree 组织结构图

2,572 阅读1分钟

组织机构图、echart树图

1. echart实现树图

1.1 要求

  1. 展开折叠自定义图片,根据状态显示不同的图片。
  2. 文字点击和图片点击分开处理,点击图片实现节点的展开折叠,点击文字实现其他自定义业务需求。

1.2 效果

image.png

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 效果

image.png 说明:原生的话,直接拼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>