什么是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的实时监控流程图实现技术 #### 摘要 实时监控流程图作为工业生产控制和管理信息系统的重要组成部分,在诸如DCS(分布式控制系统)、MES(制造执行系统)以及一体化管控系统中发挥着关键作用。为了提高...
在本文中,我们将深入探讨如何使用SVG技术来绘制流程图,并实现拖拽、修改和保存的功能。 首先,SVG的基本结构是由一系列的形状元素组成的,如`<rect>`(矩形)、`<circle>`(圆形)、`<line>`(线)、`<polygon>`...
基于SVG的实时监控流程图实现技术.pdf 联合证券 公司研究-思源电气(002028)090323产业升级,GIS、SVG值得期待(增持).pdf: 网络图形标准svg的特征与实现.pdf CR-SVG-20000802.pdf SVG 技术在电网调度自动化中的...
SVG的特点在于它可以无损地缩放,无论放大多少倍,图形依然保持清晰,这对于显示复杂的工作流程图至关重要。SVG支持动画,这意味着工作流程中的状态变化可以以动态的方式呈现,提高用户理解度。 基于VML和SVG的工作...
《基于SVG/WEB SERVICE的WEB监控技术在EMS中的应用》 在现代电力系统中,能量管理系统(EMS)扮演着至关重要的角色,它负责实时监控、调度自动化以及优化电网运行。随着信息技术的飞速发展,传统的EMS已经无法满足...
总结来说,SVG技术为WebGIS提供了高效、灵活且互动的解决方案,不仅提升了地图的显示质量,还增强了用户体验。结合XML和Web Service,SVG在数据交换和跨平台服务方面也表现出强大的潜力。对于开发人员而言,掌握SVG...
**基于SVG的jQuery星级评分插件-jRate** 在Web开发中,用户界面的交互性和视觉效果对于提升用户体验至关重要。`jRate`是一个优秀的jQuery插件,它专门用于创建基于SVG的星级评分系统。这个插件使得开发者能够轻松地...
jbpm4.4是一款强大的业务流程管理(BPM)框架,它允许开发者设计、执行和管理复杂的业务流程。在线设计流程图功能使得流程设计更为直观和便捷,无需离开Web环境即可完成。本教程将深入探讨jbpm4.4的在线设计流程图...
SVG技术是一种基于XML的矢量图形语言,它用来描述二维矢量图形。SVG文件是纯文本,可以使用任何文本编辑器打开和编辑,也可以直接嵌入到HTML中。SVG文件的扩展名是.svg,是Scalable Vector Graphics的缩写。SVG技术...
综上所述,基于SVG技术的多级电网自动化调度策略利用了SVG的矢量特性,提供了强大的可视化工具,帮助电力系统实现高效、安全和灵活的调度。这种技术不仅改善了调度效率,也为电力系统的现代化和智能化打下了坚实的...
SVG是一种基于XML的矢量图像格式,它允许开发者创建可缩放、清晰且交互式的图形。SVG图形在任何分辨率下都能保持高质量,这使得它非常适合用于创建复杂的图表和流程图。Vue.js则是一个流行的JavaScript框架,用于...
这个插件使用SVG图形来表示星星,并且提供了丰富的配置参数,可以自定义评分显示的样式、大小、颜色等。用户点击后,插件会通过回调函数返回被点击的星星数量,以便于开发者获取并处理用户的评分数据。 【回调函数...
HTML5基于SVG技术实现动画效果的折线图,并且还具有渐变色效果,用chrome打开本特效后,会看到拆线图以动画效果绘制,很像以前那种Flash效果的曲线图。使用HTML5技术可很好的就实现此种效果,且可跨平台(PC和智能...
### 基于SVG的地图生成 #### 摘要 随着信息技术的发展,地图绘制技术也在不断进步。传统的地图数据格式多样且互不兼容,导致地图数据的共享与发布变得复杂。为了解决这一问题,SVG(Scalable Vector Graphics)...
基于SVG与Ajax技术的WebGIS研究与设计 本文探索了基于SVG与Ajax技术的WebGIS的研究与设计。传统的WebGIS技术存在一些不足之处,例如对特定支撑环境的依赖、有限网络带宽对数据传输的限制、数据共享困难、缺乏丰富的...