端到端功能 节点展开与闭合功能优化

This commit is contained in:
qinoy 2023-06-13 17:33:47 +08:00
parent e7b489532a
commit 0e50564887
3 changed files with 276 additions and 18 deletions

View File

@ -7,6 +7,7 @@ import com.actionsoft.apps.coe.method.process.subprocess.graph.component.Abstrac
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.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;
@ -35,6 +36,7 @@ public class GraphNodeExpandHandle {
private JSONObject scopeLimitationShape; // 范围标注框
private AbstractDefinitionHandle definitionHandle; // 当前总图 define 处理器
private AbstractDefinitionHandle subProcessNodeDefineHandle; // 子流程节点 define 处理器
private ScopeShapeMonitor scopeShapeMonitor;
private double[] scopeLimitationShapeBeforePoi; // 范围选择框在子流程文件中的坐标
@ -51,6 +53,8 @@ public class GraphNodeExpandHandle {
definitionHandle = new DefinitionThreadUnSafe(endToEndProcessDefineStr);
subProcessNodeDefineHandle = new DefinitionThreadUnSafe(SubProcessNodeDefineUtil.readSubProcessNodeDefine(repositoryId, shapeId));
scopeShapeMonitor = new ScopeShapeMonitor(definitionHandle, subProcessNodeDefineHandle);
toAssembleScopeLimitationShape();
} catch (Exception e) {
throw new AWSException(e);
@ -99,10 +103,13 @@ public class GraphNodeExpandHandle {
*/
public String handleNodeExpand() throws AWSException{
// 1总图节点以及连线处理
// 1甄别总图中的范围标识框以及其内的节点
scopeShapeMonitor.buildScopeShapeMonitors();
// 2总图节点以及连线处理
handleEndToEndGraphNodeAndLinker();
// 2子流程节点内部元素处理
// 3子流程节点内部元素处理
handleRelationModelNodePosition();
return definitionHandle.getDefine().toJSONString();
@ -141,12 +148,15 @@ public class GraphNodeExpandHandle {
JSONObject processProperties = definitionHandle.getProcessProperties();
String direction = processProperties.getString("direction");
NodeExpandLinkerRender linkerRender = new NodeExpandLinkerRender(vertexBounding, expandAdjMatrix);
JSONArray linkers = linkerRender.toAssembleLinker(direction, shapeId);
JSONArray linkers = linkerRender.toAssembleLinker(direction);
for (Object o : linkers) {
JSONObject linker = (JSONObject) o;
definitionHandle.addEle(linker.getString("id"), linker);
}
// 范围框内的元素 坐标更新
scopeShapeMonitor.updateScopeShapeInnerEle();
// 8更新画布的大小
// 确定画布的宽度与高度
double w = Arrays.stream(vertexBounding).mapToDouble(position -> position[0]).max().orElse(0.0);
@ -220,20 +230,40 @@ public class GraphNodeExpandHandle {
JSONObject props = ele.getJSONObject("props");
if (ele.getString("id").equals(scopeLimitationShape.getString("id"))) continue;
if ("vertically".equals(direction)){
if (props.getDoubleValue("x") > scopeShapeX) { // 当前元素在待展开节点的右侧
props.put("x", props.getDoubleValue("x") + scopeShapeW - SubProcessConst.SUB_PROCESS_SHAPE_W);
if (props.getDoubleValue("x") > scopeShapeX && !scopeShapeMonitor.checkShapeIsScopeInRange(key)) { // 当前元素在待展开节点的右侧
double rightMoveDistance = scopeShapeW - SubProcessConst.SUB_PROCESS_SHAPE_W;
props.put("x", props.getDoubleValue("x") + rightMoveDistance);
if (scopeShapeMonitor.checkShapeIsScopeShape(key)){
scopeShapeMonitor.updateMonitorRightInfo(key, true, rightMoveDistance);
}
}
if (props.getDoubleValue("y") > scopeShapeY || props.getDoubleValue("y") == scopeShapeY) { // 当前元素在待展开节点的下侧
props.put("y", props.getDoubleValue("y") + scopeShapeH - SubProcessConst.SUB_PROCESS_SHAPE_H);
if (props.getDoubleValue("y") >= scopeShapeY && !scopeShapeMonitor.checkShapeIsScopeInRange(key)) { // 当前元素在待展开节点的下侧
double bottomMoveDistance = scopeShapeH - SubProcessConst.SUB_PROCESS_SHAPE_H;
props.put("y", props.getDoubleValue("y") + bottomMoveDistance);
if (scopeShapeMonitor.checkShapeIsScopeShape(key)){
scopeShapeMonitor.updateMonitorBottomInfo(key, true, bottomMoveDistance);
}
}
}else {
if (props.getDoubleValue("x") > scopeShapeX) { // 当前元素在待展开节点的右侧
props.put("x", props.getDoubleValue("x") + scopeShapeW - SubProcessConst.SUB_PROCESS_SHAPE_W);
}else if (props.getDoubleValue("x") == scopeShapeX && props.getDoubleValue("y") > scopeShapeY) { // 当前元素与待展开节点在一列上 且在下侧
props.put("x", props.getDoubleValue("x") + scopeShapeW - SubProcessConst.SUB_PROCESS_SHAPE_W);
if (props.getDoubleValue("x") > scopeShapeX && !scopeShapeMonitor.checkShapeIsScopeInRange(key)) { // 当前元素在待展开节点的右侧
double rightMoveDistance = scopeShapeW - SubProcessConst.SUB_PROCESS_SHAPE_W;
props.put("x", props.getDoubleValue("x") + rightMoveDistance);
if (scopeShapeMonitor.checkShapeIsScopeShape(key)){
scopeShapeMonitor.updateMonitorRightInfo(key, true, rightMoveDistance);
}
}else if (props.getDoubleValue("x") == scopeShapeX && props.getDoubleValue("y") > scopeShapeY && !scopeShapeMonitor.checkShapeIsScopeInRange(key)) { // 当前元素与待展开节点在一列上 且在下侧
double rightMoveDistance = scopeShapeW - SubProcessConst.SUB_PROCESS_SHAPE_W;
props.put("x", props.getDoubleValue("x") + rightMoveDistance);
if (scopeShapeMonitor.checkShapeIsScopeShape(key)){
scopeShapeMonitor.updateMonitorRightInfo(key, true, rightMoveDistance);
}
}
if (props.getDoubleValue("y") > scopeShapeY) { // 当前元素在待展开节点的下侧
props.put("y", props.getDoubleValue("y") + scopeShapeH - SubProcessConst.SUB_PROCESS_SHAPE_H);
if (props.getDoubleValue("y") > scopeShapeY && !scopeShapeMonitor.checkShapeIsScopeInRange(key)) { // 当前元素在待展开节点的下侧
double bottomMoveDistance = scopeShapeH - SubProcessConst.SUB_PROCESS_SHAPE_H;
props.put("y", props.getDoubleValue("y") + bottomMoveDistance);
if (scopeShapeMonitor.checkShapeIsScopeShape(key)){
scopeShapeMonitor.updateMonitorBottomInfo(key, true, bottomMoveDistance);
}
}
}
@ -251,6 +281,7 @@ public class GraphNodeExpandHandle {
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);
@ -270,7 +301,7 @@ public class GraphNodeExpandHandle {
Set<String> eleKeys = new HashSet<>();
for (String key : elements.keySet()) {
JSONObject ele = elements.getJSONObject(key);
if ("linker".equals(ele.getString("name"))){
if ("linker".equals(ele.getString("name")) && !scopeShapeMonitor.checkShapeIsScopeInRange(key)){
eleKeys.add(key);
}
}
@ -356,13 +387,11 @@ class NodeExpandLinkerRender{
private List<String> nodeIds; // 图形节点ID集合
private double[][] vertexPosition; // 所有节点的坐标以及宽高 double[][]{{x, y, w, h},{}}
private NodeExpandAdjMatrix expandAdjMatrix; // 节点矩阵
// private JSONObject scopeLimitationShape; // 范围标注框
public NodeExpandLinkerRender(double[][] vertexPosition, NodeExpandAdjMatrix expandAdjMatrix) {
this.nodeIds = expandAdjMatrix.getNodeIds();
this.vertexPosition = vertexPosition;
this.expandAdjMatrix = expandAdjMatrix;
// this.scopeLimitationShape = scopeLimitationShape;
}
/**
@ -371,9 +400,8 @@ class NodeExpandLinkerRender{
* @param shapeId 当前待展开节点ID
* @return
*/
public JSONArray toAssembleLinker(String direction, String shapeId){
public JSONArray toAssembleLinker(String direction){
JSONArray linkers = new JSONArray();
int index = nodeIds.indexOf(shapeId);
for (int i = 0; i < vertexPosition.length; i++) {
double[] fromBounding = vertexPosition[i];
List<Integer> nextNodeIndex = expandAdjMatrix.getNeighbors(i);

View File

@ -0,0 +1,230 @@
package com.actionsoft.apps.coe.method.process.subprocess.mode;
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.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author oYang
* @Description 虚线范围框及其内部元素的监视器模型
* @createTime 2023年06月13日 14:46:00
*/
public class ScopeShapeMonitor {
private AbstractDefinitionHandle definitionHandle; // 总图 define 处理器
private AbstractDefinitionHandle subProcessDefineHandle; // 子流程节点 define 处理器
private Map<String, MonitorInfo> scopeShapeMonitorMap; // 范围框及内部元素集合
public ScopeShapeMonitor(AbstractDefinitionHandle definitionHandle, AbstractDefinitionHandle subProcessDefineHandle) {
this.definitionHandle = definitionHandle;
this.subProcessDefineHandle = subProcessDefineHandle;
}
/**
* 构建范围标识框及其内部元素的监视器模型
* @param definitionHandle 总图 define 处理器
* @param subProcessDefineHandle 子流程节点 define 处理器
* @return Map<String, MonitorInfo>
*/
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());
if (scopeShapeKeySet.size() == 0) return;
Map<String, MonitorInfo> scopeShapeMonitorMap = new HashMap<>();
for (String scopeShapeKey : scopeShapeKeySet) {
Set<String> inScopeLimitationRangeEles = SubProcessNodeDefineUtil.getInScopeLimitationRangeEles(scopeShapeKey, definitionHandle, subProcessDefineHandle);
MonitorInfo monitorInfo = new MonitorInfo(scopeShapeKey, false, 0.0, false, 0.0, inScopeLimitationRangeEles);
scopeShapeMonitorMap.put(scopeShapeKey, monitorInfo);
}
this.scopeShapeMonitorMap = scopeShapeMonitorMap;
}
public Map<String, MonitorInfo> getScopeShapeMonitorMap() {
return scopeShapeMonitorMap;
}
/**
* 更新范围框的监视属性信息
* @param scopeShapeId 当前范围框图形ID
* @param isRightMove 是否右移
* @param rightMoveDistance 右移动距离
* @throws AWSException
*/
public void updateMonitorRightInfo(String scopeShapeId, boolean isRightMove, double rightMoveDistance) throws AWSException{
if (scopeShapeMonitorMap == null) return;
if (!scopeShapeMonitorMap.containsKey(scopeShapeId))
throw new AWSException("【参数异常】当前范围框监视器不包含图形ID【" + scopeShapeId + "");
MonitorInfo monitorInfo = scopeShapeMonitorMap.get(scopeShapeId);
monitorInfo.setRightMove(isRightMove);
monitorInfo.setRightMoveDistance(rightMoveDistance);
}
/**
* 更新范围框的监视属性信息
* @param scopeShapeId 当前范围框图形ID
* @param isBottomMove 是否下移
* @param bottomMoveDistance 下移距离
* @throws AWSException
*/
public void updateMonitorBottomInfo(String scopeShapeId, boolean isBottomMove, double bottomMoveDistance) throws AWSException{
if (scopeShapeMonitorMap == null) return;
if (!scopeShapeMonitorMap.containsKey(scopeShapeId))
throw new AWSException("【参数异常】当前范围框监视器不包含图形ID【" + scopeShapeId + "");
MonitorInfo monitorInfo = scopeShapeMonitorMap.get(scopeShapeId);
monitorInfo.setBottomMove(isBottomMove);
monitorInfo.setBottomMoveDistance(bottomMoveDistance);
}
/**
* 检查当前元素是否是某一个范围框内的元素
* @param shapeId
* @return
*/
public boolean checkShapeIsScopeInRange(String shapeId){
boolean flag = false;
if (scopeShapeMonitorMap != null){
for (String key : scopeShapeMonitorMap.keySet()) {
MonitorInfo monitorInfo = scopeShapeMonitorMap.get(key);
Set<String> inRangeShapeIdSet = monitorInfo.getInRangeShapeIdSet();
if (inRangeShapeIdSet.contains(shapeId)){
flag = true;
break;
}
}
}
return flag;
}
/**
* 检查当前图形是否是范围框元素
* @param shapeId
* @return
*/
public boolean checkShapeIsScopeShape(String shapeId){
boolean flag = false;
if (scopeShapeMonitorMap != null){
flag = scopeShapeMonitorMap.containsKey(shapeId);
}
return flag;
}
/**
* 更新范围内元素 坐标
*/
public void updateScopeShapeInnerEle(){
if (scopeShapeMonitorMap != null){
for (String scopeShapeKey : scopeShapeMonitorMap.keySet()) {
MonitorInfo monitorInfo = scopeShapeMonitorMap.get(scopeShapeKey);
Set<String> inRangeShapeIdSet = monitorInfo.getInRangeShapeIdSet();
if (monitorInfo.isRightMove()){
double rightMoveDistance = monitorInfo.getRightMoveDistance();
for (String key : inRangeShapeIdSet) {
JSONObject shape = definitionHandle.getShapeByKey(key);
if ("linker".equals(shape.getString("name"))){
JSONObject from = shape.getJSONObject("from");
from.put("x", from.getDoubleValue("x") + rightMoveDistance);
JSONObject to = shape.getJSONObject("to");
to.put("x", to.getDoubleValue("x") + rightMoveDistance);
JSONArray points = shape.getJSONArray("points");
for (Object o : points) {
JSONObject point = (JSONObject) o;
point.put("x", point.getDoubleValue("x") + rightMoveDistance);
}
}else {
JSONObject props = definitionHandle.getShapeByProps(key);
props.put("x", props.getDoubleValue("x") + rightMoveDistance);
}
}
}
if (monitorInfo.isBottomMove()){
double bottomMoveDistance = monitorInfo.getBottomMoveDistance();
for (String key : inRangeShapeIdSet) {
JSONObject shape = definitionHandle.getShapeByKey(key);
if ("linker".equals(shape.getString("name"))){
JSONObject from = shape.getJSONObject("from");
from.put("y", from.getDoubleValue("y") + bottomMoveDistance);
JSONObject to = shape.getJSONObject("to");
to.put("y", to.getDoubleValue("y") + bottomMoveDistance);
JSONArray points = shape.getJSONArray("points");
for (Object o : points) {
JSONObject point = (JSONObject) o;
point.put("y", point.getDoubleValue("y") + bottomMoveDistance);
}
}else {
JSONObject props = definitionHandle.getShapeByProps(key);
props.put("y", props.getDoubleValue("y") + bottomMoveDistance);
}
}
}
}
}
}
class MonitorInfo {
private String scopeShapeId; // 当前虚线范围框的图形ID
private boolean isRightMove; // 范围框是否右移
private double rightMoveDistance; // 右移动距离
private boolean isBottomMove; // 范围框是否下移
private double bottomMoveDistance; // 下移距离
private Set<String> inRangeShapeIdSet; // 范围内的图形与连线的ID集合
public MonitorInfo(String scopeShapeId, boolean isRightMove, double rightMoveDistance, boolean isBottomMove, double bottomMoveDistance, Set<String> inRangeShapeIdSet) {
this.scopeShapeId = scopeShapeId;
this.isRightMove = isRightMove;
this.rightMoveDistance = rightMoveDistance;
this.isBottomMove = isBottomMove;
this.bottomMoveDistance = bottomMoveDistance;
this.inRangeShapeIdSet = inRangeShapeIdSet;
}
public boolean isRightMove() {
return isRightMove;
}
public double getRightMoveDistance() {
return rightMoveDistance;
}
public boolean isBottomMove() {
return isBottomMove;
}
public double getBottomMoveDistance() {
return bottomMoveDistance;
}
public void setRightMove(boolean rightMove) {
isRightMove = rightMove;
}
public void setRightMoveDistance(double rightMoveDistance) {
this.rightMoveDistance = rightMoveDistance;
}
public void setBottomMove(boolean bottomMove) {
isBottomMove = bottomMove;
}
public void setBottomMoveDistance(double bottomMoveDistance) {
this.bottomMoveDistance = bottomMoveDistance;
}
public Set<String> getInRangeShapeIdSet() {
return inRangeShapeIdSet;
}
}
}