d3 js nodes are out of the window - javascript

using d3.js to visualize 50 nodes and their links, some of the nodes doesn't appear within the window (they are out of screen) - unless I drag them in:
This is my code, any suggestion how to make all the nodes appear on load? :
var width = window.innerWidth;
var height = window.innerHeight - 100;
var svg = d3.select("#sharedActivityGraph")
.append("svg")
.attr("width", width)
.attr("height", height);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink())
.force("charge", d3.forceManyBody().strength(-600))
.force("center", d3.forceCenter(width / 2, height / 2));
var links = svg.selectAll("foo")
.data(gSharedActivityGraphEdges)
.enter()
.append("line")
.style("stroke", "#ccc")
.style("stroke-width", function (e) { return e.width });
var color = d3.scaleOrdinal(d3.schemeCategory20);
var node = svg.selectAll("foo")
.data(gSharedActivityGraphNodes)
.enter()
.append("g")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.on('mouseover', function (d) {
console.log(d);
SharedActivityShowInfo(d);
node.filter(function (d1) { return (d !== d1
&& d1.adjacents.indexOf(d.id) == -1);
}).select("image").style("opacity", 0.2);
node.filter(function (d1) { return (d == d1
|| d1.adjacents.indexOf(d.id) !== -1);
}).select("image").style("opacity", 1);
})
.on('mouseout', function () {
SharedActivityHideInfo();
node.select("image").style("opacity", 1);
});
var nodeCircle = node.append("circle")
.attr("r", function (d) { return 0.5 * Math.max(d.width, d.height) })
.attr("stroke", "gray")
.attr("stroke-width", "2px")
.attr("fill", "white");
var nodeImage = node.append("image")
.attr("xlink:href", function (d) { return d.image })
.attr("height", function (d) { return d.height + "" })
.attr("width", function (d) { return d.width + "" })
.attr("x", function (d) {return -0.5 * d.width })
.attr("y", function (d) {return -0.5 * d.height })
.attr("clip-path", function (d) { return "circle(" + (0.48 * Math.max(d.width, d.height)) + "px)"});
simulation.nodes(gSharedActivityGraphNodes);
simulation
.force("link")
.links(gSharedActivityGraphEdges);
simulation.on("tick", function() {
links.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
})
node.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"});
});
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;
}

Ended up with adding the following lines:
node.attr("cx", function(d) { return d.x = Math.max(d.width, Math.min(width - d.width, d.x)); })
.attr("cy", function(d) { return d.y = Math.max(d.height, Math.min(height - heightDelta - d.height, d.y)); });
below the line:
node.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"});
#TomShanley thanks for the ref!

Related

D3.js: How to highlight connected edges and nodes in a Force-Directed Graph?

I'm trying to build a Force-Directed Graph with Link Highlighting.
Initially the graph will look like the following:
But after hovering on a particular node I want it to become like the following (only connected nodes and edges will be highlighted):
I've tried the following code. But the highlighting part is not working.
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
d3.json("miserables.json", function (error, graph) {
if (error) throw error;
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter()
.append("line")
.attr("stroke-width", function (d) { return Math.sqrt(d.value); });
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("g")
.data(graph.nodes)
.enter()
.append("g")
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.call(
d3
.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
);
var circles = node.append("circle")
.attr("r", 10)
.attr("fill", function (d) { return color(d.group); });
var lables = node.append("text")
.text(function (d) {
return d.id;
})
.attr("x", 0)
.attr("dy", ".35em")
.attr("text-anchor", "middle");
node.append("title")
.text(function (d) { return d.id; });
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
function ticked() {
link
.attr("x1", function (d) { return d.source.x; })
.attr("y1", function (d) { return d.source.y; })
.attr("x2", function (d) { return d.target.x; })
.attr("y2", function (d) { return d.target.y; });
node
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
})
}
});
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;
}
graph.links.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
linkedByIndex[d.target.index + "," + d.source.index] = 1;
});
function neighboring(a, b) {
return a.index == b.index || linkedByIndex[a.index + "," + b.index];
}
function mouseover(d) {
d3.selectAll("link").transition().duration(500)
.style("opacity", function (o) {
return o.source === d || o.target === d ? 1 : 0;
});
d3.selectAll("node").transition().duration(500)
.style("opacity", function (o) {
return neighboring(d, o) ? 1 : 0;
});
}
function mouseout() {
d3.selectAll("link").transition().duration(500)
.style("opacity", 1);
d3.selectAll("node").transition().duration(500)
.style("opacity", 1);
}
The full code can be found at https://plnkr.co/edit/BA9OfjVQjOwyHDkh
Could you please help me find the issue here and make it work?

Restrict nodes movements in boundary for D3 directed graph

I am trying to restrict the node movement within the specified boundary. But I m not succeeded yet. I know that some changes are required in the ticked method, I am confused. Beginner with D3 library.
I have integrated the below Directed graph in my angular code.
http://bl.ocks.org/fancellu/2c782394602a93921faff74e594d1bb1
html tag:
<svg width="960" height="600"></svg>
Javascript code:
var colors = d3.scaleOrdinal(d3.schemeCategory10);
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
node,
link;
svg.append('defs').append('marker')
.attrs({
'id': 'arrowhead',
'viewBox': '-0 -5 10 10',
'refX': 13,
'refY': 0,
'orient': 'auto',
'markerWidth': 13,
'markerHeight': 13,
'xoverflow': 'visible'
})
.append('svg:path')
.attr('d', 'M 0,-5 L 10 ,0 L 0,5')
.attr('fill', '#999')
.style('stroke', 'none');
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id; }).distance(100).strength(1))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
d3.json("graph.json", function (error, graph) {
if (error) throw error;
update(graph.links, graph.nodes);
})
function update(links, nodes) {
link = svg.selectAll(".link")
.data(links)
.enter()
.append("line")
.attr("class", "link")
.attr('marker-end', 'url(#arrowhead)')
link.append("title")
.text(function (d) { return d.type; });
edgepaths = svg.selectAll(".edgepath")
.data(links)
.enter()
.append('path')
.attrs({
'class': 'edgepath',
'fill-opacity': 0,
'stroke-opacity': 0,
'id': function (d, i) { return 'edgepath' + i }
})
.style("pointer-events", "none");
edgelabels = svg.selectAll(".edgelabel")
.data(links)
.enter()
.append('text')
.style("pointer-events", "none")
.attrs({
'class': 'edgelabel',
'id': function (d, i) { return 'edgelabel' + i },
'font-size': 10,
'fill': '#aaa'
});
edgelabels.append('textPath')
.attr('xlink:href', function (d, i) { return '#edgepath' + i })
.style("text-anchor", "middle")
.style("pointer-events", "none")
.attr("startOffset", "50%")
.text(function (d) { return d.type });
node = svg.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
//.on("end", dragended)
);
node.append("circle")
.attr("r", 5)
.style("fill", function (d, i) { return colors(i); })
node.append("title")
.text(function (d) { return d.id; });
node.append("text")
.attr("dy", -3)
.text(function (d) { return d.name + ":" + d.label; });
simulation
.nodes(nodes)
.on("tick", ticked);
simulation.force("link")
.links(links);
}
function ticked() {
link
.attr("x1", function (d) { return d.source.x; })
.attr("y1", function (d) { return d.source.y; })
.attr("x2", function (d) { return d.target.x; })
.attr("y2", function (d) { return d.target.y; });
node
.attr("transform", function (d) { return "translate(" + d.x + ", " + d.y + ")"; });
edgepaths.attr('d', function (d) {
return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
});
edgelabels.attr('transform', function (d) {
if (d.target.x < d.source.x) {
var bbox = this.getBBox();
rx = bbox.x + bbox.width / 2;
ry = bbox.y + bbox.height / 2;
return 'rotate(180 ' + rx + ' ' + ry + ')';
}
else {
return 'rotate(0)';
}
});
}
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;
}
Just add a function to constrain the allowed x/y values to your bounds:
function checkBounds(d){
if (d.x < 0) d.x = 0;
if (d.x > width) d.x = width;
if (d.y < 0) d.y = 0;
if (d.y > width) d.y = height;
}
Then call it in the tick method:
link
.attr("x1", function (d) {
checkBounds(d.source);
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
checkBounds(d.target);
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
node
.attr("transform", function (d) {
checkBounds(d);
return "translate(" + d.x + ", " + d.y + ")";
});
Running example:
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
.node {}
.link { stroke: #999; stroke-opacity: .6; stroke-width: 1px; }
svg {border: 1px solid black}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js" type="text/javascript"></script>
<script src="https://d3js.org/d3-selection-multi.v1.js"></script>
<svg width="400" height="400"></svg>
<script>
var colors = d3.scaleOrdinal(d3.schemeCategory10);
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
node,
link;
svg.append('defs').append('marker')
.attrs({
'id': 'arrowhead',
'viewBox': '-0 -5 10 10',
'refX': 13,
'refY': 0,
'orient': 'auto',
'markerWidth': 13,
'markerHeight': 13,
'xoverflow': 'visible'
})
.append('svg:path')
.attr('d', 'M 0,-5 L 10 ,0 L 0,5')
.attr('fill', '#999')
.style('stroke', 'none');
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id; }).distance(100).strength(1))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
var graph = {
"nodes": [
{
"name": "Peter",
"label": "Person",
"id": 1
},
{
"name": "Michael",
"label": "Person",
"id": 2
},
{
"name": "Neo4j",
"label": "Database",
"id": 3
},
{
"name": "Graph Database",
"label": "Database",
"id": 4
}
],
"links": [
{
"source": 1,
"target": 2,
"type": "KNOWS",
"since": 2010
},
{
"source": 1,
"target": 3,
"type": "FOUNDED"
},
{
"source": 2,
"target": 3,
"type": "WORKS_ON"
},
{
"source": 3,
"target": 4,
"type": "IS_A"
}
]
};
update(graph.links, graph.nodes);
function update(links, nodes) {
link = svg.selectAll(".link")
.data(links)
.enter()
.append("line")
.attr("class", "link")
.attr('marker-end', 'url(#arrowhead)')
link.append("title")
.text(function (d) { return d.type; });
edgepaths = svg.selectAll(".edgepath")
.data(links)
.enter()
.append('path')
.attrs({
'class': 'edgepath',
'fill-opacity': 0,
'stroke-opacity': 0,
'id': function (d, i) { return 'edgepath' + i }
})
.style("pointer-events", "none");
edgelabels = svg.selectAll(".edgelabel")
.data(links)
.enter()
.append('text')
.style("pointer-events", "none")
.attrs({
'class': 'edgelabel',
'id': function (d, i) { return 'edgelabel' + i },
'font-size': 10,
'fill': '#aaa'
});
edgelabels.append('textPath')
.attr('xlink:href', function (d, i) { return '#edgepath' + i })
.style("text-anchor", "middle")
.style("pointer-events", "none")
.attr("startOffset", "50%")
.text(function (d) { return d.type });
node = svg.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
//.on("end", dragended)
);
node.append("circle")
.attr("r", 5)
.style("fill", function (d, i) { return colors(i); })
node.append("title")
.text(function (d) { return d.id; });
node.append("text")
.attr("dy", -3)
.text(function (d) { return d.name + ":" + d.label; });
simulation.nodes(nodes)
.on("tick", ticked);
simulation.force("link")
.links(links);
}
function ticked() {
link
.attr("x1", function (d) {
checkBounds(d.source);
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
checkBounds(d.target);
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
node
.attr("transform", function (d) {
checkBounds(d);
return "translate(" + d.x + ", " + d.y + ")";
});
edgepaths.attr('d', function (d) {
return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
});
edgelabels.attr('transform', function (d) {
if (d.target.x < d.source.x) {
var bbox = this.getBBox();
rx = bbox.x + bbox.width / 2;
ry = bbox.y + bbox.height / 2;
return 'rotate(180 ' + rx + ' ' + ry + ')';
}
else {
return 'rotate(0)';
}
});
}
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 checkBounds(d){
if (d.x < 0) d.x = 0;
if (d.x > width) d.x = width;
if (d.y < 0) d.y = 0;
if (d.y > width) d.y = height;
}
</script>
</body>
</html>

d3.js fixed x,y coords for some nodes in force

I'm new with d3.js.
I have a disjointed network, it means, in a same file I have many small network like:
a a
a b
a c
b a
b b
b c
c a
c b
c c
e e
e f
e g
f e
f f
f g
g e
g f
g g
In this example, has two disjointed networks, one has [a,b,c] nodes other[e,f,g] nodes.
I may tag only one node per network to be my "hub" (not a hub itself necessarily, hubs are highly connected) or "chosen" just inserting 1 if it is chosen or 0 if it is not.
Now the problem is:
"In a force directed graph how do I keep fixed the hubs?".
Actually, what I really would like is, distribute in the space all networks, left-to-right and top-to-bottom, from largest to smallest (in number of nodes).
What did I think. Take only the hubs and assign the x and y coords and if (d.choose == 1){ //returns x,y}else{ //free coords}.
The problem isn't create x and y columns, but the d3.js code itself to keep some choords frozen.
Follow my code
<!DOCTYPE html>
<meta charset="utf-8">
<!-- width="2480" height="1720 -->
<svg width="2600" height="1020"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script type="text/javascript">
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = 6;
var simulation = d3.forceSimulation()
// One thing to consider is the overall strength, negative spaced, positive agglomerates
.force("charge", d3.forceManyBody().strength( function(d){
if ( d.choose == 1 ) { return -2;}
if ( d.choose == 0 ) { return -0.2; } } ) )
// Another issue is the distance + distance more distant the dots,
// d is the jason file, here it is accessing the d.id and d.line
.force("link", d3.forceLink().iterations(10).id(function(d) {
return d.id; }
).distance(function (d) {if (d.line == "none"){
return 15;}
else {
return 15;
}
}))
// center graph
.force("center", d3.forceCenter(width / 2, height / 2));
// load json file (?)
d3.json("genomes_net.json", function(error, graph) {
if (error) throw error;
var canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height);
// draw line for each pair
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
// line color
.attr("stroke", function (d) {return d.colorsamp;})
// draw lines (% of total, or gradient?)
.attr("stroke-width", 1);
// draw circles for each node
var node = svg.append("g")
.attr("class","nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", (d) => {
if (d.choose == 0 ) {return 8;}
if (d.choose == 1) {return 16;}
})
//.style("fill", "#FF69B4") //function(d) { return d.colorsamp; })
.attr("fill", function(d) { return d.colorsamp ; })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("title")
.text(function(d) { return (d.name+ "\n" + d.lineage + " (" + d.genera +")"); });
var text = svg.append("g")
.attr("class","labels")
.selectAll("text")
.data(graph.nodes)
.enter().append("text")
.text(function (d) {
if (d.direto == "yes"){
return d.id;
}
})
.attr("font-size", "8px")
.attr("font-family", "sans-serif")
.attr("dx", 15)
.attr("dy", ".31em")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
function ticked() {
link
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x = Math.max(radius, Math.min(width - radius, d.x)); })
.attr("cy", function(d) { return d.y = Math.max(radius, Math.min(height - radius, d.y)); });
text
.attr("dx", function (d) {return d.x -20; })
.attr("dy", function (d) {return d.y + 15; })
}
});
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;
}
// Important notes:
// Understanding forces: https://bl.ocks.org/steveharoz/8c3e2524079a8c440df60c1ab72b5d03
//
</script>

Adding Multiple shaped nodes to a force directed network diagram in d3v4

I am Trying to add rectangle and circle nodes in d3v4, the graph works although the nodes are all grouped together in one corner and their positions are not being updated. I can't work out what i'm doing wrong?
I have tried looking for examples online but cant seem to find any that are using d3v4 specifically
<!DOCTYPE html>
<meta charset="UTF-8">
<style>
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// Properties
var width = 800;
var height = 600;
var nominal_stroke = 4;
// Simulation
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody().strength(-400))
.force("center", d3.forceCenter(width / 2, height / 2));
// Create SVG window
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g");
svg.style("cursor", "move");
// Load JSON data
d3.json("./network.json", function(error, graph) {
console.log(graph);
if (error) throw error;
// Draw links
var link = g.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", nominal_stroke)
.style("stroke", "#999")
.style("stroke-opacity", 0.6);
// Draw nodes
var node = g.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
// Setup node properties
var circle = node.append("path")
.attr("d", d3.symbol()
.type(function (d) {
if
(d.shape == "rect") {
return d3.symbolSquare;
} else if
(d.shape == "circle") {
return d3.symbolCircle;
}
})
.size(400))
.style("stroke", "#999")
.style("stroke-opacity", 0.6)
.style("fill", function (d) {
return "blue"
});
// Add titles
node.append("title")
.text(function (d) {return d.id;});
// Start Simulation
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
// Refresh page
function ticked() {
link
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
// Zoom handler
svg.call(d3.zoom()
.scaleExtent([1 / 2, 8])
.on("zoom", zoomed));
function zoomed() {
node.attr("transform", d3.event.transform);
link.attr("transform", d3.event.transform);
}
});
// Functions
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 = d.x;
d.fy = d.y;
}
function openLink() {
return function (d) {
var url = "";
if (d.url != "") {
url = d.url
}
window.open(url)
}
}
</script>
</body>
You should not use cx and cy in the ticked function, since you're dealing with <path>s, not <circle>s. You should use translate instead.
Therefore, it has to be:
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
Here is your code with that change (I'm using fake data here):
var width = 600;
var height = 400;
var nominal_stroke = 4;
// Simulation
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
return d.id;
}))
.force("charge", d3.forceManyBody().strength(-400))
.force("center", d3.forceCenter(width / 2, height / 2));
// Create SVG window
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g");
svg.style("cursor", "move");
graph = {
nodes: [{
id: 1,
shape: "rect"
}, {
id: 2,
shape: "circle"
}, {
id: 3,
shape: "rect"
}, {
id: 4,
shape: "rect"
}, {
id: 5,
shape: "circle"
}, {
id: 6,
shape: "circle"
}, {
id: 7,
shape: "circle"
}],
links: [{
source: 1,
target: 2
}, {
source: 1,
target: 3
}, {
source: 1,
target: 4
}, {
source: 1,
target: 5
}, {
source: 3,
target: 6
}, {
source: 3,
target: 7
}]
}
// Draw links
var link = g.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", nominal_stroke)
.style("stroke", "#999")
.style("stroke-opacity", 0.6);
// Draw nodes
var node = g.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
// Setup node properties
var circle = node.append("path")
.attr("d", d3.symbol()
.type(function(d) {
if (d.shape == "rect") {
return d3.symbolSquare;
} else if (d.shape == "circle") {
return d3.symbolCircle;
}
})
.size(400))
.style("stroke", "#999")
.style("stroke-opacity", 0.6)
.style("fill", function(d) {
return "blue"
});
// Add titles
node.append("title")
.text(function(d) {
return d.id;
});
// Start Simulation
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
// Refresh page
function ticked() {
link
.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
// Zoom handler
svg.call(d3.zoom()
.scaleExtent([1 / 2, 8])
.on("zoom", zoomed));
function zoomed() {
g.attr("transform", d3.event.transform);
}
// Functions
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 = d.x;
d.fy = d.y;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
PS: Your zoom function is not working, which is a different problem. I also fixed it.

Network line with arrow in US map

I am trying to give an arrow sign on a US network map to indicate the direction of the link.I have followed the http://bl.ocks.org/d3noob/5141278 link for this and many other but can't able to achieve the same.
I have created a fiddler for this.Kindly have a look on this and please provide some solution to achieve this.
https://jsfiddle.net/AmitSah/bp6p3p92/
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = 10;
/*svg.call(d3.zoom().on("zoom", function () {
svg.attr("transform", d3.event.transform);
}));*/
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.node_id; }).strength(1) )
//.force("charge", d3.forceManyBody())
.force("collide", d3.forceCollide(radius + 1).iterations(4))
.force("center", d3.forceCenter(width / 2, height / 2));
// projection definition
var projection = d3.geoAlbers()
.scale(1280)
.translate([width / 2, height / 2]);
// path generator definition for major cities, including point radius
var path = d3.geoPath()
.projection(projection)
.pointRadius(2);
// draws the states
d3.json("https://raw.githubusercontent.com/LogicalInsightscg/Web-Mobile-Dashboard/master/us_new.json", function(error, us_new) {
if (error) return console.error(error);
svg.selectAll(".states")
.data(topojson.feature(us_new, us_new.objects.states).features)
.enter().append("path")
.attr("class", function(d) { return "states " + d.id; })
.attr("d", path);
// adding state boundaries
svg.append("path")
.datum(topojson.mesh(us_new, us_new.objects.states))
.attr("d", path)
.attr("class", "state-boundary");
d3.json("https://raw.githubusercontent.com/LogicalInsightscg/Web-Mobile-Dashboard/master/nodesandlinks.json", function(error, graph) {
if (error) throw error;
// build the arrow.
svg.append("svg:defs").selectAll("marker")
.data(["end"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("svg:line")
.attr("d", "M0,-5L10,0L0,5");
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) { return Math.sqrt(d.referrals); })
.attr("marker-end", "url(#end)");
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 5)
.attr("fill", function(d) { return color(d.group); })
//.attr("fixed", true)
.attr("cx", function(d) {
return projection([d.longitude, d.latitude])[0];
})
.attr("cy", function(d) {
return projection([d.longitude, d.latitude])[1];
})
/* .call(d3.drag()
.on("end", dragended)); */
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
node.attr('fx', function(d) { return projection([d.longitude, d.latitude])[0]; })
.attr('fy', function(d) { return projection([d.longitude, d.latitude])[1]; });
link.attr('x1', function(d) { return projection([d.source.longitude, d.source.latitude])[0]; })
.attr('y1', function(d) { return projection([d.source.longitude, d.source.latitude])[1]; })
.attr('x2', function(d) { return projection([d.target.longitude, d.target.latitude])[0]; })
.attr('y2', function(d) { return projection([d.target.longitude, d.target.latitude])[1]; });
node.append("title")
.text(function(d) { return d.node_name; });
function ticked() {
link
.attr("distance", 10)
// .attr("x1", function(d) { return d.source.x; })
// .attr("y1", function(d) { return d.source.y; })
.attr('x1', function(d) { return projection([d.source.longitude, d.source.latitude])[0]; })
.attr('y1', function(d) { return projection([d.source.longitude, d.source.latitude])[1]; })
.attr('x2', function(d) { return projection([d.target.longitude, d.target.latitude])[0]; })
.attr('y2', function(d) { return projection([d.target.longitude, d.target.latitude])[1]; });
node.attr('cx', function(d) {if (d.group > 0) { return projection([d.longitude, d.latitude])[0]; }
else { return d.x; }})
.attr('cy', function(d) {if (d.group > 0) { return projection([d.longitude, d.latitude])[1]; }
else { return d.y; }});
}
/* function ticked() {
link.attr('x1', function(d) { return projection([d.source.longitude, d.source.latitude])[0]; })
.attr('y1', function(d) { return projection([d.source.longitude, d.source.latitude])[1]; })
.attr('x2', function(d) { return projection([d.target.longitude, d.target.latitude])[0]; })
.attr('y2', function(d) { return projection([d.target.longitude, d.target.latitude])[1]; });
node.attr('r', width/100)
.attr('cx', function(d) { return projection([d.longitude, d.latitude])[0]; })
.attr('cy', function(d) { return projection([d.longitude, d.latitude])[1]; });
} */
});
});
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;
}
Thanks in advance.
Amit Sah

Categories

Resources