How to Add layers based on a tree Click and keep existing Nodes on previous Layers

Hi Walter,
Below is my requirement,

  1. I have tree structure, based on click on the tree element, i need to create a new Layer(if there is no layer existing with the same name). And now i will be able to drag and drop elements from palette to the Layer(Diagram)
  2. now, if i click on another tree element i need to again create a new Layer if there is no layer existing with the same name. But, the Elements which i have drawn on the previous layers should still be there.

This can go on for n number of tree Elements.

I have tried as below

    this.myDiagram.nodeTemplate =
    SCE(go.Part,  // no links or grouping, so can use the simpler Part class
        new go.Binding("layerName", "StateMachine"),
    ); //Default Layer at the start

    this.myAppTreeView.addDiagramListener("ObjectSingleClicked", this.treeObjectSingleClicked); //Added a function for singleClick on Tree Element

    treeObjectSingleClicked = (ev) => {
        this.myDiagram.startTransaction("toggle layer visibility");
        var lay = this.myDiagram.findLayer(this.selectedTreeNode); //selectedTreeNode is the tree element which is selectec
        var myD = this.myDiagram;
        if (!lay) {
            this.myDiagram.addLayerAfter($(go.Layer, { name: this.selectedTreeNode }), myDiagram.findLayer(""));
        } else {
            lay.visible = !lay.visible;
        }
        this.myDiagram.commitTransaction("toggle layer visibility");
    }

The problem is, previously dragged and dropped nodes[elements/shapes] on a first layer is staying even though i have clicked on another tree element[for creating second layer].

i could see the layers are getting created as i could see the myDiagram.layer.count

But where is the code to hide previously shown layers? If that is actually what you want.

Yes Exactly, is there a way where i can hide the layer that was previously shown? using myDiagram?
at any given point of time, only one layer should be shown and only the nodes that are drawn on that layer should be shown.

if (!lay) {
this.myDiagram.addLayerAfter($(go.Layer, { name: this.selectedTreeNode }), myDiagram.findLayer(""));
//If layer is null i am adding a new layer and also i should show it
} else {
//Hide the previous layer and show the current layer
lay.visible = !lay.visible;
}

can you help me out with that couple of lines. how can i access the layer that is shown using this.myDiagram?

If you only want to show one Layer at a time, it seems to me that you need to remember the Layer (or its name) that was shown previously and then set Layer.visible to false. Unless that Layer is the same Layer that you want to make visible.

Yes, i have done that too, i am storing the previousLayer Name and using it to set it to False.
Still i could see the diagram which is drawn on the previous layer.
here is my code snippet

this.myDiagram.nodeTemplate =
SCE(go.Part,  // no links or grouping, so can use the simpler Part class
    new go.Binding("layerName", "StateMachine"),
); //Default Layer at the start

this.myAppTreeView.addDiagramListener("ObjectSingleClicked", this.treeObjectSingleClicked); //Added a function for singleClick on Tree Element

treeObjectSingleClicked = (ev) => {
    this.myDiagram.startTransaction("toggle layer visibility");
    var lay = this.myDiagram.findLayer(this.selectedTreeNode);
    var prevLay = this.myDiagram.findLayer(previousLayerName);
    if (!lay) {
        this.myDiagram.addLayerAfter(SCE(go.Layer, { name: this.selectedTreeNode }), this.myDiagram.findLayer(""));
    } else {
        prevLay.visible = false;
        lay.visible = true;
    }
    previousLayerName = <any>this.selectedTreeNode;
    this.myDiagram.commitTransaction("toggle layer visibility");
}

Your code doesn’t make sense to me. I think you are going to have to debug your code to make sure it is doing what you think it is doing.

Ok. I have resolved it and its working now as i want it to be.
thought i have one more ques,
I wanted to use separate models (but common UndoManager) for each layer, so that when i add nodes/shapes from palette to a particular layer it should be added in to particular layer’s Model only, can that be possible? If yes, can you point me to any reference how can i achieve this.

Sorry, but a Diagram can have only one Model. But multiple Diagrams can share a single Model.

I suggest that when you want to save the model that you then only save the data corresponding to a single layer. But you will have to do that yourself.

Ok, Thank you. When you say, save only data corresponding to a single layer that means[Model will consist of node data of all layers], i need to loop through the NodedataArray and LinkDataArray of the Diagram’s Model and then save the data[nodes data] corresponding to that layer?

As i could see that NodeDataArray and LinkDataArray are Array’s, can these be map’s with ID as a key for each node? so that the looping would be fast?

I hope you understood my problem, if i have multiple layers with many nodes in each layer then my Model would be big, so when i want to save data only of a specific layer then i need to loop the whole Model’s nodedataArray and linkdataArray and save only nodes that are corresponding to that layer[i can find which node belongs to which layer as i have a property LayerName associated with each node].

Yes, that’s right. Iterating over an Array is pretty fast – faster than iterating over the properties of an Object, in fact.

Ok.
couple of more questions, hopefully my last on this.

Iterating over an Array is pretty fast

  1. How can i differentiate which node belongs to which layer in NodeDataArray/LinkDataArray?
    because, when i drag and drop nodes on different layers and try to save, all the nodes will be in myDiagram.model, now i need a way to say that a particular node belongs to particular Layer in NodeDataArray and LinkDataArray so that i could pick them and save them only.
    Is there any way i could do this using gojs? other than adding a property manually?

  2. How can we differentiate which node belongs to which Layer? i know about “part.LayerName” this i am doing it when i drag and drop a node from palette, but when i do myDiagram.model.toJSON() and save the required data to JSON file. i couldn’t see any property that would say the particular node belongs to particular layer, as it is saving “part.data”.

Why i need this is because, when i load the diagram JSON back to model i need to know which node belongs to which Layer. Can it be done automatically by gojs? do i need to add any property or something?

I was assuming you already had information on the node data objects so that you could tell which “layer” they belonged to. If that’s not the case, and if you really are putting the Nodes into differernt Layers, then you could have a TwoWay Binding remember the Part.layerName. Something like:

    new go.Binding("layerName").makeTwoWay()

in your Node template(s).

The advantage of this is that when you load the model, the nodes will automatically be placed back in the same layers – IFF you make sure those named Layers exist before you load the model.

Ok, understood.
Yes i already have layer information with each node data, i am already adding a property layerName in node.data using

model.setDataProperty(node.data, “layerName”, node.layerName);

when i drag and drop the node from palette.

Now, I have done the two way binding as you suggested. so my second issue would have been resolved, though i need to check it. and i would make sure that the layers are created before loading data to Model.


as of now, when i am trying to save the data specific to one layer nodes, i have model.nodeDataArray that consists of all the nodes data[i.e. part.data] for all layers, hence i am looping through it and checking the layerName of each node and deciding whether to save it or not.

Can you recommend any other alternative? as traversing nodeDataArray and linkDataArray of whole model and checking each node’s layerName property and then saving might not be that efficient.

Try it and time it – I think you’ll find it plenty fast enough.

Ok Sure. Thank You Walter.