I'm trying to explore the cytoscape graph core object and I want to access its properties in runtime. Can I use Node.js interpreter to instantiate the cy object and run methods on the elements ? If this is an option, I also don't understand where 're real graphics going to be displayed. Is Node.js will open a browser window ?
Node.js REPL represents JavaScript interpreter, but it has no relation to DOM. From the examples on how to use cytoscape, the DOM is required:
var cy = cytoscape({
container: document.getElementById('cy') // container to render in
});
So it seems you can't use cytoscape's visual features with REPL. However, the docs says that:
container : A HTML DOM element in which the graph should be rendered.
This is unspecified if Cytoscape.js is run headlessly.
But I think you can use REPL to run Cytoscape headlessly.
Actually i just find how to run Cytoscape in a REPL environment. still didnt find a way to display it graphically, but i can interact with the object to explore its properties :
$ node
>var cytoscape = require('cytoscape');
>var cy = cytoscape({
container: document.getElementById('cy'), // container to render in
elements: [ // list of graph elements to start with
{ // node a
data: { id: 'a' }
},
{ // node b
data: { id: 'b' }
},
{ // edge ab
data: { id: 'ab', source: 'a', target: 'b' }
}
],
style: [ // the stylesheet for the graph
{
selector: 'node',
style: {
'background-color': '#666',
'label': 'data(id)'
}
},
{
selector: 'edge',
style: {
'width': 3,
'line-color': '#ccc',
'target-arrow-color': '#ccc',
'target-arrow-shape': 'triangle'
}
}
],
layout: {
name: 'grid',
rows: 1
}
});
After i instantiate the cy object, i can interact with it by typing :
> cy.
cy.__defineGetter__ cy.__defineSetter__
cy.__lookupGetter__ cy.__lookupSetter__
cy.__proto__ cy.constructor
cy.hasOwnProperty cy.isPrototypeOf
cy.propertyIsEnumerable cy.toLocaleString
cy.toString cy.valueOf
> cy.elements().forEach(function(e){ console.log(e.data())});
{ id: 'a' }
{ id: 'b' }
{ id: 'ab', source: 'a', target: 'b' }
Related
i have an object and need to convert it into css, ex:
const options = {
style: {
base: {
background: 'red',
':hover': {
background: 'green',
},
},
},
};
i used package jso-to-css works fine but in case nested object like hover return [Object]
base{background:red;:hover:[object Object]}
instead of
base{background:red;}
base:hover{background: green;}
also, any suggestion compatible with react is welcomed.
If you change yor data structure - you can create style rules easily frm an object or JSON etc.
Knowing the anatomy of a style rule has three parts - selector / property and value - you can create a data structure to allow for these to be parsed into strings and then inserted either into an existing style sheet - or you can create an entirely new stylesheet, append it to the document head and then insert the rules.
You will need to create a plan to allow the code to know about nesting - for example - I am using pseudostates as a child array to allow the styling of the base element - and iterate over the pseudostates array and for each - pass it to the same createStyle function as the original base element, and create their style rules... you can do this to any depth and with any type of styling - you jsut need to plan for it and update the structure of the data to match the planned styling.
In the following - i am setting the background color and text color of the p element and then changing both on the hover. You could extend this to have the type of selector (id or class) - but will leave that for further development. This includes the "#" or the "." in the selector.
const options = [{
selector: '.base',
declarations: [{
property: 'background',
value: 'red',
},{
property: 'color',
value: 'white',
}],
pseudoStates:[{
selector: ':hover',
declarations: [{
property: 'background',
value: 'green'
},{
property: 'color',
value: 'orange'
},{
property: 'cursor',
value: 'pointer'
}]
}]
}, {
selector: '#extra',
declarations: [{
property: 'background',
value: 'aqua',
},{
property: 'color',
value: 'black',
}],
pseudoStates:[{
selector: ':hover',
declarations: [{
property: 'background',
value: 'blue'
},{
property: 'color',
value: 'white'
}]
}]
}]
options.forEach(function(option){
createStyleRule(option.selector, option.declarations);
option.pseudoStates.forEach(function(pS){
createStyleRule(option.selector + pS.selector, pS.declarations);
})
});
function createStyleRule(selector, declarations){
let styleDeclarations = [];
declarations.forEach(function(dec){
styleDeclarations.push( dec.property +": " + dec.value);
})
let styleRule = selector + " {" + styleDeclarations.join("; ") + "}";
document.styleSheets[0].insertRule(styleRule, 0);
}
<p class="base">This is the base element</p>
<p id="extra">This is the extra element</p>
cytoscape.js to fails to render the graph if the graph has redundant edges/arcs. Why is this happening?
Example:
https://jsfiddle.net/smiccke/mq5t1rw9/4/
$(function() {
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
ready: function() {},
style: [{
selector: 'node',
css: {
'content': 'data(name)'
}
}, {
selector: 'edge',
css: {
'target-arrow-shape': 'triangle'
}
}],
elements: {
nodes: [{
data: {
id: 'j',
name: 'Jerry'
}
}, {
data: {
id: 'e',
name: 'Elaine'
}
}, {
data: {
id: 'k',
name: 'Kramer'
}
},
],
edges: [{
data: {
source: 'j',
target: 'e'
}
}, {
data: {
source: 'j',
target: 'k'
}
}
]
}
});
});
The graph works if you remove the two redundant edges from the end (j->e, j->e).
It seems like one redundant edge is ok, but two or more is a problem. Any clues why this is so?
As workaround, any nice short-cuts to remove redundant edges from the graph?
All the edges are there. You've rendered all parallel edges on top of one another, because that's how your edge style is specified.
Use appropriate style for the type of graph you're rendering. E.g., a multigraph should probably use haystack edges with a non-zero haystack radius or bundled bezier edges.
Refer to curve-style etc. in the docs: http://js.cytoscape.org/#style/edge-line
Edit: you mention that cytoscape.js fails to render the graph, but it renders fine for me. Are you truly not seeing any graph at all? If so, what browser are you using, and have you checked your code for errors?
Multiple edges between nodes default along the same path as maxkfranz said. You can set the 'curve-style': 'bezier' which will show all of the edges, or use 'haystack-radius': 1 to keep straight lines (play with values between 0 and 1).
I also noticed you have directed arrows turned on. These won't work with the default 'haystack' curve style, so I would suggest you use 'bezier' if you want to visualize directed edges.
I am attempting to create a Dojo layout using this code:
require([ 'dijit/registry', 'dijit/layout/BorderContainer', 'dijit/layout/TabContainer', 'dijit/layout/ContentPane', 'dojo/store/Memory', 'gridx/core/model/cache/Sync', 'gridx/Grid', 'dojox/dgauges/components/default/HorizontalLinearGauge', 'dojox/charting/Chart', 'dojo/domReady!' ], function(
registry,
BorderContainer,
TabContainer,
ContentPane,
Memory,
Sync,
Grid,
HorizontalLinearGauge,
Chart
) {
Layout = new BorderContainer({
'design' : 'headline',
'class': 'borderContainerLayout'
}, 'dashboardLayout');
Layout.addChild(new ContentPane({
'id': 'layoutRight',
'region' : 'right',
'content': '<div id="days-between-purchases"></div>',
'splitter': true
}));
Layout.startup();
var hlg = new HorizontalLinearGauge({
'title': 'Purchase Cycle (Average # of days between purchases)',
'srcRefNode': 'abc',
'value': 20,
'class': 'gauge',
'noChange': true,
'width': 150,
'height': 150,
'min': 0,
'max': 100,
}, registry.byId('days-between-purchases'));
hlg.render();
There is more code to add a center, left, etc to the BorderContainer, but the problem I'm getting is "Unable to get property 'nodeType' of undefined or null reference. From the DOM captured at the time, it seems that the layout is not yet rendered into the DOM, so it cannot find registry.byId('days-between-purchases'). I have tried about 10 different ways of trying to put this together to render the layout and gauge during run time and searched heavily for a solution, but have come up with nothing.
What am I doing wrong? Do you know of a tutorial which shows how to fully render a layout with a gauge at runtime? Sample code?
Thanks, in advance.
FYI: I am using the latest version of dojo with this dojoConfig:
var dojoConfig = {
baseUrl : "//ajax.googleapis.com/ajax/libs/dojo/1.9.1/",
async : true,
isDebug : true,
parseOnLoad : false,
//gfxRenderer: "svg,silverlight,vml",
packages : [ {
name : "dojo",
location : "dojo"
}, {
name : "dijit",
location : "dijit"
}, {
name : "dojox",
location : "dojox"
}, {
'name': 'gridx',
'location': '/resources/common/javascript/gridx'
}]
};
Hard to understand what is going on as your sample does not seem to be fully runnable? In particular I don't think gauges have a render() method and you are calling render on it?
In dojox/dgauges/tests/test_all.html you will find a test showing gauges used in a BorderContainer. Maybe it can help.
I am trying to use Cystoscape (http://cytoscape.github.io/cytoscape.js/) to create a star layout. I am able to get all the nodes and relate them accordingly. What i am unable to do is to make the central node appear in the center while the others appearing in a constellation fashion.
$('#cy').cytoscape({
elements: [
{ // node n1
group: 'nodes', // 'nodes' for a node, 'edges' for an edge
data: { // element data (put dev data here)
id: 'n1', // mandatory for each element, assigned automatically on undefined
parent: 'nparent', // indicates the compound node parent id; not defined => no parent
},
position: { // the model position of the node (optional on init, mandatory after)
x: 100,
y: 100
},
selected: false, // whether the element is selected (default false)
selectable: true, // whether the selection state is mutable (default true)
locked: false, // when locked a node's position is immutable (default false)
grabbable: true, // whether the node can be grabbed and moved by the user
classes: 'foo bar' // a space separated list of class names that the element has
},
{ // node n2
group: 'nodes',
data: { id: 'n2' },
renderedPosition: { x: 200, y: 200 } // can alternatively specify position in rendered on-screen pixels
},
{ // node n3
group: 'nodes',
data: { id: 'n3', parent: 'nparent' },
position: { x: 123, y: 234 }
},
{ // node nparent
group: 'nodes',
data: { id: 'nparent' }
},
{ // edge e1
group: 'edges',
data: {
id: 'e1',
source: 'n1', // the source node id (edge comes from this node)
target: 'n2' // the target node id (edge goes to this node)
}
}
],
// so we can see the ids
style: cytoscape.stylesheet().
selector('node')
.css({
'content': 'data(id)'
})
});
Additional problem i am facing is the ability to add a new node. Being new to this library, i would appreciate any help.
Look at the link http://cytoscape.github.io/cytoscape.js/#style/properties
and change the node property "shape" to "star" as follows. It will automatically change your topology to star shape. Then you will not need to specify positions x,y of each node. And it will automatically appear in center
shape:star
I am trying to interact with a javascript api (bare in mind I have never done this before). An example of what I am attempting to work with is here:
SearchSpring.Catalog.init({
leaveInitialResults : true,
facets : '.leftNav',
results : '#results',
result_layout: 'list',
results_per_page : 12,
layout: 'top',
loadCSS: false,
filters: {
color: ['Blue']
},
backgroundFilters: {
category: ['Shirt', 'Shoes'],
department: ['Mens']
},
maxFacets: 5,
maxFacetOptions: 10,
sortText: 'Sort By ',
sortType: 'dropdown',
filterText: 'Refine Search Results',
previousText: 'Previous',
scrollType: 'scroll',
scrollTo: 'body',
backgroundSortField: 'price',
backgroundSortDir: 'desc',
compareText: 'Compare Items',
summaryText: 'Current Filters',
showSummary: true,
subSearchText: 'Subsearch:',
showSubSearch: true,
forwardSingle: false,
afterResultsChange: function() { $('.pagination').hide(); },
filterData: function(data) { console.debug(data); }
});
In the example I want to add a "backgroundFilter" to this with a value:
var cat="MyNewCategory";
cat.value="ANewValue;
How would I add this category and value to the backgroundFilters: listed above?
This is a very common framework initialization pattern when working with frameworks.
Your example code is passing a JavaScript Object {} as a parameter into a function () that is called init.
Taking out all definitions the pattern looks like this:
SomeFramework.frameworkFunction({});
In the above code the {} is an empty object used for initialization. There are two ways that you can work with that object in practice.
Regarding your first code snippet, you can add code into that 'object literal'.
backgroundFilters: {
category: ['Shirt', 'Shoes'],
department: ['Mens'],
cat: ['My value']
},
Notice the added comma, this is an important tripping point. This may or may not fit your needs, depending on a few factors.
Regarding your second code snippet, you can apply members to JavaScript objects at runtime. What I mean is, your var cat can be added to the anonymous object-literal that is being passed in. Hard to say, but a simple concept. Here is how:
//Say this is initialized in some separate way. //There is a bug here I'll describe later.
var cat="MyNewCategory";
cat.value="ANewValue";
//Extract and name the initialization object. It is verbatim at this point.
var initObject = {
leaveInitialResults : true,
facets : '.leftNav',
results : '#results',
result_layout: 'list',
results_per_page : 12,
layout: 'top',
loadCSS: false,
filters: {
color: ['Blue']
},
backgroundFilters: {
category: ['Shirt', 'Shoes'],
department: ['Mens']
},
maxFacets: 5,
maxFacetOptions: 10,
sortText: 'Sort By ',
sortType: 'dropdown',
filterText: 'Refine Search Results',
previousText: 'Previous',
scrollType: 'scroll',
scrollTo: 'body',
backgroundSortField: 'price',
backgroundSortDir: 'desc',
compareText: 'Compare Items',
summaryText: 'Current Filters',
showSummary: true,
subSearchText: 'Subsearch:',
showSubSearch: true,
forwardSingle: false,
afterResultsChange: function() { $('.pagination').hide(); },
filterData: function(data) { console.debug(data); }
};
//Now we can add variables (and functions) dynamically at runtime.
initObject.cat = cat;
//And pass them into the framework initialization in a separated way.
SearchSpring.Catalog.init(initObject);
Now for the bug. I don't know the solution because I do not know what it is intended to do, but I can point out what is potentially incorrect.
var cat="MyNewCategory";
cat.value="ANewValue;
This code is: 1 creating a String Object called cat. 2 changing the value to a new string.
I do not think this is what you really want.
To add a new backgroundFilter, in the separated way above, it would be:
initObject.backgroundFilters.cat = ['A', 'B'];
//Line above would give you this type of definition within the initObject (at runtime):
backgroundFilters: {
category: ['Shirt', 'Shoes'],
department: ['Mens'],
cat: ['A','B']
},
For this to work it will depend on what the framework is expecting regarding backgroundFilters.
Hope that helps.
All the best!
Nash
I don't quite understand - do you want to have the backgroundFilters categories as structured objects rather than plain strings? If you are in control of the entire API, you can do something like
...
backgroundFilters: {
category: [
new SearchSpring.Catalog.Category("Shirt"),
new SearchSpring.Catalog.Category("Shoes"),
new SearchSpring.Catalog.Category("MyNewCategory", "ANewValue")
],
department: 'Mens'
}
...