I made a copy of samples/minimal.html and modified its JavaScript, as follows:
[code] function init() {
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, “myDiagram”, // create a Diagram for the DIV HTML element
{
initialContentAlignment: go.Spot.Center, // center the content
“undoManager.isEnabled”: true // enable undo & redo
});
var tool = myDiagram.toolManager.linkingTool;
tool.doActivate = function() {
go.LinkingTool.prototype.doActivate.call(tool);
// turn all port strokes to be either green or red depending on whether isValidLink is true
myDiagram.skipsUndoManager = true;
var startport = tool.startPort;
var startnode = startport.part;
myDiagram.nodes.each(function(node) {
node.ports.each(function(port) {
if (tool.isForwards) {
port.stroke = tool.isValidLink(startnode, startport, node, port) ? “green” : “red”;
} else {
port.stroke = tool.isValidLink(node, port, startnode, startport) ? “green” : “red”;
}
});
});
myDiagram.skipsUndoManager = false;
};
tool.doDeactivate = function() {
go.LinkingTool.prototype.doDeactivate.call(tool);
// restore all ports to normal color, here assumed to be black
myDiagram.skipsUndoManager = true;
myDiagram.nodes.each(function(node) {
node.ports.each(function(port) {
port.stroke = “black”;
});
});
myDiagram.skipsUndoManager = false;
};
// define a simple Node template
myDiagram.nodeTemplate =
$(go.Node, "Auto", // the Shape will go around the TextBlock
$(go.Shape, "RoundedRectangle",
<font color="#ff0000"> { portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer" },
{ strokeWidth: 3 },</font>
// Shape.fill is bound to Node.data.color
new go.Binding("fill", "color")),
$(go.TextBlock,
{ margin: 3 }, // some room around the text
// TextBlock.text is bound to Node.data.key
new go.Binding("text", "key"))
);
// but use the default Link template, by not setting Diagram.linkTemplate
// create the model data that will be represented by Nodes and Links
myDiagram.model = new go.GraphLinksModel(
[
{ key: "Alpha", color: "lightblue" },
{ key: "Beta", color: "orange" },
{ key: "Gamma", color: "lightgreen" },
{ key: "Delta", color: "pink" }
],
[
]);
}[/code]
First I turned the node’s Shape into a port and made them interactively linkable. I also removed all of the predefined link data in the model.
Second I decided to use the port’s stroke to show whether it’s OK to link with that port. To make it easier to see, I set the strokeWidth to 3. Valid ports’s strokes would turn green, invalid would turn red. Of course you may have other ways of showing this information.
Third I modified the LinkingTool, myDiagram.toolManager.linkingTool. This is JavaScript, so I just clobbered that particular tool in order to override the doActivate and doDeactivate methods, but you could have defined a subclass of LinkingTool. (There are several examples of this in the samples; I recommend you also read: http://gojs.net/latest/intro/extensions.html, if you haven’t already.)
You can see the overrides in the code above. Each iterates over all of the ports of all of the nodes in the diagram. Although usually new links are drawn “from” to “to”, in some situations they are drawn “backwards”, which is why there are two calls to isValidLink.
Regarding your additional question about showing WHY a link would be invalid, it would be easy for you to show a tooltip or some temporary Adornment in an override of doMouseMove when the mouse is over an invalid port (or when it isn’t over or near any valid port, if you like), but it isn’t clear to me what you would say. I suspect that information is too application-specific for me to speculate about.