记录一下项目中的需求完成流程图示例,使用的是使用vue-cli搭建的项目,配合gojs来实现的,附上截图一份:
由于没有中文文档,所以也摸索了一天的时间,终于是完成了需求:
第一步:引入GOJS(官方文档上下载的有水印,我用的是破解版本的,需要的可以找我拿一下QQ:1013218132)
话不多说,直接上代码: gojs的引入和echarts有点类似,也是画布完成的,都是根据ID值获取页面节点去渲染标签的
<template>
<div class="modelingBox">
<div class="modelingHead">
<el-button id="SaveButton" @click="save">保存</el-button>
<el-button @click="load">清空</el-button>
<textarea id="mySavedModel" style="width:100%;height:300px;display:none"> { "class": "go.GraphLinksModel", "linkFromPortIdProperty": "fromPort", "linkToPortIdProperty": "toPort", "nodeDataArray": [ ], "linkDataArray": [ ]}
</textarea>
<div class="msg_">
<p>流程</p>
<el-select v-model="valueOptions" @change="selectChange" filterable placeholder="请选择">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</div>
</div>
<div id="sample">
<div style="width: 100%;height:100%; display: flex; justify-content: space-between">
<div id="myPaletteDiv" style="width: 200px; margin-right: 2px; background-color: #fafafa;"></div>
<div id="myDiagramDiv" style="flex-grow: 1; height: 100%; background-color: #fafafa;"></div>
</div>
</div>
<el-dialog title="开始节点" :visible.sync="StartShow" width="30%" :before-close="handleClose">
<span>这是一段信息</span> <span slot="footer" class="dialog-footer">
<el-button @click="StartShow = false">取 消</el-button>
<el-button type="primary" @click="StartShow = false">确 定</el-button> </span>
</el-dialog>
<el-dialog title="审批节点" :visible.sync="ActivityShow" width="30%" :before-close="handleClose">
<span>这是一段信息</span> <span slot="footer" class="dialog-footer">
<el-button @click="ActivityShow = false">取 消</el-button>
<el-button type="primary" @click="ActivityShow = false">确 定</el-button> </span>
</el-dialog>
</div>
</template>
js:
<script> // import { init } from "./test"; import go from "./gojs/go-cracked"; export default { data() { return { StartShow: false, ActivityShow: false, options: [ { value: '0', label:'路段管理单位发文流程(1.0)' }, { value: '1', label: '支队收文流程(1.0)' } ], valueOptions:'' }; }, methods: { selectChange() { console.log(this.valueOptions,'select') }, handleClose() { this.StartShow = false this.ActivityShow = false }, nodeDoubleClick(e, node) { console.log(e, node.part.data.category); if (node.part.data.category == "Start") { this.StartShow = true; } else if (node.part.data.category == "Activity") { this.ActivityShow = true; } }, nodeStyle() { var this_ = this; return [ { locationSpot: go.Spot.Center, isShadowed: false, doubleClick: function (e, node) { if (!e.diagram) return; if (!e.diagram.allowLink) return; var nCategory = node.part.data.category; if (nCategory != "Activity" && nCategory != "Start") return; this_.nodeDoubleClick(e, node); }, //鼠标悬停时显示node上的点 mouseEnter: function (e, obj) { // this.displayNodePorts(obj.part, true); var diagram = obj.part.diagram; if (!diagram || diagram.isReadOnly || !diagram.allowLink) return; obj.part.ports.each(function (port) { port.stroke = true ? "white" : null; }); }, mouseLeave: function (e, obj) { // this.displayNodePorts(obj.part, false); var diagram = obj.part.diagram; if (!diagram || diagram.isReadOnly || !diagram.allowLink) return; obj.part.ports.each(function (port) { port.stroke = false ? "white" : null; }); }, }, new go.Binding("location", "loc", go.Point.parse).makeTwoWay( go.Point.stringify ), ]; }, // displayNodePorts(node, show) { // var diagram = node.diagram; // if (!diagram || diagram.isReadOnly || !diagram.allowLink) return; // node.ports.each(function (port) { // port.stroke = show ? "white" : null; // }); // }, load() { this.myDiagram.model = go.Model.fromJson( document.getElementById("mySavedModel").value ); }, // Show the diagram's model in JSON format that the user may edit 点击生产JSON save() { document.getElementById( "mySavedModel" ).value = this.myDiagram.model.toJson(); this.myDiagram.isModified = false; console.log(this.myDiagram.model.toJson(), "this.myDiagram"); }, }, mounted() { var mySelf = this; // if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this var $ = go.GraphObject.make; // for conciseness in defining templates mySelf.myDiagram = $(go.Diagram, "myDiagramDiv", { initialContentAlignment: go.Spot.Center, // 居中显示 allowDrop: true, isReadOnly: false, "undoManager.isEnabled": true, // 支持 Ctrl-Z 和 Ctrl-Y 操作 // "toolManager.hoverDelay": 100, //tooltip提示显示延时 // "toolManager.toolTipDuration": 10000, //tooltip持续显示时间 "animationManager.isEnabled": true, "animationManager.duration": 500, //isReadOnly:true,//只读 "grid.visible": true, //显示网格 // allowMove: true, //允许拖动 // allowDragOut: true, // allowDelete: true, // allowCopy: true, // allowClipboard: false, // "toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom, //有鼠标滚轮事件放大和缩小,而不是向上和向下滚动 //拖动后自动排列位置 // layout: $(go.TreeLayout, { // angle: 0, // layerSpacing: 35, // }), }); //构建gojs对象 var tbFontNormal = "normal normal normal 14px 'Microsoft YaHei',Arial"; var tbFontBold = "normal normal bold 14px 'Microsoft YaHei',Arial"; // // when the document is modified, add a "*" to the title and enable the "Save" button // mySelf.myDiagram.addDiagramListener("Modified", (e) => { // var button = document.getElementById("SaveButton"); // if (button) button.disabled = !mySelf.myDiagram.isModified; // var idx = document.title.indexOf("*"); // if (mySelf.myDiagram.isModified) { // if (idx < 0) document.title += "*"; // } else { // if (idx >= 0) document.title = document.title.substr(0, idx); // } // }); // // helper definitions for node templates // mySelf.nodeStyle(); // Define a function for creating a "port" that is normally transparent. // The "name" is used as the GraphObject.portId, // the "align" is used to determine where to position the port relative to the body of the node, // the "spot" is used to control how links connect with the port and whether the port // stretches along the side of the node, // and the boolean "output" and "input" arguments control whether the user can draw links from or to the port. // mySelf.makePort(name, align, spot, output, input) // function makePort(name, align, spot, output, input) { // var horizontal = // align.equals(go.Spot.Top) || align.equals(go.Spot.Bottom); // // the port is basically just a transparent rectangle that stretches along the side of the node, // // and becomes colored when the mouse passes over it // return $(go.Shape, { // fill: "transparent", // changed to a color in the mouseEnter event handler // strokeWidth: 0, // no stroke // width: horizontal ? NaN : 8, // if not stretching horizontally, just 8 wide // height: !horizontal ? NaN : 8, // if not stretching vertically, just 8 tall // alignment: align, // align the port on the main Shape // stretch: horizontal // ? go.GraphObject.Horizontal // : go.GraphObject.Vertical, // portId: name, // declare this object to be a "port" // fromSpot: spot, // declare where links may connect at this port // fromLinkable: output, // declare whether the user may draw links from here // toSpot: spot, // declare where links may connect at this port // toLinkable: input, // declare whether the user may draw links to here // cursor: "pointer", // show a different cursor to indicate potential link point // mouseEnter: function (e, port) { // // the PORT argument will be this Shape // if (!e.diagram.isReadOnly) port.fill = "rgba(255,0,255,0.5)"; // }, // mouseLeave: (e, port) => { // port.fill = "transparent"; // }, // }); // } //创建node上的点,默认透明,悬停后显示白色 function makeNodePort(name, spot, output, input) { return $(go.Shape, "Circle", { fill: "transparent", stroke: null, desiredSize: new go.Size(8, 8), cursor: "pointer", portId: name, alignment: spot, alignmentFocus: spot, fromSpot: spot, toSpot: spot, fromLinkable: output, toLinkable: input, }); } function textStyle() { return { font: "bold 11pt Lato, Helvetica, Arial, sans-serif", stroke: "#F8F8F8", }; } // // define the Node templates for regular nodes //审批节点 mySelf.myDiagram.nodeTemplateMap.add( "Activity", $( go.Node, "Spot", mySelf.nodeStyle(), $( go.Panel, "Auto", $(go.Shape, "Rectangle", { desiredSize: new go.Size(80, 40), minSize: new go.Size(20, 10), fill: "#1E90FF", stroke: "#1E90FF", }), $( go.TextBlock, "上级审批", { stroke: "#FFFFFF", font: tbFontNormal, textAlign: "center", margin: new go.Margin(7, 5, 5, 5), maxSize: new go.Size(50, 20), }, new go.Binding("text").makeTwoWay() ) ), makeNodePort("T", go.Spot.Top, false, true), makeNodePort("R", go.Spot.Right, true, true), makeNodePort("B", go.Spot.Bottom, true, false), makeNodePort("L", go.Spot.Left, true, true) ) ); mySelf.myDiagram.nodeTemplateMap.add( "Conditional", $( go.Node, "Spot", mySelf.nodeStyle(), // the main object is a Panel that surrounds a TextBlock with a rectangular Shape $( go.Panel, "Auto", $( go.Shape, "Terminator", { minSize: new go.Size(120, 38), fill: "#4AAA4A", stroke: "#4AAA4A", strokeWidth: 3.5, }, new go.Binding("figure", "figure") ), $( go.TextBlock, // textStyle(), { stroke: "#FFFFFF", font: tbFontBold, textAlign: "center", margin: new go.Margin(7, 5, 5, 5), maxSize: new go.Size(160, NaN), }, new go.Binding("text").makeTwoWay() ) ), // four named ports, one on each side: makeNodePort("T", go.Spot.Top, false, true), makeNodePort("R", go.Spot.Right, false, true), makeNodePort("L", go.Spot.Left, false, true) ) ); mySelf.myDiagram.nodeTemplateMap.add( "Start", $( go.Node, "Spot", mySelf.nodeStyle(), $( go.Panel, "Auto", $(go.Shape, "Terminator", { // desiredSize: new go.Size(80, 40), minSize: new go.Size(120, 38), fill: "#1E90FF", stroke: "#1E90FF", strokeWidth: 3, }), $(go.TextBlock, "Start", textStyle(), new go.Binding("text")) ), // three named ports, one on each side except the top, all output only: makeNodePort("T", go.Spot.Top, false, true), makeNodePort("R", go.Spot.Right, true, true), makeNodePort("B", go.Spot.Bottom, true, false), makeNodePort("L", go.Spot.Left, true, true) ) ); mySelf.myDiagram.nodeTemplateMap.add( "End", $( go.Node, "Auto", mySelf.nodeStyle(), // $( // go.Panel, // "Auto", $(go.Shape, "StopSign", { desiredSize: new go.Size(43, 43), // minSize: new go.Size(43, 43), fill: "#F37B1D", stroke: null, strokeWidth: 3, }), $( go.TextBlock, "End", { stroke: "#FFFFFF", font: tbFontNormal, textAlign: "center" }, new go.Binding("text") ), // ), // three named ports, one on each side except the bottom, all input only: makeNodePort("T", go.Spot.Top, false, true), makeNodePort("R", go.Spot.Right, false, true), makeNodePort("B", go.Spot.Bottom, false, true), makeNodePort("L", go.Spot.Left, 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, 0.75 * w, 0)); fig.add(new go.PathSegment(go.PathSegment.Line, w, 0.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(0.75 * w, 0, false); geo.add(fig2); // The Fold fig2.add(new go.PathSegment(go.PathSegment.Line, 0.75 * w, 0.25 * h)); fig2.add(new go.PathSegment(go.PathSegment.Line, w, 0.25 * h)); geo.spot1 = new go.Spot(0, 0.25); geo.spot2 = go.Spot.BottomRight; return geo; }); mySelf.myDiagram.nodeTemplateMap.add( "Comment", $( go.Node, "Auto", mySelf.nodeStyle(), $(go.Shape, "File", { minSize: new go.Size(80, 38), fill: "#F8EBBF", stroke: "#E1C76F", strokeWidth: 0, }), $( go.TextBlock, textStyle(), { stroke: "#555555", font: tbFontNormal, wrap: go.TextBlock.WrapFit, margin: new go.Margin(4, 5, 5, 5), maxSize: new go.Size(200, NaN), editable: true, }, new go.Binding("text").makeTwoWay() ) // no ports, because no links are allowed to connect with a comment ) ); // // replace the default Link template in the linkTemplateMap mySelf.myDiagram.linkTemplate = $( go.Link, // the whole link panel { routing: go.Link.AvoidsNodes, curve: go.Link.JumpOver, corner: 2, fromShortLength: 1, toShortLength: 2, relinkableFrom: true, relinkableTo: true, reshapable: true, resegmentable: true, mouseEnter: function (e, link) { link.findObject("HIGHLIGHT").stroke = "rgba(30,144,255,0.5)"; }, mouseLeave: function (e, link) { link.findObject("HIGHLIGHT").stroke = "transparent"; }, // selectionAdorned: false, doubleClick: function (e, link) { if (!e.diagram) return; if (!e.diagram.allowLink) return; linkDoubleClick(e, link); }, }, new go.Binding("points").makeTwoWay(), $( go.Shape, // the highlight shape, normally transparent { isPanelMain: true, strokeWidth: 8, stroke: "transparent", name: "HIGHLIGHT", } ), $( go.Shape, // the link path shape { isPanelMain: true, stroke: "gray", strokeWidth: 2 }, new go.Binding("stroke", "isSelected", function (sel) { return sel ? "dodgerblue" : "gray"; }).ofObject() ), $( go.Shape, // the arrowhead { toArrow: "standard", strokeWidth: 0, fill: "gray" } ), $( go.Panel, "Auto", // the link label, normally not visible { visible: false, name: "LABEL", segmentIndex: 2, segmentFraction: 0.5, }, new go.Binding("visible", "visible").makeTwoWay(), $( go.Shape, "RoundedRectangle", // the label shape { fill: "#F8F8F8", strokeWidth: 0 } ), $( go.TextBlock, "Yes", // the label { textAlign: "center", font: "10pt helvetica, arial, sans-serif", stroke: "#333333", editable: true, }, new go.Binding("text").makeTwoWay() ) ) ); // Make link labels visible if coming out of a "conditional" node. // This listener is called by the "LinkDrawn" and "LinkRelinked" DiagramEvents. function showLinkLabel(e) { var label = e.subject.findObject("LABEL"); if (label !== null) label.visible = e.subject.fromNode.data.category === "Conditional"; } // temporary links used by LinkingTool and RelinkingTool are also orthogonal: mySelf.myDiagram.toolManager.linkingTool.temporaryLink.routing = go.Link.Orthogonal; mySelf.myDiagram.toolManager.relinkingTool.temporaryLink.routing = go.Link.Orthogonal; mySelf.load(); // load an initial diagram from some JSON text // initialize the Palette that is on the left side of the page mySelf.myPalette = $( go.Palette, "myPaletteDiv", // must name or refer to the DIV HTML element { // Instead of the default animation, use a custom fade-down // "animationManager.initialAnimationStyle": go.AnimationManager.None, // "InitialAnimationStarting": animateFadeDown, // Instead, animate with this function nodeTemplateMap: mySelf.myDiagram.nodeTemplateMap, // share the templates used by myDiagram model: new go.GraphLinksModel([ // specify the contents of the Palette { category: "Start", text: "开始" }, { category: "Activity", text: "审批" }, { category: "Conditional", text: "完成" }, { category: "End", text: "撤销" }, { category: "Comment", text: "备注" }, ]), } ); // This is a re-implementation of the default animation, except it fades in from downwards, instead of upwards. 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(); } }, };</script>
css"
<style lang="less" scoped> .modelingBox{ width:100%; height:96%; } .modelingHead{ height:40px; line-height:40px; .msg_ { float: right; position: relative; p { display: inline; margin-right: 15px; position: absolute; top: 2px; left: -40px; } } } #sample { width: 100%; height: calc(100% - 40px); }</style>
简书代码不知道如何格式化,有需要的可以去我博客园看看: