组织架构图

js写一个这样的组织架构图,下面是代码(复制两份代码,安装依赖,可以看到效果,依赖:vue.js element-ui)

代码地址:https://gitee.com/xxsheep/organization_chart

1.插件官网https://balkangraph.com/ (官网上说有收费版,但是下载的是免费版的)

可以下载js文件,也可以用npm安装

cnpm i @balkangraph/orgchart.js -S

2.修改成自己想要的样式(因为没太多时间,只简单的改成了自己要做的样子,也没有好好处理代码,该文件可直接复制使用,setTemp是修改模板),下面是代码

// 组织机构图
import OrgChart from '@balkangraph/orgchart.js/orgchart';

export default class Chart {
    direction   = 'top'                 // 图形方向: top-从上到下,left-从左到右
    idKey       = 'orgId'               // 节点id key
    parentIdKey = 'orgParentId'         // 节点的父id key
    childKey    = 'childList'           // 子节点key

    // 初始化
    init(dom, treeData) {
        let tree = this.delParentId(treeData);
        let list = [];
        this.treeArray(tree, list);
        return this.draw(dom, list);
    }

    // 删除顶级节点的父id
    delParentId(treeData) {
        if (!treeData) {
            console.error('机构图数据为空,请检查')
            return false; 
        }
        if (!Array.isArray(treeData)) {
            console.error('机构图数据必须是数组,请检查')
            return false; 
        }
        if (treeData.length === 0) {
            return false;
        }

        let list = treeData.map(item => {
            delete item[this.parentIdKey];
            return item;
        })
        return list;
    }

    // 把树形格式化为数组
    treeArray(list, result = []) {
        if (list && Array.isArray(list) && list.length > 0) {
            list.forEach(item => {
                item.id = item[this.idKey];
                item.pid = item[this.parentIdKey];
                item.name = `${item.orgManagerName}/${item.orgManagerPositionName}`;
                item.number = `${item.staffNumbers}/${item.planNumbers}`;
                item.img = require('../img/user/user.png');
                result.push(item);
                this.treeArray(item[this.childKey], result);
            });
        }
    }

    // 渲染机构树图形
    draw(dom, list){
        this.setTmp();
        let nodes = list.map(item => {
            item.tags = ["Management"];
            return item;
        })
        return new OrgChart(dom, {
            nodes: nodes,
            nodeBinding: {
                field_0: "orgName",
                field_1: "name",
                field_2: "number",
                img_0: "img"
            },
            tags: {
                Management: {
                    template: "myTemplate"
                }
            },
            // menu: {
            //     pdf: { text: "导出 PDF" },
            //     png: { text: "导出 PNG" },
            //     svg: { text: "导出 SVG" },
            //     csv: { text: "导出 CSV" }
            // },
            toolbar: {
                layout: false,
                zoom: true,
                fit: true,
                expandAll: false
            },
            orientation: OrgChart.orientation[this.direction],          // 方向
            enableSearch: false,                                        // 是否可以搜索
            nodeMouseClick: OrgChart.action.none,                       // 关闭点击后出现的效果,该效果有很多,可以去官网查看
        });
    }

    // 模板
    setTmp() {
        OrgChart.templates.myTemplate = Object.assign({}, OrgChart.templates.ana);
        OrgChart.templates.myTemplate.size = [168, 80];
        // OrgChart.templates.myTemplate.node = '<circle cx="100" cy="100" r="100" fill="#fff" stroke-width="1" stroke="#1C1C1C"></circle>';
        // OrgChart.templates.myTemplate.node = '<rect class="hy_node" width="168" height="80" rx="4" ry="4" fill="#fff" ></rect>';
        OrgChart.templates.myTemplate.node = 
        `<g>
            <rect class="hy_node" width="168" height="80" x="0" y="0" rx="4" ry="4" fill="#ccc" filter="url(#f1)" ></rect>
            <filter id="f1" x="0" y="0">
                <feGaussianBlur in="SourceGraphic" stdDeviation="4" />
            </filter>
            <rect class="hy_node" width="168" height="80" rx="4" ry="4" fill="#fff" ></rect>
        </g>
        `;

        // 鼠标点击效果
        OrgChart.templates.myTemplate.ripple = {
            radius: 0,
            color: "#FC8E58",
            rect: null
        };

        OrgChart.templates.myTemplate.field_0 = 
        `<g>
            <rect class="hy_node" width="168" height="32" rx="4" ry="4" fill="#FC8E58" ></rect>
            <rect class="hy_node" width="168" y="12" height="20" fill="#FC8E58" ></rect>
            <text style="font-size: 14px;" fill="#fff" x="84" y="21" text-anchor="middle">{val}</text>
        </g>
        `;
        OrgChart.templates.myTemplate.field_1 = '<text style="font-size: 12px;" width="102" text-overflow="ellipsis" fill="#676B6D" x="52" y="52" text-anchor="left">{val}</text>';
        OrgChart.templates.myTemplate.field_2 = '<text style="font-size: 12px;" width="102" text-overflow="ellipsis" fill="#FF8C58" x="52" y="70" text-anchor="left">{val}</text>';

        OrgChart.templates.myTemplate.img_0 = 
              '<clipPath id="ulaImg">'
            + '<rect class="hy_node_img" x="8" y="40" width="32" height="32" fill="#ccc" ></rect>'
            + '</clipPath>' 
            + '<image preserveAspectRatio="xMidYMid slice" clip-path="url(#ulaImg)" xlink:href="{val}" x="8" y="40" width="32" height="32">'
            + '</image>';

        // 连接线条
        // OrgChart.templates.myTemplate.link = '<path stroke="#686868" stroke-width="1px" fill="none" link-id="[{id}][{child-id}]" d="M{xa},{ya} C{xb},{yb} {xc},{yc} {xd},{yd}" />';

        // OrgChart.templates.myTemplate.nodeMenuButton = 
        //     '<g style="cursor:pointer;" transform="matrix(1,0,0,1,93,15)" control-node-menu-id="{id}">'
        //     + '<rect x="-4" y="-10" fill="#000000" fill-opacity="0" width="22" height="22">'
        //     + '</rect>'
        //     + '<line x1="0" y1="0" x2="0" y2="10" stroke-width="2" stroke="#0890D3" />'
        //     + '<line x1="7" y1="0" x2="7" y2="10" stroke-width="2" stroke="#0890D3" />'
        //     + '<line x1="14" y1="0" x2="14" y2="10" stroke-width="2" stroke="#0890D3" />'
        //     + '</g>';

        OrgChart.templates.myTemplate.plus = 
            '<rect x="6" y="7" width="16" height="16" rx="8" ry="8" fill="#fff" stroke="#aeaeae" stroke-width="1"></rect>'
            + '<line x1="10" y1="15" x2="18" y2="15" stroke-width="1" stroke="#aeaeae"></line>'
            + '<line x1="14" y1="11" x2="14" y2="19" stroke-width="1" stroke="#aeaeae"></line>'

        OrgChart.templates.myTemplate.minus = 
            '<rect x="6" y="7" width="16" height="16" rx="8" ry="8" fill="#fff" stroke="#aeaeae" stroke-width="1"></rect>'
            + '<line x1="10" y1="15" x2="18" y2="15" stroke-width="1" stroke="#aeaeae"></line>'

        // OrgChart.templates.myTemplate.expandCollapseSize = 36;

        // OrgChart.templates.myTemplate.exportMenuButton = 
        //     '<div style="position:absolute;right:{p}px;top:{p}px; width:40px;height:50px;cursor:pointer;" control-export-menu="">'
        //     + '<hr style="background-color: #0890D3; height: 3px; border: none;">'
        //     + '<hr style="background-color: #0890D3; height: 3px; border: none;">'
        //     + '<hr style="background-color: #0890D3; height: 3px; border: none;">'
        //     + '</div>';  

        // OrgChart.templates.myTemplate.pointer = 
        //     '<g data-pointer="pointer" transform="matrix(0,0,0,0,100,100)">><g transform="matrix(0.3,0,0,0.3,-17,-17)">'
        //     + '<polygon fill="#0890D3" points="53.004,173.004 53.004,66.996 0,120" />'
        //     + '<polygon fill="#0890D3" points="186.996,66.996 186.996,173.004 240,120" />'
        //     + '<polygon fill="#0890D3" points="66.996,53.004 173.004,53.004 120,0" />'
        //     + '<polygon fill="#0890D3" points="120,240 173.004,186.996 66.996,186.996" />'
        //     + '<circle fill="#0890D3" cx="120" cy="120" r="30" />'
        //     + '</g></g>';
    }

    constructor(dom, treeData ,direction = 'top') {
        this.direction = direction;
        return this.init(dom, treeData);
    }
}

3.调用

<style lang="scss" scoped>
.test{
    padding: 10px;
}
.operation{
    padding: 10px 24px;
}
.chart {
    margin: 0 24px 18px 24px;
    border: 1px solid rgba(241, 242, 242, 1);
    height: 800px;
    margin-top: 20px;
}
</style>

<template>
    <div class="test">
        <el-row :gutter="16" class="operation">
            <el-col :span=".5">
                <el-select v-model="direction" size="small" placeholder="显示方向" @change="directionChange">
                    <el-option value="top" label="竖"></el-option>
                    <el-option value="left" label="横"></el-option>
                </el-select>
            </el-col>
            <el-col :span=".5">
                <el-select v-model="layer" size="small"  placeholder="显示层级" @change="layerChange">
                    <el-option :value="0" label="全部显示"></el-option>
                    <el-option v-for="item in layerList" :key="item" :value="item"  :label="`${item}层`"></el-option>
                </el-select>
            </el-col>
            <el-col :span=".5">
                <el-button type="primary" size="small"  @click="downloadPic">导出</el-button>
            </el-col>
        </el-row>

        <div ref="orgChartDom" class="chart"></div>
    </div>
</template>

<script>
import OrgChart from '../../assets/js/orgChart';

export default {
    name: "test",
    data() {
        return {
            direction: 'top',
            layer: 0,
            layerList: [1,2,3,4,5,6,7,8,9],
            treeData: [
                {
                    "orgId":28,
                    "orgParentId":0,
                    "orgName":"水果集团",
                    "orgManagerName":"xun悟空",
                    "orgManagerPositionName":"集团老总",
                    "staffNumbers":200,
                    "planNumbers":240,
                    "childList":[
                        {
                            "orgId":671,
                            "orgParentId":28,
                            "orgName":"南方公司",
                            "orgManagerName":"ju八戒",
                            "orgManagerPositionName":"厂长",
                            "staffNumbers":100,
                            "planNumbers":120,
                            "childList":[
                                {
                                    "orgId":1460,
                                    "orgParentId":671,
                                    "orgName":"种植部",
                                    "orgManagerName":"牛郎",
                                    "orgManagerPositionName":"部长",
                                    "staffNumbers":100,
                                    "planNumbers":120
                                },
                                {
                                    "orgId":1464,
                                    "orgParentId":671,
                                    "orgName":"运输部",
                                    "orgManagerName":"哮天犬",
                                    "orgManagerPositionName":"部长",
                                    "staffNumbers":100,
                                    "planNumbers":120,
                                    "childList":[
                                        {
                                            "orgId":1478,
                                            "orgParentId":1464,
                                            "orgName":"运输一队",
                                            "orgManagerName":"大黄",
                                            "orgManagerPositionName":"队长",
                                            "staffNumbers":100,
                                            "planNumbers":120
                                        }
                                    ]
                                },
                                {
                                    "orgId":1466,
                                    "orgParentId":671,
                                    "orgName":"加工部",
                                    "orgManagerName":"织女",
                                    "orgManagerPositionName":"部长",
                                    "staffNumbers":100,
                                    "planNumbers":120
                                },
                                {
                                    "orgId":1488,
                                    "orgParentId":671,
                                    "orgName":"销售部",
                                    "orgManagerName":"叨叨哥",
                                    "orgManagerPositionName":"部长",
                                    "staffNumbers":100,
                                    "planNumbers":120
                                },
                                {
                                    "orgId":1489,
                                    "orgParentId":671,
                                    "orgName":"财务部",
                                    "orgManagerName":"武大郎",
                                    "orgManagerPositionName":"部长",
                                    "staffNumbers":100,
                                    "planNumbers":120
                                }
                            ]
                        },
                        {
                            "orgId":1490,
                            "orgParentId":28,
                            "orgName":"北方公司",
                            "orgManagerName":"沙僧",
                            "orgManagerPositionName":"厂长",
                            "staffNumbers":100,
                            "planNumbers":120
                        }
                    ]
                }
            ],
        };
    },
    mounted() {
        // this.draw(this.$refs.tree, this.nodes);
        this.getChartData();
    },
    methods: {

        // 机构图--获取机构图数据
        getChartData() {
            this.orgChartData = this.treeData;
            this.showOrgChartData = this.deepClone(this.treeData);
            this.orgChartObject = new OrgChart(this.$refs.orgChartDom, this.showOrgChartData, 'top');
        },

        // 机构图--显示方向改变
        directionChange(v) {
            if (this.showOrgChartData) {
                this.orgChartObject = new OrgChart(this.$refs.orgChartDom, this.showOrgChartData, v);
            }
        },

        // 层级改变
        layerChange(v) {
            let layer = v === 0 ? 999 : v;
            this.showOrgChartData = this.deepClone(this.orgChartData);
            this.layerTree(this.showOrgChartData, 'childList', layer, 1);
            this.orgChartObject = new OrgChart(this.$refs.orgChartDom, this.showOrgChartData, this.direction);
        },

        // 机构图--导出按钮
        downloadPic() {
            if (this.orgChartObject) {
                this.orgChartObject.exportPNG({
                    filename: "机构图.png", 
                    openInNewTab: false,
                    expandChildren: true, 
                    margin: [10,20,10,20],
                });
            }
        },

        /**
         * 从树形数据中按层级取数据
         * @param {Array} list 树形数据
         * @param {String} childKey 子节点字段
         * @param {Number} layer 目标成绩
         * @param {Number} currentLayer 当前层级
         */
        layerTree(list, childKey, layer, currentLayer) {
            if (list && Array.isArray(list) && list.length > 0) {
                list.forEach(item => {
                    if (currentLayer < layer) {
                        this.layerTree(item[childKey], childKey, layer, currentLayer + 1)
                    }else{
                        delete item[childKey]
                    }
                });
            }
        },

        /**
         * 深拷贝,返回拷贝后的对象
         * @param {Object} target  要深拷贝的对象
         */
        deepClone (target) {
            let result, targetType = this.getObjClass(target);   
            if(targetType === 'Object'){
                result = {};
            }else if(targetType === 'Array'){
                result = [];
            }else {
                return target;
            }

            for(let key in target){
                let value = target[key];
                // eslint-disable-next-line no-constant-condition
                if(this.getObjClass(value) === "Object" || 'Array'){
                    result[key] = this.deepClone(value);
                }else {
                    result[key] = target[key];
                }
            }
            return result;
        },

        //检测数据类型
        getObjClass(obj) {
            return Object.prototype.toString.call(obj).slice(8, -1);
        },
    }
};
</script>

 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值