端到端功能 范围框内外元素 连线处理
This commit is contained in:
parent
99edb3460c
commit
18018f8c7b
Binary file not shown.
@ -38,4 +38,23 @@ public interface SubProcessConst {
|
||||
|
||||
// 范围选择框内边距
|
||||
double SCOPE_SHAPE_PADDING = 300;
|
||||
|
||||
// 子流程节点上扩展的属性名 用来存储当前子流程节点标识的模型文件信息
|
||||
String EXTEND_ATTR = "extendAttr";
|
||||
|
||||
// 节点展开时 范围框上扩镇的属性名 用来存储自身内部元素
|
||||
String INNER_ELEMENTS = "innerElements";
|
||||
|
||||
// 流程接口图形的唯一标识
|
||||
String SHAPE_NAME_PROCEDURE = "procedure";
|
||||
|
||||
// 范围框 内部前置或者后置流程接口元素 的特殊属性名
|
||||
String SHAPE_PROCEDURE_ATTR_MARK = "attrMark";
|
||||
|
||||
// 水平布局
|
||||
String DIRECTION_H = "horizontal";
|
||||
|
||||
// 垂直布局
|
||||
String DIRECTION_V = "vertically";
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,229 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.graph;
|
||||
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.constant.ElementType;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.util.LinkerPointCalculationHandle;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author oYang
|
||||
* @Description 端到端总图 连线后置处理
|
||||
* 针对展开或者闭合节点上的连线进行后置处理
|
||||
* 此时总图的状态是节点展开或者闭合已经处理
|
||||
* 展开的话连线此时是连在了范围框上 此处处理的是将范围框上的连线连到内部节点上(如果此节点存在的话)
|
||||
* 闭合的话连线此时是连在了范围框的内部节点上(也有可能是在范围框上 范围框上不处理) 此处处理的是将内部节点的连线连到闭合后的子流程节点上
|
||||
* @createTime 2023年06月28日 13:47:00
|
||||
*/
|
||||
public class ExpandOrCloseShapeLinkerConvertHandle {
|
||||
|
||||
private AbstractDefinitionHandle definitionHandle; // 总图的存储模型define处理器
|
||||
private LinkerPointCalculationHandle linkerPointCalculationHandle; // 连线上起始点以及折点处理器
|
||||
private String direction; // 当前布局方式
|
||||
|
||||
public ExpandOrCloseShapeLinkerConvertHandle(AbstractDefinitionHandle definitionHandle) {
|
||||
this.definitionHandle = definitionHandle;
|
||||
|
||||
this.linkerPointCalculationHandle = new LinkerPointCalculationHandle(definitionHandle);
|
||||
|
||||
JSONObject processProperties = definitionHandle.getProcessProperties();
|
||||
this.direction = processProperties.getString("direction");
|
||||
}
|
||||
|
||||
|
||||
public void scopeShapeLinkerHandle(){
|
||||
|
||||
Set<String> scopeShapeIds = definitionHandle.getElements().keySet().stream().filter(key -> definitionHandle.getElementTypeByKey(key).name().equals(ElementType.SCOPE_NODE.name())).collect(Collectors.toSet());
|
||||
if (scopeShapeIds.size() > 0){
|
||||
for (String shapeId : scopeShapeIds) {
|
||||
// 1、准备当前展开的子流程节点的前置连线与后置连线
|
||||
JSONArray linkers = definitionHandle.getLinkers();
|
||||
// 2、准备当前展开的子流程节点的内部元素中的流程接口 其中代表前置/后置流程文件属性的流程接口上会有 attrMark 属性
|
||||
JSONObject scopeShape = definitionHandle.getShapeByKey(shapeId);
|
||||
JSONArray innerEleKeyArr = scopeShape.getJSONArray(SubProcessConst.INNER_ELEMENTS);
|
||||
// 获取当前范围框 内部前置或者后置流程接口元素集合
|
||||
JSONArray procedureArr = innerEleKeyArr
|
||||
.stream()
|
||||
.filter(innerEleKey -> definitionHandle.getElementTypeByKey(innerEleKey.toString()).name().equals(ElementType.INNER_NODE.name()))
|
||||
.filter(innerEleKey -> SubProcessConst.SHAPE_NAME_PROCEDURE.equals(definitionHandle.getShapeByKey(innerEleKey.toString()).getString("name")))
|
||||
.filter(innerEleKey -> definitionHandle.getShapeByKey(innerEleKey.toString()).containsKey(SubProcessConst.SHAPE_PROCEDURE_ATTR_MARK))
|
||||
.map(innerEleKey -> definitionHandle.getShapeByKey(innerEleKey.toString()))
|
||||
.collect(Collectors.toCollection(JSONArray::new));
|
||||
|
||||
// 3、找到当前节点的所有前置连线
|
||||
JSONArray leadNodeLinkers = linkers
|
||||
.stream()
|
||||
.filter(l -> shapeId.equals(((JSONObject) l).getJSONObject("to").getString("id")))
|
||||
.collect(Collectors.toCollection(JSONArray::new));
|
||||
// 3.1、判断当前展开的子流程节点的内部元素中的流程接口上的文件标识 是否存在 前置子流程节点所代表的子流程文件 如果有将当前前置连线转为 与内部流程接口相连
|
||||
for (Object o1 : leadNodeLinkers) {
|
||||
JSONObject leadNodeLinker = (JSONObject) o1;
|
||||
String leadNodeId = leadNodeLinker.getJSONObject("from").getString("id");
|
||||
ElementType leadNodeType = definitionHandle.getElementTypeByKey(leadNodeId);
|
||||
JSONObject leadNode = definitionHandle.getShapeByKey(leadNodeId);
|
||||
if (procedureArr.size() > 0){ // 范围框内部存在前置或者后置流程接口
|
||||
// 判断当前前置节点的类型 如果未展开 继续判断内部节点是否与其有关联 如果有重新渲染连线 没有不处理
|
||||
if (leadNodeType.name().equals(ElementType.OUTER_NODE.name()) || leadNodeType.name().equals(ElementType.SCOPE_NODE.name())){
|
||||
// 获取前置节点的扩展属性
|
||||
JSONObject extendAttr = leadNode.getJSONObject(SubProcessConst.EXTEND_ATTR);
|
||||
// 当前前置节点 所代表的子流程文件ID
|
||||
String leadNodeRelationId = extendAttr.getString("id");
|
||||
// 1、未展开 子流程节点
|
||||
// 2、此时前置节点为范围框 同时说明之前范围框内部没有节点与当前节点有关联关系
|
||||
// 判断当前节点内部是否有流程接口 与范围框有关联关系 因为范围框本身也是一个文件
|
||||
for (Object o2 : procedureArr) {
|
||||
JSONObject procedure = (JSONObject) o2;
|
||||
JSONObject attrMark = procedure.getJSONObject(SubProcessConst.SHAPE_PROCEDURE_ATTR_MARK);
|
||||
String procedureNodeRelationId = attrMark.getString("id");
|
||||
if (leadNodeRelationId.equals(procedureNodeRelationId)){ // 前置节点与内部流程接口有关联关系
|
||||
// 删除当前 前置节点与范围框上的连线
|
||||
definitionHandle.removeShape(leadNodeLinker.getString("id"));
|
||||
// 重新渲染当前 前置节点与范围框的连线
|
||||
String procedureId = procedure.getString("id");
|
||||
double[] fromBounding = new double[]{definitionHandle.getShapeX(leadNodeId), definitionHandle.getShapeY(leadNodeId), definitionHandle.getShapeW(leadNodeId), definitionHandle.getShapeH(leadNodeId)};
|
||||
double[] toBounding = new double[]{definitionHandle.getShapeX(procedureId), definitionHandle.getShapeY(procedureId), definitionHandle.getShapeW(procedureId), definitionHandle.getShapeH(procedureId)};
|
||||
JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, leadNodeId, procedureId, fromBounding, toBounding);
|
||||
// 连线属于内外交叉连线 加个特殊标识属性
|
||||
linker.put("elementType", ElementType.CROSS_LINKER.name());
|
||||
definitionHandle.addEle(linker.getString("id"), linker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else { // 已展开 内部节点
|
||||
// 此时前置节点为某一个范围框的内部节点 找到当前内部节点归属哪个范围框 判断当前范围框是否与当前展开的内部流程接口有关联
|
||||
String scopeShapeId = leadNode.getString("scopeShapeId");
|
||||
for (Object o2 : procedureArr) {
|
||||
JSONObject procedure = (JSONObject) o2;
|
||||
JSONObject attrMark = procedure.getJSONObject(SubProcessConst.SHAPE_PROCEDURE_ATTR_MARK);
|
||||
String procedureNodeRelationId = attrMark.getString("id");
|
||||
if (procedureNodeRelationId.equals(scopeShapeId)){ // 前置内部节点所在的范围框 与 内部流程接口有关联关系
|
||||
String procedureId = procedure.getString("id");
|
||||
double[] fromBounding = new double[]{definitionHandle.getShapeX(scopeShapeId), definitionHandle.getShapeY(scopeShapeId), definitionHandle.getShapeW(scopeShapeId), definitionHandle.getShapeH(scopeShapeId)};
|
||||
double[] toBounding = new double[]{definitionHandle.getShapeX(procedureId), definitionHandle.getShapeY(procedureId), definitionHandle.getShapeW(procedureId), definitionHandle.getShapeH(procedureId)};
|
||||
JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, scopeShapeId, procedureId, fromBounding, toBounding);
|
||||
// 连线属于内外交叉连线 加个特殊标识属性
|
||||
linker.put("elementType", ElementType.CROSS_LINKER.name());
|
||||
definitionHandle.addEle(linker.getString("id"), linker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 4、根据后置连线找到后置子流程节点
|
||||
JSONArray rearNodeLinkers = linkers
|
||||
.stream()
|
||||
.filter(l -> shapeId.equals(((JSONObject) l).getJSONObject("from").getString("id")))
|
||||
.collect(Collectors.toCollection(JSONArray::new));
|
||||
// 4.1、同3.1
|
||||
for (Object o1 : rearNodeLinkers) {
|
||||
JSONObject rearNodeLinker = (JSONObject) o1;
|
||||
String rearNodeId = rearNodeLinker.getJSONObject("to").getString("id");
|
||||
ElementType rearNodeType = definitionHandle.getElementTypeByKey(rearNodeId);
|
||||
JSONObject rearNode = definitionHandle.getShapeByKey(rearNodeId);
|
||||
if (procedureArr.size() > 0){ // 范围框内部存在前置或者后置流程接口
|
||||
if (rearNodeType.name().equals(ElementType.OUTER_NODE.name()) || rearNodeType.name().equals(ElementType.SCOPE_NODE.name())){
|
||||
JSONObject extendAttr = rearNode.getJSONObject(SubProcessConst.EXTEND_ATTR);
|
||||
// 当前后置节点 所代表的子流程文件ID
|
||||
String rearNodeRelationId = extendAttr.getString("id");
|
||||
for (Object o2 : procedureArr) {
|
||||
JSONObject procedure = (JSONObject) o2;
|
||||
JSONObject attrMark = procedure.getJSONObject(SubProcessConst.SHAPE_PROCEDURE_ATTR_MARK);
|
||||
String procedureNodeRelationId = attrMark.getString("id");
|
||||
if (rearNodeRelationId.equals(procedureNodeRelationId)){ // 后置节点与内部流程接口有关联关系
|
||||
definitionHandle.removeShape(rearNodeLinker.getString("id"));
|
||||
// 重新渲染当前 前置节点与范围框的连线
|
||||
String procedureId = procedure.getString("id");
|
||||
double[] fromBounding = new double[]{definitionHandle.getShapeX(procedureId), definitionHandle.getShapeY(procedureId), definitionHandle.getShapeW(procedureId), definitionHandle.getShapeH(procedureId)};
|
||||
double[] toBounding = new double[]{definitionHandle.getShapeX(rearNodeId), definitionHandle.getShapeY(rearNodeId), definitionHandle.getShapeW(rearNodeId), definitionHandle.getShapeH(rearNodeId)};
|
||||
JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, procedureId, rearNodeId, fromBounding, toBounding);
|
||||
// 连线属于内外交叉连线 加个特殊标识属性
|
||||
linker.put("elementType", ElementType.CROSS_LINKER.name());
|
||||
definitionHandle.addEle(linker.getString("id"), linker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else {
|
||||
// 此时后置节点为某一个范围框的内部节点 找到当前内部节点归属哪个范围框 判断当前范围框是否与当前展开的内部流程接口有关联
|
||||
String scopeShapeId = rearNode.getString("scopeShapeId");
|
||||
for (Object o2 : procedureArr) {
|
||||
JSONObject procedure = (JSONObject) o2;
|
||||
JSONObject attrMark = procedure.getJSONObject(SubProcessConst.SHAPE_PROCEDURE_ATTR_MARK);
|
||||
String procedureNodeRelationId = attrMark.getString("id");
|
||||
if (procedureNodeRelationId.equals(scopeShapeId)){ // 前置内部节点所在的范围框 与 内部流程接口有关联关系
|
||||
String procedureId = procedure.getString("id");
|
||||
double[] fromBounding = new double[]{definitionHandle.getShapeX(procedureId), definitionHandle.getShapeY(procedureId), definitionHandle.getShapeW(procedureId), definitionHandle.getShapeH(procedureId)};
|
||||
double[] toBounding = new double[]{definitionHandle.getShapeX(scopeShapeId), definitionHandle.getShapeY(scopeShapeId), definitionHandle.getShapeW(scopeShapeId), definitionHandle.getShapeH(scopeShapeId)};
|
||||
JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, procedureId, scopeShapeId, fromBounding, toBounding);
|
||||
// 连线属于内外交叉连线 加个特殊标识属性
|
||||
linker.put("elementType", ElementType.CROSS_LINKER.name());
|
||||
definitionHandle.addEle(linker.getString("id"), linker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 针对闭合的节点相关连线 后置处理
|
||||
*/
|
||||
public void closeShapeLinkerConvertHandle(){
|
||||
// JSONObject subProcessNode = definitionHandle.getShapeByKey(shapeId);
|
||||
// JSONObject extendAttr = subProcessNode.getJSONObject(SubProcessConst.EXTEND_ATTR);
|
||||
// JSONArray linkers = definitionHandle.getLinkers();
|
||||
// // 当前节点的前置节点
|
||||
// JSONArray leadNodeArr = extendAttr.getJSONArray("leadNodeArr");
|
||||
// if (leadNodeArr.size() > 0){
|
||||
// for (Object o : leadNodeArr) {
|
||||
// String leadNodeId = (String) o;
|
||||
// Set<String> linkerIds = linkers.stream()
|
||||
// .filter(l -> ((JSONObject) l).getJSONObject("from").getString("id").equals(leadNodeId) && ((JSONObject) l).getJSONObject("to").getString("id").equals(shapeId))
|
||||
// .map(l -> ((JSONObject) l).getString("id"))
|
||||
// .collect(Collectors.toSet());
|
||||
// if (linkerIds.size() > 0){
|
||||
// for (String linkerId : linkerIds) {
|
||||
// definitionHandle.removeShape(linkerId);
|
||||
// }
|
||||
// }
|
||||
// // 生成连线
|
||||
// double[] fromBounding = new double[]{definitionHandle.getShapeX(leadNodeId), definitionHandle.getShapeY(leadNodeId), definitionHandle.getShapeW(leadNodeId), definitionHandle.getShapeH(leadNodeId)};
|
||||
// double[] toBounding = new double[]{definitionHandle.getShapeX(shapeId), definitionHandle.getShapeY(shapeId), definitionHandle.getShapeW(shapeId), definitionHandle.getShapeH(shapeId)};
|
||||
// JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, leadNodeId, shapeId, fromBounding, toBounding);
|
||||
//
|
||||
// linker.put("elementType", ElementType.OUTER_LINKER.name());
|
||||
// definitionHandle.addEle(linker.getString("id"), linker);
|
||||
// }
|
||||
// }
|
||||
// // 当前节点的后置节点
|
||||
// JSONArray rearNodeArr = extendAttr.getJSONArray("rearNodeArr");
|
||||
// if (rearNodeArr.size() > 0){
|
||||
// for (Object o : rearNodeArr) {
|
||||
// String rearNodeId = (String) o;
|
||||
// Set<String> linkerIds = linkers.stream()
|
||||
// .filter(l -> ((JSONObject) l).getJSONObject("from").getString("id").equals(shapeId) && ((JSONObject) l).getJSONObject("to").getString("id").equals(rearNodeId))
|
||||
// .map(l -> ((JSONObject) l).getString("id"))
|
||||
// .collect(Collectors.toSet());
|
||||
// if (linkerIds.size() > 0){
|
||||
// for (String linkerId : linkerIds) {
|
||||
// definitionHandle.removeShape(linkerId);
|
||||
// }
|
||||
// }
|
||||
// // 生成连线
|
||||
// double[] fromBounding = new double[]{definitionHandle.getShapeX(shapeId), definitionHandle.getShapeY(shapeId), definitionHandle.getShapeW(shapeId), definitionHandle.getShapeH(shapeId)};
|
||||
// double[] toBounding = new double[]{definitionHandle.getShapeX(rearNodeId), definitionHandle.getShapeY(rearNodeId), definitionHandle.getShapeW(rearNodeId), definitionHandle.getShapeH(rearNodeId)};
|
||||
// JSONObject linker = linkerPointCalculationHandle.toAssembleLinker(direction, shapeId, rearNodeId, fromBounding, toBounding);
|
||||
//
|
||||
// linker.put("elementType", ElementType.OUTER_LINKER.name());
|
||||
// definitionHandle.addEle(linker.getString("id"), linker);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
@ -130,10 +130,10 @@ public class GraphLayout {
|
||||
this.canvasHeight = h + 200.0;
|
||||
|
||||
// 打印节点坐标与画布大小
|
||||
System.out.printf("画布(%.2f, %.2f)", canvasWidth, canvasHeight);
|
||||
for (int i = 0; i < position.length; i++) {
|
||||
System.out.printf("坐标(%.2f, %.2f)", position[i][0], position[i][1]);
|
||||
}
|
||||
// System.out.printf("画布(%.2f, %.2f)", canvasWidth, canvasHeight);
|
||||
// for (int i = 0; i < position.length; i++) {
|
||||
// System.out.printf("坐标(%.2f, %.2f)", position[i][0], position[i][1]);
|
||||
// }
|
||||
|
||||
return position;
|
||||
}
|
||||
@ -205,10 +205,10 @@ public class GraphLayout {
|
||||
this.canvasHeight = h + 200.0;
|
||||
|
||||
// 打印节点坐标与画布大小
|
||||
System.out.printf("画布(%.2f, %.2f)", canvasWidth, canvasHeight);
|
||||
for (int i = 0; i < position.length; i++) {
|
||||
System.out.printf("坐标(%.2f, %.2f)", position[i][0], position[i][1]);
|
||||
}
|
||||
// System.out.printf("画布(%.2f, %.2f)", canvasWidth, canvasHeight);
|
||||
// for (int i = 0; i < position.length; i++) {
|
||||
// System.out.printf("坐标(%.2f, %.2f)", position[i][0], position[i][1]);
|
||||
// }
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
@ -7,23 +7,19 @@ import com.actionsoft.apps.coe.method.process.subprocess.graph.component.Abstrac
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.util.DefinitionThreadUnSafe;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.util.SubProcessNodeDefineUtil;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.util.ScopeShapeMonitor;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.observers.node.NodeSubject;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.cache.PALRepositoryCache;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.designer.manage.CoeDesignerAPIManager;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.designer.model.BaseModel;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.cache.DesignerShapeRelationCache;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.model.DesignerShapeRelationModel;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.designer.util.ShapeUtil;
|
||||
import com.actionsoft.bpms.util.ConsolePrinter;
|
||||
import com.actionsoft.bpms.util.UUIDGener;
|
||||
import com.actionsoft.bpms.util.UtilString;
|
||||
import com.actionsoft.exception.AWSException;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 图节点关闭处理
|
||||
@ -40,6 +36,8 @@ public class GraphNodeCloseHandle {
|
||||
private ScopeShapeMonitor scopeShapeMonitor; // 范围选择框及其内部元素监视器
|
||||
private NodeSubject nodeSubject; // 当前操作的节点主题类
|
||||
|
||||
private ExpandOrCloseShapeLinkerConvertHandle linkerConvertHandle; // 范围框内元素与外部元素连线处理器
|
||||
|
||||
public GraphNodeCloseHandle(String repositoryId, String shapeId, String endToEndProcessDefineStr) throws AWSException{
|
||||
this.repositoryId = repositoryId;
|
||||
this.shapeId = shapeId;
|
||||
@ -62,6 +60,8 @@ public class GraphNodeCloseHandle {
|
||||
nodeSubject = new NodeSubject(definitionHandle, scopeShapeMonitor, shapeId, "close");
|
||||
nodeSubject.buildObservers();
|
||||
|
||||
linkerConvertHandle = new ExpandOrCloseShapeLinkerConvertHandle(definitionHandle);
|
||||
|
||||
} catch (AWSException e) {
|
||||
throw new AWSException(e);
|
||||
}
|
||||
@ -74,15 +74,19 @@ public class GraphNodeCloseHandle {
|
||||
*/
|
||||
public String handleNodeClose() throws AWSException {
|
||||
|
||||
// 删除现有连线
|
||||
removeEndToEndGraphOldLinker();
|
||||
|
||||
// 1、处理范围选择框及其内部节点
|
||||
// 处理范围选择框及其内部节点
|
||||
removeScopeShapeAndInRangeEle();
|
||||
|
||||
// 2、处理总图中的节点与连线
|
||||
// 处理总图中的节点与连线
|
||||
handleEndToEndGraphNodeAndLinker();
|
||||
|
||||
scopeShapeMonitor.updateScopeShapeInnerEle();
|
||||
|
||||
linkerConvertHandle.scopeShapeLinkerHandle();
|
||||
|
||||
return definitionHandle.getDefine().toJSONString();
|
||||
}
|
||||
|
||||
@ -91,22 +95,27 @@ public class GraphNodeCloseHandle {
|
||||
JSONObject subProcessNode = buildSubProcessNode(shapeId, scopeLimitationShape);
|
||||
definitionHandle.addEle(shapeId, subProcessNode);
|
||||
|
||||
// 范围框闭合 将扩展属性复制到新的子流程节点上
|
||||
subProcessNode.put(SubProcessConst.EXTEND_ATTR, scopeLimitationShape.getJSONObject(SubProcessConst.EXTEND_ATTR));
|
||||
|
||||
// 通知其它节点位置更新
|
||||
nodeSubject.setScopeW(subProcessNode.getJSONObject("props").getDoubleValue("w"));
|
||||
nodeSubject.setScopeH(subProcessNode.getJSONObject("props").getDoubleValue("h"));
|
||||
|
||||
// 2、根据现有连线关系创建邻接矩阵
|
||||
NodeCloseAdjMatrix closeAdjMatrix = buildEndToEndGraphAdjMatrix();
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
List<JSONObject> nodeList = elements.keySet().stream()
|
||||
.filter(key -> definitionHandle.getElementTypeByKey(key).name().equals(ElementType.OUTER_NODE.name()) || definitionHandle.getElementTypeByKey(key).name().equals(ElementType.SCOPE_NODE.name()))
|
||||
.map(key -> definitionHandle.getShapeByKey(key))
|
||||
.collect(Collectors.toList());
|
||||
NodeCloseAdjMatrix closeAdjMatrix = new NodeCloseAdjMatrix(nodeList);
|
||||
closeAdjMatrix.buildAdjMatrix();
|
||||
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
// 更新因节点展开后 坐标发生变化的节点坐标
|
||||
String direction = definitionHandle.getProcessProperties().getString("direction");
|
||||
// graphPartNodePoiRenderAgain(elements, direction, subProcessNode);
|
||||
// 3、收集现有元素坐标
|
||||
double[][] vertexBounding = closeAdjMatrix.getVertexBounding(elements);
|
||||
// 4、删除现有连线
|
||||
removeEndToEndGraphOldLinker();
|
||||
|
||||
// 5、构建新的连线
|
||||
NodeCloseLinkerRender linkerRender = new NodeCloseLinkerRender(vertexBounding, closeAdjMatrix, definitionHandle);
|
||||
JSONArray linkers = linkerRender.toAssembleLinker(direction);
|
||||
@ -126,76 +135,6 @@ public class GraphNodeCloseHandle {
|
||||
page.put("height", h + 300);
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点闭合 部分节点坐标再次更新
|
||||
*/
|
||||
private void graphPartNodePoiRenderAgain(JSONObject elements, String direction, JSONObject subProcessNode){
|
||||
// 闭合节点的位置 及大小
|
||||
JSONObject props = subProcessNode.getJSONObject("props");
|
||||
double x = props.getDoubleValue("x");
|
||||
double y = props.getDoubleValue("y");
|
||||
|
||||
// 当前关闭的节点范围标识框的位置与大小
|
||||
double[] scope = SubProcessNodeDefineUtil.calculateSubProcessNodeExpandScope(subProcessNodeDefineHandle);
|
||||
|
||||
// double[] scopeShapeBounding = new double[]{x, y, scope[2], scope[3]};
|
||||
|
||||
// boolean yIsMove = checkShapeYIsMove(elements, scopeShapeBounding);
|
||||
|
||||
for (String key : elements.keySet()) {
|
||||
JSONObject ele = elements.getJSONObject(key);
|
||||
if ("linker".equals(ele.getString("name"))) continue;
|
||||
if (ele.getString("id").equals(subProcessNode.getString("id"))) continue;
|
||||
if (scopeShapeMonitor.checkShapeIsScopeInRange(key)) continue;
|
||||
JSONObject eleProps = ele.getJSONObject("props");
|
||||
if ("vertically".equals(direction)){ // 垂直布局
|
||||
if (x + scope[2] < eleProps.getDoubleValue("x")) {
|
||||
double xMoveDistance = -scope[2] + SubProcessConst.SUB_PROCESS_SHAPE_W;
|
||||
eleProps.put("x", eleProps.getDoubleValue("x") - scope[2] + SubProcessConst.SUB_PROCESS_SHAPE_W);
|
||||
if (scopeShapeMonitor.checkShapeIsScopeShape(key)){
|
||||
scopeShapeMonitor.updateMonitorXInfo(key, true, xMoveDistance);
|
||||
}
|
||||
}
|
||||
if (y +scope[3] < eleProps.getDoubleValue("y")){
|
||||
double yMoveDistance = -scope[3] + SubProcessConst.SUB_PROCESS_SHAPE_H;
|
||||
eleProps.put("y", eleProps.getDoubleValue("y") - scope[3] + SubProcessConst.SUB_PROCESS_SHAPE_H);
|
||||
if (scopeShapeMonitor.checkShapeIsScopeShape(key)){
|
||||
scopeShapeMonitor.updateMonitorYInfo(key, true, yMoveDistance);
|
||||
}
|
||||
}else if (y < eleProps.getDoubleValue("y") && eleProps.getDoubleValue("y") < y + scope[3]){
|
||||
eleProps.put("y", y);
|
||||
double yMoveDistance = y - eleProps.getDoubleValue("y");
|
||||
if (scopeShapeMonitor.checkShapeIsScopeShape(key)){
|
||||
scopeShapeMonitor.updateMonitorYInfo(key, true, yMoveDistance);
|
||||
}
|
||||
}
|
||||
}else { // 横向布局
|
||||
if (x + scope[2] < eleProps.getDoubleValue("x")){ // 节点在范围框右侧的节点
|
||||
double xMoveDistance = -scope[2] + SubProcessConst.SUB_PROCESS_SHAPE_W;
|
||||
eleProps.put("x", eleProps.getDoubleValue("x") - scope[2] + SubProcessConst.SUB_PROCESS_SHAPE_W);
|
||||
if (scopeShapeMonitor.checkShapeIsScopeShape(key)){
|
||||
scopeShapeMonitor.updateMonitorXInfo(key, true, xMoveDistance);
|
||||
}
|
||||
}else if (x < eleProps.getDoubleValue("x")
|
||||
&& eleProps.getDoubleValue("x") < x + scope[2]
|
||||
&& y + scope[3] < eleProps.getDoubleValue("y")){
|
||||
double xMoveDistance = x - eleProps.getDoubleValue("x");
|
||||
eleProps.put("x", x);
|
||||
if (scopeShapeMonitor.checkShapeIsScopeShape(key)){
|
||||
scopeShapeMonitor.updateMonitorXInfo(key, true, xMoveDistance);
|
||||
}
|
||||
}
|
||||
if (y + scope[3] < eleProps.getDoubleValue("y")){ // 节点在范围框下方的节点
|
||||
double yMoveDistance = -scope[3] + SubProcessConst.SUB_PROCESS_SHAPE_H;
|
||||
eleProps.put("y", eleProps.getDoubleValue("y") - scope[3] + SubProcessConst.SUB_PROCESS_SHAPE_H);
|
||||
if (scopeShapeMonitor.checkShapeIsScopeShape(key)){
|
||||
scopeShapeMonitor.updateMonitorYInfo(key, true, yMoveDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在节点闭合的时候 检查当前闭合的节点的下方节点是否需要上下移动
|
||||
* @param elements
|
||||
@ -251,41 +190,15 @@ public class GraphNodeCloseHandle {
|
||||
*/
|
||||
private void removeEndToEndGraphOldLinker(){
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
Set<String> eleKeys = new HashSet<>();
|
||||
for (String key : elements.keySet()) {
|
||||
JSONObject ele = elements.getJSONObject(key);
|
||||
if ("linker".equals(ele.getString("name")) && !scopeShapeMonitor.checkShapeIsScopeInRange(key)){
|
||||
eleKeys.add(key);
|
||||
}
|
||||
}
|
||||
for (String eleKey : eleKeys) {
|
||||
Set<String> linkerIds = elements.keySet()
|
||||
.stream()
|
||||
.filter(key -> definitionHandle.getElementTypeByKey(key).equals(ElementType.OUTER_LINKER) || definitionHandle.getElementTypeByKey(key).equals(ElementType.CROSS_LINKER))
|
||||
.collect(Collectors.toSet());
|
||||
for (String eleKey : linkerIds) {
|
||||
definitionHandle.removeShape(eleKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建节点展开前 端到端总图的邻接矩阵
|
||||
* 方便后续节点展开或者闭合进行重新连线
|
||||
*/
|
||||
private NodeCloseAdjMatrix buildEndToEndGraphAdjMatrix(){
|
||||
|
||||
List<String> nodeIdList = new ArrayList<>();
|
||||
List<JSONObject> linkerList = new ArrayList<>();
|
||||
JSONObject endToEndProcessElements = definitionHandle.getElements();
|
||||
for (String key : endToEndProcessElements.keySet()) {
|
||||
if (scopeShapeMonitor.checkShapeIsScopeInRange(key)) continue;
|
||||
JSONObject ele = endToEndProcessElements.getJSONObject(key);
|
||||
if ("linker".equals(ele.getString("name"))) {
|
||||
linkerList.add(ele);
|
||||
}else {
|
||||
nodeIdList.add(key);
|
||||
}
|
||||
}
|
||||
NodeCloseAdjMatrix closeAdjMatrix = new NodeCloseAdjMatrix(nodeIdList, linkerList);
|
||||
return closeAdjMatrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建子流程节点
|
||||
* @param shapeId
|
||||
@ -312,7 +225,8 @@ public class GraphNodeCloseHandle {
|
||||
*/
|
||||
private void removeScopeShapeAndInRangeEle(){
|
||||
|
||||
Set<String> keys = SubProcessNodeDefineUtil.getInScopeLimitationRangeEles(shapeId, definitionHandle, subProcessNodeDefineHandle);
|
||||
JSONArray innerEleKeySet = scopeLimitationShape.getJSONArray(SubProcessConst.INNER_ELEMENTS);
|
||||
Set<String> keys = innerEleKeySet.stream().map(o -> o.toString()).collect(Collectors.toSet());
|
||||
for (String key : keys) {
|
||||
definitionHandle.removeShape(key);
|
||||
}
|
||||
@ -329,32 +243,42 @@ public class GraphNodeCloseHandle {
|
||||
class NodeCloseAdjMatrix extends AbstractAdjMatrix {
|
||||
|
||||
private List<String> nodeIds;
|
||||
private List<JSONObject> linkerList;
|
||||
private List<JSONObject> nodeList; // 当前画布中所有子流程节点以及范围框节点 不包含内部节点与连线
|
||||
|
||||
public NodeCloseAdjMatrix(List<String> nodeIds, List<JSONObject> linkerList) {
|
||||
super(nodeIds.size());
|
||||
this.nodeIds = nodeIds;
|
||||
this.linkerList = linkerList;
|
||||
public NodeCloseAdjMatrix(List<JSONObject> nodeList) {
|
||||
super(nodeList.size());
|
||||
this.nodeList = nodeList;
|
||||
|
||||
this.nodeIds = nodeList.stream().map(o -> o.getString("id")).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<String> getNodeIds() {
|
||||
return nodeIds;
|
||||
}
|
||||
|
||||
public List<JSONObject> getLinkerList() {
|
||||
return linkerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建邻接矩阵
|
||||
*/
|
||||
public void buildAdjMatrix(){
|
||||
for (JSONObject linker : linkerList) {
|
||||
JSONObject from = linker.getJSONObject("from");
|
||||
JSONObject to = linker.getJSONObject("to");
|
||||
int fromIndex = nodeIds.indexOf(from.getString("id"));
|
||||
int toIndex = nodeIds.indexOf(to.getString("id"));
|
||||
addEdge(fromIndex, toIndex);
|
||||
for (JSONObject node : nodeList) {
|
||||
String currentNodeId = node.getString("id");
|
||||
JSONObject extendAttr = node.getJSONObject(SubProcessConst.EXTEND_ATTR);
|
||||
// 当前节点的前置节点
|
||||
JSONArray leadNodeArr = extendAttr.getJSONArray("leadNodeArr");
|
||||
if (leadNodeArr.size() > 0){
|
||||
for (Object o : leadNodeArr) {
|
||||
String leadNodeId = (String) o;
|
||||
addEdge(nodeIds.indexOf(leadNodeId), nodeIds.indexOf(currentNodeId));
|
||||
}
|
||||
}
|
||||
// 当前节点的后置节点
|
||||
JSONArray rearNodeArr = extendAttr.getJSONArray("rearNodeArr");
|
||||
if (rearNodeArr.size() > 0){
|
||||
for (Object o : rearNodeArr) {
|
||||
String rearNodeId = (String) o;
|
||||
addEdge(nodeIds.indexOf(currentNodeId), nodeIds.indexOf(rearNodeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,25 +7,20 @@ import com.actionsoft.apps.coe.method.process.subprocess.graph.component.Abstrac
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.util.DefinitionThreadUnSafe;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.util.SubProcessNodeDefineUtil;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.mode.Node;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.util.ScopeShapeMonitor;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.observers.node.NodeSubject;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.cache.PALRepositoryCache;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.designer.manage.CoeDesignerAPIManager;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.designer.model.BaseModel;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.cache.DesignerShapeRelationCache;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.model.DesignerShapeRelationModel;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.designer.util.CoeDesignerUtil;
|
||||
import com.actionsoft.apps.coe.pal.pal.repository.designer.util.ShapeUtil;
|
||||
import com.actionsoft.bpms.util.ConsolePrinter;
|
||||
import com.actionsoft.bpms.util.UUIDGener;
|
||||
import com.actionsoft.bpms.util.UtilString;
|
||||
import com.actionsoft.exception.AWSException;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 图节点展开处理
|
||||
@ -42,6 +37,8 @@ public class GraphNodeExpandHandle {
|
||||
private ScopeShapeMonitor scopeShapeMonitor; // 范围选择框及其内部元素监视器
|
||||
private NodeSubject nodeSubject; // 当前操作的节点主题类
|
||||
|
||||
private ExpandOrCloseShapeLinkerConvertHandle linkerConvertHandle; // 范围框内元素与外部元素连线处理器
|
||||
|
||||
private double[] scopeLimitationShapeBeforePoi; // 范围选择框在子流程文件中的坐标
|
||||
|
||||
public GraphNodeExpandHandle(String repositoryId, String shapeId, String endToEndProcessDefineStr) throws AWSException{
|
||||
@ -58,12 +55,13 @@ public class GraphNodeExpandHandle {
|
||||
subProcessNodeDefineHandle = new DefinitionThreadUnSafe(SubProcessNodeDefineUtil.readSubProcessNodeDefine(repositoryId, shapeId));
|
||||
|
||||
scopeShapeMonitor = new ScopeShapeMonitor(definitionHandle);
|
||||
// 1、构建范围框监视器模型 并关联内部元素
|
||||
scopeShapeMonitor.buildScopeShapeMonitors();
|
||||
|
||||
nodeSubject = new NodeSubject(definitionHandle, scopeShapeMonitor, shapeId, "expand");
|
||||
nodeSubject.buildObservers();
|
||||
|
||||
linkerConvertHandle = new ExpandOrCloseShapeLinkerConvertHandle(definitionHandle);
|
||||
|
||||
toAssembleScopeLimitationShape();
|
||||
} catch (Exception e) {
|
||||
throw new AWSException(e);
|
||||
@ -113,6 +111,9 @@ public class GraphNodeExpandHandle {
|
||||
minRange.put("y2", y + scope[3]);
|
||||
scopeLimitationShape.put("minRange", minRange);
|
||||
|
||||
// 扩展属性 extendAttr 存储的是关联的文件信息
|
||||
scopeLimitationShape.put(SubProcessConst.EXTEND_ATTR, currentExpandShape.getJSONObject(SubProcessConst.EXTEND_ATTR));
|
||||
|
||||
this.scopeLimitationShape = scopeLimitationShape;
|
||||
|
||||
// 通知其它节点位置更新
|
||||
@ -128,15 +129,17 @@ public class GraphNodeExpandHandle {
|
||||
*/
|
||||
public String handleNodeExpand() throws AWSException{
|
||||
|
||||
// 2、总图节点以及连线处理
|
||||
// 总图节点以及连线处理
|
||||
handleEndToEndGraphNodeAndLinker();
|
||||
|
||||
// 3、当前展开的子流程节点内部元素 以及 范围框处理
|
||||
// 当前展开的子流程节点内部元素 以及 范围框处理
|
||||
handleRelationModelNodePosition();
|
||||
|
||||
// 4、范围框内的元素 坐标更新
|
||||
// 当前节点展开前已存在的其它范围框内的元素 坐标更新
|
||||
scopeShapeMonitor.updateScopeShapeInnerEle();
|
||||
|
||||
linkerConvertHandle.scopeShapeLinkerHandle();
|
||||
|
||||
return definitionHandle.getDefine().toJSONString();
|
||||
}
|
||||
|
||||
@ -157,17 +160,20 @@ public class GraphNodeExpandHandle {
|
||||
// 2、添加到总图中
|
||||
definitionHandle.addEle(shapeId, scopeLimitationShape);
|
||||
|
||||
// 3、总图中符合范围选择框条件的节点 坐标更新
|
||||
// handleEndToEndGraphNodeExcluedExpandNode();
|
||||
|
||||
// 4、构建邻接矩阵
|
||||
NodeExpandAdjMatrix expandAdjMatrix = buildEndToEndGraphAdjMatrix();
|
||||
expandAdjMatrix.buildAdjMatrix();
|
||||
// expandAdjMatrix.printAdjMatrix();
|
||||
// 5、删除节点展开前的连线
|
||||
removeEndToEndGraphOldLinker();
|
||||
// 6、获取所有节点坐标
|
||||
|
||||
// 4、构建邻接矩阵
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
List<JSONObject> nodeList = elements.keySet().stream()
|
||||
.filter(key -> definitionHandle.getElementTypeByKey(key).name().equals(ElementType.OUTER_NODE.name()) || definitionHandle.getElementTypeByKey(key).name().equals(ElementType.SCOPE_NODE.name()))
|
||||
.map(key -> definitionHandle.getShapeByKey(key))
|
||||
.collect(Collectors.toList());
|
||||
NodeExpandAdjMatrix expandAdjMatrix = new NodeExpandAdjMatrix(nodeList);
|
||||
|
||||
expandAdjMatrix.buildAdjMatrix();
|
||||
|
||||
// 6、获取所有节点坐标
|
||||
double[][] vertexBounding = expandAdjMatrix.getVertexBounding(elements);
|
||||
// 7、构建新的连线
|
||||
JSONObject processProperties = definitionHandle.getProcessProperties();
|
||||
@ -204,6 +210,7 @@ public class GraphNodeExpandHandle {
|
||||
|
||||
// 根据范围标注框的坐标 调整子流程所有元素的坐标
|
||||
JSONObject elements = subProcessNodeDefineHandle.getElements();
|
||||
JSONArray innerEleKeyArr = new JSONArray();
|
||||
for (String key : elements.keySet()) {
|
||||
JSONObject ele = elements.getJSONObject(key);
|
||||
// 元素分为两类 一类为图形 一类为连线
|
||||
@ -231,8 +238,15 @@ public class GraphNodeExpandHandle {
|
||||
ele.put("elementType", ElementType.INNER_NODE.name());
|
||||
}
|
||||
|
||||
// 指向范围框
|
||||
ele.put("scopeShapeId", scopeLimitationShape.getString("id"));
|
||||
|
||||
// 存入内部元素
|
||||
innerEleKeyArr.add(key);
|
||||
|
||||
definitionHandle.addEle(key, ele);
|
||||
}
|
||||
scopeLimitationShape.put(SubProcessConst.INNER_ELEMENTS, innerEleKeyArr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -324,41 +338,16 @@ public class GraphNodeExpandHandle {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建节点展开前 端到端总图的邻接矩阵
|
||||
* 方便后续节点展开或者闭合进行重新连线
|
||||
*/
|
||||
private NodeExpandAdjMatrix buildEndToEndGraphAdjMatrix(){
|
||||
|
||||
List<String> nodeIdList = new ArrayList<>();
|
||||
List<JSONObject> linkerList = new ArrayList<>();
|
||||
JSONObject endToEndProcessElements = definitionHandle.getElements();
|
||||
for (String key : endToEndProcessElements.keySet()) {
|
||||
if (scopeShapeMonitor.checkShapeIsScopeInRange(key)) continue; // 范围框内的元素 暂不处理
|
||||
JSONObject ele = endToEndProcessElements.getJSONObject(key);
|
||||
if ("linker".equals(ele.getString("name"))) {
|
||||
linkerList.add(ele);
|
||||
}else {
|
||||
nodeIdList.add(key);
|
||||
}
|
||||
}
|
||||
NodeExpandAdjMatrix expandAdjMatrix = new NodeExpandAdjMatrix(nodeIdList, linkerList);
|
||||
return expandAdjMatrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除总图中节点展开前的连线
|
||||
*/
|
||||
private void removeEndToEndGraphOldLinker(){
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
Set<String> eleKeys = new HashSet<>();
|
||||
for (String key : elements.keySet()) {
|
||||
JSONObject ele = elements.getJSONObject(key);
|
||||
if ("linker".equals(ele.getString("name")) && !scopeShapeMonitor.checkShapeIsScopeInRange(key)){
|
||||
eleKeys.add(key);
|
||||
}
|
||||
}
|
||||
for (String eleKey : eleKeys) {
|
||||
Set<String> linkerIds = elements.keySet()
|
||||
.stream()
|
||||
.filter(key -> definitionHandle.getElementTypeByKey(key).equals(ElementType.OUTER_LINKER) || definitionHandle.getElementTypeByKey(key).equals(ElementType.CROSS_LINKER))
|
||||
.collect(Collectors.toSet());
|
||||
for (String eleKey : linkerIds) {
|
||||
definitionHandle.removeShape(eleKey);
|
||||
}
|
||||
}
|
||||
@ -380,32 +369,42 @@ public class GraphNodeExpandHandle {
|
||||
class NodeExpandAdjMatrix extends AbstractAdjMatrix {
|
||||
|
||||
private List<String> nodeIds;
|
||||
private List<JSONObject> linkerList;
|
||||
private List<JSONObject> nodeList; // 当前画布中所有子流程节点以及范围框节点 不包含内部节点与连线
|
||||
|
||||
public NodeExpandAdjMatrix(List<String> nodeIds, List<JSONObject> linkerList) {
|
||||
super(nodeIds.size());
|
||||
this.nodeIds = nodeIds;
|
||||
this.linkerList = linkerList;
|
||||
public NodeExpandAdjMatrix(List<JSONObject> nodeList) {
|
||||
super(nodeList.size());
|
||||
this.nodeList = nodeList;
|
||||
|
||||
this.nodeIds = nodeList.stream().map(o -> o.getString("id")).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<String> getNodeIds() {
|
||||
return nodeIds;
|
||||
}
|
||||
|
||||
public List<JSONObject> getLinkerList() {
|
||||
return linkerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建邻接矩阵
|
||||
*/
|
||||
public void buildAdjMatrix(){
|
||||
for (JSONObject linker : linkerList) {
|
||||
JSONObject from = linker.getJSONObject("from");
|
||||
JSONObject to = linker.getJSONObject("to");
|
||||
int fromIndex = nodeIds.indexOf(from.getString("id"));
|
||||
int toIndex = nodeIds.indexOf(to.getString("id"));
|
||||
addEdge(fromIndex, toIndex);
|
||||
for (JSONObject node : nodeList) {
|
||||
String currentNodeId = node.getString("id");
|
||||
JSONObject extendAttr = node.getJSONObject(SubProcessConst.EXTEND_ATTR);
|
||||
// 当前节点的前置节点
|
||||
JSONArray leadNodeArr = extendAttr.getJSONArray("leadNodeArr");
|
||||
if (leadNodeArr.size() > 0){
|
||||
for (Object o : leadNodeArr) {
|
||||
String leadNodeId = (String) o;
|
||||
addEdge(nodeIds.indexOf(leadNodeId), nodeIds.indexOf(currentNodeId));
|
||||
}
|
||||
}
|
||||
// 当前节点的后置节点
|
||||
JSONArray rearNodeArr = extendAttr.getJSONArray("rearNodeArr");
|
||||
if (rearNodeArr.size() > 0){
|
||||
for (Object o : rearNodeArr) {
|
||||
String rearNodeId = (String) o;
|
||||
addEdge(nodeIds.indexOf(currentNodeId), nodeIds.indexOf(rearNodeId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,10 +20,8 @@ import com.actionsoft.exception.AWSException;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GraphRender {
|
||||
|
||||
@ -79,6 +77,11 @@ public class GraphRender {
|
||||
subProcessNode.put("text", repositoryModel.getName());
|
||||
// 增加元素类型属性
|
||||
subProcessNode.put("elementType", ElementType.OUTER_NODE.name());
|
||||
// 增加关联文件的标识
|
||||
JSONObject extendAttr = new JSONObject();
|
||||
extendAttr.put("id", nodeList.get(i).getId());
|
||||
extendAttr.put("name", repositoryModel.getName());
|
||||
subProcessNode.put(SubProcessConst.EXTEND_ATTR, extendAttr);
|
||||
|
||||
// 处理子流程模型节点形状属性
|
||||
JSONArray dataAttributes = subProcessNode.getJSONArray("dataAttributes");
|
||||
@ -194,4 +197,41 @@ public class GraphRender {
|
||||
this.baseModel.setDefinition(defineJsonObj.toJSONString());
|
||||
CoeDesignerAPIManager.getInstance().storeDefinition(this.baseModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 依据生成后的总图的连线关系 在子流程节点属性中加入 前置节点与后置节点信息
|
||||
*/
|
||||
public void addLeadAndRearInfoToElements(){
|
||||
JSONObject defineJsonObj = JSONObject.parseObject(this.baseModel.getDefinition());
|
||||
JSONObject elements = defineJsonObj.getJSONObject("elements");
|
||||
|
||||
Set<String> subProcessNodeKeySet = elements.keySet().stream().filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name"))).collect(Collectors.toSet());
|
||||
for (String subProcessNodeKey : subProcessNodeKeySet) {
|
||||
JSONObject subProcessNode = elements.getJSONObject(subProcessNodeKey);
|
||||
JSONObject extendAttr = subProcessNode.getJSONObject(SubProcessConst.EXTEND_ATTR);
|
||||
|
||||
// 当前节点的前置节点
|
||||
JSONArray leadNodeKeyArr = elements.keySet().stream()
|
||||
.filter(key -> "linker".equals(elements.getJSONObject(key).getString("name")))
|
||||
.map(key -> elements.getJSONObject(key))
|
||||
.filter(l -> ((JSONObject)l).getJSONObject("to").getString("id").equals(subProcessNodeKey))
|
||||
.map(l -> ((JSONObject)l).getJSONObject("from").getString("id"))
|
||||
.collect(Collectors.toCollection(JSONArray::new));
|
||||
|
||||
extendAttr.put("leadNodeArr", leadNodeKeyArr);
|
||||
|
||||
// 当前节点的后置节点
|
||||
JSONArray rearNodeKeyArr = elements.keySet().stream()
|
||||
.filter(key -> "linker".equals(elements.getJSONObject(key).getString("name")))
|
||||
.map(key -> elements.getJSONObject(key))
|
||||
.filter(l -> ((JSONObject)l).getJSONObject("from").getString("id").equals(subProcessNodeKey))
|
||||
.map(l -> ((JSONObject)l).getJSONObject("to").getString("id"))
|
||||
.collect(Collectors.toCollection(JSONArray::new));
|
||||
|
||||
extendAttr.put("rearNodeArr", rearNodeKeyArr);
|
||||
}
|
||||
|
||||
this.baseModel.setDefinition(defineJsonObj.toJSONString());
|
||||
CoeDesignerAPIManager.getInstance().storeDefinition(this.baseModel);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.graph.component;
|
||||
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.constant.ElementType;
|
||||
import com.actionsoft.exception.AWSException;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author oYang
|
||||
* @Description TODO
|
||||
@ -99,9 +104,62 @@ public abstract class AbstractDefinitionHandle {
|
||||
*/
|
||||
public abstract void updateShapeH(String shapeKey, double h);
|
||||
|
||||
/**
|
||||
* 获取图形的 x坐标
|
||||
* @param shapeKey
|
||||
* @return
|
||||
*/
|
||||
public abstract double getShapeX(String shapeKey);
|
||||
|
||||
/**
|
||||
* 获取图形的 y坐标
|
||||
* @param shapeKey
|
||||
* @return
|
||||
*/
|
||||
public abstract double getShapeY(String shapeKey);
|
||||
|
||||
/**
|
||||
* 获取图形的 w宽度
|
||||
* @param shapeKey
|
||||
* @return
|
||||
*/
|
||||
public abstract double getShapeW(String shapeKey);
|
||||
|
||||
/**
|
||||
* 获取图形的 h高度
|
||||
* @param shapeKey
|
||||
* @return
|
||||
*/
|
||||
public abstract double getShapeH(String shapeKey);
|
||||
|
||||
/**
|
||||
* 获取所有连线
|
||||
* @return
|
||||
* @throws AWSException
|
||||
*/
|
||||
public abstract JSONArray getLinkers() throws AWSException;
|
||||
|
||||
/**
|
||||
* 获取指定的连线
|
||||
* @param key
|
||||
* @return
|
||||
* @throws AWSException
|
||||
*/
|
||||
public abstract JSONObject getLinkerByKey(String key) throws AWSException;
|
||||
|
||||
/**
|
||||
* 获取指定元素的元素类型
|
||||
* @param key
|
||||
* @return
|
||||
* @throws AWSException
|
||||
*/
|
||||
public abstract ElementType getElementTypeByKey(String key) throws AWSException;
|
||||
|
||||
/**
|
||||
* 获取元素类型为 SCOPE_NODE 的元素ID集合
|
||||
* @return
|
||||
* @throws AWSException
|
||||
*/
|
||||
public abstract List<String> getScopeNodeIds() throws AWSException;
|
||||
|
||||
}
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.graph.util;
|
||||
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.constant.ElementType;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle;
|
||||
import com.actionsoft.exception.AWSException;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author oYang
|
||||
@ -178,4 +183,61 @@ public class DefinitionThreadSafe extends AbstractDefinitionHandle {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray getLinkers() throws AWSException {
|
||||
lock.lock();
|
||||
try{
|
||||
JSONObject elements = getElements();
|
||||
JSONArray linkers = elements.keySet()
|
||||
.stream()
|
||||
.filter(key -> "linker".equals(elements.getJSONObject(key).getString("name")))
|
||||
.map(key -> elements.getJSONObject(key))
|
||||
.collect(Collectors.toCollection(JSONArray::new));
|
||||
return linkers;
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getLinkerByKey(String key) throws AWSException {
|
||||
lock.lock();
|
||||
try{
|
||||
JSONObject elements = getElements();
|
||||
JSONObject ele = elements.getJSONObject(key);
|
||||
if (!"linker".equals(ele.getString("name"))){
|
||||
throw new AWSException("不存在指定的连线");
|
||||
}
|
||||
return ele;
|
||||
}finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementType getElementTypeByKey(String key) throws AWSException {
|
||||
lock.lock();
|
||||
try {
|
||||
JSONObject ele = getShapeByKey(key);
|
||||
if (ele == null){
|
||||
throw new AWSException("不存在指定的元素");
|
||||
}
|
||||
return ElementType.valueOf(ele.getString("elementType"));
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getScopeNodeIds() throws AWSException {
|
||||
lock.lock();
|
||||
try {
|
||||
JSONObject elements = getElements();
|
||||
List<String> scopeShapeIds = elements.keySet().stream().filter(key -> elements.getJSONObject(key).getString("elementType").equals(ElementType.SCOPE_NODE.name())).collect(Collectors.toList());
|
||||
return scopeShapeIds;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,15 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.graph.util;
|
||||
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.constant.ElementType;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle;
|
||||
import com.actionsoft.exception.AWSException;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author oYang
|
||||
* @Description 操作 definition 工具类 线程不安全
|
||||
@ -98,4 +105,41 @@ public class DefinitionThreadUnSafe extends AbstractDefinitionHandle {
|
||||
public double getShapeH(String shapeKey) {
|
||||
return getShapeByProps(shapeKey).getDoubleValue("h");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray getLinkers() throws AWSException {
|
||||
JSONObject elements = getElements();
|
||||
JSONArray linkers = elements.keySet()
|
||||
.stream()
|
||||
.filter(key -> "linker".equals(elements.getJSONObject(key).getString("name")))
|
||||
.map(key -> elements.getJSONObject(key))
|
||||
.collect(Collectors.toCollection(JSONArray::new));
|
||||
return linkers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getLinkerByKey(String key) throws AWSException {
|
||||
JSONObject elements = getElements();
|
||||
JSONObject ele = elements.getJSONObject(key);
|
||||
if (!"linker".equals(ele.getString("name"))){
|
||||
throw new AWSException("不存在指定的连线");
|
||||
}
|
||||
return ele;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementType getElementTypeByKey(String key) throws AWSException {
|
||||
JSONObject ele = getShapeByKey(key);
|
||||
if (ele == null){
|
||||
throw new AWSException("不存在指定的元素");
|
||||
}
|
||||
return ElementType.valueOf(ele.getString("elementType"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getScopeNodeIds() throws AWSException {
|
||||
JSONObject elements = getElements();
|
||||
List<String> scopeShapeIds = elements.keySet().stream().filter(key -> elements.getJSONObject(key).getString("elementType").equals(ElementType.SCOPE_NODE.name())).collect(Collectors.toList());
|
||||
return scopeShapeIds;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.graph.util;
|
||||
|
||||
/**
|
||||
* @author oYang
|
||||
* @Description TODO
|
||||
* @createTime 2023年06月09日 16:26:00
|
||||
*/
|
||||
public class GraphNodeCloseUtil {
|
||||
}
|
||||
@ -0,0 +1,452 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.graph.util;
|
||||
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.constant.LinkerDefConstant;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle;
|
||||
import com.actionsoft.bpms.util.ConsolePrinter;
|
||||
import com.actionsoft.bpms.util.UUIDGener;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author oYang
|
||||
* @Description 连线上所有关键节点(包括起始点以及折点)计算处理
|
||||
* 类比起始图形作为直角坐标系的原点 目标图形的位置大体在四个象限内
|
||||
* @createTime 2023年06月28日 17:56:00
|
||||
*/
|
||||
public class LinkerPointCalculationHandle {
|
||||
|
||||
private AbstractDefinitionHandle definitionHandle;
|
||||
|
||||
public LinkerPointCalculationHandle(AbstractDefinitionHandle definitionHandle) {
|
||||
this.definitionHandle = definitionHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据布局方向 组装连线
|
||||
* @param direction 布局方向
|
||||
* @param fromId 起点节点ID
|
||||
* @param toId 终点节点ID
|
||||
* @param fromBounding 起点节点边框信息
|
||||
* @param toBounding 终点节点边框信息
|
||||
* @return
|
||||
*/
|
||||
public JSONObject toAssembleLinker(String direction, String fromId, String toId, double[] fromBounding, double[] toBounding){
|
||||
double[][] turnPoi = direction.equals(SubProcessConst.DIRECTION_H) ? horizLayOut(fromBounding, toBounding) : vertLayOut(fromBounding, toBounding);
|
||||
double[] angleArr = calculationLinkerAngle(turnPoi[0], turnPoi[turnPoi.length - 1], turnPoi[1], turnPoi[turnPoi.length - 2]);
|
||||
// 构建连线
|
||||
JSONObject linkerObj = JSONObject.parseObject(LinkerDefConstant.linker);
|
||||
linkerObj.put("id", UUIDGener.getObjectId());
|
||||
// 折点
|
||||
JSONArray points = new JSONArray();
|
||||
for (int j = 0; j < turnPoi.length; j++) {
|
||||
if (j > 0 && j < turnPoi.length - 1){
|
||||
JSONObject pointObj = new JSONObject();
|
||||
pointObj.put("x", turnPoi[j][0]);
|
||||
pointObj.put("y", turnPoi[j][1]);
|
||||
points.add(pointObj);
|
||||
}
|
||||
}
|
||||
linkerObj.put("points", points);
|
||||
// 起点与终点
|
||||
JSONObject fromObj = new JSONObject();
|
||||
fromObj.put("x", turnPoi[0][0]);
|
||||
fromObj.put("y", turnPoi[0][1]);
|
||||
fromObj.put("angle", angleArr[0]);
|
||||
fromObj.put("id", fromId);
|
||||
linkerObj.put("from", fromObj);
|
||||
JSONObject toObj = new JSONObject();
|
||||
toObj.put("x", turnPoi[turnPoi.length - 1][0]);
|
||||
toObj.put("y", turnPoi[turnPoi.length - 1][1]);
|
||||
toObj.put("angle", angleArr[1]);
|
||||
toObj.put("id", toId);
|
||||
linkerObj.put("to", toObj);
|
||||
|
||||
return linkerObj;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 节点水平布局下计算连线
|
||||
* @param fromBounding
|
||||
* @param toBounding
|
||||
* @return
|
||||
*/
|
||||
public double[][] horizLayOut(double[] fromBounding, double[] toBounding){
|
||||
double fromX = fromBounding[0],fromY = fromBounding[1], fromW = fromBounding[2], fromH = fromBounding[3];
|
||||
double toX = toBounding[0], toY = toBounding[1], toW = toBounding[2], toH = toBounding[3];
|
||||
if (fromY == toY) {
|
||||
return fromX < toX
|
||||
? new double[][]
|
||||
{
|
||||
{fromX + fromW, fromY + fromH / 2},
|
||||
{fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2},
|
||||
{toX - rowNodeDistanceWrapper(getNearLeftNodeDistance(toBounding)) / 2, toY + toH / 2},
|
||||
{toX, toY + toH / 2}
|
||||
}
|
||||
: new double[][]
|
||||
{
|
||||
{fromX + fromW, fromY + fromH / 2},
|
||||
{fromX + fromW + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2},
|
||||
{fromX + fromW + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY - colNodeDistanceWrapper(getNearTopNodeDistance(fromBounding)) / 2},
|
||||
{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
{toX + toW / 2, toY}
|
||||
};
|
||||
}else if (fromX == toX) { // 垂直
|
||||
// 节点横向分布 连线按照大原则 垂直 不存在 fromY < toY 的情况 也就是不存在 连线从上到下直连的情况
|
||||
double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2};
|
||||
double[] endPoint = new double[]{toX + toW / 2, toY};
|
||||
return new double[][]{startPoint,
|
||||
{fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2},
|
||||
{fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
endPoint};
|
||||
}else {
|
||||
if (fromX < toX && fromY > toY){ // 目标节点在第一象限
|
||||
double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2};
|
||||
double turnPointX = fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2;
|
||||
if (fromX + getCurrentColMaxW(fromX) + getNearRightNodeDistance(fromBounding) == toX){ // 相邻节点 存在两个折点
|
||||
double[] endPoint = new double[]{toX, toY + toH / 2};
|
||||
return new double[][]{startPoint,{turnPointX, fromY + fromH / 2},{turnPointX, toY + toH / 2}, endPoint};
|
||||
}else { // 不相邻节点 存在三个折点
|
||||
double[] endPoint = new double[]{toX + toW / 2, toY};
|
||||
return new double[][]{
|
||||
startPoint,
|
||||
{turnPointX, fromY + fromH / 2},
|
||||
{turnPointX, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
endPoint
|
||||
};
|
||||
}
|
||||
}else if (fromX > toX && fromY > toY) { // 目标节点在第二象限 无论节点是否相邻 都按照三个折点走
|
||||
double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2};
|
||||
double[] endPoint = new double[]{toX + toW / 2, toY};
|
||||
return new double[][]{
|
||||
startPoint,
|
||||
{fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2},
|
||||
{fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
endPoint
|
||||
};
|
||||
}else if (fromX < toX && fromY < toY){ // 目标节点在第四象限
|
||||
double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2};
|
||||
if (fromX + getCurrentColMaxW(fromX) + getNearRightNodeDistance(fromBounding) == toX){ // 相邻节点 存在两个折点
|
||||
double turnPointX = fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2;
|
||||
double[] endPoint = new double[]{toX, toY + toH / 2};
|
||||
return new double[][]{
|
||||
startPoint,
|
||||
{turnPointX, fromY + fromH / 2},
|
||||
{turnPointX, toY + toH / 2},
|
||||
endPoint
|
||||
};
|
||||
}else { // 不相邻节点 存在三个折点
|
||||
double[] endPoint = new double[]{toX + toW / 2, toY};
|
||||
return new double[][]{
|
||||
startPoint,
|
||||
{fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2},
|
||||
{fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
endPoint
|
||||
};
|
||||
}
|
||||
}else if (fromX > toX && fromY < toY){ // 目标节点在第三象限 横向布局的情况下 应该不会出现目标节点在第三象限的情况
|
||||
ConsolePrinter.warn("[端到端功能][节点展开模块]处理连线时目标节点在[横向布局]的情况下出现在了第三象限");
|
||||
}
|
||||
}
|
||||
return new double[2][2];
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点垂直布局下计算连线
|
||||
* @param fromBounding
|
||||
* @param toBounding
|
||||
* @return
|
||||
*/
|
||||
public double[][] vertLayOut(double[] fromBounding, double[] toBounding){
|
||||
double fromX = fromBounding[0],fromY = fromBounding[1], fromW = fromBounding[2], fromH = fromBounding[3];
|
||||
double toX = toBounding[0], toY = toBounding[1], toW = toBounding[2], toH = toBounding[3];
|
||||
if (fromY == toY){ // 水平 分析可知 水平方向上不会出现 从左到右直连的情况 只有 右边节点右侧锚点出 向上走 左折 连到左侧节点上方锚点
|
||||
double[] startPoi = new double[]{fromX + fromW, fromY + fromH / 2};
|
||||
double[] turnPoi1 = new double[]{fromX + fromW + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2};
|
||||
double[] turnPoi2 = new double[]{fromX + fromW + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2};
|
||||
double[] turnPoi3 = new double[]{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2};
|
||||
double[] endPoi = new double[]{toX + toW / 2, toY};
|
||||
return new double[][]{startPoi, turnPoi1, turnPoi2, turnPoi3, endPoi};
|
||||
}else if (fromX == toX){ // 垂直 分析可知 垂直方向上应该不会有 toY < fromY 的情况 鉴于数据不确定性 先写上
|
||||
double[] startPoi = fromY < toY
|
||||
? new double[]{fromX + fromW / 2, fromY + fromH}
|
||||
: new double[]{fromX +fromW, fromY + fromH / 2};
|
||||
double[] endPoi = new double[]{toX + toW / 2, toY};
|
||||
return fromY < toY
|
||||
? new double[][]{
|
||||
startPoi,
|
||||
{fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2},
|
||||
{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
endPoi}
|
||||
: new double[][]{
|
||||
startPoi,
|
||||
{fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2},
|
||||
{fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
endPoi};
|
||||
}else { // 分布在四个象限内
|
||||
if (fromX > toX && fromY > toY){ // 目标节点在第二象限
|
||||
return new double[][]{
|
||||
{fromX + fromW, fromY + fromH / 2},
|
||||
{fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, fromY + fromH / 2},
|
||||
{fromX + getCurrentColMaxW(fromX) + rowNodeDistanceWrapper(getNearRightNodeDistance(fromBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
{toX + toW / 2, toY}
|
||||
};
|
||||
}else if (fromX > toX && fromY < toY){ // 目标节点在第三象限
|
||||
return toY - getCurrentRowMaxH(fromY) == getNearBootomNodeDistance(fromBounding) // 相邻行节点
|
||||
? new double[][]
|
||||
{
|
||||
{fromX + fromW / 2, fromY + fromH},
|
||||
{fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2},
|
||||
{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
{toX + toW / 2, toY}
|
||||
}
|
||||
: new double[][]
|
||||
{
|
||||
{fromX + fromW / 2, fromY + fromH},
|
||||
{fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2},
|
||||
{toX + toW + rowNodeDistanceWrapper(getNearRightNodeDistance(toBounding)) / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2},
|
||||
{toX + toW + rowNodeDistanceWrapper(getNearRightNodeDistance(toBounding)) / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
{toX + toW / 2, toY - colNodeDistanceWrapper(getNearTopNodeDistance(toBounding)) / 2},
|
||||
{toX + toW / 2, toY}
|
||||
};
|
||||
}else if (fromX < toX && fromY < toY){ // 目标节点在第四象限
|
||||
return new double[][]{
|
||||
{fromX + fromW / 2, fromY + fromH},
|
||||
{fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2},
|
||||
{toX + toW / 2, fromY + getCurrentRowMaxH(fromY) + colNodeDistanceWrapper(getNearBootomNodeDistance(fromBounding)) / 2},
|
||||
{toX + toW / 2, toY}
|
||||
};
|
||||
}else {
|
||||
// fromX < toX && fromY > toY 目标节点在第一象限 分析可知 纵向排布的情况下 应该不会出现目标节点在第一象限的情况
|
||||
}
|
||||
}
|
||||
return new double[2][2];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前同一列图形的最大宽度 在水平布局中
|
||||
* @param fromShapeX 当前图形的 x 坐标
|
||||
* @return
|
||||
*/
|
||||
private double getCurrentColMaxW(double shapeX){
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
JSONObject props = elements.keySet().stream()
|
||||
.filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")) && shapeX == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x"))
|
||||
.map(key -> elements.getJSONObject(key).getJSONObject("props"))
|
||||
.max(Comparator.comparing(o -> o.getDoubleValue("w"))).get();
|
||||
return props.getDoubleValue("w");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前同一行图形的最大高度 在垂直布局中
|
||||
* @param fromShapeY
|
||||
* @return
|
||||
*/
|
||||
private double getCurrentRowMaxH(double shapeY){
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
JSONObject props = elements.keySet().stream()
|
||||
.filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")) && shapeY == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y"))
|
||||
.map(key -> elements.getJSONObject(key).getJSONObject("props"))
|
||||
.max(Comparator.comparing(o -> o.getDoubleValue("h"))).get();
|
||||
return props.getDoubleValue("h");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前图形 水平方向上 左侧相邻节点 可能为空
|
||||
* @param shapeBounding [x, y, w, h]
|
||||
* @return JSONObject shape
|
||||
*/
|
||||
private JSONObject getNearLeftNode(double[] shapeBounding){
|
||||
double shapeX = shapeBounding[0], shapeY = shapeBounding[1];
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
JSONObject leftNode = elements.keySet().stream()
|
||||
.filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")))
|
||||
.filter(key -> shapeY == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y"))
|
||||
.filter(key -> shapeX > elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x"))
|
||||
.map(key -> elements.getJSONObject(key))
|
||||
.max(Comparator.comparing(o -> o.getJSONObject("props").getDoubleValue("x"))).orElse(null);
|
||||
return leftNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前图形 水平方向上 与左侧相邻节点的间距 如果为空 则返回默认间距
|
||||
* @param shapeBounding [x, y, w, h]
|
||||
* @return
|
||||
*/
|
||||
private double getNearLeftNodeDistance(double[] shapeBounding){
|
||||
JSONObject nearLeftNode = getNearLeftNode(shapeBounding);
|
||||
if (nearLeftNode == null){
|
||||
return SubProcessConst.SHAPE_HORIZ_INTERVAL;
|
||||
}
|
||||
double shapeX = shapeBounding[0];
|
||||
JSONObject props = nearLeftNode.getJSONObject("props");
|
||||
return shapeX - props.getDoubleValue("x") + props.getDoubleValue("w");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前图形 水平方向上 右侧相邻节点 可能为空
|
||||
* @param shapeBounding [x, y, w, h]
|
||||
* @return
|
||||
*/
|
||||
private JSONObject getNearRightNode(double[] shapeBounding){
|
||||
double shapeX = shapeBounding[0], shapeY = shapeBounding[1];
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
JSONObject rightNode = elements.keySet().stream()
|
||||
.filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")))
|
||||
.filter(key -> shapeY == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y"))
|
||||
.filter(key -> shapeX < elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x"))
|
||||
.map(key -> elements.getJSONObject(key))
|
||||
.min(Comparator.comparing(o -> o.getJSONObject("props").getDoubleValue("x"))).orElse(null);
|
||||
return rightNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前图形 水平方向上 与右侧相邻节点的间距 如果为空 则返回默认间距
|
||||
* @param shapeBounding [x, y, w, h]
|
||||
* @return
|
||||
*/
|
||||
private double getNearRightNodeDistance(double[] shapeBounding){
|
||||
JSONObject nearRightNode = getNearRightNode(shapeBounding);
|
||||
if (nearRightNode == null){
|
||||
return SubProcessConst.SHAPE_HORIZ_INTERVAL;
|
||||
}
|
||||
double shapeX = shapeBounding[0], shapeW = shapeBounding[2];
|
||||
JSONObject props = nearRightNode.getJSONObject("props");
|
||||
return props.getDoubleValue("x") - shapeX + shapeW;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前图形 垂直方向上 与上侧相邻节点 可能为空
|
||||
* @param shapeBounding [x, y, w, h]
|
||||
* @return
|
||||
*/
|
||||
private JSONObject getNearTopNode(double[] shapeBounding){
|
||||
double shapeX = shapeBounding[0], shapeY = shapeBounding[1];
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
JSONObject topNode = elements.keySet().stream()
|
||||
.filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")))
|
||||
.filter(key -> shapeX == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x"))
|
||||
.filter(key -> shapeY > elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y"))
|
||||
.map(key -> elements.getJSONObject(key))
|
||||
.max(Comparator.comparing(o -> o.getJSONObject("props").getDoubleValue("y"))).orElse(null);
|
||||
return topNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前图形 垂直方向上 与上侧相邻节点的间距 如果为空 则返回默认间距
|
||||
* @param shapeBounding [x, y, w, h]
|
||||
* @return
|
||||
*/
|
||||
private double getNearTopNodeDistance(double[] shapeBounding){
|
||||
JSONObject nearTopNode = getNearTopNode(shapeBounding);
|
||||
if (nearTopNode == null){
|
||||
return SubProcessConst.SHAPE_VERT_INTERVAL;
|
||||
}
|
||||
JSONObject props = nearTopNode.getJSONObject("props");
|
||||
double shapeY = shapeBounding[1];
|
||||
return shapeY - props.getDoubleValue("y") + props.getDoubleValue("h");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前图形 垂直方向上 与下侧相邻节点 可能为空
|
||||
* @param shapeBounding [x, y, w, h]
|
||||
* @return
|
||||
*/
|
||||
private JSONObject getNearBootomNode(double[] shapeBounding){
|
||||
double shapeX = shapeBounding[0], shapeY = shapeBounding[1];
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
JSONObject bottomNode = elements.keySet().stream()
|
||||
.filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")))
|
||||
.filter(key -> shapeX == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x"))
|
||||
.filter(key -> shapeY < elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y"))
|
||||
.map(key -> elements.getJSONObject(key))
|
||||
.min(Comparator.comparing(o -> o.getJSONObject("props").getDoubleValue("y"))).orElse(null);
|
||||
return bottomNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前图形 垂直方向上 与下侧相邻节点的间距 如果为空 则返回默认间距
|
||||
* @param shapeBounding [x, y, w, h]
|
||||
* @return
|
||||
*/
|
||||
private double getNearBootomNodeDistance(double[] shapeBounding){
|
||||
JSONObject nearBootomNode = getNearBootomNode(shapeBounding);
|
||||
if (nearBootomNode == null){
|
||||
return SubProcessConst.SHAPE_VERT_INTERVAL;
|
||||
}
|
||||
JSONObject props = nearBootomNode.getJSONObject("props");
|
||||
double shapeY = shapeBounding[1], shapeH = shapeBounding[3];
|
||||
return props.getDoubleValue("y") - shapeY + shapeH;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 如果水平方向上节点间距大于默认间距 返回默认间距 否则返回实际间距
|
||||
* @param distance
|
||||
* @return
|
||||
*/
|
||||
private double rowNodeDistanceWrapper(double distance){
|
||||
if (distance > SubProcessConst.SHAPE_HORIZ_INTERVAL){
|
||||
return SubProcessConst.SHAPE_HORIZ_INTERVAL;
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果垂直方向上节点间距大于默认间距 返回默认间距 否则返回实际间距
|
||||
* @param distance
|
||||
* @return
|
||||
*/
|
||||
private double colNodeDistanceWrapper(double distance){
|
||||
if (distance > SubProcessConst.SHAPE_VERT_INTERVAL){
|
||||
return SubProcessConst.SHAPE_VERT_INTERVAL;
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算angle值
|
||||
* @param fromPoi 起始节点坐标
|
||||
* @param toPoi 结束节点坐标
|
||||
* @param firstTurnPoi 连线第一个折点坐标
|
||||
* @param lastTurnPoi 连线最后一个折点坐标
|
||||
* @return [0]: from的angle [1]: to的angle
|
||||
*/
|
||||
private double[] calculationLinkerAngle(double[] fromPoi, double[] toPoi, double[] firstTurnPoi, double[] lastTurnPoi){
|
||||
double fromX = fromPoi[0], fromY = fromPoi[1];
|
||||
double toX = toPoi[0], toY = toPoi[1];
|
||||
double firstTurnX = firstTurnPoi[0], firstTurnY = firstTurnPoi[1];
|
||||
double lastTurnX = lastTurnPoi[0], lastTurnY = lastTurnPoi[1];
|
||||
|
||||
if (fromY == toY){ // 水平
|
||||
return fromX < toX ? new double[]{LinkerDefConstant.ANGLE_LEFT, LinkerDefConstant.ANGLE_RIGHT} : new double[]{LinkerDefConstant.ANGLE_RIGHT, LinkerDefConstant.ANGLE_LEFT};
|
||||
}else if (fromX == toX){ // 垂直
|
||||
return fromY < toY ? new double[]{LinkerDefConstant.ANGLE_UP, LinkerDefConstant.ANGLE_DOWN} : new double[]{LinkerDefConstant.ANGLE_DOWN, LinkerDefConstant.ANGLE_UP};
|
||||
}else {
|
||||
double fromAngle = 0.0;
|
||||
if (fromY == firstTurnY){ // 水平
|
||||
fromAngle = fromX < firstTurnX ? LinkerDefConstant.ANGLE_LEFT : LinkerDefConstant.ANGLE_RIGHT;
|
||||
}else if (fromX == firstTurnX){ // 垂直
|
||||
fromAngle = fromY < firstTurnY ? LinkerDefConstant.ANGLE_UP : LinkerDefConstant.ANGLE_DOWN;
|
||||
}
|
||||
double toAngle = 0.0;
|
||||
if (toY == lastTurnY){ // 水平
|
||||
toAngle = toX < lastTurnX ? LinkerDefConstant.ANGLE_LEFT : LinkerDefConstant.ANGLE_RIGHT;
|
||||
}else if (toX == lastTurnX){ // 垂直
|
||||
toAngle = toY < lastTurnY ? LinkerDefConstant.ANGLE_UP : LinkerDefConstant.ANGLE_DOWN;
|
||||
}
|
||||
return new double[]{fromAngle, toAngle};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,20 +1,20 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.mode;
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.graph.util;
|
||||
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.util.SubProcessNodeDefineUtil;
|
||||
import com.actionsoft.exception.AWSException;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author oYang
|
||||
* @Description 构建虚线范围框监视器模型且关联其内部元素 方便最后调整范围框内的元素
|
||||
* @Description 构建总图中已存在的范围框监视器模型且关联其内部元素
|
||||
* 方便最后调整范围框内的元素位置
|
||||
* 内部元素只包含元素类型为 ElementType.INNER_NODE ElementType.INNER_LINKER
|
||||
* @createTime 2023年06月13日 14:46:00
|
||||
*/
|
||||
public class ScopeShapeMonitor {
|
||||
@ -34,43 +34,34 @@ public class ScopeShapeMonitor {
|
||||
*/
|
||||
public void buildScopeShapeMonitors(){
|
||||
JSONObject elements = definitionHandle.getElements();
|
||||
Set<String> scopeShapeKeySet = elements.keySet().stream().filter(key -> "scopeLimitation".equals(elements.getJSONObject(key).getString("name"))).collect(Collectors.toSet());
|
||||
// 获取总图中已存在的范围框图形ID集合
|
||||
List<String> scopeShapeKeySet = definitionHandle.getScopeNodeIds();
|
||||
if (scopeShapeKeySet.size() == 0) return;
|
||||
|
||||
Map<String, MonitorInfo> scopeShapeMonitorMap = new HashMap<>();
|
||||
for (String scopeShapeKey : scopeShapeKeySet) {
|
||||
JSONObject props = definitionHandle.getShapeByProps(scopeShapeKey);
|
||||
double scopeX = props.getDoubleValue("x"), scopeY = props.getDoubleValue("y"), scopeW = props.getDoubleValue("w"), scopeH = props.getDoubleValue("h");
|
||||
// 判断当前元素是否在范围选择框的范围内
|
||||
Set<String> inRangeEleKeySet = new HashSet<>();
|
||||
for (String key : elements.keySet()) {
|
||||
if (scopeShapeKey.equals(key)) continue; // 范围框本身不算作其内部元素
|
||||
JSONObject shape = definitionHandle.getShapeByKey(key);
|
||||
if ("linker".equals(shape.getString("name"))){ // 连线
|
||||
JSONObject from = shape.getJSONObject("from");
|
||||
JSONObject to = shape.getJSONObject("to");
|
||||
double fromX = from.getDoubleValue("x"), fromY = from.getDoubleValue("y"), toX = to.getDoubleValue("x"), toY = to.getDoubleValue("y");
|
||||
if ((scopeX < fromX && fromX < scopeX + scopeW && scopeY < fromY && fromY < scopeY + scopeH) || (scopeX < toX && toX < scopeX + scopeW && scopeY < toY && toY < scopeY + scopeH)){
|
||||
inRangeEleKeySet.add(key);
|
||||
}
|
||||
}else {
|
||||
double x = definitionHandle.getShapeByProps(key).getDoubleValue("x");
|
||||
double y = definitionHandle.getShapeByProps(key).getDoubleValue("y");
|
||||
if (scopeX <= x && x < scopeX + scopeW && scopeY <= y && y < scopeY + scopeH){
|
||||
inRangeEleKeySet.add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
JSONObject scopeShape = definitionHandle.getShapeByKey(scopeShapeKey);
|
||||
// 获取范围框内部元素
|
||||
JSONArray innerEleIds = scopeShape.getJSONArray(SubProcessConst.INNER_ELEMENTS);
|
||||
Set<String> inRangeEleKeySet = innerEleIds.stream().map(o -> o.toString()).collect(Collectors.toSet());
|
||||
MonitorInfo monitorInfo = new MonitorInfo(scopeShapeKey, false, 0.0, false, 0.0, inRangeEleKeySet);
|
||||
scopeShapeMonitorMap.put(scopeShapeKey, monitorInfo);
|
||||
}
|
||||
this.scopeShapeMonitorMap = scopeShapeMonitorMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回所有的范围框监视器数据模型
|
||||
* @return
|
||||
*/
|
||||
public Map<String, MonitorInfo> getScopeShapeMonitorMap() {
|
||||
return scopeShapeMonitorMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除指定的范围框监视器数据模型
|
||||
* @param scopeShapeId
|
||||
*/
|
||||
public void removeScopeShapeByKey(String scopeShapeId){
|
||||
if (scopeShapeMonitorMap.containsKey(scopeShapeId)){
|
||||
scopeShapeMonitorMap.remove(scopeShapeId);
|
||||
@ -78,7 +69,7 @@ public class ScopeShapeMonitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新范围框的监视属性信息
|
||||
* 更新指定范围框内部元素在x方向上的位置信息
|
||||
* @param scopeShapeId 当前范围框图形ID
|
||||
* @param isRightMove 是否右移
|
||||
* @param rightMoveDistance 右移动距离
|
||||
@ -94,7 +85,7 @@ public class ScopeShapeMonitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新范围框的监视属性信息
|
||||
* 更新指定范围框内部元素在y方向上的位置信息
|
||||
* @param scopeShapeId 当前范围框图形ID
|
||||
* @param isBottomMove 是否下移
|
||||
* @param bottomMoveDistance 下移距离
|
||||
@ -194,7 +185,6 @@ public class ScopeShapeMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class MonitorInfo {
|
||||
|
||||
private String scopeShapeId; // 当前虚线范围框的图形ID
|
||||
@ -36,6 +36,11 @@ public class SubProcessNodeDefineUtil {
|
||||
if (childProcessBaseModel == null)
|
||||
throw new AWSException("当前子流程节点内部可能没有图形元素,可以去添加后展开");
|
||||
subProcessNodeDefineStr = childProcessBaseModel.getDefinition();
|
||||
JSONObject defineObj = JSONObject.parseObject(subProcessNodeDefineStr);
|
||||
JSONObject elements = defineObj.getJSONObject("elements");
|
||||
if (elements.size() == 0){
|
||||
throw new AWSException("当前子流程节点内部可能没有图形元素,可以去添加后展开");
|
||||
}
|
||||
}
|
||||
return subProcessNodeDefineStr;
|
||||
}
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.observers.node;
|
||||
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.util.ScopeShapeMonitor;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.observers.Observer;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
/**
|
||||
* @author oYang
|
||||
|
||||
@ -2,7 +2,7 @@ package com.actionsoft.apps.coe.method.process.subprocess.observers.node;
|
||||
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.graph.util.ScopeShapeMonitor;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.observers.Observer;
|
||||
import com.actionsoft.apps.coe.method.process.subprocess.observers.Subject;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.uitl;
|
||||
|
||||
/**
|
||||
* @author oYang
|
||||
* @create 2023-05-11 13:57
|
||||
*/
|
||||
public class Node {
|
||||
|
||||
public int id; // 节点id
|
||||
public double x; // 节点x坐标
|
||||
public double y; // 节点y坐标
|
||||
public double displaceX; // x方向移动位移
|
||||
public double displaceY; // y方向移动位移
|
||||
|
||||
public Node(int id) {
|
||||
this.id = id;
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.displaceX = 0;
|
||||
this.displaceY = 0;
|
||||
}
|
||||
}
|
||||
@ -1,113 +0,0 @@
|
||||
package com.actionsoft.apps.coe.method.process.subprocess.uitl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @author oYang
|
||||
* @create 2023-05-11 13:53
|
||||
*/
|
||||
public class UtilTestGraph {
|
||||
|
||||
private final int width; // 布局区域宽度
|
||||
private final int height; // 布局区域高度
|
||||
private final double k; // 弹性系数
|
||||
private final double k2; // 斥力系数
|
||||
private final double damping; // 阻尼系数
|
||||
private final double maxDisplace; // 最大移动距离
|
||||
private final int maxIterations; // 最大迭代次数
|
||||
|
||||
// 存储每个节点的位置信息
|
||||
private ArrayList<Node> nodes;
|
||||
|
||||
// 存储每个节点之间的连线信息(邻接矩阵)
|
||||
private int[][] adjacencyMatrix;
|
||||
|
||||
public UtilTestGraph(int width, int height, double k, double k2, double damping, double maxDisplace, int maxIterations, int nodeCount) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.k = k;
|
||||
this.k2 = k2;
|
||||
this.damping = damping;
|
||||
this.maxDisplace = maxDisplace;
|
||||
this.maxIterations = maxIterations;
|
||||
|
||||
// 初始化节点数组
|
||||
this.nodes = new ArrayList<>(nodeCount);
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
Node node = new Node(i);
|
||||
node.x = Math.random() * this.width;
|
||||
node.y = Math.random() * this.height;
|
||||
nodes.add(node);
|
||||
}
|
||||
|
||||
// 初始化邻接矩阵
|
||||
this.adjacencyMatrix = new int[nodeCount][nodeCount];
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
for (int j = i + 1; j < nodeCount; j++) {
|
||||
// 随机生成一个有连线的概率
|
||||
double p = random.nextDouble();
|
||||
if (p < 0.3) {
|
||||
adjacencyMatrix[i][j] = 1;
|
||||
adjacencyMatrix[j][i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行布局操作
|
||||
public void executeLayout() {
|
||||
for (int i = 0; i < maxIterations; i++) {
|
||||
for (int j = 0; j < nodes.size(); j++) {
|
||||
Node node = nodes.get(j);
|
||||
node.displaceX = 0;
|
||||
node.displaceY = 0;
|
||||
for (int k = 0; k < nodes.size(); k++) {
|
||||
if (j == k) continue;
|
||||
Node other = nodes.get(k);
|
||||
double dx = other.x - node.x;
|
||||
double dy = other.y - node.y;
|
||||
double distanceSquared = dx * dx + dy * dy;
|
||||
if (distanceSquared == 0) {
|
||||
dx = randomDisplacement();
|
||||
dy = randomDisplacement();
|
||||
distanceSquared = dx * dx + dy * dy;
|
||||
}
|
||||
double distance = Math.sqrt(distanceSquared);
|
||||
double force = (k * k / distance) - (k2 * distance);
|
||||
node.displaceX += (dx / distance) * force;
|
||||
node.displaceY += (dy / distance) * force;
|
||||
}
|
||||
}
|
||||
|
||||
// 移动节点的位置
|
||||
for (Node node : nodes) {
|
||||
double xDisplace = node.displaceX * damping;
|
||||
double yDisplace = node.displaceY * damping;
|
||||
double displace = Math.sqrt(xDisplace * xDisplace + yDisplace * yDisplace);
|
||||
if (displace > maxDisplace) {
|
||||
xDisplace *= maxDisplace / displace;
|
||||
yDisplace *= maxDisplace / displace;
|
||||
}
|
||||
node.x += xDisplace;
|
||||
node.y += yDisplace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 随机生成一个小的位移量
|
||||
private double randomDisplacement() {
|
||||
return (Math.random() - 0.5) * 0.1;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
UtilTestGraph layout = new UtilTestGraph(800, 600, 5.0, 0.1, 0.9, 5.0, 100, 20);
|
||||
layout.executeLayout();
|
||||
|
||||
// 输出节点的最终位置
|
||||
for (Node node : layout.nodes) {
|
||||
System.out.println("Node " + node.id + ": (" + node.x + ", " + node.y + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -306,6 +306,8 @@ public class SubProcessWeb extends ActionWeb {
|
||||
// 流程属性中加入布局方向
|
||||
graphRender.addDirectionToProcessProperties(direction);
|
||||
|
||||
graphRender.addLeadAndRearInfoToElements();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -324,6 +326,7 @@ public class SubProcessWeb extends ActionWeb {
|
||||
ro.setData(define);
|
||||
return ro.toString();
|
||||
} catch (AWSException e) {
|
||||
e.printStackTrace();
|
||||
return ResponseObject.newErrResponse(e.getMessage()).toString();
|
||||
}
|
||||
}
|
||||
@ -343,6 +346,7 @@ public class SubProcessWeb extends ActionWeb {
|
||||
ro.setData(define);
|
||||
return ro.toString();
|
||||
} catch (AWSException e) {
|
||||
e.printStackTrace();
|
||||
return ResponseObject.newErrResponse(e.getMessage()).toString();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user