Cytoscape.js - draw edges below compound node - javascript

I have a set of nodes grouped inside a parent (compound) node. I would like to display the edges from the "outer" nodes (those outside the compound node) to the "inner" nodes (those inside the compound node) below the compound node.
(Approximately like this demo.)
Thus far, I've tried setting the z-index property like this, with z-index-compare set to manual, but it doesn't work:
style: [
{
selector: 'node',
style: {
'z-index-compare': 'manual',
'width': 10,
'height': 10,
'background-color': '#46A',
'z-index': 3
}
},
{
selector: ':parent',
style: {
'z-index-compare': 'manual',
'background-color': '#CDF',
'z-index': 9
}
},
{
selector: 'edge',
style: {
'z-index-compare': 'manual',
'width': 1,
'line-color': '#BCE',
'z-index': 1
}
},
{
selector: '.dense',
style: {
'z-index-compare': 'manual',
'width': 0.5,
'z-index': 1
}
}
]
The documentation for Cytoscape.js says nothing about where to specify the z-index-compare property, so maybe there's an error in my CSS.

One solution I found was to remove the z-index tags and use z-compound-depth on the :parent selector, like this:
style: [
{
selector: 'node',
style: {
'width': 10,
'height': 10,
'background-color': '#46A'
}
},
{
selector: ':parent',
style: {
'z-compound-depth': 'top',
'background-color': '#CDF'
}
},
{
selector: 'edge',
style: {
'width': 1,
'line-color': '#BCE'
}
},
{
selector: '.dense',
style: {
'width': 0.5
}
}
]

Related

Setting node style in cytoscapeJs

As you can see below not all the node style that i declare are working. I want to make the text inside the node larger and in the documentation i found the code: 'labelFontSize': 100. Than, i want to make the edge weight (that you cannot see in the picture but are present) white, and the code "labelFontColor": "white" isn't working. I am using CytoscapeJs.
Can someone explain to me why this happen?
My code is the following:
var json_obj = response.Cy_json_archi_prima_di_chiusura_atk_supp
var cy = cytoscape({
container: document.getElementById('cy_atk_supp'),
elements: JSON.parse(json_obj),
style: [
{
selector: 'node',
style: {
'shape': 'circle',
'labelFontSize': 100,
'label': 'data(label)',
'text-valign': 'center',
'text-halign': 'center',
'color': 'black',
"height": 150,
"width": 150,
'border-width': '2px',
'border-color': 'black',
'background-color': '#399AF9'
//'font-size': 20
}
},
{
selector: 'edge',
style:{
'label': 'data(weight)',
'labelFontSize': 300,
"labelFontColor": "white",
'labelFontWeight': 'bold',
'lineColor': 'data(color)',
'width': 3,
'target-arrow-color': 'data(color)',
"curve-style": "bezier",
'target-arrow-shape': 'triangle',
}
}
],
layout: {
name : 'circle'
}
});
And this is the resulting Graph:
I was checking the wrong library.
For cytoscapeJS these is the correct style option: https://js.cytoscape.org/#style/labels

Node max size in cytoscape.js dagre layout?

A major part of the project I'm building involves allowing users to create and edit DAGs fluidly. I'm using React, cytoscape.js, cytoscape edgehandles, and the dagre layout to accomplish this, and it's working pretty well, except for one annoying problem. When the graph only has a few nodes, the nodes are huge!
This is because I have fit set to true (the default) in the layout options. I need to keep this setting, because as the graphs grow I want them to zoom out to fit unless the user chooses to zoom in. I just don't want the first 1 - 4 nodes to be huge! Is there any way to define a max height/width for the nodes, or control the zoom level, or something, so that the nodes start off at a reasonable size and only start getting smaller when they have to?
Here's my layout:
cy.layout({
name: 'dagre',
ranker: 'longest-path',
padding: 15
}).run();
And here's my style settings:
const cyConfig = {
elements: [],
style: [
{
selector: 'node',
style: {
'label': 'data(name)',
'color': '#2C2029',
'text-valign':'center',
'text-halign': 'center',
'font-size': '25px',
'font-family': 'Nixie One, cursive',
'shape': 'roundrectangle',
'background-color': 'mapData(inDegree, 1, 8, rgba(163, 154, 164), rgba(240, 146, 60))',
'background-opacity': 'mapData(inDegree, 1, 8, .3, 1)',
'border-color': 'transparent',
'width': 'label',
'height': 'label',
'padding': '7px'
}
}, {
selector: 'edge',
style: {
'curve-style': 'bezier',
'target-arrow-shape': 'triangle',
'target-arrow-fill': 'hollow',
'target-arrow-color': '#2C2029',
'width': '1px',
'color': '#2C2029',
}
}
]
};
You can always define your nodes like this:
style: [
{
selector: 'node',
style: {
'shape': 'data(faveShape)',
'content': 'data(DisplayName)',
'height': 'data(faveHeight)',
'width': 'data(faveWidth)',
'background-color': 'data(faveColor)',
'line-color': '#a8eae5',
'font-family': 'Segoe UI',
'font-size': '15px',
}
}
]
If you do so, you can check how many nodes you want to add to your cytoscape window and then define their width and height properties according to the number of nodes you want to add:
jsonNew.push({
data: {
id: yourId,
parent: '',
faveShape: 'yourShape',
faveHeight: ((nodes.length > 7) ? nodes.length * 3 : nodes.length * 6),
faveWidth: ((nodes.length > 7) ? nodes.length * 5 : nodes.length * 10),
faveColor: '#ffffff'
},
position: {
x: '',
y: ''
},
parents: '',
group: 'nodes',
removed: false,
selected: false,
selectable: true,
locked: false,
grabbable: true,
classes: ''
});

Qtip not working with jquery and ajax in Cytoscape.js

I am trying to dynamically load a Cytoscape JSON elements file and display qtip text when a node in the network is clicked. This exact same code works when I hard code the network in the code so there is nothing wrong with the cyjs file or the qtip part of the code. Somehow the qtip is not working with ajax and jquery.
Any help would be appreciated! Thank you!
$(function() {
$.get('demo.cyjs', function( data ) {
$('#cy').cytoscape({
layout: {
name: 'concentric',
concentric: function( node ){
return node.degree();
},
levelWidth: function( nodes ){
return 2;
}
},
style: cytoscape.stylesheet()
.selector('node')
.css({
'content': 'data(name)',
'text-valign': 'bottom',
'color': 'white',
'font-size': 10,
'background-color': 'data(faveColor)'
})
.selector('edge')
.css({
'target-arrow-shape': 'none',
'curve-style':'haystack',
'line-color':'data(faveColor)',
'line-style': 'data(style)',
'haystack-radius': 0,
'width':'data(Ratio)'
})
.selector(':selected')
.css({
'background-color': 'grey',
'target-arrow-color': 'grey',
'source-arrow-color': 'grey',
'border-width': 3,
'border-color': '#333'
})
.selector('.faded')
.css({
'opacity': 1,
'text-opacity': 0
}),
elements : JSON.parse(data),
});
})
cy.nodes().forEach(function(n){
var a = n.data('ensembl_id');
var p=n.data('primes_id');
var e=n.data('ncbi_id');
var u=n.data('uniprot_id');
n.qtip({
content: [
{
name: 'ENSEMBL',
url: 'http://www.ensembl.org/Homo_sapiens/Gene/Summary?db=core;g='+ a
},
{
name: 'UniProt',
url: 'http://www.uniprot.org/uniprot/'+ u
},
{
name: 'NCBI',
url: 'https://www.ncbi.nlm.nih.gov/gene/' + e
}
].map(function( link ){
return '<a target="_blank" href="' + link.url + '">' + link.name + '</a>';
}).join('<br />\n'),
position: {
my: 'top center',
at: 'bottom center'
},
style: {
classes: 'qtip-bootstrap',
tip: {
width: 16,
height: 8
}
}
});
});
$('#config-toggle').on('click', function(){
$('body').toggleClass('config-closed');
cy.resize();
});
});
This is my updated code. I have initialised cy element in the body tag
<div id="cy"></div>
$(function() {
let toJson = res => res.json();
let cy = new cytoscape({
layout: {
name: 'concentric',
concentric: function( node ){
return node.degree();
},
levelWidth: function( nodes ){
return 2;
}
},
style: cytoscape.stylesheet()
.selector('node')
.css({
'content': 'data(name)',
'text-valign': 'bottom',
'color': 'white',
'font-size': 10,
'background-color': 'data(faveColor)'
})
.selector('edge')
.css({
'target-arrow-shape': 'none',
'curve-style':'haystack',
'line-color':'data(faveColor)',
'line-style': 'data(style)',
'haystack-radius': 0,
'width':'data(Ratio)'
})
.selector(':selected')
.css({
'background-color': 'grey',
'target-arrow-color': 'grey',
'source-arrow-color': 'grey',
'border-width': 3,
'border-color': '#333'
})
.selector('.faded')
.css({
'opacity': 1,
'text-opacity': 0
}),
elements: fetch('demo.cyjs').then( toJson ),
});
cy.ready( () => {
var a = n.data('ensembl_id');
var p=n.data('primes_id');
var e=n.data('ncbi_id');
var u=n.data('uniprot_id');
n.qtip({
content: [
{
name:'PrimesDB',
url:'http://primesdb.org/molecules/view/'+ p
},
{
name: 'ENSEMBL',
url: 'http://www.ensembl.org/Homo_sapiens/Gene/Summary?db=core;g='+ a
},
{
name: 'UniProt',
url: 'http://www.uniprot.org/uniprot/'+ u
},
{
name: 'NCBI',
url: 'https://www.ncbi.nlm.nih.gov/gene/' + e
}
].map(function( link ){
return '<a target="_blank" href="' + link.url + '">' + link.name + '</a>';
}).join('<br />\n'),
position: {
my: 'top center',
at: 'bottom center'
},
style: {
classes: 'qtip-bootstrap',
tip: {
width: 16,
height: 8
}
}
});
});
$('#config-toggle').on('click', function(){
$('body').toggleClass('config-closed');
cy.resize();
});
});
Structure your init like this:
let toJson = res => res.json();
let cy = new Cytoscape({
elements: fetch('some/cytoscape/elements.json').then( toJson ),
style: fetch('some/cytoscape/style.json').then( toJson ),
// ...
});
cy.ready( () => {
// specify qtips here, after the external data is loaded
} );
// or if you prefer promises, you can use a ready promise
// let readyPromise = new Promise( resolve => cy.ready(resolve) );
You're not waiting for the elements to load from your JSON file, so there are no elements in the graph when you do your forEach(). It's often easier to let Cytoscape handle the loading of the elements and the stylesheet for you. Just specify promises in place of in-line objects/JSON.
I also don't see any cy variable in your code.
Anything in the cy.ready() callback will execute only after the data from init has loaded properly. A side benefit is that you can easily separate your stylesheet into a new JSON file, keeping your code shorter and making it easier to switch between stylesheets.

Adjust shape size in cytoscape.js with dagre layout

I am trying to resize the shapes of the nodes to the size of the node text. I followed instructions from https://github.com/cytoscape/cytoscape.js/issues/649 . However:
The shapes always end up with height = width
The size of all shapes is the same.
The shape size seems to reach a max above which it can't grow.
(I am not sure if this has something to do with dagre layout.)
I am using the following libraries with the dagre layout:
cytoscape.min.js
dagre.min.js
cytoscape-dagre.js
container: document.getElementById('cy'),
boxSelectionEnabled: false, autounselectify: true,
layout: {name: 'dagre', rankDir: 'LR', align: 'LR'},
style: [{
selector: 'node',
style: {
'content': 'data(name)',
'label': 'data(name)',
'text-opacity': 1,
'text-valign': 'center',
'text-halign': 'center',
'text-wrap': 'wrap',
'font-size': 9,
'background-color': '#AAA',
'shape':'rectangle',
'width': 'data(width)' * 50,
'height': 'data(height)' * 50 }
},{
selector: 'edge',
style: {
'width': 4,
'content': 'data(name)',
'target-arrow-shape': 'triangle',
'line-color': 'data(color)',
'text-wrap': 'wrap',
'target-arrow-color': 'data(color)',
'font-size': 10,
}
}]
You've specified invalid style. "somestring" * 50 is NaN.
You want width: label, as indicated in the docs: http://js.cytoscape.org/#style/node-body

How can I change the attrs of a custom object in JointJS?

I created a custom element with the JointJS library . The object have two nested Rectangles with two associated Texts.
I want to change his atributtes inside de Model... I only get through JQUERY change his attributes and css, through its ids.
I want to change the attrs in the model and then, update the node to show his new look.
Sorry if I can not explain it well enough, I leave a jsFiddle ->
http://jsfiddle.net/y9ucn/
If you need additional information, please ask.
Thank you.
Here's the class who defines my custom object and on the jsfiddle you can play an example:
MyRect = joint.shapes.basic.Generic.extend({
markup: [
'<g class="rotatable">',
'<g class="scalable">',
'<rect class="firstRect"/><rect class="secondRect"/>',
'</g>',
'<text class="textFirstRect"/><text class="textSecondRect"/>',
'</g>'].join(''),
defaults: joint.util.deepSupplement({
type: 'basic.MyRect',
attrs: {
'.firstRect': {
'stroke': '#0A1317',
'stroke-width': 1,
'fill': '#DBF024',
'width': 100,
'height': 30,
},
'.secondRect': {
'stroke': '#0A1317',
'stroke-width': 1,
'fill': '#DBF024',
'width': 100,
'height': 30,
},
'.textFirstRect': {
'ref': '.firstRect',
'ref-x': .5,
'ref-y': .5,
'y-alignment': 'middle',
'x-alignment': 'middle',
'fill': '#333',
'font-size': 12,
'font-family': 'Calibri,Arial',
},
'.textSecondRect': {
'ref': '.secondRect',
'ref-y': .5,
'ref-x': .5,
'y-alignment': 'middle',
'x-alignment': 'middle',
'fill': '#333',
'font-size': 12,
'font-family': 'Calibri,Arial'
}
}
}, joint.shapes.basic.Generic.prototype.defaults),
initialize: function () {
_.bindAll(this, 'format');
this.format();
joint.shapes.basic.Generic.prototype.initialize.apply(this, arguments);
},
format: function () {
var attrs = this.get('attrs');
attrs['.secondRect'].transform = 'translate(0,30)';
}
});
You can use the attr() method:
cellView.model.attr('.textSecondRect/text', 'foo');
See the API reference: http://jointjs.com/api#joint.dia.Element:attr.

Categories