how to reverse a collection in cytoscape.js - javascript

I have a collection of elements (created by using pathTo from the dijkstra function).
I need to reverse elements of this collection, for instance I want to transform
[14, 2, 37, 4, 5] into [5, 4, 37, 2, 14].
I tried using the filter function as per below but to no success. Does anyone know how to reverse a collection (not an array)?
path = dijkstraDiverse.pathTo(cy.$id('5'));
newpath = path.filter(function(ele, i, eles) {
return eles[path.length - 1 - i];
});

I used the sort function and just reversed the collection that way. The important part is using -1 as the sorting metric, that way everything is simply reversed. I added some visual clarification derived from this BFS example:
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
boxSelectionEnabled: false,
autounselectify: true,
style: [{
selector: "node",
css: {
content: "data(id)",
"text-valign": "center",
"text-halign": "center",
"height": "60px",
"width": "60px",
"border-color": "black",
"border-opacity": "1",
"border-width": "10px"
}
},
{
selector: "edge",
css: {
"label": "data(weight)",
"target-arrow-shape": "triangle"
}
},
{
selector: ".highlight",
css: {
'background-color': '#61bffc',
'line-color': '#61bffc',
'target-arrow-color': '#61bffc',
'transition-property': 'background-color, line-color, target-arrow-color',
'transition-duration': '0.5s'
}
},
{
selector: ".old",
css: {
'background-color': '#ff6e63',
'line-color': '#ff6e63',
'target-arrow-color': '#ff6e63',
'transition-property': 'background-color, line-color, target-arrow-color',
'transition-duration': '0.5s'
}
}
],
elements: {
nodes: [{
data: {
id: "n0"
}
},
{
data: {
id: "n1"
}
},
{
data: {
id: "n2"
}
},
{
data: {
id: "n3"
}
},
{
data: {
id: "n4"
}
},
{
data: {
id: "n5"
}
},
{
data: {
id: "n6"
}
},
{
data: {
id: "n7"
}
},
{
data: {
id: "n8"
}
},
{
data: {
id: "n9"
}
},
{
data: {
id: "n10"
}
},
{
data: {
id: "n11"
}
},
{
data: {
id: "n12"
}
},
{
data: {
id: "n13"
}
},
{
data: {
id: "n14"
}
},
{
data: {
id: "n15"
}
},
{
data: {
id: "n16"
}
}
],
edges: [{
data: {
source: "n0",
target: "n1",
weight: 1
}
},
{
data: {
source: "n1",
target: "n2",
weight: 11
}
},
{
data: {
source: "n1",
target: "n3",
weight: 12
}
},
{
data: {
source: "n2",
target: "n7",
weight: 2
}
},
{
data: {
source: "n2",
target: "n11",
weight: 3
}
},
{
data: {
source: "n2",
target: "n16",
weight: 1
}
},
{
data: {
source: "n3",
target: "n4",
weight: 32
}
},
{
data: {
source: "n3",
target: "n16",
weight: 7
}
},
{
data: {
source: "n4",
target: "n5",
weight: 6
}
},
{
data: {
source: "n4",
target: "n6",
weight: 4
}
},
{
data: {
source: "n6",
target: "n8",
weight: 11
}
},
{
data: {
source: "n8",
target: "n9",
weight: 12
}
},
{
data: {
source: "n8",
target: "n10",
weight: 1
}
},
{
data: {
source: "n11",
target: "n12",
weight: 1
}
},
{
data: {
source: "n12",
target: "n13",
weight: 2
}
},
{
data: {
source: "n13",
target: "n14",
weight: 3
}
},
{
data: {
source: "n13",
target: "n15",
weight: 5
}
}
]
},
layout: {
name: "dagre",
padding: 5
}
}));
cy.ready(function() {
const dijkstra = cy.elements().dijkstra(
"#n0",
function(edge) {
const weight = edge.data("weight");
return weight;
}
);
const oldPath = dijkstra.pathTo(cy.$("#n10"));
console.log(oldPath);
const newPath = oldPath.sort(function(a, b) {
return -1;
});
console.log(newPath);
let i = 0;
let j = 0;
let highlightPath = newPath;
let highlightNextEle = function() {
if (i < highlightPath.length) {
if (j == 0) {
highlightPath[i].addClass("highlight");
} else {
//highlightPath[i].removeClass("highlight");
highlightPath[i].addClass("old");
}
i++;
setTimeout(highlightNextEle, 1000);
} else if (i == highlightPath.length && j !== 1) {
i = 0;
j = 1;
highlightPath = oldPath;
setTimeout(highlightNextEle, 1000);
}
};
// kick off first highlight
highlightNextEle();
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 100%;
left: 0;
top: 0;
float: left;
position: absolute;
}
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<script src="https://unpkg.com/cytoscape#3.3.0/dist/cytoscape.min.js">
</script>
<script src="https://unpkg.com/jquery#3.3.1/dist/jquery.js"></script>
<!-- cyposcape dagre -->
<script src="https://unpkg.com/dagre#0.7.4/dist/dagre.js"></script>
<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-dagre/1.5.0/cytoscape-dagre.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>

Related

can parent node support other shape?

I need to define the parent node shape custom, but if I assign the shape as usual, the shape remains rectangular (instead of a star shape like in the example):
{
selector: 'node:parent',
style: {
'background-color': 'lightgrey',
'shape': 'star',
'border-color': 'cyan',
'border-radius': '50',
'background-fill': 'radial-gradient',
}
}
Desired round parent shape:
As described in this GitHub Issue, cytoscape.js does not support all node shapes for parent elements due to problems with the calculation of the parents BoundingBox.
The only supported shapes are:
rectangle
cutrectangle
roundrectangle
Here is an example for this feature:
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
style: [{
selector: "node",
css: {
content: "data(id)",
"text-valign": "center",
"text-halign": "center",
height: "60px",
width: "60px"
}
},
{
selector: ':parent',
css: {
//shape: 'rectangle',
shape: 'cutrectangle',
//shape: 'roundrectangle',
}
},
{
selector: "edge",
css: {
label: "\u2B24",
"curve-style": "bezier",
"target-arrow-shape": "data(arrow)"
}
},
{
selector: ".selectedNode",
style: {
"border-width": 8,
"border-color": "#5da963"
}
}
],
elements: {
nodes: [{
data: {
id: "n0",
parent: "n4"
}
},
{
data: {
id: "n1",
parent: "n5"
}
},
{
data: {
id: "n2",
parent: "n5"
}
},
{
data: {
id: "n3",
parent: "n5"
}
},
{
data: {
id: "n4",
parent: "n5"
}
},
{
data: {
id: "n5"
}
}
],
edges: [{
data: {
source: "n0",
target: "n1",
arrow: "triangle"
}
},
{
data: {
source: "n1",
target: "n2",
arrow: "triangle"
}
},
{
data: {
source: "n1",
target: "n3",
arrow: "triangle"
}
}
]
},
layout: {
name: "concentric",
minNodeSpacing: 140
}
}));
cy.unbind("click");
cy.bind("click", "node", evt => {
cy.elements().removeClass("selectedNode");
evt.target.addClass("selectedNode");
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 100%;
left: 0;
top: 0;
float: left;
position: absolute;
}
.cxtmenu-disabled {
opacity: 0.333;
}
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<script src="https://cdn.jsdelivr.net/npm/cytoscape#3.10.1/dist/cytoscape.min.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>

Compound nodes overlap while using grid layout in cytoscape.js

I am using cytoscape.js for my visualization project in which I have to show a Hierarchical structure with compound nodes.
So I initially used Cose-Bilkent layout which worked like a charm but the requirement is that all the child nodes of a parent must be in a single row. So I tried to tweak around a bit but couldn't get the exact result.
Then I tried to use grid layout by giving hardcoded row and column numbers and I got the exact result but as my data is dynamic I realized its difficult to assign row numbers and column numbers on my own.
Here is the data I used,
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'}
}
]
and layout
layout:{
name: 'grid',
fit: true,
position: function( node ){ return {row:node.data('row'), col:node.data('col') }}
}
And here is the result I got(and also expected) by setting manual rows and columns
Any help would be appreciated. Thanks
Well there are two extensions, which would achieve just what you need:
even-parents
no-overlap
Coincidentally, both come from the same person, so this should not be a problem at all, all you have to do from there is to apply the right styles for the application to look like your example:
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>
The following code worked for me,
Please consider #Stephen's code if this doesn't work.
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);
});
P.S: Don't forget to include the cytoscape scripts;)

Get nodeID in BFS cytoscape Javascript

I'm using cytoscape.js to make BFS search in custom made graph's. I need to add every node ID which has been visited in this search. I've tried something like that
document.getElementById("console").innerHTML += v.id;
in bfs function
var bfs = cy.elements().bfs('#1', function(v, e, u, i, depth){}, false);
But it's not working, I'm new in JS and programming for any advice I will be thankful.
If you want to get the id of each visited node of bfs, you can, as it is also explained right here, use the visit function like this:
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
boxSelectionEnabled: false,
autounselectify: true,
style: [
{
selector: 'node',
css: {
'content': 'data(id)',
'text-valign': 'center',
'text-halign': 'center',
'height': '60px',
'width': '60px',
'border-color': 'black',
'border-opacity': '1',
'border-width': '10px'
}
},
{
selector: '$node > node',
css: {
'padding-top': '10px',
'padding-left': '10px',
'padding-bottom': '10px',
'padding-right': '10px',
'text-valign': 'top',
'text-halign': 'center',
'background-color': '#bbb'
}
},
{
selector: 'edge',
css: {
'target-arrow-shape': 'triangle'
}
},
{
selector: ':selected',
css: {
'background-color': 'black',
'line-color': 'black',
'target-arrow-color': 'black',
'source-arrow-color': 'black'
}
}
],
elements: {
nodes: [
{ data: { id: 'n0' } },
{ data: { id: 'n1' } },
{ data: { id: 'n2' } },
{ data: { id: 'n3' } },
{ data: { id: 'n4' } },
{ data: { id: 'n5' } },
{ data: { id: 'n6' } },
{ data: { id: 'n7' } },
{ data: { id: 'n8' } },
{ data: { id: 'n9' } },
{ data: { id: 'n10' } },
{ data: { id: 'n11' } },
{ data: { id: 'n12' } },
{ data: { id: 'n13' } },
{ data: { id: 'n14' } },
{ data: { id: 'n15' } },
{ data: { id: 'n16' } }
],
edges: [
{ data: { source: 'n0', target: 'n1' } },
{ data: { source: 'n1', target: 'n2' } },
{ data: { source: 'n1', target: 'n3' } },
{ data: { source: 'n2', target: 'n7' } },
{ data: { source: 'n2', target: 'n11' } },
{ data: { source: 'n2', target: 'n16' } },
{ data: { source: 'n3', target: 'n4' } },
{ data: { source: 'n3', target: 'n16' } },
{ data: { source: 'n4', target: 'n5' } },
{ data: { source: 'n4', target: 'n6' } },
{ data: { source: 'n6', target: 'n8' } },
{ data: { source: 'n8', target: 'n9' } },
{ data: { source: 'n8', target: 'n10' } },
{ data: { source: 'n11', target: 'n12' } },
{ data: { source: 'n12', target: 'n13' } },
{ data: { source: 'n13', target: 'n14' } },
{ data: { source: 'n13', target: 'n15' } },
]
},
layout: {
name: 'dagre',
padding: 5
}
});
// here is the important part of the code
var idList = []; // list for id storage
var bfs = cy.elements().bfs({
roots: '#n0',
visit: function (v, e, u, i, depth) {
console.log("The id of the node " + i + " is " + v.id()); // i is the number of the i'th visited node, v is the node itself
idList[i] = v.id();
},
directed: false
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 75%;
position: absolute;
left: 0;
top: 0;
float: left;
}
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.17/cytoscape.min.js"></script>
<script src="https://unpkg.com/jquery#3.3.1/dist/jquery.js"></script>
<script src="https://unpkg.com/dagre#0.7.4/dist/dagre.js"></script>
<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-dagre/1.5.0/cytoscape-dagre.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>

Cytsocape.js can't create edges in for loop

I'm creating chart with nodes and edges. Once I created nodes, I can't create the associated edges without getting those kind of errors :
Can not create edge 5134fb65-b30f-4947-9870-cc909e293e21 with nonexistant source Peter
My code :
var myJSONdata = info;
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
boxSelectionEnabled: false,
autounselectify: true,
style: [
{
selector: 'node',
style: {
'content': 'data(id)',
'text-opacity': 0.5,
'text-valign': 'center',
'text-halign': 'right',
'shape': 'hexagon',
'label': 'data(label)',
'background-color': '#11479e'
}
},
{
selector: 'edge',
style: {
'curve-style': 'bezier',
'width': 4,
'target-arrow-shape': 'triangle',
'line-color': '#9dbaea',
'target-arrow-color': '#9dbaea'
}
}
],
// elements: {
// nodes: [
// { data: { id: 'Peter' } },
// { data: { id: 'Claire' } },
// { data: { id: 'Mike' } },
// { data: { id: 'Rosa' } }
// ],
// edges: [
// { data: { source: 'Peter', target: 'Claire' } },
// { data: { source: 'Claire', target: 'Mike' } },
// { data: { source: 'Mike', target: 'Rosa' } }
// ]
// }
});
var array = [];
// Create nodes
for (var i = 0; i <= myJSONdata.length - 1; i++) {
array.push({
group: 'nodes',
data: {
id: i,
label: myJSONdata[i].name
}
}
);
}
// Create edges
for (var i = 0; i <= myJSONdata.length - 1; i++) {
var source = myJSONdata[i].name;
array.push({
group: 'edges',
data: {
source: source,
target: myJSONdata[i].next_op_name
}
});
}
cy.add(array);
cy.layout({
name: 'circle'
}).run();
The "Create nodes" part is working, but the "Create edges" is not.
I tried the solution here but it does not work.
Actually I want to read data from JSON file to create the chart.
I can do it with :
elements: {
nodes: [
{ data: { id: 'Peter' } },
{ data: { id: 'Claire' } },
{ data: { id: 'Mike' } },
{ data: { id: 'Rosa' } }
],
edges: [
{ data: { source: 'Peter', target: 'Claire' } },
{ data: { source: 'Claire', target: 'Mike' } },
{ data: { source: 'Mike', target: 'Rosa' } }
]
}
But I want to automate it according to the JSON file in input.
This is my JSON file :
info = [
{
"name": "Peter",
"next_op_name": "Claire",
}, {
"name": "Claire",
"next_op_name": "Mike",
}, {
"name": "Mike",
"next_op_name": "Rosa",
}, {
"name": "Rosa",
"next_op_name": "Peter",
}
];
I can't understand what is wrong.
The source and target fields in the edge are the IDs of nodes, not labels.
When you create the nodes, you need to set id to myJSONdata[i].name as well.

How to run Cytoscape.js?

I am new to Cytoscape.js and also didn't write JavaScript or HTML before.
I installed Cytoscape.js by using npm:
npm install cytoscape
I then created a HTML file from HTML-Kit as follows:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<script src="cytoscape.js"></script>
</head>
</html>
I placed this HTML file under cytoscape.js-2.7.14 folder where the file cytoscape.js resides.
I then opened my HTML file with Chrome. The window (and tab) is opened, but there is nothing there.
I then modified my HTML file as follows:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Testing Cytoscape</title>
</head>
<body>
<script src="cytoscape.js"></script>
</body>
</html>
But there is still nothing in the window when I opened the HTML file.
Any ideas on how to run Cytoscape.js?
Thanks for advice!
Cytoscape.js is a library.
Library can't do anything by itself. You can't just run it and get a result. You need to write your code to initialize and use a library.
To use it properly, follow tutorials and guides on their website.
You can use it many ways, with a web client side only, or distributed architecture with web server.
Here is an exemple for a web client side only, where cytoscape libraries are not downloaded but referenced on the web.
You can also use it though a notebook, e.g. with Observable.
https://observablehq.com/#nfigay/test-adding-compound-with-cytoscape-js
<!DOCTYPE>
<html>
<head>
<title>Test Compound Graph Editor</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
<script src="https://unpkg.com/cytoscape#3.21.0/dist/cytoscape.min.js"></script>
<script src="https://unpkg.com/layout-base#2.0.1/layout-base.js"></script>
<script src="https://unpkg.com/cose-base#2.1.0/cose-base.js"></script>
<script src="https://unpkg.com/cytoscape-fcose#2.1.0/cytoscape-fcose.js"></script>
<script src="https://unpkg.com/cytoscape-expand-collapse#4.1.0/cytoscape-expand-collapse.js"></script>
<script src="https://unpkg.com/pure-uuid#1.6.2/uuid.js"></script>
</head>
<body>
<div id="cy" style="width:100%;height:90%;background-color:white"></div>
<div class="menu-container">
<div style="text-align:center" class="panel">
<button id="compound">Add Compound Node</button>
<button id="collapseAll">Collapse all</button>
<button id="collapseRecursively">Collapse Recursively</button>
<button id="expandAll">Expand all</button>
<button id="expandRecursively">Expand Recursively</button>
</div>
</div>
</body>
<script>
var myData = [
{ data: { id: "o", "label": "Top node" } },
{ data: { id: "a", parent: "o", "label": "a" } },
{ data: { id: "b", parent: "o" } },
{ data: { id: "c", parent: "o" } },
{ data: { id: "d", parent: "o" } },
{ data: { id: "e", parent: "o" } },
{ data: { id: "f", parent: "o" } },
{ data: { id: "a1", parent: "a" } },
{ data: { id: "b1", parent: "b" } },
{ data: { id: "c1", parent: "c" } },
{ data: { id: "d1", parent: "d" } },
{ data: { id: "e1", parent: "e" } },
{ data: { id: "f1", parent: "f" } },
{ data: { id: "a2", parent: "a" } },
{ data: { id: "b2", parent: "b" } },
{ data: { id: "c2", parent: "c" } },
{ data: { id: "d2", parent: "d" } },
{ data: { id: "e2", parent: "e" } },
{ data: { id: "f2", parent: "f" } },
{ data: { id: "a3", parent: "a" } },
{ data: { id: "b3", parent: "b" } },
{ data: { id: "c3", parent: "c" } },
{ data: { id: "d3", parent: "d" } },
{ data: { id: "e3", parent: "e" } },
{ data: { id: "f3", parent: "f" } },
{ data: { id: "a4", parent: "a" } },
{ data: { id: "b4", parent: "b" } },
{ data: { id: "c4", parent: "c" } },
{ data: { id: "d4", parent: "d" } },
{ data: { id: "e4", parent: "e" } },
{ data: { id: "f4", parent: "f" } },
{ data: { id: "a5", parent: "a" } },
{ data: { id: "b5", parent: "b" } },
{ data: { id: "c5", parent: "c" } },
{ data: { id: "d5", parent: "d" } },
{ data: { id: "e5", parent: "e" } },
{ data: { id: "f5", parent: "f" } },
{ data: { id: "a6", parent: "a" } },
{ data: { id: "b6", parent: "b" } },
{ data: { id: "c6", parent: "c" } },
{ data: { id: "d6", parent: "d" } },
{ data: { id: "e6", parent: "e" } },
{ data: { id: "f6", parent: "f" } }
];
var cy = window.cy = cytoscape({
container: document.getElementById("cy"),
ready: function () {
this.layout({
name: "fcose",
randomize: true,
fit: true,
animate: true,
nodeDimensionsIncludeLabels: true,
condense: false
}).run(20, 0, 10);
var api = this.expandCollapse({
layoutBy: {
name: "fcose",
animate: true,
randomize: false,
fit: true,
nodeDimensionsIncludeLabels: true,
condense: false
},
fisheye: true,
animate: true,
undoable: false
});
api.expandAll({
layoutBy: {
name: "fcose",
animate: true,
randomize: false,
fit: true,
nodeDimensionsIncludeLabels: true,
condense: false
},
fisheye: true,
animate: true,
undoable: false,
nodeDimensionsIncludeLabels: true,
condense: false
});
},
elements: myData,
style: [
{
selector: "node",
style: {
"label": (ele) => ele.data("label"),
"color": "blue",
"shape": "diamond"
}
},
{
selector: "node.cy-expand-collapse-collapsed-node",
style: {
"shape": "rectangle",
"border-color":"black",
"border-width":3,
"color":"blue"
}
},
{
selector: ":selected",
style: {
"overlay-color": "green",
"overlay-opacity": 0.3,
'background-color': 'green',
'shape': 'rectangle',
}
},
{
selector: ":parent",
style: {
"background-color": "yellow",
"z-compound-depth": "auto",
shape: "rectangle"
}
},
{
selector: "edge",
style: {
"target-arrow-shape": "triangle",
"target-endpoint": "outside-to-node",
"target-arrow-color": "lightgreen",
"line-color": "green",
"target-distance-from-node": 0
}
}
],
layout: { name: "fcose" },
style: [
{
selector: "edge",
style: {
"curve-style": "bezier",
"target-arrow-shape": "triangle"
}
}
],
wheelSensitivity: 0.5
});
var api = cy.expandCollapse("get");
document.getElementById("collapseAll").addEventListener("click", function () {
api.collapseAll();
});
document.getElementById("expandAll").addEventListener("click", function () {
api.expandAll();
});
document
.getElementById("collapseRecursively")
.addEventListener("click", function () {
api.collapseRecursively(cy.$(":selected"));
});
document
.getElementById("expandRecursively")
.addEventListener("click", function () {
api.expandRecursively(cy.$(":selected"));
});
document.getElementById("compound").addEventListener("click", function () {
var selection = cy.nodes(":selected");
if (selection.length < 1) {
return;
}
var parent = selection[0].parent().id();
for (let i = 1; i < selection.length; i++) {
if (parent !== selection[i].parent().id()) {
return;
}
}
var myUUID = new UUID(4);
const parentNode = {
data: { id: `${myUUID}`, parent: parent, label: "label" }
};
cy.add(parentNode);
for (let i = 0; i < selection.length; i++) {
selection[i].move({ parent: `${myUUID}` });
}
api.expandAll();
});
</script>
</html>

Categories

Resources