UNPKG

logic-helper

Version:

This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.

930 lines (903 loc) 31.1 kB
import '@/assets/go.js'; import { createTemplate, gojsEventParser, getFormatData, createContextMenu, allEvents, transformer, formateModelData, Record } from './Utils.js' import Node from './Node.js' import Link from './Link.js' import deepEqual from 'deep-equal'; import { diff } from 'deep-object-diff'; import { ref, watch, toRaw, markRaw } from 'vue' const $ = go.GraphObject.make; // for conciseness in defining templates function init(diagramId = 'myDiagramDiv', paletteId = 'myPaletteDiv') { // Since 2.2 you can also author concise templates with method chaining instead of GraphObject.make // For details, see https://gojs.net/latest/intro/buildingObjects.html const myDiagram = $(go.Diagram, diagramId, // must name or refer to the DIV HTML element { "undoManager.isEnabled": true // enable undo & redo }); // when the document is modified, add a "*" to the title and enable the "Save" button myDiagram.addDiagramListener("Modified", 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.slice(0, idx); } }); // define the Node templates for regular nodes // the default category myDiagram.nodeTemplateMap.add("Input", createTemplate('Input')); myDiagram.nodeTemplateMap.add("Step", createTemplate()); myDiagram.nodeTemplateMap.add("Conditional", createTemplate('Conditional')); myDiagram.nodeTemplateMap.add("Start", createTemplate('Start')); myDiagram.nodeTemplateMap.add("End", createTemplate('End')); myDiagram.nodeTemplateMap.add("Delay", createTemplate('Delay')); myDiagram.nodeTemplateMap.add("Interrupt", createTemplate('Interrupt')); myDiagram.nodeTemplateMap.add("Subroutine", createTemplate('Subroutine')); myDiagram.nodeTemplateMap.add("Repeat", createTemplate('Repeat')); myDiagram.groupTemplate = createTemplate('Group'); // taken from ../extensions/Figures.js: go.Shape.defineFigureGenerator("File", (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", createTemplate('Comment')); // replace the default Link template in the linkTemplateMap myDiagram.linkTemplate = createTemplate('Link'); // the context menu allows users to make a position vacant, // remove a role and reassign the subtree, or remove a department myDiagram.nodeTemplate.contextMenu = createContextMenu.call(myDiagram, ['删除'], (node, btn) => { myDiagram.model.removeNodeData(node.data); }) myDiagram.linkTemplate.contextMenu = createContextMenu.call(myDiagram, ['删除'], (node, btn) => { myDiagram.model.removeLinkData(node.data); }) // temporary links used by LinkingTool and RelinkingTool are also orthogonal: myDiagram.toolManager.linkingTool.temporaryLink.routing = go.Link.Orthogonal; myDiagram.toolManager.relinkingTool.temporaryLink.routing = go.Link.Orthogonal; // initialize the Palette that is on the left side of the page const myPalette = $(go.Palette, paletteId, // must name or refer to the DIV HTML element { nodeTemplateMap: myDiagram.nodeTemplateMap, // share the templates used by myDiagram groupTemplateMap: myDiagram.groupTemplateMap, model: new go.GraphLinksModel([ // specify the contents of the Palette { category: "Start", text: "Start" }, { isGroup: true, text: "Group", horiz: true, category: "Group" }, { category: "Input", text: "Input" }, { category: "Step", text: "Step" }, { category: "Conditional", text: '???' }, // { // category: "Delay", // text: "Delay" // }, { category: "Repeat", text: "Repeat" }, { category: "Subroutine", text: "Subroutine" }, { category: "End", text: "End" }, { category: "Comment", text: "Comment" }, ]) }); // Overview let myOverview = $(go.Overview, "myOverviewDiv", // the HTML DIV element for the Overview { observed: myDiagram, contentAlignment: go.Spot.Center }); // tell it which Diagram to show and pan return { myDiagram, myPalette, myOverview }; } // end init export function load(json) { myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value); } // print the diagram by opening a new window holding SVG images of the diagram contents for each page export function 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(() => svgWindow.print(), 1); } let throttleBar = null; let x = 0 export default class { constructor(store) { const evt = {}; this.setModelRecords = new Record() this.store = store; allEvents.forEach(e => { evt[e] = new Set(); }) this.events = markRaw(evt) this.links = markRaw({}); this.nodes = markRaw({}); this.watchers = markRaw(new Set()); this.model = ref({}) watch(this.model, (val, oldVal) => { val = formateModelData(toRaw(val)); oldVal = toRaw(oldVal); console.log(val, '>>>>>>>>??????++++') if (!deepEqual(val, oldVal)) { const position ={...this.myDiagram.position} const rect = {...this.myDiagram.viewportBounds}; clearInterval(throttleBar); this.setModelRecords.setData(val); const difference = diff(oldVal, val); this.watchers.forEach(fn => fn(difference, val, oldVal)); store.topo.update(store.storage.topoId, transformer(val, store.storage)); this.setModel(val); try { if (difference.nodeDataArray) { for (let k in difference.nodeDataArray) { if (difference.nodeDataArray[k] === undefined) { let key = oldVal.nodeDataArray[k].key; if (this.nodes[key].category === 'Start' || this.nodes[key].category === 'End') { this.addCategoryTemplate(this.nodes[key].category); } if(this.store.topo.selectedEle&&key===this.store.topo.selectedEle.id){ this.store.topo.selectEle(null) } continue; } let v = val.nodeDataArray[k]; this.nodes[v.key] = new Node(v); this.nodes[v.key].setModel(this); if(this.store.topo.selectedEle&&this.nodes[v.key].id ===this.store.topo.selectedEle.id){ this.store.topo.selectEle(this.nodes[v.key]) } if(this.nodes[v.key].caption ===undefined){ this.nodes[v.key].setData({ caption: v.text + ' caption' }) } } } if (difference.linkDataArray) { for (let k in difference.linkDataArray) { if (difference.linkDataArray[k] === undefined) { this.links[k] && this.links[k].remove(); continue; } let v = val.linkDataArray[k]; this.links[v.key] = new Link(v); this.links[v.key].setModel(this); this.links[v.key].update({ visible: !!this.links[v.key].text }) } } }catch(e) { console.log('watch model error: ',difference); console.error(e); } this.refresh(); requestAnimationFrame(() => { this.myDiagram.zoomToRect(new go.Rect(position.x, position.y, rect.width, rect.height)); }) } }, { deep: true }) } ctlZ() { this.setModel(this.setModelRecords.prev()); } ctlY() { this.setModel(this.setModelRecords.next()); } zoomToFit() { this.myDiagram.commandHandler.zoomToFit() } getDiagramSize() { return this.myDiagram.documentBounds; } forbiden() { this.myDiagram.isReadOnly = true; } enable() { this.myDiagram.isReadOnly = false; } init(diagramId, paletteId) { const { myDiagram, myPalette } = init.call(this, diagramId, paletteId); this.myDiagram = myDiagram; this.myPalette = myPalette; this.myDiagram.animationManager.initialAnimationStyle = go.AnimationManager.None; for (let k in this.events) { this.myDiagram.addDiagramListener(k, (e) => { const data = gojsEventParser(e, this); this.events[k].forEach((fn) => { fn(data); }) }); } this.addEventListener(['ChangedSelection', 'ObjectSingleClicked'], e => { this.store.topo.selectEle(e.el) }) this.addModelChangedListener(evt => { this.model.value = this.getModel(); }) return this; } save() { this.myDiagram.isModified = false; return this.myDiagram.model.toJson(); } changeNodeCategory(key, type) { this.myDiagram.startTransaction('changeNodeCategory'); this.myDiagram.model.setDataProperty(this.myDiagram.model.findNodeDataForKey(key), 'category', type); this.myDiagram.commitTransaction('changeNodeCategory'); } addModelChangedListener(fn) { this.myDiagram.addModelChangedListener(evt => { if (!evt.isTransactionFinished) return; fn(evt); }); } refresh() { for (let k in this.nodes) { this.nodes[k].refresh(); } } moveToCenter(key) { const node = this.myDiagram.findNodeForKey(key); node&&this.myDiagram.centerRect(node.actualBounds); } nodeIsOutView(key) { const node = this.myDiagram.findNodeForKey(key); return !node||!this.myDiagram.viewportBounds.containsRect(node?.actualBounds); } scale(scale) { this.myDiagram.scale = scale; } printDiagram() { printDiagram.call(this); } addNode(nodeList = []) { if (!Array.isArray(nodeList)) { nodeList = [nodeList]; } this.myDiagram.startTransaction('add node'); nodeList.forEach(({text}) => { this.myDiagram.model.addNodeData({ category: 'Step', text: text, }); }) this.myDiagram.commitTransaction('add node'); } removeNode(key) { this.myDiagram.startTransaction('remove node' + key); if (key == this.store.topo.selectedEle?.key) { this.store.topo.selectEle(null) } this.myDiagram.model.removeNodeData(this.myDiagram.model.findNodeDataForKey(key)); this.myDiagram.commitTransaction('remove node' + key); } removeLink(key) { this.myDiagram.startTransaction('remove link' + key); if (key == this.store.topo.selectedEle?.key) { this.store.topo.selectEle(null) } this.myDiagram.model.removeLinkData(this.myDiagram.model.findLinkDataForKey(key)); this.myDiagram.commitTransaction('remove link' + key); } updateNode(key, data) { this.myDiagram.startTransaction('update node' + key); Object.keys(data).forEach(k => { this.myDiagram.model.setDataProperty(this.myDiagram.model.findNodeDataForKey(key), k, data[k]); }) this.myDiagram.commitTransaction('update node' + key); } updateLink(key, data) { this.myDiagram.startTransaction('update link' + key); Object.keys(data).forEach(k => { this.myDiagram.model.setDataProperty(this.myDiagram.model.findLinkDataForKey(key), k, data[k]); }) this.myDiagram.commitTransaction('update link' + key); } reverseLink(key) { this.myDiagram.startTransaction('reverse link' + key); let link = this.myDiagram.model.findLinkDataForKey(key); let from = link.from; let to = link.to; let fromPort = link.fromPort; let toPort = link.toPort; const fromNodeCategory = this.myDiagram.model.findNodeDataForKey(from).category; const toNodeCategory = this.myDiagram.model.findNodeDataForKey(to).category; if(fromNodeCategory === 'Conditional'&&toNodeCategory !== 'Conditional'){ this.myDiagram.model.setDataProperty(link, 'visible', false); } else if(fromNodeCategory !== 'Conditional'&&toNodeCategory === 'Conditional'){ this.myDiagram.model.setDataProperty(link, 'visible', true); } this.myDiagram.model.setDataProperty(link, 'fromPort', toPort); this.myDiagram.model.setDataProperty(link, 'toPort', fromPort); this.myDiagram.model.setDataProperty(link, 'from', to); this.myDiagram.model.setDataProperty(link, 'to', from); this.myDiagram.commitTransaction('reverse link' + key); } setLinkDataProp(key, prop, val) { this.myDiagram.startTransaction('setLinkLabel'); this.myDiagram.model.setDataProperty(this.myDiagram.model.findLinkDataForKey(key), prop, val); this.myDiagram.commitTransaction('setLinkLabel'); } getNodeByField(field,value) { return Object.keys(this.nodes).map(key=>this.nodes[key]).filter(node=>{ return node[field] == value; }) } getLinkByField(field, value){ return Object.keys(this.links).map(key=>this.links[key]).filter(link=>{ return link[field] == value; }) } getLinkByFT(from, to) { return Object.keys(this.links).map(key => this.links[key]).filter(link => { return link.id == `${from}>${to}`; }) } highlightNode(key = Object.keys(this.nodes)) { if (Array.isArray(key)) { key.forEach(k => { this.highlightNode(k) }) return; } const node = this.$getNode(key); if (node) { node.isHighlighted = true; this.nodes[key].isHighlighted = true; } } unhighlightNode(key = Object.keys(this.nodes)) { if (Array.isArray(key)) { key.forEach(k => { k&&this.unhighlightNode(k) }) return; } const node = this.$getNode(key); if (node) { node.isHighlighted = false; this.nodes[key].isHighlighted = false; } } highlightLink(key = Object.keys(this.links)) { if (Array.isArray(key)) { key.forEach(k => { k&&this.highlightLink(k) }) return; } const link = this.$getLink(key); if (link) { link.isHighlighted = true; this.links[key].isHighlighted = true; } } unhighlightLink(key = Object.keys(this.links)) { if (Array.isArray(key)) { key.forEach(k => { k&& this.unhighlightLink(k) }) return; } const link = this.$getLink(key); if (link) { link.isHighlighted = false; this.links[key].isHighlighted = false; } } toggleText(key = Object.keys(this.nodes),bool) { if (Array.isArray(key)) { key.forEach(k => { k&&this.toggleText(k,bool) }) return; } const node = this.getNode(key); if (node) { node.setData({ isTextVisible: bool }) } } toggleCaption(key = Object.keys(this.nodes),bool) { if (Array.isArray(key)) { key.forEach(k => { k&&this.toggleCaption(k,bool) }) return; } const node = this.getNode(key); if (node) { node.setData({ isCaptionVisible: bool }) } } grayNode(key = Object.keys(this.nodes)){ if (Array.isArray(key)) { key.forEach(k => { k&&this.grayNode(k) }) return; } const node = this.$getNode(key); if (node) { node.isEnabled = false; this.nodes[key].isEnabled = false; } } ungrayNode(key = Object.keys(this.nodes)){ if (Array.isArray(key)) { key.forEach(k => { k&&this.ungrayNode(k) }) return; } const node = this.$getNode(key); if (node) { node.isEnabled = true; this.nodes[key].isEnabled = true; } } ungrayLink(key = Object.keys(this.links)){ if (Array.isArray(key)) { key.forEach(k => { k&&this.grayLink(k) }) return; } const link = this.$getLink(key); if (link) { link.isEnabled = true; this.links[key].isEnabled = true; } } grayLink(key = Object.keys(this.links)){ if (Array.isArray(key)) { key.forEach(k => { this.ungrayLink(k) }) return; } const link = this.$getLink(key); if (link) { link.isEnabled = false; this.links[key].isEnabled = false; } } getHightlightedNodes() { return Object.keys(this.nodes).filter(k => this.nodes[k].isHighlighted) } getHightlightedLinks() { return Object.keys(this.links).filter(k => this.links[k].isHighlighted) } getGrayNodes() { return Object.keys(this.nodes).filter(k => this.nodes[k].isEnabled) } getGrayLinks() { return Object.keys(this.links).filter(k => this.links[k].isEnabled) } copyNode(id) { if (id) { const node = this.$getNode(id); if (node) { this.myDiagram.select(node); } } this.myDiagram.commandHandler.copySelection(); } pasteNode(id) { if (id) { const node = this.$getNode(id); if (node) { this.myDiagram.select(node); } } const node = this.myDiagram.commandHandler.pasteSelection(this.myDiagram.lastInput.documentPoint); } $getNode(key) { const node = this.myDiagram.findNodeForKey(key); return node } $getLink(key) { return this.myDiagram.findLinkForKey(key); } getNode(key) { return this.nodes[key] } getNodes() { return Object.keys(this.nodes).map(key => this.nodes[key]) } getLinks() { return Object.keys(this.links).map(key => this.links[key]) } getSelectedNodes() { const nodes = this.myDiagram.selection; const list = []; nodes.each((node) => { list.push(node); }) return list } getSelectedLinks() { const links = this.myDiagram.selection; const list = []; links.each((link) => { list.push(link); }) return list } getLinkData(key) { return getFormatData(this.$getLink(key)); } getNodeData(key) { return getFormatData(this.$getNode(key)); } clear() { this.myDiagram.clear(); } setModel(model) { console.log(model,' opopopo++++') try { if (typeof model == 'string') { model = JSON.parse(model); } } catch (e) { console.error(e); } if (typeof model == 'object') { model = formateModelData({ "class": "go.GraphLinksModel", "linkFromPortIdProperty": "fromPort", "linkToPortIdProperty": "toPort", ...model }); model = JSON.stringify(model); } model = go.Model.fromJson(model); model.linkKeyProperty = 'key'; this.myDiagram.model = model; } mergeModel(data){ this.myDiagram.model.mergeModel(data); } getModel(toJson = true) { const json = this.myDiagram.model; return toJson ? JSON.parse(json.toJson()) : json; } setNodeProperty(nodeId, key, value) { let node = this.$getNode(nodeId); if (node) { this.myDiagram.startTransaction('set node property' + nodeId); this.myDiagram.model.setDataProperty(node.data, key, value); this.myDiagram.commitTransaction('set node property' + nodeId); } } getNodeProperty(nodeId, key) { let node = this.$getNode(nodeId); if (node) { return this.myDiagram.model.getDataProperty(node.data, key); } } setLinkProperty(linkId, key, value) { let link = this.$getLink(linkId); if (link) { this.myDiagram.startTransaction('set link property' + linkId); this.myDiagram.model.setDataProperty(link.data, key, value); this.myDiagram.commitTransaction('set link property' + linkId); } } getLinkProperty(linkId, key) { let link = this.$getLink(linkId); if (link) { return this.myDiagram.model.getDataProperty(link.data, key); } } setNodeStyle(nodeId, style) { let node = this.$getNode(nodeId); if (node) { this.myDiagram.startTransaction('set node style' + nodeId); node.style = style; this.myDiagram.commitTransaction('set node style' + nodeId); } } setLinkStyle(linkId, style) { let link = this.$getLink(linkId); if (link) { this.myDiagram.startTransaction('set link style' + linkId); link.style = style; this.myDiagram.commitTransaction('set link style' + linkId); } } addEventListener(event, listener) { if (Array.isArray(event)) { return event.forEach(name => { this.addEventListener(name, listener); }) } if (typeof event == 'string') { this.events[event].add(listener); } else if (typeof event == 'function') { listener = event; for (let k in this.events) { this.events[k].add(listener); } } } removeEventListener(event, listener) { if (typeof event == 'string') { this.events[event].delete(listener); } else if (typeof event == 'function') { listener = event; for (let k in this.events) { this.events[k].delete(listener); } } } select(key, type = 'node') { if (type == 'node') { return this.myDiagram.select(this.myDiagram.findNodeForKey(key)); } return this.myDiagram.select(this.myDiagram.model.findLinkDataForKey(key)); } unselect(key, type = 'node') { if (key) { if (type == 'node') { return this.myDiagram.unselect(this.myDiagram.findNodeForKey(key)); } return this.myDiagram.unselect(this.myDiagram.model.findLinkDataForKey(key)); } else { this.myDiagram.clearSelection(); } } selectAll() { this.myDiagram.selectAll(); } unselectAll() { this.myDiagram.clearSelection(); } dispose() { this.links = null; this.nodes = null; this.myDiagram.clear(); this.myDiagram = null; this.myPalette.clear(); this.myPalette = null; this.events = null; } getAllLinksArroundNode(key) { let node = this.$getNode(key); if (node) { let returnLinks = []; node.findLinksConnected().each((link) => { returnLinks.push(link); }) return returnLinks } return [] } getAllLinksArroundNodeData(key) { return this.getAllLinksArroundNode(key).map((link) => { return getFormatData(link) }) } getAllNodesArroundNode(key) { let node = this.$getNode(key); let from = [], to = []; if (node) { node.findLinksConnected().each((link) => { if (link.fromNode.key == key) { to.push(link.toNode); } if (link.toNode.key == key) { from.push(link.fromNode); } }) } return { from, to, self: node, } } getAllNodesArroundNodeData(key) { const data = this.getAllNodesArroundNode(key) return { from: data.from.map((node) => { return getFormatData(node) }), to: data.to.map((node) => { return getFormatData(node) }), self: getFormatData(data.self), } } getAllNodesArroundLink(key) { let link = this.$getLink(key); let from = [], to = []; if (link) { from.push(link.fromNode); to.push(link.toNode); } return { self: link, from, to, } } getAllNodesArroundLinkData(key) { const data = this.getAllNodesArroundLink(key) if (data) { return { from: data.from.map((node) => { return getFormatData(node); })[0], to: data.to.map((node) => { return getFormatData(node); })[0], self: getFormatData(data.self) } } return { from: [], to: [], self: null, } } watch(fn) { this.watchers.add(fn); } unwatch(fn) { this.watchers.delete(fn); } moveNode(key, x, y) { let node = this.$getNode(key); if (node) { this.myDiagram.startTransaction('move node' + key); node.location = new go.Point(x, y); this.myDiagram.commitTransaction('move node' + key); } } getElementById(id) { return { node: this.nodes[id], link: this.links[id] }; } getElementsByData(prop, val) { return [...Object.keys(this.nodes).filter((key) => { return this.nodes[key][prop] === val }).map(id=>this.nodes[id]), ...Object.keys(this.links).filter((key) => { return this.links[key][prop] === val; }).map(id=>this.links[id])] } removeCategoryTemplate(category) { if (!this.myPalette.model.nodeDataArray.find((node) => { return node.category == category })) { return } this.myPalette.model.nodeDataArray = this.myPalette.model.nodeDataArray.filter((node) => { return node.category != category; }) this.myPalette.layoutDiagram(); } addCategoryTemplate(category) { if (category) { if (this.myPalette.model.nodeDataArray.find((node) => { return node.category == category })) { return } this.myPalette.model.nodeDataArray = [...this.myPalette.model.nodeDataArray, { category, key: category, text: category, }] this.myPalette.layoutDiagram(); } } getNodePorts(nodeId) { let node = this.$getNode(nodeId); if (node) { let ports = {}; node.ports.each((port) => { ports[port.portId] = port; }) return ports; } return {}; } enlargetCanvas() { this.myDiagram.scale = this.myDiagram.scale * 1.1; } reduceCanvas() { this.myDiagram.scale = this.myDiagram.scale * 0.9; } scrollNodeToCenter(nodeId) { let node = this.$getNode(nodeId); if (node) { this.myDiagram.scrollToRect(node.actualBounds); } } }