Activiti6.0 actual combat - flowchart highlight tracking customizable rendered pictures

Posted by gwood_25 on Tue, 28 Dec 2021 15:04:26 +0100

background

Record the functions commonly used in project requirements and their implementation methods. This is the second part, which will continue to be recorded later. This article is based on activiti6 0.0 principle: business data must be separated from approval process data, such as notes, documents, etc.

[process tracking] obtain the process definition diagram

The acquisition code is as follows:

ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
        .processDefinitionKey("leave")
        .singleResult();
 String diagramResourceName = processDefinition.getDiagramResourceName();
 InputStream imageStream = repositoryService.getResourceAsStream(
                            processDefinition.getDeploymentId(), diagramResourceName);
Copy code

1. Automatically generate flow definition diagram

           If only xml Definition, if there is no picture defined, Activiti The process engine automatically generates an image,The generated code may be garbled.
Copy code

The generated schematic diagram is as follows, from the official website

Garbled code problem solving:

@Configuration
public class ActivitiConfig implements ProcessEngineConfigurationConfigurer {

    /**
     * Solve the problem of image garbled generated by workflow
     *
     * @param processEngineConfiguration processEngineConfiguration
     */
    @Override
    public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
        processEngineConfiguration.setActivityFontName("Song typeface");
        processEngineConfiguration.setAnnotationFontName("Song typeface");
        processEngineConfiguration.setLabelFontName("Song typeface");
    }
}
Copy code

reference resources: blog.csdn.net/qq_27291799... Turn off automatic generation: if, for some reason, it is not necessary or unnecessary to generate a process definition picture during deployment, you need to use iscreatediagrarondeploy in the properties configured by the process engine:

<property name="createDiagramOnDeploy" value="false" />
Copy code

The process definition picture will not be generated now.

2. Provide customized pictures during deployment

Deployment method:

repositoryService.createDeployment()
.key("leave")
.name("Leave process")
.addClasspathResource("processes/leave.bpmn20.xml")
.addClasspathResource("processes/leave.png")
  .deploy();
 Next, you can API To get the process definition picture resource:
  ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                                                         .processDefinitionKey("leave")
                                                         .singleResult();
Copy code

[process tracking] obtain the highlighted activity flow chart

1. Highlight the node in progress

Pay attention to setting the font, otherwise it will be garbled

ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
        .processDefinitionKey("leave")
        .singleResult();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());// Model
List<String> highLightedActivities  = runtimeService.getActiveActivityIds("2501");// Highlight node
List<String> highLightedFlows = new ArrayList<>(); // Highlight connector
ProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
InputStream png = processDiagramGenerator.generateDiagram
                                    (bpmnModel, "png",highLightedActivities,
                                             highLightedFlows, "Song typeface", "Microsoft YaHei ", "Blackbody", null, 2.0);
Copy code

The example on the official website only highlights the nodes in progress by default

2. Highlight the node in progress + the processed connection line

Let's add the highlight of the connection line and all the processed nodes

List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
    .processInstanceId(processInstanceId)
        .orderByHistoricActivityInstanceId().asc().list();
List<String> highLightedFlows = getHighLightedFlows(bpmnModel, historicActivityInstances);// Get processed connector
 Copy code

reference resources: 791202.com/2020/03/30/...

/**
 * Get the transferred lines
 *
 * @param bpmnModel
 * @param historicActivityInstances
 * @return
 */
private static List<String> getHighLightedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
    // Highlight the line id collection of the process flow
    List<String> highLightedFlowIds = new ArrayList<>();
    // All active nodes
    List<FlowNode> historicActivityNodes = new ArrayList<>();
    // Completed historical activity node
    List<HistoricActivityInstance> finishedActivityInstances = new ArrayList<>();

    for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
        FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true);
        historicActivityNodes.add(flowNode);
        if (historicActivityInstance.getEndTime() != null) {
            finishedActivityInstances.add(historicActivityInstance);
        }
    }

    FlowNode currentFlowNode = null;
    FlowNode targetFlowNode = null;
    // Traverse the completed activity instances and find the executed activity from the outgoingFlows of each instance
    for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
        // Obtain the node information and outgoingFlows information corresponding to the current activity
        currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
        List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();

        /**
         * Traverse the outgoingFlows and find those that have been transferred. It is considered to have been transferred if the following conditions are met: 1 If the current node is a parallel gateway or a compatible gateway, all nodes that can be found in the historical activity through outgoingFlows are transferred 2 The current node is different from the above two types. The earliest flow node found through outgoingFlows is regarded as a valid flow
         */
        if ("parallelGateway".equals(currentActivityInstance.getActivityType()) || "inclusiveGateway".equals(currentActivityInstance.getActivityType())) {
            // Traverse the historical activity node to find the matching process target node
            for (SequenceFlow sequenceFlow : sequenceFlows) {
                targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
                if (historicActivityNodes.contains(targetFlowNode)) {
                    highLightedFlowIds.add(targetFlowNode.getId());
                }
            }
        } else {
            List<Map<String, Object>> tempMapList = new ArrayList<>();
            for (SequenceFlow sequenceFlow : sequenceFlows) {
                for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
                    if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
                        Map<String, Object> map = new HashMap<>();
                        map.put("highLightedFlowId", sequenceFlow.getId());
                        map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime());
                        tempMapList.add(map);
                    }
                }
            }

            if (!CollectionUtils.isEmpty(tempMapList)) {
                // Traverse the matching set and get the one with the earliest start time
                long earliestStamp = 0L;
                String highLightedFlowId = null;
                for (Map<String, Object> map : tempMapList) {
                    long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString());
                    if (earliestStamp == 0 || earliestStamp >= highLightedFlowStartTime) {
                        highLightedFlowId = map.get("highLightedFlowId").toString();
                        earliestStamp = highLightedFlowStartTime;
                    }
                }

                highLightedFlowIds.add(highLightedFlowId);
            }

        }

    }
    return highLightedFlowIds;
}
Copy code

3. Highlight the node in progress + processed connector + processed node

  // Get the nodes that have been executed in the process and sort them according to the execution order
		List<HistoricActivityInstance> historicActivityInstances = historyService.
                              createHistoricActivityInstanceQuery()
                                  .processInstanceId(processInstanceId) 
                                  .orderByHistoricActivityInstanceId().asc().list();
		// Highlight the process node ID collection that has been executed
		List<String> highLightedActivitiIds = new ArrayList<>();
		for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
			highLightedActivitiIds.add(historicActivityInstance.getActivityId());
		}                 
Copy code

4. Custom business color matching

The principle of drawing is to call the following methods and expand one wave.

ProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
processDiagramGenerator.generateDiagram()
Copy code

The core method is defaultprocessdiagramgenerator Drawactivity rewrite it

protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, 
    FlowNode flowNode, List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {
Copy code

All codes are as follows: 2 classes are involved:

LakerProcessDiagramCanvas

Inherits DefaultProcessDiagramCanvas

  • Override defines these 2 values
HIGHLIGHT_COLOR = Color.cyan;// Default color, previously red
THICK_TASK_BORDER_STROKE = new BasicStroke(6.0f);// Border width before 3.0
 Copy code
  • A new method for passing in colors is defined
public void drawHighLightColor(int x, int y, int width, int height, Color color) {
    Paint originalPaint = g.getPaint();
    Stroke originalStroke = g.getStroke();

    g.setPaint(color);
    g.setStroke(THICK_TASK_BORDER_STROKE);

    RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
    g.draw(rect);

    g.setPaint(originalPaint);
    g.setStroke(originalStroke);
}
Copy code

LakerProcessDiagramGenerator

Inherits the DefaultProcessDiagramGenerator

  • Rewritten initProcessDiagramCanvas to return to our extended LakerProcessDiagramCanvas
return new LakerProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY,
        imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
Copy code
  • Rewrites drawActivity, and the last node is displayed in custom color
// Draw the highlighted node TODO
if (highLightedActivities.contains(flowNode.getId())) {
    if (highLightedActivities.get(highLightedActivities.size() - 1).equalsIgnoreCase(flowNode.getId())) {

        LakerProcessDiagramCanvas lakerProcessDiagramCanvas = ((LakerProcessDiagramCanvas) processDiagramCanvas);
        lakerProcessDiagramCanvas.drawHighLightColor((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), Color.YELLOW);
    } else {
        processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
    }
}
Copy code

All source code

  • Inherit DefaultProcessDiagramCanvas
package com.laker.workflow.controller;

import org.activiti.image.impl.DefaultProcessDiagramCanvas;

import java.awt.*;
import java.awt.geom.RoundRectangle2D;

public class LakerProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
    public LakerProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
        super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
        HIGHLIGHT_COLOR = Color.cyan;
        THICK_TASK_BORDER_STROKE = new BasicStroke(6.0f);
    }

    public LakerProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType) {
        super(width, height, minX, minY, imageType);
        HIGHLIGHT_COLOR = Color.cyan;
        THICK_TASK_BORDER_STROKE = new BasicStroke(6.0f);
    }

    public void drawHighLightColor(int x, int y, int width, int height, Color color) {
        Paint originalPaint = g.getPaint();
        Stroke originalStroke = g.getStroke();

        g.setPaint(color);
        g.setStroke(THICK_TASK_BORDER_STROKE);

        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
        g.draw(rect);

        g.setPaint(originalPaint);
        g.setStroke(originalStroke);
    }

}
Copy code
  • Inherit DefaultProcessDiagramGenerator
package com.laker.workflow.controller;

import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.image.impl.DefaultProcessDiagramCanvas;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.List;

public class LakerProcessDiagramGenerator extends DefaultProcessDiagramGenerator {
    private BufferedImage processDiagram;

    @Override
    protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType,
                                                                 List<String> highLightedActivities, List<String> highLightedFlows,
                                                                 String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {

        {

            prepareBpmnModel(bpmnModel);

            DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);

            // Draw pool shape, if process is participant in collaboration
            for (Pool pool : bpmnModel.getPools()) {
                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
                processDiagramCanvas.drawPoolOrLane(pool.getName(), graphicInfo);
            }

            // Draw lanes
            for (Process process : bpmnModel.getProcesses()) {
                for (Lane lane : process.getLanes()) {
                    GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId());
                    processDiagramCanvas.drawPoolOrLane(lane.getName(), graphicInfo);
                }
            }

            // Draw activities and their sequence-flows
            for (FlowNode flowNode : bpmnModel.getProcesses().get(0).findFlowElementsOfType(FlowNode.class)) {
                drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor);
            }

            for (Process process : bpmnModel.getProcesses()) {
                for (FlowNode flowNode : process.findFlowElementsOfType(FlowNode.class)) {
                    drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor);
                }
            }

            // Draw artifacts
            for (Process process : bpmnModel.getProcesses()) {

                for (Artifact artifact : process.getArtifacts()) {
                    drawArtifact(processDiagramCanvas, bpmnModel, artifact);
                }

                List<SubProcess> subProcesses = process.findFlowElementsOfType(SubProcess.class, true);
                if (subProcesses != null) {
                    for (SubProcess subProcess : subProcesses) {
                        for (Artifact subProcessArtifact : subProcess.getArtifacts()) {
                            drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact);
                        }
                    }
                }
            }

            return processDiagramCanvas;
        }
    }

    @Override
    protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel,
                                FlowNode flowNode, List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {

        {

            ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass());
            if (drawInstruction != null) {

                drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode);

                // Gather info on the multi instance marker
                boolean multiInstanceSequential = false, multiInstanceParallel = false, collapsed = false;
                if (flowNode instanceof Activity) {
                    Activity activity = (Activity) flowNode;
                    MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics();
                    if (multiInstanceLoopCharacteristics != null) {
                        multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential();
                        multiInstanceParallel = !multiInstanceSequential;
                    }
                }

                // Gather info on the collapsed marker
                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
                if (flowNode instanceof SubProcess) {
                    collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded();
                } else if (flowNode instanceof CallActivity) {
                    collapsed = true;
                }

                if (scaleFactor == 1.0) {
                    // Actually draw the markers
                    processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(),
                            multiInstanceSequential, multiInstanceParallel, collapsed);
                }

                // Draw the highlighted node TODO
                if (highLightedActivities.contains(flowNode.getId())) {
                    if (highLightedActivities.get(highLightedActivities.size() - 1).equalsIgnoreCase(flowNode.getId())) {

                        LakerProcessDiagramCanvas lakerProcessDiagramCanvas = ((LakerProcessDiagramCanvas) processDiagramCanvas);
                        lakerProcessDiagramCanvas.drawHighLightColor((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), Color.YELLOW);
                    } else {
                        processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
                    }


                }

            }

            // Outgoing transitions of activity
            for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
                boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId()));
                String defaultFlow = null;
                if (flowNode instanceof Activity) {
                    defaultFlow = ((Activity) flowNode).getDefaultFlow();
                } else if (flowNode instanceof Gateway) {
                    defaultFlow = ((Gateway) flowNode).getDefaultFlow();
                }

                boolean isDefault = false;
                if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) {
                    isDefault = true;
                }
                boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && !(flowNode instanceof Gateway);

                String sourceRef = sequenceFlow.getSourceRef();
                String targetRef = sequenceFlow.getTargetRef();
                FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef);
                FlowElement targetElement = bpmnModel.getFlowElement(targetRef);
                List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
                if (graphicInfoList != null && graphicInfoList.size() > 0) {
                    graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList);
                    int xPoints[] = new int[graphicInfoList.size()];
                    int yPoints[] = new int[graphicInfoList.size()];

                    for (int i = 1; i < graphicInfoList.size(); i++) {
                        GraphicInfo graphicInfo = graphicInfoList.get(i);
                        GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);

                        if (i == 1) {
                            xPoints[0] = (int) previousGraphicInfo.getX();
                            yPoints[0] = (int) previousGraphicInfo.getY();
                        }
                        xPoints[i] = (int) graphicInfo.getX();
                        yPoints[i] = (int) graphicInfo.getY();

                    }

                    processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault, highLighted, scaleFactor);

                    // Draw sequenceflow label
                    GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId());
                    if (labelGraphicInfo != null) {
                        processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
                    }
                }
            }

            // Nested elements
            if (flowNode instanceof FlowElementsContainer) {
                for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
                    if (nestedFlowElement instanceof FlowNode) {
                        drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement,
                                highLightedActivities, highLightedFlows, scaleFactor);
                    }
                }
            }
        }
    }

    protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType,
                                                                          String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {

        // We need to calculate maximum values to know how big the image will be in its entirety
        double minX = Double.MAX_VALUE;
        double maxX = 0;
        double minY = Double.MAX_VALUE;
        double maxY = 0;

        for (Pool pool : bpmnModel.getPools()) {
            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
            minX = graphicInfo.getX();
            maxX = graphicInfo.getX() + graphicInfo.getWidth();
            minY = graphicInfo.getY();
            maxY = graphicInfo.getY() + graphicInfo.getHeight();
        }

        List<FlowNode> flowNodes = gatherAllFlowNodes(bpmnModel);
        for (FlowNode flowNode : flowNodes) {

            GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());

            // width
            if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) {
                maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth();
            }
            if (flowNodeGraphicInfo.getX() < minX) {
                minX = flowNodeGraphicInfo.getX();
            }
            // height
            if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) {
                maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight();
            }
            if (flowNodeGraphicInfo.getY() < minY) {
                minY = flowNodeGraphicInfo.getY();
            }

            for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
                List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
                if (graphicInfoList != null) {
                    for (GraphicInfo graphicInfo : graphicInfoList) {
                        // width
                        if (graphicInfo.getX() > maxX) {
                            maxX = graphicInfo.getX();
                        }
                        if (graphicInfo.getX() < minX) {
                            minX = graphicInfo.getX();
                        }
                        // height
                        if (graphicInfo.getY() > maxY) {
                            maxY = graphicInfo.getY();
                        }
                        if (graphicInfo.getY() < minY) {
                            minY = graphicInfo.getY();
                        }
                    }
                }
            }
        }

        List<Artifact> artifacts = gatherAllArtifacts(bpmnModel);
        for (Artifact artifact : artifacts) {

            GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId());

            if (artifactGraphicInfo != null) {
                // width
                if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) {
                    maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth();
                }
                if (artifactGraphicInfo.getX() < minX) {
                    minX = artifactGraphicInfo.getX();
                }
                // height
                if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) {
                    maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight();
                }
                if (artifactGraphicInfo.getY() < minY) {
                    minY = artifactGraphicInfo.getY();
                }
            }

            List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId());
            if (graphicInfoList != null) {
                for (GraphicInfo graphicInfo : graphicInfoList) {
                    // width
                    if (graphicInfo.getX() > maxX) {
                        maxX = graphicInfo.getX();
                    }
                    if (graphicInfo.getX() < minX) {
                        minX = graphicInfo.getX();
                    }
                    // height
                    if (graphicInfo.getY() > maxY) {
                        maxY = graphicInfo.getY();
                    }
                    if (graphicInfo.getY() < minY) {
                        minY = graphicInfo.getY();
                    }
                }
            }
        }

        int nrOfLanes = 0;
        for (Process process : bpmnModel.getProcesses()) {
            for (Lane l : process.getLanes()) {

                nrOfLanes++;

                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId());
                // // width
                if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) {
                    maxX = graphicInfo.getX() + graphicInfo.getWidth();
                }
                if (graphicInfo.getX() < minX) {
                    minX = graphicInfo.getX();
                }
                // height
                if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) {
                    maxY = graphicInfo.getY() + graphicInfo.getHeight();
                }
                if (graphicInfo.getY() < minY) {
                    minY = graphicInfo.getY();
                }
            }
        }

        // Special case, see https://activiti.atlassian.net/browse/ACT-1431
        if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) {
            // Nothing to show
            minX = 0;
            minY = 0;
        }

        return new LakerProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY,
                imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
    }

}
Copy code

reference resources: blog.csdn.net/u010740917/...

[process tracking] the task flow path of the process

List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
        .processInstanceId("2515")
        .orderByHistoricTaskInstanceEndTime().asc().list();
Copy code
SELECT DISTINCT RES.*
FROM ACT_HI_TASKINST RES
WHERE RES.PROC_INST_ID_ = '2515'
ORDER BY  RES.END_TIME_ ASC LIMIT '2147483647' OFFSET '0' 
Copy code

[process tracking] set the process title

For example, the process title is "Zhang San's leave form"

runtimeService.setProcessInstanceName(processInstance.getId(),"Zhang San's leave slip");
When querying
runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
Copy code

act_ru_execution,act_hi_procinst [name_] Field


Author: lakernote
Link: https://juejin.cn/post/6906322920855830542
Source: Nuggets
The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.

Topics: Java