var $ = go.GraphObject.make;  // for conciseness in defining templates

function buildAlarm(row,column,columnSpan=1){
    var obj=$(go.Shape, "Rectangle",  // define the node's outer shape
        {fill: "yellow", stroke: "black",alignment: go.Spot.TopRight,row: row, column: column, margin: 2, },
        new go.Binding("fill", "color"),
        new go.Binding("desiredSize", "", function(){ return new go.Size(40, 20) }));
    return obj;
}

function buildNodeName(row,column,columnSpan=1){
    var obj=$(go.TextBlock,
        {
          row: row, column: column,columnSpan:columnSpan,
          maxSize: new go.Size(160, NaN), margin: 2,
          font: '500 16px Roboto, sans-serif',
          alignment: go.Spot.Top,
          editable: true,
          isMultiline: false,
          minSize: new go.Size(10, 16)
        },
        new go.Binding("text", "name")
    );
    return obj;
}

function buildFields(row,column,columnSpan=1){
    var obj=$(go.TextBlock,
      {
        row: row, column: column, columnSpan: columnSpan,
        font: "12px Roboto, sans-serif",
        editable: true,
        isMultiline: true,
        name: "LIST",
        //minSize: new go.Size(10, 16),
      },
      new go.Binding("text", "", theInfoTextConverter));
    return obj;
}

function buildExpandNode(){
    var obj=$(go.Panel,  // this is underneath the "BODY"
      { height: 15 },  // always this height, even if the TreeExpanderButton is not visible
      $("TreeExpanderButton"));
    return obj;
}

function buildContentTable(){
    var obj=$(go.Panel, "Table",
      { margin: 6,
        maxSize: new go.Size(250, NaN),
        margin: new go.Margin(6, 10, 0, 3),
        defaultAlignment: go.Spot.Left
      },
      // the two TextBlocks in column 0 both stretch in width
      // but align on the left side
      $(go.RowColumnDefinition,
        {
          column: 0,
         // width: 80 ,
          stretch: go.GraphObject.Horizontal,
          alignment: go.Spot.Left
        }),
      // the name
      //标题
      buildNodeName(0,0),
      //报警标识
      buildAlarm(0,1),
      $("PanelExpanderButton", "LIST",  // the name of the element whose visibility this button toggles
              { row: 1, column: 2,columnSpan:1, alignment: go.Spot.Center, margin: 0, }),
      //属性字段
      buildFields(2,0,2));
    return obj;
}

function buildBackground(){
    var obj=$(go.Shape, "Rectangle",
      { stroke: null, strokeWidth: 0 },
      new go.Binding("fill", "isHighlighted", function(h) { return h ? "#F44336" : "#A7E7FC"; }).ofObject());
    return obj;
}

var nodeTemplateFactory={
    buildDefaultNodeTemplate:function(){
        var obj=$(go.Node, "Vertical",
            { selectionObjectName: "BODY", deletable: false,
            //desiredSize: new go.Size(300, 200),
            doubleClick: nodeDoubleClick,
              mouseEnter: mouseEnter,
              mouseLeave: mouseLeave,
              selectionChanged:nodeSelectionChanged,
              isShadowed: true,
              shadowColor: "#C5C1AA",
              //resizable: true,
              toolTip:
                $(go.Adornment, "Auto",
                  $(go.Shape, { fill: "lightyellow" }),
                  $(go.TextBlock, "double-click\nfor documentation",
                    { margin: 5 })
                ),
            },
            $(go.Panel,"Auto",
                { name: "BODY" },
                // the outer shape for the node, surrounding the Table
                buildBackground(),
                // a table to contain the different parts of the node
                buildContentTable()),
            buildExpandNode());
        return obj;
    },
    buildEnvNodeTemplate:function(){

    }
}

var nodeIdCounter = -1; // use a sequence to guarantee key uniqueness as we add/remove/modify nodes

var myDiagram =
      $(go.Diagram, "myDiagramDiv",  // the DIV HTML element
        {
          // Put the diagram contents at the top center of the viewport
          initialDocumentSpot: go.Spot.TopCenter,
          initialViewportSpot: go.Spot.TopCenter,
          initialAutoScale: go.Diagram.UniformToFill,
          maxSelectionCount: 1,
          //initialAutoScale: go.Diagram.Uniform,
          validCycle: go.Diagram.CycleDestinationTree, // make sure users can only create trees
          "clickCreatingTool.archetypeNodeData": {}, // allow double-click in background to create a new node
          "clickCreatingTool.insertPart": function(loc) {  // customize the data for the new node
            this.archetypeNodeData = {
              key: getNextKey(), // assign the key based on the number of nodes
              name: "(new person)",
              title: ""
            };
            return go.ClickCreatingTool.prototype.insertPart.call(this, loc);
          },
          // allow double-click in background to create a new node
          "clickCreatingTool.archetypeNodeData": { text: "Node", color: "white" },
          // allow Ctrl-G to call groupSelection()
          "commandHandler.archetypeGroupData": { text: "Group", isGroup: true, color: "blue" },

          // OR: Scroll to show a particular node, once the layout has determined where that node is
          //"InitialLayoutCompleted": function(e) {
          //  var node = e.diagram.findNodeForKey(28);
          //  if (node !== null) e.diagram.commandHandler.scrollToPart(node);
          //},
          layout:
            $(go.TreeLayout,  // use a TreeLayout to position all of the nodes
              {
                //treeStyle: go.TreeLayout.StyleLastParents,
                // properties for most of the tree:
                angle: 90,
                nodeSpacing: 10,
                layerSpacing: 60,
                arrangement: go.TreeLayout.ArrangementHorizontal,

                // properties for the "last parents":
                alternateAngle: 0,
                alternateAlignment: go.TreeLayout.AlignmentStart,
                alternateNodeIndent: 20,
                alternateNodeIndentPastParent: 1,
                alternateNodeSpacing: 20,
                alternateLayerSpacing: 40,
                alternateLayerSpacingParentOverlap: 1,
                alternatePortSpot: new go.Spot(0.001, 1, 20, 0),
                alternateChildPortSpot: go.Spot.Left
              }),
            "undoManager.isEnabled": true // enable undo & redo
        });

myDiagram.nodeTemplate =nodeTemplateFactory.buildDefaultNodeTemplate();

myDiagram.linkTemplate =$(go.Link, go.Link.Orthogonal,
    { corner: 5, selectable: false },
    $(go.Shape, { strokeWidth: 3, stroke: "#424242" } ));  

/*
myDiagram.linkTemplate =
    $(go.Link,
      {
        curve: go.Link.Bezier,
        toEndSegmentLength: 30, fromEndSegmentLength: 30
      },
      $(go.Shape, { strokeWidth: 1.5 }) // the link shape, with the default black stroke
    );
*/

// Overview
var myOverview =
  $(go.Overview, "myOverviewDiv",  // the HTML DIV element for the Overview
    { observed: myDiagram, contentAlignment: go.Spot.Center });   // tell it which Diagram to show and pan
    // define Converters to be used for Bindings

myDiagram.addDiagramListener("Modified", function(e) {
  var button = document.getElementById("SaveButton");
  if (button) button.disabled = !myDiagram.isModified;
  var idx = document.title.indexOf("*");
  if (myDiagram.isModified) {
    if (idx < 0) document.title += "*";
  } else {
    if (idx >= 0) document.title = document.title.substr(0, idx);
  }
});

myDiagram.addDiagramListener("SelectionDeleting", function(e) {
  var part = e.subject.first(); // e.subject is the myDiagram.selection collection,
                                // so we'll get the first since we know we only have one selection
  myDiagram.startTransaction("clear boss");
  if (part instanceof go.Node) {
    var it = part.findTreeChildrenNodes(); // find all child nodes
    while(it.next()) { // now iterate through them and clear out the boss information
      var child = it.value;
      var bossText = child.findObject("boss"); // since the boss TextBlock is named, we can access it by name
      if (bossText === null) return;
      bossText.text = undefined;
    }
  } else if (part instanceof go.Link) {
    var child = part.toNode;
    var bossText = child.findObject("boss"); // since the boss TextBlock is named, we can access it by name
    if (bossText === null) return;
    bossText.text = undefined;
  }
  myDiagram.commitTransaction("clear boss");
});

var levelColors = ["#AC193D/#BF1E4B", "#2672EC/#2E8DEF", "#8C0095/#A700AE", "#5133AB/#643EBF",
                   "#008299/#00A0B1", "#D24726/#DC572E", "#008A00/#00A600", "#094AB2/#0A5BC4"];
// override TreeLayout.commitNodes to also modify the background brush based on the tree depth level
myDiagram.layout.commitNodes = function() {
  go.TreeLayout.prototype.commitNodes.call(myDiagram.layout);  // do the standard behavior
  // then go through all of the vertexes and set their corresponding node's Shape.fill
  // to a brush dependent on the TreeVertex.level value
  myDiagram.layout.network.vertexes.each(function(v) {
    if (v.node) {
      var level = v.level % (levelColors.length);
      var colors = levelColors[level].split("/");
      var shape = v.node.findObject("SHAPE");
      if (shape) shape.fill = $(go.Brush, "Linear", { 0: colors[0], 1: colors[1], start: go.Spot.Left, end: go.Spot.Right });
    }
  });
};

// This function is used to find a suitable ID when modifying/creating nodes.
// We used the counter combined with findNodeDataForKey to ensure uniqueness.
function getNextKey() {
  var key = nodeIdCounter;
  while (myDiagram.model.findNodeDataForKey(key.toString()) !== null) {
    key = nodeIdCounter -= 1;
  }
  return key.toString();
}

function nodeDoubleClick(e, obj) {
  var clicked = obj.part;
  if (clicked !== null) {
    var thisemp = clicked.data;
    myDiagram.startTransaction("add employee");
    var nextkey = getNextKey();
    var newemp = { key: nextkey, name: "(new person)", title: "", parent: thisemp.key };
    myDiagram.model.addNodeData(newemp);
    myDiagram.commitTransaction("add employee");
  }
}

    function theNationFlagConverter(nation) {
      return "https://www.nwoods.com/go/Flags/" + nation.toLowerCase().replace(/\s/g, "-") + "-flag.Png";
    }

    function theInfoTextConverter(info) {
      var str = "";
      if (info.title) str += "Title: " + info.title;
      if (info.headOf) str += "\n\nHead of: " + info.headOf;
      if (typeof info.boss === "number") {
        var bossinfo = myDiagram.model.findNodeDataForKey(info.boss);
        if (bossinfo !== null) {
          str += "\n\nReporting to: " + bossinfo.name;
        }
      }
      return str;
    }

    // set up the nodeDataArray, describing each person/position
    var nodeDataArray = [
      { key: 0, name: "Ban Ki-moon 반기문", nation: "South Korea", title: "Secretary-General of the United Nations", headOf: "Secretariat" },
        { key: 1, boss: 0, name: "Patricia O'Brien", nation: "Ireland", title: "Under-Secretary-General for Legal Affairs and United Nations Legal Counsel", headOf: "Office of Legal Affairs" },
          { key: 3, boss: 1, name: "Peter Taksøe-Jensen", nation: "Denmark", title: "Assistant Secretary-General for Legal Affairs" },
            { key: 9, boss: 3, name: "Other Employees" },
          { key: 4, boss: 1, name: "Maria R. Vicien - Milburn", nation: "Argentina", title: "General Legal Division Director", headOf: "General Legal Division" },
            { key: 10, boss: 4, name: "Other Employees" },
          { key: 5, boss: 1, name: "Václav Mikulka", nation: "Czech Republic", title: "Codification Division Director", headOf: "Codification Division" },
            { key: 11, boss: 5, name: "Other Employees" },
          { key: 6, boss: 1, name: "Sergei Tarassenko", nation: "Russia", title: "Division for Ocean Affairs and the Law of the Sea Director", headOf: "Division for Ocean Affairs and the Law of the Sea" },
            { key: 12, boss: 6, name: "Alexandre Tagore Medeiros de Albuquerque", nation: "Brazil", title: "Chairman of the Commission on the Limits of the Continental Shelf", headOf: "The Commission on the Limits of the Continental Shelf" },
              { key: 17, boss: 12, name: "Peter F. Croker", nation: "Ireland", title: "Chairman of the Committee on Confidentiality", headOf: "The Committee on Confidentiality" },
                { key: 31, boss: 17, name: "Michael Anselme Marc Rosette", nation: "Seychelles", title: "Vice Chairman of the Committee on Confidentiality" },
                { key: 32, boss: 17, name: "Kensaku Tamaki", nation: "Japan", title: "Vice Chairman of the Committee on Confidentiality" },
                { key: 33, boss: 17, name: "Osvaldo Pedro Astiz", nation: "Argentina", title: "Member of the Committee on Confidentiality" },
                { key: 34, boss: 17, name: "Yuri Borisovitch Kazmin", nation: "Russia", title: "Member of the Committee on Confidentiality" },
              { key: 18, boss: 12, name: "Philip Alexander Symonds", nation: "Australia", title: "Chairman of the Committee on provision of scientific and technical advice to coastal States", headOf: "Committee on provision of scientific and technical advice to coastal States"},
                { key: 35, boss: 18, name: "Emmanuel Kalngui", nation: "Cameroon", title: "Vice Chairman of the Committee on provision of scientific and technical advice to coastal States" },
                { key: 36, boss: 18, name: "Sivaramakrishnan Rajan", nation: "India", title: "Vice Chairman of the Committee on provision of scientific and technical advice to coastal States" },
                { key: 37, boss: 18, name: "Francis L. Charles", nation: "Trinidad and Tobago", title: "Member of the Committee on provision of scientific and technical advice to costal States"},
                { key: 38, boss: 18, name: "Mihai Silviu German", nation: "Romania", title: "Member of the Committee on provision of scientific and technical advice to costal States"},
              { key: 19, boss: 12, name: "Lawrence Folajimi Awosika", nation: "Nigeria", title: "Vice Chairman of the Commission on the Limits of the Continental Shelf" },
              { key: 20, boss: 12, name: "Harald Brekke", nation: "Norway", title: "Vice Chairman of the Commission on the Limits of the Continental Shelf" },
              { key: 21, boss: 12, name: "Yong-Ahn Park", nation: "South Korea", title: "Vice Chairman of the Commission on the Limits of the Continental Shelf" },
              { key: 22, boss: 12, name: "Abu Bakar Jaafar", nation: "Malaysia", title: "Chairman of the Editorial Committee", headOf: "Editorial Committee" },
              { key: 23, boss: 12, name: "Galo Carrera Hurtado", nation: "Mexico", title: "Chairman of the Training Committee", headOf: "Training Committee" },
              { key: 24, boss: 12, name: "Indurlall Fagoonee", nation: "Mauritius", title: "Member of the Commission on the Limits of the Continental Shelf" },
              { key: 25, boss: 12, name: "George Jaoshvili", nation: "Georgia", title: "Member of the Commission on the Limits of the Continental Shelf" },
              { key: 26, boss: 12, name: "Wenzhang Lu", nation: "China", title: "Member of the Commission on the Limits of the Continental Shelf" },
              { key: 27, boss: 12, name: "Isaac Owusu Orudo", nation: "Ghana", title: "Member of the Commission on the Limits of the Continental Shelf" },
              { key: 28, boss: 12, name: "Fernando Manuel Maia Pimentel", nation: "Portugal", title: "Member of the Commission on the Limits of the Continental Shelf" },
          { key: 7, boss: 1, name: "Renaud Sorieul", nation: "France", title: "International Trade Law Division Director", headOf: "International Trade Law Division" },
            { key: 13, boss: 7, name: "Other Employees" },
          { key: 8, boss: 1, name: "Annebeth Rosenboom", nation: "Netherlands", title: "Treaty Section Chief", headOf: "Treaty Section" },
            { key: 14, boss: 8, name: "Bradford Smith", nation: "United States", title: "Substantive Legal Issues Head", headOf: "Substantive Legal Issues" },
              { key: 29, boss: 14, name: "Other Employees" },
            { key: 15, boss: 8, name: "Andrei Kolomoets", nation: "Russia", title: "Technical/Legal Issues Head", headOf: "Technical/Legal Issues" },
              { key: 30, boss: 15, name: "Other Employees" },
            { key: 16, boss: 8, name: "Other Employees" },
        { key: 2, boss: 0, name: "Heads of Other Offices/Departments" }
    ];

  // the Search functionality highlights all of the nodes that have at least one data property match a RegExp
  function searchDiagram() {  // called by button
    var input = document.getElementById("mySearch");
    if (!input) return;
    input.focus();

    // create a case insensitive RegExp from what the user typed
    var regex = new RegExp(input.value, "i");

    myDiagram.startTransaction("highlight search");
    myDiagram.clearHighlighteds();

    // search four different data properties for the string, any of which may match for success
    if (input.value) {  // empty string only clears highlighteds collection
      var results = myDiagram.findNodesByExample({ name: regex },
                                                 { nation: regex },
                                                 { title: regex },
                                                 { headOf: regex });
      myDiagram.highlightCollection(results);
      // try to center the diagram at the first node that was found
      if (results.count > 0) myDiagram.centerRect(results.first().actualBounds);
    }

    myDiagram.commitTransaction("highlight search");
  }

  // this event handler is called when the diagram is first ready
  myDiagram.addDiagramListener("InitialLayoutCompleted", function(e) {
    // pick a random node data
    //var data = nodeDataArray[Math.floor(Math.random()*nodeDataArray.length)];
    var data=nodeDataArray[0];
    // find the corresponding Node
    var node = myDiagram.findNodeForData(data);
    // and center it and select it
    myDiagram.centerRect(node.actualBounds);
    myDiagram.select(node);
  });

  //修改节点时触发
  myDiagram.addModelChangedListener(function(evt) {
        // ignore unimportant Transaction events
        if (!evt.isTransactionFinished) return;
        var txn = evt.object;  // a Transaction
        if (txn === null) return;
        // iterate over all of the actual ChangedEvents of the Transaction
        txn.changes.each(function(e) {
          // ignore any kind of change other than adding/removing a node
          if (e.modelChange !== "nodeDataArray") return;
          // record node insertions and removals
          if (e.change === go.ChangedEvent.Insert) {
            console.log(evt.propertyName + " added node with key: " + e.newValue.key);
          } else if (e.change === go.ChangedEvent.Remove) {
            console.log(evt.propertyName + " removed node with key: " + e.oldValue.key);
          }
        });
  });

  //连接改变时触发
  myDiagram.addModelChangedListener(function(evt) {
        // ignore unimportant Transaction events
        if (!evt.isTransactionFinished) return;
        var txn = evt.object;  // a Transaction
        if (txn === null) return;
        // iterate over all of the actual ChangedEvents of the Transaction
        txn.changes.each(function(e) {
          // record node insertions and removals
          if (e.change === go.ChangedEvent.Property) {
            if (e.modelChange === "linkFromKey") {
              console.log(evt.propertyName + " changed From key of link: " +
                          e.object + " from: " + e.oldValue + " to: " + e.newValue);
            } else if (e.modelChange === "linkToKey") {
              console.log(evt.propertyName + " changed To key of link: " +
                          e.object + " from: " + e.oldValue + " to: " + e.newValue);
            }
          } else if (e.change === go.ChangedEvent.Insert && e.modelChange === "linkDataArray") {
            console.log(evt.propertyName + " added link: " + e.newValue);
          } else if (e.change === go.ChangedEvent.Remove && e.modelChange === "linkDataArray") {
            console.log(evt.propertyName + " removed link: " + e.oldValue);
          }
        });
  });

  // To simplify this code we define a function for creating a context menu button:
  function makeButton(text, action, visiblePredicate) {
    return $("ContextMenuButton",
             $(go.TextBlock, text),
             { click: action },
             // don't bother with binding GraphObject.visible if there's no predicate
             visiblePredicate ? new go.Binding("visible", "", visiblePredicate).ofObject() : {});
  }

  var partContextMenu =
      $(go.Adornment, "Vertical",
          makeButton("Properties",
                     function(e, obj) {  // OBJ is this Button
                       var contextmenu = obj.part;  // the Button is in the context menu Adornment
                       var part = contextmenu.adornedPart;  // the adornedPart is the Part that the context menu adorns
                       // now can do something with PART, or with its data, or with the Adornment (the context menu)
                       if (part instanceof go.Link) alert(linkInfo(part.data));
                       else if (part instanceof go.Group) alert(groupInfo(contextmenu));
                       else alert(nodeInfo(part.data));
                     }),
          makeButton("Cut",
                     function(e, obj) { e.diagram.commandHandler.cutSelection(); },
                     function(o) { return o.diagram.commandHandler.canCutSelection(); }),
          makeButton("Copy",
                     function(e, obj) { e.diagram.commandHandler.copySelection(); },
                     function(o) { return o.diagram.commandHandler.canCopySelection(); }),
          makeButton("Paste",
                     function(e, obj) { e.diagram.commandHandler.pasteSelection(e.diagram.lastInput.documentPoint); },
                     function(o) { return o.diagram.commandHandler.canPasteSelection(); }),
          makeButton("Delete",
                     function(e, obj) { e.diagram.commandHandler.deleteSelection(); },
                     function(o) { return o.diagram.commandHandler.canDeleteSelection(); }),
          makeButton("Undo",
                     function(e, obj) { e.diagram.commandHandler.undo(); },
                     function(o) { return o.diagram.commandHandler.canUndo(); }),
          makeButton("Redo",
                     function(e, obj) { e.diagram.commandHandler.redo(); },
                     function(o) { return o.diagram.commandHandler.canRedo(); }),
          makeButton("Group",
                     function(e, obj) { e.diagram.commandHandler.groupSelection(); },
                     function(o) { return o.diagram.commandHandler.canGroupSelection(); }),
          makeButton("Ungroup",
                     function(e, obj) { e.diagram.commandHandler.ungroupSelection(); },
                     function(o) { return o.diagram.commandHandler.canUngroupSelection(); })
      );

  function nodeInfo(d) {  // Tooltip info for a node data object
      var str = "Node " + d.key + ": " + d.text + "\n";
      if (d.group)
        str += "member of " + d.group;
      else
        str += "top-level node";
      return str;
    }

  // When a Node is selected, highlight the corresponding HTML element.
  function nodeSelectionChanged(node) {
    if (node.isSelected) {
      //names[node.data.name].style.backgroundColor = "lightblue";
    //  node.style.backgroundColor = "lightblue";
        console.log(node.data.name);

    } else {
      //names[node.data.name].style.backgroundColor = "";
    }
  }

  function mouseEnter(e, obj) {
      obj.isHighlighted = true;
    };

    function mouseLeave(e, obj) {
      obj.isHighlighted = false;
    };
//linkData在父亲节点都不存在的情况下会自动创建Node
//{ from: "Center", to: i++, toArrow: arrowheads[j], fromArrow: arrowheads[j + 1] }

    // a selected node shows an Adornment that includes both a blue border
    // and a row of Buttons above the node
    myDiagram.nodeTemplate.selectionAdornmentTemplate =
      $(go.Adornment, "Spot",
        $(go.Panel, "Auto",
          $(go.Shape, { stroke: "dodgerblue", strokeWidth: 2, fill: null }),
          $(go.Placeholder)
        ),
        $(go.Panel, "Horizontal",
          { alignment: go.Spot.Top, alignmentFocus: go.Spot.Bottom },
          $("Button",
            { click: editText },  // defined below, to support editing the text of the node
            $(go.TextBlock, "t",
              { font: "bold 10pt sans-serif", desiredSize: new go.Size(15, 15), textAlign: "center" })
          ),
          $("Button",
            { click: changeColor, "_buttonFillOver": "transparent" },  // defined below, to support changing the color of the node
            new go.Binding("ButtonBorder.fill", "color", nextColor),
            $(go.Shape,
              { fill: null, stroke: null, desiredSize: new go.Size(14, 14) })
          ),
          $("Button",
            { // drawLink is defined below, to support interactively drawing new links
              click: drawLink,  // click on Button and then click on target node
              actionMove: drawLink  // drag from Button to the target node
            },
            $(go.Shape,
              { geometryString: "M0 0 L8 0 8 12 14 12 M12 10 L14 12 12 14" })
          ),
          $("Button",
            {
              actionMove: dragNewNode,  // defined below, to support dragging from the button
              _dragData: { text: "a Node", color: "lightgray" },  // node data to copy
              click: clickNewNode  // defined below, to support a click on the button
            },
            $(go.Shape,
              { geometryString: "M0 0 L3 0 3 10 6 10 x F1 M6 6 L14 6 14 14 6 14z", fill: "gray" })
          )
        )
      );

    function editText(e, button) {
      var node = button.part.adornedPart;
      e.diagram.commandHandler.editTextBlock(node.findObject("TEXTBLOCK"));
    }

    function editText(e, button) {
        var node = button.part.adornedPart;
        e.diagram.commandHandler.editTextBlock(node.findObject("TEXTBLOCK"));
      }

      // used by nextColor as the list of colors through which we rotate
      var myColors = ["lightgray", "lightblue", "lightgreen", "yellow", "orange", "pink"];

      // used by both the Button Binding and by the changeColor click function
      function nextColor(c) {
        var idx = myColors.indexOf(c);
        if (idx < 0) return "lightgray";
        if (idx >= myColors.length-1) idx = 0;
        return myColors[idx+1];
      }

      function changeColor(e, button) {
        var node = button.part.adornedPart;
        var shape = node.findObject("SHAPE");
        if (shape === null) return;
        node.diagram.startTransaction("Change color");
        shape.fill = nextColor(shape.fill);
        button["_buttonFillNormal"] = nextColor(shape.fill);  // update the button too
        node.diagram.commitTransaction("Change color");
      }

      function drawLink(e, button) {
        var node = button.part.adornedPart;
        var tool = e.diagram.toolManager.linkingTool;
        tool.startObject = node.port;
        e.diagram.currentTool = tool;
        tool.doActivate();
      }

      // used by both clickNewNode and dragNewNode to create a node and a link
      // from a given node to the new node
      function createNodeAndLink(data, fromnode) {
        var diagram = fromnode.diagram;
        var model = diagram.model;
        var nodedata = model.copyNodeData(data);
        model.addNodeData(nodedata);
        var newnode = diagram.findNodeForData(nodedata);
        var linkdata = model.copyLinkData({});
        model.setFromKeyForLinkData(linkdata, model.getKeyForNodeData(fromnode.data));
        model.setToKeyForLinkData(linkdata, model.getKeyForNodeData(newnode.data));
        model.addLinkData(linkdata);
        diagram.select(newnode);
        return newnode;
      }

      // the Button.click event handler, called when the user clicks the "N" button
      function clickNewNode(e, button) {
        var data = button._dragData;
        if (!data) return;
        e.diagram.startTransaction("Create Node and Link");
        var fromnode = button.part.adornedPart;
        var newnode = createNodeAndLink(button._dragData, fromnode);
        newnode.location = new go.Point(fromnode.location.x + 200, fromnode.location.y);
        e.diagram.commitTransaction("Create Node and Link");
      }

      // the Button.actionMove event handler, called when the user drags within the "N" button
      function dragNewNode(e, button) {
        var tool = e.diagram.toolManager.draggingTool;
        if (tool.isBeyondDragSize()) {
          var data = button._dragData;
          if (!data) return;
          e.diagram.startTransaction("button drag");  // see doDeactivate, below
          var newnode = createNodeAndLink(data, button.part.adornedPart);
          newnode.location = e.diagram.lastInput.documentPoint;
          // don't commitTransaction here, but in tool.doDeactivate, after drag operation finished
          // set tool.currentPart to a selected movable Part and then activate the DraggingTool
          tool.currentPart = newnode;
          e.diagram.currentTool = tool;
          tool.doActivate();
        }
      }

      // using dragNewNode also requires modifying the standard DraggingTool so that it
      // only calls commitTransaction when dragNewNode started a "button drag" transaction;
      // do this by overriding DraggingTool.doDeactivate:
      var tool = myDiagram.toolManager.draggingTool;
      tool.doDeactivate = function() {
        // commit "button drag" transaction, if it is ongoing; see dragNewNode, above
        if (tool.diagram.undoManager.nestedTransactionNames.elt(0) === "button drag") {
          tool.diagram.commitTransaction();
        }
        go.DraggingTool.prototype.doDeactivate.call(tool);  // call the base method
      };

      myDiagram.model =
          $(go.TreeModel,
            { nodeParentKeyProperty: "boss",  // this property refers to the parent node data
              //nodeParentKeyProperty: "parentKey",
              nodeDataArray: nodeDataArray });

 //更新数据
 //     model.updateTargetBindings(data);

//循环更新数据
/*
      function loop() {
          setTimeout(function() { randomProblems(); loop(); }, 2000);
        }
       loop();  // start the simulation
*/

【12-26】go.js的更多相关文章

  1. 【重温基础】15.JS对象介绍

    从这篇文章开始,复习 MDN 中级教程 的内容了,在初级教程中,我和大家分享了一些比较简单基础的知识点,并放在我的 [Cute-JavaScript]系列文章中. 关于[Cute-JavaScript ...

  2. 【开源专访】Sea.js创始人玉伯的前端开发之路

    摘要:玉伯,淘宝前端类库 KISSY.前端模块化开发框架SeaJS.前端基础类库Arale的创始人.本期[开源专访]我们邀请玉伯来为我们分享一些关于前端框架.前端开发的那些事,以及前端大牛是如何炼成的 ...

  3. 【23.26%】【codeforces 747D】Winter Is Coming

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  4. 【干货分享】Node.js 中文学习资料和教程导航

    这篇文章来自 Github 上的一位开发者收集整理的 Node.js 中文学习资料和教程导航.Node 是一个服务器端 JavaScript 解释器,它将改变服务器应该如何工作的概念,它的目标是帮助程 ...

  5. 【Python + Selenium】之JS定位总结

    感谢:小琰子 Python+Selenium 脚本中的一些js的用法汇总: 1.滚动条 driver.set_window_size(500,500) js = "window.scroll ...

  6. 【干货分享】Node.js 中文资料导航

    这篇文章与大家分享一批高质量的的 Node.js 中文资料.Node.js 是一个基于 Chrome JavaScript 运行时建立的一个平台, 用来方便地搭建快速的, 易于扩展的网络应用 Node ...

  7. 【功能代码】---5 JS通过事件隐藏显示元素

    JS通过事件隐藏显示元素 在开发中,很多时候我们需要点击事件,才显示隐藏元素.那如何做到页面刚开始就把标签隐藏. 有两种方法: (1) display:none    <div id=" ...

  8. 【功能代码】---3 JS判断字符串是否包含某个字符串

    JS判断字符串是否包含某个字符串 var str ="abc"; if(str.indexOf("bc")>-1){ alert('str中包含bc字符串 ...

  9. 【12.78%】【codeforces 677D】Vanya and Treasure

    time limit per test1.5 seconds memory limit per test256 megabytes inputstandard input outputstandard ...

  10. 【特别推荐】Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

随机推荐

  1. JS实现-页面数据无限加载

    在手机端浏览网页时,经常使用一个功能,当我们浏览京东或者淘宝时,页面滑动到底部,我们看到数据自动加载到列表.之前并不知道这些功能是怎么实现的,于是自己在PC浏览器上模拟实现这样的功能.先看看浏览效果: ...

  2. Android 监听返回键、HOME键

    拦截返回键,HOME键,继承BaseActivity即可 import android.app.Activity; import android.content.BroadcastReceiver; ...

  3. WEBPACK开始

    这是一个非常简单的例子,通过这个例子你将学习到 1.How to install webpack 2.How to use webpack 3.How to use loaders 4.How to ...

  4. 在win7下将CapsLock按键变成esc

    我喜欢用vim来编辑,经常要按到esc,但是去按那个按键确实比较的远,而且CapsLock这个按键对我来说着实有些鸡肋,所以就想在win7上也能像ubuntu那样把capslock映射为esc,在网上 ...

  5. SQL函数简述

    数字函数ABS 取绝对值 POWER 乘方 LN 10为底数取幂SQRT 平方根 EXP e的n次乘方 LOG(m,n) m为底数n取幂数学运算函数:ACOS ATAN ATAN2 COS COSH ...

  6. leetcode_question_130 Surrounded Regions

    Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A region is captured ...

  7. activemq Linux下的编译

    1.首先下载源码 ,网址:http://www.apache.org/dyn/closer.lua/activemq/activemq-cpp/3.9.4/activemq-cpp-library-3 ...

  8. Bate版敏捷冲刺每日报告--day1

    1 团队介绍 团队组成: PM:齐爽爽(258) 小组成员:马帅(248),何健(267),蔡凯峰(285)  Git链接:https://github.com/WHUSE2017/C-team 2 ...

  9. 洛谷P1083借教室题解

    题目 这个难度感觉并没有那么高,因为这个题暴力也好打,但是比较难想出正解,因为如果你不看标签是很难想到这个题竟然是二分,当然前缀和应该很好想,毕竟让你求的是在某段时间内借教室的和是否满足. 这样我们可 ...

  10. python3+selenium入门03-操作谷歌浏览器

    操作谷歌浏览器同样也需要下载相应的driver插件,官网下载.也可以从我的网盘下载,不过可能不是最新的,网盘地址.打开谷歌浏览器的操作和火狐的差不过. from selenium import web ...