Why can link be disorganized after modifying a display property of link

After modification

setup code

if (self.diagram && self.palette) {
            return;
        }
        var gojs = go.GraphObject.make;
        var diagram =
          gojs(go.Diagram, "canvas",
            {
                initialContentAlignment: go.Spot.Center,
                allowDrop: true,
                "LinkDrawn": self.showLinkLabel,
                "LinkRelinked": self.showLinkLabel,
                "animationManager.duration": 800,
                "undoManager.isEnabled": true
            });
        diagram.addDiagramListener("Modified", function (e) {
            var idx = document.title.indexOf("*");
            if (diagram.isModified) {
                if (idx < 0) document.title += "*";
                $('#btn_store_process').show();
            } else {
                if (idx >= 0) document.title = document.title.substr(0, idx);
                $('#btn_store_process').hide();
            }
        });
        // var lightText = 'whitesmoke';
        diagram.nodeTemplateMap.add("start",
              gojs(go.Node, "Spot", { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),

                gojs(go.Picture,
                    { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/start.png' },
                    new go.Binding("minSize", "minSize"),
                    new go.Binding("source", "src", function (icon) {
                        return openinfo.root + 'components/gojs/icon/' + icon;
                    })),
                // gojs(go.TextBlock, "start",
                //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),

                self.makePort("T", go.Spot.Top, true, false),
                self.makePort("L", go.Spot.Left, true, false),
                self.makePort("R", go.Spot.Right, true, false),
                self.makePort("B", go.Spot.Bottom, true, false)
              ));
        diagram.nodeTemplateMap.add("end",
              gojs(go.Node, "Spot", { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),
                gojs(go.Picture,
                    { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/end.png' },
                    new go.Binding("minSize", "minSize")),
                // gojs(go.TextBlock, "end",
                //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),

                self.makePort("T", go.Spot.Top, false, true),
                self.makePort("L", go.Spot.Left, false, true),
                self.makePort("R", go.Spot.Right, false, true),
                self.makePort("B", go.Spot.Bottom, false, true)
              ));
        diagram.nodeTemplateMap.add("task",
              gojs(go.Node, "Vertical", { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),
            gojs(go.Panel, "Spot",
                gojs(go.Picture,
                    { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/task.png' },
                    new go.Binding("minSize", "minSize"),
                    new go.Binding("source", "src", function (icon) {
                        return openinfo.root + 'components/gojs/icon/' + icon;
                    })),
                // gojs(go.TextBlock, "task",
                //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),
                self.makePort("T", go.Spot.Top, true, true),
                self.makePort("L", go.Spot.Left, true, true),
                self.makePort("R", go.Spot.Right, true, true),
                self.makePort("B", go.Spot.Bottom, true, true)
             ),
             gojs(go.TextBlock,
                new go.Binding("text", "name"))
               ));


        diagram.nodeTemplateMap.add("event",
              gojs(go.Node, "Spot", { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),
                gojs(go.Picture,
                    { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/event.png' },
                    new go.Binding("minSize", "minSize")),
                // gojs(go.TextBlock, "event",
                //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),

                self.makePort("T", go.Spot.Top, true, true),
                self.makePort("L", go.Spot.Left, true, true),
                self.makePort("R", go.Spot.Right, true, true),
                self.makePort("B", go.Spot.Bottom, true, true)

              ));
        diagram.nodeTemplateMap.add("gateway",
              gojs(go.Node, "Spot", { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),
                gojs(go.Picture,
                    { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/gateway.png' },
                    new go.Binding("minSize", "minSize")),
                // gojs(go.TextBlock, "gateway",
                //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),

                self.makePort("T", go.Spot.Top, true, true),
                self.makePort("L", go.Spot.Left, true, true),
                self.makePort("R", go.Spot.Right, true, true),
                self.makePort("B", go.Spot.Bottom, true, true)
              ));
        diagram.nodeTemplateMap.add("gather",
              gojs(go.Node, "Spot", { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),
                gojs(go.Picture,
                    { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/gather.png' },
                    new go.Binding("minSize", "minSize")),
                // gojs(go.TextBlock, "gather",
                //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),

                self.makePort("T", go.Spot.Top, true, true),
                self.makePort("L", go.Spot.Left, true, true),
                self.makePort("R", go.Spot.Right, true, true),
                self.makePort("B", go.Spot.Bottom, true, true)

              ));
        diagram.linkTemplate =
          gojs(go.Link, 
            {
                routing: go.Link.AvoidsNodes,
                curve: go.Link.JumpOver,
                corner: 5,
                toShortLength: 4,
                relinkableFrom: true,
                relinkableTo: true,
                reshapable: true,
                resegmentable: true,
                contextMenu: gojs(go.Adornment),
           
            },
            new go.Binding("points").makeTwoWay(),
            gojs(go.Shape,
              { isPanelMain: true, strokeWidth: 8, stroke: "transparent", name: "HIGHLIGHT" }),
            gojs(go.Shape,
              { isPanelMain: true, stroke: "gray", strokeWidth: 2 }),
            gojs(go.Shape,
              { toArrow: "standard", stroke: null, fill: "gray" }),
            gojs(go.Panel, "Auto",
              { visible: false, name: "LABEL", segmentIndex: 2, segmentFraction: 0.5 },
              new go.Binding("visible", "visible").makeTwoWay(),
              gojs(go.Shape, "RoundedRectangle",
                { fill: "#F8F8F8", stroke: null }),
              gojs(go.TextBlock, 
                {
                    textAlign: "center",
                    font: "10pt helvetica, arial, sans-serif",
                    stroke: "#333333",
                    editable: true
                },
                new go.Binding("text").makeTwoWay())
            )
          );

        diagram.toolManager.linkingTool.temporaryLink.routing = go.Link.Orthogonal;
        diagram.toolManager.relinkingTool.temporaryLink.routing = go.Link.Orthogonal;

        var palette =
              gojs(go.Palette, "canvas_ele",
                {
                    "animationManager.duration": 800,
                    nodeTemplateMap: diagram.nodeTemplateMap,
                    model: new go.GraphLinksModel([
                      { category: "start", minSize: new go.Size(40, 40) },
                      { category: "end", minSize: new go.Size(40, 40) },
                      { category: "task", minSize: new go.Size(40, 40) },
                      { category: "event", minSize: new go.Size(40, 40) },
                      { category: "gateway", minSize: new go.Size(40, 40) },
                      { category: "gather", minSize: new go.Size(40, 40) }
                    ])
                });

        diagram.model.linkFromPortIdProperty = "fromPort";
        diagram.model.linkToPortIdProperty = "toPort";

        diagram.addDiagramListener('LinkDrawn', function (e) {
            self.linkDrawn(e);
        });

        diagram.addDiagramListener('ExternalObjectsDropped', function (e) {
            self.externalObjectsDropped(e);
        });

        // 右键菜单
        // Override the ContextMenuTool.showContextMenu and hideContextMenu methods
        // in order to modify the HTML appropriately.
        var cxTool = diagram.toolManager.contextMenuTool;
        var cxElement = document.getElementById("canvas_context");
        cxElement.addEventListener("contextmenu", function (e) {
            e.preventDefault();
            return false;
        }, false);
        cxElement.addEventListener("blur", function (e) {
            cxTool.stopTool();
            // maybe start another context menu
            if (cxTool.canStart()) {
                diagram.currentTool = cxTool;
                cxTool.doMouseUp();
            }
        }, false);
        cxElement.tabIndex = "1";
        // This is the override of ContextMenuTool.showContextMenu:
        // This does not not need to call the base method.
        cxTool.showContextMenu = function (contextmenu, obj) {
            var _diagram = this.diagram;
            if (_diagram === null) return;
            // Hide any other existing context menu
            if (contextmenu !== this.currentContextMenu) {
                this.hideContextMenu();
            }
            var ele = [];
            var link = [];
            _diagram.selection.filter(function (_ele) {
                if (_ele.data.category) {
                    ele.push(_ele);
                }
                else {
                    link.push(_ele);
                }
                return ele;
            });
            var display = true;
            if (ele.length == 1 && link.length == 0) {
                $('#align').css({ 'display': 'none' });
                $('#vertical_align').css({ 'display': 'none' });
                $('#attribute').css({ 'display': 'block' });
            }
            else if (ele.length > 1 && link.length == 0) {
                $('#align').css({ 'display': 'block' });
                $('#vertical_align').css({ 'display': 'block' });
                $('#attribute').css({ 'display': 'none' });
            }
            else if (ele.length == 0 && link.length == 1) {
                $('#align').css({ 'display': 'none' });
                $('#vertical_align').css({ 'display': 'none' });
                $('#attribute').css({ 'display': 'block' });
            }
            else {
                display = false;
            }
            if (display) {
                // Now show the whole context menu element
                cxElement.style.display = "block";
            }
            // we don't bother overriding positionContextMenu, we just do it here:
            var mousePt = _diagram.lastInput.viewPoint;
            cxElement.style.left = mousePt.x - 470 + "px";
            cxElement.style.top = mousePt.y - 40 + "px";
            // Remember that there is now a context menu showing
            this.currentContextMenu = contextmenu;

        }
        // This is the corresponding override of ContextMenuTool.hideContextMenu:
        // This does not not need to call the base method.
        cxTool.hideContextMenu = function () {
            if (this.currentContextMenu === null) return;
            cxElement.style.display = "none";
            this.currentContextMenu = null;
           
        }

        // 变量
        self.diagram = diagram;
        self.palette = palette;
        self.diagram.attr = {
            start: {
                linkCount: { from: 1000, to: 0 },
                totalCount: 1
            },
            end: {
                linkCount: { from: 0, to: 1000 },
                totalCount: 1000
            },
            task: {
                linkCount: { from: 1000, to: 1000 },
                totalCount: 1000
            },
            event: {
                linkCount: { from: 0, to: 1 },
                totalCount: 1000
            },
            gateway: {
                linkCount: { from: 1000, to: 1 },
                totalCount: 1000
            },
            gather: {
                linkCount: { from: 1, to: 1000 },
                totalCount: 1000
            }
        };
        self.diagram.title = {
            start: "开始",
            end: "结束",
            task: "任务",
            event: "事件",
            gateway: "网关",
            gather: "聚合"
        };

Modify the code

  var action = $('.sel_task_link_type').val();
        var attribute = {
            fromAction: action
        };
        var ele = self.diagram.selection.first();
        ele.data.visible = true;
        ele.data.text = $('.sel_task_link_type').val() == "同意" ? "Yes" : "No";
        ele.data.attribute = attribute;
        self.diagram.model.updateTargetBindings(ele.data);
        self.current_link = undefined;
        self.store_process();
        $('#dv_task_link_dialog').modal('hide');

Why can link be disorganized after modifying a display property of link????

That’s a lot of code to look through. Yet the relevant code appears to be missing – what does store_process() do? But I didn’t see anything that would cause that odd behavior.

I hope you realize that by calling Model.updateTargetBindings and by not calling Model.set (a.k.a. Model.setDataProperty), you are giving up the ability to properly perform Undo and Redo. Perhaps that does not matter to you.

Defining time value:

{ “class”: “go.GraphLinksModel”,
“linkFromPortIdProperty”: “fromPort”,
“linkToPortIdProperty”: “toPort”,
“nodeDataArray”: [
{“category”:“start”, “minSize”:{“class”:“go.Size”, “width”:40, “height”:40}, “key”:-1, “loc”:"-410.9999999999997 -486.0000000000002", “type”:“10”, “attribute”:{“Msg”:"", “OnTimeType”:"", “Value”:""}, “src”:“start.png”},
{“category”:“end”, “minSize”:{“class”:“go.Size”, “width”:40, “height”:40}, “key”:-2, “loc”:"-17.000000000000124 -555.0000000000002"},
{“category”:“task”, “minSize”:{“class”:“go.Size”, “width”:40, “height”:40}, “key”:-3, “loc”:"-240.00000000000023 -399.00000000000057", “person”:[], “attribute”:{“Type”:“20”, “SetNextExcutor”:“0”, “Action”:[ “同意”,“不同意” ], “Name”:“12”}, “src”:“taskoneperson.png”, “name”:“12”}
],
“linkDataArray”: [
{“from”:-3, “to”:-2, “fromPort”:“R”, “toPort”:“L”, “points”:[-220.0000000000001,-407.25607910156305,-210.0000000000001,-407.25607910156305,-128.5000000000001,-407.25607910156305,-128.5000000000001,-563.2560791015627,-47.00000000000013,-563.2560791015627,-37.00000000000013,-563.2560791015627], “visible”:true, “text”:“No”, “attribute”:{“fromAction”:“不同意”}},
{“from”:-1, “to”:-3, “fromPort”:“R”, “toPort”:“L”, “points”:[-390.9999999999997,-494.2560791015627,-380.9999999999997,-494.2560791015627,-325.4999999999999,-494.2560791015627,-325.4999999999999,-407.25607910156305,-270.0000000000001,-407.25607910156305,-260.0000000000001,-407.25607910156305]},
{“from”:-3, “to”:-2, “fromPort”:“T”, “toPort”:“T”, “points”:[-240.0000000000001,-427.25607910156305,-240.0000000000001,-437.25607910156305,-240.0000000000001,-593.2560791015627,-128.5000000000001,-593.2560791015627,-17.000000000000128,-593.2560791015627,-17.000000000000128,-583.2560791015627], “visible”:true, “text”:“No”, “attribute”:{“fromAction”:“不同意”}}
]}

After triggering the right key menu, the value is:

{ “class”: “go.GraphLinksModel”,
“linkFromPortIdProperty”: “fromPort”,
“linkToPortIdProperty”: “toPort”,
“nodeDataArray”: [
{“category”:“start”, “minSize”:{“class”:“go.Size”, “width”:40, “height”:40}, “key”:-1, “loc”:"-410.9999999999997 -486.0000000000002", “type”:“10”, “attribute”:{“Msg”:"", “OnTimeType”:"", “Value”:""}, “src”:“start.png”},
{“category”:“end”, “minSize”:{“class”:“go.Size”, “width”:40, “height”:40}, “key”:-2, “loc”:"-17.000000000000124 -555.0000000000002"},
{“category”:“task”, “minSize”:{“class”:“go.Size”, “width”:40, “height”:40}, “key”:-3, “loc”:"-240.00000000000023 -399.00000000000057", “person”:[], “attribute”:{“Type”:“20”, “SetNextExcutor”:“0”, “Action”:[ “同意”,“不同意” ], “Name”:“12”}, “src”:“taskoneperson.png”, “name”:“12”}
],
“linkDataArray”: [
{“from”:-3, “to”:-2, “fromPort”:“R”, “toPort”:“L”, “points”:[40,19.99999999999998,50,19.99999999999998,50,64.512158203125,-10,64.512158203125,-10,20,0,20], “visible”:true, “text”:“No”, “attribute”:{“fromAction”:“不同意”}},
{“from”:-1, “to”:-3, “fromPort”:“R”, “toPort”:“L”, “points”:[40,20,50,20,50,-8.000000000000021,-10,-8.000000000000021,-10,19.99999999999998,0,19.99999999999998]},
{“from”:-3, “to”:-2, “fromPort”:“T”, “toPort”:“T”, “points”:[20,-2.1316282072803006e-14,20,-10.000000000000021,20,-10.000000000000021,20,-10.00000000000001,20,-10,20,0], “visible”:true, “text”:“No”, “attribute”:{“fromAction”:“不同意”}}
]}

Is the result of this reason, whether I configure the problem?

var gojs = go.GraphObject.make;
var diagram =
gojs(go.Diagram, “canvas”,
{
initialContentAlignment: go.Spot.Center,
allowDrop: true,
“LinkDrawn”: self.showLinkLabel,
“LinkRelinked”: self.showLinkLabel,
“animationManager.duration”: 800,
“undoManager.isEnabled”: true
});
diagram.addDiagramListener(“Modified”, function (e) {
var idx = document.title.indexOf("");
if (diagram.isModified) {
if (idx < 0) document.title += "
";
$(’#btn_store_process’).show();
} else {
if (idx >= 0) document.title = document.title.substr(0, idx);
$(’#btn_store_process’).hide();
}
});
// var lightText = ‘whitesmoke’;
diagram.nodeTemplateMap.add(“start”,
gojs(go.Node, “Spot”, { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),

            gojs(go.Picture,
                { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/start.png' },
                new go.Binding("minSize", "minSize"),
                new go.Binding("source", "src", function (icon) {
                    return openinfo.root + 'components/gojs/icon/' + icon;
                })),
            // gojs(go.TextBlock, "start",
            //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),
              gojs(go.TextBlock,
               { alignment: go.Spot.Bottom, alignmentFocus: go.Spot.Top },
                    new go.Binding("   ")),
            self.makePort("T", go.Spot.Top, true, false),
            self.makePort("L", go.Spot.Left, true, false),
            self.makePort("R", go.Spot.Right, true, false),
            self.makePort("B", go.Spot.Bottom, true, false)
          ));
    diagram.nodeTemplateMap.add("end",
          gojs(go.Node, "Spot", { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),
            gojs(go.Picture,
                { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/end.png' },
                new go.Binding("minSize", "minSize")),
            // gojs(go.TextBlock, "end",
            //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),
             gojs(go.TextBlock,
               { alignment: go.Spot.Bottom, alignmentFocus: go.Spot.Top },
                    new go.Binding("   ")),
            self.makePort("T", go.Spot.Top, false, true),
            self.makePort("L", go.Spot.Left, false, true),
            self.makePort("R", go.Spot.Right, false, true),
            self.makePort("B", go.Spot.Bottom, false, true)
          ));
    diagram.nodeTemplateMap.add("task",
          gojs(go.Node, "Spot", { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),
            gojs(go.Picture,
                { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/task.png' },
                new go.Binding("minSize", "minSize"),
                new go.Binding("source", "src", function (icon) {
                    return openinfo.root + 'components/gojs/icon/' + icon;
                })),
            // gojs(go.TextBlock, "task",
            //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),
            gojs(go.TextBlock,
               { alignment: go.Spot.Bottom, alignmentFocus: go.Spot.Top },
                    new go.Binding("text", "name")),
      
            self.makePort("T", go.Spot.Top, true, true),
            self.makePort("L", go.Spot.Left, true, true),
            self.makePort("R", go.Spot.Right, true, true),
            self.makePort("B", go.Spot.Bottom, true, true)

           ));
    diagram.nodeTemplateMap.add("event",
          gojs(go.Node, "Spot", { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),
            gojs(go.Picture,
                { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/event.png' },
                new go.Binding("minSize", "minSize")),
            // gojs(go.TextBlock, "event",
            //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),
              gojs(go.TextBlock,
               { alignment: go.Spot.Bottom, alignmentFocus: go.Spot.Top },
                    new go.Binding("   ")),
            self.makePort("T", go.Spot.Top, true, true),
            self.makePort("L", go.Spot.Left, true, true),
            self.makePort("R", go.Spot.Right, true, true),
            self.makePort("B", go.Spot.Bottom, true, true)

          ));
    diagram.nodeTemplateMap.add("gateway",
          gojs(go.Node, "Spot", { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),
            gojs(go.Picture,
                { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/gateway.png' },
                new go.Binding("minSize", "minSize")),
            // gojs(go.TextBlock, "gateway",
            //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),
              gojs(go.TextBlock,
               { alignment: go.Spot.Bottom, alignmentFocus: go.Spot.Top },
                    new go.Binding("   ")),
            self.makePort("T", go.Spot.Top, true, true),
            self.makePort("L", go.Spot.Left, true, true),
            self.makePort("R", go.Spot.Right, true, true),
            self.makePort("B", go.Spot.Bottom, true, true)
          ));
    diagram.nodeTemplateMap.add("gather",
          gojs(go.Node, "Spot", { contextMenu: gojs(go.Adornment) }, self.nodeStyle(),
            gojs(go.Picture,
                { minSize: new go.Size(40, 40), source: openinfo.root + 'components/gojs/icon/gather.png' },
                new go.Binding("minSize", "minSize")),
            // gojs(go.TextBlock, "gather",
            //     { font: "bold 11pt Helvetica, Arial, sans-serif", stroke: lightText }),
              gojs(go.TextBlock,
               { alignment: go.Spot.Bottom, alignmentFocus: go.Spot.Top },
                    new go.Binding("   ")),
            self.makePort("T", go.Spot.Top, true, true),
            self.makePort("L", go.Spot.Left, true, true),
            self.makePort("R", go.Spot.Right, true, true),
            self.makePort("B", go.Spot.Bottom, true, true)

          ));
    diagram.linkTemplate =
      gojs(go.Link,
        {
            routing: go.Link.AvoidsNodes,
            curve: go.Link.JumpOver,
            corner: 5,
            toShortLength: 4,
            relinkableFrom: true,
            relinkableTo: true,
            reshapable: true,
            resegmentable: true,
            contextMenu: gojs(go.Adornment),
            mouseEnter: function (e, link) { link.findObject("HIGHLIGHT").stroke = "rgba(30,144,255,0.2)"; },
            mouseLeave: function (e, link) { link.findObject("HIGHLIGHT").stroke = "transparent"; }
        },
        new go.Binding("points").makeTwoWay(),
        gojs(go.Shape,
          { isPanelMain: true, strokeWidth: 8, stroke: "transparent", name: "HIGHLIGHT" }),
        gojs(go.Shape,
          { isPanelMain: true, stroke: "gray", strokeWidth: 2 }),
        gojs(go.Shape,
          { toArrow: "standard", stroke: null, fill: "gray" }),
        gojs(go.Panel, "Auto",
          { visible: false, name: "LABEL", segmentIndex: 2, segmentFraction: 0.5 },
          new go.Binding("visible", "visible").makeTwoWay(),
          gojs(go.Shape, "RoundedRectangle",
            { fill: "#F8F8F8", stroke: null }),
          gojs(go.TextBlock, 
            {
                textAlign: "center",
                font: "10pt helvetica, arial, sans-serif",
                stroke: "#333333",
                editable: true
            },
            new go.Binding("text", "text"))
        )
      );

    diagram.toolManager.linkingTool.temporaryLink.routing = go.Link.Orthogonal;
    diagram.toolManager.relinkingTool.temporaryLink.routing = go.Link.Orthogonal;

    var palette =
          gojs(go.Palette, "canvas_ele",
            {
                "animationManager.duration": 800,
                nodeTemplateMap: diagram.nodeTemplateMap,
                model: new go.GraphLinksModel([
                  { category: "start", minSize: new go.Size(40, 40) },
                  { category: "end", minSize: new go.Size(40, 40) },
                  { category: "task", minSize: new go.Size(40, 40) },
                  { category: "event", minSize: new go.Size(40, 40) },
                  { category: "gateway", minSize: new go.Size(40, 40) },
                  { category: "gather", minSize: new go.Size(40, 40) }
                ])
            });

    diagram.model.linkFromPortIdProperty = "fromPort";
    diagram.model.linkToPortIdProperty = "toPort";

    diagram.addDiagramListener('LinkDrawn', function (e) {
        self.linkDrawn(e);
    });

    diagram.addDiagramListener('ExternalObjectsDropped', function (e) {
        self.externalObjectsDropped(e);
    });
  
    // 右键菜单
    // Override the ContextMenuTool.showContextMenu and hideContextMenu methods
    // in order to modify the HTML appropriately.
    var cxTool = diagram.toolManager.contextMenuTool;
    var cxElement = document.getElementById("canvas_context");
    cxElement.addEventListener("contextmenu", function (e) {
        e.preventDefault();
        return false;
    }, false);
    cxElement.addEventListener("blur", function (e) {
        cxTool.stopTool();
        // maybe start another context menu
        if (cxTool.canStart()) {
            diagram.currentTool = cxTool;
            cxTool.doMouseUp();
        }
    }, false);
    cxElement.tabIndex = "1";
    // This is the override of ContextMenuTool.showContextMenu:
    // This does not not need to call the base method.
    cxTool.showContextMenu = function (contextmenu, obj) {
     
        console.log(self.diagram.model.toJSON())
        var _diagram = this.diagram;
        if (_diagram === null) return;
        // Hide any other existing context menu
        if (contextmenu !== this.currentContextMenu) {
            this.hideContextMenu();
        }
        var ele = [];
        var link = [];
        _diagram.selection.filter(function (_ele) {
            if (_ele.data.category) {
                ele.push(_ele);
            }
            else {
                link.push(_ele);
            }
            return ele;
        });
        var display = true;
        if (ele.length == 1 && link.length == 0) {
            $('#align').css({ 'display': 'none' });
            $('#vertical_align').css({ 'display': 'none' });
            $('#attribute').css({ 'display': 'block' });
        }
        else if (ele.length > 1 && link.length == 0) {
            $('#align').css({ 'display': 'block' });
            $('#vertical_align').css({ 'display': 'block' });
            $('#attribute').css({ 'display': 'none' });
        }
        else if (ele.length == 0 && link.length == 1) {
            $('#align').css({ 'display': 'none' });
            $('#vertical_align').css({ 'display': 'none' });
            $('#attribute').css({ 'display': 'block' });
        }
        else {
            display = false;
        }
        if (display) {
            // Now show the whole context menu element
            cxElement.style.display = "block";
        }
        // we don't bother overriding positionContextMenu, we just do it here:
        var mousePt = _diagram.lastInput.viewPoint;
        cxElement.style.left = mousePt.x - 470 + "px";
        cxElement.style.top = mousePt.y - 40 + "px";
        // Remember that there is now a context menu showing
        this.currentContextMenu = contextmenu;

    }
    // This is the corresponding override of ContextMenuTool.hideContextMenu:
    // This does not not need to call the base method.
    cxTool.hideContextMenu = function () {
        if (this.currentContextMenu === null) return;
        cxElement.style.display = "none";
        this.currentContextMenu = null;
    }

    // 变量
    self.diagram = diagram;
    self.palette = palette;
    self.diagram.attr = {
        start: {
            linkCount: { from: 1000, to: 0 },
            totalCount: 1
        },
        end: {
            linkCount: { from: 0, to: 1000 },
            totalCount: 1000
        },
        task: {
            linkCount: { from: 1000, to: 1000 },
            totalCount: 1000
        },
        event: {
            linkCount: { from: 0, to: 1 },
            totalCount: 1000
        },
        gateway: {
            linkCount: { from: 1000, to: 1 },
            totalCount: 1000
        },
        gather: {
            linkCount: { from: 1, to: 1000 },
            totalCount: 1000
        }
    };
    self.diagram.title = {
        start: "开始",
        end: "结束",
        task: "任务",
        event: "事件",
        gateway: "网关",
        gather: "聚合"
    };
this.reload_gojs = function () {
    if (self.diagram && self.palette) {
        var tree = $.fn.zTree.getZTreeObj("tree");
        var treeNode = tree.getSelectedNodes()[0];
        var process = treeNode.process_data;
        if (process.CN_S_CONTENT) {
            self.diagram.model = go.Model.fromJson(process.CN_S_CONTENT);
        }
        else {
            self.diagram.clear();
        }
        var idx = document.title.indexOf("*");
        if (idx >= 0) document.title = document.title.substr(0, idx);
        self.diagram.isModified = false
        console.log(self.diagram.model.toJSON());
    }
   
};
this.showLinkLabel = function (e) {
    var label = e.subject.findObject("LABEL");
    if (label !== null) label.visible = (e.subject.fromNode.data.figure === "Diamond");
}
this.nodeStyle = function () {
    var gojs = go.GraphObject.make;
    return [
      new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
      {
          locationSpot: go.Spot.Center,
          mouseEnter: function (e, obj) { self.showPorts(obj.part, true); },
          mouseLeave: function (e, obj) { self.showPorts(obj.part, false); }
      }
    ];
}
this.makePort = function (name, spot, output, input) {
    var gojs = go.GraphObject.make;
    return gojs(go.Shape, "Circle",
    {
        fill: "transparent",
        stroke: null,
        desiredSize: new go.Size(8, 8),
        alignment: spot, alignmentFocus: spot,
        portId: name,
        fromSpot: spot, toSpot: spot,
        fromLinkable: output, toLinkable: input,
        cursor: "pointer"
    });
}
this.showPorts = function (node, show) {
    var diagram = node.diagram;
    if (!diagram || diagram.isReadOnly || !diagram.allowLink) return;
    node.ports.each(function (port) {
        port.stroke = (show ? "white" : null);
    });
}
this.linkDrawn = function (e) {
    // the DiagramEvent.subject is the new Link
    var from = e.subject.fromNode;
    var to = e.subject.toNode;
    var count = self.diagram.attr[from.data.category].linkCount.from;
    if (from.findLinksOutOf().count > count) {
        self.diagram.remove(e.subject);
    }
    count = self.diagram.attr[to.data.category].linkCount.to;
    if (to.findLinksInto().count > count) {
        self.diagram.remove(e.subject);
    }
    switch (from.data.category) {
        case 'task':
            self.current_link = e.subject;
            self.show_add_task_link();
            break;
        case 'gateway':
            self.current_link = e.subject;
            self.show_add_gateway_link();
            break;
    }
};
this.externalObjectsDropped = function (e) {
    // the DiagramEvent.parameter is the source Diagram
    // the DiagramEvent.subject is the set of Parts that were dropped (which is also the Diagram.selection)
    var category = e.subject.first().data.category;
    var count = self.diagram.attr[category].totalCount;
    if (self.diagram.findNodesByExample({ category: category }).count > count) {
        // alert(self.diagram.title[category] + '已存在');
        self.diagram.remove(e.subject.first());
        return;
    }
    switch (category) {
        case 'start':
            self.current_element = e.subject.first();
            self.show_add_start();
            break;
        case 'task':
            self.current_element = e.subject.first();
            self.show_add_task();
            break;
    }
};

Maybe because updatetargetbindings () changes the location of the link to replace the value of the link instead of updatetargetbindings ()?

I’m sorry, but after spending some time reading all of the code that you posted, almost all of which is probably unrelated to your problem, I still did not see the definition for store_process().

I cannot debug your app for you via a forum. You need to state precisely what the situation is and what causes the undesirable behavior to occur. I suggest that you create a sample that reproduces the problem and that has as little code in it as possible. Keep cutting out code until you get a minimum sample that reproduces the problem, and then we can talk about it and I can understand it well enough to offer useful advice.

this.store_process = function () {
var tree = $.fn.zTree.getZTreeObj(“tree”);
var treeNode = tree.getSelectedNodes()[0];
var json = self.diagram.model.toJSON();
$.ajax({
url: openinfo.root + “process/storeprocess”,
type: “POST”,
data: { id: treeNode.id, req: json },
dataType: “json”,
beforeSend: function () {
$(’#btn_store_process’).attr(‘disabled’, ‘disabled’);
$(’.dv_canvas_overlay’).addClass(‘display’);
},
complete: function () {
$(’#btn_store_process’).removeAttr(‘disabled’);
$(’.dv_canvas_overlay’).removeClass(‘display’);
},
success: function (ret) {
if (ret.code == “00000”) {
var d = dialog({
content: ‘保存成功’
});
d.show();
setTimeout(function () {
d.close().remove();
}, 1000);
treeNode.process_data.CN_S_CONTENT = json;
tree.updateNode(treeNode);
self.show_process_setting();
}
else {
var d = dialog({
title: ’ ’ + ‘错误’,
content: ret.msg
});
d.show();
}
},
error: function () {
}
});
};

This method only provides the role of writing Json into the database

I’m sorry, but after trying to read what you have posted here, I have no idea of what your app is doing. This way of debugging your app in a forum cannot work.

Somehow you need to narrow down what the undesirable behavior really is. Then you need to describe it in a concise fashion.