DiagramEvent with LayoutCompleted after mergeNodeDataArray

Hi,

I’m using LayoutCompleted event to position some of the nodes behind others based on the relation they have to each other. I’m basically trying to achieve grouping of nodes but nodes may be in many groups at the same time, visually there’s just number of “backgrounds” behind the node to reflect that.

I’m finding that whenever I change the underlying model representing those nodes and commit those changes and use mergeNodeDataArray, the LayoutCompleted event gets DiagramEvent with only some of the nodes passed to the event. I check the nodeDataArray of the model before and after the commit (all the nodes are there) but during the commit, only some of the nodes are present in event.diagram.nodes.

Is this an expected behaviour and I’m missing something? Or am I doing something wrong? I’m happy to provide more code to illustrate if needed but so far I’m thinking it may be that I simply don’t understand LayoutCompleted?

Thanks for any help!

So you are not using Groups at all? Much like the Shared States sample? Shared States

In that case the “LayoutCompleted” DiagramEvent will be raised each time after the Diagram.layout is performed. The functionality is similar to what you would get if you overrode the Layout.commitLayout method to do your extra layout work.

The Diagram.nodes collection should include all Nodes that are in that Diagram at the time. (That would include Groups, but you don’t have any.) It would not include any simple Parts – i.e. non-Node non-Link non-Adornment Parts. So if you have any node templates that are direct instances of Part, those instances would not be included in the Diagram.nodes collection.

Yes, quite similar to Shared States, with different representation of those “groups” but also not using Groups. I don’t do custom layout but try to react on LayoutCompleted and position them then.

It seems like two consecutive LayoutCompleted events which try to replace or merge nodeDataArray with my data can produce different number of nodes being available to the listeners.

May it be that those objects in nodeDataArray are treated differently if I create them based on a Javascript class vs. object literal?

Without wasting more of your time.

Some nodes inside nodeDataArray were created based on others using spread operator.

nodeDataArray = [
   ...someRepository.all(),
   ...someRepository.all().map((s) => {...s, id: newId, etc: etc})
]

(nodeKeyProperty: ‘id’ on GraphLinkModel set)

which may cause problems in identifying how many unique nodes there are really because the underlying class may overload equals?

That’s my current guess anyway. Happy to hear if that’s what may be happening here but otherwise I consider this be a problem with my code.

The only funny thing is that the method returns consistently these type of objects and sometimes they end up being passed to DiagramEvent, sometimes not. Any idea why this may be?

Wait – your code shows that there are always only two nodes in the model. Each of those node data objects is an Array, which is definitely not normal.

Maybe you mean to concat the mapped Array result to a copy of the Array?

I’m sorry @walter, corrected the code.

There are multiple nodes but some of them are created by transforming the original objects into something else. They would appear in the nodeDataArray but would not be passed via DiagramEvent. Removing ...s in the inner map function helped.

My guess is that these object wouldn’t be distinguishable by go.js therefore only the original nodes were created? sometimes…? like I said - one update would result in all objects passed via DiagramEvent, the other update - only those “original ones”, which was a bit strange.

This summarizes the general design of identity in models: GoJS Using Models -- Northwoods Software

Your call to Array.map is producing a new Array of new Objects. That’s fine. Your code appears to be assigning the same key value to every additional data Object, but maybe that’s just how you are summarizing your code. The model will make sure each node data object has a unique key.

That’s right, I’ve simplified a lot of code here.

I’ve set nodeKeyProperty to “id” and when creating new array of objects using Array.map I’m assigning each object a unique “id”. newId relates only to the fact that this id is not the same as it would come from the Repository mentioned. It would be generated for each object differently, almost like using a function which takes originalID and generates a new one.

Anyway, all the object in nodeDataArray have unique IDs. It’s just some of the were created from others using spread notation and the effect was that … which I mentioned. I would get either DiagramEvent with all the nodes (someRepository.all() and someRepository.all().map()) OR with only nodes coming from someRepository.all().

Thanks a lot for reading and your time, I will re-read GoJS Using Models and perhaps understand why it was like that.

I don’t have any more problems when I removed the spread operator.