org.fireflow.webdesigner.transformer.FpdlDiagramSerializerSvgImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.fireflow.webdesigner.transformer.FpdlDiagramSerializerSvgImpl.java

Source

/**
 * Copyright 2007-2010 ?
 * All rights reserved. 
 * 
 * This library is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License v3 as published by the Free Software
 * Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along
 * with this library; if not, see http://www.gnu.org/licenses/lgpl.html.
 *
 */
package org.fireflow.webdesigner.transformer;

import java.awt.Dimension;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.fireflow.model.ModelElement;
import org.fireflow.model.io.SerializerException;
import org.fireflow.pdl.fpdl.diagram.ActivityShape;
import org.fireflow.pdl.fpdl.diagram.AssociationShape;
import org.fireflow.pdl.fpdl.diagram.CommentShape;
import org.fireflow.pdl.fpdl.diagram.ConnectorShape;
import org.fireflow.pdl.fpdl.diagram.Diagram;
import org.fireflow.pdl.fpdl.diagram.DiagramElement;
import org.fireflow.pdl.fpdl.diagram.EndNodeShape;
import org.fireflow.pdl.fpdl.diagram.GroupShape;
import org.fireflow.pdl.fpdl.diagram.LaneShape;
import org.fireflow.pdl.fpdl.diagram.MessageFlowShape;
import org.fireflow.pdl.fpdl.diagram.NodeShape;
import org.fireflow.pdl.fpdl.diagram.PoolShape;
import org.fireflow.pdl.fpdl.diagram.ProcessNodeShape;
import org.fireflow.pdl.fpdl.diagram.RouterShape;
import org.fireflow.pdl.fpdl.diagram.StartNodeShape;
import org.fireflow.pdl.fpdl.diagram.TransitionShape;
import org.fireflow.pdl.fpdl.diagram.figure.Figure;
import org.fireflow.pdl.fpdl.diagram.figure.Line;
import org.fireflow.pdl.fpdl.diagram.figure.Rectangle;
import org.fireflow.pdl.fpdl.diagram.figure.part.Bounds;
import org.fireflow.pdl.fpdl.diagram.figure.part.BoundsImpl;
import org.fireflow.pdl.fpdl.diagram.figure.part.FulfilStyle;
import org.fireflow.pdl.fpdl.diagram.figure.part.Label;
import org.fireflow.pdl.fpdl.diagram.figure.part.LabelImpl;
import org.fireflow.pdl.fpdl.diagram.figure.part.Point;
import org.fireflow.pdl.fpdl.io.FPDLNames;
import org.fireflow.pdl.fpdl.process.Activity;
import org.fireflow.pdl.fpdl.process.EndNode;
import org.fireflow.pdl.fpdl.process.Router;
import org.fireflow.pdl.fpdl.process.StartNode;
import org.fireflow.pdl.fpdl.process.WorkflowProcess;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

/**
 *
 * @author ? nychen2000@163.com
 * Fire Workflow www.firesoa.com  www.fireflow.org
 *
 */
public class FpdlDiagramSerializerSvgImpl extends AbstractFpdlDiagramSerializer {
    private Log log = LogFactory.getLog(FpdlDiagramSerializerSvgImpl.class);
    private static final String BASIC_CIRCLE_MARKER_ID = "BASIC_CIRCLE_MARKER";
    private static final String BASIC_BLOCK_ARROW_MARKER_ID = "BASIC_BLOCK_ARROW_MARKER";
    private static final String BASIC_BLOCK_ARROW_MARKER2_ID = "BASIC_BLOCK_ARROW_MARKER2";//

    private Element defsElement = null;
    private Map<String, Element> circleMarkerMap = new HashMap<String, Element>();
    private Map<String, Element> blockArrowMarkerMap = new HashMap<String, Element>();
    private Map<String, Element> blockArrowMarker2Map = new HashMap<String, Element>();

    /* (non-Javadoc)
     * @see org.fireflow.clientwidget.transformer.FpdlDiagramSerializer#serializeDiagramToDoc(org.fireflow.pdl.fpdl.process.WorkflowProcess, java.lang.String)
     */
    public Document serializeDiagramToDoc(WorkflowProcess workflowProcess, String subProcessName)
            throws SerializerException {
        _init(workflowProcess, subProcessName);

        //
        Element root = document.createElement("svg");
        root.setAttribute("id", diagram.getId());
        if (diagram.getWorkflowElementRef() != null) {
            root.setAttribute(FPDLNames.REF, diagram.getWorkflowElementRef().getId());
        }

        root.setAttribute("version", "1.1");
        root.setAttribute("xmlns", "http://www.w3.org/2000/svg");
        root.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
        root.setAttribute("onload", "fireflowSvgInit('" + diagram.getId() + "');");
        root.setAttribute("onunload", "fireflowSvgDestroy('" + diagram.getId() + "')");

        document.appendChild(root);

        //javascript
        Element scriptElm = document.createElement("script");
        scriptElm.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", this.resourcePathPrefix
                + "/org/fireflow/clientwidget/resources/jquery-ui-1.10.3.custom/js/jquery-1.10.2.min.js");
        root.appendChild(scriptElm);

        scriptElm = document.createElement("script");
        scriptElm.setAttribute("type", "application/ecmascript");
        root.appendChild(scriptElm);
        String data = "$ff=$;";
        CDATASection cdata = document.createCDATASection(data);
        scriptElm.appendChild(cdata);

        scriptElm = document.createElement("script");
        scriptElm.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href",
                this.resourcePathPrefix + "/org/fireflow/webdesigner/resources/svg/FireflowSvgControl.js");
        root.appendChild(scriptElm);

        //defs
        defsElement = document.createElement("defs");
        root.appendChild(defsElement);

        //markers
        //
        Element circleMk = document.createElement("marker");
        circleMk.setAttribute("id", BASIC_CIRCLE_MARKER_ID);
        circleMk.setAttribute("markerWidth", "8");
        circleMk.setAttribute("markerHeight", "8");
        circleMk.setAttribute("refX", "4");
        circleMk.setAttribute("refY", "4");
        circleMk.setAttribute("markerUnits", "userSpaceOnUse");
        defsElement.appendChild(circleMk);

        Element circleTmp = document.createElement("circle");
        circleTmp.setAttribute("cx", "4");
        circleTmp.setAttribute("cy", "4");
        circleTmp.setAttribute("r", "4");
        circleTmp.setAttribute("style", "stroke:#000000;fill:none;stroke-dasharray:2 0;");
        circleMk.appendChild(circleTmp);

        circleMarkerMap.put("#000000", circleMk);

        //Block?
        Element blockArrowMk = document.createElement("marker");
        blockArrowMk.setAttribute("id", BASIC_BLOCK_ARROW_MARKER_ID);
        blockArrowMk.setAttribute("markerWidth", "13");
        blockArrowMk.setAttribute("markerHeight", "12");
        blockArrowMk.setAttribute("refX", "11");
        blockArrowMk.setAttribute("refY", "6");
        blockArrowMk.setAttribute("orient", "auto");
        blockArrowMk.setAttribute("markerUnits", "userSpaceOnUse");
        defsElement.appendChild(blockArrowMk);

        Element blockArrow = document.createElement("path");
        blockArrow.setAttribute("d", "M2,2 L2,10 L11,6 L2,2");
        blockArrow.setAttribute("style", "stroke:none;fill:#000000;");
        blockArrowMk.appendChild(blockArrow);

        blockArrowMarkerMap.put("#000000", blockArrowMk);

        //Block?
        Element blockArrowMk2 = document.createElement("marker");
        blockArrowMk2.setAttribute("id", BASIC_BLOCK_ARROW_MARKER2_ID);
        blockArrowMk2.setAttribute("markerWidth", "13");
        blockArrowMk2.setAttribute("markerHeight", "12");
        blockArrowMk2.setAttribute("refX", "11");
        blockArrowMk2.setAttribute("refY", "6");
        blockArrowMk2.setAttribute("orient", "auto");
        blockArrowMk2.setAttribute("markerUnits", "userSpaceOnUse");
        defsElement.appendChild(blockArrowMk2);

        Element blockArrow2 = document.createElement("path");
        blockArrow2.setAttribute("d", "M2,2 L2,10 L11,6 L2,2");
        blockArrow2.setAttribute("style", "stroke:#000000;fill:none;stroke-dasharray:2,0;");
        blockArrowMk2.appendChild(blockArrow2);

        blockArrowMarker2Map.put("#000000", blockArrowMk2);

        //id=viewportg
        Element g = document.createElement("g");
        g.setAttribute("id", "viewport");
        root.appendChild(g);

        //?
        List<ProcessNodeShape> processNodeShapeList = diagram.getProcessNodeShapes();
        if (processNodeShapeList != null && processNodeShapeList.size() > 0) {
            for (ProcessNodeShape nodeShape : processNodeShapeList) {
                Element cell = this.transformProcessNodeShape2Svg(nodeShape, true);
                if (cell != null) {
                    g.appendChild(cell);
                }
            }
        }

        //
        List<CommentShape> commentShapeList = diagram.getComments();
        if (commentShapeList != null && commentShapeList.size() > 0) {
            for (CommentShape commentShape : commentShapeList) {
                Element cell = transformCommentShape2Svg(commentShape, true);
                if (cell != null) {
                    g.appendChild(cell);
                }

            }
        }

        //Group
        List<GroupShape> groupShapeList = diagram.getGroups();
        if (groupShapeList != null && groupShapeList.size() > 0) {
            for (GroupShape groupShape : groupShapeList) {
                Element cell = transformGroupShape2Svg(groupShape, true);
                if (cell != null) {
                    g.appendChild(cell);
                }
            }
        }

        //Pool
        List<PoolShape> poolShapeList = diagram.getPools();
        if (poolShapeList != null && poolShapeList.size() > 0) {
            for (PoolShape poolShape : poolShapeList) {
                Element cell = this.transformPool2Svg(poolShape, true);
                if (cell != null) {
                    g.appendChild(cell);
                }
            }
        }

        //
        //transition
        List<TransitionShape> transitionShapeList = diagram.getTransitions();
        if (transitionShapeList != null && transitionShapeList.size() > 0) {
            for (TransitionShape transitionShape : transitionShapeList) {
                Element cell = transformConnectorShape2Svg(transitionShape);
                if (cell != null) {
                    g.appendChild(cell);
                }
            }
        }

        //association
        List<AssociationShape> associationShapeList = diagram.getAssociations();
        if (associationShapeList != null && associationShapeList.size() > 0) {
            for (AssociationShape associationShape : associationShapeList) {
                Element cell = transformConnectorShape2Svg(associationShape);
                if (cell != null) {
                    g.appendChild(cell);
                }
            }
        }
        //      
        //      //messageflow
        List<MessageFlowShape> messageFlowShapeList = diagram.getMessageFlows();
        if (messageFlowShapeList != null && messageFlowShapeList.size() > 0) {
            for (MessageFlowShape messageFlowShape : messageFlowShapeList) {
                Element cell = this.transformConnectorShape2Svg(messageFlowShape);
                if (cell != null) {
                    g.appendChild(cell);
                }
            }
        }

        //?root
        int width = this.rightDownX - this.leftTopX;
        int height = this.rightDownY - this.leftTopY;
        root.setAttribute("width", Integer.toString(width));
        root.setAttribute("height", Integer.toString(height));

        /*
        int origX = 0;
        int origY = 0;
        if (this.leftTopX<0){
           origX = this.leftTopX;
        }
        if (this.leftTopY<0){
           origY = this.leftTopY;
        }
        root.setAttribute("coordorigin", origX+","+origY);
         */

        return document;
    }

    private Element transformProcessNodeShape2Svg(ProcessNodeShape nodeShape, boolean isTopLevelElem) {
        Element cell = null;
        if (nodeShape instanceof StartNodeShape) {
            cell = this.transformStartNodeShape2Svg((StartNodeShape) nodeShape, isTopLevelElem, true);
        }

        else if (nodeShape instanceof EndNodeShape) {
            cell = this.transformEndNodeShape2Svg((EndNodeShape) nodeShape, isTopLevelElem);
        } else if (nodeShape instanceof RouterShape) {
            cell = this.transformRouterShape2Svg((RouterShape) nodeShape, isTopLevelElem);
        } else if (nodeShape instanceof ActivityShape) {
            cell = this.transformActivityShape2Svg((ActivityShape) nodeShape, true);
        }
        //ModelElement wfElm = nodeShape.getWorkflowElementRef();

        return cell;
    }

    /**
     * 
     * @param nodeShape
     * @param isTopLevelElem
     * @return
     */
    private Element transformActivityShape2Svg(ActivityShape nodeShape, boolean isTopLevelElem) {
        Activity activity = (Activity) nodeShape.getWorkflowElementRef();
        String imgUri = _getActivityImgUri(activity);

        //1?viewport
        Bounds newportBounds = _getViewPortBounds(nodeShape);
        Rectangle figure = (Rectangle) nodeShape.getFigure();

        Element nodeGroup = document.createElement("g");

        nodeGroup.setAttribute(FPDLNames.ID, nodeShape.getId());
        nodeGroup.setAttribute(TYPE, FPDLNames.ACTIVITY);
        ModelElement wfElmRef = nodeShape.getWorkflowElementRef();
        String wfElmId = wfElmRef == null ? "" : wfElmRef.getId();
        String wfElmName = wfElmRef == null ? "" : wfElmRef.getName();
        if (wfElmRef != null) {
            nodeGroup.setAttribute(FPDLNames.REF, wfElmId);
        }

        //2?Activity      
        Bounds rectBounds = figure.getBounds().copy();
        int thick = rectBounds.getThick();
        int newWidth = rectBounds.getWidth() - thick;
        int newHeight = rectBounds.getHeight() - thick;

        Element rect = document.createElement("rect");
        rect.setAttribute("x", Integer.toString(newportBounds.getX() + thick / 2));
        rect.setAttribute("y", Integer.toString(newportBounds.getY() + thick / 2));
        rect.setAttribute("width", Integer.toString(newWidth));
        rect.setAttribute("height", Integer.toString(newHeight));
        rect.setAttribute("rx", Integer.toString(rectBounds.getCornerRadius()));
        rect.setAttribute("ry", Integer.toString(rectBounds.getCornerRadius()));
        nodeGroup.appendChild(rect);

        StringBuffer rectStyle = (new StringBuffer());

        //2.1 
        if (figure.getBounds() != null) {
            rectStyle.append("stroke-width:").append(Integer.toString(thick < 0 ? 1 : thick)).append("px;");
            String color = rectBounds.getColor();
            rectStyle.append("stroke:").append((color == null || color.trim().equals("")) ? "#000000" : color)
                    .append(";");
            String lineType = rectBounds.getLineType();
            if (Bounds.LINETYPE_DOTTED.equals(lineType) || Bounds.LINETYPE_DASHED.equals(lineType)
                    || Bounds.LINETYPE_DASHDOTTED.equals(lineType)) {
                String dashArray = rectBounds.getDashArray();
                if (dashArray == null || dashArray.trim().equals("")) {
                    if (Bounds.LINETYPE_DOTTED.equals(lineType)) {
                        dashArray = DEFAULT_DOT_DASHARRAY;
                    } else if (Bounds.LINETYPE_DASHED.equals(lineType)) {
                        dashArray = DEFAULT_DASH_DASHARRAY;
                    } else if (Bounds.LINETYPE_DASHDOTTED.equals(lineType)) {
                        dashArray = DEFAULT_DOTDASH_DASHARRAY;
                    }
                }
                rectStyle.append("stroke-dasharray: ").append(dashArray).append(";");
            }
        }

        //2.2

        if (figure.getFulfilStyle() != null) {
            //defsElement?grandient
            String gradientElmId = wfElmName + "_fill_pattern";
            Element gradientElm = document.createElement("linearGradient");
            gradientElm.setAttribute("id", gradientElmId);
            gradientElm.setAttribute("spreadMethod", "pad");

            String color1 = figure.getFulfilStyle().getColor1();
            Element stop1 = document.createElement("stop");
            stop1.setAttribute("offset", "0%");
            stop1.setAttribute("stop-color", color1);
            stop1.setAttribute("stop-opacity", "1");

            String color2 = figure.getFulfilStyle().getColor2();
            Element stop2 = document.createElement("stop");
            stop2.setAttribute("offset", "100%");
            stop2.setAttribute("stop-color", color2);
            stop2.setAttribute("stop-opacity", "1");

            String gradient = figure.getFulfilStyle().getGradientStyle();

            if (gradient == null || gradient.trim().equals("")
                    || FulfilStyle.GRADIENT_STYLE_NONE.equals(gradient)) {
                gradientElm.appendChild(stop2);
            } else {
                gradientElm.appendChild(stop1);
                gradientElm.appendChild(stop2);

                if (FulfilStyle.GRADIENT_STYLE_TOP2DOWN.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "0%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_UPPERLEFT2LOWERRIGHT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_UPPERRIGHT2LOWERLEFT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "100%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "0%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_LEFT2RIGHT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "0%");//?
                } else {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "0%");//?
                }
            }

            this.defsElement.appendChild(gradientElm);

            rectStyle.append("fill:url(#").append(gradientElmId).append(");");
        } else {
            rectStyle.append("fill:none;");
        }

        rect.setAttribute("style", rectStyle.toString());

        //2.3 activity??
        String displayName = activity.getDisplayName();
        if (displayName == null || displayName.trim().equals("")) {
            displayName = activity.getName();
        }
        int padding = 6;
        int spacing = 5;

        //textbox
        int textBoxPaddingY = (SVC_LOGO_RADIUS * 2 + padding + spacing);
        int textBoxPaddingX = padding;
        Label contentLabel = null;
        int fontSize = DEFAULT_FONT_SIZE;
        if (figure.getContentLabel() != null) {
            contentLabel = figure.getContentLabel().copy();
            fontSize = contentLabel.getFontSize();
        } else {
            contentLabel = new LabelImpl();
            contentLabel.setFontSize(fontSize);
        }
        contentLabel.setText(displayName);

        Element textRect = this.drawActivityText(nodeShape, FPDLNames.ACTIVITY,
                newportBounds.getX() + textBoxPaddingX, newportBounds.getY() + textBoxPaddingY,
                rectBounds.getWidth() - textBoxPaddingX * 2, rectBounds.getHeight() - textBoxPaddingY * 2,
                contentLabel);

        if (textRect != null) {
            nodeGroup.appendChild(textRect);
        }

        //logo
        if (imgUri != null) {
            Element nodeImg = document.createElement("image");
            nodeImg.setAttribute("x", Integer.toString(newportBounds.getX() + padding + thick));
            nodeImg.setAttribute("y", Integer.toString(newportBounds.getY() + padding + thick));
            nodeImg.setAttribute("width", Integer.toString(SVC_LOGO_RADIUS * 2));
            nodeImg.setAttribute("height", Integer.toString(SVC_LOGO_RADIUS * 2));
            nodeImg.setAttribute("xlink:href", this.resourcePathPrefix + imgUri);
            nodeGroup.appendChild(nodeImg);
        }

        //attatched event node

        List<DiagramElement> children = nodeShape.getChildren();
        if (children != null && children.size() > 0) {
            //1???
            Element attachedEvtSvg = document.createElement("svg");
            attachedEvtSvg.setAttribute("x", Integer.toString(rectBounds.getX()));
            attachedEvtSvg.setAttribute("y",
                    Integer.toString(rectBounds.getY() + rectBounds.getHeight() - IMG_RADIUS));
            attachedEvtSvg.setAttribute("width", Integer.toString(rectBounds.getWidth()));
            attachedEvtSvg.setAttribute("height",
                    Integer.toString(IMG_RADIUS * 2 + DEFAULT_FONT_SIZE + IconTextGap));

            nodeGroup.appendChild(attachedEvtSvg);

            for (DiagramElement child : children) {
                Element elm = this.transformStartNodeShape2Svg((StartNodeShape) child, false, false);
                attachedEvtSvg.appendChild(elm);
            }
        }

        if (isTopLevelElem) {
            _refreshDiagramSize(newportBounds);
        }

        return nodeGroup;
    }

    private Element drawActivityText(DiagramElement diagramElement, String elementType, int x, int y, int w, int h,
            Label label) {
        Element result = null;

        String text = label.getText();

        String fontColor = label.getFontColor();
        //      String fontFamily = "FangSong_GB2312";//mxUtils.getString(style,
        //mxConstants.STYLE_FONTFAMILY, mxConstants.DEFAULT_FONTFAMILIES);

        int fontSize = label.getFontSize();

        String fireFontStyle = label.getFontStyle();

        boolean isItalic = false;
        if (Label.FONT_STYLE_ITALIC.equals(fireFontStyle) || Label.FONT_STYLE_ITALIC_BOLD.equals(fireFontStyle)) {
            isItalic = true;
        }
        //      int fontStyle = mxUtils.getInt(style, mxConstants.STYLE_FONTSTYLE);
        String weight = "normal";
        if (Label.FONT_STYLE_BOLD.equals(fireFontStyle) || Label.FONT_STYLE_ITALIC_BOLD.equals(fireFontStyle)) {
            weight = "bold";
        }

        String uline = "none";

        if (text != null && text.length() > 0) {
            Element foreignObject = document.createElement("foreignObject");
            foreignObject.setAttribute("x", Integer.toString(x));
            foreignObject.setAttribute("y", Integer.toString(y));
            foreignObject.setAttribute("width", Integer.toString(w));
            foreignObject.setAttribute("height", Integer.toString(h));
            foreignObject.setAttribute("requiredFeatures", "http://www.w3.org/TR/SVG11/feature#Extensibility");

            Element textDiv = document.createElement("div");
            foreignObject.appendChild(textDiv);

            textDiv.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
            textDiv.setAttribute("onmouseover", "this.style.cursor='pointer';");
            textDiv.setAttribute("onmouseout", "this.style.cursor='default';");

            StringBuffer styleBufP = new StringBuffer();

            //
            styleBufP.append("width:").append(w).append("px;").append("height:").append(h).append("px;")
                    .append("text-align:center;word-wrap:break-word;");

            //  fontSize+3?
            styleBufP.append("line-height:100%;");

            styleBufP.append("font-weight:").append(weight).append(";").append("font-size:")
                    .append(String.valueOf(fontSize)).append("px;").append("color:").append(fontColor).append(";")
                    .append("text-decoration:none;");
            if (isItalic) {
                styleBufP.append("font-style:").append("italic").append(";");
            }
            textDiv.setAttribute("style", styleBufP.toString());

            //click handlerdiagramId
            StringBuffer clickHandler = new StringBuffer();
            clickHandler.append("on_element_click(").append("'").append(diagramElement.getId()).append("',");

            ModelElement wfElement = diagramElement.getWorkflowElementRef();

            //click handler wfElement Id
            if (wfElement != null) {
                clickHandler.append("'").append(wfElement.getId()).append("',");
            } else {
                clickHandler.append("'',");
            }
            //click handler --element type
            clickHandler.append("'").append(elementType).append("',");

            //click handler --process id 
            clickHandler.append("'").append(workflowProcess.getId()).append("',");

            //click handler --subprocess name
            clickHandler.append("'").append(this.subProcessName).append("');");

            textDiv.setAttribute("onclick", clickHandler.toString());

            textDiv.appendChild(document.createTextNode(text));

            result = foreignObject;
        }
        return result;
    }

    private Element drawActivityText_bak(DiagramElement diagramElement, String elementType, int x, int y, int w,
            int h, Label label) {
        Element result = null;

        String text = label.getText();

        String fontColor = label.getFontColor();
        String fontFamily = "FangSong_GB2312";//mxUtils.getString(style,
        //mxConstants.STYLE_FONTFAMILY, mxConstants.DEFAULT_FONTFAMILIES);

        int fontSize = label.getFontSize();

        String fireFontStyle = label.getFontStyle();

        boolean isItalic = false;
        if (Label.FONT_STYLE_ITALIC.equals(fireFontStyle) || Label.FONT_STYLE_ITALIC_BOLD.equals(fireFontStyle)) {
            isItalic = true;
        }
        //      int fontStyle = mxUtils.getInt(style, mxConstants.STYLE_FONTSTYLE);
        String weight = "normal";
        if (Label.FONT_STYLE_BOLD.equals(fireFontStyle) || Label.FONT_STYLE_ITALIC_BOLD.equals(fireFontStyle)) {
            weight = "bold";
        }

        String uline = "none";

        if (text != null && text.length() > 0) {
            // Applies the opacity
            float opacity = 100;

            String transform = null;

            //         if (!mxUtils.isTrue(style, mxConstants.STYLE_HORIZONTAL, true))
            //         {
            //            double cx = x + w / 2;
            //            double cy = y + h / 2;
            //            transform = "rotate(270 " + cx + " " + cy + ")";
            //         }

            //0?switch
            Element switchElm = document.createElement("switch");
            result = switchElm;

            //1?svg1.2textarea
            Element g = document.createElement("g");
            g.setAttribute("requiredFeatures", "http://www.w3.org/Graphics/SVG/feature/1.2/#TextFlow");
            switchElm.appendChild(g);

            Element textArea = document.createElement("textArea");
            textArea.setAttribute("width", Integer.toString(w));
            textArea.setAttribute("height", Integer.toString(h));
            textArea.setAttribute("font-weight", weight);
            textArea.setAttribute("text-decoration", uline);
            if (isItalic) {
                textArea.setAttribute("font-style", "italic");
            }
            textArea.setAttribute("font-size", String.valueOf(fontSize));
            textArea.setAttribute("font-family", fontFamily);
            textArea.setAttribute("fill", fontColor);
            if (opacity != 100) {
                String value = String.valueOf(opacity / 100);
                textArea.setAttribute("fill-opacity", value);
                textArea.setAttribute("stroke-opacity", value);
            }
            g.appendChild(textArea);

            textArea.appendChild(document.createTextNode(text));

            //2?foreignObject 
            Element foreignObject = document.createElement("foreignObject");
            foreignObject.setAttribute("x", Integer.toString(x));
            foreignObject.setAttribute("y", Integer.toString(y));
            foreignObject.setAttribute("width", Integer.toString(w));
            foreignObject.setAttribute("height", Integer.toString(h));
            foreignObject.setAttribute("requiredFeatures", "http://www.w3.org/TR/SVG11/feature#Extensibility");
            switchElm.appendChild(foreignObject);

            StringBuffer styleBuf = new StringBuffer();
            styleBuf.append("font-weight:").append(weight).append(";").append("font-size:")
                    .append(String.valueOf(fontSize)).append("px;").append("font-family:").append(fontFamily)
                    .append(";").append("color:").append(fontColor).append(";");
            if (isItalic) {
                styleBuf.append("font-style:").append("italic").append(";");
            }
            Element pElem = document.createElement("p");
            pElem.setAttribute("style", styleBuf.toString());
            pElem.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");

            pElem.appendChild(document.createTextNode(text));
            foreignObject.appendChild(pElem);

            //4?text
            Element textElm = null;
            textElm = document.createElement("text");
            textElm.setAttribute("font-weight", weight);
            textElm.setAttribute("font-decoration", uline);
            if (isItalic) {
                textElm.setAttribute("font-style", "italic");
            }

            textElm.setAttribute("font-size", String.valueOf(fontSize));
            textElm.setAttribute("font-family", fontFamily);
            textElm.setAttribute("fill", fontColor);

            if (opacity != 100) {
                String value = String.valueOf(opacity / 100);
                textElm.setAttribute("fill-opacity", value);
                textElm.setAttribute("stroke-opacity", value);
            }

            String[] lines = text.split("\n");
            y += fontSize + (h - lines.length * (fontSize)) / 2 - 2;

            String align = "center";
            String anchor = "start";

            if (align.equals("right")) {
                anchor = "end";
                x += w - 0;//mxConstants.LABEL_INSET ;
            } else if (align.equals("center")) {
                anchor = "middle";
                x += w / 2;
            } else {
                x += 0;//mxConstants.LABEL_INSET ;
            }

            textElm.setAttribute("text-anchor", anchor);

            for (int i = 0; i < lines.length; i++) {
                Element tspan = document.createElement("tspan");

                tspan.setAttribute("x", String.valueOf(x));
                tspan.setAttribute("y", String.valueOf(y));

                tspan.appendChild(document.createTextNode(lines[i]));
                textElm.appendChild(tspan);

                y += fontSize + 0;// mxConstants.LINESPACING;
            }

            if (transform != null) {
                textElm.setAttribute("transform", transform);
            }

            switchElm.appendChild(textElm);

            //appendSvgElement(switchElm);//?append
        }

        return result;
    }

    /**
     * 
     * @param nodeShape
     * @param isTopLevelElem
     * @return
     */
    private Element transformRouterShape2Svg(RouterShape nodeShape, boolean isTopLevelElem) {
        String imgUri = _getSynchronizerNodeImgUri(nodeShape);

        Router node = (Router) nodeShape.getWorkflowElementRef();

        //start node group???
        Bounds bounds = _getViewPortBounds(nodeShape);
        Figure figure = nodeShape.getFigure();

        Element nodeGroup = document.createElement("g");

        //id 
        nodeGroup.setAttribute(FPDLNames.ID, nodeShape.getId());
        nodeGroup.setAttribute(TYPE, FPDLNames.ROUTER);
        ModelElement wfElmRef = nodeShape.getWorkflowElementRef();
        if (wfElmRef != null) {
            nodeGroup.setAttribute(FPDLNames.REF, wfElmRef == null ? "" : wfElmRef.getId());
        }

        Element nodeImg = document.createElement("image");

        nodeImg.setAttribute("width", Integer.toString(IMG_RADIUS * 2));
        nodeImg.setAttribute("height", Integer.toString(IMG_RADIUS * 2));

        nodeImg.setAttribute("x", Integer.toString(bounds.getX() + (bounds.getWidth() / 2 - IMG_RADIUS)));
        nodeImg.setAttribute("y", Integer.toString(bounds.getY()));

        nodeImg.setAttribute("xlink:href", this.resourcePathPrefix + imgUri);
        nodeGroup.appendChild(nodeImg);

        String displayName = node.getDisplayName();
        if (displayName != null && !displayName.trim().equals("")) {
            Label titleLabel = null;
            int fontSize = DEFAULT_FONT_SIZE;
            if (figure.getTitleLabel() != null) {
                titleLabel = figure.getTitleLabel().copy();
                fontSize = titleLabel.getFontSize();
            } else {
                titleLabel = new LabelImpl();
                titleLabel.setFontSize(fontSize);
            }
            titleLabel.setText(displayName);

            Element textRect = this.buildTextBox(nodeShape, FPDLNames.ROUTER, bounds.getX(),
                    bounds.getY() + (IMG_RADIUS * 2 + IconTextGap), bounds.getWidth(), (int) (fontSize), titleLabel,
                    "middle");

            nodeGroup.appendChild(textRect);
        }

        if (isTopLevelElem) {
            _refreshDiagramSize(bounds);
        }

        return nodeGroup;
    }

    /**
     * 
     * @param nodeShape
     * @param isTopLevelElem
     * @return
     */
    private Element transformEndNodeShape2Svg(EndNodeShape nodeShape, boolean isTopLevelElem) {
        String imgUri = _getSynchronizerNodeImgUri(nodeShape);

        EndNode node = (EndNode) nodeShape.getWorkflowElementRef();

        //start node group???
        Bounds bounds = _getViewPortBounds(nodeShape);
        Figure figure = nodeShape.getFigure();

        Element nodeGroup = document.createElement("g");

        nodeGroup.setAttribute(FPDLNames.ID, nodeShape.getId());
        nodeGroup.setAttribute(TYPE, FPDLNames.END_NODE);
        ModelElement wfElmRef = nodeShape.getWorkflowElementRef();
        if (wfElmRef != null) {
            nodeGroup.setAttribute(FPDLNames.REF, wfElmRef == null ? "" : wfElmRef.getId());
        }

        Element nodeImg = document.createElement("image");

        nodeImg.setAttribute("width", Integer.toString(IMG_RADIUS * 2));
        nodeImg.setAttribute("height", Integer.toString(IMG_RADIUS * 2));

        nodeImg.setAttribute("x", Integer.toString(bounds.getX() + (bounds.getWidth() / 2 - IMG_RADIUS)));
        nodeImg.setAttribute("y", Integer.toString(bounds.getY()));

        nodeImg.setAttribute("xlink:href", this.resourcePathPrefix + imgUri);
        nodeGroup.appendChild(nodeImg);

        String displayName = node.getDisplayName();
        if (displayName != null && !displayName.trim().equals("")) {
            Label titleLabel = null;
            int fontSize = DEFAULT_FONT_SIZE;
            if (figure.getTitleLabel() != null) {
                titleLabel = figure.getTitleLabel().copy();
                fontSize = titleLabel.getFontSize();
            } else {
                titleLabel = new LabelImpl();
                titleLabel.setFontSize(fontSize);
            }
            titleLabel.setText(displayName);

            Element textRect = this.buildTextBox(nodeShape, FPDLNames.END_NODE, bounds.getX(),
                    bounds.getY() + (IMG_RADIUS * 2 + IconTextGap), bounds.getWidth(), (int) (fontSize), titleLabel,
                    "middle");

            nodeGroup.appendChild(textRect);
        }

        if (isTopLevelElem) {
            _refreshDiagramSize(bounds);
        }

        return nodeGroup;
    }

    /**
     * 
     * @param startNodeShape
     * @param isTopLevelElem
     * @return
     */
    private Element transformStartNodeShape2Svg(StartNodeShape startNodeShape, boolean isTopLevelElem,
            boolean showLabel) {
        String imgUri = _getSynchronizerNodeImgUri(startNodeShape);

        StartNode startNode = (StartNode) startNodeShape.getWorkflowElementRef();

        //start node group???
        Bounds bounds = _getViewPortBounds(startNodeShape);
        Figure figure = startNodeShape.getFigure();

        Element startNodeGroup = document.createElement("g");

        //id 
        startNodeGroup.setAttribute(FPDLNames.ID, startNodeShape.getId());
        startNodeGroup.setAttribute(TYPE, FPDLNames.START_NODE);
        ModelElement wfElmRef = startNodeShape.getWorkflowElementRef();
        if (wfElmRef != null) {
            startNodeGroup.setAttribute(FPDLNames.REF, wfElmRef == null ? "" : wfElmRef.getId());
        }

        Element startNodeImg = document.createElement("image");

        startNodeImg.setAttribute("width", Integer.toString(IMG_RADIUS * 2));
        startNodeImg.setAttribute("height", Integer.toString(IMG_RADIUS * 2));

        startNodeImg.setAttribute("x", Integer.toString(bounds.getX() + (bounds.getWidth() / 2 - IMG_RADIUS)));
        startNodeImg.setAttribute("y", Integer.toString(bounds.getY()));

        startNodeImg.setAttribute("xlink:href", this.resourcePathPrefix + imgUri);
        startNodeGroup.appendChild(startNodeImg);

        if (showLabel) {
            String displayName = startNode.getDisplayName();
            if (displayName != null && !displayName.trim().equals("")) {
                Label titleLabel = null;
                int fontSize = DEFAULT_FONT_SIZE;
                if (figure.getTitleLabel() != null) {
                    titleLabel = figure.getTitleLabel().copy();
                    fontSize = titleLabel.getFontSize();
                } else {
                    titleLabel = new LabelImpl();
                    titleLabel.setFontSize(fontSize);
                }
                titleLabel.setText(displayName);

                Element textRect = this.buildTextBox(startNodeShape, FPDLNames.START_NODE, bounds.getX(),
                        bounds.getY() + (IMG_RADIUS * 2 + IconTextGap), bounds.getWidth(), (int) (fontSize),
                        titleLabel, "middle");

                startNodeGroup.appendChild(textRect);
            }
        }

        if (isTopLevelElem) {
            _refreshDiagramSize(bounds);
        }

        return startNodeGroup;
    }

    private Element buildTextBox(DiagramElement diagramElement, String elementType, int left, int top, int width,
            int height, Label label, String textAlign) {
        return buildTextBox(diagramElement, elementType, left, top, width, height, label, textAlign, "middle",
                true);
    }

    private Element buildTextBox(DiagramElement diagramElement, String elementType, int left, int top, int width,
            int height, Label label, String textAlign, String valign, boolean ishorizonal) {

        int fontSize = label.getFontSize();
        String fontColor = label.getFontColor();
        String fontStyle = label.getFontStyle();

        if (fontStyle == null || fontStyle.trim().equals("")) {
            fontStyle = Label.FONT_STYLE_NORMAL;
        }

        Element textBox = document.createElement("text");

        if (ishorizonal) {//???
            if ("middle".equals(textAlign)) {
                textBox.setAttribute("x", Integer.toString(left + width / 2));
            } else if ("start".equals(textAlign)) {
                textBox.setAttribute("x", Integer.toString(left));
            } else if ("end".equals(textAlign)) {
                textBox.setAttribute("x", Integer.toString(left + width));
            } else {
                textBox.setAttribute("x", Integer.toString(left));
            }
            textBox.setAttribute("y", Integer.toString(top + height));
        } else {
            //???TODO ?middle
            String x = Integer.toString(left + fontSize);
            String y = Integer.toString(top + height / 2);
            textBox.setAttribute("x", x);
            textBox.setAttribute("y", y);

            //90
            textBox.setAttribute("transform", "rotate(270 " + x + "," + y + ")");
        }

        StringBuffer textStyle = new StringBuffer();

        if (!ishorizonal) {
            //firefox ??writting-mode
            //textStyle.append("writing-mode: tb;");
        }

        textStyle.append("text-anchor:").append(textAlign).append(";").append("font-size:").append(fontSize)
                .append("px;")
                //            .append("letter-spacing:").append("1px;")
                .append("fill:").append(fontColor).append(";").append("stroke:none;");

        if (fontStyle.equals(Label.FONT_STYLE_BOLD)) {
            textStyle.append("font-weight:").append("bold;");
        } else if (fontStyle.equals(Label.FONT_STYLE_ITALIC)) {
            textStyle.append("font-style:").append("italic;");
        } else if (fontStyle.equals(Label.FONT_STYLE_ITALIC_BOLD)) {
            textStyle.append("font-weight:").append("bold;");
            textStyle.append("font-style:").append("italic;");
        }

        textBox.setAttribute("style", textStyle.toString());

        textBox.setAttribute("onmouseover", "this.style.cursor='pointer';");
        textBox.setAttribute("onmouseout", "this.style.cursor='default';");

        //click handlerdiagramId
        StringBuffer clickHandler = new StringBuffer();
        clickHandler.append("on_element_click(").append("'").append(diagramElement.getId()).append("',");

        ModelElement wfElement = diagramElement.getWorkflowElementRef();

        //click handler wfElement Id
        if (wfElement != null) {
            clickHandler.append("'").append(wfElement.getId()).append("',");
        } else {
            clickHandler.append("'',");
        }
        //click handler --element type
        clickHandler.append("'").append(elementType).append("',");

        //click handler --process id 
        clickHandler.append("'").append(workflowProcess.getId()).append("',");

        //click handler --subprocess name
        clickHandler.append("'").append(this.subProcessName).append("');");

        textBox.setAttribute("onclick", clickHandler.toString());

        Text textNode = document.createTextNode(label.getText());
        textBox.appendChild(textNode);

        return textBox;
    }

    private Element transformGroupShape2Svg(GroupShape nodeShape, boolean isTopLevelElem) {

        //1?viewport
        Bounds viewportBounds = _getViewPortBounds(nodeShape);
        Rectangle figure = (Rectangle) nodeShape.getFigure();

        Element nodeGroup = document.createElement("g");

        nodeGroup.setAttribute(FPDLNames.ID, nodeShape.getId());
        nodeGroup.setAttribute(TYPE, FPDLNames.GROUP);
        ModelElement wfElmRef = nodeShape.getWorkflowElementRef();
        if (wfElmRef != null) {
            nodeGroup.setAttribute(FPDLNames.REF, wfElmRef == null ? "" : wfElmRef.getId());
        }

        //2?Group      
        Bounds rectBounds = figure.getBounds().copy();
        int thick = rectBounds.getThick();
        int newWidth = rectBounds.getWidth() - thick;
        int newHeight = rectBounds.getHeight() - thick;

        Element rect = document.createElement("rect");
        rect.setAttribute("x", Integer.toString(viewportBounds.getX() + thick / 2));
        rect.setAttribute("y", Integer.toString(viewportBounds.getY() + thick / 2));
        rect.setAttribute("width", Integer.toString(newWidth));
        rect.setAttribute("height", Integer.toString(newHeight));
        rect.setAttribute("rx", Integer.toString(rectBounds.getCornerRadius()));
        rect.setAttribute("ry", Integer.toString(rectBounds.getCornerRadius()));
        nodeGroup.appendChild(rect);

        StringBuffer rectStyle = (new StringBuffer());

        //2.1 
        if (figure.getBounds() != null) {
            rectStyle.append("stroke-width:").append(Integer.toString(thick < 0 ? 1 : thick)).append("px;");
            String color = rectBounds.getColor();
            rectStyle.append("stroke:").append((color == null || color.trim().equals("")) ? "#000000" : color)
                    .append(";");
            String lineType = rectBounds.getLineType();
            if (Bounds.LINETYPE_DOTTED.equals(lineType) || Bounds.LINETYPE_DASHED.equals(lineType)
                    || Bounds.LINETYPE_DASHDOTTED.equals(lineType)) {
                String dashArray = rectBounds.getDashArray();
                if (dashArray == null || dashArray.trim().equals("")) {
                    dashArray = DEFAULT_GROUP_DASHARRAY;
                }

                rectStyle.append("stroke-dasharray: ").append(dashArray).append(";");
            }
        }

        //2.2

        if (figure.getFulfilStyle() != null) {
            //defsElement?grandient
            String gradientElmId = nodeShape.getId() + "_fill_pattern";
            Element gradientElm = document.createElement("linearGradient");
            gradientElm.setAttribute("id", gradientElmId);
            gradientElm.setAttribute("spreadMethod", "pad");

            String color1 = figure.getFulfilStyle().getColor1();
            Element stop1 = document.createElement("stop");
            stop1.setAttribute("offset", "0%");
            stop1.setAttribute("stop-color", color1);
            stop1.setAttribute("stop-opacity", "1");

            String color2 = figure.getFulfilStyle().getColor2();
            Element stop2 = document.createElement("stop");
            stop2.setAttribute("offset", "100%");
            stop2.setAttribute("stop-color", color2);
            stop2.setAttribute("stop-opacity", "1");

            String gradient = figure.getFulfilStyle().getGradientStyle();

            if (gradient == null || gradient.trim().equals("")
                    || FulfilStyle.GRADIENT_STYLE_NONE.equals(gradient)) {
                gradientElm.appendChild(stop2);
            } else {
                gradientElm.appendChild(stop1);
                gradientElm.appendChild(stop2);

                if (FulfilStyle.GRADIENT_STYLE_TOP2DOWN.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "0%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_UPPERLEFT2LOWERRIGHT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_UPPERRIGHT2LOWERLEFT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "100%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "0%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_LEFT2RIGHT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "0%");//?
                } else {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "0%");//?
                }
            }

            this.defsElement.appendChild(gradientElm);

            rectStyle.append("fill:url(#").append(gradientElmId).append(");");
        } else {
            rectStyle.append("fill:none;");
        }

        rect.setAttribute("style", rectStyle.toString());

        //2.3 label??
        String title = figure.getTitle();
        if (title != null && !title.trim().equals("")) {
            //textbox
            int paddingLeft = thick;
            Label titleLabel = figure.getTitleLabel();
            int fontSize = titleLabel.getFontSize();

            int width = rectBounds.getWidth() - paddingLeft * 2;//width???2?thick
            if (width < 0) {
                width = 0;
            }

            int textRectHeight = (int) (fontSize + 2);//?

            int check = GROUP_TITLE_HEIGHT - textRectHeight - thick;
            int paddingTop = thick;
            int height = textRectHeight;

            if (check > 0) {
                paddingTop = thick + (int) (check / 2);

            } else {
                height = GROUP_TITLE_HEIGHT - thick;
            }

            Element textRect = this.buildTextBox(nodeShape, FPDLNames.GROUP, viewportBounds.getX() + paddingLeft,
                    viewportBounds.getY() + paddingTop, width, height, titleLabel, "middle");

            nodeGroup.appendChild(textRect);
        }

        if (isTopLevelElem) {
            _refreshDiagramSize(viewportBounds);
        }

        //3??
        List<DiagramElement> children = nodeShape.getChildren();
        if (children != null && children.size() > 0) {
            //view portviewportgroup?
            Element childrenGroup = document.createElement("svg");
            childrenGroup.setAttribute("x", Integer.toString(viewportBounds.getX() + thick));
            childrenGroup.setAttribute("y", Integer.toString(viewportBounds.getY() + GROUP_TITLE_HEIGHT));
            childrenGroup.setAttribute("width", Integer.toString(rectBounds.getWidth() - thick * 2));
            childrenGroup.setAttribute("height",
                    Integer.toString(rectBounds.getHeight() - GROUP_TITLE_HEIGHT - thick));

            for (DiagramElement diagramElm : children) {
                if (diagramElm instanceof ProcessNodeShape) {
                    Element elm = this.transformProcessNodeShape2Svg((ProcessNodeShape) diagramElm, false);
                    if (elm != null) {
                        childrenGroup.appendChild(elm);
                    }
                }
                //            else if (diagramElm instanceof CommentShape){
                //               Element elm = this.transformCommentShape2Vml((CommentShape)diagramElm, false);
                //               if (elm!=null){
                //                  childrenGroup.appendChild(elm);
                //               }
                //            }
            }

            nodeGroup.appendChild(childrenGroup);
        }

        return nodeGroup;
    }

    private Element drawCommentText(DiagramElement diagramElement, String elementType, int x, int y, int w, int h,
            Label label) {
        Element result = null;

        String text = label.getText();

        String fontColor = label.getFontColor();
        //      String fontFamily = "FangSong_GB2312";//mxUtils.getString(style,
        //mxConstants.STYLE_FONTFAMILY, mxConstants.DEFAULT_FONTFAMILIES);

        int fontSize = label.getFontSize();

        String fireFontStyle = label.getFontStyle();

        boolean isItalic = false;
        if (Label.FONT_STYLE_ITALIC.equals(fireFontStyle) || Label.FONT_STYLE_ITALIC_BOLD.equals(fireFontStyle)) {
            isItalic = true;
        }
        //      int fontStyle = mxUtils.getInt(style, mxConstants.STYLE_FONTSTYLE);
        String weight = "normal";
        if (Label.FONT_STYLE_BOLD.equals(fireFontStyle) || Label.FONT_STYLE_ITALIC_BOLD.equals(fireFontStyle)) {
            weight = "bold";
        }

        String uline = "none";

        if (text != null && text.length() > 0) {
            Element foreignObject = document.createElement("foreignObject");
            foreignObject.setAttribute("x", Integer.toString(x));
            foreignObject.setAttribute("y", Integer.toString(y));
            foreignObject.setAttribute("width", Integer.toString(w));
            foreignObject.setAttribute("height", Integer.toString(h));
            foreignObject.setAttribute("requiredFeatures", "http://www.w3.org/TR/SVG11/feature#Extensibility");

            Element textDiv = document.createElement("div");
            textDiv.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
            foreignObject.appendChild(textDiv);

            StringBuffer styleBuf = new StringBuffer();
            //
            styleBuf.append("width:").append(w).append("px;").append("height:").append(h).append("px;")
                    .append("word-wrap:break-word;");

            //  fontSize+3?
            styleBuf.append("line-height:100%;");
            styleBuf.append("font-weight:").append(weight).append(";").append("font-size:")
                    .append(String.valueOf(fontSize)).append("px;").append("color:").append(fontColor).append(";");
            if (isItalic) {
                styleBuf.append("font-style:").append("italic").append(";");
            }

            textDiv.setAttribute("style", styleBuf.toString());

            StringTokenizer tokenizer = new StringTokenizer(text, "\n", true);
            while (tokenizer.hasMoreTokens()) {
                String tmpStr = tokenizer.nextToken();
                if (tmpStr.equals("\n")) {
                    Element brElm = document.createElement("br");
                    textDiv.appendChild(brElm);
                } else {
                    Element pElem = document.createElement("span");

                    pElem.appendChild(document.createTextNode(tmpStr));
                    textDiv.appendChild(pElem);
                }
            }

            result = foreignObject;
        }
        return result;
    }

    private Element transformCommentShape2Svg(CommentShape commentShape, boolean isTopLevelElm) {
        //1?view port
        Bounds viewportBounds = _getViewPortBounds(commentShape);
        Rectangle figure = (Rectangle) commentShape.getFigure();

        Element nodeGroup = document.createElement("g");

        nodeGroup.setAttribute(FPDLNames.ID, commentShape.getId());
        nodeGroup.setAttribute(TYPE, FPDLNames.COMMENT);
        ModelElement wfElmRef = commentShape.getWorkflowElementRef();
        if (wfElmRef != null) {
            nodeGroup.setAttribute(FPDLNames.REF, wfElmRef == null ? "" : wfElmRef.getId());
        }

        //2?Comment      
        Bounds rectBounds = figure.getBounds().copy();
        int thick = rectBounds.getThick();
        int newWidth = rectBounds.getWidth() - thick;
        int newHeight = rectBounds.getHeight() - thick;

        Element polyline = document.createElement("path");
        StringBuffer pointList = new StringBuffer();
        pointList.append("M ").append(rectBounds.getX() + (int) (rectBounds.getWidth() / 3)).append(" ")
                .append(rectBounds.getY()).append(" ").append("L ").append(rectBounds.getX()).append(" ")
                .append(rectBounds.getY()).append(" ").append("L ").append(rectBounds.getX()).append(" ")
                .append(rectBounds.getY() + rectBounds.getHeight()).append(" ").append("L ")
                .append(rectBounds.getX() + (int) (rectBounds.getWidth() / 3)).append(" ")
                .append(rectBounds.getY() + rectBounds.getHeight());

        polyline.setAttribute("d", pointList.toString());
        polyline.setAttribute("fill", "none");
        nodeGroup.appendChild(polyline);

        //2.1 
        StringBuffer polylineStyle = (new StringBuffer());
        if (figure.getBounds() != null) {
            polylineStyle.append("stroke-width:").append(Integer.toString(thick < 0 ? 1 : thick)).append("px;");
            String color = rectBounds.getColor();
            polylineStyle.append("stroke:").append((color == null || color.trim().equals("")) ? "#000000" : color)
                    .append(";");
            String lineType = rectBounds.getLineType();
            if (Bounds.LINETYPE_DOTTED.equals(lineType) || Bounds.LINETYPE_DASHED.equals(lineType)
                    || Bounds.LINETYPE_DASHDOTTED.equals(lineType)) {
                String dashArray = rectBounds.getDashArray();
                if (dashArray == null || dashArray.trim().equals("")) {
                    if (Bounds.LINETYPE_DOTTED.equals(lineType)) {
                        dashArray = DEFAULT_DOT_DASHARRAY;
                    } else if (Bounds.LINETYPE_DASHED.equals(lineType)) {
                        dashArray = DEFAULT_DASH_DASHARRAY;
                    } else if (Bounds.LINETYPE_DASHDOTTED.equals(lineType)) {
                        dashArray = DEFAULT_DOTDASH_DASHARRAY;
                    }
                }
                polylineStyle.append("stroke-dasharray: ").append(dashArray).append(";");
            }
        }
        polyline.setAttribute("style", polylineStyle.toString());

        //2.2       
        Element contentBackground = document.createElement("rect");
        contentBackground.setAttribute("x", Integer.toString(rectBounds.getX() + thick + 1));
        contentBackground.setAttribute("y", Integer.toString(rectBounds.getY() + thick + 1));
        contentBackground.setAttribute("width", Integer.toString(newWidth - 2));
        contentBackground.setAttribute("height", Integer.toString(newHeight - 2));

        nodeGroup.appendChild(contentBackground);

        StringBuffer contentBackgroundStyle = (new StringBuffer());
        contentBackgroundStyle.append("stroke:none;");

        if (figure.getFulfilStyle() != null) {
            //defsElement?grandient
            String gradientElmId = commentShape.getId() + "_fill_pattern";
            Element gradientElm = document.createElement("linearGradient");
            gradientElm.setAttribute("id", gradientElmId);
            gradientElm.setAttribute("spreadMethod", "pad");

            String color1 = figure.getFulfilStyle().getColor1();
            Element stop1 = document.createElement("stop");
            stop1.setAttribute("offset", "0%");
            stop1.setAttribute("stop-color", color1);
            stop1.setAttribute("stop-opacity", "1");

            String color2 = figure.getFulfilStyle().getColor2();
            Element stop2 = document.createElement("stop");
            stop2.setAttribute("offset", "100%");
            stop2.setAttribute("stop-color", color2);
            stop2.setAttribute("stop-opacity", "1");

            String gradient = figure.getFulfilStyle().getGradientStyle();

            if (gradient == null || gradient.trim().equals("")
                    || FulfilStyle.GRADIENT_STYLE_NONE.equals(gradient)) {
                gradientElm.appendChild(stop2);
            } else {
                gradientElm.appendChild(stop1);
                gradientElm.appendChild(stop2);

                if (FulfilStyle.GRADIENT_STYLE_TOP2DOWN.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "0%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_UPPERLEFT2LOWERRIGHT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_UPPERRIGHT2LOWERLEFT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "100%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "0%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_LEFT2RIGHT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "0%");//?
                } else {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "0%");//?
                }
            }

            this.defsElement.appendChild(gradientElm);

            contentBackgroundStyle.append("fill:url(#").append(gradientElmId).append(");");
        } else {
            contentBackgroundStyle.append("fill:none;");
        }

        contentBackground.setAttribute("style", contentBackgroundStyle.toString());

        //comment
        String contentTxt = figure.getContent();
        if (contentTxt != null && !contentTxt.trim().equals("")) {
            //textbox
            int padding = 4;
            int spacing = 0;
            int textBoxPadding = (padding + thick);
            Label contentLabel = figure.getContentLabel().copy();

            Element textRect = this.drawCommentText(commentShape, FPDLNames.COMMENT,
                    viewportBounds.getX() + textBoxPadding, viewportBounds.getY() + textBoxPadding,
                    newWidth - textBoxPadding * 2, newHeight - textBoxPadding * 2, contentLabel);

            nodeGroup.appendChild(textRect);
        }

        if (isTopLevelElm) {
            _refreshDiagramSize(viewportBounds);
        }

        return nodeGroup;
    }

    private Element transformPool2Svg(PoolShape nodeShape, boolean isTopLevelElem) {
        //1?viewport
        Bounds viewportBounds = _getViewPortBounds(nodeShape);
        Rectangle figure = (Rectangle) nodeShape.getFigure();

        Element nodeGroup = document.createElement("g");

        nodeGroup.setAttribute(FPDLNames.ID, nodeShape.getId());
        nodeGroup.setAttribute(TYPE, FPDLNames.POOL);
        ModelElement wfElmRef = nodeShape.getWorkflowElementRef();
        if (wfElmRef != null) {
            nodeGroup.setAttribute(FPDLNames.REF, wfElmRef == null ? "" : wfElmRef.getId());
        }

        //2?pool      
        Bounds rectBounds = figure.getBounds().copy();
        int thick = rectBounds.getThick();
        int newWidth = rectBounds.getWidth() - thick;
        int newHeight = rectBounds.getHeight() - thick;
        Element rect = document.createElement("rect");
        rect.setAttribute("x", Integer.toString(rectBounds.getX() + thick / 2));
        rect.setAttribute("y", Integer.toString(rectBounds.getY() + thick / 2));
        rect.setAttribute("width", Integer.toString(newWidth));
        rect.setAttribute("height", Integer.toString(newHeight));

        nodeGroup.appendChild(rect);

        Element line = document.createElement("line");
        if (Diagram.VERTICAL.equals(diagram.getDirection())) {
            line.setAttribute("x1", Integer.toString(rectBounds.getX() + thick));
            line.setAttribute("y1", Integer.toString(rectBounds.getY() + POOL_LANE_TITLE_HEIGHT));

            line.setAttribute("x2", Integer.toString(rectBounds.getX() + (thick + newWidth)));
            line.setAttribute("y2", Integer.toString(rectBounds.getY() + POOL_LANE_TITLE_HEIGHT));
        } else {
            line.setAttribute("x1", Integer.toString(rectBounds.getX() + POOL_LANE_TITLE_HEIGHT));
            line.setAttribute("y1", Integer.toString(rectBounds.getY() + thick));

            line.setAttribute("x2", Integer.toString(rectBounds.getX() + POOL_LANE_TITLE_HEIGHT));
            line.setAttribute("y2", Integer.toString(rectBounds.getY() + (thick + newHeight)));
        }
        nodeGroup.appendChild(line);

        //2.1
        StringBuffer rectStyle = (new StringBuffer());

        //2.1 
        if (figure.getBounds() != null) {
            rectStyle.append("stroke-width:").append(Integer.toString(thick < 0 ? 1 : thick)).append("px;");
            String color = rectBounds.getColor();
            rectStyle.append("stroke:").append((color == null || color.trim().equals("")) ? "#000000" : color)
                    .append(";");
            String lineType = rectBounds.getLineType();
            if (Bounds.LINETYPE_DOTTED.equals(lineType) || Bounds.LINETYPE_DASHED.equals(lineType)
                    || Bounds.LINETYPE_DASHDOTTED.equals(lineType)) {
                String dashArray = rectBounds.getDashArray();
                if (dashArray == null || dashArray.trim().equals("")) {
                    if (Bounds.LINETYPE_DOTTED.equals(lineType)) {
                        dashArray = DEFAULT_DOT_DASHARRAY;
                    } else if (Bounds.LINETYPE_DASHED.equals(lineType)) {
                        dashArray = DEFAULT_DASH_DASHARRAY;
                    } else if (Bounds.LINETYPE_DASHDOTTED.equals(lineType)) {
                        dashArray = DEFAULT_DOTDASH_DASHARRAY;
                    }
                }
                rectStyle.append("stroke-dasharray: ").append(dashArray).append(";");
            }
        }
        line.setAttribute("style", rectStyle.toString());

        //2.2
        if (figure.getFulfilStyle() != null) {
            //defsElement?grandient
            String gradientElmId = nodeShape.getId() + "_fill_pattern";
            Element gradientElm = document.createElement("linearGradient");
            gradientElm.setAttribute("id", gradientElmId);
            gradientElm.setAttribute("spreadMethod", "pad");

            String color1 = figure.getFulfilStyle().getColor1();
            Element stop1 = document.createElement("stop");
            stop1.setAttribute("offset", "0%");
            stop1.setAttribute("stop-color", color1);
            stop1.setAttribute("stop-opacity", "1");

            String color2 = figure.getFulfilStyle().getColor2();
            Element stop2 = document.createElement("stop");
            stop2.setAttribute("offset", "100%");
            stop2.setAttribute("stop-color", color2);
            stop2.setAttribute("stop-opacity", "1");

            String gradient = figure.getFulfilStyle().getGradientStyle();

            if (gradient == null || gradient.trim().equals("")
                    || FulfilStyle.GRADIENT_STYLE_NONE.equals(gradient)) {
                gradientElm.appendChild(stop2);
            } else {
                gradientElm.appendChild(stop1);
                gradientElm.appendChild(stop2);

                if (FulfilStyle.GRADIENT_STYLE_TOP2DOWN.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "0%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_UPPERLEFT2LOWERRIGHT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_UPPERRIGHT2LOWERLEFT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "100%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "0%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_LEFT2RIGHT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "0%");//?
                } else {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "0%");//?
                }
            }

            this.defsElement.appendChild(gradientElm);

            rectStyle.append("fill:url(#").append(gradientElmId).append(");");
        } else {
            rectStyle.append("fill:none;");
        }

        rect.setAttribute("style", rectStyle.toString());

        //2.3 label??
        String title = figure.getTitle();
        if (title != null && !title.trim().equals("")) {
            //textbox
            int paddingLeft = (thick);
            Label titleLabel = figure.getTitleLabel().copy();
            int fontSize = titleLabel.getFontSize();
            ;

            int textRectHeight = (int) (fontSize + 2);//?

            int check = POOL_LANE_TITLE_HEIGHT - textRectHeight - thick;
            int paddingTop = thick;

            if (check > 0) {
                paddingTop = thick + (int) (check / 2);

            } else {
                textRectHeight = POOL_LANE_TITLE_HEIGHT - thick;
            }
            //??
            if (Diagram.VERTICAL.equals(diagram.getDirection())) {
                int width = rectBounds.getWidth() - paddingLeft * 2;//width???2?thick
                if (width < 0) {
                    width = 0;
                }
                Element textRect = this.buildTextBox(nodeShape, FPDLNames.POOL, rectBounds.getX() + paddingLeft,
                        rectBounds.getY() + paddingTop, width, textRectHeight, titleLabel, "middle");
                nodeGroup.appendChild(textRect);
            } else {//??
                int height = rectBounds.getHeight() - paddingLeft * 2;
                Element textRect = this.buildTextBox(nodeShape, FPDLNames.POOL, rectBounds.getX() + paddingTop,
                        rectBounds.getY() + paddingLeft, textRectHeight, height, titleLabel, "middle", "middle",
                        false);
                nodeGroup.appendChild(textRect);
            }
        }

        if (isTopLevelElem) {
            _refreshDiagramSize(viewportBounds);
        }

        //3??
        List<DiagramElement> children = nodeShape.getChildren();
        if (children != null && children.size() > 0) {
            //??
            Element childrenGroup = document.createElement("svg");
            //         StringBuffer tmpStyle = new StringBuffer();
            if (Diagram.VERTICAL.equals(diagram.getDirection())) {
                childrenGroup.setAttribute("x", Integer.toString(rectBounds.getX() + thick));
                childrenGroup.setAttribute("y", Integer.toString(rectBounds.getY() + POOL_LANE_TITLE_HEIGHT));
                childrenGroup.setAttribute("width", Integer.toString(newWidth));
                childrenGroup.setAttribute("height",
                        Integer.toString(rectBounds.getHeight() - GROUP_TITLE_HEIGHT - thick));
            } else {
                childrenGroup.setAttribute("x", Integer.toString(rectBounds.getX() + POOL_LANE_TITLE_HEIGHT));
                childrenGroup.setAttribute("y", Integer.toString(rectBounds.getY() + thick));
                childrenGroup.setAttribute("width",
                        Integer.toString(rectBounds.getWidth() - POOL_LANE_TITLE_HEIGHT - thick));
                childrenGroup.setAttribute("height", Integer.toString(newHeight));

                //            tmpStyle.append("position:absolute;")
                //            .append("left:").append().append("px;")
                //            .append("top:").append().append("px;")
                //            .append("width:").append().append("px;")
                //            .append("height:").append(newHeight).append("px");
            }

            //         if (Diagram.VERTICAL.equals(diagram.getDirection())){
            //            StringBuffer coordSizeBufTmp = new StringBuffer();
            //            coordSizeBufTmp.append(newWidth).append(",").append(rectBounds.getHeight()-GROUP_TITLE_HEIGHT-thick);
            //            childrenGroup.setAttribute("coordsize", coordSizeBufTmp.toString());
            //         }else{
            //            StringBuffer coordSizeBufTmp = new StringBuffer();
            //            coordSizeBufTmp.append(viewportBounds.getWidth()-POOL_LANE_TITLE_HEIGHT-thick).append(",").append(newHeight);
            //            childrenGroup.setAttribute("coordsize", coordSizeBufTmp.toString());
            //         }
            int offset = 0;
            int laneCount = children.size();
            for (int index = 0; index < laneCount; index++) {
                DiagramElement diagramElm = children.get(index);
                if (diagramElm instanceof LaneShape) {
                    LaneShape laneShape = (LaneShape) diagramElm;
                    Element elm = this.transformLane2Svg(laneShape, offset, index, laneCount);
                    if (elm != null) {
                        childrenGroup.appendChild(elm);
                    }

                    Rectangle rectTmp = (Rectangle) laneShape.getFigure();
                    Bounds tmpBounds = rectTmp.getBounds();

                    if (Diagram.VERTICAL.equals(diagram.getDirection())) {
                        offset = offset + tmpBounds.getWidth();
                    } else {
                        offset = offset + tmpBounds.getHeight();
                    }
                }
            }

            nodeGroup.appendChild(childrenGroup);
        }

        return nodeGroup;
    }

    private Element transformLane2Svg(LaneShape nodeShape, int offset, int laneIndex, int laneCount) {
        Bounds viewportBounds = _getViewPortBounds(nodeShape);
        Rectangle figure = (Rectangle) nodeShape.getFigure();

        Element nodeGroup = document.createElement("g");

        int x = 0;
        int y = 0;
        if (Diagram.VERTICAL.equals(diagram.getDirection())) {
            x = offset;
            y = 0;
        } else {
            x = 0;
            y = offset;
        }

        nodeGroup.setAttribute(FPDLNames.ID, nodeShape.getId());
        nodeGroup.setAttribute(TYPE, FPDLNames.LANE);
        ModelElement wfElmRef = nodeShape.getWorkflowElementRef();
        if (wfElmRef != null) {
            nodeGroup.setAttribute(FPDLNames.REF, wfElmRef == null ? "" : wfElmRef.getId());
        }

        Bounds rectBounds = figure.getBounds().copy();
        int thick = rectBounds.getThick();
        int newWidth = rectBounds.getWidth() - thick * 2;
        int newHeight = rectBounds.getHeight() - thick * 2;
        String title = figure.getTitle();

        //1?
        Element rect = document.createElement("rect");
        rect.setAttribute("width", Integer.toString(newWidth));
        rect.setAttribute("height", Integer.toString(newHeight));
        rect.setAttribute("x", Integer.toString(x + thick));
        rect.setAttribute("y", Integer.toString(y + thick));

        nodeGroup.appendChild(rect);

        StringBuffer fillStyle = new StringBuffer();
        fillStyle.append("stroke:none;");

        if (figure.getFulfilStyle() != null) {
            //defsElement?grandient
            String gradientElmId = nodeShape.getId() + "_fill_pattern";
            Element gradientElm = document.createElement("linearGradient");
            gradientElm.setAttribute("id", gradientElmId);
            gradientElm.setAttribute("spreadMethod", "pad");

            String color1 = figure.getFulfilStyle().getColor1();
            Element stop1 = document.createElement("stop");
            stop1.setAttribute("offset", "0%");
            stop1.setAttribute("stop-color", color1);
            stop1.setAttribute("stop-opacity", "1");

            String color2 = figure.getFulfilStyle().getColor2();
            Element stop2 = document.createElement("stop");
            stop2.setAttribute("offset", "100%");
            stop2.setAttribute("stop-color", color2);
            stop2.setAttribute("stop-opacity", "1");

            String gradient = figure.getFulfilStyle().getGradientStyle();

            if (gradient == null || gradient.trim().equals("")
                    || FulfilStyle.GRADIENT_STYLE_NONE.equals(gradient)) {
                gradientElm.appendChild(stop2);
            } else {
                gradientElm.appendChild(stop1);
                gradientElm.appendChild(stop2);

                if (FulfilStyle.GRADIENT_STYLE_TOP2DOWN.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "0%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_UPPERLEFT2LOWERRIGHT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_UPPERRIGHT2LOWERLEFT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "100%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "0%");
                    gradientElm.setAttribute("y2", "100%");
                } else if (FulfilStyle.GRADIENT_STYLE_LEFT2RIGHT.equals(gradient)) {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "0%");//?
                } else {
                    gradientElm.setAttribute("x1", "0%");
                    gradientElm.setAttribute("y1", "0%");
                    gradientElm.setAttribute("x2", "100%");
                    gradientElm.setAttribute("y2", "0%");//?
                }
            }

            this.defsElement.appendChild(gradientElm);

            fillStyle.append("fill:url(#").append(gradientElmId).append(");");
        } else {
            fillStyle.append("fill:none;");
        }
        rect.setAttribute("style", fillStyle.toString());

        //2? 
        StringBuffer strokeStyle = (new StringBuffer());

        //2.1 
        if (figure.getBounds() != null) {
            strokeStyle.append("stroke-width:").append(Integer.toString(thick < 0 ? 1 : thick)).append("px;");
            String color = rectBounds.getColor();
            strokeStyle.append("stroke:").append((color == null || color.trim().equals("")) ? "#000000" : color)
                    .append(";");
            String lineType = rectBounds.getLineType();
            if (Bounds.LINETYPE_DOTTED.equals(lineType) || Bounds.LINETYPE_DASHED.equals(lineType)
                    || Bounds.LINETYPE_DASHDOTTED.equals(lineType)) {
                String dashArray = rectBounds.getDashArray();
                if (dashArray == null || dashArray.trim().equals("")) {
                    if (Bounds.LINETYPE_DOTTED.equals(lineType)) {
                        dashArray = DEFAULT_DOT_DASHARRAY;
                    } else if (Bounds.LINETYPE_DASHED.equals(lineType)) {
                        dashArray = DEFAULT_DASH_DASHARRAY;
                    } else if (Bounds.LINETYPE_DASHDOTTED.equals(lineType)) {
                        dashArray = DEFAULT_DOTDASH_DASHARRAY;
                    }
                }
                strokeStyle.append("stroke-dasharray: ").append(dashArray).append(";");
            }
        }
        // lane
        if (Diagram.VERTICAL.equals(diagram.getDirection())) {

            //2
            if (title != null && !title.trim().equals("")) {
                Element line = document.createElement("line");

                line.setAttribute("x1", Integer.toString(x + thick));
                line.setAttribute("y1", Integer.toString(y + POOL_LANE_TITLE_HEIGHT));
                //            String from = thick + "," + POOL_LANE_TITLE_HEIGHT;
                //            line.setAttribute("from", from);

                line.setAttribute("x2", Integer.toString(x + (thick + newWidth)));
                line.setAttribute("y2", Integer.toString(y + POOL_LANE_TITLE_HEIGHT));
                //            String to = (thick+newWidth) + ","  + POOL_LANE_TITLE_HEIGHT;
                //            line.setAttribute("to", to);
                if (strokeStyle != null) {
                    line.setAttribute("style", strokeStyle.toString());
                }
                nodeGroup.appendChild(line);
            }

            //
            if (laneIndex > 0) {
                Element line = document.createElement("line");
                line.setAttribute("x1", Integer.toString(x + thick));
                line.setAttribute("y1", Integer.toString(y + thick));

                //            String from = thick + "," + thick;
                //            line.setAttribute("from", from);
                line.setAttribute("x2", Integer.toString(x + (thick + newHeight)));
                line.setAttribute("y2", Integer.toString(y + thick));

                //            String to = (thick+newHeight) + "," + (thick );
                //            line.setAttribute("to", to);
                if (strokeStyle != null) {
                    line.setAttribute("style", strokeStyle.toString());
                }
                nodeGroup.appendChild(line);
            }

        } else {
            //1

            //2
            if (title != null && !title.trim().equals("")) {
                Element line = document.createElement("line");
                line.setAttribute("x1", Integer.toString(x + POOL_LANE_TITLE_HEIGHT));
                line.setAttribute("y1", Integer.toString(y + thick));
                //            String from = POOL_LANE_TITLE_HEIGHT + "," + thick;
                //            line.setAttribute("from", from);

                line.setAttribute("x2", Integer.toString(x + POOL_LANE_TITLE_HEIGHT));
                line.setAttribute("y2", Integer.toString(y + (thick + newHeight)));
                //            String to = POOL_LANE_TITLE_HEIGHT + "," + (thick + newHeight);
                //            line.setAttribute("to", to);
                if (strokeStyle != null) {
                    line.setAttribute("style", strokeStyle.toString());
                }
                nodeGroup.appendChild(line);
            }

            //
            if (laneIndex > 0) {
                Element line = document.createElement("line");
                line.setAttribute("x1", Integer.toString(x + thick));
                line.setAttribute("y1", Integer.toString(y + thick));
                //            String from = thick + "," + thick;
                //            line.setAttribute("from", from);

                line.setAttribute("x2", Integer.toString(x + (thick + newWidth)));
                line.setAttribute("y2", Integer.toString(y + thick));
                //            String to = (thick+newWidth) + "," + (thick );
                //            line.setAttribute("to", to);
                if (strokeStyle != null) {
                    line.setAttribute("style", strokeStyle.toString());
                }
                nodeGroup.appendChild(line);
            }

        }

        //3?label??      
        if (title != null && !title.trim().equals("")) {
            int paddingLeft = (thick);
            Label titleLabel = figure.getTitleLabel().copy();
            int fontSize = titleLabel.getFontSize();

            int textRectHeight = (int) (fontSize + 2);//?

            int check = POOL_LANE_TITLE_HEIGHT - textRectHeight - thick;
            int paddingTop = thick;

            if (check > 0) {
                paddingTop = thick + (int) (check / 2);

            } else {
                textRectHeight = POOL_LANE_TITLE_HEIGHT - thick;
            }
            //??
            if (Diagram.VERTICAL.equals(diagram.getDirection())) {
                int width = rectBounds.getWidth() - paddingLeft * 2;//width???2?thick
                if (width < 0) {
                    width = 0;
                }
                Element textRect = this.buildTextBox(nodeShape, FPDLNames.LANE, x + paddingLeft, y + paddingTop,
                        width, textRectHeight, titleLabel, "middle");
                nodeGroup.appendChild(textRect);
            } else {//??
                int height = rectBounds.getHeight() - paddingLeft * 2;
                Element textRect = this.buildTextBox(nodeShape, FPDLNames.LANE, x + paddingTop, y + paddingLeft,
                        textRectHeight, height, titleLabel, "middle", "middle", false);
                nodeGroup.appendChild(textRect);
            }
        }

        //4??
        List<DiagramElement> children = nodeShape.getChildren();
        if (children != null && children.size() > 0) {

            //??
            Element childrenGroup = document.createElement("svg");
            if (Diagram.VERTICAL.equals(diagram.getDirection())) {
                childrenGroup.setAttribute("x", Integer.toString(x + thick));
                childrenGroup.setAttribute("y", Integer.toString(y + POOL_LANE_TITLE_HEIGHT));
                childrenGroup.setAttribute("width", Integer.toString(newWidth));
                childrenGroup.setAttribute("height",
                        Integer.toString(rectBounds.getHeight() - GROUP_TITLE_HEIGHT - thick));
            } else {
                childrenGroup.setAttribute("x", Integer.toString(x + POOL_LANE_TITLE_HEIGHT));
                childrenGroup.setAttribute("y", Integer.toString(y + thick));
                childrenGroup.setAttribute("width",
                        Integer.toString(rectBounds.getWidth() - POOL_LANE_TITLE_HEIGHT - thick));
                childrenGroup.setAttribute("height", Integer.toString(newHeight));
            }

            for (DiagramElement diagramElm : children) {
                if (diagramElm instanceof ProcessNodeShape) {
                    Element elm = this.transformProcessNodeShape2Svg((ProcessNodeShape) diagramElm, false);
                    if (elm != null) {
                        childrenGroup.appendChild(elm);
                    }
                } else if (diagramElm instanceof CommentShape) {
                    Element elm = this.transformCommentShape2Svg((CommentShape) diagramElm, false);
                    if (elm != null) {
                        childrenGroup.appendChild(elm);
                    }
                } else if (diagram instanceof GroupShape) {
                    Element elm = this.transformGroupShape2Svg((GroupShape) diagram, false);
                    if (elm != null) {
                        childrenGroup.appendChild(elm);
                    }
                }
            }

            nodeGroup.appendChild(childrenGroup);

        }

        return nodeGroup;
    }

    private Element transformConnectorShape2Svg(ConnectorShape connectorShape) {
        NodeShape fromNodeShape = connectorShape.getFromNode();
        NodeShape toNodeShape = connectorShape.getToNode();
        ModelElement wfElm = connectorShape.getWorkflowElementRef();
        String wfElmId = wfElm == null ? "null" : wfElm.getId();
        if (fromNodeShape == null || toNodeShape == null) {
            log.warn("TransitionShape[Id=" + connectorShape.getId() + ",WfElemId=" + wfElmId
                    + "] from_nodeto_node");
            return null;
        }

        Bounds absoluteFromNodeBounds = this._getAbsoluteBounds(fromNodeShape);
        Bounds absoluteToNodeBounds = this._getAbsoluteBounds(toNodeShape);

        if (absoluteFromNodeBounds == null || absoluteToNodeBounds == null) {
            log.warn("TransitionShape[Id=" + connectorShape.getId() + ",WfElemId=" + wfElmId
                    + "] from_nodeto_nodebounds");
            return null;
        }

        Line fireLine = (Line) connectorShape.getFigure();
        List<Point> linePoints = fireLine.getPoints();

        Point fromRefPoint = null;//from_anchor?
        Point toRefPoint = null;//to_anchor?
        if (linePoints == null || linePoints.size() == 0) {
            fromRefPoint = new Point();
            fromRefPoint.setX(absoluteToNodeBounds.getX() + absoluteToNodeBounds.getWidth() / 2);
            fromRefPoint.setY(absoluteToNodeBounds.getY() + absoluteToNodeBounds.getHeight() / 2);

        } else {
            fromRefPoint = linePoints.get(0);
        }
        if (linePoints == null || linePoints.size() == 0) {
            toRefPoint = new Point();
            toRefPoint.setX(absoluteFromNodeBounds.getX() + absoluteFromNodeBounds.getWidth() / 2);
            toRefPoint.setY(absoluteFromNodeBounds.getY() + absoluteFromNodeBounds.getHeight() / 2);

        } else {
            toRefPoint = linePoints.get(linePoints.size() - 1);
        }

        //from_anchor
        Point fromAnchor = null;
        fromAnchor = _calculateAnchor(fromNodeShape, absoluteFromNodeBounds, fromRefPoint);

        //to_anchor      
        Point toAnchor = null;
        toAnchor = _calculateAnchor(toNodeShape, absoluteToNodeBounds, toRefPoint);

        Element groupElement = document.createElement("g");
        String elementType = null;
        groupElement.setAttribute(FPDLNames.ID, connectorShape.getId());
        if (connectorShape instanceof TransitionShape) {
            elementType = FPDLNames.TRANSITION;
        } else if (connectorShape instanceof MessageFlowShape) {
            elementType = FPDLNames.MESSAGEFLOW;
        } else if (connectorShape instanceof AssociationShape) {
            elementType = FPDLNames.ASSOCIATION;
        }
        groupElement.setAttribute(TYPE, elementType);

        ModelElement wfElmRef = connectorShape.getWorkflowElementRef();
        if (wfElmRef != null) {
            groupElement.setAttribute(FPDLNames.REF, wfElmRef == null ? "" : wfElmRef.getId());
        }

        //polyline
        Element polylineElm = document.createElement("polyline");
        groupElement.appendChild(polylineElm);

        polylineElm.setAttribute("points", _makePointsSeq(fromAnchor.copy(), toAnchor.copy(), linePoints));

        //2.1 
        StringBuffer lineStyle = (new StringBuffer());
        Bounds lineBounds = fireLine.getBounds();
        String color = "#000000";
        if (lineBounds != null) {
            int thick = lineBounds.getThick();
            lineStyle.append("stroke-width:").append(Integer.toString(thick < 0 ? 1 : thick)).append("px;");
            color = lineBounds.getColor();
            color = (color == null || color.trim().equals("")) ? "#000000" : color;
            lineStyle.append("stroke:").append(color).append(";");
            String lineType = lineBounds.getLineType();
            if (Bounds.LINETYPE_DOTTED.equals(lineType) || Bounds.LINETYPE_DASHED.equals(lineType)
                    || Bounds.LINETYPE_DASHDOTTED.equals(lineType)) {
                String dashArray = lineBounds.getDashArray();
                if (dashArray == null || dashArray.trim().equals("")) {
                    if (connectorShape instanceof AssociationShape) {
                        dashArray = DEFAULT_ASSOC_DASHARRAY;
                    } else if (connectorShape instanceof MessageFlowShape) {
                        dashArray = DEFAULT_MESSAGEFLOW_DASHARRAY;
                    } else {
                        if (Bounds.LINETYPE_DOTTED.equals(lineType)) {
                            dashArray = DEFAULT_DOT_DASHARRAY;
                        } else if (Bounds.LINETYPE_DASHED.equals(lineType)) {

                            dashArray = DEFAULT_DASH_DASHARRAY;
                        } else if (Bounds.LINETYPE_DASHDOTTED.equals(lineType)) {
                            dashArray = DEFAULT_DOTDASH_DASHARRAY;
                        }
                    }

                }
                lineStyle.append("stroke-dasharray: ").append(lineBounds.getDashArray()).append(";");
            }
        }

        //
        if (connectorShape instanceof TransitionShape) {
            Element mkElm = this.blockArrowMarkerMap.get(color);
            String mkId = BASIC_BLOCK_ARROW_MARKER_ID;
            if (mkElm != null) {
                mkId = mkElm.getAttribute("id");
            } else {
                //marker
                Element mkElmOriginal = this.blockArrowMarkerMap.get("#000000");
                if (mkElmOriginal != null) {
                    Element newElm = (Element) mkElmOriginal.cloneNode(true);

                    mkId = connectorShape.getId() + "_end_marker";
                    newElm.setAttribute("id", mkId);
                    Element pathElm = (Element) newElm.getFirstChild();
                    pathElm.setAttribute("style", "stroke:none;fill:" + color + ";");

                    blockArrowMarkerMap.put(color, newElm);
                    this.defsElement.appendChild(newElm);
                }
            }
            polylineElm.setAttribute("marker-end", "url(#" + mkId + ")");
        } else if (connectorShape instanceof MessageFlowShape) {
            Element mkElm = this.circleMarkerMap.get(color);
            String mkId = BASIC_CIRCLE_MARKER_ID;
            if (mkElm != null) {
                mkId = mkElm.getAttribute("id");
            } else {
                //marker
                Element mkElmOriginal = this.circleMarkerMap.get("#000000");
                if (mkElmOriginal != null) {
                    Element newElm = (Element) mkElmOriginal.cloneNode(true);

                    mkId = connectorShape.getId() + "_start_marker";
                    newElm.setAttribute("id", mkId);
                    Element pathElm = (Element) newElm.getFirstChild();
                    pathElm.setAttribute("style", "stroke:" + color + ";fill:none;stroke-dasharray:2,0;");

                    circleMarkerMap.put(color, newElm);
                    this.defsElement.appendChild(newElm);
                }
            }
            polylineElm.setAttribute("marker-start", "url(#" + mkId + ")");

            mkElm = this.blockArrowMarker2Map.get(color);
            mkId = BASIC_BLOCK_ARROW_MARKER2_ID;
            if (mkElm != null) {
                mkId = mkElm.getAttribute("id");
            } else {
                //marker
                Element mkElmOriginal = this.blockArrowMarker2Map.get("#000000");
                if (mkElmOriginal != null) {
                    Element newElm = (Element) mkElmOriginal.cloneNode(true);

                    mkId = connectorShape.getId() + "_end_marker";
                    newElm.setAttribute("id", mkId);
                    Element pathElm = (Element) newElm.getFirstChild();
                    pathElm.setAttribute("style", "stroke:" + color + ";fill:none;stroke-dasharray:2,0;");

                    blockArrowMarker2Map.put(color, newElm);
                    this.defsElement.appendChild(newElm);
                }
            }
            polylineElm.setAttribute("marker-end", "url(#" + mkId + ")");

        }

        //
        lineStyle.append("fill:none;");

        polylineElm.setAttribute("style", lineStyle.toString());

        //
        Label lb = fireLine.getTitleLabel();
        String displayName = null;
        if (wfElm != null) {
            displayName = wfElm.getDisplayName();
        } else {
            displayName = fireLine.getTitle();
        }
        if (displayName != null && !displayName.trim().equals("")) {
            Point labelRelativePos = fireLine.getLabelPosition();
            //labelAbsPoslabel
            Point labelAbsPos = _getLabelAbsolutePosition(fromAnchor.copy(), toAnchor.copy(), linePoints,
                    labelRelativePos);
            Label titleLabel = null;
            if (lb == null) {
                titleLabel = new LabelImpl();
                titleLabel.setFontSize(DEFAULT_FONT_SIZE);
            } else {
                titleLabel = lb.copy();
            }
            titleLabel.setText(displayName);
            Dimension dimension = _calculateFontSize(titleLabel.getText(), titleLabel.getFontSize());

            labelAbsPos.setX(labelAbsPos.getX() - dimension.width / 2);
            labelAbsPos.setY(labelAbsPos.getY() - dimension.height / 2);

            Element textRect = this.buildTextBox(connectorShape, elementType, labelAbsPos.getX(),
                    labelAbsPos.getY(), dimension.width, dimension.height, titleLabel, "middle");

            groupElement.appendChild(textRect);

            //??
            Bounds boundsTmp = new BoundsImpl();
            boundsTmp.setX(labelAbsPos.getX());
            boundsTmp.setY(labelAbsPos.getY());
            boundsTmp.setWidth(dimension.width);
            boundsTmp.setHeight(dimension.height);

            this._refreshDiagramSize(boundsTmp);

        }

        //??
        List<Point> tmpList = new ArrayList<Point>();
        tmpList.addAll(linePoints);
        tmpList.add(fromAnchor);
        tmpList.add(toAnchor);
        _refreshDiagramSize(tmpList);

        return groupElement;
    }
}