Sizing Node Relative to Label in cytoscape - cytoscape.js

So I'm aware you can use a function to compute a css property in Cytoscape.js e.g.
cytoscape.stylesheet()
.selector('node')
.css({
'width': function(ele) {
return 12;
})
I'm also aware of the special value 'label' that can be the value of the property e.g.
cytoscape.stylesheet()
.selector('node')
.css({
'width': 'label'
})
What I'm wondering is is there any particular property I could use to scale the label by some factor, e.g. what I want is something like
cytoscape.stylesheet()
.selector('node')
.css({
'width': function(ele) {
return labelWidth * 1.5; //Where to get labelWidth from
})
Specially I want the ability to be able to calculate the height and width of an ellipse so that the label is completely contained within the ellipse (which can be computed using some math e.g. Ellipse bounding a rectangle).
But I haven't been able to find a way to get the labelWidth. I did manage to do it using rscratch but only if the node actually got rendered twice (e.g. multiple .selectors), any proper way to get the label width and height from a given element (or at least a way to calculate how it'll be rendered?).

If you want to do more sophisticated sizing, your calculations are going to have to be more sophisticated.
Options :
(1) Calculate the dimensions of the text yourself using a div.
(2) Use the auto sizing, and then adjust the size based on the current size.
(1) is cleaner than (2).
It doesn't make sense for Cytoscape.js to expose rendered calculated values for you in the stylesheet. Those values are calculated from the stylesheet, creating a dependency cycle.

If you just want the label inside your node, you could just set the padding attribute to make more space around the text.

Related

Cytoscape disappearing edges with bezier curves and nodes moving/longer labels in nodes

I am using cytoscape with bezier curves but edges are disappearing when having a node with longer label or just moving source node next to target node.
Video: https://www.screencast.com/t/N2f5eZ5M7
Runnable sample: https://stackblitz.com/edit/web-platform-vpl72r?file=index.html
I have already seen "Edge xxxxx has invalid endpoints and so it is impossible to draw" warning and searched corresponding threads but couldn't find a solution.
Does anyone know how to handle that ?
I see some warnings on the console
The style value of label is deprecated for width
The style value of label is deprecated for height
After I deleted 'width': 'label', 'height':'label', I no longer observe such problem.
--- Update 1.1 ---
but I'd like to have node's dimensions based on label's dimensions.
To do this I think you should write a function style. See the below example. In the example, you can see that we are setting the size of the nodes dynamically based on their name length. I assumed name is a string that stores labels.
cy.style().selector('node').style({
'width': (x) => { return x.data('name').length + 'px;' }
'height': (x) => { return x.data('name').length + 'px;' }
}).update();

Border-Shadow and decrease the size of parent element css in cytoscape

I have a following image:
I am trying to add border shadow to the rectangle shape. Is that possible in cytoscape? Also, the parent elements are Customers and order. Can I decrease the size of customers and order parent element?
Here's is the link to the code and the working example:
https://stackblitz.com/edit/angular-kpnys1?file=src%2Fapp%2Fdemo_test.json
Decreasing the parent size:
This is a styling issue, cytoscape.js applies padding to parent elements, if you want your parent element to be as small as possible, you'll have to adjust the padding in the :parent style:
{
selector: ":parent",
css: {
...
"padding": "0px" \\ remove padding completely, parent almost touching inner nodes
}
},
Border shadow
This was a little tricky, cytoscape.js only provides a normal border (like "border": "1px solid black"). You can use these styles:
border-width : The size of the node’s border.
border-style : The style of the node’s border; may be solid, dotted, dashed, or double.
border-color : The colour of the node’s border.
border-opacity : The opacity of the node’s border.
None of this provides us with the ability to apply a one sided border. As an alternative, I used the ghost styles:
ghost : Whether to use the ghost effect; may be yes or no.
ghost-offset-x : The horizontal offset used to position the ghost effect.
ghost-offset-y : The vertical offset used to position the ghost effect.
ghost-opacity : The opacity of the ghost effect.
If you adjust it a little bit, you can use the x offset and a nice opacity value to achieve this box shadow:
ghost: "yes",
"ghost-opacity": 0.5,
"ghost-offset-x": 1
Here is a working stackblitz with both changes applied.

Cytoscape JS CoSe Layout Label Length Effect

I made an observation with Cytoscape Layout and I am wondering how to change it. The layout manager CoSe produces different results depending on the length of the label name. I encountered this when I changed the node label from a long to a short id and also to no id. The best result is produced with no id.
How to deactivate this label layout effect ?
There is a planned feature to specify how the bounding box is calculated for nodes in a layout: https://github.com/cytoscape/cytoscape.js/issues/1626
Before that's implemented, you'll have to hide labels while the layout is running.
E.g.
cy.nodes().addClass('no-labels');
cy.one('layoutstop', () => cy.nodes().removeClass('no-labels'));
cy.makeLayout({ ... }).run();
Where node.no-labels { label: '' } is defined in your stylesheet.

Vertically scrolling graph with fixed size nodes with Cytoscape.js?

I'm using Cytoscape to generate a simple flow/state diagram and I'm able to generate the graph, but as the graph grows, it just keeps zooming out so the nodes become really small. Is there a way to have Cytoscape to just keep growing in height instead of shrinking the graph and having to zoom in? I would rather have the nodes stay a known size (i.e. 100px X 100px) and as the graph grows and have it grow vertically so the user just has to scroll down the page to see the rest of the graph. Right now, the viewport is restricted to the height of the page when the page is first rendered. Let me know if there is a way to achieve a vertically scrolling graph with fixed size nodes. Thanks!
Based on the suggestions of maxkfranz and gcpdev, I came up with the following solution that seems to work pretty well.
Cytoscope Init:
cy = cytoscape({
container: document.getElementById('cy'),
style: cytoscape.stylesheet()
.selector('node')
.css({
'shape': 'roundrectangle',
'height': 80,
'width': 150,
'background-fit': 'cover',
'background-color': '#F5F5F5',
'border-color': '#F5F5F5',
'border-width': 3,
'border-opacity': 0.5,
'text-valign': 'center',
'content': 'data(name)',
})
.selector('edge')
.css({
'width': 6,
'target-arrow-shape': 'triangle',
'line-color': '#0088cc',
'target-arrow-color': '#0088cc'
}),
elements: data,
zoomingEnabled: false,
layout: {
name: 'breadthfirst',
directed: true,
padding: 10
}
}); // cy init
After we have initialized the diagram, we have to set the size of our container div to be at least as high as the bounds of the graph. We also need to reset the size anytime someone resizes the window.
cy.on('ready', function () {
updateBounds();
});
//if they resize the window, resize the diagram
$(window).resize(function () {
updateBounds();
});
var updateBounds = function () {
var bounds = cy.elements().boundingBox();
$('#cyContainer').css('height', bounds.h + 300);
cy.center();
cy.resize();
//fix the Edgehandles
$('#cy').cytoscapeEdgehandles('resize');
};
I am also calling updateBounds() any time the user add a node to the graph. This gives me a graph that is full size and grows vertically. I can scroll down the page just fine as well!
(1) Layouts usually fit to the graph. Set layoutOptions.fit: false to override this default behaviour (at least for included layouts).
(2) The use of (1) means that running the layout will leave the graph viewport in the reset state (i.e. default zoom of 1 at origin position { x: 0, y: 0 }). If you want the viewport maintained at zoom: 1 but with an altered pan position, you can use cy.pan() with some simple calculations with cy.elements().boundingBox(). You may also find cy.center() useful -- though perhaps only horizontally in your case.
(3) The use of (2) means that your graph viewport (i.e. canvas) will be the same size, but the user will be able to pan down to see the remainder of the graph. If you prefer scrolling over panning, you will need to implement your own mechanism for this. You can make clever combination of cy.elements().boundingBox() and jQuery('#cy-div').css(), for example, to adjust the cy div to the size of the graph. You may want to turn off user panning and zooming (and autolock nodes etc.), if the graph is not interactive.
Well, I think you could set the zoom amount to fixed and disable zoom in/out, and use some strategy to dynamically change your div/page's height.
This answer or this one should help you.

Determine the dimensions of a Dojo Widget

My objective is to build a Dojo widget that embeds some graphic information, for example an Analogue Gauge, along with some other stuff.
I have managed to build a widget and initialise the Analogue widget with code such as:
gauge = new dojox.widget.AnalogGauge({
id: "defaultGauge",
width: 300,
height: 200,
cx: 150,
cy: 175,
radius: 125,
Now I've generalised this so that the width, height, cx, cy and radius can be calculated if I know the dimensions in which the widget will be rendered. Say for example, it's going to be in the "top" region of a Border Layout of height 150px, then I can compute suitable values.
The question: how do I determine the available space for my widget to work in? Is there some API by which I can obtain this information from the Layout or Content Pane?
It seems that the widget can provide a
resize(dimensions)
method, which is called both when the widget is first displayed and also when it is resized. The argument being an object holding the width and height of the display area.
Hence if the
gauge = new dojox.widget.AnalogGauge({
code is moved into the resize method we can provide suitable size information to the gauge constructor. I have yet to understand how to deal with subsequent resize() requests.