GOJS使用–前端拓扑图

1.基础版:

  • 引入go.js

    <script src="./js/go.js" type="text/javascript"></script>
    
  • 定义html标签

    <!--每个go.js图都包含在html元素中,我们需要给出一个显示的大小-->
    <div id="myDiagramDiv" style="width:400px; height:150px;background-color: #DAE4E4"></div>
    
  • js

    <script>
        // make构建gojs对象,使$缩写go.GraphObject
        var $ = go.GraphObject.make;
        // JS中,绘制图标时需要传递html标签的ID
        var myDiagram = $(go.Diagram, "myDiagramDiv",
            {
                "undoManager.isEnabled": true //启动ctrl+z撤销 和 ctrk+y 重做
            }
        );
        // 在模型数据中,每个节点都由一个JavaScript对象表示
        var Mymodel = $(go.Model);
        Mymodel.nodeDataArray = [
            {key: "Alpha"},
            {key: "Beta"},
            {key: "Gamma"},
        ];
        myDiagram.model = Mymodel
    </script>
    
  • 效果如下显示:可以在go.js图的范围内任意拖动三个模块,但是不难发现html上多了几行水印:

  • 去除水印方式:

    在go.js搜索7eba17a4ca3b1a8346
    # 注释掉该行
    a.zr = b.V[Ra("7eba17a4ca3b1a8346")][Ra("78a118b7")](b.V, Ik, 4, 4);
    # 下一行添加
    a.zr = function(){return true;}
    

2.拓扑图模块添置图片

  • js

    <script>
        // make构建gojs对象,使$缩写go.GraphObject
        var $ = go.GraphObject.make;
        // JS中,绘制图标时需要传递html标签的ID
        var myDiagram = $(go.Diagram, "myDiagramDiv",
            {
                "undoManager.isEnabled": true //启动ctrl+z撤销 和 ctrk+y 重做
            }
        );
        // 定义node
        myDiagram.nodeTemplate =
            $(go.Node, "Horizontal",
                // 添加北京颜色 此为当前节点对象
                {background:"#44CCFF"},
                $(go.Picture,
                    // 图片的宽高,包括图片背景(在未设置情况下显示)
                    {margin:10,width:50,height:50,background:"red"},
                    // Picture.source 绑定模型数据source属性的数据
                    new go.Binding("source")
                ),
                $(go.TextBlock,
                    // TextBlock.text初始值
                    "默认值..",
                    // 文本一些样式设置字体颜色,字体大小。。。
                    {margin:12,stroke:"white",font:"bold 16px sans-serif"},
                    // TextBlock.text 是绑定到模型数据的 name属性的数据
                    new go.Binding("text","name")
                )
            );
        // 在模型数据中,每个节点都由一个JavaScript对象表示
        var Mymodel = $(go.Model);
        Mymodel.nodeDataArray = [
            {name: "Alpha", "source":"img/cat1.png"},
            {name: "Beta", "source":"img/cat2.png"},
            {name: "Gamma", "source":"img/cat2.png"},
            {/* Emoty node data */}
        ];
        myDiagram.model = Mymodel
    </script>
    
  • 显示效果:

3.添置连接线

  • 只需要将Model模型改成TreeModel.并将定义每条数据key和parent来确定每个节点之间关系。

    // key 和oarent来确定每个节点之间关系
    var Mymodel = $(go.TreeModel);
        Mymodel.nodeDataArray = [
            {name: "Alpha", "source":"img/cat1.png", key:"1"},
            {name: "Beta", "source":"img/cat2.png", key:"2", parent:"1"},
            {name: "Gamma", "source":"img/cat2.png", key:"3",parent:"1"},
        ];
    
  • 显示效果

4.图标布局 树形结构先似乎

  • 需要定义layout.来构建树形结构

    <script>
        // make构建gojs对象,使$缩写go.GraphObject
        var $ = go.GraphObject.make;
        // JS中,绘制图标时需要传递html标签的ID
        var myDiagram = $(go.Diagram, "myDiagramDiv",
            {
                "undoManager.isEnabled": true, //启动ctrl+z撤销 和 ctrk+y 重做
                // 指定一个树形结构:从上到下
                // TreeLayout 默认未从左到右流动,当设置90从上到下,当设置180,从右向左,当设置270表示从下到上
                // layerSpacing 实行结构每一层的间距
                layout: $(go.TreeLayout,
                    {angle:90,layerSpacing:50}
                )
            }
        );
        // 定义node
        myDiagram.nodeTemplate =
            $(go.Node, "Horizontal",
                // 添加北京颜色 此为当前节点对象
                {background:"#44CCFF"},
                $(go.Picture,
                    // 图片的宽高,包括图片背景(在未设置情况下显示)
                    {margin:10,width:50,height:50,background:"red"},
                    // Picture.source 绑定模型数据source属性的数据
                    new go.Binding("source")
                ),
                $(go.TextBlock,
                    // TextBlock.text初始值
                    "默认值..",
                    // 文本一些样式设置字体颜色,字体大小。。。
                    {margin:12,stroke:"white",font:"bold 16px sans-serif"},
                    // TextBlock.text 是绑定到模型数据的 name属性的数据
                    new go.Binding("text","name")
                )
            );
        // 在模型数据中,每个节点都由一个JavaScript对象表示
        var Mymodel = $(go.TreeModel);
        Mymodel.nodeDataArray = [
            {name: "Alpha", "source":"img/cat1.png", key:"1"},
            {name: "Beta", "source":"img/cat2.png", key:"2", parent:"1"},
            {name: "Gamma", "source":"img/cat3.png", key:"3",parent:"1"},
            {name: "Jellylorum", "source":"img/cat4.png", key:"4",parent:"3"},
            {name: "Alonzo", "source":"img/cat5.png", key:"5",parent:"3"},
            {name: "Munkustrap", "source":"img/cat6.png", key:"6",parent:"2"},
        ];
        myDiagram.model = Mymodel
    </script>
    
  • 显示效果

5.链接模式

  • 需要定义路线模板和箭头模板

    <script>
        // make构建gojs对象,使$缩写go.GraphObject
        var $ = go.GraphObject.make;
        // JS中,绘制图标时需要传递html标签的ID
        var myDiagram = $(go.Diagram, "myDiagramDiv",
            {
                "undoManager.isEnabled": true, //启动ctrl+z撤销 和 ctrk+y 重做
                // 指定一个树形结构:从上到下
                // TreeLayout 默认未从左到右流动,当设置90从上到下,当设置180,从右向左,当设置270表示从下到上
                // layerSpacing 实行结构每一层的间距
                layout: $(go.TreeLayout,
                    {angle:90,layerSpacing:50}
                )
            }
        );
        // 定义node
        myDiagram.nodeTemplate =
            $(go.Node, "Horizontal",
                // 添加北京颜色 此为当前节点对象
                {background:"#44CCFF"},
                $(go.Picture,
                    // 图片的宽高,包括图片背景(在未设置情况下显示)
                    {margin:10,width:50,height:50,background:"red"},
                    // Picture.source 绑定模型数据source属性的数据
                    new go.Binding("source")
                ),
                $(go.TextBlock,
                    // TextBlock.text初始值
                    "默认值..",
                    // 文本一些样式设置字体颜色,字体大小。。。
                    {margin:12,stroke:"white",font:"bold 16px sans-serif"},
                    // TextBlock.text 是绑定到模型数据的 name属性的数据
                    new go.Binding("text","name")
                )
            );
        // 定义一个有箭头路线模板
        myDiagram.linkTemplate =
            $(go.Link,
                // routing默认未go.Link.Normal
                // corner 为转角值,就是线置交转交的弧度
                {routing:go.Link.Orthogonal, corner:5},
                // strokeWidth 线的粗细,stroke 线的颜色
                $(go.Shape,{strokeWidth:3, stroke: "#555"}),
                // 生成箭头模板toArrow:Standard,OpenTriangle... stroke为箭头颜色
                $(go.Shape,{toArrow:"Standard",stroke:null})
            );
        // 在模型数据中,每个节点都由一个JavaScript对象表示
        var Mymodel = $(go.TreeModel);
        Mymodel.nodeDataArray = [
            {name: "Alpha", "source":"img/cat1.png", key:"1"},
            {name: "Beta", "source":"img/cat2.png", key:"2", parent:"1"},
            {name: "Gamma", "source":"img/cat3.png", key:"3",parent:"1"},
            {name: "Jellylorum", "source":"img/cat4.png", key:"4",parent:"3"},
            {name: "Alonzo", "source":"img/cat5.png", key:"5",parent:"3"},
            {name: "Munkustrap", "source":"img/cat6.png", key:"6",parent:"2"},
        ];
        myDiagram.model = Mymodel
    </script>
    
    
  • 显示效果:

6.自定义:

  • js版本:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Flowchart</title>
        <meta name="description" content="Interactive flowchart diagram implemented by GoJS in JavaScript for HTML."/>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- Copyright 1998-2020 by Northwoods Software Corporation. -->
    
        <script src="./js/go.js"></script>
        <link href=\'https://fonts.googleapis.com/css?family=Lato:300,400,700\' rel=\'stylesheet\' type=\'text/css\'>
        <!--<script src="../assets/js/goSamples.js"></script>  &lt;!&ndash; this is only for the GoJS Samples framework &ndash;&gt;-->
        <script id="code">
            function init() {
                // 初始化示例
                // if (window.goSamples) goSamples();  // init for these samples -- you don\'t need to call this
                // make构建模板
                var $ = go.GraphObject.make;  // for conciseness in defining templates
                myDiagram =
                    $(go.Diagram, document.getElementById("myDiagramDiv"),  // must name or refer to the DIV HTML element
                        {
                            // 每次画线后调用的事件:为条件连线加上标签
                            "LinkDrawn": showLinkLabel,  // this DiagramEvent listener is defined below
                            // 每次重画线后调用的事件
                            "LinkRelinked": showLinkLabel,
                            // 启用Ctrl-Z和Ctrl-Y撤销重做功能
                            "undoManager.isEnabled": true,  // enable undo & redo
                            // 居中显示内容
                            initialContentAlignment: go.Spot.Center,
                            // 是否允许从Palette面板拖入元素
                            allowDrop: true,
                        });
    
                // 当图有改动时,在页面标题后加*,且启动保存按钮
                myDiagram.addDiagramListener("Modified", function (e) {
                    var button = document.getElementById("SaveButton");
                    if (button) button.disabled = !myDiagram.isModified;
                    var idx = document.title.indexOf("*");
                    if (myDiagram.isModified) {
                        if (idx < 0) document.title += "*";
                    } else {
                        if (idx >= 0) document.title = document.title.substr(0, idx);
                    }
                });
                // 设置节点位置风格,并与模型"loc"属性绑定,该方法会在初始化各种节点模板时使用
                function nodeStyle() {
                    return [
                        // 将节点位置信息 Node.location 同节点模型数据中 "loc" 属性绑定:
                        // 节点位置信息从 节点模型 "loc" 属性获取, 并由静态方法 Point.parse 解析.
                        // 如果节点位置改变了, 会自动更新节点模型中"loc"属性, 并由 Point.stringify 方法转化为字符串
                        new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                        {
                            // 节点位置 Node.location 定位在节点的中心
                            locationSpot: go.Spot.Center
                        }
                    ];
                }
                // 创建"port"方法,"port"是一个透明的长方形细长图块,在每个节点的四个边界上,如果鼠标移到节点某个边界上,它会高亮
                // "name": "port" ID,即GraphObject.portId,
                // "align": 决定"port" 属于节点4条边的哪条
                // "spot": 控制连线连入/连出的位置,如go.Spot.Top指, go.Spot.TopSide
                // "output" / "input": 布尔型,指定是否允许连线从此"port"连入或连出
                function makePort(name, align, spot, output, input) {
                    // 表示如果是上,下,边界则是水平的"port"
                    var horizontal = align.equals(go.Spot.Top) || align.equals(go.Spot.Bottom);
                    return $(go.Shape,
                        {
                            fill: "transparent",  // 默认透明不现实
                            strokeWidth: 0,  // 无边框
                            width: horizontal ? NaN : 8,  // 垂直"port"则8像素宽
                            height: !horizontal ? NaN : 8,  // 水平"port"则8像素
                            alignment: align,  // 同其节点对齐
                            stretch: (horizontal ? go.GraphObject.Horizontal : go.GraphObject.Vertical),//自动同其节点一同伸缩
                            portId: name,  // 声明ID
                            fromSpot: spot,  // 声明连线头连出此"port"的位置
                            fromLinkable: output,  // 布尔型,是否允许连线从此"port"连出
                            toSpot: spot,  // 声明连线尾连入此"port"的位置
                            toLinkable: input,  // 布尔型,是否允许连线从此"port"连出
                            cursor: "pointer",  // 鼠标由指针改为手指,表示此处可点击生成连线
                            mouseEnter: function (e, port) {  //鼠标移到"port"位置后,高亮
                                if (!e.diagram.isReadOnly) port.fill = "rgba(255,0,255,0.5)";
                            },
                            mouseLeave: function (e, port) {// 鼠标移出"port"位置后,透明
                                port.fill = "transparent";
                            }
                        });
                }
                // 定义图形上的文字风格
                function textStyle() {
                    return {
                        font: "bold 11pt Lato, Helvetica, Arial, sans-serif",
                        stroke: "#F8F8F8"
                    }
                }
    
                // 定义步骤(默认类型)节点的模板
    
                myDiagram.nodeTemplateMap.add("",  // the default category
                    $(go.Node, "Table", nodeStyle(),
                        // 步骤节点是一个包含可编辑文字块的长方形图块
                        $(go.Panel, "Auto",
                            $(go.Shape, "Rectangle",
                                {fill: "#282c34", stroke: "#00A9C9", strokeWidth: 3.5},
                                new go.Binding("figure", "figure")),
                            $(go.TextBlock, textStyle(),
                                {
                                    margin: 8,
                                    maxSize: new go.Size(160, NaN),
                                    wrap: go.TextBlock.WrapFit,// 尺寸自适应
                                    editable: true// 文字可编辑
                                },
                                new go.Binding("text").makeTwoWay())// 双向绑定模型中"text"属性
                        ),
                        // 上、左、右可以入,左、右、下可以出
                        // "Top"表示中心,"TopSide"表示上方任一位置,自动选择
                        makePort("T", go.Spot.Top, go.Spot.TopSide, false, true),
                        makePort("L", go.Spot.Left, go.Spot.LeftSide, true, true),
                        makePort("R", go.Spot.Right, go.Spot.RightSide, true, true),
                        makePort("B", go.Spot.Bottom, go.Spot.BottomSide, true, false)
                    ));
                // 定义条件节点的模板
                myDiagram.nodeTemplateMap.add("Conditional",
                    $(go.Node, "Table", nodeStyle(),
                        // 条件节点是一个包含可编辑文字块的菱形图块
                        $(go.Panel, "Auto",
                            $(go.Shape, "Diamond",
                                {fill: "#282c34", stroke: "#00A9C9", strokeWidth: 3.5},
                                new go.Binding("figure", "figure")),
                            $(go.TextBlock, textStyle(),
                                {
                                    margin: 8,
                                    maxSize: new go.Size(160, NaN),
                                    wrap: go.TextBlock.WrapFit,
                                    editable: true
                                },
                                new go.Binding("text").makeTwoWay())
                        ),
                        // 上、左、右可以入,左、右、下可以出
                        makePort("T", go.Spot.Top, go.Spot.Top, false, true),
                        makePort("L", go.Spot.Left, go.Spot.Left, true, true),
                        makePort("R", go.Spot.Right, go.Spot.Right, true, true),
                        makePort("B", go.Spot.Bottom, go.Spot.Bottom, true, false)
                    ));
                // 定义开始节点的模板
                myDiagram.nodeTemplateMap.add("Start",
                    $(go.Node, "Table", nodeStyle(),
                        $(go.Panel, "Spot",
                            $(go.Shape, "Circle",
                                {desiredSize: new go.Size(70, 70), fill: "#282c34", stroke: "#09d3ac", strokeWidth: 3.5}),
                            $(go.TextBlock, "Start", textStyle(),
                                new go.Binding("text"))
                        ),
                        // 左、右、下可以出,但都不可入
                        makePort("L", go.Spot.Left, go.Spot.Left, true, false),
                        makePort("R", go.Spot.Right, go.Spot.Right, true, false),
                        makePort("B", go.Spot.Bottom, go.Spot.Bottom, true, false)
                    ));
                // 定义结束节点的模板
                myDiagram.nodeTemplateMap.add("End",
                    $(go.Node, "Table", nodeStyle(),
                        // 结束节点是一个圆形图块,文字不可编辑
                        $(go.Panel, "Spot",
                            $(go.Shape, "Circle",
                                {desiredSize: new go.Size(60, 60), fill: "#282c34", stroke: "#DC3C00", strokeWidth: 3.5}),
                            $(go.TextBlock, "End", textStyle(),
                                new go.Binding("text"))
                        ),
                        // 上、左、右可以入,但都不可出
                        makePort("T", go.Spot.Top, go.Spot.Top, false, true),
                        makePort("L", go.Spot.Left, go.Spot.Left, false, true),
                        makePort("R", go.Spot.Right, go.Spot.Right, false, true)
                    ));
    
                // taken from ../extensions/Figures.js:
                go.Shape.defineFigureGenerator("File", function (shape, w, h) {
                    var geo = new go.Geometry();
                    var fig = new go.PathFigure(0, 0, true); // starting point
                    geo.add(fig);
                    fig.add(new go.PathSegment(go.PathSegment.Line, .75 * w, 0));
                    fig.add(new go.PathSegment(go.PathSegment.Line, w, .25 * h));
                    fig.add(new go.PathSegment(go.PathSegment.Line, w, h));
                    fig.add(new go.PathSegment(go.PathSegment.Line, 0, h).close());
                    var fig2 = new go.PathFigure(.75 * w, 0, false);
                    geo.add(fig2);
                    // The Fold
                    fig2.add(new go.PathSegment(go.PathSegment.Line, .75 * w, .25 * h));
                    fig2.add(new go.PathSegment(go.PathSegment.Line, w, .25 * h));
                    geo.spot1 = new go.Spot(0, .25);
                    geo.spot2 = go.Spot.BottomRight;
                    return geo;
                });
                 // 定义注释节点的模板
                myDiagram.nodeTemplateMap.add("Comment",
                    // 注释节点是一个包含可编辑文字块的文件图块
                    $(go.Node, "Auto", nodeStyle(),
                        $(go.Shape, "File",
                            {fill: "#282c34", stroke: "#DEE0A3", strokeWidth: 3}),
                        $(go.TextBlock, textStyle(),
                            {
                                margin: 8,
                                maxSize: new go.Size(200, NaN),
                                wrap: go.TextBlock.WrapFit,// 尺寸自适应
                                textAlign: "center",
                                editable: true// 文字可编辑
                            },
                            new go.Binding("text").makeTwoWay())
                        // 不支持连线入和出
                    ));
    
    
                // 初始化连接线的模板
                myDiagram.linkTemplate =
                    $(go.Link,  // 所有连接线
                        {
                            routing: go.Link.AvoidsNodes,// 连接线避开节点
                            curve: go.Link.JumpOver,
                            corner: 5, toShortLength: 4,// 直角弧度,箭头弧度
                            relinkableFrom: true,// 允许连线头重设
                            relinkableTo: true,// 允许连线尾重设
                            reshapable: true,// 允许线形修改
                            resegmentable: true,// 允许连线分割(折线)修改
                            // 鼠标移到连线上后高亮
                            mouseEnter: function (e, link) {
                                link.findObject("HIGHLIGHT").stroke = "rgba(30,144,255,0.2)";
                            },
                            mouseLeave: function (e, link) {
                                link.findObject("HIGHLIGHT").stroke = "transparent";
                            },
                            selectionAdorned: false
                        },
                        new go.Binding("points").makeTwoWay(), // 双向绑定模型中"points"数组属性
                        $(go.Shape,  // 隐藏的连线形状,8个像素粗细,当鼠标移上后显示
                            {isPanelMain: true, strokeWidth: 8, stroke: "transparent", name: "HIGHLIGHT"}),
                        $(go.Shape,  // 连线规格(颜色,选中/非选中,粗细)
                            {isPanelMain: true, stroke: "gray", strokeWidth: 2},
                            new go.Binding("stroke", "isSelected", function (sel) {
                                return sel ? "dodgerblue" : "gray";
                            }).ofObject()),
                        $(go.Shape,   // 箭头规格
                            {toArrow: "standard", strokeWidth: 0, fill: "gray"}),
                        $(go.Panel, "Auto",  // 连线标签,默认不显示
                            {visible: false, name: "LABEL", segmentIndex: 2, segmentFraction: 0.5},
                            new go.Binding("visible", "visible").makeTwoWay(),// 双向绑定模型中"visible"属性
                            $(go.Shape, "RoundedRectangle",  // 连线中显示的标签形状
                                {fill: "#F8F8F8", strokeWidth: 0}),
                            $(go.TextBlock, "Yes",  // // 连线中显示的默认标签文字
                                {
                                    textAlign: "center",
                                    font: "10pt helvetica, arial, sans-serif",
                                    stroke: "#333333",
                                    editable: true
                                },
                                new go.Binding("text").makeTwoWay()) // 双向绑定模型中"text"属性
                        )
                    );
    
                // 此事件方法由整个画板的LinkDrawn和LinkRelinked事件触发
                // 如果连线是从"conditional"条件节点出发,则将连线上的标签显示出来
                function showLinkLabel(e) {
                    var label = e.subject.findObject("LABEL");
                    if (label !== null) label.visible = (e.subject.fromNode.data.category === "Conditional");
                }
    
                // 临时的连线(还在画图中),包括重连的连线,都保持直角
                myDiagram.toolManager.linkingTool.temporaryLink.routing = go.Link.Orthogonal;
                myDiagram.toolManager.relinkingTool.temporaryLink.routing = go.Link.Orthogonal;
    
                load();  // load an initial diagram from some JSON text
    
                // 在图形页面的左边初始化图例Palette面板
                myPalette =
                    $(go.Palette, "myPaletteDiv", // 必须同HTML中Div元素id一致
                        {
                            // Instead of the default animation, use a custom fade-down
                            "animationManager.initialAnimationStyle": go.AnimationManager.None,
                            "InitialAnimationStarting": animateFadeDown, // 使用此函数设置动画
    
                            nodeTemplateMap: myDiagram.nodeTemplateMap,  // 同myDiagram公用一种node节点模板
                            model: new go.GraphLinksModel([  // 初始化Palette面板里的内容
                                {category: "Start", text: "Start"},
                                {text: "Step"},
                                {category: "Conditional", text: "???"},
                                {category: "End", text: "End"},
                                {category: "Comment", text: "Comment"}
                            ])
                        });
    
                // 动画效果
                function animateFadeDown(e) {
                    var diagram = e.diagram;
                    var animation = new go.Animation();
                    animation.isViewportUnconstrained = true; // So Diagram positioning rules let the animation start off-screen
                    animation.easing = go.Animation.EaseOutExpo;
                    animation.duration = 900;
                    // Fade "down", in other words, fade in from above
                    animation.add(diagram, \'position\', diagram.position.copy().offset(0, 200), diagram.position);
                    animation.add(diagram, \'opacity\', 0, 1);
                    animation.start();
                }
    
            } // end init
            // 将go模型以JSon格式保存在文本框内
            function save() {
                document.getElementById("mySavedModel").value = myDiagram.model.toJson();
                myDiagram.isModified = false;
            }
            // 初始化模型范例
            function load() {
                myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
            }
    
            // 在新窗口中将图形转化为SVG,并分页打印
            function printDiagram() {
                var svgWindow = window.open();
                if (!svgWindow) return;  // failure to open a new Window
                var printSize = new go.Size(700, 960);
                var bnds = myDiagram.documentBounds;
                var x = bnds.x;
                var y = bnds.y;
                while (y < bnds.bottom) {
                    while (x < bnds.right) {
                        var svg = myDiagram.makeSVG({scale: 1.0, position: new go.Point(x, y), size: printSize});
                        svgWindow.document.body.appendChild(svg);
                        x += printSize.width;
                    }
                    x = bnds.x;
                    y += printSize.height;
                }
                setTimeout(function () {
                    svgWindow.print();
                }, 1);
            }
        </script>
    </head>
        <body onload="init()">
            <div id="sample">
                <div style="width: 100%; display: flex; justify-content: space-between">
                    <div id="myPaletteDiv" style="width: 100px; margin-right: 2px; background-color: #282c34;"></div>
                    <div id="myDiagramDiv" style="flex-grow: 1; height: 750px; background-color: #282c34;"></div>
                </div>
                <button id="SaveButton" onclick="save()">Save</button>
                <button onclick="load()">Load</button>
                Diagram Model saved in JSON format:
                <textarea id="mySavedModel" style="width:100%;height:300px">
                    { "class": "go.GraphLinksModel",
                      "linkFromPortIdProperty": "fromPort",
                      "linkToPortIdProperty": "toPort",
                      "nodeDataArray": [
                     ],
                      "linkDataArray": [
                     ]}
                </textarea>
                <button onclick="printDiagram()">Print Diagram Using SVG</button>
            </div>
        </body>
    </html>
    
    
  • vue版

    <template>
      <el-card>
        <my-bread level1=\'拓扑图\' level2=\'拓扑图绘制\'></my-bread>
        <div id=\'sample\'>
          <div style=\'width: 100%; display: flex; justify-content: space-between\'>
            <div ref=\'myPaletteDiv\' style=\'width: 100px; margin-right: 2px; background-color: #282c34;\'></div>
            <div ref=\'myDiagramDiv\' style=\'flex-grow: 1; height: 750px; background-color: #282c34;\'></div>
          </div>
          <button id=\'SaveButton\' @click=\'save()\'>Save</button>
          <button @click=\'load()\'>Load</button>
          Diagram Model saved in JSON format:
          <textarea ref=\'mySavedModel\' style=\'width:100%;height:300px\'>
                    {{this.diagramData}}
                </textarea>
          <button @click=\'printDiagram()\'>Print Diagram Using SVG</button>
        </div>
      </el-card>
    <!--  <button @click=\'init()\'></button>-->
    </template>
    
    <script>
    import go from \'gojs\'
    let $ = go.GraphObject.make
    export default {
      data () {
        return {
          diagramData : { \'class\': \'go.GraphLinksModel\',
            \'linkFromPortIdProperty\': \'fromPort\',
            \'linkToPortIdProperty\': \'toPort\',
            \'nodeDataArray\': [
            ],
            \'linkDataArray\': [
            ]},
          myDiagram: null,
          myPalette: null
        }
      },
      mounted () {
        this.myDiagram =
          $(go.Diagram, this.$refs.myDiagramDiv,
            {
              // 每次画线后调用的事件:为条件连线加上标签
              \'LinkDrawn\': this.showLinkLabel,
              // 每次重画线后调用的事件
              \'LinkRelinked\': this.showLinkLabel,
              // 启用Ctrl-Z和Ctrl-Y撤销重做功能
              \'undoManager.isEnabled\': true,
              // 居中显示内容
              initialContentAlignment: go.Spot.Center,
              // 是否允许从Palette面板拖入元素
              allowDrop: true,
            })
        // console.log(this.$refs.SaveButton)
        // 当图有改动时,在页面标题后加*,且启动保存按钮
        // this.myDiagram.addDiagramListener(\'Modified\', function (e) {
        //   // var button = this.$refs.SaveButton
        //   var button = document.getElementById(\'SaveButton\')
        //   if (button) button.disabled =! this.myDiagram.isModified
        //   var idx = document.title.indexOf(\'*\')
        //   if (this.myDiagram.isModified) {
        //     if (idx < 0) document.title += \'*\'
        //   } else {
        //     if (idx >= 0) document.title = document.title.substr(0, idx)
        //   }
        // })
        // 定义步骤(默认类型)节点的模板
        this.myDiagram.nodeTemplateMap.add(\'\',
          $(go.Node, \'Table\', this.nodeStyle(),
            // 步骤节点是一个包含可编辑文字块的长方形图块
            $(go.Panel, \'Auto\',
              $(go.Shape, \'Rectangle\',
                {fill: \'#282c34\', stroke: \'#00A9C9\', strokeWidth: 3.5},
                new go.Binding(\'figure\', \'figure\')),
              $(go.TextBlock, this.textStyle(),
                {
                  margin: 8,
                  maxSize: new go.Size(160, NaN),
                  wrap: go.TextBlock.WrapFit,// 尺寸自适应
                  editable: true// 文字可编辑
                },
                new go.Binding(\'text\').makeTwoWay())// 双向绑定模型中\'text\'属性
            ),
            // 上、左、右可以入,左、右、下可以出
            // \'Top\'表示中心,\'TopSide\'表示上方任一位置,自动选择
            this.makePort(\'T\', go.Spot.Top, go.Spot.TopSide, false, true),
            this.makePort(\'L\', go.Spot.Left, go.Spot.LeftSide, true, true),
            this.makePort(\'R\', go.Spot.Right, go.Spot.RightSide, true, true),
            this.makePort(\'B\', go.Spot.Bottom, go.Spot.BottomSide, true, false)
          ))
        // 定义条件节点的模板
        this.myDiagram.nodeTemplateMap.add(\'Conditional\',
          $(go.Node, \'Table\', this.nodeStyle(),
            // 条件节点是一个包含可编辑文字块的菱形图块
            $(go.Panel, \'Auto\',
              $(go.Shape, \'Diamond\',
                {fill: \'#282c34\', stroke: \'#00A9C9\', strokeWidth: 3.5},
                new go.Binding(\'figure\', \'figure\')),
              $(go.TextBlock, this.textStyle(),
                {
                  margin: 8,
                  maxSize: new go.Size(160, NaN),
                  wrap: go.TextBlock.WrapFit,
                  editable: true
                },
                new go.Binding(\'text\').makeTwoWay())
            ),
            // 上、左、右可以入,左、右、下可以出
            this.makePort(\'T\', go.Spot.Top, go.Spot.Top, false, true),
            this.makePort(\'L\', go.Spot.Left, go.Spot.Left, true, true),
            this.makePort(\'R\', go.Spot.Right, go.Spot.Right, true, true),
            this.makePort(\'B\', go.Spot.Bottom, go.Spot.Bottom, true, false)
          ))
          // 定义开始节点的模板
        this.myDiagram.nodeTemplateMap.add(\'Start\',
          $(go.Node, \'Table\', this.nodeStyle(),
            $(go.Panel, \'Spot\',
              $(go.Shape, \'Circle\',
                {desiredSize: new go.Size(70, 70), fill: \'#282c34\', stroke: \'#09d3ac\', strokeWidth: 3.5}),
              $(go.TextBlock, \'Start\', this.textStyle(),
                new go.Binding(\'text\'))
            ),
            // 左、右、下可以出,但都不可入
            this.makePort(\'L\', go.Spot.Left, go.Spot.Left, true, false),
            this.makePort(\'R\', go.Spot.Right, go.Spot.Right, true, false),
            this.makePort(\'B\', go.Spot.Bottom, go.Spot.Bottom, true, false)
          ))
        // 定义结束节点的模板
        this.myDiagram.nodeTemplateMap.add(\'End\',
          $(go.Node, \'Table\', this.nodeStyle(),
            // 结束节点是一个圆形图块,文字不可编辑
            $(go.Panel, \'Spot\',
              $(go.Shape, \'Circle\',
                {desiredSize: new go.Size(60, 60), fill: \'#282c34\', stroke: \'#DC3C00\', strokeWidth: 3.5}),
              $(go.TextBlock, \'End\', this.textStyle(),
                new go.Binding(\'text\'))
            ),
            // 上、左、右可以入,但都不可出
            this.makePort(\'T\', go.Spot.Top, go.Spot.Top, false, true),
            this.makePort(\'L\', go.Spot.Left, go.Spot.Left, false, true),
            this.makePort(\'R\', go.Spot.Right, go.Spot.Right, false, true)
          ));
        // taken from
        go.Shape.defineFigureGenerator(\'File\', function (shape, w, h) {
          var geo = new go.Geometry();
          var fig = new go.PathFigure(0, 0, true); // starting point
          geo.add(fig);
          fig.add(new go.PathSegment(go.PathSegment.Line, .75 * w, 0));
          fig.add(new go.PathSegment(go.PathSegment.Line, w, .25 * h));
          fig.add(new go.PathSegment(go.PathSegment.Line, w, h));
          fig.add(new go.PathSegment(go.PathSegment.Line, 0, h).close());
          var fig2 = new go.PathFigure(.75 * w, 0, false);
          geo.add(fig2);
          // The Fold
          fig2.add(new go.PathSegment(go.PathSegment.Line, .75 * w, .25 * h));
          fig2.add(new go.PathSegment(go.PathSegment.Line, w, .25 * h));
          geo.spot1 = new go.Spot(0, .25);
          geo.spot2 = go.Spot.BottomRight;
          return geo;
        })
        // 定义注释节点的模板
        this.myDiagram.nodeTemplateMap.add(\'Comment\',
          // 注释节点是一个包含可编辑文字块的文件图块
          $(go.Node, \'Auto\', this.nodeStyle(),
            $(go.Shape, \'File\',
              {fill: \'#282c34\', stroke: \'#DEE0A3\', strokeWidth: 3}),
            $(go.TextBlock, this.textStyle(),
              {
                margin: 8,
                maxSize: new go.Size(200, NaN),
                wrap: go.TextBlock.WrapFit,// 尺寸自适应
                textAlign: \'center\',
                editable: true// 文字可编辑
              },
              new go.Binding(\'text\').makeTwoWay())
            // 不支持连线入和出
          ))
        // 初始化连接线的模板
        this.myDiagram.linkTemplate =
          $(go.Link,  // 所有连接线
            {
              routing: go.Link.AvoidsNodes,// 连接线避开节点
              curve: go.Link.JumpOver,
              corner: 5, toShortLength: 4,// 直角弧度,箭头弧度
              relinkableFrom: true,// 允许连线头重设
              relinkableTo: true,// 允许连线尾重设
              reshapable: true,// 允许线形修改
              resegmentable: true,// 允许连线分割(折线)修改
              // 鼠标移到连线上后高亮
              mouseEnter: function (e, link) {
                link.findObject(\'HIGHLIGHT\').stroke = \'rgba(30,144,255,0.2)\';
              },
              mouseLeave: function (e, link) {
                link.findObject(\'HIGHLIGHT\').stroke = \'transparent\';
              },
              selectionAdorned: false
            },
            new go.Binding(\'points\').makeTwoWay(), // 双向绑定模型中\'points\'数组属性
            $(go.Shape,  // 隐藏的连线形状,8个像素粗细,当鼠标移上后显示
              {isPanelMain: true, strokeWidth: 8, stroke: \'transparent\', name: \'HIGHLIGHT\'}),
            $(go.Shape,  // 连线规格(颜色,选中/非选中,粗细)
              {isPanelMain: true, stroke: \'gray\', strokeWidth: 2},
              new go.Binding(\'stroke\', \'isSelected\', function (sel) {
                return sel ? \'dodgerblue\' : \'gray\';
              }).ofObject()),
            $(go.Shape,   // 箭头规格
              {toArrow: \'standard\', strokeWidth: 0, fill: \'gray\'}),
            $(go.Panel, \'Auto\',  // 连线标签,默认不显示
              {visible: false, name: \'LABEL\', segmentIndex: 2, segmentFraction: 0.5},
              new go.Binding(\'visible\', \'visible\').makeTwoWay(),// 双向绑定模型中\'visible\'属性
              $(go.Shape, \'RoundedRectangle\',  // 连线中显示的标签形状
                {fill: \'#F8F8F8\', strokeWidth: 0}),
              $(go.TextBlock, \'Yes\',  // // 连线中显示的默认标签文字
                {
                  textAlign: \'center\',
                  font: \'10pt helvetica, arial, sans-serif\',
                  stroke: \'#333333\',
                  editable: true
                },
                new go.Binding(\'text\').makeTwoWay()) // 双向绑定模型中\'text\'属性
            )
          );
        // 临时的连线(还在画图中),包括重连的连线,都保持直角
        this.myDiagram.toolManager.linkingTool.temporaryLink.routing = go.Link.Orthogonal;
        this.myDiagram.toolManager.relinkingTool.temporaryLink.routing = go.Link.Orthogonal;
        // 读取json数据
        this.load()
        // 在图形页面的左边初始化图例Palette面板
        this.myPalette =
          $(go.Palette, this.$refs.myPaletteDiv, // 必须同HTML中Div元素id一致
            {
              // Instead of the default animation, use a custom fade-down
              \'animationManager.initialAnimationStyle\': go.AnimationManager.None,
              \'InitialAnimationStarting\': this.animateFadeDown, // 使用此函数设置动画
    
              nodeTemplateMap: this.myDiagram.nodeTemplateMap,  // 同myDiagram公用一种node节点模板
              model: new go.GraphLinksModel([  // 初始化Palette面板里的内容
                {category: \'Start\', text: \'开始\'},
                {text: \'步骤\'},
                {category: \'Conditional\', text: \'选择\'},
                {category: \'End\', text: \'结束\'},
                {category: \'Comment\', text: \'标识\'}
              ])
            })
      },
      methods : {
        showLinkLabel (e) {
          var label = e.subject.findObject(\'LABEL\')
          if (label !== null) label.visible = (e.subject.fromNode.data.category === \'Conditional\')
        },
        // 设置节点位置风格,并与模型\'loc\'属性绑定,该方法会在初始化各种节点模板时使用
        nodeStyle () {
          return [
            // 将节点位置信息 Node.location 同节点模型数据中 \'loc\' 属性绑定:
            // 节点位置信息从 节点模型 \'loc\' 属性获取, 并由静态方法 Point.parse 解析.
            // 如果节点位置改变了, 会自动更新节点模型中\'loc\'属性, 并由 Point.stringify 方法转化为字符串
            new go.Binding(\'location\', \'loc\', go.Point.parse).makeTwoWay(go.Point.stringify),
            {
              // 节点位置 Node.location 定位在节点的中心
              locationSpot: go.Spot.Center
            }
          ]
        },
        // 创建\'port\'方法,\'port\'是一个透明的长方形细长图块,在每个节点的四个边界上,如果鼠标移到节点某个边界上,它会高亮
        // \'name\': \'port\' ID,即GraphObject.portId,
        // \'align\': 决定\'port\' 属于节点4条边的哪条
        // \'spot\': 控制连线连入/连出的位置,如go.Spot.Top指, go.Spot.TopSide
        // \'output\' / \'input\': 布尔型,指定是否允许连线从此\'port\'连入或连出
        makePort (name, align, spot, output, input) {
          // 表示如果是上,下,边界则是水平的\'port\'
          var horizontal = align.equals(go.Spot.Top) || align.equals(go.Spot.Bottom);
          return $(go.Shape,
            {
              fill: \'transparent\',  // 默认透明不现实
              strokeWidth: 0,  // 无边框
              width: horizontal ? NaN : 8,  // 垂直\'port\'则8像素宽
              height: !horizontal ? NaN : 8,  // 水平\'port\'则8像素
              alignment: align,  // 同其节点对齐
              stretch: (horizontal ? go.GraphObject.Horizontal : go.GraphObject.Vertical),//自动同其节点一同伸缩
              portId: name,  // 声明ID
              fromSpot: spot,  // 声明连线头连出此\'port\'的位置
              fromLinkable: output,  // 布尔型,是否允许连线从此\'port\'连出
              toSpot: spot,  // 声明连线尾连入此\'port\'的位置
              toLinkable: input,  // 布尔型,是否允许连线从此\'port\'连出
              cursor: \'pointer\',  // 鼠标由指针改为手指,表示此处可点击生成连线
              mouseEnter: function (e, port) {  //鼠标移到\'port\'位置后,高亮
                if (!e.diagram.isReadOnly) port.fill = \'rgba(255,0,255,0.5)\';
              },
              mouseLeave: function (e, port) {// 鼠标移出\'port\'位置后,透明
                port.fill = \'transparent\';
              }
            })
        },
        // 定义图形上的文字风格
        textStyle() {
          return {
            font: \'bold 11pt Lato, Helvetica, Arial, sans-serif\',
            stroke: \'#F8F8F8\'
          }
        },
        load () {
          this.myDiagram.model = go.Model.fromJson(this.$refs.mySavedModel.value)
          // console.log(this.$refs.mySavedModel.value)
        },
        animateFadeDown(e) {
          var diagram = e.diagram;
          var animation = new go.Animation();
          animation.isViewportUnconstrained = true; // So Diagram positioning rules let the animation start off-screen
          animation.easing = go.Animation.EaseOutExpo;
          animation.duration = 900;
          // Fade \'down\', in other words, fade in from above
          animation.add(diagram, \'position\', diagram.position.copy().offset(0, 200), diagram.position);
          animation.add(diagram, \'opacity\', 0, 1);
          animation.start();
        },
        // 初始化模型范例
        save () {
          this.$refs.mySavedModel.value = this.myDiagram.model.toJson()
          this.myDiagram.isModified = false
        },
        // 在新窗口中将图形转化为SVG,并分页打印
        printDiagram() {
          var svgWindow = window.open();
          if (!svgWindow) return;  // failure to open a new Window
          var printSize = new go.Size(700, 960);
          var bnds = this.myDiagram.documentBounds;
          var x = bnds.x;
          var y = bnds.y;
          while (y < bnds.bottom) {
            while (x < bnds.right) {
              var svg = this.myDiagram.makeSVG({scale: 1.0, position: new go.Point(x, y), size: printSize});
              svgWindow.document.body.appendChild(svg);
              x += printSize.width;
            }
            x = bnds.x;
            y += printSize.height;
          }
          setTimeout(function () {
            svgWindow.print();
          }, 1);
        }
      }
    }
    </script>
    <style scoped>
    
    </style>
    
    
  • 参考文件:

http://www.bjhee.com/gojs.html

https://github.com/NorthwoodsSoftware/GoJS

版权声明:本文为xujunkai原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/xujunkai/p/12585052.html