<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      activiti7移除了靜態方法創建ProcessDiagramGenerator,需要創建DefaultProcessDiagramGenerator實例

      依賴:

          <properties>
            <batik-transcoder.version>1.17</batik-transcoder.version>
            <batik-codec.version>1.17</batik-codec.version>
            <activiti-json-converter.version>7.1.0.M6</activiti-json-converter.version>
            <activiti-spring-boot-starter.version>7.1.0.M6</activiti-spring-boot-starter.version>
          </properties>
          
          <dependencies>
            <!-- 流程圖設計 -->
            <dependency>
              <groupId>org.apache.xmlgraphics</groupId>
              <artifactId>batik-transcoder</artifactId>
              <version>${batik-transcoder.version}</version>
            </dependency>
            <dependency>
              <groupId>org.apache.xmlgraphics</groupId>
              <artifactId>batik-codec</artifactId>
              <version>${batik-codec.version}</version>
            </dependency>
            <dependency>
              <groupId>org.activiti</groupId>
              <artifactId>activiti-json-converter</artifactId>
              <version>${activiti-json-converter.version}</version>
            </dependency>
            <!-- activiti -->
            <dependency>
              <groupId>org.activiti</groupId>
              <artifactId>activiti-spring-boot-starter</artifactId>
              <version>${activiti-spring-boot-starter.version}</version>
            </dependency>
            <dependency>
              <groupId>org.activiti</groupId>
              <artifactId>activiti-image-generator</artifactId>
              <version>${activiti-spring-boot-starter.version}</version>
            </dependency>
          </dependencies>
      View Code

      參數移除了imageType、customClassLoader,生成的文件格式為svg,在響應給客戶端流程圖的時候,可以設置響應類型

      response.setContentType("image/svg+xml");
      IOUtils.copy(is, response.getOutputStream());
      或者把svg轉換為png
      new PNGTranscoder().transcode(new TranscoderInput(is), new TranscoderOutput(response.getOutputStream()));

      is為生成的文件流。

      具體實現代碼:

      ProcessDiagramGenerator

       1 import org.activiti.bpmn.model.BpmnModel;
       2 
       3 import java.awt.*;
       4 import java.io.InputStream;
       5 import java.util.List;
       6 import java.util.Set;
       7 
       8 /**
       9  * @author penglibo
      10  * @date 2022-11-24 09:11:02
      11  * @since jdk 1.8
      12  */
      13 
      14 public interface ProcessDiagramGenerator extends org.activiti.image.ProcessDiagramGenerator {
      15 
      16     /**
      17      * 生成流程圖
      18      * @param bpmnModel             模型
      19      * @param highLightedActivities 高亮已經執行流程節點ID集合
      20      * @param highLightedFlows      高亮流程已發生流轉的線id集合
      21      * @param activityFontName
      22      * @param labelFontName
      23      * @param annotationFontName
      24      * @param colors                流程圖顏色定義,這里固定寫死的,[0]new Color(0, 205, 0)-綠色-已經運行后的流程;[1]new Color(255, 0, 0)-紅色-當前正在執行的流程;
      25      * @param activityIds           當前激活的節點
      26      * @return
      27      */
      28     InputStream generateDiagram(BpmnModel bpmnModel,
      29                                 List<String> highLightedActivities,
      30                                 List<String> highLightedFlows,
      31                                 String activityFontName,
      32                                 String labelFontName,
      33                                 String annotationFontName,
      34                                 Color[] colors,
      35                                 Set<String> activityIds);
      36 }
      View Code
      ProcessDiagramGeneratorImpl
      import org.activiti.bpmn.model.Process;
      import org.activiti.bpmn.model.*;
      import org.activiti.image.impl.DefaultProcessDiagramCanvas;
      import org.activiti.image.impl.DefaultProcessDiagramGenerator;
      import org.springframework.stereotype.Component;
      import org.springframework.util.CollectionUtils;
      
      import java.awt.*;
      import java.io.InputStream;
      import java.util.Collections;
      import java.util.List;
      import java.util.Set;
      
      /**
       * @author penglibo
       * @date 2023-11-24 10:02:33
       * @since jdk 1.8
       */
      
      public class ProcessDiagramGeneratorImpl extends DefaultProcessDiagramGenerator implements ProcessDiagramGenerator {
      
          /**
           * {@link DefaultProcessDiagramGenerator#generateProcessDiagram(BpmnModel, List, List, String, String, String)}
           */
          public ProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel,
                                                             List<String> highLightedActivities, List<String> highLightedFlows, String activityFontName,
                                                             String labelFontName, String annotationFontName,
                                                             Color[] colors, Set<String> currIds) {
              if (null == highLightedActivities) {
                  highLightedActivities = Collections.emptyList();
              }
              if (null == highLightedFlows) {
                  highLightedFlows = Collections.emptyList();
              }
      
              prepareBpmnModel(bpmnModel);
      
              ProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, activityFontName, labelFontName, annotationFontName);
      
              // Draw pool shape, if process is participant in collaboration
              for (Pool pool : bpmnModel.getPools()) {
                  GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
                  processDiagramCanvas.drawPoolOrLane(pool.getId(), pool.getName(), graphicInfo);
              }
      
              // Draw lanes
              for (Process process : bpmnModel.getProcesses()) {
                  for (Lane lane : process.getLanes()) {
                      GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId());
                      processDiagramCanvas.drawPoolOrLane(lane.getId(), lane.getName(), graphicInfo);
                  }
              }
      
              // 繪制活動及其序列流,這里添加了colors, currIds
              for (Process process : bpmnModel.getProcesses()) {
                  List<FlowNode> flowNodeList = process.findFlowElementsOfType(FlowNode.class);
                  for (FlowNode flowNode : flowNodeList) {
                      drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, colors, currIds);
                  }
              }
      
              // 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;
          }
      
          /**
           * {@link DefaultProcessDiagramGenerator#drawActivity(DefaultProcessDiagramCanvas, BpmnModel, FlowNode, List, List)}
           */
          protected void drawActivity(ProcessDiagramCanvas processDiagramCanvas,
                                      BpmnModel bpmnModel,
                                      FlowNode flowNode,
                                      List<String> highLightedActivities,
                                      List<String> highLightedFlows,
                                      Color[] colors,
                                      Set<String> currIds) {
              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 highlighted activities
                  // historicActivityInstance里取得的list中,最后一個節點就是當前節點,前面的節點都是已完成的節點
                  if (highLightedActivities.contains(flowNode.getId())) {
                      if (!CollectionUtils.isEmpty(currIds) && currIds.contains(flowNode.getId()) && !(flowNode instanceof Gateway)) {
                          // 非結束節點,并且是當前節點
                          drawHighLight((flowNode instanceof StartEvent), processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()), colors[1]);
                      } else {
                          // 普通節點
                          drawHighLight((flowNode instanceof StartEvent) || (flowNode instanceof EndEvent), processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()), colors[0]);
                      }
                  }
      
              }
      
              // Outgoing transitions of activity
              for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
                  String flowId = sequenceFlow.getId();
                  boolean highLighted = (highLightedFlows.contains(flowId));
                  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(flowId)) {
                      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(flowId);
                  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, false, isDefault, highLighted, colors[0]);
                      processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault, highLighted, colors[0]);
      
                      // 繪制序列流標簽
                      GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(flowId);
                      if (labelGraphicInfo != null) {
                          processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
                      } else {
                          // 解決流程圖連線名稱不顯示的BUG
                          GraphicInfo lineCenter = getLineCenter(graphicInfoList);
                          processDiagramCanvas.drawLabel(highLighted, sequenceFlow.getName(), lineCenter, Math.abs(xPoints[1] - xPoints[0]) >= 5);
                      }
                  }
              }
      
              // Nested elements
              if (flowNode instanceof FlowElementsContainer) {
                  for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
                      if (nestedFlowElement instanceof FlowNode) {
                          drawActivity(processDiagramCanvas,
                                  bpmnModel,
                                  (FlowNode) nestedFlowElement,
                                  highLightedActivities,
                                  highLightedFlows);
                      }
                  }
              }
          }
      
          protected void drawHighLight(boolean isStartOrEnd, ProcessDiagramCanvas
                  processDiagramCanvas, GraphicInfo graphicInfo, Color color) {
              processDiagramCanvas.drawHighLight(isStartOrEnd, (int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), color);
          }
      
          /**
           * 拷貝DefaultProcessDiagramCanvas方法
           * @return {@link org.activiti.image.impl.DefaultProcessDiagramGenerator#initProcessDiagramCanvas
           */
          protected static ProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel,
                                                                         String activityFontName,
                                                                         String labelFontName,
                                                                         String annotationFontName) {
      
              // 我們需要計算最大值,以了解圖像整體的大小
              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 ProcessDiagramCanvas(
                      (int) maxX + 10,
                      (int) maxY + 10,
                      (int) minX,
                      (int) minY,
                      activityFontName,
                      labelFontName,
                      annotationFontName);
          }
      
          @Override
          public InputStream generateDiagram(BpmnModel bpmnModel, List<String> highLightedActivities,
                                             List<String> highLightedFlows, String activityFontName, String labelFontName, String
                                                     annotationFontName,
                                             Color[] colors, Set<String> activityIds) {
              ProcessDiagramCanvas processDiagramCanvas = generateProcessDiagram(bpmnModel, highLightedActivities, highLightedFlows,
                      activityFontName, labelFontName, annotationFontName, colors, activityIds);
              return processDiagramCanvas.generateImage();
          }
      
          @Override
          public InputStream generateDiagram(BpmnModel bpmnModel, String activityFontName, String labelFontName, String
                  annotationFontName) {
              return generateDiagram(bpmnModel, Collections.<String>emptyList(), Collections.<String>emptyList(),
                      activityFontName, labelFontName, annotationFontName, new Color[]{Color.BLACK, Color.BLACK}, null);
          }
      
      }
      View Code
      ProcessDiagramCanvas
        1 import org.activiti.bpmn.model.AssociationDirection;
        2 import org.activiti.bpmn.model.GraphicInfo;
        3 import org.activiti.image.impl.DefaultProcessDiagramCanvas;
        4 
        5 import java.awt.*;
        6 import java.awt.font.FontRenderContext;
        7 import java.awt.font.LineBreakMeasurer;
        8 import java.awt.font.TextAttribute;
        9 import java.awt.font.TextLayout;
       10 import java.awt.geom.Line2D;
       11 import java.awt.geom.Rectangle2D;
       12 import java.awt.geom.RoundRectangle2D;
       13 import java.text.AttributedCharacterIterator;
       14 import java.text.AttributedString;
       15 
       16 /**
       17  * @author penglibo
       18  * @date 2023-11-24 10:35:13
       19  * @since jdk 1.8
       20  */
       21 
       22 public class ProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
       23 
       24     protected static Color LABEL_COLOR = new Color(0, 0, 0);
       25 
       26     /** 動態流程圖顏色定義 **/
       27     public static final Color COLOR_NORMAL = new Color(0, 205, 0);
       28 
       29     public static final Color COLOR_CURRENT = new Color(255, 0, 0);
       30 
       31     //font
       32     protected String labelFontName = "宋體";
       33 
       34     /**
       35      * 移除了String imageType和ClassLoader customClassLoader
       36      */
       37     public ProcessDiagramCanvas(int width, int height, int minX, int minY, String activityFontName, String labelFontName, String annotationFontName) {
       38         super(width, height, minX, minY, activityFontName, labelFontName, annotationFontName);
       39     }
       40 
       41     /**
       42      * {@link DefaultProcessDiagramCanvas#drawHighLight(int, int, int, int)}
       43      */
       44     public void drawHighLight(boolean isStartOrEnd,
       45                               int x,
       46                               int y,
       47                               int width,
       48                               int height,
       49                               Color color) {
       50         Paint originalPaint = g.getPaint();
       51         Stroke originalStroke = g.getStroke();
       52 
       53         // 這里是高亮的顏色
       54         g.setPaint(color);
       55         g.setStroke(MULTI_INSTANCE_STROKE);
       56         if (isStartOrEnd) {
       57             // 開始、結束節點畫圓
       58             g.drawOval(x, y, width, height);
       59         } else {
       60             // 非開始、結束節點畫圓角矩形
       61             RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 5, 5);
       62             g.draw(rect);
       63         }
       64         g.setPaint(originalPaint);
       65         g.setStroke(originalStroke);
       66     }
       67 
       68     /**
       69      * {@link DefaultProcessDiagramCanvas#drawSequenceflow(int[], int[], boolean, boolean, boolean)}
       70      */
       71     public void drawSequenceflow(int[] xPoints,
       72                                  int[] yPoints,
       73                                  boolean conditional,
       74                                  boolean isDefault,
       75                                  boolean highLighted,
       76                                  Color color) {
       77         drawConnection(xPoints,
       78                 yPoints,
       79                 conditional,
       80                 isDefault,
       81                 "sequenceFlow",
       82                 AssociationDirection.ONE,
       83                 highLighted,
       84                 color);
       85     }
       86 
       87     /**
       88      * {@link DefaultProcessDiagramCanvas#drawConnection(int[], int[], boolean, boolean, String, AssociationDirection, boolean)}
       89      */
       90     public void drawConnection(int[] xPoints,
       91                                int[] yPoints,
       92                                boolean conditional,
       93                                boolean isDefault,
       94                                String connectionType,
       95                                AssociationDirection associationDirection,
       96                                boolean highLighted,
       97                                Color color) {
       98 
       99         Paint originalPaint = g.getPaint();
      100         Stroke originalStroke = g.getStroke();
      101 
      102         g.setPaint(CONNECTION_COLOR);
      103         if ("association".equals(connectionType)) {
      104             g.setStroke(ASSOCIATION_STROKE);
      105         } else if (highLighted) {
      106             // 設置高亮顏色
      107             g.setPaint(color);
      108             g.setStroke(HIGHLIGHT_FLOW_STROKE);
      109         }
      110 
      111         for (int i = 1; i < xPoints.length; i++) {
      112             int sourceX = xPoints[i - 1];
      113             int sourceY = yPoints[i - 1];
      114             int targetX = xPoints[i];
      115             int targetY = yPoints[i];
      116             Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY);
      117             g.draw(line);
      118         }
      119 
      120         if (isDefault) {
      121             Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
      122             drawDefaultSequenceFlowIndicator(line);
      123         }
      124 
      125         if (conditional) {
      126             Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
      127             drawConditionalSequenceFlowIndicator(line);
      128         }
      129 
      130         if (associationDirection.equals(AssociationDirection.ONE)
      131                 || associationDirection.equals(AssociationDirection.BOTH)) {
      132             Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2],
      133                     xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]);
      134             drawArrowHead(line);
      135         }
      136         if (associationDirection.equals(AssociationDirection.BOTH)) {
      137             Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]);
      138             drawArrowHead(line);
      139         }
      140         g.setPaint(originalPaint);
      141         g.setStroke(originalStroke);
      142     }
      143 
      144     /**
      145      * {@link DefaultProcessDiagramCanvas#drawLabel(String, GraphicInfo, boolean)}
      146      */
      147     public void drawLabel(boolean highLighted, String text, GraphicInfo graphicInfo, boolean centered) {
      148         float interline = 1.0f;
      149 
      150         // text
      151         if (text != null && text.length() > 0) {
      152             Paint originalPaint = g.getPaint();
      153             Font originalFont = g.getFont();
      154             if (highLighted) {
      155                 g.setPaint(COLOR_NORMAL);
      156             } else {
      157                 g.setPaint(LABEL_COLOR);
      158             }
      159             g.setFont(new Font(labelFontName, Font.BOLD, 10));
      160 
      161             int wrapWidth = 100;
      162             int textY = (int) graphicInfo.getY();
      163 
      164             AttributedString as = new AttributedString(text);
      165             as.addAttribute(TextAttribute.FOREGROUND, g.getPaint());
      166             as.addAttribute(TextAttribute.FONT, g.getFont());
      167             AttributedCharacterIterator aci = as.getIterator();
      168             FontRenderContext frc = new FontRenderContext(null, true, false);
      169             LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
      170 
      171             while (lbm.getPosition() < text.length()) {
      172                 TextLayout tl = lbm.nextLayout(wrapWidth);
      173                 textY += tl.getAscent();
      174                 Rectangle2D bb = tl.getBounds();
      175                 double tX = graphicInfo.getX();
      176                 if (centered) {
      177                     tX += (int) (graphicInfo.getWidth() / 2 - bb.getWidth() / 2);
      178                 }
      179                 tl.draw(g, (float) tX, textY);
      180                 textY += tl.getDescent() + tl.getLeading() + (interline - 1.0f) * tl.getAscent();
      181             }
      182 
      183             // restore originals
      184             g.setFont(originalFont);
      185             g.setPaint(originalPaint);
      186         }
      187     }
      188 }
      View Code

      查看流程圖代碼:

              BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
              // activiti7移除了靜態方法創建,需要DefaultProcessDiagramGenerator實例。
              // ProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
              // 由于是創建的新實例,這里的DiagramGenerator就不用注入到配置類里面了,當然ActivitiConfiguration配置類也移除了set的方法。
              ProcessDiagramGeneratorImpl diagramGenerator = new ProcessDiagramGeneratorImpl();
              InputStream is = diagramGenerator.generateDiagram(bpmnModel, "宋體", "宋體", "宋體");
              try {
                  HttpServletResponse response = ServletUtil.getResponse();
      
                  // 響應svg到客戶端
                  // response.setContentType("image/svg+xml");
                  // IOUtils.copy(is, response.getOutputStream());
      
                  // 轉換svg為png響應
                  response.setContentType("image/png");
                  new PNGTranscoder().transcode(new TranscoderInput(is), new TranscoderOutput(response.getOutputStream()));
      
              } catch (Exception e) {
                  throw new RuntimeException(e);
              }

      效果:

      流程進度高亮

      ActivitiUtil

       1 import org.activiti.bpmn.model.BpmnModel;
       2 import org.activiti.bpmn.model.FlowNode;
       3 import org.activiti.bpmn.model.SequenceFlow;
       4 import org.activiti.engine.history.HistoricActivityInstance;
       5 import org.springframework.util.CollectionUtils;
       6 
       7 import java.util.ArrayList;
       8 import java.util.HashMap;
       9 import java.util.List;
      10 import java.util.Map;
      11 
      12 /**
      13  * @author penglibo
      14  * @date 2023-11-24 17:29:08
      15  * @since jdk 1.8
      16  */
      17 public class ActivitiUtil {
      18 
      19     /**
      20      * 獲取已經流轉的線
      21      * @param bpmnModel                 流程圖模板
      22      * @param historicActivityInstances 歷史實例
      23      */
      24     public static List<String> getHighLightedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
      25         // 高亮流程已發生流轉的線id集合
      26         List<String> highLightedFlowIds = new ArrayList<>();
      27         // 全部活動節點
      28         List<FlowNode> historicActivityNodes = new ArrayList<>();
      29         // 已完成的歷史活動節點
      30         List<HistoricActivityInstance> finishedActivityInstances = new ArrayList<>();
      31 
      32         for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
      33             FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true);
      34             historicActivityNodes.add(flowNode);
      35             if (historicActivityInstance.getEndTime() != null) {
      36                 finishedActivityInstances.add(historicActivityInstance);
      37             }
      38         }
      39 
      40         FlowNode currentFlowNode = null;
      41         FlowNode targetFlowNode = null;
      42         // 遍歷已完成的活動實例,從每個實例的outgoingFlows中找到已執行的
      43         for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
      44             // 獲得當前活動對應的節點信息及outgoingFlows信息
      45             currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
      46             List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();
      47 
      48             /**
      49              * 遍歷outgoingFlows并找到已已流轉的 滿足如下條件認為已已流轉: 1.當前節點是并行網關或兼容網關,則通過outgoingFlows能夠在歷史活動中找到的全部節點均為已流轉 2.當前節點是以上兩種類型之外的,通過outgoingFlows查找到的時間最早的流轉節點視為有效流轉
      50              */
      51             if ("parallelGateway".equals(currentActivityInstance.getActivityType()) || "inclusiveGateway".equals(currentActivityInstance.getActivityType())) {
      52                 // 遍歷歷史活動節點,找到匹配流程目標節點的
      53                 for (SequenceFlow sequenceFlow : sequenceFlows) {
      54                     targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
      55                     if (historicActivityNodes.contains(targetFlowNode)) {
      56                         highLightedFlowIds.add(targetFlowNode.getId());
      57                     }
      58                 }
      59             } else {
      60                 List<Map<String, Object>> tempMapList = new ArrayList<>();
      61                 for (SequenceFlow sequenceFlow : sequenceFlows) {
      62                     for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
      63                         if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
      64                             Map<String, Object> map = new HashMap<>();
      65                             map.put("highLightedFlowId", sequenceFlow.getId());
      66                             map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime());
      67                             tempMapList.add(map);
      68                         }
      69                     }
      70                 }
      71 
      72                 if (!CollectionUtils.isEmpty(tempMapList)) {
      73                     // 遍歷匹配的集合,取得開始時間最早的一個
      74                     long earliestStamp = 0L;
      75                     String highLightedFlowId = null;
      76                     for (Map<String, Object> map : tempMapList) {
      77                         long highLightedFlowStartTime = Long.parseLong(map.get("highLightedFlowStartTime").toString());
      78                         if (earliestStamp == 0 || earliestStamp >= highLightedFlowStartTime) {
      79                             highLightedFlowId = map.get("highLightedFlowId").toString();
      80                             earliestStamp = highLightedFlowStartTime;
      81                         }
      82                     }
      83 
      84                     highLightedFlowIds.add(highLightedFlowId);
      85                 }
      86 
      87             }
      88 
      89         }
      90         return highLightedFlowIds;
      91     }
      92 }
      View Code

      查看流程進度代碼:

       1 // 定義businessKey,一般為流程實例key與實際業務數據的結合
       2             String businessKey = apply.getDefKey() + ":" + apply.getId();
       3             // 如果流程結束(駁回),當前流程實例為空
       4             ProcessInstance process = runtimeService.createProcessInstanceQuery()
       5                     .processDefinitionKey(apply.getDefKey())
       6                     .processInstanceBusinessKey(businessKey)
       7                     .singleResult();
       8 
       9             // 獲取歷史流程實例來查詢流程進度
      10             HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
      11             if (null == processInstance) {
      12                 log.error("流程信息不存在");
      13                 return;
      14             }
      15             // 獲取流程中已經執行的節點,按照執行先后順序排序
      16             List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
      17                     // 這里,如果流程結束的話,process會為空,所以查詢歷史流程,這樣也能看到結束的流程進度信息。
      18                     .processInstanceId(null == process ? processInstance.getId() : process.getId())
      19                     .orderByHistoricActivityInstanceStartTime().asc().list();
      20             BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
      21             // highLightedActivities(需要高亮的執行流程節點集合的獲取)以及
      22             // highLightedFlows(需要高亮流程連接線集合的獲取)
      23             // 高亮流程已發生流轉的線id集合
      24             List<String> highLightedFlowIds = ActivitiUtil.getHighLightedFlows(bpmnModel, historicActivityInstances);
      25 
      26             // 高亮已經執行流程節點ID集合
      27             List<String> highLightedActivitiIds = historicActivityInstances.stream().map(HistoricActivityInstance::getActivityId).collect(Collectors.toList());
      28 
      29             Set<String> activityIds = runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).list()
      30                     .stream().map(org.activiti.engine.runtime.Execution::getActivityId).collect(Collectors.toSet());
      31             // activiti7移除了靜態方法創建,需要DefaultProcessDiagramGenerator實例
      32             // ProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
      33             // 由于是創建的新實例,這里的DiagramGenerator就不用注入到配置類里面了,當然ActivitiConfiguration配置類也移除了set的方法。
      34             ProcessDiagramGeneratorImpl diagramGenerator = new ProcessDiagramGeneratorImpl();
      35             // 使用默認配置獲得流程圖表生成器,并生成追蹤圖片字符流
      36             InputStream is = diagramGenerator.generateDiagram(bpmnModel,
      37                     highLightedActivitiIds,
      38                     highLightedFlowIds,
      39                     "宋體",
      40                     "微軟雅黑",
      41                     "黑體",
      42                     new Color[]{ProcessDiagramCanvas.COLOR_NORMAL, ProcessDiagramCanvas.COLOR_CURRENT},
      43                     activityIds
      44             );
      45 
      46             HttpServletResponse response = ServletUtil.getResponse();
      47 
      48             // 響應svg到客戶端
      49             // response.setContentType("image/svg+xml");
      50             // IOUtils.copy(is, response.getOutputStream());
      51 
      52             // 轉換svg為png響應
      53             response.setContentType("image/png");
      54             new PNGTranscoder().transcode(new TranscoderInput(is), new TranscoderOutput(response.getOutputStream()));
      View Code

      效果:

      bpmn-js

      流程設計:

      - 官網:https://bpmn.io/
      - 倉庫:https://github.com/bpmn-io/bpmn-js

      流程進度高亮:

      源碼倉庫地址:

      https://gitee.com/cmmplb/spring-boot-activiti  

      posted on 2023-12-07 14:35  夏目co  閱讀(3317)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 日韩成人福利视频在线观看| 国产蜜臀av在线一区二区| 泸水县| 国产色婷婷亚洲99精品小说| 成人性能视频在线| 粉嫩在线一区二区三区视频| 国产偷窥熟女高潮精品视频| 久女女热精品视频在线观看| 亚洲精品中文av在线| 欧美怡春院一区二区三区| 爱性久久久久久久久| 无码国产成人午夜电影在线观看| 人妻精品人妻无码一区二区三区| 撕开奶罩揉吮奶头高潮av| 黄色特级片一区二区三区| 亚洲欧洲精品日韩av| 好紧好滑好湿好爽免费视频| 国产精品无码a∨麻豆| 九九热视频在线免费观看| 99精品国产兔费观看久久99| 99精品全国免费观看视频| 日本不卡码一区二区三区| 92精品国产自产在线观看481页| 华人在线亚洲欧美精品| 亚洲产在线精品亚洲第一站一| 国产精品深夜福利免费观看| 亚洲熟妇自偷自拍另亚洲| 97久久久亚洲综合久久| 亚洲精品www久久久久久| 97免费公开在线视频| 国产精品黄色一区二区三区| 国产精品大片中文字幕| 国产精品大片中文字幕| 免费无码成人AV片在线| 高清不卡一区二区三区| 亚洲伊人久久大香线蕉| 久久综合狠狠综合久久| 国产亚洲精品黑人粗大精选| 欧美人与动牲交A免费观看| 丁香花成人电影| 亚洲午夜精品久久久久久浪潮|