I think it’s expected to see the same diagram as the saved one, but in my case they are not the same. Please, take a look at the screen shots attached.
Before:
After:
What should we do to overcome this issue?
I think it’s expected to see the same diagram as the saved one, but in my case they are not the same. Please, take a look at the screen shots attached.
Before:
After:
What should we do to overcome this issue?
First, do all of your Nodes have a TwoWay Binding on Node.location?
Second, do you not set Diagram.layout, or do you set the layout but disable automatic layout on initialization by setting Layout.isInitial to false?
Could you tell me, please, what’s wrong with the following code that produced 2 different diagrams above?
var red = "orangered"; // 0 or false
var green = "forestgreen"; // 1 or true
var blue = "blue";
var aqua = "aqua";
var white = "white";
var dollarbill = "#85BB65";
var myDiagram;
function initElectricalShema() {
//if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this
var $ = go.GraphObject.make; // for conciseness in defining templates
myDiagram =
$(go.Diagram, "myDiagramDiv", // create a new Diagram in the HTML DIV element "myDiagramDiv"
{
//initialContentAlignment: go.Spot.Center,
allowDrop: true, // Nodes from the Palette can be dropped into the Diagram
//"draggingTool.isGridSnapEnabled": true, // dragged nodes will snap to a grid of 10x10 cells
"undoManager.isEnabled": true
});
//myDiagram.model = go.Model.fromJson("{ \"class\": \"go.GraphLinksModel\", \"nodeDataArray\": [], \"linkDataArray\": []}");
//myDiagram.model = go.Model.fromJson("{ \"class\": \"go.GraphLinksModel\", \"nodeDataArray\": [ {\"category\":\"input\", \"key\":-1, \"loc\":\"-111.45001220703125 -39.91667175292969\"} ], \"linkDataArray\": []}");
myDiagram.requestUpdate();
// when the document is modified, add a "*" to the title and enable the "Save" button
myDiagram.addDiagramListener("Modified", function (e) {
var button = document.getElementById("saveModel");
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);
}
});
var palette = new go.Palette("palette"); // create a new Palette in the HTML DIV element "palette"
// creates relinkable Links that will avoid crossing Nodes when possible and will jump over other Links in their paths
myDiagram.linkTemplate =
$(go.Link,
{
//routing: go.Link.AvoidsNodes,
//curve: go.Link.JumpOver,
//corner: 3,
relinkableFrom: true, relinkableTo: true,
selectionAdorned: false, // Links are not adorned when selected so that their color remains visible.
shadowOffset: new go.Point(0, 0), shadowBlur: 5, shadowColor: "blue"
},
new go.Binding("isShadowed", "isSelected").ofObject(),
$(go.Shape,
{ name: "SHAPE", strokeWidth: 2, stroke: red }));
// node template helpers
var sharedToolTip =
$(go.Adornment, "Auto",
$(go.Shape, "RoundedRectangle", { fill: "lightyellow" }),
$(go.TextBlock, { margin: 2 },
new go.Binding("text", "", function (d) { return d.category; })));
// define some common property settings
function nodeStyle() {
return [new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
new go.Binding("isShadowed", "isSelected").ofObject(),
{
selectionAdorned: false,
shadowOffset: new go.Point(0, 0),
shadowBlur: 15,
shadowColor: "blue",
toolTip: sharedToolTip
}];
}
function shapeStyle1() {
return {
name: "NODESHAPE",
fill: "lightgray",
stroke: "darkslategray",
desiredSize: new go.Size(40, 40),
strokeWidth: 2
};
}
function shapeStyle2() {
return {
name: "NODESHAPE1",
fill: "aqua",
stroke: "yellow",
desiredSize: new go.Size(40, 40),
strokeWidth: 2
};
}
function shapeStyle3() {
return {
name: "NODESHAPE2",
fill: "dollarbill",
stroke: "darkgreen",
desiredSize: new go.Size(10, 40),
strokeWidth: 2
};
}
function shapeStyle4() {
return {
name: "NODESHAPE3",
fill: "green",
stroke: "green",
desiredSize: new go.Size(1, 4),
strokeWidth: 2
};
}
function shapeStyle5() {
return {
name: "NODESHAPE4",
fill: "green",
stroke: "green",
desiredSize: new go.Size(1, 10),
strokeWidth: 2
};
}
function portStyle(input) {
return {
desiredSize: new go.Size(6, 6),
fill: "black",
fromSpot: go.Spot.Right,
fromLinkable: !input,
toSpot: go.Spot.Left,
toLinkable: input,
toMaxLinks: 2,
cursor: "pointer"
};
}
function portStyle1(input) {
return {
desiredSize: new go.Size(2, 2),
fill: "green",
//fromSpot: go.Spot.Center,
fromLinkable: input,
//toSpot: go.Spot.Center,
toLinkable: !input,
toMaxLinks: 2,
cursor: "pointer"
};
}
function portStyle2(input) {
return {
desiredSize: new go.Size(2, 2),
fill: "green",
//fromSpot: go.Spot.Center,
fromLinkable: !input,
//toSpot: go.Spot.Center,
toLinkable: input,
toMaxLinks: 2,
cursor: "pointer"
};
}
// define templates for each type of node
var inputTemplate =
$(go.Node, "Spot",
//{ guid: "12345" },
//new go.Binding("guid", "number"),
nodeStyle(),
$(go.Shape, "Circle", shapeStyle1(),
{ fill: red }), // override the default fill (from shapeStyle1()) to be red
$(go.Shape, "Rectangle", portStyle(false), // the only port
{ portId: "", alignment: new go.Spot(1, 0.5) }),
{ // if double-clicked, an input node will change its value, represented by the color.
doubleClick: function (e, obj) {
//e.diagram.startTransaction("Toggle Input");
//var shp = obj.findObject("NODESHAPE");
//shp.fill = (shp.fill === green) ? red : green;
//updateStates();
//e.diagram.commitTransaction("Toggle Input");
window.open("http://www.microsoft.com", "_blank");
}}
);
var outputTemplate =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Rectangle", shapeStyle1(),
{ fill: green }), // override the default fill (from shapeStyle1()) to be green
$(go.Shape, "Rectangle", portStyle(true), // the only port
{ portId: "", alignment: new go.Spot(0, 0.5) })
//{
// doubleclick: function (e, node) {
// window.open("http://www.microsoft.com", "_blank");
// }
//}
);
var andTemplate =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "AndGate", shapeStyle1()),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in1", alignment: new go.Spot(0, 0.3) }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in2", alignment: new go.Spot(0, 0.7) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(1, 0.5) })
);
var orTemplate =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "OrGate", shapeStyle1()),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in1", alignment: new go.Spot(0.16, 0.3) }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in2", alignment: new go.Spot(0.16, 0.7) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(1, 0.5) })
);
var xorTemplate =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "XorGate", shapeStyle1()),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in1", alignment: new go.Spot(0.26, 0.3) }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in2", alignment: new go.Spot(0.26, 0.7) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(1, 0.5) })
);
var norTemplate =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "NorGate", shapeStyle1()),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in1", alignment: new go.Spot(0.16, 0.3) }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in2", alignment: new go.Spot(0.16, 0.7) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(1, 0.5) })
);
var xnorTemplate =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "XnorGate", shapeStyle1()),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in1", alignment: new go.Spot(0.26, 0.3) }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in2", alignment: new go.Spot(0.26, 0.7) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(1, 0.5) })
);
var nandTemplate =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "NandGate", shapeStyle1()),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in1", alignment: new go.Spot(0, 0.3) }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in2", alignment: new go.Spot(0, 0.7) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(1, 0.5) })
);
var notTemplate =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Inverter", shapeStyle1()),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in", alignment: new go.Spot(0, 0.5) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(1, 0.5) })
);
var custom1Template =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Rectangle", shapeStyle2(),
{ fill: blue }), // override the default fill (from shapeStyle1()) to be green
$(go.Shape, "Rectangle", portStyle(true), // the only port
{ portId: "", alignment: new go.Spot(0, 0.5) })
);
var custom2Template =
$(go.Node, "Vertical",
$(go.Shape, "Circle", shapeStyle1(),
{ fill: white }), // override the default fill (from shapeStyle1()) to be green
$(go.Shape, "Rectangle", shapeStyle4(),
{ fill: green }), // override the default fill (from shapeStyle1()) to be green
$(go.Shape, "Rectangle", shapeStyle3(),
{ fill: dollarbill }, // override the default fill (from shapeStyle1()) to be green
{ visible: false }),
$(go.Shape, "Rectangle", shapeStyle5(),
{ fill: green }), // override the default fill (from shapeStyle1()) to be green
$(go.Shape, "Rectangle", portStyle1(true), // the only port
{ portId: "" }),
$(go.Shape, "Rectangle", portStyle2(true), // the only port
{ portId: "" }),
{ // if double-clicked, an input node will change its value, represented by the color.
doubleClick: function (e, obj) {
//e.diagram.startTransaction("Toggle Input");
//var shp = obj.findObject("NODESHAPE");
//shp.fill = (shp.fill === green) ? red : green;
//updateStates();
//e.diagram.commitTransaction("Toggle Input");
window.open("http://www.microsoft.com", "_blank");
}
}
);
// add the templates created above to myDiagram and palette
myDiagram.nodeTemplateMap.add("input", inputTemplate);
myDiagram.nodeTemplateMap.add("output", outputTemplate);
myDiagram.nodeTemplateMap.add("and", andTemplate);
myDiagram.nodeTemplateMap.add("or", orTemplate);
myDiagram.nodeTemplateMap.add("xor", xorTemplate);
myDiagram.nodeTemplateMap.add("not", notTemplate);
myDiagram.nodeTemplateMap.add("nand", nandTemplate);
myDiagram.nodeTemplateMap.add("nor", norTemplate);
myDiagram.nodeTemplateMap.add("xnor", xnorTemplate);
myDiagram.nodeTemplateMap.add("custom1", custom1Template);
myDiagram.nodeTemplateMap.add("custom2", custom2Template);
// share the template map with the Palette
palette.nodeTemplateMap = myDiagram.nodeTemplateMap;
palette.model.nodeDataArray = [
{ category: "input" },
{ category: "output" },
{ category: "and" },
{ category: "or" },
{ category: "xor" },
{ category: "not" },
{ category: "nand" },
{ category: "nor" },
{ category: "xnor" },
{ category: "custom1" },
{ category: "custom2" }
];
// load the initial diagram
load();
// continually update the diagram
loop();
}
// update the diagram every 250 milliseconds
function loop() {
setTimeout(function () { updateStates(); loop(); }, 250);
}
// update the value and appearance of each node according to its type and input values
function updateStates() {
var oldskip = myDiagram.skipsUndoManager;
myDiagram.skipsUndoManager = true;
// do all "input" nodes first
myDiagram.nodes.each(function (node) {
if (node.category === "input") {
doInput(node);
}
});
// now we can do all other kinds of nodes
myDiagram.nodes.each(function (node) {
switch (node.category) {
case "and": doAnd(node); break;
case "or": doOr(node); break;
case "xor": doXor(node); break;
case "not": doNot(node); break;
case "nand": doNand(node); break;
case "nor": doNor(node); break;
case "xnor": doXnor(node); break;
case "output": doOutput(node); break;
case "custom1": doCustom1(node); break;
case "custom2": doCustom2(node); break;
case "input": break; // doInput already called, above
}
});
myDiagram.skipsUndoManager = oldskip;
}
// helper predicate
function linkIsTrue(link) { // assume the given Link has a Shape named "SHAPE"
return link.findObject("SHAPE").stroke === green;
}
// helper function for propagating results
function setOutputLinks(node, color) {
node.findLinksOutOf().each(function (link) { link.findObject("SHAPE").stroke = color; });
}
// update nodes by the specific function for its type
// determine the color of links coming out of this node based on those coming in and node type
function doInput(node) {
// the output is just the node's Shape.fill
setOutputLinks(node, node.findObject("NODESHAPE").fill);
}
function doAnd(node) {
var color = node.findLinksInto().all(linkIsTrue) ? green : red;
setOutputLinks(node, color);
}
function doNand(node) {
var color = !node.findLinksInto().all(linkIsTrue) ? green : red;
setOutputLinks(node, color);
}
function doNot(node) {
var color = !node.findLinksInto().all(linkIsTrue) ? green : red;
setOutputLinks(node, color);
}
function doOr(node) {
var color = node.findLinksInto().any(linkIsTrue) ? green : red;
setOutputLinks(node, color);
}
function doNor(node) {
var color = !node.findLinksInto().any(linkIsTrue) ? green : red;
setOutputLinks(node, color);
}
function doXor(node) {
var truecount = 0;
node.findLinksInto().each(function (link) { if (linkIsTrue(link)) truecount++; });
var color = truecount % 2 === 0 ? green : red;
setOutputLinks(node, color);
}
function doXnor(node) {
var truecount = 0;
node.findLinksInto().each(function (link) { if (linkIsTrue(link)) truecount++; });
var color = truecount % 2 !== 0 ? green : red;
setOutputLinks(node, color);
}
function doOutput(node) {
// assume there is just one input link
// we just need to update the node's Shape.fill
node.linksConnected.each(function (link) { node.findObject("NODESHAPE").fill = link.findObject("SHAPE").stroke; });
}
function doCustom1(node) {
// assume there is just one input link
// we just need to update the node's Shape.fill
node.linksConnected.each(function (link) { node.findObject("NODESHAPE1").fill = link.findObject("SHAPE").stroke; });
}
function doCustom2(node) {
// assume there is just one input link
// we just need to update the node's Shape.fill
node.linksConnected.each(function (link) { node.findObject("NODESHAPE1").fill = link.findObject("SHAPE").stroke; });
}
// save a model to and load a model from JSON text, displayed below the Diagram
function save() {
document.getElementById("mySavedModel").value = myDiagram.model.toJson();
//alert(myDiagram.model.toJson());
myDiagram.isModified = false;
}
function load() {
myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
}
I don’t see a Node.location Binding on your custom2 template.
We really cannot debug your code for you.
We resolved this issue. I’ve found one of my custom node templates without nodeStyle() where was placed:
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify)