什么是svg :http://zh.wikipedia.org/wiki/SVG
由于我想以流程图驱动任务的执行,所以我就准备把流程图显示到页面上,首先我使用了jbpm自带的流程图,因为它的流程图生成后是一张图片,所以很难在它每个节点上做超链接,当然可以模拟在每个节点上面加个透明的div,这样做我觉得太麻烦,而且可能不够灵活,所以我选择了另一种方式,使用svg技术动态生成流程图。
实现的servlet: (这个servlet也是在网上搜来的然后进行的改造,特此感谢!)
public class SvgJbpmImageServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private WebApplicationContext wac = null;
private Element rootDiagramElement = null;
private Token currentToken = null;
private String basePath = "";
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if(wac == null) {
System.out.println("初始化Spring上下文");
wac = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession().getServletContext());
}
// 显示task实例状态图
response.setContentType("image/svg+xml");
String pid = request.getParameter("pid");
response.setCharacterEncod[size=medium][/size]ing("utf-8");
String path = request.getContextPath();
basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
if(pid != null) {
String result = getProcessDefinitionSvgInfoById(Long.parseLong(pid));
if(StringUtils.isNotEmpty(result))
response.getWriter().write(result);
}
}
/**
* 根据taskid获得流程定义图字节码
*
* @param id taskid
* @return
*/
private String getProcessDefinitionSvgInfoById(final long id) {
JbpmTemplate jbpmTemplate = (JbpmTemplate) wac.getBean("jbpmTemplate");
return (String)jbpmTemplate.execute(new JbpmCallback() {
public Object doInJbpm(JbpmContext context) {
StringBuffer svgInfo = new StringBuffer();
initSvgInfo(svgInfo);
try {
ProcessDefinition pd = context.getProcessInstance(id).getProcessDefinition();
currentToken = context.getProcessInstance(id).getRootToken();
byte [] gpdBytes = getGpdBytesByPdfId(id); // 获取图形的基础信息
if(gpdBytes==null){
return null;
}
rootDiagramElement = DocumentHelper.parseText(new String(gpdBytes)).getRootElement();
for(int i=0;i<pd.getNodes().size();i++){
Node n = (Node)pd.getNodes().get(i);
int[] boxConstraint = extractBoxConstraint(rootDiagramElement, n.getName());
svgInfo.append(getSvgStringInfo(boxConstraint,n));
}
svgInfo.append("</svg>");
if(pd.getFileDefinition() == null) {
// message = "没有流程图";
return null;
} else {
return svgInfo.toString();
}
} catch(Exception e) {
e.printStackTrace();
// message = "No TaskInstance:" + id;
return null;
}
}
});
}
private void initSvgInfo(StringBuffer s){
s.append("<?xml version='1.0' encoding='UTF-8'?>");
s.append("<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' ");
s.append("'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>");
s.append("<svg xmlns='http://www.w3.org/2000/svg' version='1.1' ");
s.append("width='100%' height='100%'>");
s.append("<desc>Markers</desc> ");
s.append("<defs>");
s.append("<marker id='arrow' viewBox='0 0 20 20' refX='0' refY='10' markerUnits='strokeWidth' markerWidth='9' markerHeight='30' orient='auto'> ");
s.append(" <path d='M 0 0 L 20 10 L 0 20 z' fill='white' stroke='black'/> ");
s.append(" </marker> ");
s.append(" </defs> ");
s.append("<defs>");
s.append("<linearGradient id='orange_red' x1='0%' y1='0%' x2='0%' y2='100%'>");
s.append("<stop offset='0%' style='stop-color:#e6e6e6; stop-opacity:1'/>");
s.append("<stop offset='100%' style='stop-color:#ffffff; stop-opacity:1'/>");
s.append("</linearGradient>");
s.append("</defs>");
}
private String getSvgStringInfo(int[] xy,Node n){
String s = "";
s +=" <a xlink:href='"+basePath+PurchaseConstants.getNodeLinkMap().get(n.getName())+"'>";
if(n instanceof Decision){//如果是个决策节点就以菱形显示
s+="<polygon points='"+(xy[0]+xy[2]/2)+","+(xy[1]+xy[3])+" "+(xy[0]+xy[2])+","+(xy[1]+xy[3]/2)+" "+(xy[0]+xy[2]/2)+","+xy[1]+" "+(xy[0])+","+(xy[1]+xy[3]/2)+"' style='fill:url(#orange_red);stroke-width:1;stroke:#bebebe'/>";
}
else//否则以矩形显示
{
if(n.getName().equals(this.currentToken.getNode().getName()))
s +="<rect x='"+xy[0]+"' y='"+xy[1]+"' width='"+xy[2]+"' height='"+xy[3]+"' style='fill:url(#orange_red);stroke-width:1;stroke:red' />";
else
s +="<rect x='"+xy[0]+"' y='"+xy[1]+"' width='"+xy[2]+"' height='"+xy[3]+"' style='fill:url(#orange_red);stroke-width:1;stroke:#bebebe' />";
}
s +="<text style='fill:black;' y='"+(xy[1]+xy[3]/2)+"' x='"+(xy[0]+35)+"'>"+n.getName()+"</text>";
s +="</a>";
List list =n.getLeavingTransitionsList();
for(int i=0;i<list.size();i++){
Transition t = (Transition)list.get(i);
Node to = t.getTo();
int[] toXY = extractBoxConstraint(rootDiagramElement, to.getName());
s +="<g id='chart' stroke='purple' stroke-width='1' fill='none' marker-end='url(#arrow)' >";
if(to instanceof Decision){ //如果是个决策节点就直接指向它的上边的点
s +="<path d='M"+(xy[0]+xy[2]/2)+" "+(xy[1]+xy[3])+" L"+(toXY[0]+toXY[2]/2+10)+" "+(toXY[1]-5)+"'/>";
}
else
{
int[] param=new int[]{(xy[0]+xy[2]/2),(xy[1]+xy[3])};
double[][] rectXY = new double[4][2];
rectXY[0] =new double[]{toXY[0],(toXY[1]+toXY[3]/2)};//节点矩形左边中间点
rectXY[1] =new double[]{toXY[0]+toXY[2]/2,(toXY[1])};//节点矩形上边中间点
rectXY[2] =new double[]{toXY[0]+toXY[2]/2,(toXY[1]+toXY[3])};//节点矩形下边中间点
rectXY[3] =new double[]{toXY[0]+toXY[2],(toXY[1]+toXY[3]/2)};//节点矩形右边中间点
double[] d = calcu(param,rectXY);//求从起始点到目标节点的最短路径
s +="<path d='M"+(xy[0]+xy[2]/2)+" "+(xy[1]+xy[3])+" L"+(d[0]-10)+" "+(d[1]-10)+"'/>";
}
s +="</g>";
}
return s;
}
private double[] calcu(int a[],double x[][]){
double[] r = new double[4];
double min = 100000;
int w = 0;
for(int i=0;i<4;i++){
r[i] = Math.sqrt(Math.pow(a[0]-x[i][0],2)+Math.pow(a[1]-x[i][1],2));
//获取最大的r[i] 并且记录i
}
for(int j=0;j<4;j++){
if(r[j]<min)
min = r[j];
}
for(int z = 0;z<4;z++){
if(r[z]==min)
w = z;
}
return x[w];
}
private byte[] getGpdBytesByPdfId(final long id) {
JbpmTemplate jbpmTemplate = (JbpmTemplate) wac.getBean("jbpmTemplate");
return (byte[])jbpmTemplate.execute(new JbpmCallback() {
public Object doInJbpm(JbpmContext context) {
try {
ProcessDefinition pd = context.getProcessInstance(id).getProcessDefinition();
if(pd.getFileDefinition() == null) {
// message = "没有流程图";
return null;
} else {
return pd.getFileDefinition().getBytes("gpd.xml");
}
} catch(Exception e) {
e.printStackTrace();
// message = "No TaskInstance:" + id;
return null;
}
}
});
}
/**
* 提取座标及宽高
*
* @param root 根节点
* @param token
* @return
*/
private int[] extractBoxConstraint(Element root, String nodeName) {
int[] result = new int[4];
XPath xPath = new DefaultXPath("//node[@name='" + nodeName + "']");
Element node = (Element) xPath.selectSingleNode(root);
result[0] = Integer.valueOf(node.attribute("x").getValue()).intValue();
result[1] = Integer.valueOf(node.attribute("y").getValue()).intValue();
result[2] = Integer.valueOf(node.attribute("width").getValue())
.intValue();
result[3] = Integer.valueOf(node.attribute("height").getValue())
.intValue();
return result;
}
}
以上servlet并没有经过严格的单元测试,使用者自行负责
还有个问题是 我想在任务节点上加超链接,但是这里的链接都是写死的,如果灵活的话可以扩展jbpm的Node,但时间有限未再扩展
生成的图片样子还比较丑,还有很大的优化余地....
分享到:
相关推荐
基于SVG的实时监控流程图实现技术.pdf
基于SVG建立的图形展示系统,通过浏览器端以SVG为核心,建立动画引擎,驱动SVG的动画图像,实现工业控制数据实时显示、生产数据动态显示。将SVG技术应用于中国平煤神马集团工况系统、采掘动态系统中,证明了技术的可行性...
基于SVG的实时监控流程图实现技术.pdf 联合证券 公司研究-思源电气(002028)090323产业升级,GIS、SVG值得期待(增持).pdf: 网络图形标准svg的特征与实现.pdf CR-SVG-20000802.pdf SVG 技术在电网调度自动化中的...
svg画流程图支持拖拽,修改和保存,本人原创
针对煤矿图形系统传统实施方案的诸多不足,设计了一种基于SVG技术的煤矿综合自动化矢量图形系统。详细论述了SVG技术概念、优势及SVG格式文档解析方式。利用传统ASP.NET三层架构体系,对煤矿矢量图形系统整体架构进行...
基于SVG技术WebGIS的实现方案.pdf
基于VML和SVG的工作流程动态展示实现,自己开发工作流时可以用到,展示方便,用起来简单。
基于SVG技术的多级电网自动化调度策略.rar
基于SVG技术的多级电网自动化调度策略.pdf
HTML5基于SVG技术实现动画效果的折线图,并且还具有渐变色效果,用chrome打开本特效后,会看到拆线图以动画效果绘制,很像以前那种Flash效果的曲线图。使用HTML5技术可很好的就实现此种效果,且可跨平台(PC和智能...
基于SVG/WEB SERVICE的WEB监控技术在EMS中的应用rar,能量管理系统,调度自动化,可缩放矢量因形,WEB SERVICE,异构平台,可扩展置标语言,网络安.
在传统考古领域中利用现代探测和信息技术辅助考古发掘,详细阐述了利用SVG技术和Java技术实现...首先介绍了SVG技术,分析了考古探测Web GIS的系统结构,研究了基于SVG技术的交互式图层管理,最后建立了系统的模拟结果。
基于SVG 的电子功能画板
网页动画素材 html5基于svg绘制卡通人物坐在卧室悠闲的看着电视场景动画特效。(抖音资料)网页动画素材 html5基于svg绘制卡通人物坐在卧室悠闲的看着电视场景动画特效。(抖音资料)网页动画素材 html5基于svg绘制...
jRate是一款基于SVG的jQuery星级评分插件。jRate评分插件提供许多参数,用于设置评分的星星个数、颜色、大小等属性。由于是SVG制作的,评分星星放大缩小都不会变形。
计算机毕业设计_asp.net基于SVG的自动站雨量分析系统(源代码+)__毕设源码实例.zip计算机毕业设计_asp.net基于SVG的自动站雨量分析系统(源代码+)__毕设源码实例.zip计算机毕业设计_asp.net基于SVG的自动站雨量分析...
基于SVG的jQuery星级评分插件是一款提供大量的配置参数来设置评分效果,通过回调函数来获取用户点击的星星数量。
基于svg的地图生成,希望为svg地图开发的朋友提供些帮助。
SVG系列--基于XSL技术SVG图像的更新