前言

使用GOJS在vue项目中实现拖拉拽的图形化需求,记录了常用功能的实现,需要完整使用的可以去官方文档查看。


1. Gojs的安装

首先通过npm命令添加go.js插件

npm install gojs --save

2. 在vue项目中的引用

使用时需要在html用dom容器来挂载渲染图像,这里我通常使用div元素

<template>
  <div id="wrap">
    <div id="chart-wrap">
      <div id="myPalette"></div>
      <div id="myDiagramDiv"></div>
    </div>
    <div>
      <button type="button" id="SaveButton" @click="save()" class="save-Botton">SAVE</button>
    </div>
  </div>
</template>

然后看心情在全局main.js文件或在组件中引用

3. js导入

  import go from 'gojs' //在export default前
  const $ = go.GraphObject.make;

4. 画布初始化

在methods方法中创建init()函数

init() {
  var mySelf = this;
  mySelf.myDiagram =
    $(go.Diagram, "myDiagramDiv",//为DIV.HTML元素创建一个画布
      {
          //设置画布配置
      });
 }

画布基础配置

isReadOnly: true, // 只读,无法编辑操作
allowMove: true, // 允许拖动画板
allowDragOut:true, // 允许拖拽节点
allowDelete: true, // 允许删除节点
allowCopy: true, // 允许复制节点
allowClipboard: true, // 允许粘贴节点
allowLink: true,//是否可以绘制新链接。
allowRelink: true,//是否可以重新连接现有链接
initialContentAlignment: go.Spot.Center, // 居中显示
initialAutoScale: go.Diagram.Uniform,  // 缩放以使所有内容都适合

"grid.visible": true, //显示网格
"undoManager.isEnabled": true, // 支持 Ctrl-Z 和 Ctrl-Y 操作
"toolManager.hoverDelay": 100, //tooltip提示显示延时
"toolManager.toolTipDuration": 10000, //tooltip持续显示时间
"toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom, //有鼠标滚轮事件放大和缩小,而不是向上和向下滚动
"clickCreatingTool.archetypeNodeData": { text: "node258", color: "white" },//允许在后台双击以创建新node258节点

主画布layout配置

本文配置的是雪花关系图,代码段同样放在init()函数中

        class DemoForceDirectedLayout extends go.ForceDirectedLayout {
          makeNetwork(coll) {
            const net = super.makeNetwork(coll);
            net.vertexes.each(vertex => {
              const node = vertex.node;
              if (node !== null) vertex.isFixed = node.isSelected;
            });
            return net;
          }
        }

然后在画布中配置layout,这样不会出现新节点产生时与原节点重合的情况

layout: new DemoForceDirectedLayout() 

右侧画布配置

initPalette() 放在 methods中,在init()函数中用 mySelf.initPalette();即可显示。

      initPalette() {
        var mySelf = this;
        window.myPalette = $(
          go.Palette,
          "myPalette", // 必须命名或引用DIV.HTML元素
          {
            scrollsPageOnFocus: false,
            nodeTemplateMap: mySelf.myDiagram.nodeTemplateMap, // 共享myDiagram使用的模板
            model: new go.GraphLinksModel([
              // 指定调色板的内容
              {
                category: "node258",
                text: "规则"
              },
              {
                category: "node258",
                text: "计划1"
              },
              {
                category: "node258",
                text: "执行2"
              }
            ])
          }
        );
      }

5. 连接线的配置

        mySelf.myDiagram.linkTemplate = $(go.Link, {
            selectable: true, //连接线是否可选
            relinkableFrom: true,//出发点是否可以改变
            relinkableTo: true,//目标点是否可以改变
          },new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),//记录loc
          $(go.Shape, {
            strokeWidth: 2,//节点连接线宽度
            stroke: "#F60"//颜色
          }),
          $(go.Shape, {
            toArrow: "Standard",
            fill: "red",//箭头填充色
            stroke: "blue"//外边框颜色
          })//箭头
        );

6. 节点的配置

   mySelf.myDiagram.nodeTemplateMap.add(//创建名为node258的节点
          "node258",
          $(go.Node,
            "auto",
            {//节点配置
              movable:true,//是否可拖动
              deletable:true,//是否可删除
              selectable:true, //是否可选择
              selectionAdorned:false, //显示选中边框
              // reshapable:true, // 重塑(改变shape形状边界时使用,将影响节点大小)
              // resizable: true, // 可调整大小的(手动调整节点大小时,节点内容显示区域时使用)
            },new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            $(go.Panel, //表明需要创建一个panel面板对象//声明创建一个新的面板对象,自定义方式可参考mySelf.myDiagram.nodeTemplate
              "Auto", //页面布局为自动
              $(go.Shape,//声明构建一个圆形
                "Circle", {
                  fill: "#44CCFF",//内填充色
                  cursor: "pointer",//指针
                  stroke: null,//外框颜色null
                  portId: "",
                  fromLinkable: true,
                  fromLinkableSelfNode: false,
                  fromLinkableDuplicates: true,
                  toLinkable: true,
                  toLinkableSelfNode: false,
                  toLinkableDuplicates: false,
                },
                new go.Binding("figure", "figure") //声明并创建一个新的图形
              ),
              $(go.TextBlock, {//声明一个可编辑文本域
                  font: "12pt Helvetica, Arial, sans-serif",
                  width: 50,
                  maxSize: new go.Size(360, NaN),
                  wrap: go.TextBlock.WrapFit, //文本域换行
                  editable: true, //是否可编辑
                  margin: 12,
                },
                new go.Binding("text").makeTwoWay()

              ),
            ),
            {//  悬浮提示
              toolTip:
                $("ToolTip",
                  $(go.TextBlock, { margin: 4 },
                    new go.Binding("text", "text"))
                ),
            }
          )
        );

7. 节点数据

第一种

this.myDiagram.model.nodeDataArray = [] //节点数据 格式为[{ key: "Alpha", color: "lightblue", loc: "400 0" }]
this.myDiagram.model.linkDataArray = [] //连线数据 格式为[{ from: "Beta", to: "Alpha" }]

第二种

或者在data中

data() {
      return {
        nodeData: [],
        linkData: [],
      }
}

节点与连接线保存的数据格式

        nodeData: [
          {"category":"node258","text":"规则","key":-1,"loc":"-605.5896437273716 -214.50164873808765"},
          {"category":"node258","text":"计划1","key":-2,"loc":"-173.03724493296755 -192.24882726306356"},
        ],
        linkData: [
          {"from":-1,"to":-2},
        ],
mySelf.myDiagram.model.nodeDataArray = mySelf.nodeData;
mySelf.myDiagram.model.linkDataArray = mySelf.linkData;

第三种

let myModel = $(go.GraphLinksModel); //也可以创建link model;需要配置myModel.linkDataArray 如下
myModel.nodeDataArray = mySelf.nodeData;
myModel.linkDataArray = mySelf.linkData;

8 保存

监听画布是否修改

        mySelf.myDiagram.addDiagramListener("Modified", e => { //监听画布是否修改
          const button = document.getElementById("SaveButton");
          if (button) button.disabled = !mySelf.myDiagram.isModified;
          const idx = document.title.indexOf("*");
          if (mySelf.myDiagram.isModified) {
            if (idx < 0) document.title += "*";
          } else {
            if (idx >= 0) document.title = document.title.slice(0, idx);
          }
        });

在方法中创建save()函数

      save(){
        var mySelf = this;
        console.log(mySelf.myDiagram.model.toJson());
        mySelf.myDiagram.isModified = false;
      },

这是里是把修改后的函数打印出来了,如果想存到后端的话也是可以的。

9 源代码

<template>
  <div id="wrap">
    <div id="chart-wrap">
      <div id="myPalette"></div>
      <div id="myDiagramDiv"></div>
    </div>
    <div>
      <button type="button" id="SaveButton" @click="save()" class="save-Botton">SAVE</button>
    </div>
  </div>
</template>
<script>
  import go from 'gojs' //在export default前
  const $ = go.GraphObject.make;
  export default {
    data() {
      return {
        nodeData: [
          {"category":"node258","text":"规则","key":-1,"loc":"-605.5896437273716 -214.50164873808765"},
          {"category":"node258","text":"计划1","key":-2,"loc":"-173.03724493296755 -192.24882726306356"},
        ],
        linkData: [
          {"from":-1,"to":-2},
        ],
      }
    },

    mounted() {
      this.init()
    },
    methods: {
      save(){
        var mySelf = this;
        console.log(mySelf.myDiagram.model.toJson());
        mySelf.myDiagram.isModified = false;
      },
      init() {


        class DemoForceDirectedLayout extends go.ForceDirectedLayout { //布局
          makeNetwork(coll) {
            const net = super.makeNetwork(coll);
            net.vertexes.each(vertex => {
              const node = vertex.node;
              if (node !== null) vertex.isFixed = node.isSelected;
            });
            return net;
          }
        }
        var mySelf = this;

        mySelf.myDiagram =
          $(go.Diagram, "myDiagramDiv",  // 为DIV.HTML元素创建一个画布
            {
                //设置画布配置
              initialContentAlignment: go.Spot.Center, // 居中显示
              "undoManager.isEnabled": true, // 支持 Ctrl-Z 和 Ctrl-Y 操作
              "toolManager.hoverDelay": 100, //tooltip提示显示延时
              "toolManager.toolTipDuration": 10000, //tooltip持续显示时间
              //isReadOnly:true,//只读
              "grid.visible": true, //显示网格
              allowMove: true, //允许拖动
              allowDragOut:true,
              allowDelete: true,
              allowCopy: true,
              allowClipboard: true, initialAutoScale: go.Diagram.Uniform,  // 缩放以使所有内容都适合

              "toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom, //有鼠标滚轮事件放大和缩小,而不是向上和向下滚动
              'clickCreatingTool.archetypeNodeData': { category: 'node258', text: '新节点', notice: ''}, // 双击新建节点(可以写入节点的默认信息);
              layout: new DemoForceDirectedLayout()
            });
        mySelf.myDiagram.linkTemplate = $(go.Link, {
            selectable: true, //连接线是否可选
            relinkableFrom: true,//出发点是否可以改变
            relinkableTo: true,//目标点是否可以改变
          },new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
          $(go.Shape, {
            strokeWidth: 2,//节点连接线宽度
            stroke: "#F60"//颜色
          }),
          $(go.Shape, {
            toArrow: "Standard",
            fill: "red",//箭头填充色
            stroke: "blue"//外边框颜色
          })//箭头
        );
        mySelf.myDiagram.nodeTemplateMap.add(//创建名为node258的节点
          "node258",
          $(go.Node,
            "auto",
            {
              movable:true,//是否可拖动
              deletable:true,//是否可删除
              selectable:true, //是否可选择
              selectionAdorned:false, //显示选中边框
              // reshapable:true, // 重塑(改变shape形状边界时使用,将影响节点大小)
              // resizable: true, // 可调整大小的(手动调整节点大小时,节点内容显示区域时使用)
            },new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            $(go.Panel, //表明需要创建一个panel面板对象//声明创建一个新的面板对象,自定义方式可参考mySelf.myDiagram.nodeTemplate
              "Auto", //页面布局为自动
              $(go.Shape,//声明构建一个圆形
                "Circle", {
                  fill: "#44CCFF",//内填充色
                  cursor: "pointer",//指针
                  stroke: null,//外框颜色null
                  portId: "",
                  fromLinkable: true,
                  fromLinkableSelfNode: false,
                  fromLinkableDuplicates: true,
                  toLinkable: true,
                  toLinkableSelfNode: false,
                  toLinkableDuplicates: false,
                },
                new go.Binding("figure", "figure") //声明并创建一个新的图形
              ),
              $(go.TextBlock, {//声明一个可编辑文本域
                  font: "12pt Helvetica, Arial, sans-serif",
                  width: 50,
                  maxSize: new go.Size(360, NaN),
                  wrap: go.TextBlock.WrapFit, //文本域换行
                  editable: true, //是否可编辑
                  margin: 12,
                },
                new go.Binding("text").makeTwoWay()

              ),
            ),
            {//  悬浮提示
              toolTip:
                $("ToolTip",
                  $(go.TextBlock, { margin: 4 },
                    new go.Binding("text", "text"))
                ),
            }
          )
        );
        // let myModel = $(go.GraphLinksModel); //也可以创建link model;需要配置myModel.linkDataArray 如下
        // myModel.nodeDataArray = mySelf.nodeData;
        // myModel.linkDataArray = mySelf.linkData;
        // mySelf.myDiagram.model = myModel;
        mySelf.myDiagram.model.nodeDataArray = mySelf.nodeData;
        mySelf.myDiagram.model.linkDataArray = mySelf.linkData;
        mySelf.initPalette();

        mySelf.myDiagram.addDiagramListener("Modified", e => { //监听画布是否修改
          const button = document.getElementById("SaveButton");
          if (button) button.disabled = !mySelf.myDiagram.isModified;
          const idx = document.title.indexOf("*");
          if (mySelf.myDiagram.isModified) {
            if (idx < 0) document.title += "*";
          } else {
            if (idx >= 0) document.title = document.title.slice(0, idx);
          }
        });
      },
      initPalette() {
        var mySelf = this;
        window.myPalette = $(
          go.Palette,
          "myPalette", // 必须命名或引用DIV.HTML元素
          {
            scrollsPageOnFocus: false,
            nodeTemplateMap: mySelf.myDiagram.nodeTemplateMap, // 共享myDiagram使用的模板
            model: new go.GraphLinksModel([
              // 指定调色板的内容
              {
                category: "node258",
                text: "规则"
              },
              {
                category: "node258",
                text: "计划1"
              },
              {
                category: "node258",
                text: "执行2"
              }
            ])
          }
        );
      },
    }
  }
</script>
<style lang="less" scoped>
  #form-wrap {
    padding: 20px 40px;
    border: solid 1px rgb(244, 244, 244);
  }

  #submit {
    width: 102px;
    height: 40px;
    float: right;
    margin: 20px 5px 16px 0;
  }

  #chart-wrap {
    width: 100%;
    display: flex;
    justify-content: space-between;
    margin-bottom: 22px;

    #myPalette {
      width: 180px;
      margin-right: 30px;
      background-color: white;
      border: solid 1px rgb(244, 244, 244);
    }

    #myDiagramDiv {
      flex-grow: 1;
      height: 720px;
      background-color: white;
      border: solid 1px rgb(244, 244, 244);
    }
  }

  #SaveButton{
    position: relative;
    height: 60px;
    width: 100px;
    top: -60px;
    margin-left: 800px;
    background: #82ff90;
  }

</style>

总结

至此,就能在vue项目中使用Gojs实现简单的双画布托拉拽雪花图需求。

Logo

前往低代码交流专区

更多推荐