How to paint multi colors on one single node (not gradients) with cytoscape? Thank you - cytoscape.js

How to render multiple colors to a node in cytoscape? The shape of the node can be arbitrary. Multiple different colors on the node are arranged from left to right (or from top to bottom). Also, I don't want gradients. I want to display multiple independent solid colors on one node.

You can use SVG graphic as parts of the nodes' markers. Here is a runnable code to demonstrate the concept.
const svg_rect = '<svg width="60" height="60" viewBox="0 0 60 60" version="1.1" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="60" height="60" style="fill:rgb(0,0,255);stroke-width:0.3;stroke:rgb(0,0,0)" /><rect x="20" y="0" width="60" height="60" style="fill:rgb(0,255,0);stroke-width:0.3;stroke:rgb(0,0,0)" /><rect x="40" y="0" width="20" height="60" style="fill:rgb(255,0,0);stroke-width:0.3;stroke:rgb(0,0,0)" /></svg>';
const svgrect_Url = encodeURI("data:image/svg+xml;utf-8,"+svg_rect);
var cy = cytoscape({
container: document.getElementById("cy"),
elements: {
nodes: [
{ data: { id: "j", name: "John" }, position: { x: 100, y: 100 } },
{ data: { id: "e", name: "Elena" }, position: { x: 100, y: 500 } },
{ data: { id: "k", name: "Kim" }, position: { x: 600, y: 500 } },
{ data: { id: "g", name: "Gordon" }, position: { x: 550, y: 80 } }
],
edges: [
{ data: { source: "j", target: "e", label: "JE" } },
{ data: { source: "j", target: "g", label: "JG" } },
{ data: { source: "e", target: "j" } },
{ data: { source: "k", target: "j" } },
{ data: { source: "k", target: "e", label: "KE" } },
{ data: { source: "k", target: "g" } },
{ data: { source: "g", target: "j" } }
]
},
style: [
{
selector: "node",
style: {
shape: "rectangle",
"background-color": "lightgray",
"background-image": svgrect_Url,
label: "data(name)",
width: 60,
height: 60,
opacity: 0.85
}
},
{
selector: "edge",
style: {
label: "data(label)",
width: 3,
"line-color": "#c0c",
"target-arrow-color": "#00c",
"curve-style": "bezier",
"target-arrow-shape": "triangle",
"target-arrow-fill": "#c00",
"arrow-scale" : 20
}
},
{
selector: ".highlight",
css: {
"background-color": "yellow"
}
}
],
layout: {
name: "preset"
}
});
#cy {
width: 100%;
height: 80%;
position: absolute;
top: 10px;
left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/2.7.10/cytoscape.min.js"></script>
<div id="cy"></div>

Related

Remove empty space around a barchart with no axes showing in Chartjs

Fairly straightforward, but I have a single bar on a barchart that I want to show by itself. I've hidden the axes and their ticks, but there is still all of that space there on the left and top//bottom of chart from the axes and the legend I am presuming.
Is there a way to remove this space without just putting negative margins on the element?
I've tried working with negative padding, but that doesn't work on the top and bottom of the chart.
I made a quick CodeSandbox to show my actual component
Any tips would be greatly appreciated!
Cheers!
Horizontal Stacked Bar Chart
<template>
<div style="width: 100%; height: 100%">
<canvas :id="id" width="100%" height="100%"></canvas>
</div>
</template>
<script>
import { defineComponent, onMounted } from "vue"
import Chart from "chart.js/auto"
import ChartDataLabels from "chartjs-plugin-datalabels"
export default defineComponent({
props: {
kind: {
/**
* #example: 'single', 'stacked'
*/
type: String,
default: "stacked",
},
color: {
type: String,
default: "rgba(255, 99, 132, 1)",
},
labels: {
type: Array,
default: () => ["S1", "S2", "S4", "S6"],
},
datasets: {
type: Array,
default: () => [
{
label: "va_value",
data: [80, 10, 60, 50],
backgroundColor: "#11DCB5",
borderColor: "transparent",
barThickness: 20,
minBarLength: 4,
// This is here to show SOMETHING even if the value is 0
},
{
label: "nva_value",
data: [20, 0, 40, 0],
backgroundColor: "#CA2F4B",
borderColor: "transparent",
barThickness: 20,
minBarLength: 4,
},
],
},
},
setup(props, context) {
const id = Math.random().toString()
onMounted(() => {
Chart.register(ChartDataLabels)
const ctx = document.getElementById(id)
const myChart = new Chart(ctx, {
type: "bar",
data: {
labels: props.labels,
datasets: props.datasets,
},
options: {
layout: {
padding: {
left: -20,
bottom: -20,
top: -20
}
},
plugins: {
legend: {
display: false,
},
datalabels: {
formatter: function (value) {
return props.kind === "stacked" ? `${value}s` : `${value}%`
},
color: "#fff",
anchor: "center",
align: "center",font: {
weight: "bold",
},
},
},
responsive: true,
maintainAspectRatio: false,
indexAxis: "y",
scales: {
y: {
beginAtZero: true,
stacked: true,
ticks: {
color: "#fff",
},
grid: {
drawBorder: false,
display: false,
},
},
x: {
display: props.kind === "stacked" ? true : false,
beginAtZero: true,
stacked: true,
ticks: {
color: "#fff",
},
grid: {
drawBorder: false,
display: false,
},
title: {
display: true,
text: props.kind === "stacked" ? "Step Time (s)" : "",
color: "#fff",
},
},
},
},
})
myChart
})
return { id }
},
})
</script>
<style lang=""></style>
This is because you set barThickness to 20 in your datasets. If you remove this it will show as you want:
https://codesandbox.io/s/modest-wave-60xui0

arcgis js 4. X use the editor tool to edit the FeatureLayer in real time

I want to make a panel. The longitude and latitude of the selected elements and the rotation angle are displayed on the panel. I use the panel to adjust the position and angle of the elements. However, with the editor, the modified elements can only be updated after applyedits is applied. I hope I can see the modification process in real time. This problem has been bothering me for a long time, so I hope someone can give me some advice.
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>
Thematic multivariate visualization (2D) | Sample | ArcGIS API for
JavaScript 4.22
</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#search {
display: block;
position: absolute;
z-index: 2;
top: 20px;
right: 20px;
}
#exit{
display: block;
position: absolute;
z-index: 2;
top: 50px;
right: 50px;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.22/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.22/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/widgets/Legend",
"esri/Graphic",
"esri/widgets/Editor"
], (Map, MapView, FeatureLayer, Legend, Graphic, Editor) => {
const map = new Map({
basemap: {
portalItem: {
id: "ba223f982a3c4a0ea8c9953346e2a201"
}
},
});
const view = new MapView({
container: "viewDiv",
map: map,
zoom: 14,
center: [-88, 41]
});
view.ui.add(
new Legend({
view: view
}),
"bottom-right"
);
let axisPng = 'axle.png';
////////////////////////// 实时编辑功能/////////////////////////////////////////////
let AxisPoint = [
{
type: "point",
longitude: 121.08058594084916,
latitude: 37.69302040429612,
symbolType: "picture-marker",
id: 1,
url: axisPng,
width: "24px",
height: "24px",
name: "gz1",
angle: "0",
},
{
type: "point",
longitude: 121.08058594084919,
latitude: 37.692905793166474,
symbolType: "picture-marker",
id: 2,
url: axisPng,
width: "24px",
height: "24px",
name: "gz2",
angle: "90",
},
{
type: "point",
longitude: 121.08058057642913,
latitude: 37.6927572229193,
symbolType: "picture-marker",
id: 3,
url: axisPng,
width: "24px",
height: "24px",
name: "gz3",
angle: "60",
},
{
type: "point",
longitude: 121.08058057642913,
latitude: 37.69306479108028,
symbolType: "picture-marker",
id: 4,
url: axisPng,
width: "24px",
height: "24px",
name: "gz4",
angle: "0",
},
{
type: "point",
longitude: 121.08058057642913,
latitude: 37.693038260757845,
symbolType: "picture-marker",
id: 5,
url: axisPng,
width: "24px",
height: "24px",
name: "gz5",
angle: "0",
},
{
type: "point",
longitude: 121.08058057642913,
latitude: 37.693038260757845,
symbolType: "picture-marker",
id: 6,
url: axisPng,
width: "24px",
height: "24px",
name: "gz6",
angle: "0",
},
{
type: "point",
longitude: 121.08058057642913,
latitude: 37.69308397577108,
symbolType: "picture-marker",
id: 7,
url: axisPng,
width: "24px",
height: "24px",
name: "gz7",
angle: "0",
},
{
type: "point",
longitude: 121.08058057642913,
latitude: 37.693098832743665,
symbolType: "picture-marker",
id: 8,
url: axisPng,
width: "24px",
height: "24px",
name: "gz8",
angle: "0",
},
{
type: "point",
longitude: 121.08058057642913,
latitude: 37.693123463156034,
symbolType: "picture-marker",
id: 9,
url: axisPng,
width: "24px",
height: "24px",
name: "gz9",
angle: "0",
},
];
let temporaryAxis = [];
AxisPoint.forEach((item) => {
const AxisProperties = {
Name: item.name,
Angle: item.angle,
id: item.id,
opacity: item.opacity,
gisRack: item.gisRack,
Size: item.scaleX,// 使用scaleX来代表xy同时缩放的比例,单独缩放暂未找到方法
...item
};
const axisGraphic = new Graphic({
geometry: item,
attributes: AxisProperties,
spatialReference: { wkid: 3857 },
});
//存储管轴图形
temporaryAxis.push(axisGraphic);
})
AxleLayer = new FeatureLayer({
title: "管轴图层",
id: "AxisLayer",
//图层资源
source: temporaryAxis,
objectIdField: "id",
//渲染器
renderer: {
// 简单渲染
type: "simple",
// 设置渲染的统一样式
symbol: {
type: "picture-marker",
width: "36px",
height: "36px",
url: axisPng,
// angle: "0"
},
// 根据属性字段中的angle字段的值,单独改动渲染的角度信息,实现角度旋转
visualVariables: [
{
type: "rotation",
field: "angle",
rotationType: "geographic",
},
],
},
fields: [
{
name: "Name",
type: "string",
},
{
name: "Angle",
type: "string",
},
{
name: "id",
type: "integer",
},
{
name: "opacity",
type: "string",
},
{
name: "gisRack",
type: "integer",
},
{
name: "Size",
type: "string",
}
],
//弹出模板
popupTemplate: {
overwriteActions: true,
title: "管轴基础信息",
content: [
{
type: "fields",
fieldInfos: [
{
fieldName: "Name",
label: "管轴名称",
},
{
fieldName: "Angle",
label: "旋转角度",
},
],
},
],
// TODO 在此筛选各图层的图元
},
});
map.add(AxleLayer, 1);
editor = new Editor({
//编辑器所在视图,
view: view,
visible: false,// 关闭编辑面板显示
supportingWidgetDefaults: {// 编辑器默认参数设置--方法1
sketch: {
defaultUpdateOptions: {
enableRotation: false,// 禁用旋转
tool: "reshape",// 默认开启重塑工具
enableScaling: false,// 禁用缩放
toggleToolOnClick: false// 禁用点击切换编辑工具
}
}
}
});
view.on("click", (e) => {
// 点击左键才弹窗
if (e.button === 0) {
view.hitTest(e).then((pickerfeature) => {
// 开启编辑
editor.startUpdateWorkflowAtFeatureEdit(pickerfeature.results[0].graphic);
});
}
// 点击中键
if(e.button === 1){
changePosition(editor, AxleLayer)
}
if(e.button === 2){
exitEdit(editor, AxleLayer)
}
});
function changePosition(editor, AxleLayer){
let getUpdateFeatures = editor.viewModel.sketchViewModel.updateGraphics.items;
let newData = getUpdateFeatures;
newData[0].geometry.latitude += 0.0005;// 修改经纬度
newData[0].geometry.longitude += 0.0005;
newData[0].attributes.Angle += 20;// 修改角度
// console.log("接受到的编辑数据newData[0]", newData[0]);
let edits = {
updateFeatures: newData
};
AxleLayer.applyEdits(edits);
console.log();
};
function exitEdit(editor, AxleLayer){
let getUpdateFeatures = editor.viewModel.sketchViewModel.updateGraphics.items;
let newData = getUpdateFeatures;
let edits = {
updateFeatures: newData
};
AxleLayer.applyEdits(edits);
editor.cancelWorkflow();
}
});
</script>
</head>
<body>
<div id="viewDiv">
</div>
</body>
</html>

In Cytoscape.js, how do I select the set of visible nodes that have no visible edges?

After hiding a set of nodes by shape
cy.elements('[shape="ellipse"]').addClass('hidden');
I am left with a few nodes that have no remaining visible edges (incoming or outgoing), which I would also like to hide. But after a considerable time trying to find invisible roots and leaves and union'ing and differenc'ing them, I simply can't see what must be a simple solution.
Any help greatly appreciated!
Your approach is good, it just needs some adjustments for your desired result. I'd add a filter for every non ellipse node and remove the nodes with no visible connected edges. I use the function .hidden() for that, it returns true if every edge is hidden and false if there is at least one visible edge:
cy.nodes('[shape="ellipse"]').addClass("hidden");
cy.nodes('[shape!="ellipse"]').each(function(node) {
if (node.connectedEdges().hidden()) {
node.addClass("hidden");
}
});
This works because of the style I added. Nodes with a display value of none hide their edges automatically, so there is no need to hide edges manually:
{
selector: '.hidden',
css: {
'display': 'none'
}
}
I tried this out in this dagre graph within a click event listener. I also changed the addClass to toggleClass, you can remove and add the classes with repeated clicks that way:
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
boxSelectionEnabled: false,
autounselectify: true,
style: [{
selector: 'node',
css: {
'content': 'data(id)',
'text-valign': 'center',
'text-halign': 'center',
'height': '60px',
'width': '60px',
'border-color': 'black',
'border-opacity': '1',
'border-width': '10px',
'shape': 'data(shape)'
}
},
{
selector: '$node > node',
css: {
'padding-top': '10px',
'padding-left': '10px',
'padding-bottom': '10px',
'padding-right': '10px',
'text-valign': 'top',
'text-halign': 'center',
'background-color': '#bbb'
}
},
{
selector: 'edge',
css: {
'target-arrow-shape': 'triangle'
}
},
{
selector: ':selected',
css: {
'background-color': 'black',
'line-color': 'black',
'target-arrow-color': 'black',
'source-arrow-color': 'black'
}
},
{
selector: '.hidden',
css: {
'display': 'none'
}
}
],
elements: {
nodes: [{
data: {
id: 'n0',
shape: 'ellipse'
}
},
{
data: {
id: 'n1',
shape: 'ellipse'
}
},
{
data: {
id: 'n2',
shape: 'ellipse'
}
},
{
data: {
id: 'n3',
shape: 'ellipse'
}
},
{
data: {
id: 'n4',
shape: 'ellipse'
}
},
{
data: {
id: 'n5',
shape: 'ellipse'
}
},
{
data: {
id: 'n6',
shape: 'rectangle'
}
},
{
data: {
id: 'n7',
shape: 'ellipse'
}
},
{
data: {
id: 'n8',
shape: 'rectangle'
}
},
{
data: {
id: 'n9',
shape: 'ellipse'
}
},
{
data: {
id: 'n10',
shape: 'ellipse'
}
},
{
data: {
id: 'n11',
shape: 'ellipse'
}
},
{
data: {
id: 'n12',
shape: 'ellipse'
}
},
{
data: {
id: 'n13',
shape: 'rectangle'
}
},
{
data: {
id: 'n14',
shape: 'ellipse'
}
},
{
data: {
id: 'n15',
shape: 'rectangle'
}
},
{
data: {
id: 'n16',
shape: 'ellipse'
}
}
],
edges: [{
data: {
source: 'n0',
target: 'n1'
}
},
{
data: {
source: 'n1',
target: 'n2'
}
},
{
data: {
source: 'n1',
target: 'n3'
}
},
{
data: {
source: 'n2',
target: 'n7'
}
},
{
data: {
source: 'n2',
target: 'n11'
}
},
{
data: {
source: 'n2',
target: 'n16'
}
},
{
data: {
source: 'n3',
target: 'n4'
}
},
{
data: {
source: 'n3',
target: 'n16'
}
},
{
data: {
source: 'n4',
target: 'n5'
}
},
{
data: {
source: 'n4',
target: 'n6'
}
},
{
data: {
source: 'n6',
target: 'n8'
}
},
{
data: {
source: 'n8',
target: 'n9'
}
},
{
data: {
source: 'n8',
target: 'n10'
}
},
{
data: {
source: 'n11',
target: 'n12'
}
},
{
data: {
source: 'n12',
target: 'n13'
}
},
{
data: {
source: 'n13',
target: 'n14'
}
},
{
data: {
source: 'n13',
target: 'n15'
}
},
]
},
layout: {
name: 'dagre',
padding: 5
}
});
cy.unbind("click");
cy.bind("click", function(event) {
cy.nodes('[shape!="ellipse"]').toggleClass("hidden");
cy.nodes('[shape="ellipse"]').each(function(node) {
if (node.connectedEdges().hidden()) {
node.toggleClass("hidden");
}
});
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 75%;
position: absolute;
left: 0;
top: 0;
float: left;
}
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.17/cytoscape.min.js"></script>
<script src="https://unpkg.com/jquery#3.3.1/dist/jquery.js"></script>
<script src="https://unpkg.com/dagre#0.7.4/dist/dagre.js"></script>
<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-dagre/1.5.0/cytoscape-dagre.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>

With cytoscape.js how to automatically expand the height of the container of a graph?

Is it possible to automatically expand the height of the container of a graph, according to the size of the graph?
I want to display lots of graphs of different sizes on a web page, without having to specify the height of each DOM container.
Does it make sense?
Answer:
It is not the best solution to change anything regarding the container of cytoscape.
Alternative for you:
It is far better to work with the padding of the graph in order to display the graph in a dynamic/suitable way. The easiest way to do that, is to add your nodes and run your layout and then, when the layout is loaded, you can call cy.fit(cy.elements(), yourPadding).
In cytoscape, padding is handled exactly the same way as in css, so you just calculate (based on the number of nodes maybe?) the appropriate padding for your graph and fit it to the viewport.
Additionally, you can always wrap things up with a slick ease-in animation to top things off.
Code:
Snippet works when you click on edit the above snippet and run it in the snippet editor, here the function does not work due to the size limitation and I can't be bothered to adjust it without seeing the outcome in the editor.
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
boxSelectionEnabled: false,
autounselectify: true,
style: [
{
selector: "node",
css: {
content: "data(id)",
"text-valign": "bottom",
"text-halign": "center",
height: "60px",
width: "60px",
"border-color": "black",
"border-opacity": "1",
"background-image":
"https://farm8.staticflickr.com/7272/7633179468_3e19e45a0c_b.jpg"
}
},
{
selector: "edge",
css: {
"target-arrow-shape": "triangle"
}
},
{
selector: ":selected",
css: {
"background-color": "black",
"line-color": "black",
"target-arrow-color": "black",
"source-arrow-color": "black"
}
}
],
elements: {
nodes: [
{ data: { id: "n0" } },
{ data: { id: "n1" } },
{ data: { id: "n2" } },
{ data: { id: "n3" } },
{ data: { id: "n4" } },
{ data: { id: "n5" } },
{ data: { id: "n6" } },
{ data: { id: "n7" } },
{ data: { id: "n8" } },
{ data: { id: "n9" } },
{ data: { id: "n10" } },
{ data: { id: "n11" } },
{ data: { id: "n12" } },
{ data: { id: "n13" } },
{ data: { id: "n14" } },
{ data: { id: "n15" } },
{ data: { id: "n16" } }
],
edges: [
{ data: { source: "n0", target: "n1" } },
{ data: { source: "n1", target: "n2" } },
{ data: { source: "n1", target: "n3" } },
{ data: { source: "n2", target: "n7" } },
{ data: { source: "n2", target: "n11" } },
{ data: { source: "n2", target: "n16" } },
{ data: { source: "n3", target: "n4" } },
{ data: { source: "n3", target: "n16" } },
{ data: { source: "n4", target: "n5" } },
{ data: { source: "n4", target: "n6" } },
{ data: { source: "n6", target: "n8" } },
{ data: { source: "n8", target: "n9" } },
{ data: { source: "n8", target: "n10" } },
{ data: { source: "n11", target: "n12" } },
{ data: { source: "n12", target: "n13" } },
{ data: { source: "n13", target: "n14" } },
{ data: { source: "n13", target: "n15" } }
]
},
layout: {
name: "dagre",
padding: 5
}
}));
cy.unbind("click");
cy.bind("click", "node", function(event) { // just for demonstration purposes here
var coll = cy.$(event.target).successors(); // get all outgoing nodes
coll = coll.add(event.target); // add their source
var removed = cy.remove(cy.elements().not(coll)); // remove all other elements
var len = cy.nodes().length;
var pad = (len < 10 ? (len < 5 ? (len < 3 ? (len < 2 ? 150 : 100 ) : 75 ) : 50 ) : 25); // custom padding function here
cy.animate({
fit: {
eles: cy.elements(),
padding: pad
}
}, {
duration: 500,
easing: 'ease-in'
});
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
float: left;
}
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.17/cytoscape.min.js"></script>
<script src="https://unpkg.com/jquery#3.3.1/dist/jquery.js"></script>
<script src="https://unpkg.com/dagre#0.7.4/dist/dagre.js"></script>
<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-dagre/1.5.0/cytoscape-dagre.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>

Content and Label on a Node - Cytoscape

I'm trying to display nodes that have a font icon in the center of the node using 'content' and a text label underneath.
My styling is currently:
{
'selector': 'node[icon]',
'style': {
'content': 'data(icon)',
'font-family': 'Material Icons',
'text-valign': 'center',
'text-halign': 'center'
}
},
{
'selector': 'node[label]',
'style': {
'label': 'data(label)',
'text-valign': 'bottom',
'text-halign': 'center'
}
}
However, this doesn't work as i assume both of the styles is used on one element (the node).
There are a few solutions I've considered, such as:
Putting the label on a parent node
Use Popper.js or similar to show the label
Use a multi-lined label
The first 2 seem 'hacky', and the third could cause a lot of alignment problems. Is there a better solution to this?
I've found a solution using the extension: https://github.com/kaluginserg/cytoscape-node-html-label.
You can create custom HTML labels for nodes which do not interfere with the base Cytoscape labels. An example of using the Material Icons:
// Initialise the HTML Label
this.cy.nodeHtmlLabel([{
query: '.nodeIcon',
halign: 'center',
valign: 'center',
halignBox: 'center',
valignBox: 'center',
tpl: (data) => {
return '<i class="material-icons">' + data.icon + '</i>';
}
}]);
// Add the HTML Label to the node:
const node = {
group: 'nodes',
data: {
id: data.id,
label: data.label,
icon: data.icon
},
classes: 'nodeIcon' // <---- Add the HTML Label class here
};
With the method you can dynamically create nodes with font icons without the need to download a load of images.
You can even add CSS styling to change the colour of the icon:
If you want an icon as the nodes body, you can use it as the background image and define the label like you do:
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
boxSelectionEnabled: false,
autounselectify: true,
style: [{
selector: 'node',
css: {
'label': 'data(id)',
'text-valign': 'bottom',
'text-halign': 'center',
'height': '60px',
'width': '60px',
'border-color': 'black',
'border-opacity': '1',
'background-image': 'https://farm8.staticflickr.com/7272/7633179468_3e19e45a0c_b.jpg',
"text-background-opacity": 1,
"text-background-color": "lightgray"
}
},
{
selector: ':selected',
css: {
'background-color': 'black',
'line-color': 'black',
'target-arrow-color': 'black',
'source-arrow-color': 'black'
}
}
],
elements: {
nodes: [{
data: {
id: 'n0'
}
},
{
data: {
id: 'n1'
}
},
{
data: {
id: 'n2'
}
},
{
data: {
id: 'n3'
}
},
{
data: {
id: 'n4'
}
},
{
data: {
id: 'n5'
}
},
{
data: {
id: 'n6'
}
},
{
data: {
id: 'n7'
}
},
{
data: {
id: 'n8'
}
},
{
data: {
id: 'n9'
}
},
{
data: {
id: 'n10'
}
},
{
data: {
id: 'n11'
}
},
{
data: {
id: 'n12'
}
},
{
data: {
id: 'n13'
}
},
{
data: {
id: 'n14'
}
},
{
data: {
id: 'n15'
}
},
{
data: {
id: 'n16'
}
}
],
edges: [{
data: {
source: 'n0',
target: 'n1'
}
},
{
data: {
source: 'n1',
target: 'n2'
}
},
{
data: {
source: 'n1',
target: 'n3'
}
},
{
data: {
source: 'n2',
target: 'n7'
}
},
{
data: {
source: 'n2',
target: 'n11'
}
},
{
data: {
source: 'n2',
target: 'n16'
}
},
{
data: {
source: 'n3',
target: 'n4'
}
},
{
data: {
source: 'n3',
target: 'n16'
}
},
{
data: {
source: 'n4',
target: 'n5'
}
},
{
data: {
source: 'n4',
target: 'n6'
}
},
{
data: {
source: 'n6',
target: 'n8'
}
},
{
data: {
source: 'n8',
target: 'n9'
}
},
{
data: {
source: 'n8',
target: 'n10'
}
},
{
data: {
source: 'n11',
target: 'n12'
}
},
{
data: {
source: 'n12',
target: 'n13'
}
},
{
data: {
source: 'n13',
target: 'n14'
}
},
{
data: {
source: 'n13',
target: 'n15'
}
},
]
},
layout: {
name: 'dagre',
padding: 5
}
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 75%;
position: absolute;
left: 0;
top: 0;
float: left;
}
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.17/cytoscape.min.js"></script>
<script src="https://unpkg.com/jquery#3.3.1/dist/jquery.js"></script>
<script src="https://unpkg.com/dagre#0.7.4/dist/dagre.js"></script>
<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-dagre/1.5.0/cytoscape-dagre.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>