Need faster loading or doing faster layoutDiagram

Hi
I am creating organization chart
i have multi type of nodes like
reactangle,
reactangle with triangle inside,
oval within reactangle,
circle,
diamond,
triangle,
reactangle with triangleDown inside,
rectangle with circle inside,
trapezoid,
oval_within_reactangle,
pentagon

Every type showing his company type with his shape and color

Every node template has six ports up, down, and ports on right,
top and bottom ports are in used to show parent and child structure and other three ports are in used to show three different types of transactions between nodes/companies

example:

i am using go.LayeredDigraphLayout, with direction:90
Every thing is working fine,
but now i have receive the data from client its about 1400 node and links between.

now i am face slow loading or slow layout problem getting page unresponsive alert from browser. chart finally generated but getting to much time causing page unresponsive alert from browser.
i am searching from last two weeks and try many thing also read GoJS Performance Considerations -- Northwoods Software and have also try Virtualized Tree with custom layout in this case you have already know about node’s bounds and you collect node by visible area and show in main view able area.
why i am not using tree layout?
because i have multiple links between nodes like at the bottom node has two or three parents once from top level and once from low level that’s why tree layout not meeting my needs.

is there a way to speed up

myDiagram.layoutDiagram(true);

Thanks

Sorry, but I don’t believe that much can be done.

Virtualization only helps on startup and to save memory during normal usage. It does not help with computation-intensive layouts.

Could you please suggest me any other way to avoid this.
like load limited number of nodes on startup or something like this similar i have also try to load data in chunks like 100 nodes per chunk and then layout. but face same problem when number of nodes exceed 500 or 600
i spent more then four months on this project and now if only because of this issue i change the main API its mean i lost four months
so please suggest me some thing

LayeredDigraphLayout is inherently much slower than other layouts. Handling a thousand nodes and more links isn’t a problem in Java or .NET, but JavaScript is several times slower.

Could you do the layouts ahead of time, perhaps on the server, and then just save the node locations and link routes? Have you set Layout.isOngoing to false because you only want the layout to be done upon loading the model? Do you allow users to position nodes manually?

How much time is actually going into doing the layout? If you don’t set the Diagram.layout at all, how long does it take to load? (Obviously you won’t like the resulting layout – I just want to know how many seconds that the layout is taking.)

Hi
sorry for late reply
Actually we are creating Step Plan tool
So we have two different display for chart
One is where user search in diagram to find his specific part of chart to create Step Plan.
First i am trying to describe this one where user search in diagram.
Json we build from data base.

{ 
  "class": "go.GraphLinksModel",
  "nodeDataArray": [ 
    {
      "key":1, 
      "name":"Company one",
      "color":"lightblue",
      "visible":true,
      "category": "circle",
      "entity_Type": "branch_trust", 
      "internal_id": 250,
      "color": "#A00176",
      "short_name": "C Company" ,
      "entity_code": "CCOM",
      "sbu": "ABC",
      "business_chain": "Sahdy",
      "nodePath": "/node/conmpany_one",
    }
  ],
  "linkDataArray": [
    { 
      'from': 1,
      'to':  2,
      'frompid': 'parent port',
      'topid': 'child port',
      'category': 'flow',
      'visible': FALSE,
      'percent': 05.00%",
      'internal_id': 1,
      'parent_find': false,
      'child_find": false
    }
  ]
}

By default when i load all data in diagram all nodeData and link data is = false
my data loading into model

myDiagram.model = // this only holds nodes that should be in the viewport $(go.GraphLinksModel); // must match the model, above myDiagram.model.linkFromPortIdProperty= "frompid"; myDiagram.model.linkToPortIdProperty = "topid"; myDiagram.delayInitialization(load); in load function myDiagram.model.linkDataArray = rawJson.linkDataArray; myDiagram.model.nodeDataArray = rawJson.nodeDataArray; myDiagram.layout.isOngoing = false;

so we load all 1400 nodes and links in modal with visible = false;
and chart area display a text message “Please select ‘Business Chain’ or ‘Entity’ to create a chart first.”
Now user can search by multiple select options options are Business chains business chain is set as attribute in our nodeData like in above example “business_chain”: “Sahdy”
so user is able to pickup one or two business chains (two is the max limit to select) to create a chart or one more option list where user can select single entity or node.
After selection if you select business chain one or two we have to find all nodes with the selected business chain
for example we got 100 node with the selected business chain now we have to find all 100 node’s full tree top to bottom
so we have to run a loop on 100 nodes and find parent and child for each node
so i have implement a recursive function to find parent and child.

CODE:

/*
 * Get parents functionality
 * @pram
 *   $slectedNode graph node object
 * find parents for $slectedNode and make them visible 
 */
function getParents(selectedNode) {
  var model = myDiagram.model;
  // all model changes should happen in a transaction
  
  var key = selectedNode.key;
  var result = model.linkDataArray.filter(function(obj) {
    return obj.to === key;
  });
  //console.log(key);

  if(result.length){
    for(var i = 0; i < result.length; i++){
      if(!result[i].visible && !result.parent_find){
        var parent = model.findNodeDataForKey(result[i].from);
        if(parent){
          model.setDataProperty(result[i], "visible", true);
          model.setDataProperty(result[i], "parent_find", true);
          model.setDataProperty(parent, "visible", true);
          //setTimeout(function(){
            getParents(parent);  
          //},100);
          
        }
      }
      
    }
  }
  
  
  
}

/*
 * Get childerns functionality
 * @pram
 *   $slectedNode graph node object
 * find childrens for $slectedNode and make them visible
 * find child's parents and childrens and make them visible
 */
function getChildrens(selectedNode){
  var model = myDiagram.model;
  // all model changes should happen in a transaction
  myDiagram.startTransaction("updateNode");
  var key = selectedNode.key;
  var result = model.linkDataArray.filter(function(obj) {
    return obj.from === key;
  });
  if(result.length){
    for(var i = 0; i < result.length; i++){
      if(!result[i].visible && !result.child_find){
        child = model.findNodeDataForKey(result[i].to);
        if(child){
          model.setDataProperty(result[i], "visible", true);
          model.setDataProperty(result[i], "child_find", true);
          model.setDataProperty(child, "visible", true);
          //setTimeout(function(){
            getChildrens(child);  
          //},100)
          
        }  
      }
      
    }
  }
  
  myDiagram.commitTransaction("updateNode");
  

}

in these functions we set visibility true for node and links we set some extra attributes like “child_find” and “parent_find” to avoid to many recursive calls error mean if you find childs from one path we set it as child_find = ture mean no need to on this path once again.

when all are done all required nodes and links are set to visible = true now we are going to layout

myDiagram.remove(myLoading);

myDiagram.initialDocumentSpot= go.Spot.TopCenter,
myDiagram.initialViewportSpot= go.Spot.TopCenter,
myDiagram.layoutDiagram(true);

At this stage our biggest search has 900 node to visible and when you search biggest one layout take 59sc to layout.

Because of we are search in diagram we are not able to store node locations.
After when user search is done user have to save this chart which is visible right now.
so we get all visible nodes and links and create new json and store in data base to display users saved step plan

when we display step plan we load json in model all things are visible
now user can add transaction between companies.
Hope this make help you to understand my code and work flow

THANKS

During all of the time that the user is waiting for something to show up, you should call startTransaction/commitTransaction at top-level at most ONCE. Is that the case?

If you perform transactions repeatedly, you may be performing layouts repeatedly.

The main problem is not user is waiting for something to show up.
Before layout we print overly layer with message like "Wait we are generating chart for you " after layout we remove this message.
mean we tell the user wait we are doing something.
The problem is page getting alert unresponsive message from browser.
its really bad for user experience user think something goes wrong or page is stuck some where

We’ll see what can be done later today, after we’ve had a chance to catch up with all of our other customers.

Getting that “waiting” prompt from the browser, when I test with 999 nodes, seems to only happen on Firefox, which I assume has a shorter time than other browsers after which it puts up the prompt.

After doing some experimentation trying to change the implementation of LayeredDigraphLayout to be somewhat asynchronous, I find that there are sections of code that are not easily “interruptible”. And implementing the layout so that it is running in parallel (in a Web Worker) is a lot of work that we had been hoping to do someday after we release 2.0.

There are a bunch of steps that the layout does that can take quite long. One such step is LayeredDigraphLayout.assignLayers. Could you precalculate the layers for all of the nodes and save that information? Then an override of that method, if that information were available, could just assign each LayeredDigraphVertex.layer, skipping one long computation.

Really thank you Walter!
For giving your meaning full time.
Trying to go through with the documentation of LayeredDigraphLayout.assignLayers and LayeredDigraphVertex.layer
Then i will try to override
Really appreciated thanks

Here’s a custom LayeredDigraphLayout that either saves a JavaScript Object mapping node keys to vertex layers, or if such an object is provided as SavedLayeredDigraphLayout.layerInfo, uses those values in its override of assignLayers.

  function SavedLayeredDigraphLayout() {
    go.LayeredDigraphLayout.call(this);
  }
  go.Diagram.inherit(SavedLayeredDigraphLayout, go.LayeredDigraphLayout);

  SavedLayeredDigraphLayout.prototype.assignLayers = function() {
    if (this.layerInfo) {  // use existing saved layer info
      console.log("using layerInfo");
      var it = this.network.vertexes.iterator;
      while (it.next()) {
        var v = it.value;
        var n = v.node;
        if (n) {
          var layer = this.layerInfo[n.data.key];
          if (typeof layer === "number") v.layer = layer;
        }
      }
    } else {  // compute layers and save the information to this.layerInfo
      go.LayeredDigraphLayout.prototype.assignLayers.call(this);
      var info = {};
      var it = this.network.vertexes.iterator;
      while (it.next()) {
        var v = it.value;
        var n = v.node;
        if (n) {
          info[n.data.key] = v.layer;
          console.log(n.data.key + ": " + v.layer + "\n");
        }
      }
      this.layerInfo = info;
    }
  }

If the graph has changed and you want to collect the layer information for all of the nodes, you’ll need to set SavedLayeredDigraphLayout.layerInfo to null before the layout happens, so that the normal assignLayers behavior happens and so that the information is saved.

Of course you’ll want to remove the console.log statements and figure out how to save and load the layer information.

No words to say Thanks
will back after run experimental code

Just implement SavedLayeredDigraphLayout.layerInfo but makes no deference
also try with assign layer name with node data like

{kye:125, name:“example”, layerName: “green”}

Create layers in diagram

var forelayer = myDiagram.findLayer(“Foreground”);
myDiagram.addLayerBefore($(go.Layer, { name: “green” }), forelayer);
myDiagram.addLayerBefore($(go.Layer, { name: “blue” }), forelayer);
myDiagram.addLayerBefore($(go.Layer, { name: “orange” }), forelayer);

And in node template :

new go.Binding(“layerName”, “layerName”),

But no success
Both examples slower than before
in you previous post you talk abut Java is faster then javascript
is there any example how to work in java with Gojs?

Setting/binding Part.layerName just changes the Layer that the Part is in, which only changes the z-order of that Part. It has no effect on the layout – neither appearance nor speed.

For each diagram/model, did you run the custom layout and then save the SavedLayeredDigraphLayout.layerInfo, so that on the next load you could run the layout with that information, which presumably would be faster than the first time?

If you are using Model.toJson and Model.fromJson, you could save the layerInfo on the Model.modelData object. When loading, set the SavedLayeredDigraphLayout.layerInfo and then replace the Diagram.model.
https://gojs.net/latest/intro/usingModels.html#SavingAndLoadingModels

I have to places of chart one for searching and create sub chart
For first chart i am using LayeredDigraphLayout
and for second one i am using now SnapLinkReshaping because second chart has more links then first so add SnapLinkReshaping for reshape links to avoid links overlap
From First chart i am saving node location and link points as in above example
Second chart Diagram

var myDiagram = $(
go.Diagram,
“chart-container”, // must be the ID or reference to div
{
isReadOnly: false,
autoScrollRegion: new go.Margin(0, 0),
linkReshapingTool: $(SnapLinkReshapingTool),
}
);

For second Chart my Json is:
{
“class”: “go.GraphLinksModel”,
“linkFromPortIdProperty”: “frompid”,
“linkToPortIdProperty”: “topid”,
“modelData”: {“position”:“0 0”},
“nodeDataArray”: [
{
“key”:“1908”,
“name”:“company a”,
“category”:“reactangle”,
“entity_Type”:“Unknown”,
“visible”:true,
“internal_id”:“1908”,
“color”:“#313698”,
“short_name”:“Company A”,
“entity_code”:“C A”,
“location”:“850 0”
},
{
“key”:“1909”,
“name”:“company b”,
“category”:“reactangle”,
“entity_Type”:“Unknown”,
“visible”:true,
“internal_id”:“1909”,
“color”:“#313698”,
“short_name”:“Company B”,
“entity_code”:“C B”,
“location”:“950 0”
},
]
“linkDataArray”: [
{
“from”:“1908”,
“to”:“1909”,
“frompid”:“parent port”,
“topid”:“child port”,
“category”:“flow”,
“visible”:true,
“percent”:“1.00%”,
“internal_id”:423,
“points”:[324.5,346,324.5,356,324.5,418,525,418,525,2206,524.5,2206,524.5,2248,524.5,2258]
},
},

i have now noda location and link points to
is some thing else need to save from First Chart to load second chart faster
its still slower then first chart
is my second chart still calling LayeredDigraphLayout.assignLayers ?

It does not appear that you have set Diagram.layout in your second diagram, so your second diagram should not be calling any LayeredDigraphLayout at all. When you have (saved) node locations for all of your nodes, there is no reason to have any assignment of Diagram.layout, so I think you have set it up correctly. You can check the type of the value of myDiagram.layout to confirm if that is the case.

Is there any example of use node location to create diagram and avoid other layout functions
Like if i have node location to tell the diagram where to create node and i have link points to where create links so i think my diagram should be load faster
i checked several examples but cant find any think
Help needed

Lots of samples do not set Diagram.layout at all.

If you really want to set Diagram.layout because you sometimes want that layout, but if you sometimes don’t, please read GoJS Layouts -- Northwoods Software in order to control when layouts are invalidated.

You have already read the “Performance” section of the Introduction, GoJS Performance Considerations -- Northwoods Software, but perhaps some of it might be more meaningful now to you.