Need faster loading or doing faster layoutDiagram


#1

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 https://gojs.net/latest/intro/performance.html and have also try https://gojs.net/latest/samples/virtualizedTree.html 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


#2

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.


#3

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


#4

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.)


#5

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


#6

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.


#7

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


#8

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


#9

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.


#10

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


#11

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.


#12

No words to say Thanks
will back after run experimental code