activity工作流多实例并发绘图工具类

源代码只支持单实例,为了增加可用性本人进行了优化,现分享如下:


使用方式:

public void traceImage(String processid,HttpServletResponse response,String... executionids) throws IOException {
		Command<InputStream> cmd = new HistoryProcessInstanceDiagramCmd(processid,executionids);
		InputStream is = managementService.executeCommand(cmd);
		int len = 0;
		byte[] b = new byte[1024];

		while ((len = is.read(b, 0, 1024)) != -1) {
			response.getOutputStream().write(b, 0, len);
		}
	}
补充:controller层实战代码,调用traceImage示例。注意:传入的executionids最好排序asc

@RequestMapping(path="/showproccess")
	@ResponseBody
	public Result viewtraceImageByActiviti(@RequestParam String eventid,String prepeople,HttpServletResponse response){
		try {
			String businessKey = BPM_KEY+"."+eventid;
			ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();			
			if(p==null){//查历史流程 从新到旧
				List<HistoricProcessInstance> his_pros = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).excludeSubprocesses(false).orderByProcessInstanceId().desc().list();
				if(his_pros.size()==0){
					return Result.failure("无流程");
				}else{
					service.traceImage(his_pros.get(0).getId(),response);
				}
			}else{//查运行的流程
				//通过关联人、查出 执行中的executionid
				List<HistoricTaskInstance> list_hisTask = historyService.createHistoricTaskInstanceQuery().processInstanceId(p.getProcessInstanceId()).taskInvolvedUser(prepeople).list();
				if(list_hisTask.size()==0){
					service.traceImage(p.getProcessInstanceId(),response);//看当前总流程
					return Result.failure("无相关流程");
				}
				String executionid = list_hisTask.get(0).getExecutionId();
				List<Execution> ex_list = runtimeService.createExecutionQuery().processInstanceId(p.getProcessInstanceId()).list();
				service.traceImage(list_hisTask.get(0).getProcessInstanceId(),response,getExecutions(ex_list,executionid));
			}

			
			return Result.success(null); 
		} catch (Exception e) {
			e.printStackTrace();
			return Result.failure(e.getMessage(),null);
		}
	}
	
	
	
	public String[] getExecutions(List<Execution> list,String executionid){
		List<String> lists = new ArrayList<String>();
		//获取
		Execution e = getExecution(list,executionid);
		//获取父id
		Execution ex =e;
		while(ex!=null){
			lists.add(ex.getId());
			ex = getExecution(list,ex.getParentId());	
		}
		//获取子id
		lists.addAll(getExecutionChilds(list,executionid));
		//排序
		Collections.sort(lists);
		String[] arr = lists.toArray(new String[lists.size()]);
		for(String str:arr){
			System.out.println(str);
		}		
		return arr;
		
	}
	private Execution getExecution(List<Execution> list,String executionid){
		for(Execution e : list){
			if(e.getId().equals(executionid))
				return e;	
		}
		return null;
	}
	
	private List<String> getExecutionChilds(List<Execution> list,String executionid){
		List<String> list1 = new ArrayList<String>();
		//加载次节点
		for(Execution e : list){
			if(executionid.equals(e.getParentId()))
				list1.add(e.getId());	
		}
		//加载次节点的子节点
		for(String childid :list1){
			list1.addAll(getExecutionChilds(list,childid));
		}
		return list1;
	}




以下部分为工具类的所有代码:

package com.zihai.activiti.util;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ActivitiHistoryGraphBuilder {
    private static Logger logger = LoggerFactory
            .getLogger(ActivitiHistoryGraphBuilder.class);
    private ProcessDefinitionEntity processDefinitionEntity;
    private List<HistoricActivityInstance> historicActivityInstances;
    private List<HistoricActivityInstance> visitedHistoricActivityInstances = new ArrayList<HistoricActivityInstance>();
    private Map<String, Node> nodeMap = new HashMap<String, Node>();

    public ActivitiHistoryGraphBuilder(ProcessDefinitionEntity processDefinitionEntity,List<HistoricActivityInstance> historicActivityInstances) {
    	this.processDefinitionEntity = processDefinitionEntity;
    	this.historicActivityInstances = historicActivityInstances;
    }

    public Graph build() {

        Graph graph = new Graph();

        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
            Node currentNode = new Node();
            currentNode.setId(historicActivityInstance.getId());
            currentNode.setName(historicActivityInstance.getActivityId());
            currentNode.setType(historicActivityInstance.getActivityType());
            currentNode
                    .setActive(historicActivityInstance.getEndTime() == null);
            logger.debug("currentNode : {}:{}", currentNode.getName(),
                    currentNode.getId());

            Edge previousEdge = this.findPreviousEdge(currentNode,
                    historicActivityInstance.getStartTime().getTime());

            if (previousEdge == null) {
            	 graph.addInitial(currentNode);
            } else {
                logger.debug("previousEdge : {}", previousEdge.getName());
            }

            nodeMap.put(currentNode.getId(), currentNode);
            visitedHistoricActivityInstances.add(historicActivityInstance);
        }

        if (graph.getInitial() == null) {
            throw new IllegalStateException("cannot find initial.");
        }

        return graph;
    }


    public Edge findPreviousEdge(Node currentNode, long currentStartTime) {
        String activityId = currentNode.getName();
        ActivityImpl activityImpl = processDefinitionEntity
                .findActivity(activityId);
        HistoricActivityInstance nestestHistoricActivityInstance = null;
        String temporaryPvmTransitionId = null;

        // 遍历进入当前节点的所有连线
        for (PvmTransition pvmTransition : activityImpl
                .getIncomingTransitions()) {
            PvmActivity source = pvmTransition.getSource();

            String previousActivityId = source.getId();

            HistoricActivityInstance visitiedHistoryActivityInstance = this
                    .findVisitedHistoricActivityInstance(previousActivityId);

            if (visitiedHistoryActivityInstance == null) {
                continue;
            }

            // 如果上一个节点还未完成,说明不可能是从这个节点过来的,跳过
            if (visitiedHistoryActivityInstance.getEndTime() == null) {
                continue;
            }

            logger.debug("current activity start time : {}", new Date(
                    currentStartTime));
            logger.debug("nestest activity end time : {}",
                    visitiedHistoryActivityInstance.getEndTime());

            // 如果当前节点的开始时间,比上一个节点的结束时间要早,跳过
            if (currentStartTime < visitiedHistoryActivityInstance.getEndTime()
                    .getTime()) {
                continue;
            }

            if (nestestHistoricActivityInstance == null) {
                nestestHistoricActivityInstance = visitiedHistoryActivityInstance;
                temporaryPvmTransitionId = pvmTransition.getId();
            } else if ((currentStartTime - nestestHistoricActivityInstance
                    .getEndTime().getTime()) > (currentStartTime - visitiedHistoryActivityInstance
                    .getEndTime().getTime())) {
                // 寻找离当前节点最近的上一个节点
                // 比较上一个节点的endTime与当前节点startTime的差
                nestestHistoricActivityInstance = visitiedHistoryActivityInstance;
                temporaryPvmTransitionId = pvmTransition.getId();
            }
        }

        // 没找到上一个节点,就返回null
        if (nestestHistoricActivityInstance == null) {
            return null;
        }

        Node previousNode = nodeMap
                .get(nestestHistoricActivityInstance.getId());

        if (previousNode == null) {
            return null;
        }

        logger.debug("previousNode : {}:{}", previousNode.getName(),
                previousNode.getId());

        Edge edge = new Edge();
        edge.setName(temporaryPvmTransitionId);
        previousNode.getEdges().add(edge);
        edge.setSrc(previousNode);
        edge.setDest(currentNode);

        return edge;
    }

    public HistoricActivityInstance findVisitedHistoricActivityInstance(
            String activityId) {
        for (int i = visitedHistoricActivityInstances.size() - 1; i >= 0; i--) {
            HistoricActivityInstance historicActivityInstance = visitedHistoricActivityInstances
                    .get(i);

            if (activityId.equals(historicActivityInstance.getActivityId())) {
                return historicActivityInstance;
            }
        }

        return null;
    }
}

package com.zihai.activiti.util;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Ellipse2D.Double;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import org.activiti.bpmn.constants.BpmnXMLConstants;
import org.activiti.bpmn.model.Artifact;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowElementsContainer;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.GraphicInfo;
import org.activiti.bpmn.model.Lane;
import org.activiti.bpmn.model.Pool;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.HistoricActivityInstanceQueryImpl;
import org.activiti.engine.impl.Page;
import org.activiti.engine.impl.cmd.GetBpmnModelCmd;
import org.activiti.engine.impl.cmd.GetDeploymentProcessDefinitionCmd;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.apache.commons.io.FilenameUtils;

/**
 * 流程图绘制工具
 */
public class CustomProcessDiagramGenerator {
    public static final int OFFSET_SUBPROCESS = 5;
    public static final int OFFSET_TASK = 20;
    private static List<String> taskType = new ArrayList<String>();
    private static List<String> eventType = new ArrayList<String>();
    private static List<String> gatewayType = new ArrayList<String>();
    private static List<String> subProcessType = new ArrayList<String>();
    private static Color RUNNING_COLOR = Color.RED;
    private static Color HISTORY_COLOR = Color.GREEN;
    private static Color SKIP_COLOR = Color.GRAY;
    private static Stroke THICK_BORDER_STROKE = new BasicStroke(3.0f);
    private int minX;
    private int minY;
    BpmnModel bpmnModel;
    ProcessDefinitionEntity definition;
    List<HistoricActivityInstance> activityInstances = new ArrayList<HistoricActivityInstance>();

    public CustomProcessDiagramGenerator() {
        init();
    }

    protected static void init() {
        taskType.add(BpmnXMLConstants.ELEMENT_TASK_MANUAL);
        taskType.add(BpmnXMLConstants.ELEMENT_TASK_RECEIVE);
        taskType.add(BpmnXMLConstants.ELEMENT_TASK_SCRIPT);
        taskType.add(BpmnXMLConstants.ELEMENT_TASK_SEND);
        taskType.add(BpmnXMLConstants.ELEMENT_TASK_SERVICE);
        taskType.add(BpmnXMLConstants.ELEMENT_TASK_USER);

        gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_EXCLUSIVE);
        gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_INCLUSIVE);
        gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_EVENT);
        gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL);

        eventType.add("intermediateTimer");
        eventType.add("intermediateMessageCatch");
        eventType.add("intermediateSignalCatch");
        eventType.add("intermediateSignalThrow");
        eventType.add("messageStartEvent");
        eventType.add("startTimerEvent");
        eventType.add(BpmnXMLConstants.ELEMENT_ERROR);
        eventType.add(BpmnXMLConstants.ELEMENT_EVENT_START);
        eventType.add("errorEndEvent");
        eventType.add(BpmnXMLConstants.ELEMENT_EVENT_END);

        subProcessType.add(BpmnXMLConstants.ELEMENT_SUBPROCESS);
        subProcessType.add(BpmnXMLConstants.ELEMENT_CALL_ACTIVITY);
    }

    /**
     * 根据任务id获得轨迹图
     * */
    public InputStream generateDiagram(String processInstanceId,String...executionIds)
            throws IOException {
    	 HistoricProcessInstance historicProcessInstance = Context
                 .getCommandContext().getHistoricProcessInstanceEntityManager()
                 .findHistoricProcessInstance(processInstanceId);
         String processDefinitionId = historicProcessInstance
                 .getProcessDefinitionId();
         GetBpmnModelCmd getBpmnModelCmd = new GetBpmnModelCmd(
                 processDefinitionId);
         bpmnModel = getBpmnModelCmd.execute(Context
                 .getCommandContext());
         Point point = getMinXAndMinY(bpmnModel);
		/*
		 * this.minX = point.x; this.minY = point.y; this.minX = (this.minX <=
		 * 5) ? 5 : this.minX; this.minY = (this.minY <= 5) ? 5 : this.minY;
		 * this.minX -= 5; this.minY -= 5;
		 * 
		 * this.minX =0; this.minY=0;
		 */
		/*
		 * this.minX = point.x; this.minY = point.y;
		 * System.out.println(this.minX + "=======" + this.minY); this.minX =
		 * (this.minX <= 5) ? 0 : this.minX; this.minY = (this.minY <= 5) ? 0 :
		 * this.minY;
		 */
		this.minX = point.x;
		this.minY = point.y;
		if (this.minX > 0) {
			this.minX = 0;
		}
		if (this.minY > 0) {
			this.minY = 0;
}
        definition = new GetDeploymentProcessDefinitionCmd(
                processDefinitionId).execute(Context.getCommandContext());
        String diagramResourceName = definition.getDiagramResourceName();
        String deploymentId = definition.getDeploymentId();
        byte[] bytes = Context
                .getCommandContext()
                .getResourceEntityManager()
                .findResourceByDeploymentIdAndResourceName(deploymentId,
                        diagramResourceName).getBytes();
        InputStream originDiagram = new ByteArrayInputStream(bytes);
        BufferedImage image = ImageIO.read(originDiagram);

        HistoricActivityInstanceQueryImpl historicActivityInstanceQueryImpl = new HistoricActivityInstanceQueryImpl();
        Page page = new Page(0, 100);
        if(executionIds.length==0){
            historicActivityInstanceQueryImpl.processInstanceId(processInstanceId);        
           activityInstances = Context .getCommandContext().getHistoricActivityInstanceEntityManager()
                    .findHistoricActivityInstancesByQueryCriteria( historicActivityInstanceQueryImpl, page);
        }else{
        	 for(int i=0;i<executionIds.length;i++){
        		 historicActivityInstanceQueryImpl.processInstanceId(processInstanceId).executionId(executionIds[i]);
        		 List<HistoricActivityInstance> act = Context .getCommandContext().getHistoricActivityInstanceEntityManager()
                         .findHistoricActivityInstancesByQueryCriteria( historicActivityInstanceQueryImpl, page);
                activityInstances.addAll(act);
        	 }

        }
                      

  

        this.drawHistoryFlow(image, processInstanceId);

        for (HistoricActivityInstance historicActivityInstance : activityInstances) {
            String historicActivityId = historicActivityInstance
                    .getActivityId();
            ActivityImpl activity = definition.findActivity(historicActivityId);

            if (activity != null) {
                if (historicActivityInstance.getEndTime() == null) {
                    // 节点正在运行中
                    signRunningNode(image, activity.getX() - this.minX,
                            activity.getY() - this.minY, activity.getWidth(),
                            activity.getHeight(),
                            historicActivityInstance.getActivityType());
                } else {
                    String deleteReason = null;

                    if (historicActivityInstance.getTaskId() != null) {
                        deleteReason = Context
                                .getCommandContext()
                                .getHistoricTaskInstanceEntityManager()
                                .findHistoricTaskInstanceById(
                                        historicActivityInstance.getTaskId())
                                .getDeleteReason();
                    }

                    // 节点已经结束
                    if ("completed".equals(deleteReason)) {
                        signSkipNode(image, activity.getX(),
                                activity.getY(),
                                activity.getWidth(), activity.getHeight(),
                                historicActivityInstance.getActivityType());
                    } else {
                        signHistoryNode(image, activity.getX() - this.minX,
                                activity.getY() - this.minY,
                                activity.getWidth(), activity.getHeight(),
                                historicActivityInstance.getActivityType());
                    }
                }
            }
        }

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        String formatName = getDiagramExtension(diagramResourceName);
        ImageIO.write(image, formatName, out);

        return new ByteArrayInputStream(out.toByteArray());
    }
    private static String getDiagramExtension(String diagramResourceName) {
        return FilenameUtils.getExtension(diagramResourceName);
    }

    /**
     * 标记运行节点
     * 
     * @param image
     *            原始图片
     * @param x
     *            左上角节点坐在X位置
     * @param y
     *            左上角节点坐在Y位置
     * @param width
     *            宽
     * @param height
     *            高
     * @param activityType
     *            节点类型
     */
    private static void signRunningNode(BufferedImage image, int x, int y,
            int width, int height, String activityType) {
        Color nodeColor = RUNNING_COLOR;
        Graphics2D graphics = image.createGraphics();

        try {
            drawNodeBorder(x, y, width, height, graphics, nodeColor,
                    activityType);
        } finally {
            graphics.dispose();
        }
    }

    /**
     * 标记历史节点
     * 
     * @param image
     *            原始图片
     * @param x
     *            左上角节点坐在X位置
     * @param y
     *            左上角节点坐在Y位置
     * @param width
     *            宽
     * @param height
     *            高
     * @param activityType
     *            节点类型
     */
    private static void signHistoryNode(BufferedImage image, int x, int y,
            int width, int height, String activityType) {
        Color nodeColor = HISTORY_COLOR;
        Graphics2D graphics = image.createGraphics();

        try {
            drawNodeBorder(x, y, width, height, graphics, nodeColor,
                    activityType);
        } finally {
            graphics.dispose();
        }
    }

    private static void signSkipNode(BufferedImage image, int x, int y,
            int width, int height, String activityType) {
        Color nodeColor = HISTORY_COLOR;
        Graphics2D graphics = image.createGraphics();

        try {
            drawNodeBorder(x, y, width, height, graphics, nodeColor,
                    activityType);
        } finally {
            graphics.dispose();
        }
    }

    /**
     * 绘制节点边框
     * 
     * @param x
     *            左上角节点坐在X位置
     * @param y
     *            左上角节点坐在Y位置
     * @param width
     *            宽
     * @param height
     *            高
     * @param graphics
     *            绘图对象
     * @param color
     *            节点边框颜色
     * @param activityType
     *            节点类型
     */
    protected static void drawNodeBorder(int x, int y, int width, int height,
            Graphics2D graphics, Color color, String activityType) {
        graphics.setPaint(color);
        graphics.setStroke(THICK_BORDER_STROKE);

        if (taskType.contains(activityType)) {
            drawTask(x, y, width, height, graphics);
        } else if (gatewayType.contains(activityType)) {
            drawGateway(x, y, width, height, graphics);
        } else if (eventType.contains(activityType)) {
            drawEvent(x, y, width, height, graphics);
        } else if (subProcessType.contains(activityType)) {
            drawSubProcess(x, y, width, height, graphics);
        }
    }

    /**
     * 绘制任务
     */
    protected static void drawTask(int x, int y, int width, int height,
            Graphics2D graphics) {
        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width,
                height, OFFSET_TASK, OFFSET_TASK);
        graphics.draw(rect);
    }

    /**
     * 绘制网关
     */
    protected static void drawGateway(int x, int y, int width, int height,
            Graphics2D graphics) {
        Polygon rhombus = new Polygon();
        rhombus.addPoint(x, y + (height / 2));
        rhombus.addPoint(x + (width / 2), y + height);
        rhombus.addPoint(x + width, y + (height / 2));
        rhombus.addPoint(x + (width / 2), y);
        graphics.draw(rhombus);
    }

    /**
     * 绘制任务
     */
    protected static void drawEvent(int x, int y, int width, int height,
            Graphics2D graphics) {
        Double circle = new Ellipse2D.Double(x, y, width, height);
        graphics.draw(circle);
    }

    /**
     * 绘制子流程
     */
    protected static void drawSubProcess(int x, int y, int width, int height,
            Graphics2D graphics) {
        RoundRectangle2D rect = new RoundRectangle2D.Double(x + 1, y + 1,
                width - 2, height - 2, OFFSET_SUBPROCESS, OFFSET_SUBPROCESS);
        graphics.draw(rect);
    }

    protected Point getMinXAndMinY(BpmnModel bpmnModel) {
        // We need to calculate maximum values to know how big the image will be in its entirety
        double theMinX = java.lang.Double.MAX_VALUE;
        double theMaxX = 0;
        double theMinY = java.lang.Double.MAX_VALUE;
        double theMaxY = 0;

        for (Pool pool : bpmnModel.getPools()) {
            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
            theMinX = graphicInfo.getX();
            theMaxX = graphicInfo.getX() + graphicInfo.getWidth();
            theMinY = graphicInfo.getY();
            theMaxY = 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()) > theMaxX) {
                theMaxX = flowNodeGraphicInfo.getX()
                        + flowNodeGraphicInfo.getWidth();
            }

            if (flowNodeGraphicInfo.getX() < theMinX) {
                theMinX = flowNodeGraphicInfo.getX();
            }

            // height
            if ((flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight()) > theMaxY) {
                theMaxY = flowNodeGraphicInfo.getY()
                        + flowNodeGraphicInfo.getHeight();
            }

            if (flowNodeGraphicInfo.getY() < theMinY) {
                theMinY = flowNodeGraphicInfo.getY();
            }

            for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
                List<GraphicInfo> graphicInfoList = bpmnModel
                        .getFlowLocationGraphicInfo(sequenceFlow.getId());

                for (GraphicInfo graphicInfo : graphicInfoList) {
                    // width
                    if (graphicInfo.getX() > theMaxX) {
                        theMaxX = graphicInfo.getX();
                    }

                    if (graphicInfo.getX() < theMinX) {
                        theMinX = graphicInfo.getX();
                    }

                    // height
                    if (graphicInfo.getY() > theMaxY) {
                        theMaxY = graphicInfo.getY();
                    }

                    if (graphicInfo.getY() < theMinY) {
                        theMinY = 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()) > theMaxX) {
                    theMaxX = artifactGraphicInfo.getX()
                            + artifactGraphicInfo.getWidth();
                }

                if (artifactGraphicInfo.getX() < theMinX) {
                    theMinX = artifactGraphicInfo.getX();
                }

                // height
                if ((artifactGraphicInfo.getY() + artifactGraphicInfo
                        .getHeight()) > theMaxY) {
                    theMaxY = artifactGraphicInfo.getY()
                            + artifactGraphicInfo.getHeight();
                }

                if (artifactGraphicInfo.getY() < theMinY) {
                    theMinY = artifactGraphicInfo.getY();
                }
            }

            List<GraphicInfo> graphicInfoList = bpmnModel
                    .getFlowLocationGraphicInfo(artifact.getId());

            if (graphicInfoList != null) {
                for (GraphicInfo graphicInfo : graphicInfoList) {
                    // width
                    if (graphicInfo.getX() > theMaxX) {
                        theMaxX = graphicInfo.getX();
                    }

                    if (graphicInfo.getX() < theMinX) {
                        theMinX = graphicInfo.getX();
                    }

                    // height
                    if (graphicInfo.getY() > theMaxY) {
                        theMaxY = graphicInfo.getY();
                    }

                    if (graphicInfo.getY() < theMinY) {
                        theMinY = graphicInfo.getY();
                    }
                }
            }
        }

        int nrOfLanes = 0;

        for (org.activiti.bpmn.model.Process process : bpmnModel.getProcesses()) {
            for (Lane l : process.getLanes()) {
                nrOfLanes++;

                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId());

                // // width
                if ((graphicInfo.getX() + graphicInfo.getWidth()) > theMaxX) {
                    theMaxX = graphicInfo.getX() + graphicInfo.getWidth();
                }

                if (graphicInfo.getX() < theMinX) {
                    theMinX = graphicInfo.getX();
                }

                // height
                if ((graphicInfo.getY() + graphicInfo.getHeight()) > theMaxY) {
                    theMaxY = graphicInfo.getY() + graphicInfo.getHeight();
                }

                if (graphicInfo.getY() < theMinY) {
                    theMinY = graphicInfo.getY();
                }
            }
        }

        // Special case, see http://jira.codehaus.org/browse/ACT-1431
        if ((flowNodes.size() == 0) && (bpmnModel.getPools().size() == 0)
                && (nrOfLanes == 0)) {
            // Nothing to show
            theMinX = 0;
            theMinY = 0;
        }

        return new Point((int) theMinX, (int) theMinY);
    }

    protected static List<Artifact> gatherAllArtifacts(BpmnModel bpmnModel) {
        List<Artifact> artifacts = new ArrayList<Artifact>();

        for (org.activiti.bpmn.model.Process process : bpmnModel.getProcesses()) {
            artifacts.addAll(process.getArtifacts());
        }

        return artifacts;
    }

    protected static List<FlowNode> gatherAllFlowNodes(BpmnModel bpmnModel) {
        List<FlowNode> flowNodes = new ArrayList<FlowNode>();

        for (org.activiti.bpmn.model.Process process : bpmnModel.getProcesses()) {
            flowNodes.addAll(gatherAllFlowNodes(process));
        }

        return flowNodes;
    }

    protected static List<FlowNode> gatherAllFlowNodes(
            FlowElementsContainer flowElementsContainer) {
        List<FlowNode> flowNodes = new ArrayList<FlowNode>();

        for (FlowElement flowElement : flowElementsContainer.getFlowElements()) {
            if (flowElement instanceof FlowNode) {
                flowNodes.add((FlowNode) flowElement);
            }

            if (flowElement instanceof FlowElementsContainer) {
                flowNodes
                        .addAll(gatherAllFlowNodes((FlowElementsContainer) flowElement));
            }
        }

        return flowNodes;
    }

    public void drawHistoryFlow(BufferedImage image, String processInstanceId) {
        Graph graph = new ActivitiHistoryGraphBuilder(definition, activityInstances)
                .build();

        for (Edge edge : graph.getEdges()) {
            drawSequenceFlow(image, edge.getName());
        }
    }

    public void drawSequenceFlow(BufferedImage image, String sequenceFlowId) {
        Graphics2D graphics = image.createGraphics();
        graphics.setPaint(HISTORY_COLOR);
        graphics.setStroke(new BasicStroke(2f));

        try {
            List<GraphicInfo> graphicInfoList = bpmnModel
                    .getFlowLocationGraphicInfo(sequenceFlowId);

            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() - minX;
                    yPoints[0] = (int) previousGraphicInfo.getY() - minY;
                }

                xPoints[i] = (int) graphicInfo.getX() - minX;
                yPoints[i] = (int) graphicInfo.getY() - minY;
            }

            int radius = 15;

            Path2D path = new Path2D.Double();

            for (int i = 0; i < xPoints.length; i++) {
                Integer anchorX = xPoints[i];
                Integer anchorY = yPoints[i];

                double targetX = anchorX;
                double targetY = anchorY;

                double ax = 0;
                double ay = 0;
                double bx = 0;
                double by = 0;
                double zx = 0;
                double zy = 0;

                if ((i > 0) && (i < (xPoints.length - 1))) {
                    Integer cx = anchorX;
                    Integer cy = anchorY;

                    // pivot point of prev line
                    double lineLengthY = yPoints[i] - yPoints[i - 1];

                    // pivot point of prev line
                    double lineLengthX = xPoints[i] - xPoints[i - 1];
                    double lineLength = Math.sqrt(Math.pow(lineLengthY, 2)
                            + Math.pow(lineLengthX, 2));
                    double dx = (lineLengthX * radius) / lineLength;
                    double dy = (lineLengthY * radius) / lineLength;
                    targetX = targetX - dx;
                    targetY = targetY - dy;

                    // isDefaultConditionAvailable = isDefault && i == 1 && lineLength > 10;
                    if ((lineLength < (2 * radius)) && (i > 1)) {
                        targetX = xPoints[i] - (lineLengthX / 2);
                        targetY = yPoints[i] - (lineLengthY / 2);
                    }

                    // pivot point of next line
                    lineLengthY = yPoints[i + 1] - yPoints[i];
                    lineLengthX = xPoints[i + 1] - xPoints[i];
                    lineLength = Math.sqrt(Math.pow(lineLengthY, 2)
                            + Math.pow(lineLengthX, 2));

                    if (lineLength < radius) {
                        lineLength = radius;
                    }

                    dx = (lineLengthX * radius) / lineLength;
                    dy = (lineLengthY * radius) / lineLength;

                    double nextSrcX = xPoints[i] + dx;
                    double nextSrcY = yPoints[i] + dy;

                    if ((lineLength < (2 * radius))
                            && (i < (xPoints.length - 2))) {
                        nextSrcX = xPoints[i] + (lineLengthX / 2);
                        nextSrcY = yPoints[i] + (lineLengthY / 2);
                    }

                    double dx0 = (cx - targetX) / 3;
                    double dy0 = (cy - targetY) / 3;
                    ax = cx - dx0;
                    ay = cy - dy0;

                    double dx1 = (cx - nextSrcX) / 3;
                    double dy1 = (cy - nextSrcY) / 3;
                    bx = cx - dx1;
                    by = cy - dy1;

                    zx = nextSrcX;
                    zy = nextSrcY;
                }

                if (i == 0) {
                    path.moveTo(targetX, targetY);
                } else {
                    path.lineTo(targetX, targetY);
                }

                if ((i > 0) && (i < (xPoints.length - 1))) {
                    // add curve
                    path.curveTo(ax, ay, bx, by, zx, zy);
                }
            }

            graphics.draw(path);

            // draw arrow
            Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2],
                    yPoints[xPoints.length - 2], xPoints[xPoints.length - 1],
                    yPoints[xPoints.length - 1]);

            int ARROW_WIDTH = 5;
            int doubleArrowWidth = 2 * ARROW_WIDTH;
            Polygon arrowHead = new Polygon();
            arrowHead.addPoint(0, 0);
            arrowHead.addPoint(-ARROW_WIDTH, -doubleArrowWidth);
            arrowHead.addPoint(ARROW_WIDTH, -doubleArrowWidth);

            AffineTransform transformation = new AffineTransform();
            transformation.setToIdentity();

            double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1);
            transformation.translate(line.x2, line.y2);
            transformation.rotate((angle - (Math.PI / 2d)));

            AffineTransform originalTransformation = graphics.getTransform();
            graphics.setTransform(transformation);
            graphics.fill(arrowHead);
            graphics.setTransform(originalTransformation);
        } finally {
            graphics.dispose();
        }
    }
}

package com.zihai.activiti.util;

public class Edge extends GraphElement {
    private Node src;
    private Node dest;

    public Node getSrc() {
        return src;
    }

    public void setSrc(Node src) {
        this.src = src;
    }

    public Node getDest() {
        return dest;
    }

    public void setDest(Node dest) {
        this.dest = dest;
    }
}

package com.zihai.activiti.util;

import java.util.ArrayList;
import java.util.List;

public class Graph {
    private List<Node> initials = new ArrayList<Node>();
    
    public Node getInitial(){
    	if(initials.size()>0){
    		return initials.get(0);
    	}
    	return null;
    }

    public List<Node> getNodes() {
        List<Node> nodes = new ArrayList<Node>();
        for(Node initial:initials){
        	 visitNode(initial, nodes);
        }
        return nodes;
    }

    public void visitNode(Node node, List<Node> nodes) {
        nodes.add(node);

        for (Edge edge : node.getEdges()) {
            Node nextNode = edge.getDest();
            visitNode(nextNode, nodes);
        }
    }

    public List<Edge> getEdges() {
        List<Edge> edges = new ArrayList<Edge>();
        for(Node initial:initials){
        	 visitEdge(initial, edges);
       }       
        return edges;
    }

    public void visitEdge(Node node, List<Edge> edges) {
        for (Edge edge : node.getEdges()) {
            edges.add(edge);

            Node nextNode = edge.getDest();
            visitEdge(nextNode, edges);
        }
    }

    public Node findById(String id) {
        for (Node node : this.getNodes()) {
            if (id.equals(node.getId())) {
                return node;
            }
        }

        return null;
    }

	public void addInitial(Node currentNode) {
		initials.add(currentNode);
		
	}
}

package com.zihai.activiti.util;

public class GraphElement {
    private String id;
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

package com.zihai.activiti.util;

import java.io.InputStream;

import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;

public class HistoryProcessInstanceDiagramCmd implements Command<InputStream> {
    protected String historyProcessInstanceId;
    
    protected String[] executionids;

    public HistoryProcessInstanceDiagramCmd(String proccessid,String... executionids) {
        this.historyProcessInstanceId = proccessid;
        this.executionids = executionids;
    }

    public InputStream execute(CommandContext commandContext) {
        try {
            CustomProcessDiagramGenerator customProcessDiagramGenerator = new CustomProcessDiagramGenerator();

            return customProcessDiagramGenerator
                    .generateDiagram(historyProcessInstanceId,executionids);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}


猜你喜欢

转载自blog.csdn.net/lylhjh/article/details/76350829