Составные узлы перекрываются при использовании компоновки сетки в cytoscape. js - PullRequest
2 голосов
/ 20 февраля 2020

Я использую cytoscape. js для моего проекта визуализации, в котором мне нужно показать иерархическую структуру с составными узлами.

Поэтому я изначально использовал макет Cose-Bilkent , который работал как очарование, но требование состоит в том, что все дочерние узлы родителя должны быть в одной строке. Поэтому я попытался немного подправить, но не смог получить точный результат.

Затем я попытался использовать компоновку сетки, задав номера строк и столбцов в жестком коде , и я получил точный результат, но поскольку мои данные являются динамическими c, я понял, что трудно самостоятельно назначать номера строк и столбцов.

Вот данные, которые я использовал,

elements: [ // list of graph elements to start with
            { // node a
                data: { id: 'X1', label: 'X1'}
            },
            {
                data: { id: 'X2', label: 'X2'}
            },
            {
                data: { id: 'X3', label: 'X3'}
            },
            {
                data: { id: 'X4', label: 'X4'}
            },
            {
                data: { id: 'X5', label: 'X5'}
            },
            {
                data: { id: 'X6', label: 'X6'}
            },
            {
                data: { id: 'X7', label: 'X7'}
            },
            {
                data: { id: 'X8', label: 'X8'}
            },
            {
                data: { id: 'X9', label: 'X9'}
            },
            {
                  data: { id: 'X10', label: 'X10'}
            },
            {
                data: { id: 'X1e1',label: 'e1', parent: 'X1', row: '1' ,col: '1'}
            },
            {
                data: { id: 'X1e5',label: 'e5', parent: 'X1', row: '1',col: '2'}
            },
            {
                data: { id: 'X1e6',label: 'e6', parent: 'X1', row: '1',col: '3'}
            },
            {
                data: { id: 'X2e2',label: 'e2', parent: 'X2', row: '3',col: '1'}
            },
            {
                data: { id: 'X2e3',label: 'e3', parent: 'X2', row: '3',col: '2'}
             },
            {
                data: { id: 'X3e4',label: 'e4', parent: 'X3', row: '4',col: '1'}
            },
            {
                data: { id: 'X4e5',label: 'e5', parent: 'X4', row: '2',col: '1'}
            },
            {
                data: { id: 'X4e6',label: 'e6', parent: 'X4', row: '2',col: '2'}
            },
            {
                data: { id: 'X5e7',label: 'e7', parent: 'X5', row: '7',col: '1'}
            },
            {
                data: { id: 'X6e8',label: 'e8', parent: 'X6', row: '5',col: '1'}
            },
            {
                data: { id: 'X6e9',label: 'e9', parent: 'X6', row: '5',col: '2'}
            },
            {
                data: { id: 'X7e10',label: 'e10', parent: 'X7', row: '7',col: '2'}
            },
            {
                data: { id: 'X7e11',label: 'e11', parent: 'X7', row: '7',col: '3'}
            },
            {
                data: { id: 'X7e12',label: 'e12', parent: 'X7', row: '7',col: '4'}
            },
            {
                data: { id: 'X8e13',label: 'e13', parent: 'X8', row: '6',col: '1'}
            },
            {
                data: { id: 'X8e14',label: 'e14', parent: 'X8', row: '6',col: '2'}
            },
            {
                data: { id: 'X8e15',label: 'e15', parent: 'X8', row: '6',col: '3'}
            },
            {
                data: { id: 'X8e16',label: 'e16', parent: 'X8', row: '6',col: '4'}
            },
            {
                data: { id: 'X9e17',label: 'e17', parent: 'X9', row: '8',col: '1'}
            },
            {
                data: { id: 'X10e18',label: 'e18', parent: 'X10', row: '8',col: '2'}
            },
            {
                data: { id: 'X1e5X4e5', source:'X1e5', target:'X4e5'}
            },
            {
                data: { id: 'X1e6X4e6', source:'X1e6', target:'X4e6'}
            },
            {
                data: { id: 'X1e1X2', source:'X1e1', target:'X2'}
            },
            {
                data: { id: 'X2e3X3', source:'X2e3', target:'X3'}
            },
            {
                data: { id: 'X4e5X5', source:'X4e5', target:'X5'}
            },
            {
                data: { id: 'X4e6X6', source:'X4e6', target:'X6'}
            },
            {
                data: { id: 'X6X8e16', source:'X6', target:'X8e16'}
            },
            {
                data: { id: 'X6e9X8', source:'X6e9', target:'X8'}
            },
            {
                data: { id: 'X6e8X7', source:'X6e8', target:'X7'}
            },
            {
                data: { id: 'X6X7e12', source:'X6', target:'X7e12'}
            }
        ]

и макет

layout:{
            name: 'grid',
            fit: true,
            position: function( node ){ return {row:node.data('row'), col:node.data('col') }} 
        }

И вот результат, который я получил (и также ожидал), установив строки и столбцы вручную

Required visualization image

Любая помощь будет принята с благодарностью , Спасибо

Ответы [ 2 ]

3 голосов
/ 20 февраля 2020

Ну, есть два расширения, которые бы достигли именно того, что вам нужно:

По совпадению, оба происходят от одного и того же человека, так что это не должно быть проблемой, все, что вам нужно сделать, это применить правильные стили, чтобы приложение выглядело как ваш пример:

document.addEventListener("DOMContentLoaded", function() {
  var cy = (window.cy = cytoscape({
    container: document.getElementById("cy"),
    layout: {
      name: "evenParent"
    },
    style: [{
        selector: "node",
        style: {
          "content": "data(id)",
          "background-color": "#ad1a66"
        }
      },
      {
        selector: ":parent",
        style: {
          "background-opacity": 0.333
        }
      },
      {
        selector: "edge",
        style: {
          width: 3,
          "line-color": "#ad1a66"
        }
      },
      {
        selector: "edge.meta",
        style: {
          width: 2,
          "line-color": "red"
        }
      },
      {
        selector: ":selected",
        style: {
          "border-width": 3,
          "border-color": "#DAA520"
        }
      }
    ],
    elements: {
      nodes: [{
          data: {
            id: "Jerry",
            name: "Jerry"
          }
        },
        {
          data: {
            id: "Elaine",
            name: "Elaine"
          }
        },
        {
          data: {
            id: "Kramer",
            name: "Kramer"
          }
        },
        {
          data: {
            id: "George",
            name: "George"
          }
        },
        {
          data: {
            id: "Martin",
            name: "Martin"
          }
        },
        {
          data: {
            id: "Philippe",
            name: "Philippe"
          }
        },
        {
          data: {
            id: "Louis",
            name: "Louis"
          }
        },
        {
          data: {
            id: "Genevieve",
            name: "Genevieve"
          }
        },
        {
          data: {
            id: "Leo",
            name: "Leo"
          }
        },
        {
          data: {
            id: "Larry",
            name: "Larry"
          }
        },
        {
          data: {
            id: "Logaina",
            name: "Logaina"
          }
        }
      ],
      edges: [{
          data: {
            source: "Jerry",
            target: "Elaine"
          }
        },
        {
          data: {
            source: "Jerry",
            target: "Kramer"
          }
        },
        {
          data: {
            source: "Jerry",
            target: "George"
          }
        },
        {
          data: {
            source: "Elaine",
            target: "Martin"
          }
        },
        {
          data: {
            source: "Elaine",
            target: "Philippe"
          }
        },
        {
          data: {
            source: "Elaine",
            target: "Louis"
          }
        },
        {
          data: {
            source: "Elaine",
            target: "Genevieve"
          }
        },
        {
          data: {
            source: "Elaine",
            target: "Leo"
          }
        },
        {
          data: {
            source: "Kramer",
            target: "Larry"
          }
        },
        {
          data: {
            source: "Kramer",
            target: "Logaina"
          }
        }
      ]
    }
  }));

  // demo your collection ext
  cy.nodes().noOverlap({
    padding: 5
  });
});
body {
  font: 14px helvetica neue, helvetica, arial, sans-serif;
}

#cy {
  height: 100%;
  width: 100%;
  position: absolute;
  left: 0;
  top: 0;
}
<html>

<head>
  <script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/cytoscape-even-parent@1.1.1/cytoscape-even-parent.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/cytoscape-no-overlap@1.0.1/cytoscape-no-overlap.min.js"></script>
</head>

<body>
  <div id="cy"></div>
</body>

</html>
2 голосов
/ 21 февраля 2020

Следующий код работал для меня,

Пожалуйста, рассмотрите код @ Stephen, если это не работает.

var cy = cytoscape({
    container: /* your div within which you want to render */ ,
    elements: [ /*list of graph elements to start with */ ] ,
    style: [ /* the stylesheet for the graph */ ] ,
    layout:{
                name: 'cola',
                fit: false,
                infinite: false,
                avoidOverlap: true
            }
});

//Used to make child nodes stay on the same row
cy.ready(function(){
                setTimeout(function(){
                    cy.zoom(0.5);
                    cy.nodes(':compound').forEach(function(comp,j,comps){
                        var nodePosition={};
                        if(comp.descendants().length>1)
                        {
                            var minX;
                            var maxY;
                            comp.descendants().forEach(function(ele,i,eles){
                                if(i==0)
                                {
                                    minX=ele.renderedPosition('x');
                                    maxY=ele.renderedPosition('y');
                                }
                                else
                                {
                                    var tempX=ele.renderedPosition('x');
                                    var tempY=ele.renderedPosition('y');
                                    if(tempX<minX)
                                    {
                                        minX=tempX;
                                    }
                                    if(tempY>maxY)
                                    {
                                        maxY=tempY;
                                    }
                                }
                            });
                            comp.descendants().forEach(function(ele,i,eles){
                                ele.renderedPosition({x:minX,y:maxY});
                                minX=minX+60;
                            });
                        }
                        cy.resize();
                        cy.fit();
                        cy.minZoom(cy.zoom());
                    });
                },1000);
            });

PS: Не забудьте включить скрипты cytoscape;)

...