节点和 link 文本的 gojs 动态下拉选项
gojs dinamical dropdown choices for node and link text
我想为用户创建自定义选择下拉菜单以编辑节点和 link 文本。
到目前为止,我使用此代码使用户 select 节点和 links 文本 select 能够出现在下拉列表中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>State Chart</title>
<meta name="description" content="A finite state machine chart with editable and interactive features." />
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="{{url_for('static', filename='go.js')}}"></script>
<!-- custom text editors -->
<script src="{{url_for('static', filename='TextEditorSelectBox.js')}}"></script>
<script src="{{url_for('static', filename='TextEditorRadioButtons.js')}}"></script>
<script src="{{url_for('static', filename='TextEditorSelectBox.js')}}"></script>
<script src="{{url_for('static', filename='DataInspector.js')}}"></script>
<link href="https://gojs.net/latest/extensions/DataInspector.css" rel="stylesheet">
<link href="{{url_for('static', filename='DataInspector.css')}}" rel="stylesheet">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<style>
body {
overflow-x: hidden;
}
#wrapper {
padding-left: 0;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
#wrapper.toggled {
padding-left: 250px;
}
#sidebar-wrapper {
z-index: 1000;
position: fixed;
left: 250px;
width: 0;
height: 100%;
margin-left: -250px;
overflow-y: auto;
background: #000;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
#wrapper.toggled #sidebar-wrapper {
width: 250px;
}
#page-content-wrapper {
width: 100%;
position: absolute;
padding: 15px;
}
#wrapper.toggled #page-content-wrapper {
position: absolute;
margin-right: -250px;
}
/* Sidebar Styles */
.sidebar-nav {
position: absolute;
top: 0;
width: 250px;
margin: 0;
padding: 0;
list-style: none;
}
.sidebar-nav li {
text-indent: 20px;
line-height: 40px;
}
.sidebar-nav li a {
display: block;
text-decoration: none;
color: #999999;
}
.sidebar-nav li a:hover {
text-decoration: none;
color: #fff;
background: rgba(255, 255, 255, 0.2);
}
.sidebar-nav li a:active, .sidebar-nav li a:focus {
text-decoration: none;
}
.sidebar-nav>.sidebar-brand {
height: 65px;
font-size: 18px;
line-height: 60px;
}
.sidebar-nav>.sidebar-brand a {
color: #999999;
}
.sidebar-nav>.sidebar-brand a:hover {
color: #fff;
background: none;
}
@media(min-width:768px) {
#wrapper {
padding-left: 0;
}
#wrapper.toggled {
padding-left: 250px;
}
#sidebar-wrapper {
width: 0;
}
#wrapper.toggled #sidebar-wrapper {
width: 250px;
}
#page-content-wrapper {
padding: 20px;
position: relative;
}
#wrapper.toggled #page-content-wrapper {
position: relative;
margin-right: 0;
}
}
</style>
<script id="code">
var nodeChoices = ['choice 1', 'choice 2', 'choice 3', 'choice 4', 'choice 5'];
const originalNodeChoices = ['choice 1', 'choice 2', 'choice 3', 'choice 4', 'choice 5'];
var linkChoices = ['link choice 1', 'link choice 2', 'link choice 3', 'link choice 4', 'link choice 5'];
const originalLinkChoices = ['link choice 1', 'link choice 2', 'link choice 3', 'link choice 4', 'link choice 5'];
function init() {
var $ = go.GraphObject.make;
myDiagram =
$(go.Diagram, "myDiagramDiv", // must name or refer to the DIV HTML element
{
// start everything in the middle of the viewport
initialContentAlignment: go.Spot.Center,
// have mouse wheel events zoom in and out instead of scroll up and down
"toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom,
// support double-click in background creating a new node
"clickCreatingTool.archetypeNodeData": { text: "new node" },
// enable undo & redo
"textEditingTool.defaultTextEditor": window.TextEditorSelectBox,
"undoManager.isEnabled": true,
"layout": new go.ForceDirectedLayout(),
"ModelChanged": function(e) {
//console.log("Diagram model changed!");
if (e.change === go.ChangedEvent.Remove && e.modelChange === "linkDataArray") {
console.log("eee its linkDataArray");
console.log(e);
var linkdata = e.oldValue;
console.log("linkdata");
console.log(linkdata);
var oldstr = linkdata.text;
console.log("oldstr");
console.log(oldstr);
if (!oldstr) return;
var customModelData = e.model.modelData.choices;
var choices = e.model.modelData.choices.linkChoices;
console.log("choices");
console.log(choices);
var idx = choices.indexOf(oldstr);
if (idx < 0) {
console.log("adding choice: " + oldstr);
var newchoices = Array.prototype.slice.call(choices);
newchoices.push(oldstr);
e.model.set(e.model.modelData, "choices", newchoices);
}
}else if(e.change === go.ChangedEvent.Remove && e.modelChange === "nodeDataArray"){
console.log("eee its nodeDataArray");
}
/*
else{
console.log("elseeeeeee111!");
console.log("e.change");
console.log(e.change);
console.log("e.modelChange");
console.log(e.modelChange);
}*/
}
});
//myDiagram.model.set(myDiagram.model.modelData, "choices", JSON.parse('{{ link_choices | tojson | safe}}'));
//myDiagram.model.set(myDiagram.model.modelData, "choices", ["one", "two", "three"]);
console.log("myDiagram.model.modelData");
console.log(myDiagram.model.modelData);
console.log("myDiagram.model.modelData.choices");
console.log(myDiagram.model.modelData.choices);
// when the document is modified, add a "*" to the title and enable the "Save" button
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("textEdited", function(e) {
console.log("Text is edited");
console.log(e);
//CHECK IF LINK,
//IF YES REMOVE THAT OPTION FROM LIST
});
myDiagram.addDiagramListener("SelectionDeleting", function(e) {
console.log("inside SelectionDeleting");
console.log(e);
//CHECK IF LINK,
//IF YES PUT THAT OPTION BACK IN OPTION LIST
});
// define the Node template
myDiagram.nodeTemplate =
$(go.Node, "Auto",
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
// define the node's outer shape, which will surround the TextBlock
$(go.Shape, "RoundedRectangle",
{
parameter1: 20, // the corner has a large radius
fill: $(go.Brush, "Linear", { 0: "rgb(254, 201, 0)", 1: "rgb(254, 162, 0)" }),
stroke: null,
portId: "", // this Shape is the Node's port, not the whole Node
fromLinkable: true, fromLinkableDuplicates: true,
toLinkable: true, toLinkableDuplicates: true,
cursor: "pointer"
}),
$(go.TextBlock,
{
font: "bold 11pt helvetica, bold arial, sans-serif",
editable: true, // editing the text automatically updates the model data
//textEditor: window.TextEditorRadioButtons, // defined in textEditorRadioButtons.js
// this specific TextBlock has its own choices:
textEditor: window.TextEditorRadioButtons,
textEdited: function(tb, oldstr, newstr) {
console.log("textEdited nodeeeeeeeeeeeeeeeeeeeeeeeee!!!");
var choices = tb.diagram.model.modelData.choices.nodeChoices;
console.log("choices");
console.log(choices);
console.log("newstr");
console.log(newstr);
console.log("oldstr");
console.log(oldstr);
var idx = choices.indexOf(newstr);
if (idx >= 0 && oldstr !== newstr ) {
console.log(choices);
console.log("choices");
console.log(choices);
console.log("removing choice " + idx + ": " + newstr);
var newchoices = Array.prototype.slice.call(choices);
newchoices.splice(idx, 1);
console.log("after remove");
console.log(newchoices);
var currentChoicesFromModel = tb.diagram.model.modelData.choices;
console.log("currentChoicesFromModel");
console.log(currentChoicesFromModel);
currentChoicesFromModel.nodeChoices = newchoices;
console.log("currentChoicesFromModel after update: ");
console.log(currentChoicesFromModel);
tb.diagram.model.set(tb.diagram.model.modelData, "choices", currentChoicesFromModel);
//tb.editable = false; // don't allow choice again
}else{
console.log("elseeeeee");
}
},
//choices: JSON.parse('{{ choices | tojson | safe}}')
choices: nodeChoices
},
new go.Binding("text").makeTwoWay())
);
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",
{ // 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: "?????", 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" })
)
)
);
//myDiagram.model.set(myDiagram.model.modelData, "choices", JSON.parse('{{ link_choices | tojson | safe}}'));
//myDiagram.model.set(myDiagram.model.modelData, "choices", ["one", "two", "three"]);
console.log("myDiagram.model.modelData");
console.log(myDiagram.model.modelData);
console.log(myDiagram.model.modelData.choices);
function editText(e, button) {
//console.log(e);
var node = button.part.adornedPart;
console.log("node");
//console.log(node);
e.diagram.commandHandler.editTextBlock(node.findObject("TEXTBLOCK"));
//$("#nodeText").val(node.findObject("TEXTBLOCK"));
}
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
};
// replace the default Link template in the linkTemplateMap
myDiagram.linkTemplate =
$(go.Link, // the whole link panel
{
curve: go.Link.Bezier,
adjusting: go.Link.Stretch,
reshapable: true,
relinkableFrom: true,
relinkableTo: true,
toShortLength: 3
},
new go.Binding("points").makeTwoWay(),
new go.Binding("curviness"),
$(go.Shape, // the link shape
{ strokeWidth: 1.5 }),
$(go.Shape, // the arrowhead
{ toArrow: "standard", stroke: null }),
$(go.Panel, "Auto",
$(go.Shape, // the label background, which becomes transparent around the edges
{
fill: $(go.Brush, "Radial", { 0: "rgb(240, 240, 240)", 0.3: "rgb(240, 240, 240)", 1: "rgba(240, 240, 240, 0)" }),
stroke: null
}),
$(go.TextBlock,
{
background: "white",
editable: true,
textEditor: window.TextEditorSelectBox, // defined in extensions/textEditorSelectBox.js
textEdited: function(tb, oldstr, newstr) {
var choices = tb.diagram.model.modelData.choices.linkChoices;
console.log("choices");
console.log(choices);
console.log("newstr");
console.log(newstr);
console.log("oldstr");
console.log(oldstr);
var idx = choices.indexOf(newstr);
if (idx >= 0 && oldstr !== newstr ) {
console.log(choices);
console.log("choices");
console.log(choices);
console.log("removing choice " + idx + ": " + newstr);
var newchoices = Array.prototype.slice.call(choices);
newchoices.splice(idx, 1);
tb.diagram.model.set(tb.diagram.model.modelData.choices.linkChoices, "choices", newchoices);
//tb.editable = false; // don't allow choice again
}else{
console.log("elseeeeee");
}
}
},
// editing the text automatically updates the model data
//new go.Binding("text"),
new go.Binding("text").makeTwoWay(),
new go.Binding("choices").ofModel())
)
);
var inspector = new Inspector('myInspectorDiv', myDiagram,
{
// uncomment this line to only inspect the named properties below instead of all properties on each object:
// includesOwnProperties: false,
properties: {
"text": { },
// an example of specifying the type
"password": { show: Inspector.showIfPresent, type: 'password' },
// key would be automatically added for nodes, but we want to declare it read-only also:
"key": { readOnly: true, show: Inspector.showIfPresent },
// color would be automatically added for nodes, but we want to declare it a color also:
"color": { show: Inspector.showIfPresent, type: 'color' },
// Comments and LinkComments are not in any node or link data (yet), so we add them here:
"Comments": { show: Inspector.showIfNode },
"flag": { show: Inspector.showIfNode, type: 'checkbox' },
"LinkComments": { show: Inspector.showIfLink },
"isGroup": { readOnly: true, show: Inspector.showIfPresent }
}
});
// read in the JSON data from flask
loadGraphData();
}
function loadGraphData() {
var graphDataString = JSON.parse('{{ diagramData | tojson | safe}}');
//console.log("graphDataString");
//console.log(graphDataString);
var allChoices = JSON.parse('{{ allChoices | tojson | safe}}');
console.log("allChoices");
console.log(allChoices);
myDiagram.model = go.Model.fromJson(graphDataString);
//myDiagram.model.set(myDiagram.model.modelData, "choices", ["one", "two", "three"]);
var customModelData = {
"linkChoices": linkChoices, "nodeChoices": nodeChoices
};
myDiagram.model.set(myDiagram.model.modelData, "choices", allChoices);
//myDiagram.model.set(myDiagram.model.modelData, "choices", JSON.parse('{{ link_choices | tojson | safe}}'));
//myDiagram.model.set(myDiagram.model.modelData, "choices", customModelData);
console.log("whole model modelData");
console.log(myDiagram.model.modelData);
}
function saveGraphData(form, event) {
console.log("inside saveGraphData");
event.preventDefault();
document.getElementById("mySavedModel").value = myDiagram.model.toJson();
form.submit();
}
function zoomToFit(){
console.log("inside zoomToFit");
myDiagram.zoomToRect(myDiagram.documentBounds);
}
function zoomIn(){
console.log("inside zoomIn");
myDiagram.commandHandler.increaseZoom();
}
function zoomOut(){
console.log("inside zoomOut");
myDiagram.commandHandler.decreaseZoom();
}
</script>
</head>
<body onload="init()">
<div id="wrapper">
<!-- Sidebar -->
<div id="sidebar-wrapper">
<ul class="sidebar-nav">
<li class="sidebar-brand"> <a href="#"> CUSTOM CHOICES MODE </a> </li>
<li> <a href="{{ url_for('main') }}">Free editing mode</a> </li>
<li> <a href="{{ url_for('graphMode1') }}">Fill mode</a> </li>
<li> <a href="{{ url_for('graphMode2') }}">Custom choices mode</a> </li>
<li> <a href="{{ url_for('graphMode3') }}">Locked choices mode</a> </li>
</ul>
</div>
<!-- /#sidebar-wrapper -->
<!-- Page Content -->
<div id="page-content-wrapper">
<div class="container-fluid">
<div id=formWrapper style="padding: 30px;">
<a href="#menu-toggle" class="btn btn-secondary" id="menu-toggle" style="margin-bottom: 15px;">Toggle Menu</a>
<form method="POST" action="http://localhost:5000/updateResultFile" name="updateResultFileForm"
id="updateResultFileForm"
onsubmit="saveGraphData(this, event);">
<div id="graphWrapper" style="margin-bottom: 15px;">
<div id="myDiagramDiv" style="border: solid 1px black; width: 100%; height: 800px;margin-bottom: 15px;"></div>
<div style="display: none;"><input id="mySavedModel" name="mySavedModel"></div>
<button class="btn btn-default" type="submit"> Save <i class="fa fa-save"> </i> </button>
</div>
</form>
<div id="myInspectorDiv">
</div>
<div>
<button class="btn btn-default" onclick="zoomToFit()"> Zoom to fit <i class="fa fa-search"> </i> </button>
<button class="btn btn-default" onclick="zoomIn()"> Zoom in <i class="fa fa-search-plus"> </i> </button>
<button class="btn btn-default" onclick="zoomOut()"> Zoom out <i class="fa fa-search-minus"> </i> </button>
</div>
</div>
</div>
</div>
</div>
<script src="{{url_for('static', filename='jquery.min.js')}}"></script>
<script src="{{url_for('static', filename='bootstrap.bundle.min.js')}}"></script>
<!-- Menu Toggle Script -->
<script>
var menuOpen = false;
$("#menu-toggle").click(function(e) {
e.preventDefault();
$("#wrapper").toggleClass("toggled");
if(menuOpen){
menuOpen = false;
$("#myDiagramDiv").css({border: "solid 1px black"});
}else{
menuOpen = true;
$("#myDiagramDiv").css({border: ""});
}
});
</script>
</body>
</html>
所以基本上我已经为节点和 links 做出了自定义选择。例如,对于节点,我有以下选择:
- 节点选择 1
- 节点选择2
- 节点选择3
对于 links 我有这些选择:
- link选择1
- link选择2
- link选择3
我想要完成的是,当我从一个节点上的下拉列表中 select "node choice 1" 时,该选项 "node choice 1" 不能再次被 selected另一个节点。但是,如果用户删除节点,或在节点文本上设置空 selection,则 "node choice 1" 必须再次可用。
link 也是如此。
我认为我的代码适用于 links,但我在检测节点文本更改和更新 dataModel 内容时遇到问题。
我之前好像错过了这个。下面是一些代码,通过实现它来回答您的问题:
function init() {
var $ = go.GraphObject.make;
myDiagram =
$(go.Diagram, "myDiagramDiv",
{
initialContentAlignment: go.Spot.Center,
"undoManager.isEnabled": true,
"ModelChanged": function(e) { // just for demonstration purposes,
if (e.isTransactionFinished) { // show the model data in the page's TextArea
document.getElementById("mySavedModel").textContent = e.model.toJson();
}
if (e.change === go.ChangedEvent.Remove) {
if (e.modelChange === "linkDataArray") {
var linkdata = e.oldValue;
var oldstr = linkdata.text;
if (!oldstr) return;
var linkchoices = e.model.modelData.linkchoices;
var idx = linkchoices.indexOf(oldstr);
if (idx < 0) {
console.log("deletion adding link choice: " + oldstr);
var newlinkchoices = Array.prototype.slice.call(linkchoices);
newlinkchoices.push(oldstr);
e.model.set(e.model.modelData, "linkchoices", newlinkchoices);
}
} else if (e.modelChange === "nodeDataArray") {
var nodedata = e.oldValue;
var oldstr = nodedata.text;
if (!oldstr) return;
var nodechoices = e.model.modelData.nodechoices;
var idx = nodechoices.indexOf(oldstr);
if (idx < 0) {
console.log("deletion adding node choice: " + oldstr);
var newnodechoices = Array.prototype.slice.call(nodechoices);
newnodechoices.push(oldstr);
e.model.set(e.model.modelData, "nodechoices", newnodechoices);
}
}
}
}
});
myDiagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape,
{ fill: "white", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer" },
new go.Binding("fill", "color")),
$(go.TextBlock,
{
margin: 8,
editable: true,
textEditor: window.TextEditorSelectBox, // defined in extensions/textEditorSelectBox.js
textEdited: function(tb, oldstr, newstr) {
if (oldstr !== newstr) {
console.log("changing from " + oldstr + " to " + newstr);
var model = tb.diagram.model;
var nodechoices = model.modelData.nodechoices;
if (!nodechoices) {
nodechoices = [];
model.set(model.modelData, "nodechoices", nodechoices);
}
var idx = nodechoices.indexOf(newstr);
if (idx >= 0) {
console.log("removing node choice " + idx + ": " + newstr);
model.removeArrayItem(nodechoices, idx);
}
if (oldstr) {
console.log(" adding node choice " + oldstr);
model.addArrayItem(nodechoices, oldstr);
}
}
}
},
new go.Binding("text").makeTwoWay(),
new go.Binding("choices", "nodechoices").ofModel())
);
myDiagram.linkTemplate =
$(go.Link,
$(go.Shape),
$(go.Shape, { toArrow: "OpenTriangle" }),
$(go.TextBlock,
{
background: "white",
editable: true,
textEditor: window.TextEditorSelectBox, // defined in extensions/textEditorSelectBox.js
textEdited: function(tb, oldstr, newstr) {
if (oldstr !== newstr) {
console.log("changing from " + oldstr + " to " + newstr);
var model = tb.diagram.model;
var linkchoices = model.modelData.linkchoices;
if (!linkchoices) {
linkchoices = [];
model.set(model.modelData, "linkchoices", linkchoices);
}
var idx = linkchoices.indexOf(newstr);
if (idx >= 0) {
console.log("removing link choice " + idx + ": " + newstr);
model.removeArrayItem(linkchoices, idx);
}
if (oldstr) {
console.log(" adding link choice " + oldstr);
model.addArrayItem(linkchoices, oldstr);
}
}
}
},
new go.Binding("text").makeTwoWay(),
new go.Binding("choices", "linkchoices").ofModel())
);
myDiagram.model = new go.GraphLinksModel(
[
{ key: 1, text: "Alpha", color: "lightblue" },
{ key: 2, text: "Beta", color: "orange" },
{ key: 3, text: "Gamma", color: "lightgreen" },
{ key: 4, text: "Delta", color: "pink" }
],
[
{ from: 1, to: 2, text: "one" },
{ from: 1, to: 3, text: "two" },
{ from: 3, to: 4, text: "three" }
]);
myDiagram.model.set(myDiagram.model.modelData, "nodechoices", ["Epsilon"]);
myDiagram.model.set(myDiagram.model.modelData, "linkchoices", ["four"]);
}
我想为用户创建自定义选择下拉菜单以编辑节点和 link 文本。
到目前为止,我使用此代码使用户 select 节点和 links 文本 select 能够出现在下拉列表中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>State Chart</title>
<meta name="description" content="A finite state machine chart with editable and interactive features." />
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="{{url_for('static', filename='go.js')}}"></script>
<!-- custom text editors -->
<script src="{{url_for('static', filename='TextEditorSelectBox.js')}}"></script>
<script src="{{url_for('static', filename='TextEditorRadioButtons.js')}}"></script>
<script src="{{url_for('static', filename='TextEditorSelectBox.js')}}"></script>
<script src="{{url_for('static', filename='DataInspector.js')}}"></script>
<link href="https://gojs.net/latest/extensions/DataInspector.css" rel="stylesheet">
<link href="{{url_for('static', filename='DataInspector.css')}}" rel="stylesheet">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<style>
body {
overflow-x: hidden;
}
#wrapper {
padding-left: 0;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
#wrapper.toggled {
padding-left: 250px;
}
#sidebar-wrapper {
z-index: 1000;
position: fixed;
left: 250px;
width: 0;
height: 100%;
margin-left: -250px;
overflow-y: auto;
background: #000;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
#wrapper.toggled #sidebar-wrapper {
width: 250px;
}
#page-content-wrapper {
width: 100%;
position: absolute;
padding: 15px;
}
#wrapper.toggled #page-content-wrapper {
position: absolute;
margin-right: -250px;
}
/* Sidebar Styles */
.sidebar-nav {
position: absolute;
top: 0;
width: 250px;
margin: 0;
padding: 0;
list-style: none;
}
.sidebar-nav li {
text-indent: 20px;
line-height: 40px;
}
.sidebar-nav li a {
display: block;
text-decoration: none;
color: #999999;
}
.sidebar-nav li a:hover {
text-decoration: none;
color: #fff;
background: rgba(255, 255, 255, 0.2);
}
.sidebar-nav li a:active, .sidebar-nav li a:focus {
text-decoration: none;
}
.sidebar-nav>.sidebar-brand {
height: 65px;
font-size: 18px;
line-height: 60px;
}
.sidebar-nav>.sidebar-brand a {
color: #999999;
}
.sidebar-nav>.sidebar-brand a:hover {
color: #fff;
background: none;
}
@media(min-width:768px) {
#wrapper {
padding-left: 0;
}
#wrapper.toggled {
padding-left: 250px;
}
#sidebar-wrapper {
width: 0;
}
#wrapper.toggled #sidebar-wrapper {
width: 250px;
}
#page-content-wrapper {
padding: 20px;
position: relative;
}
#wrapper.toggled #page-content-wrapper {
position: relative;
margin-right: 0;
}
}
</style>
<script id="code">
var nodeChoices = ['choice 1', 'choice 2', 'choice 3', 'choice 4', 'choice 5'];
const originalNodeChoices = ['choice 1', 'choice 2', 'choice 3', 'choice 4', 'choice 5'];
var linkChoices = ['link choice 1', 'link choice 2', 'link choice 3', 'link choice 4', 'link choice 5'];
const originalLinkChoices = ['link choice 1', 'link choice 2', 'link choice 3', 'link choice 4', 'link choice 5'];
function init() {
var $ = go.GraphObject.make;
myDiagram =
$(go.Diagram, "myDiagramDiv", // must name or refer to the DIV HTML element
{
// start everything in the middle of the viewport
initialContentAlignment: go.Spot.Center,
// have mouse wheel events zoom in and out instead of scroll up and down
"toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom,
// support double-click in background creating a new node
"clickCreatingTool.archetypeNodeData": { text: "new node" },
// enable undo & redo
"textEditingTool.defaultTextEditor": window.TextEditorSelectBox,
"undoManager.isEnabled": true,
"layout": new go.ForceDirectedLayout(),
"ModelChanged": function(e) {
//console.log("Diagram model changed!");
if (e.change === go.ChangedEvent.Remove && e.modelChange === "linkDataArray") {
console.log("eee its linkDataArray");
console.log(e);
var linkdata = e.oldValue;
console.log("linkdata");
console.log(linkdata);
var oldstr = linkdata.text;
console.log("oldstr");
console.log(oldstr);
if (!oldstr) return;
var customModelData = e.model.modelData.choices;
var choices = e.model.modelData.choices.linkChoices;
console.log("choices");
console.log(choices);
var idx = choices.indexOf(oldstr);
if (idx < 0) {
console.log("adding choice: " + oldstr);
var newchoices = Array.prototype.slice.call(choices);
newchoices.push(oldstr);
e.model.set(e.model.modelData, "choices", newchoices);
}
}else if(e.change === go.ChangedEvent.Remove && e.modelChange === "nodeDataArray"){
console.log("eee its nodeDataArray");
}
/*
else{
console.log("elseeeeeee111!");
console.log("e.change");
console.log(e.change);
console.log("e.modelChange");
console.log(e.modelChange);
}*/
}
});
//myDiagram.model.set(myDiagram.model.modelData, "choices", JSON.parse('{{ link_choices | tojson | safe}}'));
//myDiagram.model.set(myDiagram.model.modelData, "choices", ["one", "two", "three"]);
console.log("myDiagram.model.modelData");
console.log(myDiagram.model.modelData);
console.log("myDiagram.model.modelData.choices");
console.log(myDiagram.model.modelData.choices);
// when the document is modified, add a "*" to the title and enable the "Save" button
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("textEdited", function(e) {
console.log("Text is edited");
console.log(e);
//CHECK IF LINK,
//IF YES REMOVE THAT OPTION FROM LIST
});
myDiagram.addDiagramListener("SelectionDeleting", function(e) {
console.log("inside SelectionDeleting");
console.log(e);
//CHECK IF LINK,
//IF YES PUT THAT OPTION BACK IN OPTION LIST
});
// define the Node template
myDiagram.nodeTemplate =
$(go.Node, "Auto",
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
// define the node's outer shape, which will surround the TextBlock
$(go.Shape, "RoundedRectangle",
{
parameter1: 20, // the corner has a large radius
fill: $(go.Brush, "Linear", { 0: "rgb(254, 201, 0)", 1: "rgb(254, 162, 0)" }),
stroke: null,
portId: "", // this Shape is the Node's port, not the whole Node
fromLinkable: true, fromLinkableDuplicates: true,
toLinkable: true, toLinkableDuplicates: true,
cursor: "pointer"
}),
$(go.TextBlock,
{
font: "bold 11pt helvetica, bold arial, sans-serif",
editable: true, // editing the text automatically updates the model data
//textEditor: window.TextEditorRadioButtons, // defined in textEditorRadioButtons.js
// this specific TextBlock has its own choices:
textEditor: window.TextEditorRadioButtons,
textEdited: function(tb, oldstr, newstr) {
console.log("textEdited nodeeeeeeeeeeeeeeeeeeeeeeeee!!!");
var choices = tb.diagram.model.modelData.choices.nodeChoices;
console.log("choices");
console.log(choices);
console.log("newstr");
console.log(newstr);
console.log("oldstr");
console.log(oldstr);
var idx = choices.indexOf(newstr);
if (idx >= 0 && oldstr !== newstr ) {
console.log(choices);
console.log("choices");
console.log(choices);
console.log("removing choice " + idx + ": " + newstr);
var newchoices = Array.prototype.slice.call(choices);
newchoices.splice(idx, 1);
console.log("after remove");
console.log(newchoices);
var currentChoicesFromModel = tb.diagram.model.modelData.choices;
console.log("currentChoicesFromModel");
console.log(currentChoicesFromModel);
currentChoicesFromModel.nodeChoices = newchoices;
console.log("currentChoicesFromModel after update: ");
console.log(currentChoicesFromModel);
tb.diagram.model.set(tb.diagram.model.modelData, "choices", currentChoicesFromModel);
//tb.editable = false; // don't allow choice again
}else{
console.log("elseeeeee");
}
},
//choices: JSON.parse('{{ choices | tojson | safe}}')
choices: nodeChoices
},
new go.Binding("text").makeTwoWay())
);
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",
{ // 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: "?????", 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" })
)
)
);
//myDiagram.model.set(myDiagram.model.modelData, "choices", JSON.parse('{{ link_choices | tojson | safe}}'));
//myDiagram.model.set(myDiagram.model.modelData, "choices", ["one", "two", "three"]);
console.log("myDiagram.model.modelData");
console.log(myDiagram.model.modelData);
console.log(myDiagram.model.modelData.choices);
function editText(e, button) {
//console.log(e);
var node = button.part.adornedPart;
console.log("node");
//console.log(node);
e.diagram.commandHandler.editTextBlock(node.findObject("TEXTBLOCK"));
//$("#nodeText").val(node.findObject("TEXTBLOCK"));
}
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
};
// replace the default Link template in the linkTemplateMap
myDiagram.linkTemplate =
$(go.Link, // the whole link panel
{
curve: go.Link.Bezier,
adjusting: go.Link.Stretch,
reshapable: true,
relinkableFrom: true,
relinkableTo: true,
toShortLength: 3
},
new go.Binding("points").makeTwoWay(),
new go.Binding("curviness"),
$(go.Shape, // the link shape
{ strokeWidth: 1.5 }),
$(go.Shape, // the arrowhead
{ toArrow: "standard", stroke: null }),
$(go.Panel, "Auto",
$(go.Shape, // the label background, which becomes transparent around the edges
{
fill: $(go.Brush, "Radial", { 0: "rgb(240, 240, 240)", 0.3: "rgb(240, 240, 240)", 1: "rgba(240, 240, 240, 0)" }),
stroke: null
}),
$(go.TextBlock,
{
background: "white",
editable: true,
textEditor: window.TextEditorSelectBox, // defined in extensions/textEditorSelectBox.js
textEdited: function(tb, oldstr, newstr) {
var choices = tb.diagram.model.modelData.choices.linkChoices;
console.log("choices");
console.log(choices);
console.log("newstr");
console.log(newstr);
console.log("oldstr");
console.log(oldstr);
var idx = choices.indexOf(newstr);
if (idx >= 0 && oldstr !== newstr ) {
console.log(choices);
console.log("choices");
console.log(choices);
console.log("removing choice " + idx + ": " + newstr);
var newchoices = Array.prototype.slice.call(choices);
newchoices.splice(idx, 1);
tb.diagram.model.set(tb.diagram.model.modelData.choices.linkChoices, "choices", newchoices);
//tb.editable = false; // don't allow choice again
}else{
console.log("elseeeeee");
}
}
},
// editing the text automatically updates the model data
//new go.Binding("text"),
new go.Binding("text").makeTwoWay(),
new go.Binding("choices").ofModel())
)
);
var inspector = new Inspector('myInspectorDiv', myDiagram,
{
// uncomment this line to only inspect the named properties below instead of all properties on each object:
// includesOwnProperties: false,
properties: {
"text": { },
// an example of specifying the type
"password": { show: Inspector.showIfPresent, type: 'password' },
// key would be automatically added for nodes, but we want to declare it read-only also:
"key": { readOnly: true, show: Inspector.showIfPresent },
// color would be automatically added for nodes, but we want to declare it a color also:
"color": { show: Inspector.showIfPresent, type: 'color' },
// Comments and LinkComments are not in any node or link data (yet), so we add them here:
"Comments": { show: Inspector.showIfNode },
"flag": { show: Inspector.showIfNode, type: 'checkbox' },
"LinkComments": { show: Inspector.showIfLink },
"isGroup": { readOnly: true, show: Inspector.showIfPresent }
}
});
// read in the JSON data from flask
loadGraphData();
}
function loadGraphData() {
var graphDataString = JSON.parse('{{ diagramData | tojson | safe}}');
//console.log("graphDataString");
//console.log(graphDataString);
var allChoices = JSON.parse('{{ allChoices | tojson | safe}}');
console.log("allChoices");
console.log(allChoices);
myDiagram.model = go.Model.fromJson(graphDataString);
//myDiagram.model.set(myDiagram.model.modelData, "choices", ["one", "two", "three"]);
var customModelData = {
"linkChoices": linkChoices, "nodeChoices": nodeChoices
};
myDiagram.model.set(myDiagram.model.modelData, "choices", allChoices);
//myDiagram.model.set(myDiagram.model.modelData, "choices", JSON.parse('{{ link_choices | tojson | safe}}'));
//myDiagram.model.set(myDiagram.model.modelData, "choices", customModelData);
console.log("whole model modelData");
console.log(myDiagram.model.modelData);
}
function saveGraphData(form, event) {
console.log("inside saveGraphData");
event.preventDefault();
document.getElementById("mySavedModel").value = myDiagram.model.toJson();
form.submit();
}
function zoomToFit(){
console.log("inside zoomToFit");
myDiagram.zoomToRect(myDiagram.documentBounds);
}
function zoomIn(){
console.log("inside zoomIn");
myDiagram.commandHandler.increaseZoom();
}
function zoomOut(){
console.log("inside zoomOut");
myDiagram.commandHandler.decreaseZoom();
}
</script>
</head>
<body onload="init()">
<div id="wrapper">
<!-- Sidebar -->
<div id="sidebar-wrapper">
<ul class="sidebar-nav">
<li class="sidebar-brand"> <a href="#"> CUSTOM CHOICES MODE </a> </li>
<li> <a href="{{ url_for('main') }}">Free editing mode</a> </li>
<li> <a href="{{ url_for('graphMode1') }}">Fill mode</a> </li>
<li> <a href="{{ url_for('graphMode2') }}">Custom choices mode</a> </li>
<li> <a href="{{ url_for('graphMode3') }}">Locked choices mode</a> </li>
</ul>
</div>
<!-- /#sidebar-wrapper -->
<!-- Page Content -->
<div id="page-content-wrapper">
<div class="container-fluid">
<div id=formWrapper style="padding: 30px;">
<a href="#menu-toggle" class="btn btn-secondary" id="menu-toggle" style="margin-bottom: 15px;">Toggle Menu</a>
<form method="POST" action="http://localhost:5000/updateResultFile" name="updateResultFileForm"
id="updateResultFileForm"
onsubmit="saveGraphData(this, event);">
<div id="graphWrapper" style="margin-bottom: 15px;">
<div id="myDiagramDiv" style="border: solid 1px black; width: 100%; height: 800px;margin-bottom: 15px;"></div>
<div style="display: none;"><input id="mySavedModel" name="mySavedModel"></div>
<button class="btn btn-default" type="submit"> Save <i class="fa fa-save"> </i> </button>
</div>
</form>
<div id="myInspectorDiv">
</div>
<div>
<button class="btn btn-default" onclick="zoomToFit()"> Zoom to fit <i class="fa fa-search"> </i> </button>
<button class="btn btn-default" onclick="zoomIn()"> Zoom in <i class="fa fa-search-plus"> </i> </button>
<button class="btn btn-default" onclick="zoomOut()"> Zoom out <i class="fa fa-search-minus"> </i> </button>
</div>
</div>
</div>
</div>
</div>
<script src="{{url_for('static', filename='jquery.min.js')}}"></script>
<script src="{{url_for('static', filename='bootstrap.bundle.min.js')}}"></script>
<!-- Menu Toggle Script -->
<script>
var menuOpen = false;
$("#menu-toggle").click(function(e) {
e.preventDefault();
$("#wrapper").toggleClass("toggled");
if(menuOpen){
menuOpen = false;
$("#myDiagramDiv").css({border: "solid 1px black"});
}else{
menuOpen = true;
$("#myDiagramDiv").css({border: ""});
}
});
</script>
</body>
</html>
所以基本上我已经为节点和 links 做出了自定义选择。例如,对于节点,我有以下选择:
- 节点选择 1
- 节点选择2
- 节点选择3
对于 links 我有这些选择:
- link选择1
- link选择2
- link选择3
我想要完成的是,当我从一个节点上的下拉列表中 select "node choice 1" 时,该选项 "node choice 1" 不能再次被 selected另一个节点。但是,如果用户删除节点,或在节点文本上设置空 selection,则 "node choice 1" 必须再次可用。
link 也是如此。
我认为我的代码适用于 links,但我在检测节点文本更改和更新 dataModel 内容时遇到问题。
我之前好像错过了这个。下面是一些代码,通过实现它来回答您的问题:
function init() {
var $ = go.GraphObject.make;
myDiagram =
$(go.Diagram, "myDiagramDiv",
{
initialContentAlignment: go.Spot.Center,
"undoManager.isEnabled": true,
"ModelChanged": function(e) { // just for demonstration purposes,
if (e.isTransactionFinished) { // show the model data in the page's TextArea
document.getElementById("mySavedModel").textContent = e.model.toJson();
}
if (e.change === go.ChangedEvent.Remove) {
if (e.modelChange === "linkDataArray") {
var linkdata = e.oldValue;
var oldstr = linkdata.text;
if (!oldstr) return;
var linkchoices = e.model.modelData.linkchoices;
var idx = linkchoices.indexOf(oldstr);
if (idx < 0) {
console.log("deletion adding link choice: " + oldstr);
var newlinkchoices = Array.prototype.slice.call(linkchoices);
newlinkchoices.push(oldstr);
e.model.set(e.model.modelData, "linkchoices", newlinkchoices);
}
} else if (e.modelChange === "nodeDataArray") {
var nodedata = e.oldValue;
var oldstr = nodedata.text;
if (!oldstr) return;
var nodechoices = e.model.modelData.nodechoices;
var idx = nodechoices.indexOf(oldstr);
if (idx < 0) {
console.log("deletion adding node choice: " + oldstr);
var newnodechoices = Array.prototype.slice.call(nodechoices);
newnodechoices.push(oldstr);
e.model.set(e.model.modelData, "nodechoices", newnodechoices);
}
}
}
}
});
myDiagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape,
{ fill: "white", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer" },
new go.Binding("fill", "color")),
$(go.TextBlock,
{
margin: 8,
editable: true,
textEditor: window.TextEditorSelectBox, // defined in extensions/textEditorSelectBox.js
textEdited: function(tb, oldstr, newstr) {
if (oldstr !== newstr) {
console.log("changing from " + oldstr + " to " + newstr);
var model = tb.diagram.model;
var nodechoices = model.modelData.nodechoices;
if (!nodechoices) {
nodechoices = [];
model.set(model.modelData, "nodechoices", nodechoices);
}
var idx = nodechoices.indexOf(newstr);
if (idx >= 0) {
console.log("removing node choice " + idx + ": " + newstr);
model.removeArrayItem(nodechoices, idx);
}
if (oldstr) {
console.log(" adding node choice " + oldstr);
model.addArrayItem(nodechoices, oldstr);
}
}
}
},
new go.Binding("text").makeTwoWay(),
new go.Binding("choices", "nodechoices").ofModel())
);
myDiagram.linkTemplate =
$(go.Link,
$(go.Shape),
$(go.Shape, { toArrow: "OpenTriangle" }),
$(go.TextBlock,
{
background: "white",
editable: true,
textEditor: window.TextEditorSelectBox, // defined in extensions/textEditorSelectBox.js
textEdited: function(tb, oldstr, newstr) {
if (oldstr !== newstr) {
console.log("changing from " + oldstr + " to " + newstr);
var model = tb.diagram.model;
var linkchoices = model.modelData.linkchoices;
if (!linkchoices) {
linkchoices = [];
model.set(model.modelData, "linkchoices", linkchoices);
}
var idx = linkchoices.indexOf(newstr);
if (idx >= 0) {
console.log("removing link choice " + idx + ": " + newstr);
model.removeArrayItem(linkchoices, idx);
}
if (oldstr) {
console.log(" adding link choice " + oldstr);
model.addArrayItem(linkchoices, oldstr);
}
}
}
},
new go.Binding("text").makeTwoWay(),
new go.Binding("choices", "linkchoices").ofModel())
);
myDiagram.model = new go.GraphLinksModel(
[
{ key: 1, text: "Alpha", color: "lightblue" },
{ key: 2, text: "Beta", color: "orange" },
{ key: 3, text: "Gamma", color: "lightgreen" },
{ key: 4, text: "Delta", color: "pink" }
],
[
{ from: 1, to: 2, text: "one" },
{ from: 1, to: 3, text: "two" },
{ from: 3, to: 4, text: "three" }
]);
myDiagram.model.set(myDiagram.model.modelData, "nodechoices", ["Epsilon"]);
myDiagram.model.set(myDiagram.model.modelData, "linkchoices", ["four"]);
}