Merge remote-tracking branch 'origin/apps_dev' into apps_dev

This commit is contained in:
wangpf 2023-06-01 10:37:13 +08:00
commit b47e182781
8 changed files with 659 additions and 108 deletions

View File

@ -130,9 +130,9 @@ public class SubProcessController {
}
@Mapping("com.actionsoft.apps.coe.method.process.subprocess.shape_expand")
public String shapeExpand(UserContext uc, String repositoryId, String shapeId){
return ResponseObject.newOkResponse("展开成功").toString();
public String shapeExpand(UserContext uc, String repositoryId, String shapeId, String direction){
SubProcessWeb processWeb = new SubProcessWeb(uc);
return processWeb.shapeNodeExpand(repositoryId, shapeId, direction);
}
}

View File

@ -33,4 +33,7 @@ public interface SubProcessConst {
double SHAPE_VERT_INTERVAL = 80.0;
// 图形间水平间隔
double SHAPE_HORIZ_INTERVAL = 80.0;
// 范围选择框内边距
double SCOPE_SHAPE_PADDING = 300;
}

View File

@ -17,7 +17,6 @@ public class GraphAdjMatrix {
private int[][] adjMatrix; // 邻接矩阵
private List<Node> vertexList; // 存储节点
private int numEdges; // 边的数目
/**
* 构造函数 初始化邻接矩阵
@ -26,7 +25,6 @@ public class GraphAdjMatrix {
public GraphAdjMatrix(List<Node> nodeList) {
adjMatrix = new int[nodeList.size()][nodeList.size()];
vertexList = nodeList;
numEdges = 0;
}
/**
@ -34,7 +32,6 @@ public class GraphAdjMatrix {
*/
public void addEdge(int u, int v) {
adjMatrix[u][v] = 1; // 设置邻接矩阵中相应的位置为 1
numEdges++;
}
/**
@ -57,14 +54,6 @@ public class GraphAdjMatrix {
return adjMatrix[u][v] == 1;
}
/**
* 获取边的树目
* @return
*/
public int getNumEdges(){
return numEdges;
}
/**
* 获取邻接矩阵
* @return

View File

@ -3,6 +3,7 @@ package com.actionsoft.apps.coe.method.process.subprocess.graph;
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.mode.Node;
import com.actionsoft.bpms.util.ConsolePrinter;
import com.actionsoft.bpms.util.UUIDGener;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
@ -180,15 +181,6 @@ public class GraphLinkerRender {
{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoint
};
}else if (fromX > toX && fromY < toY){ // 目标节点在第三象限
double[] startPoint = new double[]{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H};
double[] endPoint = new double[]{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY};
return new double[][]{
startPoint,
{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoint
};
}else if (fromX < toX && fromY < toY){ // 目标节点在第四象限
double[] startPoint = new double[]{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2};
if (fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点
@ -201,15 +193,17 @@ public class GraphLinkerRender {
endPoint
};
}else { // 不相邻节点 存在三个折点
double[] endPoint = new double[]{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY + SubProcessConst.SUB_PROCESS_SHAPE_H};
double[] endPoint = new double[]{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY};
return new double[][]{
startPoint,
{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + SubProcessConst.SUB_PROCESS_SHAPE_H / 2},
{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY + SubProcessConst.SUB_PROCESS_SHAPE_H + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{fromX + SubProcessConst.SUB_PROCESS_SHAPE_W + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + SubProcessConst.SUB_PROCESS_SHAPE_W / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoint
};
}
}else if (fromX > toX && fromY < toY){ // 目标节点在第三象限 横向布局的情况下 应该不会出现目标节点在第三象限的情况
ConsolePrinter.warn("[端到端功能][总图生成模块]处理连线时目标节点在[横向布局]的情况下出现在了第三象限");
}
}
return new double[2][2];

View File

@ -1,17 +1,23 @@
package com.actionsoft.apps.coe.method.process.subprocess.graph;
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.mode.Node;
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.List;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
/**
* 图节点展开处理
@ -22,46 +28,59 @@ public class GraphNodeExpandHandle {
private String shapeId; // 总图中当前要展开的子流程图形ID
private String relationFileId; // 当前要展开的子流程图形所标识模型文件ID
private CoeDesignerAPIManager apiManager;
private String childProcessDefine; // 要展开的子流程模型信息
private String endToEndProcessDefine; // 总图的模型信息
private JSONObject childProcessDefine; // 要展开的子流程模型信息
private JSONObject endToEndProcessDefine; // 总图的模型信息
private JSONObject scopeLimitationShape; // 范围标注框
public GraphNodeExpandHandle(String repositoryId, String shapeId) {
private double[] scopeLimitationShapeBeforePoi;
private final ReentrantLock lock = new ReentrantLock();
public GraphNodeExpandHandle(String repositoryId, String shapeId) throws AWSException{
this.repositoryId = repositoryId;
this.shapeId = shapeId;
apiManager = CoeDesignerAPIManager.getInstance();
readChildProcessDefine();
readCurrentProcessDefine();
try {
readChildProcessDefine();
readCurrentProcessDefine();
toAssembleScopeLimitationShape();
} catch (AWSException e) {
throw new AWSException(e);
}
}
/**
* 读取子流程节点的存储信息
* @throws AWSException
*/
public void readChildProcessDefine() throws AWSException{
private void readChildProcessDefine() throws AWSException{
List<DesignerShapeRelationModel> childProcessModelList = DesignerShapeRelationCache.getListByAttrId(repositoryId, shapeId, SubProcessConst.CHILD_PROCESS);
DesignerShapeRelationModel relationModel = childProcessModelList.stream().findFirst().orElse(null);
if (relationModel == null)
throw new AWSException("未找到当前节点所标识的子流程文件信息");
relationFileId = relationModel.getRelationFileId();
// 先去与总图存储的同级目录下读取 如果为空说明是初次读取
childProcessDefine = apiManager.getChildProcessDefine(repositoryId, 0, relationFileId);
if (UtilString.isEmpty(childProcessDefine)){ // 初次读取 去源文件目录读取
String childProcessDefineStr = apiManager.getChildProcessDefine(repositoryId, 0, relationFileId);
if (UtilString.isEmpty(childProcessDefineStr)){ // 初次读取 去源文件目录读取
BaseModel childProcessBaseModel = apiManager.getDefinition(relationFileId, 0);
childProcessDefine = childProcessBaseModel.getDefinition();
if (childProcessBaseModel == null)
throw new AWSException("当前子流程节点内部可能没有图形元素,可以去添加后展开");
childProcessDefineStr = childProcessBaseModel.getDefinition();
}
childProcessDefine = JSONObject.parseObject(childProcessDefineStr);
}
/**
* 读取当前总图的存储信息
* @throws AWSException
*/
public void readCurrentProcessDefine() throws AWSException{
private void readCurrentProcessDefine() throws AWSException{
BaseModel baseModel = apiManager.getDefinition(repositoryId, 0);
if (baseModel == null)
throw new AWSException("未找到当前总图存储的模型信息");
endToEndProcessDefine = baseModel.getDefinition();
endToEndProcessDefine = JSONObject.parseObject(baseModel.getDefinition());
}
/**
@ -69,16 +88,40 @@ public class GraphNodeExpandHandle {
* @return 范围标注框
* @throws AWSException
*/
private JSONObject toAssembleScopeLimitationShape() throws AWSException{
private void toAssembleScopeLimitationShape() throws AWSException{
JSONObject scopeLimitationShape = ShapeUtil.getProcessShapeDefinition(SubProcessConst.SUB_PROCESS_METHOD_ID, "展开范围标注");
JSONObject childProcessDefineObj = JSONObject.parseObject(childProcessDefine);
JSONObject childProcessPage = childProcessDefineObj.getJSONObject("page");
JSONObject childProcessPage = childProcessDefine.getJSONObject("page");
JSONObject childProcessElements = childProcessDefine.getJSONObject("elements");
JSONObject childProcessEleMaxX = childProcessElements.keySet()
.stream()
.filter(key -> !"linker".equals(childProcessElements.getJSONObject(key).getString("name")))
.map(key -> childProcessElements.getJSONObject(key).getJSONObject("props"))
.max((o1, o2) -> Double.compare(o1.getDoubleValue("x"), o2.getDoubleValue("x"))).get();
JSONObject childProcessEleMixX = childProcessElements.keySet()
.stream()
.filter(key -> !"linker".equals(childProcessElements.getJSONObject(key).getString("name")))
.map(key -> childProcessElements.getJSONObject(key).getJSONObject("props"))
.min((o1, o2) -> Double.compare(o1.getDoubleValue("x"), o2.getDoubleValue("x"))).get();
JSONObject childProcessEleMaxY = childProcessElements.keySet()
.stream()
.filter(key -> !"linker".equals(childProcessElements.getJSONObject(key).getString("name")))
.map(key -> childProcessElements.getJSONObject(key).getJSONObject("props"))
.max((o1, o2) -> Double.compare(o1.getDoubleValue("y"), o2.getDoubleValue("y"))).get();
JSONObject childProcessEleMinY = childProcessElements.keySet()
.stream()
.filter(key -> !"linker".equals(childProcessElements.getJSONObject(key).getString("name")))
.map(key -> childProcessElements.getJSONObject(key).getJSONObject("props"))
.min((o1, o2) -> Double.compare(o1.getDoubleValue("y"), o2.getDoubleValue("y"))).get();
// 当前节点所标识的子流程文件的 画布宽度与高度 减去边距
double childProcessPageWidth = childProcessPage.getDoubleValue("width") - childProcessPage.getDoubleValue("padding") * 2;
double childProcessPageHeight = childProcessPage.getDoubleValue("height") - childProcessPage.getDoubleValue("padding") * 2;
// double childProcessPageWidth = childProcessPage.getDoubleValue("width") - childProcessPage.getDoubleValue("padding") * 2;
// double childProcessPageHeight = childProcessPage.getDoubleValue("height") - childProcessPage.getDoubleValue("padding") * 2;
double scopeShapeW = childProcessEleMaxX.getDoubleValue("x") + childProcessEleMaxX.getDoubleValue("w") - childProcessEleMixX.getDoubleValue("x") + SubProcessConst.SCOPE_SHAPE_PADDING;
double scopeShapeH = childProcessEleMaxY.getDoubleValue("y") + childProcessEleMaxY.getDoubleValue("h") - childProcessEleMinY.getDoubleValue("y") + SubProcessConst.SCOPE_SHAPE_PADDING;
JSONObject endToEndProcessDefineObj = JSONObject.parseObject(endToEndProcessDefine);
JSONObject elements = endToEndProcessDefineObj.getJSONObject("elements");
// 计算下范围选择框在子流程所代表的模型文件的坐标
scopeLimitationShapeBeforePoi = new double[]{childProcessEleMixX.getDoubleValue("x") - SubProcessConst.SCOPE_SHAPE_PADDING / 2, childProcessEleMinY.getDoubleValue("y") - SubProcessConst.SCOPE_SHAPE_PADDING / 2};
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
// 找到当前要展开的子流程节点
JSONObject currentExpandShape = elements.getJSONObject(shapeId);
if (currentExpandShape == null)
@ -87,47 +130,196 @@ public class GraphNodeExpandHandle {
double x = props.getDoubleValue("x");
double y = props.getDoubleValue("y");
// 当前要展开的子流程节点的坐标赋给范围标注框
scopeLimitationShape.put("id", shapeId);
JSONObject scopeShapeProps = scopeLimitationShape.getJSONObject("props");
scopeShapeProps.put("x", x);
scopeShapeProps.put("y", y);
scopeShapeProps.put("w", childProcessPageWidth);
scopeShapeProps.put("h", childProcessPageHeight);
scopeShapeProps.put("w", scopeShapeW);
scopeShapeProps.put("h", scopeShapeH);
scopeShapeProps.put("zindex", 1);
return scopeLimitationShape;
this.scopeLimitationShape = scopeLimitationShape;
}
/**
* 处理子流程中所有节点的坐标
* 节点展开
* @param direction 排布方向
* @throws Exception
* @return 节点展开后的模型存储信息
*/
public void handleRelationModelNodePosition(){
public String handleNodeExpand(String direction) throws Exception{
// Thread t1 = new Thread(() -> {
// // 1总图节点以及连线处理
// handleEndToEndGraphNodeAndLinker(direction);
// });
// t1.start();
//
// Thread t2 = new Thread(() -> {
// // 2子流程节点内部元素处理
// handleRelationModelNodePosition();
// });
// t2.start();
//
// t1.join();
// t2.join();
// 1总图节点以及连线处理
handleEndToEndGraphNodeAndLinker(direction);
// 2子流程节点内部元素处理
handleRelationModelNodePosition();
// 6保存总图模型信息 以及 子流程模型信息备份
// BaseModel baseModel = apiManager.getDefinition(repositoryId, 0);
// baseModel.setDefinition(endToEndProcessDefine.toJSONString());
// apiManager.storeDefinition(baseModel);
// apiManager.storeChildProcessDefine(baseModel, relationFileId, childProcessDefine.toJSONString());
return endToEndProcessDefine.toJSONString();
}
/**
* 处理总图中的节点与连线
* 1删除待展开的节点
* 2替换为范围选择框
* 3节点x > 范围标注框x || 节点y < 范围标注框y 针对符合条件的节点 进行坐标调整
* 4根据旧有连线关系构建邻接矩阵
* 5获取当前总图中的所有节点的坐标
* 6删除旧有连线关系
* 7构建新的连线关系
*/
private void handleEndToEndGraphNodeAndLinker(String direction){
// 1删除当前要展开的节点
removeEndToEndGraphElements(shapeId);
// 2添加到总图中
addEndToEndGraphElements(scopeLimitationShape);
// 3总图中符合范围选择框条件的节点 坐标更新
handleEndToEndGraphNodeExcluedExpandNode();
// 4构建邻接矩阵
NodeExpandAdjMatrix expandAdjMatrix = buildEndToEndGraphAdjMatrix();
expandAdjMatrix.buildAdjMatrix();
// 5删除节点展开前的连线
removeEndToEndGraphOldLinker();
// 6获取所有节点坐标
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
double[][] vertexPosition = expandAdjMatrix.getVertexPosition(elements);
// 7构建新的连线
NodeExpandLinkerRender linkerRender = new NodeExpandLinkerRender(vertexPosition, expandAdjMatrix, scopeLimitationShape);
JSONArray linkers = linkerRender.toAssembleLinker(direction, shapeId);
for (Object o : linkers) {
JSONObject linker = (JSONObject) o;
addEndToEndGraphElements(linker);
}
}
/**
* 处理待展开节点所代表的流程文件中的节点的坐标
*/
private void handleRelationModelNodePosition(){
// 范围标注框 坐标
JSONObject scopeLimitationShape = toAssembleScopeLimitationShape();
JSONObject scopeShapeProps = scopeLimitationShape.getJSONObject("props");
double scopeShapeX = scopeShapeProps.getDoubleValue("x");
double scopeShapeY = scopeShapeProps.getDoubleValue("y");
double distanceX = scopeShapeX - scopeLimitationShapeBeforePoi[0];
double distanceY = scopeShapeY - scopeLimitationShapeBeforePoi[1];
// 根据范围标注框的坐标 调整子流程所有元素的坐标
JSONObject childProcessDefineObj = JSONObject.parseObject(childProcessDefine);
JSONObject elements = childProcessDefineObj.getJSONObject("elements");
JSONObject elements = childProcessDefine.getJSONObject("elements");
for (String key : elements.keySet()) {
JSONObject ele = elements.getJSONObject(key);
JSONObject props = ele.getJSONObject("props");
props.put("x", scopeShapeX + props.getDoubleValue("x"));
props.put("y", scopeShapeY + props.getDoubleValue("y"));
// 元素分为两类 一类为图形 一类为连线
if ("linker".equals(ele.getString("name"))){ // 连线的话折点需要额外处理
if ("linker".equals(ele.getString("name"))){ // 连线
JSONObject from = ele.getJSONObject("from");
from.put("x", distanceX + from.getDoubleValue("x"));
from.put("y", distanceY + from.getDoubleValue("y"));
JSONObject to = ele.getJSONObject("to");
to.put("x", distanceX + to.getDoubleValue("x"));
to.put("y", distanceY + to.getDoubleValue("y"));
// 连线的话折点也需要处理
JSONArray points = ele.getJSONArray("points");
for (Object p : points) {
JSONObject point = (JSONObject) p;
point.put("x", point.getDoubleValue("x") + scopeShapeX);
point.put("y", point.getDoubleValue("y") + scopeShapeY);
point.put("x", point.getDoubleValue("x") + distanceX);
point.put("y", point.getDoubleValue("y") + distanceY);
}
}else { // 图形
JSONObject props = ele.getJSONObject("props");
props.put("x", distanceX + props.getDoubleValue("x"));
props.put("y", distanceY + props.getDoubleValue("y"));
}
addEndToEndGraphElements(ele);
}
}
/**
* 处理总图中的节点
* 节点x > 范围标注框x || 节点y < 范围标注框y
* 针对符合条件的节点 进行坐标调整
*/
private void handleEndToEndGraphNodeExcluedExpandNode(){
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
// 范围标注框 大小 位置
JSONObject scopeShapeProps = scopeLimitationShape.getJSONObject("props");
double scopeShapeX = scopeShapeProps.getDoubleValue("x");
double scopeShapeY = scopeShapeProps.getDoubleValue("y");
double scopeShapeW = scopeShapeProps.getDoubleValue("w");
double scopeShapeH = scopeShapeProps.getDoubleValue("h");
for (String key : elements.keySet()) {
JSONObject ele = elements.getJSONObject(key);
if ("linker".equals(ele.getString("name"))) continue; // 连线先不处理
JSONObject props = ele.getJSONObject("props");
if (props.getDoubleValue("x") > scopeShapeX) { // 当前元素在待展开节点的右侧
props.put("x", props.getDoubleValue("x") + scopeShapeW - SubProcessConst.SUB_PROCESS_SHAPE_W);
}
if (props.getDoubleValue("y") > scopeShapeY) { // 当前元素在待展开节点的下侧
props.put("y", props.getDoubleValue("y") + scopeShapeH - SubProcessConst.SUB_PROCESS_SHAPE_H);
}
addEndToEndGraphElements(ele);
}
}
/**
* 构建节点展开前 端到端总图的邻接矩阵
* 方便后续节点展开或者闭合进行重新连线
*/
private NodeExpandAdjMatrix buildEndToEndGraphAdjMatrix(){
List<String> nodeIdList = new ArrayList<>();
List<JSONObject> linkerList = new ArrayList<>();
JSONObject endToEndProcessElements = endToEndProcessDefine.getJSONObject("elements");
for (String key : endToEndProcessElements.keySet()) {
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;
}
// 找到总图中 x坐标 >= 范围标注框x坐标 y坐标 >= 范围标注框y坐标 的图形
/**
* 删除总图中节点展开前的连线
*/
private void removeEndToEndGraphOldLinker(){
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
Set<String> eleKeys = new HashSet<>();
for (String key : elements.keySet()) {
JSONObject ele = elements.getJSONObject(key);
if ("linker".equals(ele.getString("name"))){
eleKeys.add(key);
}
}
for (String eleKey : eleKeys) {
removeEndToEndGraphElements(eleKey);
}
}
/**
@ -136,6 +328,404 @@ public class GraphNodeExpandHandle {
*/
public void storeChildProcessDefine(){
BaseModel baseModel = apiManager.getDefinition(relationFileId, 0);
apiManager.storeChildProcessDefine(baseModel, relationFileId, childProcessDefine);
apiManager.storeChildProcessDefine(baseModel, relationFileId, childProcessDefine.toJSONString());
}
/**
* 总图中添加元素
* @param ele
*/
private void addEndToEndGraphElements(JSONObject ele){
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
String id = ele.getString("id");
lock.lock();
try{
elements.put(id, ele);
}finally {
lock.unlock();
}
}
/**
* 总图中删除元素
* @param key
*/
private void removeEndToEndGraphElements(String key){
JSONObject elements = endToEndProcessDefine.getJSONObject("elements");
lock.lock();
try{
elements.remove(key);
}finally {
lock.unlock();
}
}
}
/**
* 节点展开的邻接矩阵
*/
class NodeExpandAdjMatrix{
private int[][] adjMatrix;
private List<String> nodeIds;
private List<JSONObject> linkerList;
public NodeExpandAdjMatrix(List<String> nodeIds, List<JSONObject> linkerList) {
this.adjMatrix = new int[nodeIds.size()][nodeIds.size()];
this.nodeIds = nodeIds;
this.linkerList = linkerList;
}
/**
* 添加一条从顶点 u 到顶点 v 的有向边
*/
public void addEdge(int u, int v) {
adjMatrix[u][v] = 1; // 设置邻接矩阵中相应的位置为 1
}
/**
* 获取从顶点 u 出发可以到达的所有顶点
*/
public List<Integer> getNeighbors(int u) {
List<Integer> neighbors = new ArrayList<>();
for (int i = 0; i < nodeIds.size(); i++) {
if (adjMatrix[u][i] == 1) {
neighbors.add(i);
}
}
return neighbors;
}
/**
* 判断从顶点 u 是否可以到达顶点 v
*/
public boolean hasEdge(int u, int v) {
return adjMatrix[u][v] == 1;
}
/**
* 获取邻接矩阵
* @return
*/
public int[][] getAdjMatrix(){
return adjMatrix;
}
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);
}
}
// 输出邻接矩阵
public void printAdjMatrix() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < nodeIds.size(); i++) {
for (int j = 0; j < nodeIds.size(); j++) {
sb.append(adjMatrix[i][j]).append(" ");
}
sb.append("\n");
}
System.out.println(sb.toString());
}
/**
* 获取总图中节点展开前的所有节点坐标
* @param elements
* @return
*/
public double[][] getVertexPosition(JSONObject elements){
double[][] position = new double[nodeIds.size()][2];
for (int i = 0; i < nodeIds.size(); i++) {
JSONObject shape = elements.getJSONObject(nodeIds.get(i));
JSONObject props = shape.getJSONObject("props");
double x = props.getDoubleValue("x");
double y = props.getDoubleValue("y");
position[i][0] = x;
position[i][1] = y;
}
return position;
}
}
/**
* 节点展开后连线重构
*/
class NodeExpandLinkerRender{
private List<String> nodeIds; // 图形节点ID集合
private double[][] vertexPosition; // 所有节点的坐标
private NodeExpandAdjMatrix expandAdjMatrix; // 节点矩阵
private JSONObject scopeLimitationShape; // 范围标注框
public NodeExpandLinkerRender(double[][] vertexPosition, NodeExpandAdjMatrix expandAdjMatrix, JSONObject scopeLimitationShape) {
this.nodeIds = expandAdjMatrix.getNodeIds();
this.vertexPosition = vertexPosition;
this.expandAdjMatrix = expandAdjMatrix;
this.scopeLimitationShape = scopeLimitationShape;
}
/**
* 根据连线方向 组装连线
* @param direction 连线方向
* @param shapeId 当前待展开节点ID
* @return
*/
public JSONArray toAssembleLinker(String direction, String shapeId){
JSONArray linkers = new JSONArray();
int index = nodeIds.indexOf(shapeId);
for (int i = 0; i < vertexPosition.length; i++) {
boolean currentExpandNodeIsStart = false;
if (i == index){
currentExpandNodeIsStart = true; // 当前待展开的节点此处应是范围选择框为连线的出发点
}
double[] fromPoi = vertexPosition[i];
List<Integer> nextNodeIndex = expandAdjMatrix.getNeighbors(i);
if (nextNodeIndex.size() > 0){ // 说明当前节点有连线
for (Integer nodeIndex : nextNodeIndex) {
boolean currentExpandNodeIsEnd = false;
if (nodeIndex.intValue() == index){
currentExpandNodeIsEnd = true; // 当前待展开的节点 此处应是范围选择框为连线的终点
}
double[] toPoi = vertexPosition[nodeIndex];
double[][] turnPoi = "horizontal".equals(direction)
? calculationLinkerPointInHorizLayOut(fromPoi, toPoi, currentExpandNodeIsStart, currentExpandNodeIsEnd)
: calculationLinkerPointInVertLayOut(fromPoi, toPoi, currentExpandNodeIsStart, currentExpandNodeIsEnd);
double[] angleArr = calculationLinkerAngle(fromPoi, toPoi, 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", nodeIds.get(i));
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", nodeIds.get(nodeIndex.intValue()));
linkerObj.put("to", toObj);
linkers.add(linkerObj);
}
}
}
return linkers;
}
private double[][] calculationLinkerPointInVertLayOut(double[] fromPoi, double[] toPoi, boolean currentExpandNodeIsStart, boolean currentExpandNodeIsEnd) {
double fromX = fromPoi[0],fromY = fromPoi[1],toX = toPoi[0],toY = toPoi[1];
double scopeShapeW = scopeLimitationShape.getDoubleValue("w"), scopeShapeH = scopeLimitationShape.getDoubleValue("h");
if (fromY == toY){ // 水平 分析可知 水平方向上不会出现 从左到右直连的情况 只有 右边节点右侧锚点出 向上走 左折 连到左侧节点上方锚点
double[] startPoi = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double[] turnPoi1 = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double[] turnPoi2 = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2};
double[] turnPoi3 = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2};
double[] endPoi = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return new double[][]{startPoi, turnPoi1, turnPoi2, turnPoi3, endPoi};
}else if (fromX == toX){ // 垂直 分析可知 垂直方向上应该不会有 toY < fromY 的情况 鉴于数据不确定性 先写上
double[] startPoi = fromY < toY
? new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)}
: new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double[] endPoi = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return fromY < toY
? new double[][]{
startPoi,
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoi}
: new double[][]{
startPoi,
{fromX + ((currentExpandNodeIsStart || currentExpandNodeIsEnd) ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + ((currentExpandNodeIsStart || currentExpandNodeIsEnd) ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoi};
}else { // 分布在四个象限内
if (fromX > toX && fromY > toY){ // 目标节点在第二象限
return new double[][]{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
};
}else if (fromX > toX && fromY < toY){ // 目标节点在第三象限
return toY - fromY == SubProcessConst.SHAPE_VERT_INTERVAL
? new double[][]
{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
}
: new double[][]
{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
};
}else if (fromX < toX && fromY < toY){ // 目标节点在第四象限
return new double[][]{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H)},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) + SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
};
}else {
// fromX < toX && fromY > toY 目标节点在第一象限 分析可知 纵向排布的情况下 应该不会出现目标节点在第一象限的情况
}
}
return new double[2][2];
}
private double[][] calculationLinkerPointInHorizLayOut(double[] fromPoi, double[] toPoi, boolean currentExpandNodeIsStart, boolean currentExpandNodeIsEnd) {
double fromX = fromPoi[0],fromY = fromPoi[1],toX = toPoi[0],toY = toPoi[1];
double scopeShapeW = scopeLimitationShape.getDoubleValue("w"), scopeShapeH = scopeLimitationShape.getDoubleValue("h");
if (fromY == toY) { // 水平 方向上 存在从左向右直连的情况 但不存在从右向左直连的情况 水平方向上 从左向右 应是 右出 向上 左折 向下
return fromX < toX
? new double[][]
{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{toX - SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{toX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2}
}
: new double[][]
{
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY}
};
}else if (fromX == toX) { // 垂直
// 节点横向分布 连线按照大原则 垂直 不存在 fromY < toY 的情况 也就是不存在 连线从上到下直连的情况
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return new double[][]{startPoint,
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoint};
}else {
if (fromX < toX && fromY > toY){ // 目标节点在第一象限
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double turnPointX = fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2;
if (fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点
double[] endPoint = new double[]{toX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
return new double[][]{startPoint,{turnPointX, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},{turnPointX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2}, endPoint};
}else { // 不相邻节点 存在三个折点
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return new double[][]{
startPoint,
{turnPointX, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{turnPointX, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoint
};
}
}else if (fromX > toX && fromY > toY) { // 目标节点在第二象限 无论节点是否相邻 都按照三个折点走
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return new double[][]{
startPoint,
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoint
};
}else if (fromX < toX && fromY < toY){ // 目标节点在第四象限
double[] startPoint = new double[]{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W), fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
if (fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点
double turnPointX = fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2;
double[] endPoint = new double[]{toX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2};
return new double[][]{
startPoint,
{turnPointX, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{turnPointX, toY + (currentExpandNodeIsEnd ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
endPoint
};
}else { // 不相邻节点 存在三个折点
double[] endPoint = new double[]{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY};
return new double[][]{
startPoint,
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + (currentExpandNodeIsStart ? scopeShapeH : SubProcessConst.SUB_PROCESS_SHAPE_H) / 2},
{fromX + (currentExpandNodeIsStart ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
{toX + (currentExpandNodeIsEnd ? scopeShapeW : SubProcessConst.SUB_PROCESS_SHAPE_W) / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2},
endPoint
};
}
}else if (fromX > toX && fromY < toY){ // 目标节点在第三象限 横向布局的情况下 应该不会出现目标节点在第三象限的情况
ConsolePrinter.warn("[端到端功能][节点展开模块]处理连线时目标节点在[横向布局]的情况下出现在了第三象限");
}
}
return new double[2][2];
}
/**
* 计算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};
}
}
}

View File

@ -303,50 +303,22 @@ public class SubProcessWeb extends ActionWeb {
}
public void shapeNodeExpand(String repositoryId, String shapeId){
/*
* 以当前节点展开涉及到动作拆分
*
* 0判断当前节点是否展开过了初次展开的话去源文件中找否则去备份的文件中找
*
* 1准备范围限制框元素该元素坐标与当前被展开的节点坐标一致宽度与高度与子流程标识的模型画布-边距的宽度高度一致
* 同时子流程标识的模型内的所有元素 以当前被展开的节点坐标为准下移右移 被展开节点坐标距离原点的距离
*
* 2找到x大于等于y大于等于当前被展开节点的所有子流程节点将这些节点下移右移到范围框之外
*
* 3根据与当前节点的连线找到总图中所有与当前被展开节点的相连的前置节点与后置节点
*
* 4将子流程模型备份一份为后续对展开后的节点做删除等操作
*
* */
// 获取子流程标识的文件存储信息
List<DesignerShapeRelationModel> childProcessModelList = DesignerShapeRelationCache.getListByAttrId(repositoryId, shapeId, SubProcessConst.CHILD_PROCESS);
DesignerShapeRelationModel relationModel = childProcessModelList.stream().findFirst().orElse(null);
if (relationModel == null)
throw new AWSException("未找到当前节点所标识的子流程文件信息");
String relationFileId = relationModel.getRelationFileId();
CoeDesignerAPIManager apiManager = CoeDesignerAPIManager.getInstance();
BaseModel childProcessBaseModel = apiManager.getDefinition(relationFileId, 0);
String childProcessDefinition = childProcessBaseModel.getDefinition();
JSONObject childProcessDefineObj = JSONObject.parseObject(childProcessDefinition);
JSONObject childProcessPage = childProcessDefineObj.getJSONObject("page");
// 当前节点所标识的子流程文件的 画布宽度与高度 减去边距
double childProcessPageWidth = childProcessPage.getDoubleValue("width") - childProcessPage.getDoubleValue("padding") * 2;
double childProcessPageHeight = childProcessPage.getDoubleValue("height") - childProcessPage.getDoubleValue("padding") * 2;
// 获取总图的存储数据
BaseModel baseModel = CoeDesignerAPIManager.getInstance().getDefinition(repositoryId, 0);
String definition = baseModel.getDefinition();
JSONObject defineJsonObj = JSONObject.parseObject(definition);
JSONObject elements = defineJsonObj.getJSONObject("elements");
JSONObject shapeObj = elements.getJSONObject(shapeId);
JSONObject shapeProps = shapeObj.getJSONObject("props");
// 当前节点的坐标
double x = shapeProps.getDoubleValue("x");
double y = shapeProps.getDoubleValue("y");
/**
* 节点展开操作
* @param repositoryId 当前总图ID
* @param shapeId 待展开的子流程节点ID
* @param direction 布局方向
*/
public String shapeNodeExpand(String repositoryId, String shapeId, String direction){
try {
GraphNodeExpandHandle nodeExpandHandle = new GraphNodeExpandHandle(repositoryId, shapeId);
String define = nodeExpandHandle.handleNodeExpand(direction);
ResponseObject ro = ResponseObject.newOkResponse("展开成功");
ro.setData(define);
return ro.toString();
} catch (Exception e) {
return ResponseObject.newErrResponse(e.getMessage()).toString();
}
}
}

View File

@ -7,6 +7,7 @@ $(function(){
const subProcess = new SubProcess(Model, ruuid, sid);
subProcess.shapeIconRender();
// 连线框 鼠标指针样式设置 防止因为连线z-index层级较高 会导致节点展开图标点击不到
$('.shape_box.linker_box').css({
'pointer-events': 'none'
});
@ -43,7 +44,7 @@ class SubProcess {
// 节点展开事件
shapeExpand(event){
let param = event.data;
alert('节点展开事件 ' + param.Model.define.elements[event.data.shapeId].text);
// alert('节点展开事件 ' + param.Model.define.elements[event.data.shapeId].text);
// 1、同时只能支持一个子流程节点展开
let elements = param.Model.define.elements;
for (let key in elements) {
@ -65,7 +66,9 @@ class SubProcess {
shapeId: param.shapeId
},
ok: function(r){
console.log(r);
console.log(JSON.stringify(r.data));
definition = JSON.stringify(r.data);
Designer.open(definition);
},
err: function(r){
$.simpleAlert(r.msg);