Angular D3 not Displaying - javascript

I am trying to create an Angular D3 force directed graph but for some reason it is not displaying, and there are no errors in the console. Now it currently loads a JSON however I am also trying to figure out how to load in a variable instead.... any help will be appreciated
index.html
<head>
<!--<script src="css/angular.css"></script>-->
</head>
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
</style>
<body>
<div ng-controller="MainCtrl">
<d3-bars data="d3Data"></d3-bars>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.4/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.12/d3.js"></script>
<script src="js/index.js"></script>
</body>
app.js
app = angular.module("triForce", [])
app.controller("MainCtrl", function($scope, $http) {
$scope.width = 900;
$scope.height = 900;
var color = d3.scale.category20()
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([$scope.width, $scope.height]);
$scope.data=[{
"nodes": [
{
"name": "hblodget",
"group": 1,
"size": 1,
"image": null
},
{
"name": "DowntownDonna69",
"group": 1,
"size": 20,
"image": "http://pbs.twimg.com/profile_images/636139174672732160/L5cd008s_normal.jpg"
},
{
"name": "PupsherLive",
"group": 1,
"size": 19,
"image": "http://pbs.twimg.com/profile_images/378800000210840839/93a8ba3852a8e20364957eb8b907b6b3_normal.jpeg"
},
{
"name": "PupsherLive",
"group": 1,
"size": 19,
"image": "http://pbs.twimg.com/profile_images/378800000210840839/93a8ba3852a8e20364957eb8b907b6b3_normal.jpeg"
},
{
"name": "PupsherLive",
"group": 1,
"size": 19,
"image": "http://pbs.twimg.com/profile_images/378800000210840839/93a8ba3852a8e20364957eb8b907b6b3_normal.jpeg"
},
{
"name": "PupsherLive",
"group": 1,
"size": 19,
"image": "http://pbs.twimg.com/profile_images/378800000210840839/93a8ba3852a8e20364957eb8b907b6b3_normal.jpeg"
},
{
"name": "PupsherLive",
"group": 1,
"size": 19,
"image": "http://pbs.twimg.com/profile_images/378800000210840839/93a8ba3852a8e20364957eb8b907b6b3_normal.jpeg"
},
{
"name": "PupsherLive",
"group": 1,
"size": 19,
"image": "http://pbs.twimg.com/profile_images/378800000210840839/93a8ba3852a8e20364957eb8b907b6b3_normal.jpeg"
}
],
"links": [
{
"source": 1,
"target": 0,
"value": 1
},
{
"source": 2,
"target": 0,
"value": 1
},
{
"source": 2,
"target": 0,
"value": 1
},
{
"source": 2,
"target": 0,
"value": 1
},
{
"source": 2,
"target": 0,
"value": 1
},
{
"source": 2,
"target": 0,
"value": 1
},
{
"source": 1,
"target": 0,
"value": 1
}
]
}
];
$scope.nodes = graph.nodes;
$scope.links = graph.links;
for(var i=0; i < $scope.links.length ; i++){
$scope.links[i].strokeWidth = Math.round(Math.sqrt($scope.links[i].value))
}
for(var i=0; i < $scope.nodes.length ; i++){
$scope.nodes[i].color = color($scope.nodes[i].group)
}
force
.nodes($scope.nodes)
.links($scope.links)
.on("tick", function(){$scope.$apply()})
.start();
})

I have not dug to far into your code, but at first glance it looks like you are not binding the <d3-bars data="d3Data"></d3-bars> directive to the right variable. It looks like your controller is setting the property $scope.data not $scope.d3Data

Related

How to keep the previous position when expand and collapse group with cytoscape.js

I've been searching for a good topology layout javascript library for a long time. I learned many library D3, WebCola, and so on, and eventually I was deeply attracted to
cytoscape and its amazing extension cytoscape.js-expand-collapse
What I want is a javascript layout library, which can do a reasonable layout with a lot of nodes. The parent nodes contains children nodes, in other words, there is an inheritance relationship between the nodes.
This Demo is almost extactly what I need. The expanding and collapsing feature is really great.
And I create my demo base on the above demo. But, when expand a node and then collapse the node, all nodes on the graph are changed.
Initial graph
The state after expand and collapse node at first time
The state after expand and collapse node at second time
Obviously that's not my need. And I learn the original offial demo again. I find the elements values of demo has position on each data.
{"data":{"id":"nwtN_50c55b8c-3489-4c4e-8bea-6a1c1162ac9c"},"position":{"x":577.5410894097904,"y":612.5647477282114},"group":"nodes"}
I know if each data has reasonable coordinate, all nodes position will not be changed after expand and collapse some nodes.
The key point is that I don't know the coordinate and I can't set the initial coordinate for my nodes. I think the core algorithm of layout is to calculate the appropriate coordinate points for each point.
So, I can't set the initial coordinate for all nodes and I expect all nodes position are fixed , no matter expand and collpase any node. Is it possible?
The following is my demo.
document.addEventListener('DOMContentLoaded', function() {
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
ready: function() {
var api = this.expandCollapse({
layoutBy: {
name: "cose-bilkent",
animate: "end",
randomize: false,
fit: false
},
fisheye: true,
animate: false,
undoable: false
});
api.collapseAll();
},
style: [{
selector: 'node',
style: {
'label': 'data(id)'
}
}],
elements: [{
"group": "nodes",
"data": {
"id": "n_0",
"name": "External Network"
}
}, {
"group": "nodes",
"data": {
"id": "n_4",
"name": "虚拟机网络",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "n_3",
"name": "VM Network 2",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_128",
"name": "bfcui-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_105",
"name": "bychen-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_93",
"name": "CE-bj",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_100",
"name": "changliu-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_67",
"name": "chaoma-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_83",
"name": "chenwang",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_68",
"name": "cwang-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_15",
"name": "gqpei-bj",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_1",
"name": "gwxu-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_118",
"name": "gyzhao-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_76",
"name": "hlli-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_18",
"name": "hwzhang-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_40",
"name": "hxqu-pc"
}
}, {
"group": "nodes",
"data": {
"id": "v_69",
"name": "hxwang-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_71",
"name": "jbshi-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_64",
"name": "jdai-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_16",
"name": "jfxiao-bj",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_78",
"name": "jhhou-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_91",
"name": "jjsun-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_17",
"name": "jppan-bj",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_45",
"name": "jqwang-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_50",
"name": "jxli-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_42",
"name": "jyyou-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_28",
"name": "jyzhou-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_46",
"name": "jzhao-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_19",
"name": "lfeng-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_65",
"name": "lhzhen-pc",
"parent": "group2"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_1",
"source": "n_0",
"target": "v_1"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_100",
"source": "n_0",
"target": "v_100"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_46",
"source": "n_0",
"target": "v_46"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_64",
"source": "n_0",
"target": "v_64"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_65",
"source": "n_0",
"target": "v_65"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_67",
"source": "n_0",
"target": "v_67"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_69",
"source": "n_0",
"target": "v_69"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_71",
"source": "n_0",
"target": "v_71"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_76",
"source": "n_0",
"target": "v_76"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_78",
"source": "n_0",
"target": "v_78"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_83",
"source": "n_0",
"target": "v_83"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_91",
"source": "n_0",
"target": "v_91"
}
}, {
"data": {
"group": "edges",
"id": "v_1n_0",
"source": "v_1",
"target": "n_0"
}
}, {
"data": {
"group": "edges",
"id": "v_1v_128",
"source": "v_1",
"target": "v_128"
}
}, {
"data": {
"group": "edges",
"id": "v_100n_0",
"source": "v_100",
"target": "n_0"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_16",
"source": "v_118",
"target": "v_16"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_18",
"source": "v_118",
"target": "v_18"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_46",
"source": "v_118",
"target": "v_46"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_67",
"source": "v_118",
"target": "v_67"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_69",
"source": "v_118",
"target": "v_69"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_71",
"source": "v_118",
"target": "v_71"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_78",
"source": "v_118",
"target": "v_78"
}
}, {
"data": {
"group": "edges",
"id": "v_128n_0",
"source": "v_128",
"target": "n_0"
}
}, {
"data": {
"group": "edges",
"id": "v_128v_1",
"source": "v_128",
"target": "v_1"
}
}, {
"data": {
"group": "edges",
"id": "v_128v_105",
"source": "v_128",
"target": "v_105"
}
}, {
"data": {
"group": "edges",
"id": "v_128v_46",
"source": "v_128",
"target": "v_46"
}
}, {
"data": {
"group": "edges",
"id": "v_128v_65",
"source": "v_128",
"target": "v_65"
}
}, {
"data": {
"group": "edges",
"id": "v_15n_0",
"source": "v_15",
"target": "n_0"
}
}, {
"data": {
"group": "edges",
"id": "v_50v_40",
"source": "v_50",
"target": "v_40"
}
}, {
"data": {
"group": "edges",
"id": "v_50v_46",
"source": "v_50",
"target": "v_46"
}
}, {
"data": {
"group": "edges",
"id": "v_50v_64",
"source": "v_50",
"target": "v_64"
}
}, {
"data": {
"group": "edges",
"id": "v_65v_19",
"source": "v_65",
"target": "v_19"
}
}, {
"data": {
"group": "edges",
"id": "v_65v_91",
"source": "v_65",
"target": "v_91"
}
}, {
"data": {
"group": "edges",
"id": "v_67n_0",
"source": "v_67",
"target": "n_0"
}
}, {
"data": {
"group": "edges",
"id": "v_67v_100",
"source": "v_67",
"target": "v_100"
}
}, {
"data": {
"group": "edges",
"id": "v_67v_105",
"source": "v_67",
"target": "v_105"
}
}, {
"data": {
"group": "edges",
"id": "v_67v_42",
"source": "v_67",
"target": "v_42"
}
}, {
"data": {
"group": "edges",
"id": "v_91v_16",
"source": "v_91",
"target": "v_16"
}
}, {
"data": {
"group": "edges",
"id": "v_91v_18",
"source": "v_91",
"target": "v_18"
}
}, {
"data": {
"group": "edges",
"id": "v_91v_28",
"source": "v_91",
"target": "v_28"
}
}, {
"data": {
"group": "edges",
"id": "v_91v_45",
"source": "v_91",
"target": "v_45"
}
}, {
"group": "nodes",
"data": {
"id": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "group2"
}
}]
});
var api = cy.expandCollapse('get');
var beforeExpand = null;
cy.unbind('expandcollapse.beforeexpand');
cy.nodes().bind('expandcollapse.beforeexpand', function(event) {
if (beforeExpand == null)
beforeExpand = cy.elements().clone(); // save the graph before the first expand
}); // Triggered before a node is expanded
cy.unbind('expandcollapse.aftercollapse');
cy.nodes().bind('expandcollapse.aftercollapse', function(event) {
if(beforeExpand != null) {
cy.elements().remove();
cy.add(beforeExpand); // set the graph to original values
beforeExpand = null;
}
});
});
body {
font-family: helvetica neue, helvetica, liberation sans, arial, sans-serif;
font-size: 14px;
}
#cy {
z-index: 999;
width: 100%;
height: 100%;
}
h1 {
opacity: 0.5;
font-size: 1em;
font-weight: bold;
}
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="https://unpkg.com/cytoscape#3.1.0/dist/cytoscape.min.js"></script>
<!-- for testing with local version of cytoscape.js -->
<!--<script src="../cytoscape.js/build/cytoscape.js"></script>-->
<script src="https://unpkg.com/cytoscape-cose-bilkent#4.0.0/cytoscape-cose-bilkent.js"></script>
<script src="https://unpkg.com/cytoscape-expand-collapse#3.1.1/cytoscape-expand-collapse.js"></script>
<div id="cy"></div>
Finally, sum up what I need :
Init graph with some nodes, which may be expandable depending on a property like type. Nodes with type=1 are expandable and type=2 not.
All nodes do a reasonable layout, like layoutBy:{name:'cose-bilkent'}
When expand one node (eg : A), Send ajax request to get children nodes (eg: A1, A2, A3) and then layout children. The graph maybe need an appropriate adjustments. I hope it's a incremental layout, not a full re-layout.
When collapse the previous compond nodes (group A with A1,A2,A3), all nodes on the graph keep the previous position.
When expand the last group node (eg : A), the children nodes are also keep the previous position.
I think my requirement is very basic, but I can't find a demo to display this feature? Do I describe my requirement clearly ?
Can someone help me? Thanks in advance. Thanks very much.
What you are trying to do is not really efficient. You said yourself, that you don't know the coordinates of your nodes, so cytoscape doesn'know that either. But non the less, cose-blikent still positions the elements as good as possible. The position may change, but the structure stays the same. There is really no problem there that justifies the trouble and work you'd have to go through to.
If you really want to achieve this, i suppose you can do this within a specific event that has occured:
Code:
var nodes = cy.nodes();
var positions = [];
for (node in nodes) {
positions[node] = nodes[node].position(); // save the i'th nodes positions
}
and then after you collapse a parent and expand it again, you can set all the nodes positions that you stored before:
var nodes = cy.nodes();
for (node in nodes) {
nodes[node].position(positions[node]); // set x and y of node
}
Events:
cy.nodes().on("expandcollapse.beforecollapse", function(event) { var node = this; ... }) // Triggered before a node is collapsed
cy.nodes().on("expandcollapse.aftercollapse", function(event) { var node = this; ... }) // Triggered after a node is collapsed
cy.nodes().on("expandcollapse.beforeexpand", function(event) { var node = this; ... }) // Triggered before a node is expanded
cy.nodes().on("expandcollapse.afterexpand", function(event) { var node = this; ... }) // Triggered after a node is expanded
Edit:
var beforeExpand = null;
cy.unbind('expandcollapse.beforeexpand');
cy.nodes().bind('expandcollapse.beforeexpand', function(event) {
if (beforeExpand == null)
beforeExpand = cy.elements().clone(); // save the graph before the first expand
}); // Triggered before a node is expanded
cy.unbind('expandcollapse.aftercollapse');
cy.nodes().bind('expandcollapse.aftercollapse', function(event) {
if(beforeExpand != null) {
cy.elements().remove();
cy.add(beforeExpand); // set the graph to original values
beforeExpand = null;
}
}); // Triggered before a node is expanded
Edit:
Here is how you repair your demo:
change fit: false to fit: true
change your css for the cytoscape like in the following snippet
document.addEventListener('DOMContentLoaded', function() {
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
ready: function() {
var api = this.expandCollapse({
layoutBy: {
name: "cose-bilkent",
animate: "end",
randomize: false,
fit: true // set this to true
},
fisheye: true,
animate: false,
undoable: false
});
api.collapseAll();
},
style: [{
selector: 'node',
style: {
'label': 'data(id)'
}
}],
elements: [{
"group": "nodes",
"data": {
"id": "n_0",
"name": "External Network"
}
}, {
"group": "nodes",
"data": {
"id": "n_4",
"name": "虚拟机网络",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "n_3",
"name": "VM Network 2",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_128",
"name": "bfcui-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_105",
"name": "bychen-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_93",
"name": "CE-bj",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_100",
"name": "changliu-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_67",
"name": "chaoma-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_83",
"name": "chenwang",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_68",
"name": "cwang-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_15",
"name": "gqpei-bj",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_1",
"name": "gwxu-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_118",
"name": "gyzhao-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_76",
"name": "hlli-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_18",
"name": "hwzhang-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_40",
"name": "hxqu-pc"
}
}, {
"group": "nodes",
"data": {
"id": "v_69",
"name": "hxwang-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_71",
"name": "jbshi-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_64",
"name": "jdai-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_16",
"name": "jfxiao-bj",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_78",
"name": "jhhou-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_91",
"name": "jjsun-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_17",
"name": "jppan-bj",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_45",
"name": "jqwang-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_50",
"name": "jxli-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_42",
"name": "jyyou-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_28",
"name": "jyzhou-pc",
"parent": "group2"
}
}, {
"group": "nodes",
"data": {
"id": "v_46",
"name": "jzhao-pc",
"parent": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "v_19",
"name": "lfeng-pc",
"parent": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "v_65",
"name": "lhzhen-pc",
"parent": "group2"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_1",
"source": "n_0",
"target": "v_1"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_100",
"source": "n_0",
"target": "v_100"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_46",
"source": "n_0",
"target": "v_46"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_64",
"source": "n_0",
"target": "v_64"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_65",
"source": "n_0",
"target": "v_65"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_67",
"source": "n_0",
"target": "v_67"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_69",
"source": "n_0",
"target": "v_69"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_71",
"source": "n_0",
"target": "v_71"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_76",
"source": "n_0",
"target": "v_76"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_78",
"source": "n_0",
"target": "v_78"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_83",
"source": "n_0",
"target": "v_83"
}
}, {
"data": {
"group": "edges",
"id": "n_0v_91",
"source": "n_0",
"target": "v_91"
}
}, {
"data": {
"group": "edges",
"id": "v_1n_0",
"source": "v_1",
"target": "n_0"
}
}, {
"data": {
"group": "edges",
"id": "v_1v_128",
"source": "v_1",
"target": "v_128"
}
}, {
"data": {
"group": "edges",
"id": "v_100n_0",
"source": "v_100",
"target": "n_0"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_16",
"source": "v_118",
"target": "v_16"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_18",
"source": "v_118",
"target": "v_18"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_46",
"source": "v_118",
"target": "v_46"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_67",
"source": "v_118",
"target": "v_67"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_69",
"source": "v_118",
"target": "v_69"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_71",
"source": "v_118",
"target": "v_71"
}
}, {
"data": {
"group": "edges",
"id": "v_118v_78",
"source": "v_118",
"target": "v_78"
}
}, {
"data": {
"group": "edges",
"id": "v_128n_0",
"source": "v_128",
"target": "n_0"
}
}, {
"data": {
"group": "edges",
"id": "v_128v_1",
"source": "v_128",
"target": "v_1"
}
}, {
"data": {
"group": "edges",
"id": "v_128v_105",
"source": "v_128",
"target": "v_105"
}
}, {
"data": {
"group": "edges",
"id": "v_128v_46",
"source": "v_128",
"target": "v_46"
}
}, {
"data": {
"group": "edges",
"id": "v_128v_65",
"source": "v_128",
"target": "v_65"
}
}, {
"data": {
"group": "edges",
"id": "v_15n_0",
"source": "v_15",
"target": "n_0"
}
}, {
"data": {
"group": "edges",
"id": "v_50v_40",
"source": "v_50",
"target": "v_40"
}
}, {
"data": {
"group": "edges",
"id": "v_50v_46",
"source": "v_50",
"target": "v_46"
}
}, {
"data": {
"group": "edges",
"id": "v_50v_64",
"source": "v_50",
"target": "v_64"
}
}, {
"data": {
"group": "edges",
"id": "v_65v_19",
"source": "v_65",
"target": "v_19"
}
}, {
"data": {
"group": "edges",
"id": "v_65v_91",
"source": "v_65",
"target": "v_91"
}
}, {
"data": {
"group": "edges",
"id": "v_67n_0",
"source": "v_67",
"target": "n_0"
}
}, {
"data": {
"group": "edges",
"id": "v_67v_100",
"source": "v_67",
"target": "v_100"
}
}, {
"data": {
"group": "edges",
"id": "v_67v_105",
"source": "v_67",
"target": "v_105"
}
}, {
"data": {
"group": "edges",
"id": "v_67v_42",
"source": "v_67",
"target": "v_42"
}
}, {
"data": {
"group": "edges",
"id": "v_91v_16",
"source": "v_91",
"target": "v_16"
}
}, {
"data": {
"group": "edges",
"id": "v_91v_18",
"source": "v_91",
"target": "v_18"
}
}, {
"data": {
"group": "edges",
"id": "v_91v_28",
"source": "v_91",
"target": "v_28"
}
}, {
"data": {
"group": "edges",
"id": "v_91v_45",
"source": "v_91",
"target": "v_45"
}
}, {
"group": "nodes",
"data": {
"id": "group0"
}
}, {
"group": "nodes",
"data": {
"id": "group1"
}
}, {
"group": "nodes",
"data": {
"id": "group2"
}
}]
});
var api = cy.expandCollapse('get');
var beforeExpand = null;
cy.unbind('expandcollapse.beforeexpand');
cy.nodes().bind('expandcollapse.beforeexpand', function(event) {
if (beforeExpand == null)
beforeExpand = cy.elements().clone(); // save the graph before the first expand
}); // Triggered before a node is expanded
cy.unbind('expandcollapse.aftercollapse');
cy.nodes().bind('expandcollapse.aftercollapse', function(event) {
if(beforeExpand != null) {
cy.elements().remove();
cy.add(beforeExpand); // set the graph to original values
beforeExpand = null;
}
});
});
body {
font-family: helvetica;
font-size: 14px;
}
#cy { /*change your css*/
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 999;
}
h1 {
opacity: 0.5;
font-size: 1em;
}
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="https://unpkg.com/cytoscape#3.1.0/dist/cytoscape.min.js"></script>
<!-- for testing with local version of cytoscape.js -->
<!--<script src="../cytoscape.js/build/cytoscape.js"></script>-->
<script src="https://unpkg.com/cytoscape-cose-bilkent#4.0.0/cytoscape-cose-bilkent.js"></script>
<script src="https://unpkg.com/cytoscape-expand-collapse#3.1.1/cytoscape-expand-collapse.js"></script>
<div id="cy"></div>
The nodes in the example have positions just because it was exported from another tool.
Each time an expand or a collapse operation is performed, if the layoutBy option is set, that layout is applied to the graph. In the example the layoutBy option is set to cose-bilkent, and that is why the positions change.
I believe you can achieve what you want by setting layoutBy to null, and fisheye to false. You can see the other options and their explanations here.
P.S: for the initial coordinates, you might consider setting the layout option of Cytoscape while initializing.
I too, ran into the same issue while using fCose layout, I had forgotten to give the key , "randomize" and set it to false, a simple mistake.
From the docs, it looks it shall randomize the only the overall layout if given true but under the expand-collapse context, it rearranges every single node displayed.
If you also missed on understanding randomize while using different third-party libs, this answer shall help you.

Unable to extract graph data (nodes,links) from json in d3.js

After days of effort, I have finally created my first d3.js layout. But now I want to segregate data and script. I was trying to use JSON to keep data and extract from it. But it didn't work. Please help.
I tried this, but then it started failing:
d3.json("sample.json", function(data) {
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(data.links)
.enter().append("line")
.attr("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(data.nodes)
.enter().append("circle")
.attr("r", 5)
.attr("fill", function(d) { return color(d.group); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
...
)};
Here is the complete code I am working on.
JSFIDDLE : d3_graph_labelled_edge.js
Invalid JSON. After formatting (removing last line commas and replacing single quotes with double):
{
"nodes": [{
"name": "NE1",
"full_name": "NE1",
"type": 2,
"slug": "12.3",
"entity": "company",
"img_hrefD": "",
"img_hrefL": ""
},
{
"name": "NE2",
"full_name": "NE2",
"type": 2,
"slug": "12.4",
"entity": "company",
"img_hrefD": "",
"img_hrefL": ""
},
{
"name": "NE3",
"full_name": "NE3",
"type": 2,
"slug": "12.3",
"entity": "company",
"img_hrefD": "",
"img_hrefL": ""
},
{
"name": "NE4",
"full_name": "NE4",
"type": 2,
"slug": "12.1",
"entity": "company",
"img_hrefD": "",
"img_hrefL": ""
},
{
"name": "NE5",
"full_name": "NE5",
"type": 2,
"slug": "12.0",
"entity": "company",
"img_hrefD": "",
"img_hrefL": ""
}
],
"links": [{
"source": 0,
"target": 1,
"value": 1,
"distance": 15,
"a": "123",
"z": "111"
},
{
"source": 0,
"target": 2,
"value": 1,
"distance": 15,
"a": "123",
"z": "111"
},
{
"source": 0,
"target": 3,
"value": 1,
"distance": 15,
"a": "123",
"z": "111"
},
{
"source": 1,
"target": 2,
"value": 1,
"distance": 15,
"a": "123",
"z": "111"
},
{
"source": 1,
"target": 3,
"value": 1,
"distance": 15,
"a": "123",
"z": "111"
},
{
"source": 2,
"target": 3,
"value": 1,
"distance": 15,
"a": "123",
"z": "111"
},
{
"source": 1,
"target": 4,
"value": 1,
"distance": 15,
"a": "123",
"z": "111"
}
]
}
Here's a plunkr using the above JSON: http://plnkr.co/edit/vRrYyjH3mtPz8vEuTZKx?p=preview
Recommendation: Use JSON Lint for validation.
Hope this helps.

Sigma curve and curvedArrow edge type renders as a line

I am messing around with Sigma and I cannot seem to get the lines to curve. Regular arrows work ok, but curved do not.
var graphData = {
"nodes": [
{ "id": "n0", "label": "A node", "x": 0, "y": 0, "size": 3 },
{ "id": "n1", "label": "Another node", "x": 3, "y": 1, "size": 2 },
{ "id": "n2", "label": "And a last one", "x": 1, "y": 3, "size": 1 },
{ "id": "n3", "label": "A node", "x": 2, "y": 0, "size": 8, "color": "#48ec51" },
{ "id": "n4", "label": "Another node", "x": 0, "y": 2, "size": 5, "color": "#5148ec" },
{ "id": "n5", "label": "And a last one", "x": 2, "y": 3, "size": 3, "color": "#ec48ec" }
],
"edges": [
{ "id": "e0", "source": "n0", "target": "n1", "type": "curvedArrow", "size": 5 },
{ "id": "e1", "source": "n1", "target": "n2", "type": "curvedArrow" },
{ "id": "e2", "source": "n2", "target": "n0", "type": "curvedArrow" },
{ "id": "e3", "source": "n3", "target": "n4", "type": "arrow", "size": 3 },
{ "id": "e4", "source": "n4", "target": "n5", "type": "arrow", "size": 2 },
{ "id": "e5", "source": "n5", "target": "n3", "type": "arrow", "size": 1 }
]
};
// Initialize the Sigma graph
const sigmaInstance = new sigma({
graph: graphData,
container: 'sigma-container',
settings: {
defaultNodeColor: '#ec5148',
defaultEdgeType: 'arrow',
minEdgeSize: 5,
maxEdgeSize: 5
}
});
// Refresh the edges. Comment this out to see the arrows...
var types = [ 'line', 'curve', 'arrow', 'curvedArrow' ];
sigmaInstance.graph.edges().forEach(function(e) { e.type = types[3]; });
sigmaInstance.refresh();
// Set initial zoom
sigmaInstance.cameras[0].goTo({ x: 1, y: 1, angle: 0, ratio: 2.0 });
// Add drag listener
let dragListener = sigma.plugins.dragNodes(sigmaInstance, sigmaInstance.renderers[0]);
body {
background: #ddd;
}
h1 {
text-align: center;
}
.sigma-wrapper {
max-width: 300px;
background: #fff;
border: 2px solid #AAA;
margin: auto;
}
#sigma-container {
max-width: 300px;
height: 300px;
}
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sigma.js/1.2.1/sigma.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sigma.js/1.2.1/plugins/sigma.parsers.json.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sigma.js/1.2.1/plugins/sigma.plugins.dragNodes.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sigma.js/1.2.1/plugins/sigma.renderers.parallelEdges.min.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/jacomyal/sigma.js/9c940aa9/src/renderers/canvas/sigma.canvas.edges.curve.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/jacomyal/sigma.js/9c940aa9/src/renderers/canvas/sigma.canvas.edges.arrow.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/jacomyal/sigma.js/9c940aa9/src/renderers/canvas/sigma.canvas.edges.curvedArrow.js"></script>
<h1>Sigma JS Workbench</h1>
<div class="sigma-wrapper">
<div id="sigma-container"></div>
</div>
A Github user solved this by specifying a canvas renderer.
const sigmaInstance = new sigma({
graph: graphData,
container: 'sigma-container',
...
// canvas renderer
// ===============
renderer: {
container: document.getElementById('sigma-container'),
type: sigma.renderers.canvas
}
});
I know this is a late answer but I hope it still helps someone out there with this problem.
If you are using the minified library file sigma.min.js to include the sigma core library then the problem is most likely coming from there. If you open the gruntfile used to compile the minified file, the file names pointing to the curved edges files are wrong:
'src/renderers/canvas/sigma.canvas.edges.dotCurve.js',
'src/renderers/canvas/sigma.canvas.edges.arrow.js',
'src/renderers/canvas/sigma.canvas.edges.dotCurvedArrow.js'
they should be this ones (without the "dot"):
'src/renderers/canvas/sigma.canvas.edges.curve.js',
'src/renderers/canvas/sigma.canvas.edges.arrow.js',
'src/renderers/canvas/sigma.canvas.edges.curvedArrow.js'
Hope it helped!

Zooming in a d3js force simulation on a canvas

I've set up a force directed graph with d3.js using svg, but eventually the graph became to big and it's having performance issues. I decided to try to do it in a canvas, because I read it renders stuff muck better and faster. But now I'm having an issue with zooming. I've implemented the zoom behavior correctly (i guess), but i can only zoom when the graph is at rest. Before the simulation find an equilibrium point zoom behavior does not work. Any idea why? Or any tips on what should i do?
var force = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d, i) { return i; }))
.force("charge", d3.forceManyBody().strength( -5 ))
.force("center", d3.forceCenter(width / 2, height / 2));
force.nodes(data.nodes)
.on("tick", ticked)
force.force("link")
.links(data.links);
function ticked(){
context.clearRect(0, 0, width, height);
// Draw the links
data.links.forEach(function(d) {
// Draw a line from source to target.
context.beginPath();
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
context.stroke();
});
// Draw the nodes
data.nodes.forEach(function(d, i) {
// Draws a complete arc for each node.
context.beginPath();
context.arc(d.x, d.y, d.radius, 0, 2 * Math.PI, true);
context.fill();
});
};
// now the zooming part
canvas.call( d3.zoom().scaleExtent([0.2, 10]).on("zoom", zoomed) )
function zoomed(d) {
context.save();
context.clearRect(0, 0, width, height);
context.translate(d3.event.transform.x, d3.event.transform.y);
context.scale(d3.event.transform.k, d3.event.transform.k);
// Draw the links ...
data.links.forEach(function(d) {
context.beginPath();
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
context.stroke();
});
// Draw the nodes ...
data.nodes.forEach(function(d, i) {
context.beginPath();
context.arc(d.x, d.y, d.radius, 0, 2 * Math.PI, true);
context.fill();
});
context.restore();
}
You tick function is not aware of any transforms created by the zoom. Best way to do this is to always apply a transform in the tick (which before any zooming is the identity transform). This allows you to reuse the tick method to do all drawing.
var force = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d, i) {
return d.id;
}))
.force("charge", d3.forceManyBody().strength(-5))
.force("center", d3.forceCenter(width / 2, height / 2));
force.nodes(data.nodes)
.on("tick", ticked);
force.force("link")
.links(data.links)
var trans = d3.zoomIdentity; //<-- identity transform
function ticked() {
context.save();
context.clearRect(0, 0, width, height);
context.translate(trans.x, trans.y); //<-- this always applies a transform
context.scale(trans.k, trans.k);
// Draw the links
data.links.forEach(function(d) {
// Draw a line from source to target.
context.beginPath();
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
context.stroke();
});
// Draw the nodes
data.nodes.forEach(function(d, i) {
// Draws a complete arc for each node.
context.beginPath();
context.arc(d.x, d.y, 5, 0, 2 * Math.PI, true);
context.fill();
});
context.restore();
};
// now the zooming part
canvas.call(d3.zoom().scaleExtent([0.2, 10]).on("zoom", zoomed))
function zoomed(d) {
trans = d3.event.transform; //<-- set to current transform
ticked(); //<-- use tick to redraw regardless of event
}
Full running code:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<canvas width="500" height="500"></canvas>
<script>
var width = 500,
height = 500
canvas = document.querySelector("canvas"),
context = canvas.getContext("2d");
canvas = d3.select(canvas);
var data = {
"nodes": [{
"id": "Myriel",
"group": 1
}, {
"id": "Napoleon",
"group": 1
}, {
"id": "Mlle.Baptistine",
"group": 1
}, {
"id": "Mme.Magloire",
"group": 1
}, {
"id": "CountessdeLo",
"group": 1
}, {
"id": "Geborand",
"group": 1
}, {
"id": "Champtercier",
"group": 1
}, {
"id": "Cravatte",
"group": 1
}, {
"id": "Count",
"group": 1
}, {
"id": "OldMan",
"group": 1
}, {
"id": "Labarre",
"group": 2
}, {
"id": "Valjean",
"group": 2
}, {
"id": "Marguerite",
"group": 3
}, {
"id": "Mme.deR",
"group": 2
}, {
"id": "Isabeau",
"group": 2
}, {
"id": "Gervais",
"group": 2
}, {
"id": "Tholomyes",
"group": 3
}, {
"id": "Listolier",
"group": 3
}, {
"id": "Fameuil",
"group": 3
}, {
"id": "Blacheville",
"group": 3
}, {
"id": "Favourite",
"group": 3
}, {
"id": "Dahlia",
"group": 3
}, {
"id": "Zephine",
"group": 3
}, {
"id": "Fantine",
"group": 3
}, {
"id": "Mme.Thenardier",
"group": 4
}, {
"id": "Thenardier",
"group": 4
}, {
"id": "Cosette",
"group": 5
}, {
"id": "Javert",
"group": 4
}, {
"id": "Fauchelevent",
"group": 0
}],
"links": [{
"source": "Napoleon",
"target": "Myriel",
"value": 1
}, {
"source": "Mlle.Baptistine",
"target": "Myriel",
"value": 8
}, {
"source": "Mme.Magloire",
"target": "Myriel",
"value": 10
}, {
"source": "Mme.Magloire",
"target": "Mlle.Baptistine",
"value": 6
}, {
"source": "CountessdeLo",
"target": "Myriel",
"value": 1
}, {
"source": "Geborand",
"target": "Myriel",
"value": 1
}, {
"source": "Champtercier",
"target": "Myriel",
"value": 1
}, {
"source": "Cravatte",
"target": "Myriel",
"value": 1
}, {
"source": "Count",
"target": "Myriel",
"value": 2
}, {
"source": "OldMan",
"target": "Myriel",
"value": 1
}, {
"source": "Valjean",
"target": "Labarre",
"value": 1
}, {
"source": "Valjean",
"target": "Mme.Magloire",
"value": 3
}, {
"source": "Valjean",
"target": "Mlle.Baptistine",
"value": 3
}, {
"source": "Valjean",
"target": "Myriel",
"value": 5
}, {
"source": "Marguerite",
"target": "Valjean",
"value": 1
}, {
"source": "Mme.deR",
"target": "Valjean",
"value": 1
}, {
"source": "Isabeau",
"target": "Valjean",
"value": 1
}, {
"source": "Gervais",
"target": "Valjean",
"value": 1
}, {
"source": "Listolier",
"target": "Tholomyes",
"value": 4
}, {
"source": "Fameuil",
"target": "Tholomyes",
"value": 4
}, {
"source": "Fameuil",
"target": "Listolier",
"value": 4
}, {
"source": "Blacheville",
"target": "Tholomyes",
"value": 4
}, {
"source": "Blacheville",
"target": "Listolier",
"value": 4
}, {
"source": "Blacheville",
"target": "Fameuil",
"value": 4
}, {
"source": "Favourite",
"target": "Tholomyes",
"value": 3
}, {
"source": "Favourite",
"target": "Listolier",
"value": 3
}, {
"source": "Favourite",
"target": "Fameuil",
"value": 3
}, {
"source": "Favourite",
"target": "Blacheville",
"value": 4
}, {
"source": "Dahlia",
"target": "Tholomyes",
"value": 3
}, {
"source": "Dahlia",
"target": "Listolier",
"value": 3
}, {
"source": "Dahlia",
"target": "Fameuil",
"value": 3
}, {
"source": "Dahlia",
"target": "Blacheville",
"value": 3
}, {
"source": "Dahlia",
"target": "Favourite",
"value": 5
}, {
"source": "Zephine",
"target": "Tholomyes",
"value": 3
}, {
"source": "Zephine",
"target": "Listolier",
"value": 3
}, {
"source": "Zephine",
"target": "Fameuil",
"value": 3
}, {
"source": "Zephine",
"target": "Blacheville",
"value": 3
}, {
"source": "Zephine",
"target": "Favourite",
"value": 4
}, {
"source": "Zephine",
"target": "Dahlia",
"value": 4
}, {
"source": "Fantine",
"target": "Tholomyes",
"value": 3
}, {
"source": "Fantine",
"target": "Listolier",
"value": 3
}, {
"source": "Fantine",
"target": "Fameuil",
"value": 3
}, {
"source": "Fantine",
"target": "Blacheville",
"value": 3
}, {
"source": "Fantine",
"target": "Favourite",
"value": 4
}, {
"source": "Fantine",
"target": "Dahlia",
"value": 4
}, {
"source": "Fantine",
"target": "Zephine",
"value": 4
}, {
"source": "Fantine",
"target": "Marguerite",
"value": 2
}]
}
var force = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d, i) {
return d.id;
}))
.force("charge", d3.forceManyBody().strength(-5))
.force("center", d3.forceCenter(width / 2, height / 2));
force.nodes(data.nodes)
.on("tick", ticked);
force.force("link")
.links(data.links)
var trans = d3.zoomIdentity;
function ticked() {
context.save();
context.clearRect(0, 0, width, height);
context.translate(trans.x, trans.y);
context.scale(trans.k, trans.k);
// Draw the links
data.links.forEach(function(d) {
// Draw a line from source to target.
context.beginPath();
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
context.stroke();
});
// Draw the nodes
data.nodes.forEach(function(d, i) {
// Draws a complete arc for each node.
context.beginPath();
context.arc(d.x, d.y, 5, 0, 2 * Math.PI, true);
context.fill();
});
context.restore();
};
// now the zooming part
canvas.call(d3.zoom().scaleExtent([0.2, 10]).on("zoom", zoomed))
function zoomed(d) {
trans = d3.event.transform;
ticked();
}
</script>
</body>
</html>

D3.js append circle to the GROUP based on the JSON value

Here I'm getting json data as
{
"nodes": [{
"name": "Tomcat",
"comp_type": "tomcat_155:7077",
"id": "tomcat_155:7077",
"pie": true,
"url": "../images/component_icons/1424962275_f-server_128.svg",
"group": 1,
"fixed": true
}, {
"name": "lraj_155_Nov_3(MS SQL)",
"comp_type": "192.168.11.212:1433_Ba",
"id": "lraj_155_Nov_3(MS SQL)",
"pie": false,
"url": "../images/component_icons/1424962160_19.svg",
"group": 2,
"fixed": true
}, {
"name": "rajesh_window",
"comp_type": "192.234.11.116:1433_window",
"id": "rajesh_window",
"pie": false,
"url": "../images/component_icons/1424882359_database.svg",
"group": 3,
"fixed": true
}, {
"name": "shanker_ux_win_3(PS)",
"comp_type": "192.168.11.116:1433_window",
"pie": true,
"id": "shanker_ux_win_3(PS)",
"url": "../images/component_icons/1424882359_database.svg",
"group": 4,
"fixed": true
}],
"links": [{
"source": 1,
"target": 0,
"description": "windows flows",
"value": 1
}, {
"source": 2,
"description": "SQLMS(36.67%)",
"target": 0,
"value": 8
}, {
"source": 1,
"description": "",
"target": 0,
"value": 8
}, {
"source": 3,
"target": 2,
"description": "ctrix 6765",
"value": 1
}]
}
Each node contains PIE which is true or false.
So when i render d3 force layout, If PIE is true a circle have to append to group else no circle have to append.
Please help me out. Thanks in advance.
You can do this using a filter. For example, assuming that you append a g element for each datum and circles only for those for which pie == true:
d3.selectAll("g").data(json.nodes)
.enter().append("g")
.filter(function(d) { return d.pie; })
.append("circle");

Categories