You can do either or both of the solutions that you suggest.
For a custom resize Adornment, you can specify three properties on Part: Part.resizable, Part.resizeObjectName, and Part.resizeAdornmentTemplate:
function nodeStyle() {
return [
// The Node.location comes from the "loc" property of the node data,
// converted by the Point.parse static method.
// If the Node.location is changed, it updates the "loc" property of the node data,
// converting back using the Point.stringify static method.
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
{
// the Node.location is at the center of each node
locationSpot: go.Spot.Center,
//isShadowed: true,
//shadowColor: "#888",
// handle mouse enter/leave events to show/hide the ports
mouseEnter: function (e, obj) { showPorts(obj.part, true); },
mouseLeave: function (e, obj) { showPorts(obj.part, false); },
resizable: true,
resizeObjectName: "BOX",
resizeAdornmentTemplate:
$(go.Adornment, "Spot",
$(go.Placeholder),
$(go.Shape, { alignment: go.Spot.TopLeft, desiredSize: new go.Size(8, 8), fill: "lightblue", stroke: "dodgerblue", cursor: "nw-resize" }),
$(go.Shape, { alignment: go.Spot.TopRight, desiredSize: new go.Size(8, 8), fill: "lightblue", stroke: "dodgerblue", cursor: "ne-resize" }),
$(go.Shape, { alignment: go.Spot.BottomRight, desiredSize: new go.Size(8, 8), fill: "lightblue", stroke: "dodgerblue", cursor: "se-resize" }),
$(go.Shape, { alignment: go.Spot.BottomLeft, desiredSize: new go.Size(8, 8), fill: "lightblue", stroke: "dodgerblue", cursor: "sw-resize" })
)
}
];
}
Note how Part.resizeObjectName needs to refer to the GraphObject that you want the user to resize, so in this case you need to give “BOX” as the name of the “Auto” Panel in each template. For example:
myDiagram.nodeTemplateMap.add("", // the default category
$(go.Node, "Spot", nodeStyle(),
// the main object is a Panel that surrounds a TextBlock with a rectangular Shape
$(go.Panel, "Auto",
{ name: "BOX" },
$(go.Shape, "Rectangle",
{ fill: "#00A9C9", stroke: null },
new go.Binding("figure", "figure")),
$(go.TextBlock,
. . .
To move the ports to be on the outside of the box, just change the makePort function to use the opposite Spot for the alignmentFocus:
alignment: spot, alignmentFocus: spot.opposite(), // align the port on the main Shape
Because the nodes are then bigger, you’ll want to move them apart a bit. Also, you’ll want to change the showPorts function to use “gray” instead of “white” so that the ports can be seen against the white background.