TreeLayout - set initial position of a node when it was dragged and dropped from a palette?

Hi, there. I’m using TreeLayout. When A node is dragged from a palette, it will be dropped to the end of the tree. How can it be positioned just where it’s dropped and when it is linked to a node in the tree, it will still be re-arranged automatically?

Here is my code:

const { Diagram, GraphObject, TreeLayout, Spot } = go
  const $ = GraphObject.make;
  const treeLayout = $(
   TreeLayout,
   {
    angle: 90,
    arrangement: TreeLayout.ArrangementVertical,
    treeStyle: TreeLayout.StyleLayered,
    arrangementSpacing: new Size(0, 35),
  },
)

const myDiagram = $(
 Diagram,
 diagramId,
 {
    layout: treeLayout,
    isReadOnly: false,
    allowHorizontalScroll: true,
    allowVerticalScroll: true,
    allowZoom: true,
    allowSelect: true,
    contentAlignment: Spot.TopCenter,
    minScale: 0.5,
    maxScale: 1,
    initialScale: 0.85,
    "undoManager.isEnabled": true,  // enable undo & redo
  },
);

return myDiagram;

Thanks in advance.

Try setting layoutConditions: go.Part.Layout.None on your Node template.

More info: https://gojs.net/latest/intro/layouts.html#LayoutInvalidation

Hi, Walter. Thanks for your reply. I use ‘LayoutNone’ and it does not put the added node to the end of the tree. But still, when a node was linked to the tree, all un-linked nodes automatically moved to then end of the tree. So, how to keep the un-linked nodes as the place they were placed? Any methods should be overridden or Events should be listen to?

OK, instead of setting layoutConditions, try setting isLayoutPositioned to false on the node template. Then when you connect the node to another node, set Node.isLayoutPositioned back to true.

1 Like

Hi Walter, you idea almost solve the issue.
Here is my code:

myDiagram.addDiagramListener('LinkDrawn', (event) => {
console.log(`Diagram event: LinkDrawn()`)
event.subject.fromNode.isLayoutPositioned = true
event.subject.toNode.isLayoutPositioned = true

})

myDiagram.addDiagramListener('LinkRelinked', (event) => {
console.log(`Diagram event: LinkRelinked()`)
event.subject.fromNode.isLayoutPositioned = true
event.subject.toNode.isLayoutPositioned = true

})

One last question:
I wonder what is the event like ‘LinkRemoved’ which I can listen to and make the ‘fromNode.isLayoutPosistioned’ and ‘toNode.isLayoutPosistioned’ to ‘false’ again?

Never mind. I’ve just written a diagram listener for ‘SelectionDeleted’ for deleting Links from the diagram.

Good point about deletion. I hope you are not blindly setting isLayoutPositioned back to false, since the node might still be connected with other links.

Rather than those DiagramEvents, I think it would be better to implement two event handlers:
https://gojs.net/latest/api/symbols/Node.html#linkConnected
https://gojs.net/latest/api/symbols/Node.html#linkDisconnected

linkConnected: n => n.isLayoutPositioned = true,
linkDisconnected: n => n.isLayoutPositioned = n.linksConnected.count > 0
1 Like

I think using linkConnected and linkDisconnected is the right way to do.
It would be more specific, more reliable & more convenient to do this task.
Thanks for pointing this out. :clap :clap

BTW, I might have been there to check if there is any event handler could be used for the job. And maybe I’ve just misled by the property and method list on the right side which says both linkConnected and linkDisconnected are properties but not methods.

That is correct – simple event handlers are properties of type function. The assumption is that unicast event handlers are sufficient for almost all uses, unlike the multicast DiagramEvent and ChangedEvent listeners.

In GoJS functional property event handlers always default to null and may be regular functions, not methods that expect to have this bound. That means you can always use arrow functions, and usually they do not need to be closures.

Sure. It’s unnecessary to have all Nodes to have a linkConected handler of its own.
Now they sound more reasonable to me.