`
lookdd1
  • 浏览: 47796 次
  • 性别: Icon_minigender_1
  • 来自: 日照
文章分类
社区版块
存档分类
最新评论

基于SVG技术的JBPM流程显示

阅读更多
什么是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的实时监控流程图实现技术

    ### 基于SVG的实时监控流程图实现技术 #### 摘要 实时监控流程图作为工业生产控制和管理信息系统的重要组成部分,在诸如DCS(分布式控制系统)、MES(制造执行系统)以及一体化管控系统中发挥着关键作用。为了提高...

    svg 画流程图

    在本文中,我们将深入探讨如何使用SVG技术来绘制流程图,并实现拖拽、修改和保存的功能。 首先,SVG的基本结构是由一系列的形状元素组成的,如`&lt;rect&gt;`(矩形)、`&lt;circle&gt;`(圆形)、`&lt;line&gt;`(线)、`&lt;polygon&gt;`...

    SVG技术参考文档资料汇总

    基于SVG的实时监控流程图实现技术.pdf 联合证券 公司研究-思源电气(002028)090323产业升级,GIS、SVG值得期待(增持).pdf: 网络图形标准svg的特征与实现.pdf CR-SVG-20000802.pdf SVG 技术在电网调度自动化中的...

    基于VML和SVG的工作流程动态展示实现

    SVG的特点在于它可以无损地缩放,无论放大多少倍,图形依然保持清晰,这对于显示复杂的工作流程图至关重要。SVG支持动画,这意味着工作流程中的状态变化可以以动态的方式呈现,提高用户理解度。 基于VML和SVG的工作...

    基于SVG/WEB SERVICE的WEB监控技术在EMS中的应用.rar

    《基于SVG/WEB SERVICE的WEB监控技术在EMS中的应用》 在现代电力系统中,能量管理系统(EMS)扮演着至关重要的角色,它负责实时监控、调度自动化以及优化电网运行。随着信息技术的飞速发展,传统的EMS已经无法满足...

    基于SVG技术WebGIS的实现方案.pdf

    总结来说,SVG技术为WebGIS提供了高效、灵活且互动的解决方案,不仅提升了地图的显示质量,还增强了用户体验。结合XML和Web Service,SVG在数据交换和跨平台服务方面也表现出强大的潜力。对于开发人员而言,掌握SVG...

    基于SVG的jQuery星级评分插件-jRate

    **基于SVG的jQuery星级评分插件-jRate** 在Web开发中,用户界面的交互性和视觉效果对于提升用户体验至关重要。`jRate`是一个优秀的jQuery插件,它专门用于创建基于SVG的星级评分系统。这个插件使得开发者能够轻松地...

    jbpm4.4 在线设计流程图 ext + raphael

    jbpm4.4是一款强大的业务流程管理(BPM)框架,它允许开发者设计、执行和管理复杂的业务流程。在线设计流程图功能使得流程设计更为直观和便捷,无需离开Web环境即可完成。本教程将深入探讨jbpm4.4的在线设计流程图...

    基于SVG技术的多级电网自动化调度策略.pdf

    SVG技术是一种基于XML的矢量图形语言,它用来描述二维矢量图形。SVG文件是纯文本,可以使用任何文本编辑器打开和编辑,也可以直接嵌入到HTML中。SVG文件的扩展名是.svg,是Scalable Vector Graphics的缩写。SVG技术...

    基于SVG技术的多级电网自动化调度策略.rar

    综上所述,基于SVG技术的多级电网自动化调度策略利用了SVG的矢量特性,提供了强大的可视化工具,帮助电力系统实现高效、安全和灵活的调度。这种技术不仅改善了调度效率,也为电力系统的现代化和智能化打下了坚实的...

    SVG+DIV画审批流程图,生成JSON

    SVG是一种基于XML的矢量图像格式,它允许开发者创建可缩放、清晰且交互式的图形。SVG图形在任何分辨率下都能保持高质量,这使得它非常适合用于创建复杂的图表和流程图。Vue.js则是一个流行的JavaScript框架,用于...

    基于SVG的jQuery星级评分插件.zip

    这个插件使用SVG图形来表示星星,并且提供了丰富的配置参数,可以自定义评分显示的样式、大小、颜色等。用户点击后,插件会通过回调函数返回被点击的星星数量,以便于开发者获取并处理用户的评分数据。 【回调函数...

    HTML5基于SVG技术实现动画效果的折线图.rar

    HTML5基于SVG技术实现动画效果的折线图,并且还具有渐变色效果,用chrome打开本特效后,会看到拆线图以动画效果绘制,很像以前那种Flash效果的曲线图。使用HTML5技术可很好的就实现此种效果,且可跨平台(PC和智能...

    基于svg的地图生成

    ### 基于SVG的地图生成 #### 摘要 随着信息技术的发展,地图绘制技术也在不断进步。传统的地图数据格式多样且互不兼容,导致地图数据的共享与发布变得复杂。为了解决这一问题,SVG(Scalable Vector Graphics)...

    基于SVG与Ajax技术的WebGIS研究与设计.pdf

    基于SVG与Ajax技术的WebGIS研究与设计 本文探索了基于SVG与Ajax技术的WebGIS的研究与设计。传统的WebGIS技术存在一些不足之处,例如对特定支撑环境的依赖、有限网络带宽对数据传输的限制、数据共享困难、缺乏丰富的...

Global site tag (gtag.js) - Google Analytics