Javascript 如何将节点插入gojs中的多段线链接中,在新节点任一侧的链接中保留点的位置

Javascript 如何将节点插入gojs中的多段线链接中,在新节点任一侧的链接中保留点的位置,javascript,polyline,gojs,Javascript,Polyline,Gojs,我问了一个关于StackOverflow()的问题,并被指向gojs拼接示例 这让我走了很长的一段路,所以谢谢你的回答,但是我为了达到我想要的行为,遇到了困难 我正在尝试创建的应用程序用于编辑地图上的边界: 节点=三个或多个边界相交的位置 链接=两个节点之间的边界段 因此,节点和链接是未标记的(节点只是小圆,链接只是多段线) 我已尝试适当调整拼接示例()。除了示例的功能外,我还需要以下关键功能: 选择新节点在现有节点之间的链接上的确切位置 保留多段线的形状 (现有示例将新节点与现有节点等

我问了一个关于StackOverflow()的问题,并被指向gojs拼接示例

这让我走了很长的一段路,所以谢谢你的回答,但是我为了达到我想要的行为,遇到了困难

我正在尝试创建的应用程序用于编辑地图上的边界:

  • 节点=三个或多个边界相交的位置
  • 链接=两个节点之间的边界段
因此,节点和链接是未标记的(节点只是小圆,链接只是多段线)

我已尝试适当调整拼接示例()。除了示例的功能外,我还需要以下关键功能:

  • 选择新节点在现有节点之间的链接上的确切位置
  • 保留多段线的形状
(现有示例将新节点与现有节点等距放置,并使用直链接。)

我尝试创建的用户体验是这样的:首先,您选择链接,这样它就可以得到通常的装饰;然后按住shift键并单击多段线上某个点上的某个装饰,该点将成为新节点

我试图通过使用中描述的扩展机制重写LinkReformingTool的方法来实现这一点(而不是创建子类)

但是,无论我尝试了什么,我都无法使多段线保持不变。在我的代码运行后,通过在Chrome DevTools调试器中检查图表数据模型,它似乎是正确的(即,我可以在链接中看到正确的点数组)。但是,当我允许执行继续时,链接不会按预期显示(它们是直的),如果我随后查看数据模型,则多个点已消失,每个链接只有一个起点和终点

我尝试过各种方法,但都没有成功,例如:

  • 将拼接推迟到工具完成后
  • 以不同的方式将点传递到修改的链接(数组v列表v字符串)
  • 将处理放入不同的重写方法中
我现在的代码如下。请原谅粗俗的风格失礼-我不是一个经验丰富的JavaScript程序员

<!DOCTYPE html>  <!-- HTML5 document type -->
<!--
Adapted from splicing example from gojs.net
 -->
<html>
<head>
  <!-- use go-debug.js when developing and go.js when deploying -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/gojs/1.8.28/go-debug.js"></script>
</head>
<body>

<div id="myDiagramDiv"
     style="width:400px; height:300px; background-color: #DAE4E4;"></div>

<script>
  var $ = go.GraphObject.make;

  // state variables to remember what to do after reshaping tool aborted
  var doSpliceNode     = false;
  var doSpliceIntoLink = null;
  var doSplicePoint    = null;
  var doSpliceIndex    = -1;  
  
  // diagram
  var myDiagram = $(go.Diagram, "myDiagramDiv",
                     {
                       "undoManager.isEnabled": true
                     });
                     
  var tool = myDiagram.toolManager.linkReshapingTool;

  // Override doMouseDown on linkreshapingtool.  If user clicks on a handle with SHIFT pressed, want to insert
  // a new node at that point rather than use the default behaviour to (further) reshape the link, and moreover
  // want to retain the points in the link.  I.e. turn one of the points in the link into a new node.
  // (Existing gojs splicing example does not do this: it just puts a new node at the midpoint of the existing
  // link, with no regard to the points along the link.)
  tool.doMouseDown = function() {
  
    console.log("mousedown at (" + this.Fp.M + "," + this.Fp.N + ")");
    console.log(" on link from " + this.adornedLink.fromNode + " to " + this.adornedLink.toNode);
    console.log(" with shift pressed? " + myDiagram.lastInput.shift);

    
    var spliced = false;
    
    if (myDiagram.lastInput.shift)
    {
    
      // work out which of the points on the link was clicked
      var link   = this.adornedLink;
      var numpts = link.pointsCount;
      var i;
      var x = this.Fp.M; // @@TODO - by inspection in debugger this contains the X coord, but what's documented place to get this?
      var y = this.Fp.N; // @@TODO - ditto for Y coord
    
      for (i = 1; !spliced && (i < numpts - 1); i++)
      {
        if ((link.getPoint(i).x == x) && (link.getPoint(i).y == y))
        {
           console.log(" .. at point " + i);

           // Store off what to do.  (This used to be done inline - deferred to after as one of the things
           // to try to make it work.)
           doSpliceNode     = true;
           doSpliceIntoLink = link;
           doSplicePoint    = new go.Point(x, y);
           doSpliceIndex    = i;  
         
           spliced = true;
        }
      }
    }
    
    //if (!doSpliceNode)
    { 
      console.log(".. call base class doMouseDown");
      go.LinkReshapingTool.prototype.doMouseDown.call(tool);
    }
  }

  // Override doMouseUp as well.  If we had decided during mousedown to do the splice, then stop the tool now.
  tool.doMouseUp = function()
  {
    // First call base class
    go.LinkReshapingTool.prototype.doMouseUp.call(tool);
  
    if (doSpliceNode)
    {
      // Doing splice - stop tool
      console.log("STOP TOOL");
      this.stopTool();
      this.doDeactivate();
    }
  }  
  
  // Finally, override doStop to actually do the splice
  tool.doStop = function() {

    console.log("doStop");
    
    // First call base class
    go.LinkReshapingTool.prototype.doStop.call(tool);
  
  
    if (doSpliceNode)
    {
      // now splice the node
      console.log("splice node");
      spliceNewNodeIntoLink2(doSpliceIntoLink, doSplicePoint, doSpliceIndex);  // @@TODO make it respect points in existing link before and after
    }  
  
    // Reset everything
    doSpliceNode     = false;
    doSpliceIntoLink = null;
    doSplicePoint    = null;
    doSpliceIndex    = -1;  
  } 
    
  // Debug variable for inspecting later - not functional                    
  var debugLastLink = null;                  
                     
  // Model, node and links for this application.  Based heavily on https://gojs.net/temp/splicing.html and adapted as needed.
  
  var myModel = $(go.GraphLinksModel);
  
  myDiagram.nodeTemplate = $(go.Node,
                             "Auto",
                             new go.Binding("location", "location", go.Point.parse).makeTwoWay(go.Point.stringify),
                             $(go.Shape, "Circle", { width: 6, height: 6, strokeWidth: 0 }));
  
  
  
  myDiagram.linkTemplate =
        $(go.Link,
          {
            relinkableFrom: true, relinkableTo: true,
            reshapable: true, resegmentable: true,
          /*  selectionAdornmentTemplate:     @@ COMMENT OUT - NOT NEEDED
              $(go.Adornment,
                $(go.Shape, { isPanelMain: true, stroke: "dodgerblue", strokeWidth: 2 }),
                $(go.Shape, "PlusLine",
                  {
                    isActionable: true,  // so that click works in an Adornment
                    width: 16, height: 16, stroke: "green", strokeWidth: 4, background: "transparent",
                    segmentOffset: new go.Point(8, 0),
                    click: function(e, shape) {
                      alert(e);
                      var link = shape.part.adornedPart;
                      var p0 = link.getPoint(0);
                      var p1 = link.getPoint(link.pointsCount - 1);
                      var pt = new go.Point((p0.x + p1.x) / 2, (p0.y + p1.y) / 2);
                      
                      // @@TODO - instead, find the position where the mouse was clicked and place the node there
                      // ... need to work out which segment of polyline this was in so as to calculate new lines
                      
                      // @@TODO - handle drag of node so that it just affects segments of lines immediately into it, rather than
                      // blatting over top of them

                      // @@TODO - what is object e and its components
                      
                      spliceNewNodeIntoLink(link, pt);
                    },
                    cursor: "pointer"
                  })
              ), */
            toShortLength: 1
          },
          new go.Binding("points").makeTwoWay(),   // Use the points information from the linkDataArray initializer
          $(go.Shape, { strokeWidth: 2 })
        );

/*      function spliceNewNodeIntoLink(link, pt) {  // @@ original version no longer called
        link.diagram.commit(function(diag) {
          var tokey = link.toNode.key;
          // add a new node
          var newnodedata = { text: "on link", location: go.Point.stringify(pt) };
          diag.model.addNodeData(newnodedata);
          // and splice it in by changing the existing link to refer to the new node
          diag.model.setToKeyForLinkData(link.data, newnodedata.key);
          // and by adding a new link from the new node to the original "toNode"
          diag.model.addLinkData({ from: newnodedata.key, to: tokey });
          // optional: select the new node
          diag.select(diag.findNodeForData(newnodedata));
        }, "spliced in node on a link");
      }  */

      // Utility function used in one attempt to get this to work.  Initializers in nodeDataArray do it via an array of numbers,
      // so try that here.
      function toArray(nodelist)
      {
        var returnarray = new Array();
        var i;
        
        for (i = 0; i < nodelist.size; i++)
        {
          var pt = nodelist.elt(i);
          returnarray.push(pt.x);
          returnarray.push(pt.y);
        }
        
        return returnarray;
      }
      
      // Function to splice the new node into the link.  Parameters are
      // - link:  the link to splice into
      // - pt:    the point within the link to turn into a node
      // - index: index into existing polyline of that point
      function spliceNewNodeIntoLink2(link, pt, index) {
        link.diagram.commit(function(diag) {
          
          var oldlinkpointslist = link.points;
          var link1pointslist = new go.List(go.Point);
          var link2pointslist = new go.List(go.Point);
          var i;
          
          // Create new points list, from "from" node to new node to be added
          for (i = 0; i <= index; i++)
          {
            var point = new go.Point(link.getPoint(i).x, link.getPoint(i).y);
            link1pointslist.add(point);
          }
          
          console.log(link1pointslist);
          
          // .. and from new node to "to" node
          for (i = index; i < link.pointsCount; i++)
          {
            var point = new go.Point(link.getPoint(i).x, link.getPoint(i).y);
            link2pointslist.add(point);
          }

          console.log(link2pointslist);
          
          var tokey = link.toNode.key;
          // add a new node
          var newnodedata = { text: "on link", location: go.Point.stringify(pt) };
          diag.model.addNodeData(newnodedata);
          // and splice it in by changing the existing link to refer to the new node
          diag.model.setToKeyForLinkData(link.data, newnodedata.key);

          // ** NEW CODE
          // Code this was based on re-used the existing link, re-purposing it to go from "from" node 
          // to new node, so do the same, but give it a new points list.
          link.points = link1pointslist;    // @@TODO find out why this doesn't work    
                                            // ... actually it does, but something ditches the points later ...
                                            // so maybe I need to move this code to after the tool has really finished operating
                                            // by saving off the info and calling it in an override of the last tool method that
                                            // gets called (perhaps not - did this and it didn't work)
                                

          debugLastLink = link; // @@TEMP         
          
          // and by adding a new link from the new node to the original "toNode"
          // ** UPDATED to include the second new point list
          diag.model.addLinkData({ from: newnodedata.key, to: tokey, points: toArray(link2pointslist) });
          
          // optional: select the new node
          diag.select(diag.findNodeForData(newnodedata));
        }, "spliced in node on a link");
      }

      // not called at present
      function maySpliceOutNode(node) {
        return node.findLinksInto().count === 1 &&
          node.findLinksOutOf().count === 1 &&
          node.findLinksInto().first() !== node.findLinksOutOf().first();
      }

      // not called at present
      function spliceNodeOutFromLinkChain(node) {
        if (maySpliceOutNode(node)) {
          node.diagram.commit(function(diag) {
            var inlink = node.findLinksInto().first();
            var outlink = node.findLinksOutOf().first();
            // reconnect the existing incoming link
            inlink.toNode = outlink.toNode;
            // remove the node and the outgoing link
            diag.removeParts([node, outlink], false);
            // optional: select the original link
            diag.select(inlink);
          }, "spliced out node from chain of links");
        }
      }

 
  // Initialize modeldi 
  myModel.nodeDataArray = [
         { key: "1" , "location": "30 30" },
         { key: "2" , "location": "130 30" },
         { key: "3" , "location": "30 130" }
  ];
  
  myModel.linkDataArray = [ 
         { from: "1", to: "2", "points": [  30,30,  70,20, 100,40, 130,30 ] },
         { from: "2", to: "3", "points": [ 130,30, 100,80,  70,90, 30,130 ] },
         { from: "3", to: "1", "points": [ 30,130, 20,100,  40,70,  30,30 ] }
  ];
  
  myDiagram.model = myModel;
  
  
</script>
     
</body>
</html> 

var$=go.GraphObject.make;
//状态变量,以记住在整形工具中止后要执行的操作
var dospliconode=假;
var doSpliceIntoLink=null;
var doSplicePoint=null;
var doSpliceIndex=-1;
//图解
var myDiagram=$(go.Diagram,“myDiagramDiv”,
{
“undoManager.isEnabled”:真
});
var-tool=myDiagram.toolManager.linkReformingTool;
//在LinkReformingTool上覆盖doMouseDown。如果用户在按住SHIFT键的情况下单击手柄,则要插入
//在该点创建新节点,而不是使用默认行为(进一步)重塑链接,而且
//希望保留链接中的点。即,将链接中的一个点转换为新节点。
//(现有的gojs拼接示例并没有做到这一点:它只是将一个新节点放置在现有节点的中点
//链接,不考虑链接沿线的点。)
tool.doMouseDown=函数(){
log(“mousedown at(“+this.Fp.M+”,“+this.Fp.N+”));
log(“从“+this.adornedLink.fromNode+”链接到“+this.adornedLink.toNode”);
console.log(“按下shift时?”+myDiagram.lastInput.shift);
var拼接=假;
if(myDiagram.lastInput.shift)
{
//找出链接上的哪些点被单击
var link=this.adornedLink;
var numpts=link.pointscont;
var i;
var x=this.Fp.M;//@@TODO-通过在调试器中的检查,这包含x坐标,但是在什么地方可以得到它?
var y=this.Fp.N;//@@TODO-y坐标同上
对于(i=1;!拼接&&(i