这篇文章写得很好,揭示了图片点击出现信息的方法,于是我也做了,只不过有些改动,可能是activiti的版本不同的原因。
jsp页面,通过流程实例id进行操作
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ include file="/pages/common/common-js.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
.activity-attr{border-radius: 10px; border: 3px solid red; transition:ease-out 0.5s; box-shadow:0px 0px 9px red;}
#processKey{color: red;}
#flowImageAndRect{position: relative;overflow: scroll;height:300px; heibackground-image: url('grid_10.png')}
body,html{margin: 0px;padding:0px;}
</style>
<script type="text/javascript">
var baseURL = "<%=rootPath%>/pages/WorkTaskCon/";
$(function(){ debugger;
var pid = '${flowKey}'; // 流程定义的key
var $flowImageAndRect = $('#flowImageAndRect');
$('#processKey').html('流程定义的key --> ' + pid);
// 加载流程图片
loadProcessImage(pid,$flowImageAndRect);
// 加载各节点信息,最终实现,在点击图片上的各节点时,出现高亮
setTimeout(function(){
loadProcessTrace(pid,$flowImageAndRect);
},200);
var $revClickRect = null; // 上次点击的图形
// 绑定click事件,点击实现,只有点击的不是同一个时,才显示红色的边框(如果多次点击同一个,红色的边框只出现一次)
$('#flowImageAndRect').off('click').on('click','.activity-attr',function(e){
var $this = $(this);
var prevFlag = false; // 是上一个图形,避免多次点击同一个
if($revClickRect){ // 说明不是第一次点击
prevFlag = ($revClickRect.attr('actId')!=$this.attr('actId')) ? false : true;// 说明2次点击的不是同一个
if(!prevFlag)
$revClickRect.css('opacity','0');
}
if(!prevFlag){ // 此处可以请求后台,加载相关的数据(多次点击同一个,下方可确保只执行一次)
$this.css('opacity','1'); // 显示当前的
$revClickRect = $this; // 将当前设置为上次点击的
$('#info').html('节点ID --> ' + $this.attr('actId') + " | " + "节点名称 --> " + $this.attr('name'));
}
});
});
/**
* 加载图片
*/
function loadProcessImage(pid,$flowImageAndRect){ debugger;
var imageUrl =baseURL+ 'readResource.htm?pid=' + pid;
// 加载图片
$('<img />',{
"src" : imageUrl,
"alt" : ''
}).appendTo($flowImageAndRect);
}
/**
* 加载流程中各节点的信息
* @param pid : 流程定义的key
* @param $flowImageAndRect
*/
function loadProcessTrace(pid,$flowImageAndRect){ debugger;
var traceUrl = baseURL+'getProcessTrace.htm?pid='+pid;
$.getJSON(traceUrl,function(infos){
var html = "";
$.each(infos,function(i,v){
// 矩形的div
var $div = $('<div/>', {
'class': 'activity-attr'
}).css({
position: 'absolute',
left: v.x,
top: v.y,
width: v.width - 3,
height:v.height - 3,
opacity: 0,
zIndex: 100,
cursor : 'pointer'
}).attr({'actId':v.actId,'name':v.name});
html += $div.prop("outerHTML");
});
$('<div />',{'id':'processRect'}).html(html).appendTo($flowImageAndRect);
});
}
</script>
</head>
<body>
<div id="main">
<div id="flowImageAndRect">
</div>
<div id="processKey" style="font-size: 12px;text-align: center;margin-bottom: 50px;">
</div>
<div id="info" style="font-size: 12px;text-align: center;">
</div>
</div>
</body>
</html>
java代码,通过反射调用源码中的节点x、y以及信息
/**
* 根据流程的key生成图片
*
* @param request
* @param response
* @param wfKey 流程定义的key
*/
@RequestMapping(value="readResource.htm")
public void readResource(HttpServletRequest request,HttpServletResponse response) {
try {
IMap params = new IMap(request);
String processDefinitionId = ProcessEngines.getDefaultProcessEngine().getHistoryService()
.createHistoricProcessInstanceQuery()
.processInstanceId(params.getString("pid")).singleResult()
.getProcessDefinitionId();
RepositoryService repositoryService = ProcessEngines.getDefaultProcessEngine().getRepositoryService();
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(processDefinitionId);
InputStream imageStream = iActivitiUtilSvc.getFlowImageByKey(processDefinition.getKey());
// 输出资源内容到相应对象
byte[] b = new byte[1024];
int len;
while ((len = imageStream.read(b, 0, 1024)) != -1) {
response.getOutputStream().write(b, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取各个节点的具体的信息
* @param wfKey
* 流程定义的key
* @return
*/
@RequestMapping("getProcessTrace.htm")
@ResponseBody
public List<Map<String, Object>> getProcessTrace(String pid) throws Exception {
List<Map<String, Object>> activityInfos = new ArrayList<Map<String, Object>>();
String processDefinitionId = ProcessEngines.getDefaultProcessEngine().getHistoryService()
.createHistoricProcessInstanceQuery()
.processInstanceId(pid).singleResult()
.getProcessDefinitionId();
RepositoryService repositoryService = ProcessEngines.getDefaultProcessEngine().getRepositoryService();
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(processDefinitionId);
List<ActivityImpl> activitiList = processDefinition.getActivities();
InputStream xmlIs = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
BpmnModel bm = new BpmnXMLConverter().convertToBpmnModel(new InputStreamSource(xmlIs), false, true);
// 下方使用反射获取最小的x和y,仔细看就会发现调用的是上方2.1节的方法
Class<?> clazz = Class.forName("org.activiti.image.impl.DefaultProcessDiagramGenerator");
Method method = clazz.getDeclaredMethod("initProcessDiagramCanvas", BpmnModel.class, String.class,
String.class, String.class, ClassLoader.class);
method.setAccessible(true);
DefaultProcessDiagramCanvas pdc = (DefaultProcessDiagramCanvas) method.invoke(clazz.newInstance(), bm,"png", "宋体", "宋体", null); // 调用方法
clazz = Class.forName("org.activiti.image.impl.DefaultProcessDiagramCanvas");
Field minXField = clazz.getDeclaredField("minX"); // 得到minX字段
Field minYField = clazz.getDeclaredField("minY");
minXField.setAccessible(true);
minYField.setAccessible(true);
int minX = minXField.getInt(pdc);// 最小的x值
int minY = minYField.getInt(pdc); // 最小的y的值
minX = minX > 0 ? minX - 5 : 0; // 此处为什么需要减5,上方2.2中activiti源码中有</span>
minY = minY > 0 ? minY - 5 : 0;
for (ActivityImpl activity : activitiList) {
Map<String, Object> activityInfo = new HashMap<String, Object>();
activityInfo.put("width", activity.getWidth());
activityInfo.put("height", activity.getHeight());
activityInfo.put("x", activity.getX() - minX);
activityInfo.put("y", activity.getY() - minY);
activityInfo.put("actId", activity.getId());
activityInfo.put("name", activity.getProperty("name")); // </strong>ActivityImpl 中没有getName方法,所以此处需要这样获取。</span>
activityInfos.add(activityInfo);
}
return activityInfos;
}
public InputStream getFlowImageByKey(String flowKey){
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(flowKey).latestVersion()
.singleResult();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
// 不使用spring请使用下面的两行代码
ProcessEngineImpl defaultProcessEngine = (ProcessEngineImpl) ProcessEngines.getDefaultProcessEngine();
Context.setProcessEngineConfiguration(defaultProcessEngine.getProcessEngineConfiguration());
// 使用spring注入引擎请使用下面的这行代码
// Context.setProcessEngineConfiguration(processEngine.getProcessEngineConfiguration());
ProcessDiagramGenerator a = defaultProcessEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
return a.generateDiagram(bpmnModel, "png", "宋体", "宋体", null, 1.0);
}