It sounds like you want a customized ClickCreatingTool.
Except for the custom cursor, it’s easy to set up what you want.
First, set ClickCreatingTool.isDoubleClick to false in your main/target Diagram.
Second, when in that special mode, set ClickCreatingTool.archetypeNodeData to the JavaScript Object that you want to be copied as the node data object for a new node that that tool inserts when the user clicks in the background of the diagram.
And I think you want to set the Diagram.currentCursor and Diagram.defaultCursor to a cursor that shows an image of the node to be created.
Here’s a sample that uses a Palette instead of plain HTML. But I hope the ideas are clear:
<!DOCTYPE html>
<html>
<head>
<title>Minimal GoJS Editor</title>
<!-- Copyright 1998-2023 by Northwoods Software Corporation. -->
</head>
<body>
<div style="width: 100%; display: flex; justify-content: space-between">
<div style="display: flex; flex-direction: column; margin: 0 2px 0 0">
<div id="myPaletteDiv" style="flex-grow: 1; width: 100px; background-color: floralwhite; border: solid 1px black"></div>
</div>
<div id="myDiagramDiv" style="flex-grow: 1; height: 400px; border: solid 1px black"></div>
</div>
<script src="go.js"></script>
<script id="code">
const $ = go.GraphObject.make;
// initialize main Diagram
const myDiagram =
$(go.Diagram, "myDiagramDiv",
{
"undoManager.isEnabled": true,
"clickCreatingTool.isDoubleClick": false,
"ModelChanged": e => myPalette.clearSelection() // disable click from inserting a new node
});
myDiagram.nodeTemplate =
$(go.Node, "Auto",
{ locationSpot: go.Spot.Center },
new go.Binding("location", "location", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape,
{
fill: "white", stroke: "gray", strokeWidth: 2,
portId: "", cursor: "pointer", fromLinkable: true, toLinkable: true,
},
new go.Binding("stroke", "color")),
$(go.TextBlock,
{
margin: new go.Margin(5, 5, 3, 5),
minSize: new go.Size(16, 16), maxSize: new go.Size(120, NaN),
editable: true
},
new go.Binding("text").makeTwoWay())
);
// initialize Palette
const myPalette =
$(go.Palette, "myPaletteDiv",
{
nodeTemplateMap: myDiagram.nodeTemplateMap,
"ChangedSelection": e => {
const node = e.diagram.selection.first();
if (node) {
const imgdata = e.diagram.makeImageData({ parts: new go.List().add(node) });
myDiagram.currentCursor = myDiagram.defaultCursor = `url(${imgdata})`;
myDiagram.toolManager.clickCreatingTool.archetypeNodeData = node.data;
} else {
myDiagram.currentCursor = myDiagram.defaultCursor = "";
myDiagram.toolManager.clickCreatingTool.archetypeNodeData = null;
}
},
model: new go.GraphLinksModel([
{ text: "red node", color: "red" },
{ text: "green node", color: "green" },
{ text: "blue node", color: "blue" },
{ text: "orange node", color: "orange" }
])
});
myDiagram.model = new go.GraphLinksModel({
"nodeDataArray": [
{"key":1, "text":"hello", "color":"green", "location":"0 0"},
{"key":2, "text":"world", "color":"red", "location":"70 0"}
],
"linkDataArray": [
{"from":1, "to":2}
]
});
</script>
</body>
</html>
Alas, the cursor code shown above doesn’t work, even though I know the data URL produced by Diagram.makeImageData is correct. But if instead of “url(…)” as the cursor I just use “crosshair” as the cursor, everything works as expected. I don’t have time right now to investigate this.