I have a json file of nodes and then the links specified with source and target. |
|
When I load the above data from within the file, the links show up. When I do this dynamically, no links are visible.
Why dynamically? The keyword is searched using ElasticSearch on MongoDB, there is a json created with nodes, links (sources and targets) and that is referenced in the js for creating the D3 network visualization.
I need to do this dynamically since the search use cases would be limitless and filtering and storing so many versions of json files would be sub-optimal.
Code for creating the arrays is below
var arr = new Object;
arr["nodes"] = nodearray;
arr["links"] = linkarray;
Script for creating D3 network visualization is below
d3.json('d3datap.json', function(error, graph) {
// console.log(JSON.stringify(arr));
var graph = JSON.parse(JSON.stringify(arr));
console.log(graph.nodes);
console.log(graph.links);
const width = 1200;
const height = 500;
const mouseOverFunction = function (d) {
const circle = d3.select(this);
node.append("text")
.attr("x", 12)
.attr("dy", ".35em")
.text(function(d) { return d.Party; });
node
.transition(500)
.style('opacity', o => {
const isConnectedValue = isConnected(o, d);
if (isConnectedValue) {
return 1.0;
}
return 0.2
})
.style('fill', (o) => {
let fillColor;
if (isConnectedAsTarget(o, d) && isConnectedAsSource(o, d)) {
fillColor = 'green';
} else if (isConnectedAsSource(o, d)) {
fillColor = 'red';
} else if (isConnectedAsTarget(o, d)) {
fillColor = 'blue';
} else if (isEqual(o, d)) {
fillColor = 'hotpink';
} else {
fillColor = '#000';
}
return fillColor;
});
link
.transition(500)
.style('stroke-opacity', o => (o.source === d || o.target === d ? 1 : 0.2))
.transition(500)
.attr('marker-end', o => (o.source === d || o.target === d ? 'url(#arrowhead)' : 'url()'));
circle
.transition(500)
.attr('r', () => 1.4 * nodeRadius(d));
};
const mouseOutFunction = function () {
const circle = d3.select(this);
svg.selectAll("text").remove();
node
.transition(500);
link
.transition(500);
circle
.transition(500)
.attr('r', nodeRadius);
};
const nodes = graph.nodes;
const links = graph.links;
const simulation = d3.forceSimulation()
.force('link', d3.forceLink().id(d => d.id))
.force('charge', d3.forceManyBody())
.force('center', d3.forceCenter(width / 2, height / 2));
// const simulation = d3.forceSimulation()
// .nodes(nodes)
// .links(links)
// .charge(-3000)
// .friction(0.6)
// .gravity(0.6)
// .size([width, height])
// .start();
const svg = d3.select('#vis').append('svg')
.attr('width', width)
.attr('height', height)
.classed("svg-content", true);
let link = svg.selectAll('line')
.data(graph.links)
.enter().append('line');
let node = svg.selectAll('.node')
.data(graph.nodes)
.enter().append("g")
.attr('class', 'node');
node.append("svg:a")
.append('circle')
.attr("r", nodeRadius)
.on('mouseover', mouseOverFunction)
.on('mouseout', mouseOutFunction)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("dblclick",function(d){
window.open(d.url, '_blank')});
svg
.append('marker')
.attr('id', 'arrowhead')
.attr('refX', 6 + 7) // Controls the shift of the arrow head along the path
.attr('refY', 2)
.attr('markerWidth', 6)
.attr('markerHeight', 4)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 0,0 V 4 L6,2 Z');
link
.attr('marker-end', 'url()');
simulation
.nodes(graph.nodes)
.on('tick', ticked);
simulation.force('link')
.links(graph.links);
let linkedByIndex = {};
links.forEach((d) => {
linkedByIndex[`${d.source.index},${d.target.index}`] = true;
});
function isConnected(a, b) {
return isConnectedAsTarget(a, b) || isConnectedAsSource(a, b) || a.index === b.index;
}
function isConnectedAsSource(a, b) {
return linkedByIndex[`${a.index},${b.index}`];
}
function isConnectedAsTarget(a, b) {
return linkedByIndex[`${b.index},${a.index}`];
}
function isEqual(a, b) {
return a.index === b.index;
}
function ticked() {
link
.attr('x1', d => d.source.x)
.attr('y1', d => d.source.y)
.attr('x2', d => d.target.x)
.attr('y2', d => d.target.y);
node
.attr('transform', d => `translate(${d.x},${d.y})`);
}
function nodeRadius(d) { return Math.pow(40.0 * d.size, 1 / 3); }
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
});
CSS is below
.node circle {
stroke: white;
stroke-width: 1.5px;
opacity: 1.0;
}
line {
stroke: black;
stroke-width: 1.5px;
stroke-opacity: 1.0;
}
I can see the data for the json in the console but the links are not visible/ not there.
I searched all the questions on dynamic loading of json into D3 but couldn't find a solution to my problem.
If anyone can point out what is the problem with this, I'd appreciate it a lot.