Commit c0665cb0 by 吴斌

update:路径寻找,高亮显示。同时分离公共代码。

parent 85ac5828
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
<div class="text-center m-4"> <div class="text-center m-4">
<el-button @click="analyseData">数据分析</el-button> <el-button @click="analyseData">数据分析</el-button>
</div> </div>
<AnalyzeData class="w-full max-h-full" :nodeMap="nodeMap" :paths="paths" :myDiagram="myDiagram"></AnalyzeData>
</div> </div>
</div> </div>
<div class="flex"> <div class="flex">
...@@ -62,7 +63,7 @@ import * as go from "gojs"; ...@@ -62,7 +63,7 @@ import * as go from "gojs";
import SourceCollapse from "./components/source-panel/source-collapse.vue"; import SourceCollapse from "./components/source-panel/source-collapse.vue";
import {onMounted, ref} from "vue"; import {onMounted, ref} from "vue";
import {picCategory} from "./kit/ModelData.ts"; import {picCategory} from "./kit/ModelData.ts";
import {GO, makePort, showSmallPorts} from "./kit/GOJSKit.ts"; import {findNodesAllWayBetween, getMapData, getSelectedNodes, GO, makePort, showSmallPorts} from "./kit/GOJSKit.ts";
import { import {
makeKitTopRotatingTool, makeKitTopRotatingTool,
nodeResizeAdornmentTemplate, nodeRotateAdornmentTemplate, nodeResizeAdornmentTemplate, nodeRotateAdornmentTemplate,
...@@ -71,6 +72,7 @@ import { ...@@ -71,6 +72,7 @@ import {
import {animateFlow, FlowLink, linkSelectionAdornmentTemplate} from "./kit/LinkTemplateKit.ts"; import {animateFlow, FlowLink, linkSelectionAdornmentTemplate} from "./kit/LinkTemplateKit.ts";
import {Inspector} from "./kit/DataInspector.ts"; import {Inspector} from "./kit/DataInspector.ts";
import {ElMessage} from "element-plus"; import {ElMessage} from "element-plus";
import AnalyzeData from "./components/info/analyze-data.vue";
const categoryList: any = ref(null) const categoryList: any = ref(null)
let myDiagram: any = null; let myDiagram: any = null;
...@@ -80,6 +82,9 @@ let inspector:any=null; ...@@ -80,6 +82,9 @@ let inspector:any=null;
const addProperty = ref(false) const addProperty = ref(false)
let propertyForm:any =ref(null); let propertyForm:any =ref(null);
let nodeMap = ref({});
let paths = ref<any[][]>([]);
function showAddPropertyDialog(){ function showAddPropertyDialog(){
let node = myDiagram.selection.first(); let node = myDiagram.selection.first();
if (node === null){ if (node === null){
...@@ -206,7 +211,7 @@ function initDiagram() { ...@@ -206,7 +211,7 @@ function initDiagram() {
new go.Binding("stroke", "color").makeTwoWay(), new go.Binding("stroke", "color").makeTwoWay(),
new go.Binding("fill", "color"), new go.Binding("fill", "color"),
), ),
GO(go.Shape, { toArrow: "Standard", stroke: null }), GO(go.Shape, { toArrow: "Standard", stroke: null }, new go.Binding("fill", "color")),
GO(go.TextBlock, GO(go.TextBlock,
{ segmentIndex: 0, segmentOffset: new go.Point(NaN, NaN), segmentOrientation: go.Link.OrientUpright, editable:true, text:""}, { segmentIndex: 0, segmentOffset: new go.Point(NaN, NaN), segmentOrientation: go.Link.OrientUpright, editable:true, text:""},
new go.Binding("text", "from_text").makeTwoWay() new go.Binding("text", "from_text").makeTwoWay()
...@@ -291,11 +296,12 @@ function importData() { ...@@ -291,11 +296,12 @@ function importData() {
{"from":-9,"points":[-460,-5,-460,5,-460,19,-513,19,-566,19,-576,19],"from_text":"","middle_text":"","to_text":"氨产品","category":"Arrow"}, {"from":-9,"points":[-460,-5,-460,5,-460,19,-513,19,-566,19,-576,19],"from_text":"","middle_text":"","to_text":"氨产品","category":"Arrow"},
{"from":-4,"to":-10,"points":[-140,250,-130,250,200,250,200,165,200,80,200,70],"category":"Arrow"}, {"from":-4,"to":-10,"points":[-140,250,-130,250,200,250,200,165,200,80,200,70],"category":"Arrow"},
{"from":-4,"to":-2,"points":[-170,220,-170,210,-170,197,-20,197,-20,150,-20,140],"category":"Arrow"}, {"from":-4,"to":-2,"points":[-170,220,-170,210,-170,197,-20,197,-20,150,-20,140],"category":"Arrow"},
{"from":-10,"to":-2,"points":[150,20,140,20,125,20,125,20,110,20,100,20],"category":"Flow"}, {"from":-10,"to":-2,"points":[150,20,140,20,125,20,125,20,110,20,100,20],"category":"Arrow"},
{"from":-8,"to":-2,"points":[-170,-25,-170,-35,-170,-166,-20,-166,-20,-110,-20,-100],"category":"Flow"}, {"from":-8,"to":-2,"points":[-170,-25,-170,-35,-170,-166,-20,-166,-20,-110,-20,-100],"category":"Arrow"},
{"from":-1,"points":[-135,370,-125,370,-97.3671875,370,-97.3671875,370,-69.734375,370,-59.734375,370],"category":"Arrow"} {"from":-1,"points":[-135,370,-125,370,-97.3671875,370,-97.3671875,370,-69.734375,370,-59.734375,370],"category":"Arrow"}
]} ]}
); );
nodeMap.value = getMapData(myDiagram)
} }
function exportData() { function exportData() {
...@@ -304,8 +310,7 @@ function exportData() { ...@@ -304,8 +310,7 @@ function exportData() {
} }
function analyseData(){ function analyseData(){
let selectedNodes = getSelectedNodes() let selectedNodes = getSelectedNodes(myDiagram)
console.log("选择的节点", selectedNodes)
if (selectedNodes.length != 2){ if (selectedNodes.length != 2){
ElMessage.error("只能选择两个节点") ElMessage.error("只能选择两个节点")
...@@ -315,105 +320,9 @@ function analyseData(){ ...@@ -315,105 +320,9 @@ function analyseData(){
let start_node = myDiagram.findNodeForKey(selectedNodes[0].key) let start_node = myDiagram.findNodeForKey(selectedNodes[0].key)
let end_node = myDiagram.findNodeForKey(selectedNodes[1].key) let end_node = myDiagram.findNodeForKey(selectedNodes[1].key)
findNodesAllWayBetween(start_node.data.key, end_node.data.key) paths.value = findNodesAllWayBetween(start_node.data.key, end_node.data.key, myDiagram)
} }
// 寻找两个节点间的所有路径
function findNodesAllWayBetween(startKey:number, endKey:number){
// 保存所有路径
let paths = [[startKey]],
// 搜索是否完成
flag:boolean = false,
nodeLinkMap = getMapData();
while(!flag){
// 保存当前路径的节点数量
let beforePathsNode = 0;
// 保存扩展后路径的节点数量
let afterPathsNode = 0;
// 计算扩展前的总路径节点数量
for (let path of paths){
beforePathsNode += path.length
}
for (let path of paths){
// 获取当前路径的最后一个节点
let lastNode = path[path.length-1]
// 如果最后一个节点是终点,则跳过,无需扩展
if (lastNode == endKey){
continue
}
// 获取当前路径最后一个节点的下一个节点
let nextNode = nodeLinkMap[lastNode].next
// 如果没有下一个节点,则跳过,无需扩展
if (nextNode.length ==0){
continue
}
// 如果只有一个节点,则将下一个节点直接加入当前路径
if (nextNode.length ==1 ){
path.push(nextNode[0])
}
// 如果有多个节点,则将当前路径分裂为多个路径
else{
for (let nextNodeKey of nextNode){
// 如果下一个节点已经在路径中,则跳过,无需扩展,避免循环
if (nextNodeKey in path){
continue
}
let newPath = path.slice(0)
newPath.push(nextNodeKey)
paths.push(newPath)
}
// 删除没有扩展的原路径
paths = paths.filter((item:any) => item != path
)
}
}
// 计算扩展后的总路径节点数量
for (let path of paths){
afterPathsNode += path.length
}
// 如果paths内元素数量没有增加,则搜索完成
if (beforePathsNode == afterPathsNode){
flag = true
// 删除没有找到终点的路径
paths = paths.filter((item:any) => item[item.length-1] == endKey)
}
}
return paths
}
function getSelectedNodes() {
let selectObjIterator = myDiagram.selection.iterator;
let resultNodes = [];
while (selectObjIterator.next()) {
let selectedObj = selectObjIterator.value;
if (selectedObj instanceof go.Node) {
resultNodes.push(selectedObj.data);
}
}
return resultNodes;
}
function getMapData() {
/*
* {key:{next:[], data:{}}}
*/
let model = myDiagram.model
let nodeDataArray = model.nodeDataArray
let linkDataArray = model.linkDataArray
let nodeMap = {}
nodeDataArray.forEach((item:any)=>{
nodeMap[item.key] = {next:[], data:item}
})
linkDataArray.forEach((item:any)=>{
let node = null;
if (item.from && item.to){
node = nodeMap[item.from]
node.next.push(item.to)
}
})
return nodeMap
}
function changeData(){ function changeData(){
let model = myDiagram.model let model = myDiagram.model
...@@ -429,7 +338,6 @@ function changeData(){ ...@@ -429,7 +338,6 @@ function changeData(){
},5000) },5000)
} }
onMounted(() => { onMounted(() => {
initPalette(); initPalette();
initDiagram(); initDiagram();
......
<template>
<div>
<div class="text-center" v-show="paths.length === 0">暂无分析数据</div>
<div v-show="paths.length > 0">
<div>线路结果</div>
<el-scrollbar max-height="200px">
<el-collapse>
<el-collapse-item class="m-2" v-for="(value, key) in pathNodesMap" :title="'线路' + key ">
<el-form>
<el-form-item label="路线">{{value.nodesName}}</el-form-item>
<el-form-item label="权重">
<el-input v-model="value.weight"></el-input>
</el-form-item>
</el-form>
<div class="flex justify-center">
<el-checkbox @change="highlightPath(key)" v-model="value.highlight">高亮</el-checkbox>
<el-button type="primary">确定</el-button>
</div>
</el-collapse-item>
</el-collapse>
</el-scrollbar>
<div>分析结果</div>
<div class="w-full h-26 bg-red-200">
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {ref, watch} from "vue";
import { highlightLink, cancelHighlightLink } from "../../kit/GOJSKit";
const props = defineProps({
paths: {
type: Array,
default: []
},
nodeMap:{
type: Object,
default: {}
},
myDiagram:{
type: Object,
}
})
let pathNodesMap = ref<Record<string, any>>({})
watch(()=>props.paths, (newValue) => {
newValue.forEach((path:any) => {
let pathNode:any[] = []
let pathNodeName:string[] = []
path.forEach((node:any) => {
pathNode.push(props.nodeMap[node])
pathNodeName.push(props.nodeMap[node].data.name)
})
pathNodesMap.value[newValue.indexOf(path)+1] = {
'nodeKeys':path, 'nodesName': pathNodeName, "nodes": pathNode, 'highlight': false, 'weight': 1
}
})
});
function highlightPath(pathIndex:string){
let path:number[] = pathNodesMap.value[pathIndex].nodeKeys
cancelHighlightLink(props.myDiagram)
for (let i = 0; i < path.length-1; i++) {
if (pathNodesMap.value[pathIndex].highlight) {
highlightLink(path[i], path[i+1], props.myDiagram)
}
}
}
function computeData(){
}
</script>
\ No newline at end of file
...@@ -18,8 +18,8 @@ const props = defineProps({ ...@@ -18,8 +18,8 @@ const props = defineProps({
} }
}) })
var sourcePalette: any = ref(null) let sourcePalette: any = ref(null)
var sourceModel:any = ref(null) let sourceModel:any = ref(null)
function init(){ function init(){
sourcePalette = GO(go.Palette, props.picture_category, { sourcePalette = GO(go.Palette, props.picture_category, {
......
import { log } from 'console';
import go from 'gojs'; import go from 'gojs';
export var GO = go.GraphObject.make; export var GO = go.GraphObject.make;
...@@ -23,6 +24,7 @@ export function makePort(name:any, spot:any, output:any, input:any) { ...@@ -23,6 +24,7 @@ export function makePort(name:any, spot:any, output:any, input:any) {
cursor: "pointer" cursor: "pointer"
}); });
} }
/** /**
* 展示连接锚点 * 展示连接锚点
* @param {Node} node 节点 * @param {Node} node 节点
...@@ -36,3 +38,133 @@ export function showSmallPorts(node:any, show:any) { ...@@ -36,3 +38,133 @@ export function showSmallPorts(node:any, show:any) {
}); });
} }
/**
* 获取节点的所有连接,存储为一个Map。{key:{next:[], data:{}}}
*/
export function getMapData(myDiagram:any) {
let model = myDiagram.model
let nodeDataArray = model.nodeDataArray
let linkDataArray = model.linkDataArray
let nodeMap: Record<any, any> = {}
nodeDataArray.forEach((item:any)=>{
nodeMap[item.key] = {next:[], data:item}
})
linkDataArray.forEach((item:any)=>{
let node = null;
if (item.from && item.to){
node = nodeMap[item.from]
node.next.push(item.to)
}
})
return nodeMap
}
/**
* 获取所有选择的节点
* @param {go.Diagram} myDiagram
* @return [{},{}]
*/
export function getSelectedNodes(myDiagram:go.Diagram) {
let selectObjIterator = myDiagram.selection.iterator;
let resultNodes = [];
while (selectObjIterator.next()) {
let selectedObj = selectObjIterator.value;
if (selectedObj instanceof go.Node) {
resultNodes.push(selectedObj.data);
}
}
return resultNodes;
}
/**
* 获取选中的两点间的所有路径
* @param startKey
* @param endKey
* @param myDiagram
*/
export function findNodesAllWayBetween(startKey:number, endKey:number, myDiagram:go.Diagram) {
// 保存所有路径
let paths = [[startKey]],
// 搜索是否完成
flag:boolean = false,
nodeLinkMap = getMapData(myDiagram);
while(!flag){
// 保存当前路径的节点数量
let beforePathsNode = 0;
// 保存扩展后路径的节点数量
let afterPathsNode = 0;
// 计算扩展前的总路径节点数量
for (let path of paths){
beforePathsNode += path.length
}
for (let path of paths){
// 获取当前路径的最后一个节点
let lastNode = path[path.length-1]
// 如果最后一个节点是终点,则跳过,无需扩展
if (lastNode == endKey){
continue
}
// 获取当前路径最后一个节点的下一个节点
let nextNode = nodeLinkMap[lastNode].next
// 如果没有下一个节点,则跳过,无需扩展
if (nextNode.length ==0){
continue
}
// 如果只有一个节点,则将下一个节点直接加入当前路径
if (nextNode.length ==1 ){
path.push(nextNode[0])
}
// 如果有多个节点,则将当前路径分裂为多个路径
else{
for (let nextNodeKey of nextNode){
// 如果下一个节点已经在路径中,则跳过,无需扩展,避免循环
if (nextNodeKey in path){
continue
}
let newPath = path.slice(0)
newPath.push(nextNodeKey)
paths.push(newPath)
}
// 删除没有扩展的原路径
paths = paths.filter((item:any) => item != path
)
}
}
// 计算扩展后的总路径节点数量
for (let path of paths){
afterPathsNode += path.length
}
// 如果paths内元素数量没有增加,则搜索完成
if (beforePathsNode == afterPathsNode){
flag = true
// 删除没有找到终点的路径
paths = paths.filter((item:any) => item[item.length-1] == endKey)
}
}
return paths
}
/**
* 根据 from 和 to 高亮某条线
*/
export function highlightLink(from:number, to:number, myDiagram:any){
let model = myDiagram.model
let linkDataArray = model.linkDataArray
linkDataArray.forEach((item:any)=>{
if (item.from == from && item.to == to){
model.set(item, "color", "red")
}
})
console.log(linkDataArray);
}
export function cancelHighlightLink(myDiagram:any){
let model = myDiagram.model
let linkDataArray = model.linkDataArray
linkDataArray.forEach((item:any)=>{
model.set(item, "color", "black")
})
}
\ No newline at end of file
import {GO} from './GOJSKit' import {GO} from './GOJSKit'
import go from 'gojs' import go from 'gojs'
import {log} from "util";
export var linkSelectionAdornmentTemplate = export var linkSelectionAdornmentTemplate =
GO(go.Adornment, "Link", GO(go.Adornment, "Link",
...@@ -11,23 +10,22 @@ GO(go.Adornment, "Link", ...@@ -11,23 +10,22 @@ GO(go.Adornment, "Link",
); );
export function MultiArrowLink() { export function MultiArrowLink(this:go.Link) {
go.Link.call(this); go.Link.call(this);
// return GO(go.Link, {stroke:"red"})
} }
go.Diagram.inherit(MultiArrowLink, go.Link); go.Diagram.inherit(MultiArrowLink, go.Link);
MultiArrowLink.prototype.makeGeometry = function() { MultiArrowLink.prototype.makeGeometry = function() {
// get the Geometry created by the standard behavior // get the Geometry created by the standard behavior
let geo = go.Link.prototype.makeGeometry.call(this); let geo = go.Link.prototype.makeGeometry.call(this);
if (geo.type !== go.Geometry.Path || geo.figures.length === 0) return geo; if (geo.type !== go.Geometry.Path || geo.figures.length === 0) return geo;
let mainfig = geo.figures.elt(0); // assume there's just one PathFigure let mainFigure = geo.figures.elt(0); // assume there's just one PathFigure
let mainsegs = mainfig.segments; let pathSegments = mainFigure.segments;
let arrowLen = 8; // length for each arrowhead let arrowLen = 8; // length for each arrowhead
let arrowWid = 3; // actually half-width of each arrowhead let arrowWid = 3; // actually half-width of each arrowhead
let fx = mainfig.startX; let fx = mainFigure.startX;
let fy = mainfig.startY; let fy = mainFigure.startY;
for (let i = 0; i < mainsegs.length; i++) { for (let i = 0; i < pathSegments.length; i++) {
let a = mainsegs.elt(i); let a = pathSegments.elt(i);
// assume each arrowhead is a simple triangle // assume each arrowhead is a simple triangle
let ax = a.endX; let ax = a.endX;
let ay = a.endY; let ay = a.endY;
...@@ -79,8 +77,13 @@ export function animateFlow(myDiagram:go.Diagram){ ...@@ -79,8 +77,13 @@ export function animateFlow(myDiagram:go.Diagram){
// Animate the flow in the pipes // Animate the flow in the pipes
let myAnimation = new go.Animation(); let myAnimation = new go.Animation();
myAnimation.easing = go.Animation.EaseLinear; myAnimation.easing = go.Animation.EaseLinear;
myDiagram.links.each(link => link.findObject("FLOW")?myAnimation.add(link.findObject("FLOW"), "strokeDashOffset", 20, 0): null); myDiagram.links.each(link =>{
myDiagram.links.each(link => console.log(link)) let shape = link.findObject("FLOW")
if (shape instanceof go.GraphObject){
myAnimation.add(shape, "strokeDashOffset", 20, 0)
}
}
);
// Run indefinitely // Run indefinitely
myAnimation.runCount = Infinity; myAnimation.runCount = Infinity;
myAnimation.start(); myAnimation.start();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment