I'm using Cytoscape.js to represent a network diagram. I can highlight more than one node at a time by selecting the first node followed by the second node while holding the shift key.
How can I have all the node ids that I have selected available in Javascript? For example and this would be ideal, if all the node ids that have simultaneously selected where organized into a Javascript list.
I looked in the cytoscape.js docs and could not find the location where this is described.
To receive ids of all selected:
elements
var typeIds = cy.elements(':selected');
nodes
var typeIds = cy.elements('node:selected');
edges
var ConnIds = cy.elements('edge:selected');
In order to get Ids of all selected nodes you could try this:
cy = window.cy = cytoscape ({
container : document.getElementBy('cy'),
// define a style for selected node
style : cytoscape.stylesheet()
.selector('node')
.css ({..............})
.selector('edge')
.css({...............})
.selector('node:selected')
.css({ 'border-color' : 'red'})
}),
elements : eles,
layout : {.............}
});
Related
I want to filter all nodes not further away then one edge of a given node. I dont have a compound graph. I tried
var children = cy.$('#1').components()
But this only returns the node #1. I also tried
var allEles = cy.elements()
var myChildren = allEles.componentsOf(cy.$('#1'))
But this seems to return all nodes again. The docs also state a selector syntax "> (child selector) Matches direct children of the parent node (e.g. node > node)." But I cant figure that one out either. I tried
var myChildren = cy.elements('node#1 > node')
getting an empty array.
So, how can filter for direct children (depth=1) of a given node?
Did you try use:
// outgoers return all elements (edges as well) comming out from $('#1')
// nodes() > select only nodes
var children = cy.$('#1').outgoers().nodes();
doc: https://js.cytoscape.org/#nodes.outgoers
I am currently using Cytoscape to create a large graph with 500 nodes. I am using Dagre for the hierarchical layout.
Currently the graph is small on the screen because of number of nodes which makes sense but
Is there a way to focus on a single node once the graph is created. Or can I zoom in on a part of graph?
I have tried using animate filter on dagre but it animates the whole graph and does not focus or zoom in on one node or one part of the graph.
this.cy
.layout({
name: "dagre",
padding: 30,
animate: true, // whether to transition the node positions
animateFilter: function( node, i ){
if ( node[0]._private.data.type === "student") {
return true;
}
},
transform: function( node, pos ){ return pos; },
})
.run();
Also tried zoom, But I only want to zoom one or set of nodes at the same time
cy.zoom({
level: 1.1, // the zoom level
//How can I filter the nodes I want?
});
The cytoscape.js-cola documentation for the gapInequalities element of a layout dictionary says:
gapInequalities: undefined, // list of inequality constraints for the gap between the nodes,
// e.g. [{"axis":"y", "left":node1, "right":node2, "gap":25}]
How do you set up the objects that specify the nodes in the values of left and right?
maxkfranz helpfully pointed out here that these objects need to be collection objects. These contain references to specified nodes ("elements") and are created by querying the cytoscape.js "core object". What's not clear to me is, given that the layout object needs to refer to the node elements, and the elements should not be added to the graph before the layout tells how to render them, how do you properly set up those collection objects?
For example, to specify that node b should be placed above node a, what goes in place of ???a??? and ???b??? in the code below?
cy = cytoscape({
elements: [
{ data: { id: 'a' } },
{ data: { id: 'b' } },
. . .
],
layout: {
name: 'cola',
gapInequalities: [
{ axis: 'y', left: ???'a'???, right: ???'b'???, gap: 25 }
. . .
],
. . .
}
. . .
]);
In this case, the answer can't be cy.$id('a') and cy.$id('b') because the cy object hasn't been created yet. You could get around that by creating the cy object without elements and then calling cy.add() to put them in. But then what goes in the layout object that's passed to cytoscape()?
I'm new to both cytoscape.js and cola.js, so I'm most likely just missing some very elementary idea here. A simple example showing what function calls set up the objects and the sequence in which to call them would probably do it. In my application, nodes and edges are added to the graph gradually, and the animation needs to show them being added, so not having all the elements set up at the start makes more sense, anyway.
Since your nodes and edges are added gradually, you can create cy object without elements and layout object. Then when new nodes come, you can add them to the graph and apply layout.
After initialization of the cy object, every time new nodes come, apply the following :
cy.add(...);
cy.layout({
name: 'cola',
gapInequalities: [{ axis: 'y', left: cy.$id("a"), right: cy.$id("b"), gap: 25 }],
...
}).run();
I want to display several instances of cytoscape in a single page, in a time sequence: first one set of nodes are displayed on the graph, the user must interact with it (create edges), then he moves to a second graph (#cy0 is :hidden and #cy1 is :visible).
For code optimisation sake I wish to use the same initialisation function to display different successive sets of nodes. My initialisation function works fine in the first instance, but the graph is not created (cy.initrender() == false) in the second session. A command is probably missing, I tested a couple, but I don't see what to do.
Here is my code:
//elements
$(function(){ // on dom ready
var elesJson = {
nodes: [
{ data: { id: 'S', faveShape: 'rectangle',} }
...
],
edges: [
{ data: { id: 'loan', source: 'B', target: 'U' } },
...
],
};
// instance index
var indexLevel=0;
// cy initialisation
$("#cy"+indexLevel).cytoscape({
style: cytoscape.stylesheet()...
elements: elesJson,
ready: function(){
window.cy = this;});
// jQuery command to move from one instance to the other.
$('#next').click(function(){
$("#cy"+indexLevel).css("visibility","hidden");
indexLevel++;
$("#cy"+indexLevel).css("visibility","visible");
cy.load(elesJson);
cy.ready();
console.log(cy.initrender());
});
I am able to generate my node.collection, it is not empty, but the canvas element is not created and/or displayed within the #cy div, and cy.initrender() returns "false".
Any solution to this?
As noted in the docs for init, you must call cy.resize() if you play around with the cy div's display or position: http://js.cytoscape.org/#core/initialisation
cy.resize() : http://js.cytoscape.org/#core/viewport-manipulation/cy.resize
Edit: You may want to use z-index instead to simplify things...
So I'm a first time user of dgrid, and I'm currently building my tree grid like this:
var SelectionGrid = new declare([OnDemandGrid, Selection, Keyboard]);
var myGrid = new SelectionGrid({
store: myStore,
selectionMode: "single",
style: {
width: '99%',
height: '99%'
},
columns: columns
});
My problem is, the grid shows metadata for features I'm drawing in openlayers. I've written code in openlayers so that whenever I click on a feature on the map, it fires an event to scroll to that item in the grid and select it. The grid, however, doesn't pre-load the children for each parent, it only fetches the children when the parent row is expanded.
Currently I'm programmatically expanding every row and then reclosing them to force it to fetch, but it's terribly slow and ends up causing browser warnings about javascript taking too long to run, etc.
Is this a side effect of using OnDemandGrid? Is there anyway to just have all the data loaded so it's all available when the grid is rendered?
I had another issue and wanted to post another answer in case anybody has the same problem. When not using the Tree plugin and just using the OnDemandGrid, I couldn't programattically scroll to items in the grid that hadn't been loaded because the element for the row was null.
I found a property that tells the OnDemandGrid the minimum number of items to load from the store, and just set it to the length of my data, so it loads everything at once. I know that defeats the purpose/benefit of the OnDemandGrid, but it's the functionality I need. Here's the code:
var SelectionGrid = new declare([OnDemandGrid, Selection, Keyboard, DijitRegistry]);
var grid = new SelectionGrid({
store: store,
selectionMode: "single",
columns: columns,
minRowsPerPage: data.length,
farOffRemoval: 100000
});
Here's the reference for minRowsPerPage and farOffRemoval:
http://dojofoundation.org/packages/dgrid/tutorials/grids_and_stores/
I wasn't able to preload all my data, but I just discovered the glory of dojo/aspect. Now I find the parent item that needs expanded and I just build some code inside an aspect/after block that gets executed as soon as that row is finished expanding/loading:
aspect.after(grid, "expand", function (target, expand) {
var row = grid.row(id);
console.info("found row: ", row)
grid.bodyNode.scrollTop = row.element.offsetTop;
grid.clearSelection();
grid.select(row);
},
true);
grid.expand(item.id, true);