I can't get cytoscape.js to display my chart at all - javascript

I built a chart in web webpage using the JavaScript chart program cytoscape.js. It does not display anything at all. But it doesn't' give syntax errors either, other than a warning about taking over the mouse for zooming purposes.
Here is the code:
<style type="text/css">
#cy {
width: 90%;
height: 300px;
display: block;
}
</style>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.14.0/cytoscape.min.js"></script>
<script type="text/javascript">
var cy = cytoscape({
container: document.getElementById('cy'), // container to render in
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'
}
}
],
// initial viewport state:
zoom: 1,
pan: { x: 0, y: 0 },
// interaction options:
minZoom: 1e-50,
maxZoom: 1e50,
zoomingEnabled: true,
userZoomingEnabled: true,
panningEnabled: true,
userPanningEnabled: true,
boxSelectionEnabled: true,
selectionType: 'single',
touchTapThreshold: 8,
desktopTapThreshold: 4,
autolock: false,
autoungrabify: false,
autounselectify: false,
// rendering options:
headless: false,
styleEnabled: true,
hideEdgesOnViewport: false,
textureOnViewport: false,
motionBlur: false,
motionBlurOpacity: 0.2,
wheelSensitivity: 1,
pixelRatio: 'auto'
});
let options = {
name: 'breadthfirst',
fit: true, // whether to fit the viewport to the graph
directed: false, // whether the tree is directed downwards (or edges can point in any direction if false)
padding: 30, // padding on fit
circle: false, // put depths in concentric circles if true, put depths top down if false
grid: false, // whether to create an even grid into which the DAG is placed (circle:false only)
spacingFactor: 1.75, // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap)
boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm
roots: undefined, // the roots of the trees
maximal: false, // whether to shift nodes down their natural BFS depths in order to avoid upwards edges (DAGS only)
animate: false, // whether to transition the node positions
animationDuration: 500, // duration of animation in ms if enabled
animationEasing: undefined, // easing of animation if enabled,
animateFilter: function (node, i) { return true; }, // a function that determines whether the node should be animated. All nodes animated by default on animate enabled. Non-animated nodes are positioned immediately when the layout starts
ready: undefined, // callback on layoutready
stop: undefined, // callback on layoutstop
transform: function (node, position) { return position; } // transform a given node position. Useful for changing flow direction in discrete layouts
};
cy.layout(options);
var eles1 = cy.add([
{ group: 'nodes', data: { id: 'E1'} },
{ group: 'nodes', data: { id: 'E2'} },
{ group: 'nodes', data: { id: 'E3'} },
{ group: 'nodes', data: { id: 'E4'} },
{ group: 'nodes', data: { id: 'E5'} },
{ group: 'nodes', data: { id: 'E6'} },
{ group: 'nodes', data: { id: 'E7'} },
{ group: 'nodes', data: { id: 'E8'} } ]);
var eles2 = cy.add([
{ group: 'nodes', data: { id: 'LH1'} },
{ group: 'nodes', data: { id: 'RH1'} },
{ group: 'nodes', data: { id: 'LH2'} },
{ group: 'nodes', data: { id: 'LH3'} },
{ group: 'nodes', data: { id: 'RH2'} },
{ group: 'nodes', data: { id: 'LH4'} },
{ group: 'nodes', data: { id: 'RH3'} },
{ group: 'nodes', data: { id: 'RH4'} } ]);
var eles4 = cy.add([
{ group: 'edges', data: { id: 'edge0', source: 'E4', target: 'E5' } },
{ group: 'edges', data: { id: 'edge1', source: 'E6', target: 'E7' } },
{ group: 'edges', data: { id: 'edge2', source: 'LH1', target: 'E1' } },
{ group: 'edges', data: { id: 'edge3', source: 'LH1', target: 'RH1' } },
{ group: 'edges', data: { id: 'edge4', source: 'LH2', target: 'E4' } },
{ group: 'edges', data: { id: 'edge5', source: 'LH3', target: 'E4' } },
{ group: 'edges', data: { id: 'edge6', source: 'LH4', target: 'E6' } },
{ group: 'edges', data: { id: 'edge7', source: 'RH1', target: 'E2' } },
{ group: 'edges', data: { id: 'edge8', source: 'RH1', target: 'E3' } },
{ group: 'edges', data: { id: 'edge9', source: 'RH2', target: 'E5' } },
{ group: 'edges', data: { id: 'edge10', source: 'RH3', target: 'E7' } },
{ group: 'edges', data: { id: 'edge11', source: 'RH4', target: 'E8' } } ]);
</script>
<center>
<div id="cy" >
</div>
</center>
My code is actually generated in an asp.net page, but that should not make a difference.

You are adding the elements to the graph after the layout has been run. That's why all your nodes are piled up on the upper left corner.
You have two choices here:
Supply both the layout at the elements on the constructor.
Initialize the graph first, then add the elements (e.g. using cy.json()) and then tell cytoscape to run the layout with cy.layout(...).run().
Documentation for cy.layout() is here, and for cy.json() here.
The following snippet uses the first approach, but I have left the second one commented in case you cannot supply the elements on the constructor call (i.e. if you have to fetch them asynchronously).
var nodeArray = [
{ group: 'nodes', data: { id: 'E1'} },
{ group: 'nodes', data: { id: 'E2'} },
{ group: 'nodes', data: { id: 'E3'} },
{ group: 'nodes', data: { id: 'E4'} },
{ group: 'nodes', data: { id: 'E5'} },
{ group: 'nodes', data: { id: 'E6'} },
{ group: 'nodes', data: { id: 'E7'} },
{ group: 'nodes', data: { id: 'E8'} },
{ group: 'nodes', data: { id: 'LH1'} },
{ group: 'nodes', data: { id: 'RH1'} },
{ group: 'nodes', data: { id: 'LH2'} },
{ group: 'nodes', data: { id: 'LH3'} },
{ group: 'nodes', data: { id: 'RH2'} },
{ group: 'nodes', data: { id: 'LH4'} },
{ group: 'nodes', data: { id: 'RH3'} },
{ group: 'nodes', data: { id: 'RH4'} }
];
var edgeArray = [
{ group: 'edges', data: { id: 'edge0', source: 'E4', target: 'E5' } },
{ group: 'edges', data: { id: 'edge1', source: 'E6', target: 'E7' } },
{ group: 'edges', data: { id: 'edge2', source: 'LH1', target: 'E1' } },
{ group: 'edges', data: { id: 'edge3', source: 'LH1', target: 'RH1' } },
{ group: 'edges', data: { id: 'edge4', source: 'LH2', target: 'E4' } },
{ group: 'edges', data: { id: 'edge5', source: 'LH3', target: 'E4' } },
{ group: 'edges', data: { id: 'edge6', source: 'LH4', target: 'E6' } },
{ group: 'edges', data: { id: 'edge7', source: 'RH1', target: 'E2' } },
{ group: 'edges', data: { id: 'edge8', source: 'RH1', target: 'E3' } },
{ group: 'edges', data: { id: 'edge9', source: 'RH2', target: 'E5' } },
{ group: 'edges', data: { id: 'edge10', source: 'RH3', target: 'E7' } },
{ group: 'edges', data: { id: 'edge11', source: 'RH4', target: 'E8' } }
];
var stylesArray = [{
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'
}
}];
var layout = {name: 'breadthfirst'};
// You used mostly default options, there's no need to redefine them
var cy = cytoscape({
container: document.getElementById('cy'),
style: stylesArray,
// If you want to apply the layout on the constructor
// you must supply the elements too
layout: layout,
elements: {
nodes: nodeArray,
edges: edgeArray
}
});
// Or add the elements afterwards, it's your choice
// But then you need to re-run the layout
/*
cy.json({
elements: {
nodes: nodeArray,
edges: edgeArray
}
});
// Tell cytoscape to apply the layout when ready
cy.ready(function () {
cy.layout(layout).run();
});
*/
#cy {
width: 90%;
height: 300px;
display: block;
}
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.14.0/cytoscape.min.js"></script>
<div id="cy"></div>

Related

How to reset to initial coordinates after some drag operation with the library react-cytoscape.js

I'm learning the library react-cytoscape.js and trying to run the offical demo.
The demo shows that the left graph will rerender after you change the data in right area and click the 'Render' button.
I didn't make any changes to the demo code, but I have a question how to get all nodes reset to initial coordinates after some drag operation.
I thought that the data of right textarea recorded all initial coordinates, after dragged nodes, then clicked 'Render' button, the graph should be rerender base on the right data.
Please see my online demo.
window.addEventListener('DOMContentLoaded', function () {
const exampleProps = {
id: 'cy',
className: 'foo bar',
style: {
'border': '1px solid #ccc',
'width': '400px',
'height': '400px'
},
global: 'cy',
elements: [
{ data: { id: 'a', label: 'apple' }, position: { x: 0, y: 0 } },
{ data: { id: 'b', label: 'banana' }, position: { x: 100, y: 0 } },
{ data: { id: 'c', label: 'cherry' }, position: { x: 200, y: 0 } }
],
layout: {
name: 'preset'
}
};
class TestComponent extends React.Component {
constructor(props) {
super(props);
props.setStateRef(this.setState.bind(this));
this.state = exampleProps;
}
render() {
return React.createElement(ReactCytoscape, this.state);
}
}
const textBox = document.getElementById('props');
const btn = document.getElementById('update');
btn.addEventListener('click', () => {
update(JSON.parse(textBox.value));
});
let update;
ReactDOM.render(
React.createElement(TestComponent, { setStateRef: ref => update = ref }),
document.getElementById('root')
);
textBox.value = JSON.stringify(exampleProps, null, 2);
});
When you drag node at first time, and click render button, all nodes are back to their original positions.
When you drag node again and click render button, the dragged nodes can't be back to their original coordinates defined in data.
My expectation is that all nodes should be positioned to the coordinates defined in right data textarea , no matter how many times you click 'render' button.
=============== Update ================
I find if I always change positions at right data textarea and then click 'Render' button, nodes could be layout at specified position. If change node's position through dragging then click 'Render' button, nodes couldn't be layout at position defined at right textarea.
You'll need to save the current nodes json via cy.json() and load them back into you cytoscape instance via cy.json({...}) again. In my example below, I use the browsers local storage to achieve a state, with React you can probably save it in a state or just write it to the field besides the cytoscape component and read the json aferwards.
The important part here is to render the graph with the updated json,I don't think that your example code updates the text box?
The following code does not work with stackoverflow (localStorage is not permitted for security reasons), but I have this code as a working codepen here. Also, the nodes styles are currently not exportet via json, but there are some questions on SO explaining how to do that (I think):
var elements1 = [{
group: "nodes",
data: {
id: "n0"
}
},
{
group: "nodes",
data: {
id: "n1"
}
},
{
group: "nodes",
data: {
id: "n2"
}
},
{
group: "nodes",
data: {
id: "n3"
}
},
{
group: "nodes",
data: {
id: "n4",
parent1: "n37"
}
},
{
group: "nodes",
data: {
id: "n5"
}
},
{
group: "nodes",
data: {
id: "n6"
}
},
{
group: "nodes",
data: {
id: "n7",
parent1: "n37"
}
},
{
group: "nodes",
data: {
id: "n8",
parent1: "n37"
}
},
{
group: "nodes",
data: {
id: "n9",
parent1: "n37"
}
},
{
group: "nodes",
data: {
id: "n10",
parent1: "n38"
}
},
{
group: "nodes",
data: {
id: "n12"
}
},
{
group: "nodes",
data: {
id: "n13"
}
},
{
group: "nodes",
data: {
id: "n14"
}
},
{
group: "nodes",
data: {
id: "n15"
}
},
{
group: "nodes",
data: {
id: "n16"
}
},
{
group: "nodes",
data: {
id: "n17"
}
},
{
group: "nodes",
data: {
id: "n18"
}
},
{
group: "nodes",
data: {
id: "n19"
}
},
{
group: "nodes",
data: {
id: "n20"
}
},
{
group: "nodes",
data: {
id: "n21"
}
},
{
group: "nodes",
data: {
id: "n22"
}
},
{
group: "nodes",
data: {
id: "n23"
}
},
{
group: "nodes",
data: {
id: "n24",
parent1: "n39"
}
},
{
group: "nodes",
data: {
id: "n25",
parent1: "n39"
}
},
{
group: "nodes",
data: {
id: "n26",
parent1: "n42"
}
},
{
group: "nodes",
data: {
id: "n27",
parent1: "n42"
}
},
{
group: "nodes",
data: {
id: "n28",
parent1: "n42"
}
},
{
group: "nodes",
data: {
id: "n29",
parent1: "n40"
}
},
{
group: "nodes",
data: {
id: "n31",
parent1: "n41"
}
},
{
group: "nodes",
data: {
id: "n32",
parent1: "n41"
}
},
{
group: "nodes",
data: {
id: "n33",
parent1: "n41"
}
},
{
group: "nodes",
data: {
id: "n34",
parent1: "n41"
}
},
{
group: "nodes",
data: {
id: "n35",
parent1: "n41"
}
},
{
group: "nodes",
data: {
id: "n36",
parent1: "n41"
}
},
{
group: "edges",
data: {
id: "e0",
source: "n0",
target: "n1"
}
},
{
group: "edges",
data: {
id: "e1",
source: "n1",
target: "n2"
}
},
{
group: "edges",
data: {
id: "e2",
source: "n2",
target: "n3"
}
},
{
group: "edges",
data: {
id: "e3",
source: "n0",
target: "n3"
}
},
{
group: "edges",
data: {
id: "e4",
source: "n1",
target: "n4"
}
},
{
group: "edges",
data: {
id: "e5",
source: "n2",
target: "n4"
}
},
{
group: "edges",
data: {
id: "e6",
source: "n4",
target: "n5"
}
},
{
group: "edges",
data: {
id: "e7",
source: "n5",
target: "n6"
}
},
{
group: "edges",
data: {
id: "e8",
source: "n4",
target: "n6"
}
},
{
group: "edges",
data: {
id: "e9",
source: "n4",
target: "n7"
}
},
{
group: "edges",
data: {
id: "e10",
source: "n7",
target: "n8"
}
},
{
group: "edges",
data: {
id: "e11",
source: "n8",
target: "n9"
}
},
{
group: "edges",
data: {
id: "e12",
source: "n7",
target: "n9"
}
},
{
group: "edges",
data: {
id: "e13",
source: "n13",
target: "n14"
}
},
{
group: "edges",
data: {
id: "e14",
source: "n12",
target: "n14"
}
},
{
group: "edges",
data: {
id: "e15",
source: "n14",
target: "n15"
}
},
{
group: "edges",
data: {
id: "e16",
source: "n14",
target: "n16"
}
},
{
group: "edges",
data: {
id: "e17",
source: "n15",
target: "n17"
}
},
{
group: "edges",
data: {
id: "e18",
source: "n17",
target: "n18"
}
},
{
group: "edges",
data: {
id: "e19",
source: "n18",
target: "n19"
}
},
{
group: "edges",
data: {
id: "e20",
source: "n17",
target: "n20"
}
},
{
group: "edges",
data: {
id: "e21",
source: "n19",
target: "n20"
}
},
{
group: "edges",
data: {
id: "e22",
source: "n16",
target: "n20"
}
},
{
group: "edges",
data: {
id: "e23",
source: "n20",
target: "n21"
}
},
{
group: "edges",
data: {
id: "e25",
source: "n23",
target: "n24"
}
},
{
group: "edges",
data: {
id: "e26",
source: "n24",
target: "n25"
}
},
{
group: "edges",
data: {
id: "e30",
source: "n26",
target: "n27"
}
},
{
group: "edges",
data: {
id: "e31",
source: "n26",
target: "n28"
}
},
{
group: "edges",
data: {
id: "e33",
source: "n21",
target: "n31"
}
},
{
group: "edges",
data: {
id: "e35",
source: "n31",
target: "n33"
}
},
{
group: "edges",
data: {
id: "e36",
source: "n31",
target: "n34"
}
},
{
group: "edges",
data: {
id: "e37",
source: "n33",
target: "n34"
}
},
{
group: "edges",
data: {
id: "e38",
source: "n32",
target: "n35"
}
},
{
group: "edges",
data: {
id: "e39",
source: "n32",
target: "n36"
}
}
];
document.addEventListener("DOMContentLoaded", function() {
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
ready: function() {
this.nodes().forEach(function(node) {
let width = [30, 70, 110];
let size = width[Math.floor(Math.random() * 3)];
node.css("width", size);
node.css("height", size);
});
this.layout({
name: "cose-bilkent",
animationDuration: 1000
}).run();
},
style: [{
selector: "node",
style: {
'content': 'data(id)',
'text-valign': 'center',
'text-halign': 'center',
'background-color': '#ad1a66'
}
},
{
selector: ":parent",
style: {
"background-opacity": 0.333
}
},
{
selector: "edge",
style: {
width: 3,
"line-color": "#ad1a66"
}
}
],
elements: [{
group: "nodes",
data: {
id: "n0"
}
},
{
group: "nodes",
data: {
id: "n1"
}
},
{
group: "nodes",
data: {
id: "n2"
}
},
{
group: "nodes",
data: {
id: "n3"
}
},
{
group: "nodes",
data: {
id: "n4",
parent: "n37"
}
},
{
group: "nodes",
data: {
id: "n5"
}
},
{
group: "nodes",
data: {
id: "n6"
}
},
{
group: "nodes",
data: {
id: "n7",
parent: "n37"
}
},
{
group: "nodes",
data: {
id: "n8",
parent: "n37"
}
},
{
group: "nodes",
data: {
id: "n9",
parent: "n37"
}
},
{
group: "nodes",
data: {
id: "n10",
parent: "n38"
}
},
{
group: "nodes",
data: {
id: "n12"
}
},
{
group: "nodes",
data: {
id: "n13"
}
},
{
group: "nodes",
data: {
id: "n14"
}
},
{
group: "nodes",
data: {
id: "n15"
}
},
{
group: "nodes",
data: {
id: "n16"
}
},
{
group: "nodes",
data: {
id: "n17"
}
},
{
group: "nodes",
data: {
id: "n18"
}
},
{
group: "nodes",
data: {
id: "n19"
}
},
{
group: "nodes",
data: {
id: "n20"
}
},
{
group: "nodes",
data: {
id: "n21"
}
},
{
group: "nodes",
data: {
id: "n22"
}
},
{
group: "nodes",
data: {
id: "n23"
}
},
{
group: "nodes",
data: {
id: "n24",
parent: "n39"
}
},
{
group: "nodes",
data: {
id: "n25",
parent: "n39"
}
},
{
group: "nodes",
data: {
id: "n26",
parent: "n42"
}
},
{
group: "nodes",
data: {
id: "n27",
parent: "n42"
}
},
{
group: "nodes",
data: {
id: "n28",
parent: "n42"
}
},
{
group: "nodes",
data: {
id: "n29",
parent: "n40"
}
},
{
group: "nodes",
data: {
id: "n31",
parent: "n41"
}
},
{
group: "nodes",
data: {
id: "n32",
parent: "n41"
}
},
{
group: "nodes",
data: {
id: "n33",
parent: "n41"
}
},
{
group: "nodes",
data: {
id: "n34",
parent: "n41"
}
},
{
group: "nodes",
data: {
id: "n35",
parent: "n41"
}
},
{
group: "nodes",
data: {
id: "n36",
parent: "n41"
}
},
{
group: "nodes",
data: {
id: "n37"
}
},
{
group: "nodes",
data: {
id: "n38"
}
},
{
group: "nodes",
data: {
id: "n39",
parent: "n43"
}
},
{
group: "nodes",
data: {
id: "n40",
parent: "n42"
}
},
{
group: "nodes",
data: {
id: "n41",
parent: "n42"
}
},
{
group: "nodes",
data: {
id: "n42",
parent: "n43"
}
},
{
group: "nodes",
data: {
id: "n43"
}
},
{
group: "edges",
data: {
id: "e0",
source: "n0",
target: "n1"
}
},
{
group: "edges",
data: {
id: "e1",
source: "n1",
target: "n2"
}
},
{
group: "edges",
data: {
id: "e2",
source: "n2",
target: "n3"
}
},
{
group: "edges",
data: {
id: "e3",
source: "n0",
target: "n3"
}
},
{
group: "edges",
data: {
id: "e4",
source: "n1",
target: "n4"
}
},
{
group: "edges",
data: {
id: "e5",
source: "n2",
target: "n4"
}
},
{
group: "edges",
data: {
id: "e6",
source: "n4",
target: "n5"
}
},
{
group: "edges",
data: {
id: "e7",
source: "n5",
target: "n6"
}
},
{
group: "edges",
data: {
id: "e8",
source: "n4",
target: "n6"
}
},
{
group: "edges",
data: {
id: "e9",
source: "n4",
target: "n7"
}
},
{
group: "edges",
data: {
id: "e10",
source: "n7",
target: "n8"
}
},
{
group: "edges",
data: {
id: "e11",
source: "n8",
target: "n9"
}
},
{
group: "edges",
data: {
id: "e12",
source: "n7",
target: "n9"
}
},
{
group: "edges",
data: {
id: "e13",
source: "n13",
target: "n14"
}
},
{
group: "edges",
data: {
id: "e14",
source: "n12",
target: "n14"
}
},
{
group: "edges",
data: {
id: "e15",
source: "n14",
target: "n15"
}
},
{
group: "edges",
data: {
id: "e16",
source: "n14",
target: "n16"
}
},
{
group: "edges",
data: {
id: "e17",
source: "n15",
target: "n17"
}
},
{
group: "edges",
data: {
id: "e18",
source: "n17",
target: "n18"
}
},
{
group: "edges",
data: {
id: "e19",
source: "n18",
target: "n19"
}
},
{
group: "edges",
data: {
id: "e20",
source: "n17",
target: "n20"
}
},
{
group: "edges",
data: {
id: "e21",
source: "n19",
target: "n20"
}
},
{
group: "edges",
data: {
id: "e22",
source: "n16",
target: "n20"
}
},
{
group: "edges",
data: {
id: "e23",
source: "n20",
target: "n21"
}
},
{
group: "edges",
data: {
id: "e25",
source: "n23",
target: "n24"
}
},
{
group: "edges",
data: {
id: "e26",
source: "n24",
target: "n25"
}
},
{
group: "edges",
data: {
id: "e27",
source: "n26",
target: "n38"
}
},
{
group: "edges",
data: {
id: "e29",
source: "n26",
target: "n39"
}
},
{
group: "edges",
data: {
id: "e30",
source: "n26",
target: "n27"
}
},
{
group: "edges",
data: {
id: "e31",
source: "n26",
target: "n28"
}
},
{
group: "edges",
data: {
id: "e33",
source: "n21",
target: "n31"
}
},
{
group: "edges",
data: {
id: "e35",
source: "n31",
target: "n33"
}
},
{
group: "edges",
data: {
id: "e36",
source: "n31",
target: "n34"
}
},
{
group: "edges",
data: {
id: "e37",
source: "n33",
target: "n34"
}
},
{
group: "edges",
data: {
id: "e38",
source: "n32",
target: "n35"
}
},
{
group: "edges",
data: {
id: "e39",
source: "n32",
target: "n36"
}
},
{
group: "edges",
data: {
id: "e40",
source: "n16",
target: "n40"
}
}
],
}));
document.getElementById("layoutButton").addEventListener("click", function() {
var layout = cy.layout({
name: "cose-bilkent",
animate: "end",
animationEasing: "ease-out",
animationDuration: 1000,
randomize: true
});
layout.run();
});
document.getElementById("randomize").addEventListener("click", function() {
var layout = cy.layout({
name: "random",
animate: true,
animationDuration: 1000,
animationEasing: "ease-out"
});
layout.run();
});
document.getElementById("save").addEventListener("click", function() {
window.localStorage.setItem("elements", JSON.stringify(cy.json()));
});
document.getElementById("reload").addEventListener("click", function() {
cy.elements().remove();
cy.json({
elements: JSON.parse(window.localStorage.getItem("elements")).elements
}).layout({
name: 'preset'
}).run();
cy.fit();
cy.center();
});
});
body {
font-family: helvetica;
font-size: 14px;
}
#cy {
height: 100%;
width: 90%;
position: absolute;
}
h1 {
opacity: 0.5;
font-size: 1em;
}
button {
margin-right: 10px;
}
<script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
<!--polyfills are needed for this extension for old browsers like IE -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.5.7/shim.min.js"></script>
<script src="https://unpkg.com/layout-base/layout-base.js"></script>
<script src="https://unpkg.com/cose-base/cose-base.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-cose-bilkent#4.1.0/cytoscape-cose-bilkent.min.js"></script>
<body>
<button id="randomize" type="button">Randomize</button>
<button id="layoutButton" type="button">CoSE-Bilkent</button>
<button id="save" class="button">save</button>
<button id="reload" class="button">reload</button>
<div id="cy"></div>
</body>

how to change highcarts sunburst slice/level without clicking levels

I have a Sunburst Highcharts in my project. I was wondering if it is possible to change the level without clicking on them.
for example, I have a sunburst like this which has 4 levels.
var data = [{
id: '0.0',
parent: '',
name: 'The World'
}, {
id: '1.3',
parent: '0.0',
name: 'Asia'
}, {
id: '1.1',
parent: '0.0',
name: 'Africa'
}, {
id: '1.2',
parent: '0.0',
name: 'America'
}, {
id: '1.4',
parent: '0.0',
name: 'Europe'
}, {
id: '1.5',
parent: '0.0',
name: 'Oceanic'
},
/* Africa */
{
id: '2.1',
parent: '1.1',
name: 'Eastern Africa'
},
{
id: '3.1',
parent: '2.1',
name: 'Ethiopia',
value: 104957438
}, {
id: '3.2',
parent: '2.1',
name: 'Tanzania',
value: 57310019
}, {
id: '3.3',
parent: '2.1',
name: 'Kenya',
value: 49699862
}, {
id: '3.4',
parent: '2.1',
name: 'Uganda',
value: 42862958
}, {
id: '3.5',
parent: '2.1',
name: 'Mozambique',
value: 29668834
}, {
id: '3.6',
parent: '2.1',
name: 'Madagascar',
value: 25570895
}, {
id: '3.226',
parent: '2.22',
name: 'Samoa',
value: 196440
}, {
id: '3.227',
parent: '2.22',
name: 'Tonga',
value: 108020
}, {
id: '3.228',
parent: '2.22',
name: 'American Samoa',
value: 55641
}, {
id: '3.229',
parent: '2.22',
name: 'Cook Islands',
value: 17380
}, {
id: '3.230',
parent: '2.22',
name: 'Wallis and Futuna',
value: 11773
}, {
id: '3.231',
parent: '2.22',
name: 'Tuvalu',
value: 11192
}, {
id: '3.232',
parent: '2.22',
name: 'Niue',
value: 1618
}, {
id: '3.233',
parent: '2.22',
name: 'Tokelau',
value: 1300
}];
// Splice in transparent for the center circle
Highcharts.getOptions().colors.splice(0, 0, 'transparent');
Highcharts.chart('container', {
chart: {
height: '100%'
},
title: {
text: 'World population 2017'
},
subtitle: {
text: 'Source <href="https://en.wikipedia.org/wiki/List_of_countries_by_population_(United_Nations)">Wikipedia</a>'
},
series: [{
type: "sunburst",
data: data,
allowDrillToNode: true,
cursor: 'pointer',
dataLabels: {
format: '{point.name}',
filter: {
property: 'innerArcLength',
operator: '>',
value: 16
}
},
levels: [{
level: 1,
levelIsConstant: false,
dataLabels: {
filter: {
property: 'outerArcLength',
operator: '>',
value: 64
}
}
}, {
level: 2,
colorByPoint: true
},
{
level: 3,
colorVariation: {
key: 'brightness',
to: -0.5
}
}, {
level: 4,
colorVariation: {
key: 'brightness',
to: 0.5
}
}]
}],
tooltip: {
headerFormat: "",
pointFormat: 'The population of <b>{point.name}</b> is <b>{point.value}</b>'
}
});
Problem is
I want to go to specific levels without clicking on sunburst. for example, I create a button that if the user clicks on it, will do the same action as if I was clicking on Eastern Africa level of my sunburst.
<button onclick="clickOnEasternAfrica()">Do click here</button>
What code should I use for clickOnEasternAfrica() method!?
You can use fireEvent to trigge a click event:
document.getElementById('easternAfrica').addEventListener('click', function(){
var series = chart.series[0];
Highcharts.fireEvent(series, 'click', { point: series.points[6] });
});
Live demo: https://jsfiddle.net/BlackLabel/dLb5hert/
API Reference: https://api.highcharts.com/class-reference/Highcharts#.fireEvent%3CT%3E

cytoscape.js and dagre result in one node positioned awkwardly

Given the cytoscape.js snippet below, using the dagre layout, can anyone explain why node number 2 positions itself to the bottom right instead of in order like the rest of them?
var cy = cytoscape({
container: document.getElementById('cy'),
elements: [{
data: {
id: 1477,
label: "Heading",
},
},
{
data: {
id: 1483,
label: "Number 2",
parent: 1479,
},
},
{
data: {
id: 1479,
label: "Group",
},
},
{
data: {
id: 1478,
label: "Number 0",
parent: 1479,
},
},
{
data: {
id: 1480,
source: 1477,
target: 1478,
minLen: 1,
},
},
{
data: {
id: 1484,
source: 1481,
target: 1483,
minLen: 1,
},
},
{
data: {
id: 1481,
label: "Number 1",
parent: 1479,
},
},
{
data: {
id: 1482,
source: 1478,
target: 1481,
minLen: 1,
},
},
{
data: {
id: 1487,
label: "Number 4",
parent: 1479,
},
},
{
data: {
id: 1485,
label: "Number 3",
parent: 1479,
},
},
{
data: {
id: 1486,
source: 1483,
target: 1485,
minLen: 1,
},
},
{
data: {
id: 1488,
source: 1485,
target: 1487,
minLen: 1,
},
},
{
data: {
id: 1490,
source: 1487,
target: 1489,
minLen: 1,
},
},
{
data: {
id: 1489,
label: "Number 5",
parent: 1479,
},
},
{
data: {
id: 1491,
label: "Final",
},
},
{
data: {
id: 1492,
source: 1489,
target: 1491,
minLen: 1,
},
},
],
layout: {
name: 'dagre',
'nodeSep': 25,
'rankSep': 10,
},
style: [{
selector: 'node',
style: {
label: 'data(label)',
'text-valign': 'center',
'text-halign': 'right',
'text-margin-x': '-155',
'text-wrap': 'wrap',
'text-max-width': 150,
'width': 180,
'background-fit': 'contain',
'shape': 'roundrectangle',
'background-opacity': 0,
'background-position-x': 0,
'height': 24,
'border-width': 1,
'padding-right': 5,
'padding-left': 5,
'padding-top': 5,
'padding-bottom': 5,
'text-events': 'yes',
'font-size': 12,
}
},
{
selector: 'edge',
style: {
'width': 1,
'curve-style': 'bezier',
'line-color': 'black',
'line-style': 'solid',
'target-arrow-shape': 'triangle-backcurve',
'target-arrow-color': 'black',
'text-rotation': 'autorotate',
'label': 'data(label)',
}
},
{
selector: '$node > node',
style: {
'text-rotation': '-90deg',
'text-halign': 'left',
'text-margin-x': -10,
'text-margin-y': -40,
}
},
{
selector: '.Badge',
style: {
'border-width': 3,
}
},
],
minZoom: 0.5,
maxZoom: 1.5,
zoomingEnabled: true,
userZoomingEnabled: false,
autoungrabify: false,
autounselectify: true,
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.5/cytoscape.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dagre/0.8.5/dagre.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-dagre#2.2.2/cytoscape-dagre.min.js"></script>
<div id="cy"></div>
With a little re-arragement, you can easily get this to work. Generally, it is better to group the elements by nodes and edges, also in a ascending order. This improves readability and, in this case, prevents inconsistent layouts.
I think that the issue here stemms from the edges being added to the graph before the corresponding node (node Number 2) is present.
Here is the working code:
var cy = cytoscape({
container: document.getElementById('cy'),
elements: {
nodes: [{
data: {
id: 1477,
label: "Heading",
},
},
{
data: {
id: 1479,
label: "Group",
},
},
{
data: {
id: 1478,
label: "Number 0",
parent: 1479,
},
},
{
data: {
id: 1481,
label: "Number 1",
parent: 1479,
},
},
{
data: {
id: 1483,
label: "Number 2",
parent: 1479,
},
},
{
data: {
id: 1485,
label: "Number 3",
parent: 1479,
},
},
{
data: {
id: 1487,
label: "Number 4",
parent: 1479,
},
},
{
data: {
id: 1489,
label: "Number 5",
parent: 1479,
},
},
{
data: {
id: 1491,
label: "Final",
},
},
],
edges: [{
data: {
id: 1480,
source: 1477,
target: 1478,
minLen: 1,
},
},
{
data: {
id: 1482,
source: 1478,
target: 1481,
minLen: 1,
},
},
{
data: {
id: 1484,
source: 1481,
target: 1483,
minLen: 1,
},
},
{
data: {
id: 1486,
source: 1483,
target: 1485,
minLen: 1,
},
},
{
data: {
id: 1488,
source: 1485,
target: 1487,
minLen: 1,
},
},
{
data: {
id: 1490,
source: 1487,
target: 1489,
minLen: 1,
},
},
{
data: {
id: 1492,
source: 1489,
target: 1491,
minLen: 1,
},
}
]
},
layout: {
name: 'dagre',
'nodeSep': 25,
'rankSep': 10,
},
style: [{
selector: 'node',
style: {
label: 'data(label)',
'text-valign': 'center',
'text-halign': 'right',
'text-margin-x': '-155',
'text-wrap': 'wrap',
'text-max-width': 150,
'width': 180,
'background-fit': 'contain',
'shape': 'roundrectangle',
'background-opacity': 0,
'background-position-x': 0,
'height': 24,
'border-width': 1,
'padding-right': 5,
'padding-left': 5,
'padding-top': 5,
'padding-bottom': 5,
'text-events': 'yes',
'font-size': 12,
}
},
{
selector: 'edge',
style: {
'width': 1,
'curve-style': 'bezier',
'line-color': 'black',
'line-style': 'solid',
'target-arrow-shape': 'triangle-backcurve',
'target-arrow-color': 'black',
'text-rotation': 'autorotate',
'label': 'data(label)',
}
},
{
selector: '$node > node',
style: {
'text-rotation': '-90deg',
'text-halign': 'left',
'text-margin-x': -10,
'text-margin-y': -40,
}
},
{
selector: '.Badge',
style: {
'border-width': 3,
}
},
],
minZoom: 0.5,
maxZoom: 1.5,
zoomingEnabled: true,
userZoomingEnabled: false,
autoungrabify: false,
autounselectify: true,
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.5/cytoscape.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dagre/0.8.5/dagre.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-dagre#2.2.2/cytoscape-dagre.min.js"></script>
<div id="cy"></div>

My cytoscape graph has an edge going from one nodes to another that crosses behind a third. How do I avoid that?

I made a cytoscape graph where all the edges are straight, and the layout is "breadth-first" (I just chose the layout arbitrarily) and it gives a misleading chart. For instance, node RH4 is supposed to be connected to node E8. The connection goes right through another node (RH1) and so both E8 and RH4 look as if they are connected to RH1. In reality, they are not supposed to be.
Here is the code that caused this:
var cy = cytoscape({
container: document.getElementById('cy'),
style: [{
selector: 'node',
style: {
'background-color': 'mapData(activation, -1, 1, blue, red)',
'label': 'data(id)'
}
}, {
selector: 'edge',
style: {
'width': 3,
'line-color': function(ele) {
return ele.data('relation')
},
'target-arrow-color': function(ele) {
return ele.data('relation')
},
'target-arrow-shape': 'triangle'
}
}],
layout: {
name: 'breadthfirst'
},
elements: {
nodes: [{
group: 'nodes',
data: {
id: 'E1',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E2',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E3',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E4',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E5',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E6',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E7',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E8',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH1',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH1',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH2',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH3',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH2',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH4',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH3',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH4',
activation: 0
}
}
],
edges: [{
group: 'edges',
data: {
id: 'edge0',
source: 'E4',
target: 'E5',
relation: 'green'
}
},
{
group: 'edges',
data: {
id: 'edge1',
source: 'E6',
target: 'E7',
relation: 'green'
}
},
{
group: 'edges',
data: {
id: 'edge2',
source: 'LH1',
target: 'E1',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge3',
source: 'LH1',
target: 'RH1',
relation: 'green'
}
},
{
group: 'edges',
data: {
id: 'edge4',
source: 'LH2',
target: 'E4',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge5',
source: 'LH3',
target: 'E4',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge6',
source: 'LH4',
target: 'E6',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge7',
source: 'RH1',
target: 'E2',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge8',
source: 'RH1',
target: 'E3',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge9',
source: 'RH2',
target: 'E5',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge10',
source: 'RH3',
target: 'E7',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge11',
source: 'RH4',
target: 'E8',
relation: 'red'
}
}
]
}
});
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>
</head>
<body>
<div id="cy"></div>
</body>
</html>
Is the reason for this problem that 'breadthfirst' layout puts nodes in specific places, and the edges must be straight? Would there be a way to make curved edges that don't go through other nodes? Or is the answer somewhere else?
Thanks
You are using the breadthfirst layout, that is the problem:
As you can read here, the breadthfirst layout puts nodes in a hierarchy, based on a breadthfirst traversal of the graph. It is best suited to trees and forests in its default top-down mode, and it is best suited to DAGs in its circle mode.
You are using this layout in a not connected random set of elements, this would be better suited for something like the Dagre-Layout:
var cy = cytoscape({
container: document.getElementById('cy'),
style: [{
selector: 'node',
style: {
'background-color': 'mapData(activation, -1, 1, blue, red)',
'label': 'data(id)'
}
}, {
selector: 'edge',
style: {
'width': 3,
'line-color': function(ele) {
return ele.data('relation')
},
'target-arrow-color': function(ele) {
return ele.data('relation')
},
'target-arrow-shape': 'triangle'
}
}],
layout: {
name: 'dagre'
},
elements: {
nodes: [{
group: 'nodes',
data: {
id: 'E1',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E2',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E3',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E4',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E5',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E6',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E7',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E8',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH1',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH1',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH2',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH3',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH2',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH4',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH3',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH4',
activation: 0
}
}
],
edges: [{
group: 'edges',
data: {
id: 'edge0',
source: 'E4',
target: 'E5',
relation: 'green'
}
},
{
group: 'edges',
data: {
id: 'edge1',
source: 'E6',
target: 'E7',
relation: 'green'
}
},
{
group: 'edges',
data: {
id: 'edge2',
source: 'LH1',
target: 'E1',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge3',
source: 'LH1',
target: 'RH1',
relation: 'green'
}
},
{
group: 'edges',
data: {
id: 'edge4',
source: 'LH2',
target: 'E4',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge5',
source: 'LH3',
target: 'E4',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge6',
source: 'LH4',
target: 'E6',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge7',
source: 'RH1',
target: 'E2',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge8',
source: 'RH1',
target: 'E3',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge9',
source: 'RH2',
target: 'E5',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge10',
source: 'RH3',
target: 'E7',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge11',
source: 'RH4',
target: 'E8',
relation: 'red'
}
}
]
}
});
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://unpkg.com/dagre#0.7.4/dist/dagre.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-dagre#2.1.0/cytoscape-dagre.min.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>
Dagre organizes the graph using a DAG (directed acyclic graph) algorithm, which is more suited for not connected graphs like this.
PS: Please revisit your older question and add the requested answer (that you posted as a comment). Thanks

Why does my cytoscape graph lack arrow heads (though I put them in)?

The following cytoscape.js graph shows no arrow heads on its edges. I do have a selector for edges that specifies a triangular arrowhead, but it does not show up.
var cy = cytoscape({
container: document.getElementById('cy'),
style: [{
selector: 'node',
style: {
'background-color': 'mapData(activation, -1, 1, blue, red)',
'label': 'data(id)'
}
}, {
selector: 'edge',
style: {
'width': 3,
'line-color': function(ele) {
return ele.data('relation')
},
'target-arrow-color': function(ele) {
return ele.data('relation')
},
'target-arrow-shape': 'triangle'
}
}],
// If you want to apply the layout on the constructor
// you must supply the elements too
layout: {
name: 'breadthfirst'
},
elements: {
nodes: [{
group: 'nodes',
data: {
id: 'E1',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E2',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E3',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E4',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E5',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E6',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E7',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'E8',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH1',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH1',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH2',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH3',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH2',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'LH4',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH3',
activation: 0
}
},
{
group: 'nodes',
data: {
id: 'RH4',
activation: 0
}
}
],
edges: [{
group: 'edges',
data: {
id: 'edge0',
source: 'E4',
target: 'E5',
relation: 'green'
}
},
{
group: 'edges',
data: {
id: 'edge1',
source: 'E6',
target: 'E7',
relation: 'green'
}
},
{
group: 'edges',
data: {
id: 'edge2',
source: 'LH1',
target: 'E1',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge3',
source: 'LH1',
target: 'RH1',
relation: 'green'
}
},
{
group: 'edges',
data: {
id: 'edge4',
source: 'LH2',
target: 'E4',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge5',
source: 'LH3',
target: 'E4',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge6',
source: 'LH4',
target: 'E6',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge7',
source: 'RH1',
target: 'E2',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge8',
source: 'RH1',
target: 'E3',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge9',
source: 'RH2',
target: 'E5',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge10',
source: 'RH3',
target: 'E7',
relation: 'red'
}
},
{
group: 'edges',
data: {
id: 'edge11',
source: 'RH4',
target: 'E8',
relation: 'red'
}
}
]
}
});
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>
</head>
<body>
<div id="cy"></div>
</body>
</html>
Note that for selector 'edge', I specify a triangular head.
Here is an example Style that gives arrow
selector: 'edge',
style: {
'target-arrow-shape': 'triangle',
'target-arrow-color': 'black',
'source-arrow-color': 'black',
'line-color': '#333',
'width': 1.5,
'curve-style': 'bezier'
}
}
The most important styles are target-arrow-shape and curve-style. curve-style value can also be straight to get similar result (but not exactly the same result in certain cases)

Categories

Resources