goJS lock nodes - javascript

I have simple python flask app where I send JSON data to my HTML and with goJS I display my graph which looks like this:
Users can add new nodes and links, but what I want is that starting graph is locked so that users can not edit or delete any nodes or links from that starting graph. I just want that they can add new nodes and links and link it to starting graph nodes.
I really tried to search for this specific case but I haven't found what I am looking for. In documentation there are some options like disabling whole diagram or set it to read only, but that is not what I need. There are some mentions that you can make specific user permissions, but there is not any examples provided, so I need help.
Here is my code:
<!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="https://cdnjs.cloudflare.com/ajax/libs/gojs/1.7.27/go.js"></script>
<script src="https://gojs.net/latest/extensions/TextEditorRadioButtons.js"></script>
<script src="https://gojs.net/latest/extensions/TextEditorSelectBox.js"></script>
<script src="https://gojs.net/latest/extensions/DataInspector.js"></script>
<link href="https://gojs.net/latest/extensions/DataInspector.css" rel="stylesheet">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script id="code">
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
"undoManager.isEnabled": true,
"layout": new go.ForceDirectedLayout()
});
// 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);
}
});
// 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:
//choices: ['One', 'Two', 'Three', 'Four']
},
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" })
)
)
);
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, "?????", // the label text
{
textAlign: "center",
font: "9pt helvetica, arial, sans-serif",
margin: 4,
editable: true // enable in-place editing
},
// editing the text automatically updates the model data
new go.Binding("text").makeTwoWay())
)
);
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);
myDiagram.model = go.Model.fromJson(graphDataString);
}
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=formWrapper style="padding: 30px;">
<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>
</body>
</html>
Any help will be appreciated

Yes, that documentation page about user permissions, https://gojs.net/latest/intro/permissions.html, should give you an answer.
I'm guessing that you don't want to disable all deletions by setting Diagram.allowDelete to false, or to disable all in-place text editing by setting Diagram.allowTextEdit to false. Instead you probably want to prevent deleting or editing the original nodes and links but not any newly created nodes or links. Is that right?
If so, you can set or bind Part.deletable and Part.textEditable to false on all those original Nodes and Links. You can do that in an "InitialLayoutCompleted" DiagramEvent listener. For example in a Diagram initialization:
$(go.Diagram, . . .,
{ . . .,
"InitialLayoutCompleted": function(e) {
e.diagram.nodes.each(function(n) { n.deletable = false; n.textEditable = false; });
e.diagram.links.each(function(l) { l.deletable = false; l.textEditable = false; });
},
. . .
})
Of course you wouldn't need to set Link.textEditable to false if you didn't have any editable text labels in your Links, but you do seem to.

Related

DiagramListener not being called?

I am trying to capture TreeExpanded and TreeCollapsed events, but the respective listeners are not being called. I have implemented the listeners as follows:
myDiagram.addDiagramListener("TreeExpanded", function(e) {
console.log(">>>>> STUFF HAPPENED in TreeExpanded");
});
myDiagram.addDiagramListener("TreeCollapsed", function(e) {
console.log(">>>>> STUFF HAPPENED in TreeCollapsed");
});
The full code for myDiagram looks like this:
myDiagram = $(go.Diagram, "myDiagramDiv",
{
"undoManager.isEnabled": true,
layout: $(go.TreeLayout),
"ChangedSelection": onSelectionChanged
});
function geoFunc(geoname) {
var geo = icons[geoname];
if (geo === undefined) geo = icons["heart"]; // use this for an unknown icon name
if (typeof geo === "string") {
geo = icons[geoname] = go.Geometry.parse(geo, true); // fill each geometry
}
return geo;
}
myDiagram.nodeTemplate =
$(go.Node, "Auto",
{isTreeExpanded:false},
{doubleClick: function(e, node) {node.expandTree(1);}},
$(go.Shape, "Rectangle",
{ strokeWidth: 2, stroke: colors["gray"], },
new go.Binding("fill", "color")),
$(go.TextBlock, {stroke:"black",font:"12pt sans-serif",margin:3,wrap: go.TextBlock.WrapDesiredSize},new go.Binding("text", "geo"))
);
// Define a Link template that routes orthogonally, with no arrowhead
myDiagram.linkTemplate =
$(go.Link,
{ routing: go.Link.Orthogonal, corner: 5, toShortLength: -2, fromShortLength: -2 },
$(go.Shape, { strokeWidth: 2, stroke: colors["gray"] })); // the link shape
myDiagram.addDiagramListener("TreeExpanded", function(e) {
console.log(">>>>> STUFF HAPPENED in TreeExpanded");
});
myDiagram.addDiagramListener("TreeCollapsed", function(e) {
console.log(">>>>> STUFF HAPPENED in TreeCollapsed");
});
// Create the model data that will be represented by Nodes and Links
myDiagram.model = new go.GraphLinksModel(
[
How do I detect when a node tree is expanded or collapsed, then call a function?
Calling Node.collapseTree or Node.expandTree is a relatively low-level operation. Your doubleClick event handler doesn't conduct a transaction (but any change should) nor does it raise any events such as "TreeExpanded" DiagramEvent.
Instead call, CommandHandler.expandTree or CommandHandler.collapseTree. E.g.:
{
doubleClick: function(e, node) {
e.diagram.commandHandler.expandTree(node);
}
},

how to pass data from api to gojs TreeModel

I am not bale to display links using GOJS and TreeModel. I am able to create nodes but not links.
I am thinking this is related to the fact GOJS uses a data array as opposed to json.
var $ = go.GraphObject.make;
var myDiagram =
$(go.Diagram, "myDiagramDiv",
{
"undoManager.isEnabled": true, // enable Ctrl-Z to undo and Ctrl-Y to redo
layout: $(go.TreeLayout, // specify a Diagram.layout that arranges trees
{ angle: 90, layerSpacing: 35 })
});
// the template we defined earlier
myDiagram.nodeTemplate =
$(go.Node, "Horizontal",
{ background: "#44CCFF" },
$(go.Picture,
{ margin: 10, width: 50, height: 50, background: "red" },
new go.Binding("source")),
$(go.TextBlock, "Default Text",
{ margin: 12, stroke: "white", font: "bold 16px sans-serif" },
new go.Binding("text", "name"))
);
var model = $(go.TreeModel);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "/api/Employees/", false);
xmlhttp.send();
var nodeArray = JSON.parse(xmlhttp.responseText);
//model = nodeArray;
myDiagram.model.nodeDataArray = nodeArray;
//myDiagram.model = model;
If you check the console window, you will see this error message:
Error: ParentKey value for node data [object Object] is not a number or a string: null
That is because you set:
"parent": null
in one of your node data objects. I suggest that you remove that property.
I also suggest that you use the go-debug.js library instead of the go.js library, because the Debug version of the library will detect and warn you about more problems than the regular version of the library.

goJS dropdown for link text

I have simple python flask app where I send JSON data to my HTML and with goJS I display my graph which looks like this:
I want to make custom choices dropdown for users to edit node and link text. So far, I used this code to make nodes text selectable in dropdown list:
<!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='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">
<script id="code">
var nodeChoices = ['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'];
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()
});
// 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,
//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" })
)
)
);
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, // the label text
{
textAlign: "center",
font: "12pt helvetica, arial, sans-serif",
margin: 4,
editable: true, // enable in-place editing
textEditor: window.TextEditorRadioButtons,
//choices: JSON.parse('{{ choices | tojson | safe}}')
choices: linkChoices
},
// editing the text automatically updates the model data
new go.Binding("text").makeTwoWay())
)
);
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);
myDiagram.model = go.Model.fromJson(graphDataString);
}
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=formWrapper style="padding: 30px;">
<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>
</body>
</html>
And It looks like this:
It's all fine with node text, but I have problem with link text. I want when user selects one option that he can not use that option anymore on other link texts. Also I want to make when that link is deleted that that option is available again.
As you can see in code, I added 2 event listeners on my diagram (textEdited and SelectionDeleting) and they work fine when user is editing text or deleting something, but I don't know how to extract information about event object and its text.
I need to make sure it is link so I can remove or add that event object text in my choices list. Any help will be appreciated.
OK, let's assume that the list of choices for the link labels is held in the Model.modelData object. I'll name the property "choices", but of course you can use whatever name you like.
myDiagram.model.set(myDiagram.model.modelData, "choices", ["one", "two", "three"]);
Your Link template might look something like:
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) {
var choices = tb.diagram.model.modelData.choices;
var idx = choices.indexOf(newstr);
if (idx >= 0 && oldstr !== newstr) {
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", newchoices);
tb.editable = false; // don't allow choice again
}
}
},
new go.Binding("text"),
new go.Binding("choices").ofModel())
);
Note how the TextBlock.textEditor is defined to be a TextEditorSelectBox and the TextBlock.textEdited event handler is defined to set the modelData.choices property to be a new Array without the chosen string.
It also sets TextBlock.editable back to false so that the user cannot re-choose for that Link. That's one way to avoid problems with repeated edits; but you could implement your own policies. In retrospect I think the more likely policy would be to add the old value to and remove the new value from the modelData.choices Array.
Also, you'll want to implement a Model Changed listener that notices when Links have been removed from the model, so that you can add its choice back to the myDiagram.model.modelData.choices Array. In your Diagram initialization:
$(go.Diagram, . . .,
{
"ModelChanged": function(e) {
if (e.change === go.ChangedEvent.Remove && e.modelChange === "linkDataArray") {
var linkdata = e.oldValue;
var oldstr = linkdata.text;
if (!oldstr) return;
var choices = e.model.modelData.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);
}
}
}
})

How to add href inside node in Gojs?

I created a diagram with GoJS.
I need that every node will contain a href.
var template = GO(go.Node, "Auto", {
desiredSize: new go.Size(width, height)
},
GO(go.Shape, shapeMap.getValue(shape), new go.Binding("fill", "fill")),
GO(go.TextBlock, {
textAlign: 'center',
margin: 4
}, new go.Binding("stroke", "color"), new go.Binding("text", "text")));
var node = {
key: src,
color: textColor,
fill: backgroundColor,
category: shape,
text: "www.google.com"
};
diagram.model.addNodeData(node);
I tried to insert a Html content.
var node = {
key: src,
color: textColor,
fill: backgroundColor,
category: shape,
text: <a href='www.google.com'>href</a>
};
But it's not working. How can I do that?
A TextBlock does not render HTML, but just a string as a block of text.
If you put the URL in your node data, you can declare a GraphObject.click event handler that opens a window.
GO(go.Node, . . .
{
click: function(e, obj) {
window.open("http://" + encodeURIComponent(obj.part.data.url));
}
},
. . .
GO(go.TextBlock,
{ textAlign: "center", margin: 4 },
new go.Binding("stroke", "color"),
new go.Binding("text", "url"))
),
. . .
)
This is for node data such as:
{ url: "www.example.com" }
You can use a conversion function on the TextBlock.text binding to show a different string than the data.url property value.
It is also demonstrated by the sample at http://gojs.net/latest/samples/euler.html
Add click event to the TextBlock, and in the click function - open new web page.
GO(go.Node,...
GO(go.TextBlock,{textAlign: 'center', click: function(e, obj) {window.open(obj.part.data.url)}}),...);

Javascript assistance with Sigma.js

I'm trying to use Sigma.js. I'm really not a Javascript person but I can't get this to do even the most basic of things.
In the developer console I get the following -
Use of getPreventDefault() is deprecated. Use defaultPrevented instead.
Is that what is causing my problem or is there something wrong with my bit of HTML/ Javascript?
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>The HTML5 Herald</title>
<meta name="description" content="Sigmas Graph Example">
<meta name="author" content="Dave">
<script type="text/javascript" src="sigma.min.js"></script>
</head>
<body>
<script>
function myFunction()
{
var sigRoot = document.getElementById('sig');
var sigInst = sigma.init(sigRoot);
sigInst.addNode('hello',{
label: 'Hello',
color: '#ff0000'
}).addNode('world',{
label: 'World !',
color: '#00ff00'
}).addEdge('hello_world','hello','world').draw();
}
if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', myFunction, false);
} else {
window.onload = myFunction;
}
</script>
<div id="sig"></div>
<button onclick="myFunction()">Try it</button>
</body>
</html>
Thanks
Yes, there are a few tricks to getting the sigma rendering canvas initialized.
A few things to note:
You add edges and nodes to the "graph" attribute of the sigma instance, not the instance itself.
You need to specify an x and y for each node.
Each node is a javascript object which should have and 'id', 'x', and 'y', and optionally 'color', and optionally other data associated with the node.
Similarly for edges, each edge should have an 'id', 'source', and 'target'
After adding edges and/or nodes, you need to call sigInst.refresh(), not draw()
There are myriad options you can set with an "options" object when creating the instance.
You need to set the size of the target div, or else you won't be able to see anything (at least on Chrome).
So, here is a working version based on your script above. You will also note in the docs there are other methods for bulk import of nodes and edges, such as graph.read().
<div id="sig" style="width: 800px; height: 600px;"></div>
<button onclick="myFunction()">Try it</button>
<script>
function myFunction()
{
var settings = {
defaultNodeColor: '#ec5148',
defaulLabelColor: '#99f',
defaultEdgeColor: '#aaa',
edgeColor: "default",
labelSizeRatio: "1",
labelThreshold: 1,
};
var sigInst = new sigma({
container: 'sig',
settings: settings
});
sigInst.graph.addNode({
id: 'hello',
label: 'Hello',
color: '#ff0000',
size: 5,
x:0,
y:0
});
sigInst.graph.addNode({
id: 'world',
label: 'World !',
color: '#00ff00',
size: 10,
x:1,
y:1
});
sigInst.graph.addEdge({
id: "helloworld",
source: "hello",
target: "world",
});
sigInst.refresh();
}
if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', myFunction, false);
} else {
window.onload = myFunction;
}
</script>
Hope that helps.

Categories