According to the official example https://gojs.net/latest/samples/draggableLink.html, the nodeStyle of the example https://gojs.net/latest/samples/roundedGroups.html is used.
However, there is a problem:
When dragging a graph from the palette to the diagram, you can find that both nodeDataArray and linkDataArray have new records, but the connection cannot be displayed immediately, and you must refresh the page to do so.
When comparing the code to the example on the official website, I think the problem lies in the nodeTemplate, because my code differs from the key code of the example https://gojs.net/latest/samples/draggableLink.html only in the nodeTemplate but I still cannot figure out how to fix it for my specific case.
Does anyone know how I can solve this issue or have any insight on how to debug it? (see code below for reference)
<!DOCTYPE html>
<html>
<body>
<div id="myDiagramDiv" style="width:1920px;height:1080px;">
</div>
<script th:src="@{/nengli/js/go-debug.js?version=2.3.13}"></script>
<script th:src="@{/nengli/js/Figures.js?version=2.3.13}"></script>
<script th:src="@{/nengli/js/RoundedRectangles.js?version=2.3.13}"></script>
<script th:inline="javascript">
$(function () {
init();
});
</script>
<script th:inline="javascript">
$('#myPaletteDiv').width($('#myPaletteDiv').width())
$('#myPaletteDiv').height($(this).height())
$('#myDiagramDiv').width($('#myDiagramDiv').width())
$('#myDiagramDiv').height($(this).height())
let myDiagram = null;
let myPalette = null;
// diagram init
function init() {
const $diagram = go.GraphObject.make; // for conciseness in defining templates
myDiagram =
new go.Diagram("myDiagramDiv", // must name or refer to the DIV HTML element
{
grid: $diagram(go.Panel, "Grid",
$diagram(go.Shape, "LineH", {stroke: "lightgray", strokeWidth: 0.5}),
$diagram(go.Shape, "LineH", {stroke: "gray", strokeWidth: 0.5, interval: 10}),
$diagram(go.Shape, "LineV", {stroke: "lightgray", strokeWidth: 0.5}),
$diagram(go.Shape, "LineV", {stroke: "gray", strokeWidth: 0.5, interval: 10})
),
"undoManager.isEnabled": true,
layout:
$diagram(go.TreeLayout,
{angle: 90, arrangement: go.TreeLayout.ArrangementFixedRoots}),
}
)
;
// when the document is modified, add a "*" to the title and enable the "Save" button
myDiagram.addDiagramListener("Modified", e => {
const title = window.title;
const idx = title.text().indexOf("*");
if (myDiagram.isModified) {
if (idx < 0) title.text(title.text() + "*");
console.log("save")
} else {
if (idx >= 0) title.text(title.text().slice(0, idx));
}
});
myDiagram.addModelChangedListener(evt => {
// ignore unimportant Transaction events
if (!evt.isTransactionFinished) return;
var txn = evt.object; // a Transaction
if (txn === null) return;
// iterate over all of the actual ChangedEvents of the Transaction
txn.changes.each(e => {
// ignore any kind of change other than adding/removing a node
// if (e.modelChange !== "nodeDataArray") return;
if (e.modelChange === "nodeDataArray") {
// record node insertions and removals
if (e.change === go.ChangedEvent.Insert) {
console.log(evt.propertyName + " added node with key: " + e.newValue.key);
} else if (e.change === go.ChangedEvent.Remove) {
console.log(evt.propertyName + " removed node with key: " + e.oldValue.key);
}
}
if (e.change === go.ChangedEvent.Property) {
if (e.modelChange === "linkFromKey") {
console.log(evt.propertyName + " changed From key of link: " +
e.object + " from: " + e.oldValue + " to: " + e.newValue);
} else if (e.modelChange === "linkToKey") {
console.log(evt.propertyName + " changed To key of link: " +
e.object + " from: " + e.oldValue + " to: " + e.newValue);
} else if (e.propertyName === "text") {
console.log(evt.propertyName + " changed property name: " + e.newValue);
}
} else if (e.change === go.ChangedEvent.Insert && e.modelChange === "linkDataArray") {
console.log(evt.propertyName + " added link: " + e.newValue);
} else if (e.change === go.ChangedEvent.Remove && e.modelChange === "linkDataArray") {
console.log(evt.propertyName + " removed link: " + e.oldValue);
}
});
});
// this simple template does not have any buttons to permit adding or
// removing properties or methods, but it could!
myDiagram.nodeTemplate =
$diagram(go.Node, "Vertical",
{
defaultStretch: go.GraphObject.Horizontal,
fromLinkable: true,
toLinkable: true,
},
$diagram(go.Panel, "Auto", {fromLinkable: false, toLinkable: false},
$diagram(go.Shape, "RoundedTopRectangle",
{fill: "white"},
new go.Binding("_symbolId", "symboldId").makeTwoWay()),
$diagram(go.TextBlock,
{margin: new go.Margin(2, 2, 0, 2), textAlign: "center"},
new go.Binding("text", "header").makeTwoWay()),
makePort("T", go.Spot.Top, false, true),
),
$diagram(go.Panel, "Auto",
{minSize: new go.Size(NaN, 70), fromLinkable: false, toLinkable: false},
$diagram(go.Shape, "Rectangle", {fill: "white"}),
$diagram(go.TextBlock,
{width: 120},
{margin: new go.Margin(2, 2, 0, 2), textAlign: "center", editable: false},
new go.Binding("text", "text").makeTwoWay()),
makePort("L", go.Spot.Left, true, true),
makePort("R", go.Spot.Right, true, true),
),
$diagram(go.Panel, "Auto", {fromLinkable: false, toLinkable: false},
$diagram(go.Shape, "RoundedBottomRectangle",
{fill: "white"},
new go.Binding("fill", "role", r => r[0] === 'b' ? "lightgray" : "white")),
$diagram(go.TextBlock,
{margin: new go.Margin(2, 2, 0, 2), textAlign: "center"},
new go.Binding("text", "footer").makeTwoWay()),
makePort("B", go.Spot.Bottom, true, false),
),
{ // handle mouse enter/leave events to show/hide the ports
mouseEnter: (e, node) => showSmallPorts(node, true),
mouseLeave: (e, node) => showSmallPorts(node, false)
},
{
contextMenu: // define a context menu for each node
$diagram("ContextMenu", // that has one button
$diagram("ContextMenuButton",
$diagram(go.TextBlock, "打开面板"),
{click: contextMenuClick})
// more ContextMenuButtons would go here
) // end Adornment
}
);
// 工具箱
myPalette =
$diagram(go.Palette, "myPaletteDiv", // must name or refer to the DIV HTML element
{
// Instead of the default animation, use a custom fade-down
"contextMenuTool.isEnabled": false,
"animationManager.initialAnimationStyle": go.AnimationManager.None,
"InitialAnimationStarting": animateFadeDown, // Instead, animate with this function
nodeTemplateMap: myDiagram.nodeTemplateMap, // share the templates used by myDiagram
// model: ),
initialScale: .7
});
const linkSelectionAdornmentTemplate =
$diagram(go.Adornment, "Link",
$diagram(go.Shape,
// isPanelMain declares that this Shape shares the Link.geometry
{isPanelMain: true, fill: null, stroke: "deepskyblue", strokeWidth: 0}) // use selection object's strokeWidth
);
myDiagram.linkTemplate =
$diagram(go.Link, // the whole link panel
{selectable: true, selectionAdornmentTemplate: linkSelectionAdornmentTemplate},
{relinkableFrom: true, relinkableTo: true, reshapable: true},
{
routing: go.Link.AvoidsNodes,
curve: go.Link.JumpOver,
corner: 5,
toShortLength: 4
},
new go.Binding("points").makeTwoWay(),
$diagram(go.Shape, // the link path shape
{isPanelMain: true, strokeWidth: 2}),
$diagram(go.Shape, // the arrowhead
{toArrow: "Standard", stroke: null}),
$diagram(go.Panel, "Auto",
new go.Binding("visible", "isSelected").ofObject(),
$diagram(go.Shape, "RoundedRectangle", // the link shape
{fill: "#F8F8F8", stroke: null}),
$diagram(go.TextBlock,
{
textAlign: "center",
font: "10pt helvetica, arial, sans-serif",
stroke: "#919191",
margin: 2,
minSize: new go.Size(10, NaN),
editable: true
},
new go.Binding("text").makeTwoWay())
)
);
function contextMenuClick(e, obj) {
myDiagram.commit(function (d) {
// get the context menu that holds the button that was clicked
const contextmenu = obj.part;
// get the node data to which the Node is data bound
const nodedata = contextmenu.data;
// compute the next color for the node
console.log(contextmenu);
console.log(nodedata);
openNodePropPanel(nodedata);
}, "Open modelDialog");
}
// 当鼠标移动到节点时显示/隐藏锚点
function showSmallPorts(node, show) {
node.ports.each(function (port) {
port.fill = show ? "rgba(255,0,0,.5)" : null;
});
}
function makePort(name, spot, output, input) {
// the port is basically just a small transparent square
return $diagram(go.Shape, "Circle",
{
fill: null, // not seen, by default; set to a translucent gray by showSmallPorts, defined below
stroke: null,
desiredSize: new go.Size(7, 7),
alignment: spot, // align the port on the main Shape
alignmentFocus: spot, // just inside the Shape
portId: name, // declare this object to be a "port"
fromSpot: spot, toSpot: spot, // declare where links may connect at this port
fromLinkable: output, toLinkable: input, // declare whether the user may draw links to/from here
fromLinkableDuplicates: false, toLinkableDuplicates: false,
fromMaxLinks: 1, toMaxLinks: 1,
cursor: "pointer" // show a different cursor to indicate potential link point
});
}
function animateFadeDown(e) {
var diagram = e.diagram;
var animation = new go.Animation();
animation.isViewportUnconstrained = true; // So Diagram positioning rules let the animation start off-screen
animation.easing = go.Animation.EaseOutExpo;
animation.duration = 900;
// Fade "down", in other words, fade in from above
animation.add(diagram, 'position', diagram.position.copy().offset(0, 200), diagram.position);
animation.add(diagram, 'opacity', 0, 1);
animation.start();
}
load();
} // end init
function load() {
}
}
</script>
</body>
</html>