I am using the regrouping example to explore this. I would like to be able to place items where I like so I have changed the diagram to use Layout instead of GridLayout. When I drop a node into a group the group repositions to wrap the node where I drop it. I would like to change that behaviour so the group expands to right and downwards to accommodate the node. This would mean the top left of the group stays where it was and the node would be repositioned within the placeholder as happens when a second node is dropped into the group. Do you have any suggestions on how to achieve this?
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GoJS expt</title>
<meta charset="UTF-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/gojs/1.8.9/go-debug.js"></script>
<script id="code">
function init() {
var $ = go.GraphObject.make;
myDiagram =
$(go.Diagram, "myDiagramDiv",
{
allowDrop: true, // from Palette
// what to do when a drag-drop occurs in the Diagram's background
mouseDrop: function(e) { finishDrop(e, null); },
layout: // Diagram has simple horizontal layout
$(go.Layout),
initialContentAlignment: go.Spot.Center,
"commandHandler.archetypeGroupData": { isGroup: true, category: "OfNodes" },
"undoManager.isEnabled": true
});
// There are two templates for Groups, "OfGroups" and "OfNodes".
// this function is used to highlight a Group that the selection may be dropped into
function highlightGroup(e, grp, show) {
if (!grp) return;
e.handled = true;
if (show) {
// cannot depend on the grp.diagram.selection in the case of external drag-and-drops;
// instead depend on the DraggingTool.draggedParts or .copiedParts
var tool = grp.diagram.toolManager.draggingTool;
var map = tool.draggedParts || tool.copiedParts; // this is a Map
// now we can check to see if the Group will accept membership of the dragged Parts
if (grp.canAddMembers(map.toKeySet())) {
grp.isHighlighted = true;
return;
}
}
grp.isHighlighted = false;
}
// Upon a drop onto a Group, we try to add the selection as members of the Group.
// Upon a drop onto the background, or onto a top-level Node, make selection top-level.
// If this is OK, we're done; otherwise we cancel the operation to rollback everything.
function finishDrop(e, grp) {
var ok = (grp !== null
? grp.addMembers(grp.diagram.selection, true)
: e.diagram.commandHandler.addTopLevelParts(e.diagram.selection, true));
if (!ok) e.diagram.currentTool.doCancel();
}
myDiagram.groupTemplateMap.add("OfGroups",
$(go.Group, "Auto",
{
background: "transparent",
// highlight when dragging into the Group
mouseDragEnter: function(e, grp, prev) { highlightGroup(e, grp, true); },
mouseDragLeave: function(e, grp, next) { highlightGroup(e, grp, false); },
computesBoundsAfterDrag: true,
// when the selection is dropped into a Group, add the selected Parts into that Group;
// if it fails, cancel the tool, rolling back any changes
mouseDrop: finishDrop,
handlesDragDropForMembers: true, // don't need to define handlers on member Nodes and Links
// Groups containing Groups lay out their members horizontally
layout:
$(go.GridLayout,
{ wrappingWidth: Infinity, alignment: go.GridLayout.Position,
cellSize: new go.Size(1, 1), spacing: new go.Size(4, 4) })
},
new go.Binding("background", "isHighlighted", function(h) { return h ? "rgba(255,0,0,0.2)" : "transparent"; }).ofObject(),
$(go.Shape, "Rectangle",
{ fill: null, stroke: "#FFDD33", strokeWidth: 2 }),
$(go.Panel, "Vertical", // title above Placeholder
$(go.Panel, "Horizontal", // button next to TextBlock
{ stretch: go.GraphObject.Horizontal, background: "#FFDD33" },
$("SubGraphExpanderButton",
{ alignment: go.Spot.Right, margin: 5 }),
$(go.TextBlock,
{
alignment: go.Spot.Left,
editable: true,
margin: 5,
font: "bold 18px sans-serif",
opacity: 0.75,
stroke: "#404040"
},
new go.Binding("text", "text").makeTwoWay())
), // end Horizontal Panel
$(go.Placeholder,
{ padding: 5, alignment: go.Spot.TopLeft })
) // end Vertical Panel
)); // end Group and call to add to template Map
myDiagram.groupTemplateMap.add("OfNodes",
$(go.Group, "Auto",
{
background: "transparent",
ungroupable: true,
// highlight when dragging into the Group
mouseDragEnter: function(e, grp, prev) { highlightGroup(e, grp, true); },
mouseDragLeave: function(e, grp, next) { highlightGroup(e, grp, false); },
computesBoundsAfterDrag: true,
// when the selection is dropped into a Group, add the selected Parts into that Group;
// if it fails, cancel the tool, rolling back any changes
mouseDrop: finishDrop,
handlesDragDropForMembers: true, // don't need to define handlers on member Nodes and Links
// Groups containing Nodes lay out their members vertically
layout:
$(go.GridLayout,
{ wrappingColumn: 1, alignment: go.GridLayout.Position,
cellSize: new go.Size(1, 1), spacing: new go.Size(4, 4) })
},
new go.Binding("background", "isHighlighted", function(h) { return h ? "rgba(255,0,0,0.2)" : "transparent"; }).ofObject(),
$(go.Shape, "Rectangle",
{ fill: null, stroke: "#33D3E5", strokeWidth: 2 }),
$(go.Panel, "Vertical", // title above Placeholder
$(go.Panel, "Horizontal", // button next to TextBlock
{ stretch: go.GraphObject.Horizontal, background: "#33D3E5" },
$("SubGraphExpanderButton",
{ alignment: go.Spot.Right, margin: 5 }),
$(go.TextBlock,
{
alignment: go.Spot.Left,
editable: true,
margin: 5,
font: "bold 16px sans-serif",
opacity: 0.75,
stroke: "#404040"
},
new go.Binding("text", "text").makeTwoWay())
), // end Horizontal Panel
$(go.Placeholder,
{ padding: 5, alignment: go.Spot.TopLeft })
) // end Vertical Panel
)); // end Group and call to add to template Map
myDiagram.nodeTemplate =
$(go.Node, "Auto",
{ // dropping on a Node is the same as dropping on its containing Group, even if it's top-level
mouseDrop: function(e, nod) { finishDrop(e, nod.containingGroup); }
},
$(go.Shape, "Rectangle",
{ fill: "#ACE600", stroke: null },
new go.Binding("fill", "color")),
$(go.TextBlock,
{
margin: 5,
editable: true,
font: "bold 13px sans-serif",
opacity: 0.75,
stroke: "#404040"
},
new go.Binding("text", "text").makeTwoWay())
);
// initialize the Palette and its contents
myPalette =
$(go.Palette, "myPaletteDiv",
{
nodeTemplateMap: myDiagram.nodeTemplateMap,
groupTemplateMap: myDiagram.groupTemplateMap,
layout: $(go.GridLayout, { wrappingColumn: 1, alignment: go.GridLayout.Position })
});
myPalette.model = new go.GraphLinksModel([
{ text: "lightgreen", color: "#ACE600" },
{ text: "yellow", color: "#FFDD33" },
{ text: "lightblue", color: "#33D3E5" }
]);
load();
}
function load() {
myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
}
</script>
</head>
<body onload="init()">
<h1>Based on Regrouping Demo but using Layout instead of GridLayout</h1>
<div id="sample">
<div style="width: 100%; display: flex; justify-content: space-between">
<div id="myPaletteDiv" style="width: 100px; margin-right: 2px; background-color: whitesmoke; border: solid 1px black"></div>
<div id="myDiagramDiv" style="flex-grow: 1; height: 500px; border: solid 1px black"></div>
</div>
<p>
Dragging A into the group makes the group reposition higher up to wrap where the node is dropped.
</p>
<textarea id="mySavedModel" style="width:100%;height:300px">
{ "class": "go.GraphLinksModel",
"nodeDataArray": [
{"key":1, "text":"Main 1", "isGroup":true, "category":"OfGroups"},
{"text":"A", "key":-7}
],
"linkDataArray": [ ]}
</textarea>
</div>
</body>
</html>