mxGraph绘图拆分重叠的节点连接线(仅组节点有效)

这是一个使用 mxGraph 创建的图形编辑器,支持自定义的折线和直线布局。通过引入 mxCustomEdgeLayout.js 文件,实现了线条在节点之间的平滑布局。用户可以指定节点的坐标,编辑器会自动避免线条之间的重叠。同时,编辑器允许设置线条是否可移动,并提供了选择线和节点的功能。此外,还提供了节点的层级结构和拖动调整布局的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

html部分

组节点坐标随机生成

<!DOCTYPE html>
<html>
<head>
    <title>组节点</title>
    <meta charset="UTF-8">
    <script type="text/javascript">
        mxBasePath = '../src';
    </script>
    <script type="text/javascript" src="../src/js/mxClient.js"></script>

    <script type="text/javascript">
        function main(container)
        {
            if (!mxClient.isBrowserSupported())
            {
                mxUtils.error('Browser is not supported!', 200, false);
            }
            else
            {
                var nodeWidth = 160;
                var nodeHeight = 130;
                var minMargin = 150;
                var defaultRadiu = Math.max(nodeWidth / 2, nodeHeight / 2);
                var width = document.getElementById('graphContainer').offsetWidth;
                var _w = width-10;
                var defaultVertexStyleStr = 'fillColor=#339966;labelBorderColor=none;fontColor=#FFFFFF;labelBackgroundColor=none;strokeColor=none';
                var defaultEdgeStyleStr = 'fontColor=#000;';
                var levelTemp1 = ['a1','a2','a3'];
                var levelTemp2 = ['b1','b2','b3'];
                var topSpace = 90;
                var prefixStr = 'nodeid';
                var nodeData = [];

                function RandomCoord(obj){
                    this.dWidth = obj.width;
                    this.dHeight = obj.height;

                    this.fix = obj.fix || false;
                    this.minMargin = obj.minMargin;
                    this.minRadius = obj.minRadius || 30;
                    this.total = obj.total || 10;
                    this.coordArray = [];
                }
                RandomCoord.prototype.check = function(x,y,r){
                    return !(x+r>this.dWidth || x-r<0||y+r>this.dHeight||y-r<0||x<r);
                };
                RandomCoord.prototype.getR = function(x,y){
                    if(this.coordArray.length == 0){
                        return true;
                    }
                    var lenArr = this.coordArray.map(function(c){
                        let _x = c.x-x;
                        let _y = c.y-y;
                        return Math.floor(Math.sqrt(Math.pow(_x, 2) + Math.pow(_y, 2))) - c.r;
                    });
                    var minCircleLen = Math.min.apply(null, lenArr);
                    let tempR = minCircleLen - this.minMargin;
                    let bool = tempR >= this.minRadius;
                    if(bool){
                        return tempR;
                    }else{
                        return false;
                    }
                }
                RandomCoord.prototype.createOneCircle = function () {
                    let x, y, r;
                    let createCircleTimes = 0;
                    while (true){
                        createCircleTimes ++;
                        x = Math.floor(Math.random()*this.dWidth);
                        y = Math.floor(Math.random()*this.dHeight);
                        let TR = this.getR(x, y);
                        if(!TR){
                            continue;
                        }else{
                            r = defaultRadiu;
                        }
                        if(this.check(x,y,r) || createCircleTimes > 200){
                            if(this.total == 1){
                                this.coordArray.push({x:x,y:y,r:r});
                            }
                            break;
                        }
                    }
                    this.check(x,y,r) && this.coordArray.push({x:x,y:y,r:r});
                }
                RandomCoord.prototype.init = function(){
                    let n = 0;
                    let that = this;
                    while(this.coordArray.length < this.total){
                        this.coordArray = [];
                        let i=0;
                        while(this.coordArray.length < this.total){
                            this.createOneCircle();
                            i++;
                            if(i>=100){
                                break;
                            }
                        }
                        n++;
                        if(n>=100){
                            break;
                        }
                    }
                }
                RandomCoord.prototype.getPositionCoords = function(){
                    return this.coordArray;
                };

                var _n = [];
                var _tempStatusArr= [];
                var totalAttach = 3;
                var linesData = [];
                var graphType = 1;   // 1-折线   2-直线

                var model = new mxGraphModel();
                var graph = new mxGraph(document.getElementById('graphContainer'), model);
                //                节点是否可以改变大小
                graph.setCellsResizable(false);
                //                是否拖动节点
                mxGraphHandler.prototype.setMoveEnabled(true);
                //                是否可以移动连线
                graph.setCellsLocked(false);
                graph.setConnectable(false);
                //                整体移动
                graph.setPanning(true);
                graph.panningHandler.useLeftButtonForPanning = true;
                graph.setHtmlLabels(true);
                graph.setTooltips(true);

                //                设置两个节点是否可以建立多个连接
                graph.setMultigraph(true);
                graph.foldingEnabled = false;  // 关闭组折叠功能
                graph.isSelectedEdge(false);   // 添加自定义设置,线不可选中且不可移动

                if(graphType == 1){
                    graph.lineType = 'brokenLine';
                }else{
                    graph.lineType = 'straightLine';
                }         

                graph.isCellFoldable = function(cell, collapse){
                    var childCount = this.model.getChildCount(cell);
                    for(var i=0;i<childCount;i++){
                        var child = this.model.getChildAt(cell, i);
                        var geo = this.getCellGeometry(child);
                        if(geo != null && geo.relative){
                            return false;
                        }
                    }
                    return childCount > 0;
                };

                function getRelativePosition(state, dx, dy){
                    if(state != null){
                        var model = graph.getModel();
                        var geo = model.getGeometry(state.cell);

                        if(geo != null && geo.relative && !model.isEdge(state.cell)){
                            var parent = model.getParent(state.cell);
                            if(model.isVertex(parent)){
                                var pstate = graph.view.getState(parent);
                                if(pstate!=null){
                                    var x = state.x+dx;
                                    var y = state.y+dy;

                                    x = (x-pstate.x)/pstate.width;
                                    y = (y-pstate.y)/pstate.height;

                                    var scaleW = geo.width / pstate.width;
                                    var scaleH = geo.height / pstate.height;
                                    if(x<=0){x=0}
                                    if(y<=0){y=0}
                                    if(x>=1||(x+scaleW>=1)){x=1}
                                    if(y>=1||(y+scaleH>=1)){y=1}

                                    return new mxPoint(x, y);
                                }
                            }
                        }
                    }
                    return null;
                }

                graph.translateCell = function(cell, dx, dy){
                    var rel = getRelativePosition(this.view.getState(cell), dx*graph.view.scale, dy*graph.view.scale);
                    if(rel != null){
                        var geo = this.model.getGeometry(cell);
                        if(geo != null && geo.relative){
                            geo = geo.clone();
                            geo.x = rel.x;
                            geo.y = rel.y;
                            //  重置x
                            geo.offset.x = 0;
                            if(rel.x == 1){
                                geo.offset.x -= geo.width;
                            }
                            // 重置y
                            geo.offset.y = 0;
                            if(rel.y == 1){
                                geo.offset.y -= geo.height;
                            }
                            this.model.setGeometry(cell, geo);
                        }
                    }
                    else{
                        mxGraph.prototype.translateCell.apply(this, arguments);
                    }
                };

                graph.graphHandler.getDelta = function(me){
                    var point = mxUtils.convertPoint(this.graph.container, me.getX(), me.getY());
                    var delta = new mxPoint(point.x - this.first.x, point.y - this.first.y);
                    return delta;
                };

                graph.graphHandler.shouldRemoveCellsFromParent = function (parent, cells, evt) {
                    console.log(cells);
                    return cells.length == 0&&!cells[0].geometry.relative&&mxGraphHandler.prototype.shouldRemoveCellsFromParent.apply(this, arguments);
                };

                var parent = graph.getDefaultParent();

                var layout = new mxCustomEdgeLayout(graph);
                var layoutMgr = new mxLayoutManager(graph);

                layoutMgr.getLayout = function(cell){
                    if(cell.getChildCount() > 0){
                        return layout;
                    }
                };

                var style = graph.getStylesheet().getDefaultEdgeStyle();
                //                折线
                if(graphType == 1){
                    style[mxConstants.STYLE_ROUNDED] = true; // false:直角   true:圆角
                    style[mxConstants.STYLE_EDGE] = mxEdgeStyle.BlineConnector;
                    graph.alternateEdgeStyle = 'elbow=vertical';
                }else{  // 直线
                    style[mxConstants.STYLE_EDGE] = mxEdgeStyle.straightLineConnector;
                }

                var nodelistData = [
                    {
                        id:'b1',text:'食品',x:0,y:0,width:0,height:0,level:1,parents:parent.id,
                        parentID:null,childs:[
                            {id:'n11',text:'苹果',x:0,y:0,width:nodeWidth,height:nodeHeight,parentID:'b1',level:2},
                            {id:'n12',text:'草莓',x:0,y:0,width:nodeWidth,height:nodeHeight,parentID:'b1',level:2},
                            {id:'n13',text:'菠萝',x:0,y:0,width:nodeWidth,height:nodeHeight,parentID:'b1',level:2},
                        ]
                    },
                    {
                        id:'b2',text:'家具',x:0,y:0,width:0,height:0,level:1,parents:parent.id,
                        parentID:null,childs:[
                            {id:'n21',text:'柜子',x:0,y:0,width:nodeWidth,height:nodeHeight,parentID:'b2',level:2},
                            {id:'n22',text:'沙发',x:0,y:0,width:nodeWidth,height:nodeHeight,parentID:'b2',level:2},
                            {id:'n23',text:'躺椅',x:0,y:0,width:nodeWidth,height:nodeHeight,parentID:'b2',le
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值