简体   繁体   中英

How to inject XML representation of vertex into existing mxgraph graph

I am having a problem when injecting a new vertex into an existing mxgraph graph.

I am able to serialize/deserialize the entire graph model using the default codec just fine. However, I would also like to be able to inject individual vertices into an existing graph. A vertex is represented as a JSON array of mxgraph XML strings - the first element being the main vertex and all subsequent elements being the ports.

["<mxCell id=\"47\" style=\"Zerply\" vertex=\"1\" connectable=\"0\" parent=\"1\">
  <Object type=\"component\" label=\"Zerply\" attribute1=\"value1\" as=\"value\"/>
  <mxGeometry x=\"573\" y=\"224\" width=\"150\" height=\"110\" as=\"geometry\"/>
</mxCell>",

"<mxCell id=\"48\" style=\"ZerplyInputLeft\" vertex=\"1\" parent=\"47\">
  <Object type=\"port\" label=\"label 2\" attribute1=\"value1\" as=\"value\"/>
  <mxGeometry y=\"0.5\" width=\"10\" height=\"10\" relative=\"1\" as=\"geometry\">
    <mxPoint x=\"-5\" y=\"-5\" as=\"offset\"/>
  </mxGeometry>
</mxCell>",

"<mxCell id=\"49\" style=\"ZerplyOutputRight\" vertex=\"1\" parent=\"47\">
  <Object type=\"port\" label=\"label 2\" attribute1=\"value1\" as=\"value\"/>
  <mxGeometry x=\"1\" y=\"0.25\" width=\"10\" height=\"10\" relative=\"1\" as=\"geometry\">
    <mxPoint x=\"-5\" y=\"-5\" as=\"offset\"/>
  </mxGeometry>
</mxCell>",

"<mxCell id=\"50\" style=\"ZerplyOutputRight\" vertex=\"1\" parent=\"47\">
  <Object type=\"port\" label=\"label 2\" attribute1=\"value1\" as=\"value\"/>
  <mxGeometry x=\"1\" y=\"0.75\" width=\"10\" height=\"10\" relative=\"1\" as=\"geometry\">
    <mxPoint x=\"-5\" y=\"-5\" as=\"offset\"/>
  </mxGeometry>
</mxCell>"]

And here is some simple code to try to inject the vertex into the graph:

var componentNode;                      
for (var i = 0; i < xmlArray.length; i++) {

    var mxXML = xmlArray[i];
    var xmlDocument = mxUtils.parseXml(mxXML);
    var decoder = new mxCodec(xmlDocument);
    var node = xmlDocument.documentElement;
    var newCell = decoder.decode(node);

    if (i == 0) {
        vertex = graph.insertVertex(root, null, newCell, x, y, 150, 110,
                this.dragElement.id);
        componentNode = vertex;
    } else {
        componentNode.insert(newCell);
    }

    vertex.connectable = 0;
}

This successfully injects the vertex (and its sub-vertices/ports) into the existing graph. The problem arises when we then try to then serialize the new graph – we get an extra child node in the first vertex:

<mxGraphModel>
  <root>
    <mxCell id="0"/>
    <mxCell id="1" parent="0"/>
    <mxCell id="2" style="Zerply" vertex="1" connectable="0">
      <Object type="component" label="Zerply" attribute1="value1" as="value"/>
      <mxGeometry x="573" y="224" width="150" height="110" as="geometry"/>
      **<mxCell style="Zerply" vertex="1" parent="1">
        <mxGeometry x="615" y="252" width="150" height="110" as="geometry"/>
      </mxCell>**
    </mxCell>
    <mxCell id="48" style="ZerplyInputLeft" parent="2" vertex="1">
      <Object type="port" label="label 2" attribute1="value1" as="value"/>
      <mxGeometry y="0.5" width="10" height="10" relative="1" as="geometry">
        <mxPoint x="-5" y="-5" as="offset"/>
      </mxGeometry>
    </mxCell>
    <mxCell id="49" style="ZerplyOutputRight" parent="2" vertex="1">
      <Object type="port" label="label 2" attribute1="value1" as="value"/>
      <mxGeometry x="1" y="0.25" width="10" height="10" relative="1" as="geometry">
        <mxPoint x="-5" y="-5" as="offset"/>
      </mxGeometry>
    </mxCell>
    <mxCell id="50" style="ZerplyOutputRight" parent="2" vertex="1">
      <Object type="port" label="label 2" attribute1="value1" as="value"/>
      <mxGeometry x="1" y="0.75" width="10" height="10" relative="1" as="geometry">
        <mxPoint x="-5" y="-5" as="offset"/>
      </mxGeometry>
    </mxCell>
  </root>
</mxGraphModel>

Am I approaching this wrong?.. or does this appear to be a bug?

Here is my "paste" function that works:

                                // deserialize cells
                                var doc = mxUtils.parseXml(decodeURIComponent(serializedCells));

                                var codec = new mxCodec(doc);

                                var cells = new Array();
                                for (var i = 0; i < doc.documentElement.childNodes.length; i++) {
                                    cells[i] = codec.decodeCell(doc.documentElement.childNodes[i]);
                                }

                                // import cells into the graph
                                var delta = mxClipboard.insertCount * mxClipboard.STEPSIZE;
                                var parent = graph.getDefaultParent();

                                graph.model.beginUpdate();
                                try
                                {
                                  for (var i = 0; i < cells.length; i++)
                                  {
                                    cells[i] = graph.importCells([cells[i]], delta, delta, parent)[0];
                                  }
                                }
                                finally
                                {
                                  graph.model.endUpdate();
                                }

                                // Increments the counter and selects the inserted cells
                                mxClipboard.insertCount++;
                                graph.setSelectionCells(cells);

Ignore the mxClipboard.insertCount, I use it to increment the paste offset when the user hits Paste multiple times.

serializedCells is an HTML-encoded string of XML (serialized from a javascript Array() of mxCell).

Each of my cells has a user object attached to them, which is why I use decodeCell() - this function performs the inversion of the user object xml nodes vs. mxCell nodes.

Then I import each cell using graph.importCells().

I use graph.model.beginUpdate() and .endUpdate() since I allow the "undo" functionality.

setSelectionCells() selects the pasted cells.

function main(container)
{
    // Checks if the browser is supported
    if (!mxClient.isBrowserSupported())
    {
        mxUtils.error('Browser is not supported!', 200, false);
    }
    else
    {
        // Creates the graph inside the DOM node.
        var graph = new mxGraph(container);

        var xml = '<mxGraphModel> <root> <mxCell id="0"/> <mxCell id="1" parent="0"/> <mxCell id="2" value="Start (node0)" style="start" vertex="1" parent="1"> <mxGeometry y="50" width="70" height="70" as="geometry"/> <Object entry_ref="node0" api_type="start" ui_type="start" is_entry_node="0" is_new_node="1" ui_subtype="start" as="custom"> <Object title="START" order="1" as="vals"/></Object> </mxCell> <mxCell id="3" value="" style="label_left" vertex="1" parent="2"> <mxGeometry x="0.2" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="4" value="" style="label_right" vertex="1" parent="2"> <mxGeometry x="0.8" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="5" value="" style="hidden" vertex="1" parent="2"> <mxGeometry x="0.2" width="10" height="10" relative="1" as="geometry"/> </mxCell> <mxCell id="6" value="" style="hidden" vertex="1" parent="2"> <mxGeometry x="0.92" y="-0.1" width="16" height="16" relative="1" as="geometry"/> </mxCell> <mxCell id="7" value="s1 (node1)" style="step_choices" vertex="1" parent="1"> <mxGeometry x="170" y="50" width="110" height="70" as="geometry"/> <Object entry_ref="node1" api_type="decision" ui_type="step" is_entry_node="1" is_new_node="1" ui_subtype="step_choices" as="custom"> <Object title="s1" body="" order="1" as="vals"/></Object> </mxCell> <mxCell id="8" value="" style="label_left" vertex="1" parent="7"> <mxGeometry x="0.2" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="9" value="" style="label_right" vertex="1" parent="7"> <mxGeometry x="0.8" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="10" value="" style="hidden" vertex="1" parent="7"> <mxGeometry x="0.2" width="10" height="10" relative="1" as="geometry"/> </mxCell> <mxCell id="11" value="" style="hidden" vertex="1" parent="7"> <mxGeometry x="0.92" y="-0.1" width="16" height="16" relative="1" as="geometry"/> </mxCell> <mxCell id="12" value="" style="noEdgeStyle=1;orthogonal=1" edge="1" parent="1" source="2" target="7"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="82" y="85"/> <mxPoint x="158" y="85"/> </Array> </mxGeometry> </mxCell> <mxCell id="13" value="c1 (node2)" style="choice" vertex="1" parent="1"> <mxGeometry x="380" width="110" height="70" as="geometry"/> <Object entry_ref="node2" head_ref="node7" api_type="link" ui_type="choice" is_entry_node="0" is_new_node="1" ui_subtype="choice" as="custom"> <Object body="c1" order="1" as="vals"/></Object> </mxCell> <mxCell id="14" value="" style="label_left" vertex="1" parent="13"> <mxGeometry x="0.2" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="15" value="" style="label_right" vertex="1" parent="13"> <mxGeometry x="0.8" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="16" value="" style="hidden" vertex="1" parent="13"> <mxGeometry x="0.2" width="10" height="10" relative="1" as="geometry"/> </mxCell> <mxCell id="17" value="1" style="label_index" vertex="1" parent="13"> <mxGeometry x="0.92" y="-0.1" width="16" height="16" relative="1" as="geometry"/> </mxCell> <mxCell id="18" value="" style="noEdgeStyle=1;orthogonal=1" edge="1" parent="1" source="7" target="13"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="292" y="70"/> <mxPoint x="368" y="35"/> </Array> </mxGeometry> </mxCell> <mxCell id="19" value="s2 (node3)" style="step_choices" vertex="1" parent="1"> <mxGeometry x="590" y="65" width="110" height="70" as="geometry"/> <Object entry_ref="node3" api_type="decision" ui_type="step" is_entry_node="0" is_new_node="1" ui_subtype="step_choices" as="custom"> <Object title="s2" body="" order="1" as="vals"/></Object> </mxCell> <mxCell id="20" value="" style="label_left" vertex="1" parent="19"> <mxGeometry x="0.2" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="21" value="" style="label_right" vertex="1" parent="19"> <mxGeometry x="0.8" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="22" value="" style="hidden" vertex="1" parent="19"> <mxGeometry x="0.2" width="10" height="10" relative="1" as="geometry"/> </mxCell> <mxCell id="23" value="" style="hidden" vertex="1" parent="19"> <mxGeometry x="0.92" y="-0.1" width="16" height="16" relative="1" as="geometry"/> </mxCell> <mxCell id="31" value="s3 (node5)" style="step_choices" vertex="1" parent="1"> <mxGeometry x="1010" y="15" width="110" height="70" as="geometry"/> <Object entry_ref="node5" api_type="decision" ui_type="step" is_entry_node="0" is_new_node="1" ui_subtype="step_choices" as="custom"> <Object title="s3" body="" order="1" as="vals"/></Object> </mxCell> <mxCell id="32" value="" style="label_left" vertex="1" parent="31"> <mxGeometry x="0.2" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="33" value="" style="label_right" vertex="1" parent="31"> <mxGeometry x="0.8" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="34" value="" style="hidden" vertex="1" parent="31"> <mxGeometry x="0.2" width="10" height="10" relative="1" as="geometry"/> </mxCell> <mxCell id="35" value="" style="hidden" vertex="1" parent="31"> <mxGeometry x="0.92" y="-0.1" width="16" height="16" relative="1" as="geometry"/> </mxCell> <mxCell id="43" value="re1 (node7)" style="redirect" vertex="1" parent="1"> <mxGeometry x="590" y="50" width="110" height="70" as="geometry"/> <Object entry_ref="node7" api_type="decision" ui_type="step" is_entry_node="0" is_new_node="1" ui_subtype="redirect" as="custom"> <Object endNodeData="http://re1" title="re1" order="1" as="vals"/></Object> </mxCell> <mxCell id="44" value="" style="label_left" vertex="1" parent="43"> <mxGeometry x="0.2" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="45" value="" style="label_right" vertex="1" parent="43"> <mxGeometry x="0.8" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="46" value="" style="hidden" vertex="1" parent="43"> <mxGeometry x="0.2" width="10" height="10" relative="1" as="geometry"/> </mxCell> <mxCell id="47" value="" style="hidden" vertex="1" parent="43"> <mxGeometry x="0.92" y="-0.1" width="16" height="16" relative="1" as="geometry"/> </mxCell> <mxCell id="56" value="c5 (node9)" style="choice" vertex="1" parent="1"> <mxGeometry x="800" width="110" height="70" as="geometry"/> <Object entry_ref="node9" head_ref="node5" api_type="link" ui_type="choice" is_entry_node="0" is_new_node="1" ui_subtype="choice" as="custom"> <Object body="c5" order="1" as="vals"/></Object> </mxCell> <mxCell id="57" value="" style="label_left" vertex="1" parent="56"> <mxGeometry x="0.2" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="58" value="" style="label_right" vertex="1" parent="56"> <mxGeometry x="0.8" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="59" value="" style="hidden" vertex="1" parent="56"> <mxGeometry x="0.2" width="10" height="10" relative="1" as="geometry"/> </mxCell> <mxCell id="60" value="1" style="label_index" vertex="1" parent="56"> <mxGeometry x="0.92" y="-0.1" width="16" height="16" relative="1" as="geometry"/> </mxCell> <mxCell id="61" value="" style="noEdgeStyle=1;orthogonal=1" edge="1" parent="1" source="19" target="56"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="712" y="80"/> <mxPoint x="788" y="35"/> </Array> </mxGeometry> </mxCell> <mxCell id="62" value="" style="noEdgeStyle=1;orthogonal=1" edge="1" parent="1" source="56" target="31"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="922" y="35"/> <mxPoint x="998" y="50"/> </Array> </mxGeometry> </mxCell> <mxCell id="63" value="c4 (node10)" style="choice" vertex="1" parent="1"> <mxGeometry x="380" y="100" width="110" height="70" as="geometry"/> <Object entry_ref="node10" head_ref="node7" api_type="link" ui_type="choice" is_entry_node="0" is_new_node="1" ui_subtype="choice" as="custom"> <Object body="c4" order="2" as="vals"/></Object> </mxCell> <mxCell id="64" value="" style="label_left" vertex="1" parent="63"> <mxGeometry x="0.2" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="65" value="" style="label_right" vertex="1" parent="63"> <mxGeometry x="0.8" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="66" value="" style="hidden" vertex="1" parent="63"> <mxGeometry x="0.2" width="10" height="10" relative="1" as="geometry"/> </mxCell> <mxCell id="67" value="2" style="label_index" vertex="1" parent="63"> <mxGeometry x="0.92" y="-0.1" width="16" height="16" relative="1" as="geometry"/> </mxCell> <mxCell id="68" value="" style="noEdgeStyle=1;orthogonal=1" edge="1" parent="1" source="7" target="63"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="292" y="100"/> <mxPoint x="368" y="135"/> </Array> </mxGeometry> </mxCell> <mxCell id="69" value="c2 (node11)" style="choice" vertex="1" parent="1"> <mxGeometry x="800" y="100" width="110" height="70" as="geometry"/> <Object entry_ref="node11" head_ref="node7" api_type="link" ui_type="choice" is_entry_node="0" is_new_node="1" ui_subtype="choice" as="custom"> <Object body="c2" order="2" as="vals"/></Object> </mxCell> <mxCell id="70" value="" style="label_left" vertex="1" parent="69"> <mxGeometry x="0.2" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="71" value="" style="label_right" vertex="1" parent="69"> <mxGeometry x="0.8" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="72" value="" style="hidden" vertex="1" parent="69"> <mxGeometry x="0.2" width="10" height="10" relative="1" as="geometry"/> </mxCell> <mxCell id="73" value="2" style="label_index" vertex="1" parent="69"> <mxGeometry x="0.92" y="-0.1" width="16" height="16" relative="1" as="geometry"/> </mxCell> <mxCell id="74" value="" style="noEdgeStyle=1;orthogonal=1" edge="1" parent="1" source="19" target="69"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="714" y="100"/> <mxPoint x="788" y="135"/> </Array> </mxGeometry> </mxCell> <mxCell id="75" value="" style="noEdgeStyle=1;orthogonal=1" edge="1" parent="1" source="63" target="43"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="502" y="135"/> <mxPoint x="578" y="100"/> </Array> </mxGeometry> </mxCell> <mxCell id="76" value="" style="noEdgeStyle=1;orthogonal=1" edge="1" parent="1" source="69" target="43"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="922" y="135"/> <mxPoint x="998" y="135"/> </Array> </mxGeometry> </mxCell> <mxCell id="77" value="c3 (node12)" style="choice" vertex="1" parent="1"> <mxGeometry x="1220" y="97.5" width="110" height="70" as="geometry"/> <Object entry_ref="node12" head_ref="node3" api_type="link" ui_type="choice" is_entry_node="0" is_new_node="1" ui_subtype="choice" as="custom"> <Object body="c3" order="1" as="vals"/></Object> </mxCell> <mxCell id="78" value="" style="label_left" vertex="1" parent="77"> <mxGeometry x="0.2" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="79" value="" style="label_right" vertex="1" parent="77"> <mxGeometry x="0.8" y="1.15" relative="1" as="geometry"/> </mxCell> <mxCell id="80" value="" style="hidden" vertex="1" parent="77"> <mxGeometry x="0.2" width="10" height="10" relative="1" as="geometry"/> </mxCell> <mxCell id="81" value="1" style="label_index" vertex="1" parent="77"> <mxGeometry x="0.92" y="-0.1" width="16" height="16" relative="1" as="geometry"/> </mxCell> <mxCell id="82" value="" style="noEdgeStyle=1;orthogonal=1" edge="1" parent="1" source="31" target="77"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="1132" y="50"/> <mxPoint x="1208" y="117.5"/> </Array> </mxGeometry> </mxCell> <mxCell id="83" value="" style="noEdgeStyle=1;orthogonal=1" edge="1" parent="1" source="77" target="19"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="1208" y="147.5"/> <mxPoint x="1170" y="215"/> <mxPoint x="960" y="215"/> <mxPoint x="960" y="200"/> <mxPoint x="750" y="200"/> <mxPoint x="712" y="120"/> </Array> </mxGeometry> </mxCell> <mxCell id="84" value="" style="noEdgeStyle=1;orthogonal=1" edge="1" parent="1" source="13" target="43"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="502" y="35"/> <mxPoint x="578" y="70"/> </Array> </mxGeometry> </mxCell> </root> </mxGraphModel>';
        var doc = mxUtils.parseXml(xml);
        var codec = new mxCodec(doc);
        codec.decode(doc.documentElement, graph.getModel());

        // Changes the default style for vertices "in-place"
        // to use the custom shape.
        var style = graph.getStylesheet().getDefaultVertexStyle();
        var edgeStyle = graph.getStylesheet().getDefaultEdgeStyle();


        // Adds a gradient and shadow to improve the user experience
        style[mxConstants.STYLE_GRADIENTCOLOR] = '#FFFFFF';
        style[mxConstants.STYLE_SHADOW] = true;
        edgeStyle[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = 'white';

        // Gets the default parent for inserting new cells. This
        // is normally the first child of the root (ie. layer 0).
        var parent = graph.getDefaultParent();

        // Adds cells to the model in a single step
        graph.getModel().beginUpdate();
        try
        {
            var layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_WEST, true);
            //layout.maintainParentLocation = true;
            layout.execute(parent);

        }
        finally
        {
            // Updates the display
            graph.getModel().endUpdate();
        }
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM