Full control on node location

Hi,
I have a set of nodes, some are grouped and some are not.
I want to have full control on the node location.
I binded the “postion” to “loc” and when the diagram is run the nodes are located exactly on the “loc” value.
But when i expand one of the group and then collapse it, the nodes loose their original location although i run thru the nodes and restore their original location.
I have tried all options :
layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized,
diagram.layout.isOngoing = false;
diagram.layout.isIntial = false;
diagram.model.setDataProperty(nodeData, “loc”, nodeData.origLoc);
node.isLayoutPositioned = false;

But still the nodes shifted down to the middle of the diagram.
How can i have full control on node location and ignore any invalidation also when collapsing a group ?
Regards,
Tany

If you are manually setting the locations of nodes, you probably shouldn’t be using a layout at the Diagram level at all. If you remove the Diagram.layout, does it act as you’d expect?

I think i found the problem. The nodes in the group had the same “Y” loc values of their parent group. As soon as the group was expanded, the other group nodes moved a side, leaving space for the nodes within the expanded group.
So, when i changed the nodes “Y” axis loc to be under the groups, the group nodes didn’t move.
This leads to another question :
My application need to show a group of group nodes layered on the same “Y” value, namely on one line.
When collapsing one group, i want the other groups to become invisible and the nodes of the group to be shown exactly on the “same Y” axis of the groups.
If i set the exact “Y” value for the nodes in the group, the group nodes “move aside” (original question).
Any idea ?

diagram.contentAlignment = go.Spot.Top;

This one helped.

So have you resolved this? If you still need help, you should probably provide some sketches or screenshots of how you want your nodes/groups to look in different situations as it is hard to determine what you want based on just a description.

Still, there’s a minor problem.
When collapsing a group, all nodes restore their original location besides the group node itself which its location is shifted to left (X) some values.
this is the code :

var nodeDataArray = [ // a JavaScript Array of JavaScript objects, one per node;
// the “color” property is added specifically for this app
{ key: 1, source: “icons/takshal.jpg”, loc: “0 500”, minor:“3”, major: “7”, critical:"", isGroup: true},
{ key: 2, source: “icons/sz.jpg”, loc: “200 500”, minor:"", major: “3”, critical:“4”, isGroup: true },
{ key: 3, source: “icons/ve.jpg”, loc: “400 500”, minor:“1”, major: “”, critical:“12”, isGroup: true },
{ key: 4, source: “icons/t-mivzait.jpg”, loc: “600 500”, minor:"", major: “”, critical:"", isGroup: true },
{ key: 5, source: “icons/timsort.jpg”, loc: “800 500”, minor:“4”, major: “2”, critical:“7”, isGroup: true },
{ key: 51, source: “icons/timsort.jpg”, loc: “0 500”, minor:"", major: “”, critical:"", group: 5 },
{ key: 52, source: “icons/timsort.jpg”, loc: “200 500”, minor:“4”, major: “2”, critical:“7”, group: 5 },
{ key: 53, source: “icons/timsort.jpg”, loc: “400 500”, minor:"", major: “8”, critical:"", group: 5 },
{ key: 54, source: “icons/timsort.jpg”, loc: “600 500”, minor:“4”, major: “2”, critical:“7”, group: 5 },
{ key: 55, source: “icons/timsort.jpg”, loc: “800 500”, minor:"", major: “2”, critical:“3”, group: 5 },
{ key: 56, source: “icons/timsort.jpg”, loc: “1000 500”, minor:“2”, major: “”, critical:“3”, group: 5 },
{ key: 6, source: “icons/ozma-gvoah.jpg”, loc: “0 700”, minor:“2”, major: “2”, critical:“3”, isGroup: true },
{ key: 7, source: “icons/hayganim.jpg”, loc: “200 700”, minor:"", major: “”, critical:"", isGroup: true },
{ key: 8, source: “icons/afik-rahav.jpg”, loc: “400 700”, minor:“13”, major: “7”, critical:“1”, isGroup: true },
{ key: 9, source: “icons/telfonia-shchora.jpg”, loc: “600 700”, minor:“11”, major: “5”, critical:“8”, isGroup: true },
{ key: 10, source: “icons/telfonia-aduma.jpg”, loc: “800 700”, minor:“5”, major: “”, critical:"", isGroup: true }
];
var i;
for (i = 0; i < nodeDataArray.length; i++ )
nodeDataArray[i].origLoc = nodeDataArray[i].loc;
var linkDataArray = [];

var $ = go.GraphObject.make;

var diagram = new go.Diagram("myDiagramDiv");
//diagram.initialContentAlignment = go.Spot.Top;
diagram.contentAlignment = go.Spot.Center;
// enable Ctrl-Z to undo and Ctrl-Y to redo
//diagram.undoManager.isEnabled = true;
diagram.allowMove = false;


diagram.nodeTemplate =
        $(go.Node, "Auto", // the Shape automatically fits around the TextBlock
		{
		 // locationSpot: go.Spot.Center,
         // layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized
		},
         new go.Binding("visible"),
         new go.Binding("position", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
         //$(go.Shape, "Rectangle", { fill: "transparent" } ),  // end Auto Panel body
         nodeTemplate()
);

diagram.groupTemplate =
        $(go.Group, "Vertical",
                new go.Binding("visible"),
                new go.Binding("position", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                {
                    isSubGraphExpanded: false,
                   // layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized,
                    // layout: $(go.TreeLayout, { isInitial:false, angle: 90, arrangement: go.TreeLayout.ArrangementHorizontal } /* isOngoing:false */)
                    //layout: $(go.GridLayout),

                    subGraphExpandedChanged: function(group) {
                        diagram.startTransaction("graph");
                         if (group.isSubGraphExpanded === false ) {
                            // collapse
                             //diagram.layout.isOngoing = true;
                             //diagram.layout.isIntial = false;
                             var groupData = diagram.model.findNodeDataForKey(group.data.key);
                             diagram.model.setDataProperty(groupData, "groupVisible", true);  // restore the original location of the group
                             for (i = 0;  i < diagram.model.nodeDataArray.length; i++ ) {
                                 var node = diagram.findNodeForKey(diagram.model.nodeDataArray[i].key);
                               //  node.isLayoutPositioned = false;
                                 var nodeData = diagram.model.findNodeDataForKey(diagram.model.nodeDataArray[i].key);
                                 diagram.model.setDataProperty(nodeData, "visible", true);
                                 diagram.model.setDataProperty(nodeData, "loc", nodeData.origLoc);

                             }
                         }
                         else {
                              // expand
                             var it = group.memberParts;
                             while (it.next()) {
                                 var node = it.value;
                                 var nodeData = diagram.model.findNodeDataForKey(node.data.key);
                                 diagram.model.setDataProperty(nodeData, "loc", nodeData.origLoc);  // restore the original location of the group
                             }
                             var groupData = diagram.model.findNodeDataForKey(group.data.key);
                             diagram.model.setDataProperty(groupData, "groupVisible", false);  // restore the original location of the group
                             for (i = 0;  i < diagram.model.nodeDataArray.length; i++ ) {
                                 var nodeData = diagram.model.findNodeDataForKey(diagram.model.nodeDataArray[i].key);
                                 if (nodeData.key !== group.data.key && (nodeData.group == undefined || nodeData.group !== group.data.key))
                                 {
                                     diagram.model.setDataProperty(nodeData, "visible", false);
                                 }
                             }
                         }
                        // diagram.layout.isOngoing = false;
                        diagram.commitTransaction("graph");
                    } // subGraphExpanderClicked
                },
                $(go.Panel, "Spot",
                    $(go.Placeholder, {  background: "white" }),
                    $("SubGraphExpanderButton", { alignment: new go.Spot(0,0) })
                ),
                $(go.Panel, "Auto",
                    new go.Binding("visible", "groupVisible"),
                    //$(go.Shape, "Rectangle", { fill: "transparent" } ),
                    nodeTemplate()
                )
        );

// the Model holds only the essential information describing the diagram

// diagram.layout = new go.Layout();
// diagram.layout.isIntial = false;
// diagram.layout.wrappingColumn = 5;
diagram.model = new go.GraphLinksModel(nodeDataArray,linkDataArray);

function nodeTemplate() {
    var x =
        $(go.Panel, "Vertical",
                    $(go.Picture, { width: 100, height: 100 }, new go.Binding("source") ),
                    //new go.Binding("location", "loc", go.Point.parse),

                    $(go.Panel, "Table", { stretch:  go.GraphObject.Fill },
                            $(go.Panel, "Auto", { row: 0, column: 0, stretch:  go.GraphObject.Fill  },
                                    $(go.Shape, "Rectangle", { stroke: "gray" },
                                            new go.Binding("fill", "minor", function (val) {
                                                if (val === "") return "transparent"; else return "yellow";
                                            })),  // end Auto Panel body
                                    $(go.TextBlock, {  margin: 3 }, new go.Binding("text", "minor"))
                            ),
                            $(go.Panel, "Auto", { row: 0, column: 1, stretch:  go.GraphObject.Fill  },
                                    $(go.Shape, "Rectangle", { stroke: "gray" },
                                            new go.Binding("fill", "major", function (val) {
                                                if (val === "") return "transparent"; else return "orange";
                                            })),  // end Auto Panel body
                                    $(go.TextBlock, {  margin: 3 }, new go.Binding("text", "major"))
                            ),
                            $(go.Panel, "Auto", { row: 0, column: 2, stretch:  go.GraphObject.Fill  },
                                    $(go.Shape, "Rectangle", { stroke: "gray" },
                                            new go.Binding("fill", "critical", function (val) {
                                                if (val === "") return "transparent"; else return "red";
                                            })),  // end Auto Panel body
                                    $(go.TextBlock, {  margin: 3 }, new go.Binding("text", "critical"))
                            )
                    )
            )
    return x;
}

Could you take a look ?

I’ve taken your example and replaced the images, and it’s not clear what the problem is. You’ll need to provide some screenshots of the issue and what your desired result would look like.

Before expanding the node :

After the node is collapsed :

I’m not seeing that issue. See https://codepen.io/jhardy/pen/LLYEro?editors=1010.

Which version of GoJS are you using?

Strange,
I use 1.6.2

If you point your code to https://gojs.net/latest/release/go.js does it work? You should probably update to a newer version.

Works perfect,
Thanks