I am using D3's forced layout to display a graph. Now, I require that the nodes change their positions when any node is clicked.
I looked up other related StackOverflow questions but that didn't help me.
The code for render is as follows :
var render = function(graph){
/* var loading = svg.append("text")
.attr("x", width / 2)
.attr("y", height / 2)
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text("Simulating. One moment please…");*/
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links);
//Enter phase for links.
link.enter().append("line");
//Update phase for links
link
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll(".node")
.data(graph.nodes,function(d){return d.name;});
//Enter phase for nodes
var node_g = node.enter()
.append("g")
.attr("class","node")
.on("dblclick",nodeClick)
.call(force.drag);
//Update phase for nodes
node_g.append("text")
.attr("class","NodeLabel")
.text(function(d){
return d.name;
});
var nodeCirlce = node_g.append("circle");
nodeCirlce
.attr("r", 5)
.style("fill", function(d) { return color(d.group); })
node_g.append("title")
.text(function(d) { return d.name; });
force.on("tick", function() {
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_g.attr("transform",function(d){
return "translate("+ d.x+","+ d.y+")";
});
//TODO : Add attr change for node text as well.
});
And the code for the node click handler looks like this :
var nodeClick = function(d,i){
//Translate the graph to center around the selected node.
var x_trans = x_cent - d.x;
var y_trans = y_cent - d.y;
var nodes = oldGraph.nodes;
for(var i=0;i<nodes.length;i++){
var node = nodes[i];
node.x = node.x + 1000;
node.y = node.y + 1000;
node.fixed = true;
}
//oldGraph.nodes = updateNodes(nodes,oldGraph.links);
render(oldGraph);
//setTimeout(function(){layout("json/HUMAN-1g.json");},000);
};
However, the node positions don't get updated.
After changing the data, you need to run the code that updates the positions in the DOM. This is exactly what you have in the tick event handler function:
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_g.attr("transform",function(d){
return "translate("+ d.x+","+ d.y+")";
I recommend pulling this out into a separate function and then setting it as the tick handler function and calling it from your nodeClick() function. To be clear, you don't need to call render() from the nodeClick() function.
Related
Hello dear Stackoverflow community,
I've come far with my force-directed graph and am really enjoying the project. Yet I keep failing when it comes to entering text elements on the nodes. Please find two images attached, one with my current nodes and one with the labels I'd like to have.
Source: https://bl.ocks.org/mbostock/1093130
Below you'll find the code snippet I'd like to include:
nodeEnter.append("text")
.attr("dy", ".35em")
.text(function(d) { return d.name; });
I've added a //text comment in the area where I have tested the code above.
I've tried a group element in svg.selectAll & .append("circle"). This however broke the visual. What am I missing?
Thank you for your support and happy weekend!
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="https://kit.fontawesome.com/01fcb12790.js">//fontawesome for searchbar
</script>
<script>
var width = 960,
height = 960,
root;
// d3 overview: https://bost.ocks.org/mike/d3/workshop/#121
var force = d3.layout.force()
.size([width, height])
.linkDistance(100) //How far apart the nodes are
.charge(-50) //how far are the group nodes from each other
.gravity(0.001) //how far away are the nodes from each other
.on("tick", tick);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var link = svg.selectAll(".link"),
node = svg.selectAll(".node");
d3.json("readme.json", function(error, json) {
if (error) throw error;
root = json;
update();
});
function update() {
var nodes = flatten(root),
links = d3.layout.tree().links(nodes);
// Restart the force layout.
force
.nodes(nodes)
.links(links)
.start();
// Update the links…
link = link.data(links, function(d) { return d.target.id; });
// Exit any old links.
link.exit().remove();
// Enter any new links.
link.enter().insert("line", ".node")
.attr("class", "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; });
// Update the nodes…
node = node.data(nodes, function(d) { return d.id; }).style("fill", color);
// Exit any old nodes.
node.exit().remove();
// Enter any new nodes.
node.enter().append("circle")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return Math.sqrt(d.size) / 10 || 10.5; })
.style("fill", color)
.on("click", click)
.call(force.drag);
}
//text
//creating the tick function from the force variable
//the "e" paramater can be used for positioning
function tick() {
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; });
}
// Color leaf nodes orange, and packages white or blue.
function color(d) {
return d._children ? "#E83E1D" : d.children ? "#c6dbef" : "#fd8d3c";
}
// Toggle children on click.
function click(d) {
if (!d3.event.defaultPrevented) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update();
}
}
// Returns a list of all nodes under the root.
function flatten(root) {
var nodes = [], i = 0;
function recurse(node) {
if (node.children) node.children.forEach(recurse);
if (!node.id) node.id = ++i;
nodes.push(node);
}
recurse(root);
return nodes;
}
// Tag animation begin.
//Tag animation end
</script>
The following code displays a graph based on http://my-neo4j-movies-app.herokuapp.com/
Now I want to make the individual nodes react to click events, similar to http://bl.ocks.org/d3noob/5141528, and increase thier size with help of the click() function, but the attribute doesn’t change. If I remove the two lines
.append("circle")
.attr("r", 5)
in the variable definition of 'node' the code breaks.
<script type="text/javascript">
var width = screen.width, height = screen.height;
var force = d3.layout.force().charge(-200).linkDistance(30)
.size([width, height]);
var svg = d3.select("#graph").append("svg")
.attr("width", "100%").attr("height", "100%")
.attr("pointer-events", "all");
d3.json("/graph", function(error, graph) {
if (error) return;
force.nodes(graph.nodes).links(graph.links).start();
var link = svg.selectAll(".link")
.data(graph.links).enter()
.append("line").attr("class", "link");
var node = svg.selectAll(".node")
.data(graph.nodes).enter()
.append("circle")
.attr("r", 5)
.attr("class", function (d) { return "node "+d.label })
.on("click", click)
.call(force.drag);
// add the nodes
node.append("circle").attr("r", 5);
// html title attribute
node.append("title").text(function (d) { return d.title; });
// force feed algo ticks
force.on("tick", function() {
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; });
});
// action to take on mouse click
function click() {
console.log(d3.select(this));
d3.select(this).select(".circle")
.attr("r", 26)
.style("fill", "lightsteelblue");
}
});
In your second example the "node" is a g element with circle and text like this:
<g>
<circle />
<text>some text</text>
</g>
So this code in the click:
d3.select(this).select(".circle")
is saying select the g and grab the first thing with class circle (the circle).
Your code though, the node is just a circle. So, in the click, just do this:
d3.select(this)
.attr("r", 26)
.style("fill", "lightsteelblue");
This is my first question here so bear with me...
I've made a Force-Directed graph using the d3 inbuilt force layout. This works find on the initial load, but when I try to reload with new data (using onchange with a select element), all the links disappear from the force layout.
The data seems to be updating correctly, in that the correct links are still present in the data, I just can't understand why the links aren't coming through as lines in the svg element.
I've made a js fiddle to show how I'm doing it:
https://jsfiddle.net/onlyskin/f5a4uxje/
(run and then select either 'size' or 'colour' from the dropdown - the expected behaviour is for the appropriate nodes and links to disappear).
The update function looks like this:
function update() {
var pointGroup = nodeGroup.selectAll('.node')
.data(data.nodes, function(d) { return d ? d.id : this.id; });
pointGroup.exit().remove();
var newNodeGroups = pointGroup.enter().append('g')
.attr('class', 'node');
newNodeGroups.append('circle')
.attr('r', function(d) { return circleRadius[d.type] });
newNodeGroups.append('text')
.text(function(d) { return d.id; })
.attr('class', function(d) { return d.type; });
var allLinks = linkGroup.selectAll('line')
.data(data.links, function(d) { return d.source+'-'+d.target; });
allLinks.exit().remove();
newLinks = allLinks.enter().append('line')
.attr('class', 'link');
var circles = nodeGroup.selectAll('circle');
var text = nodeGroup.selectAll('text');
var lines = linkGroup.selectAll('line');
function ticked() {
lines
.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; });
circles
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
text
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; });
}
simulation
.on('tick', ticked)
.restart();
};
I've been trying to glue ideas from various d3 examples into what i need, starting with the basic example using miserable.json data and then adding:
use of a key function for the data joins
modifying the underlying graph ala this example
making the links' linkDistance() function depend on an attribute of the graph's links'
adding labels to the nodes ala this example
So far i'm only 3 out of 4: something about using the g elements -- using code taken directly from the Mike's "Labeled Force Layout" example -- breaks things and the nodes aren't drawn. I can make it work if i join circle elements directly, but not if I interpose g elements with attached circles and text elements.
The code below is my best effort at a minimal example. This example works, but does not if I replace the .enter().append("circle") line with the .enter().append("g") lines.
Does anyone know why?
var Width = 200;
var Height = 200;
var Pix2Len = 10;
var color = d3.scale.category10();
var svg = d3.select("body").append("svg")
.attr("width", Width)
.attr("height", Height);
var force = d3.layout.force()
.size([Width, Height])
var graph = {
"nodes":[
{"name":"Myriel","idx":0},
{"name":"Napoleon","idx":1},
{"name":"Mlle.Baptistine","idx":2},
{"name":"Mme.Magloire","idx":3}
],
"links":[
{"source":1,"target":0,"len":1,"idx":"1-0"},
{"source":2,"target":1,"len":4,"idx":"2-1"},
{"source":2,"target":0,"len":8,"idx":"2-0"},
{"source":3,"target":0,"len":10,"idx":"3-0"},
{"source":3,"target":1,"len":4,"idx":"3-1"},
{"source":3,"target":2,"len":6,"idx":"3-2"}
]
}
console.log("data loaded. nnode="+graph.nodes.length+" nlinks="+graph.links.length);
force
.nodes(graph.nodes)
.links(graph.links)
.size([Width, Height])
.linkDistance(function(link) {
// console.log("link: "+link.source.name+' '+link.target.name+' '+link.idx+' '+link.len)
return link.len * Pix2Len})
.on("tick", tick);
var link = svg.selectAll(".link")
.data(graph.links, function(d) {return d.idx; })
.enter().append("line")
.attr("class", "link");
var node = svg.selectAll(".node")
.data(graph.nodes, function(d) {return d.idx; })
// THIS WORKS
.enter().append("circle").attr("r", 8).style("fill", function(d) { return color(0); });
// BUT THIS DOES NOT
// modeled after http://bl.ocks.org/mbostock/950642
//
//.enter().append("g")
//.attr("class", "node")
//.attr("cx", function(d) { return d.x; })
//.attr("cy", function(d) { return d.y; });
//
//node.append("circle")
//.attr("r", 10)
//.style("fill", function(d) { return color(0); });
//
//node.append("text")
//.attr("dx", 12)
//.attr("dy", ".35em")
//.text(function(d) { return d.name });
// 1. Begin with graph from JSON data
setTimeout(function() {
start();
}, 0);
// 2. Change graph topology
setTimeout(function() {
var new4 = {"name":"CountessdeLo","idx":4}
var new5 = {"name":"Geborand","idx":5}
graph.nodes.push(new4,new5);
var link40 = {"source":4,"target":0,"len":1,"idx":"4-0"};
var link43 = {"source":4,"target":3,"len":4,"idx":"4-3"};
var link50 = {"source":5,"target":0,"len":1,"idx":"5-0"};
var link52 = {"source":5,"target":2,"len":4,"idx":"5-2"};
graph.links.push(link40,link43,link50,link52);
start();
}, 3000);
//3. Change some link lengths
setTimeout(function() {
// force.links().forEach(function(link) {
graph.links.forEach(function(link) {
if (link.idx == '1-0')
{link.len=10; }
else if (link.idx == '3-0')
{link.len=2; }
else if (link.idx == '5-0')
{link.len=10; };
}); // eo-forEach
start();
}, 6000);
function start() {
link = link.data(force.links(), function(d) { return d.idx; });
link.enter().insert("line", ".node").attr("class", "link");
link.exit().remove();
node = node.data(force.nodes(), function(d) { return d.idx;});
node.enter().append("circle").attr("class", function(d) {
// tried with the <g> version above
// node.enter().append("g").attr("class", function(d) {
console.log('start:'+' '+d.name);
return d.idx; }).attr("r", 5).style("fill", function(d) { return color(1); });
node.exit().remove();
force.start();
}
function tick() {
node.attr("cx", function(d) {
// console.log('tick:'+' '+d.name);
return d.x; })
.attr("cy", function(d) { return d.y; })
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; });
}
//} // eo-ready()
In your code you are setting cx and cy attributes to the g element. g elements does not support any position attributes like x, y or cx, cy. To move the contents of a g element you will have to use the transform attribute.
Your code
var node = svg.selectAll(".node")
.data(graph.nodes, function(d) {return d.idx; })
.enter().append("g")
.attr("class", "node")
.attr("cx", function(d) { return d.x; }) //will not work
.attr("cy", function(d) { return d.y; }); //will not work
Solution
var node = svg.selectAll(".node")
.data(graph.nodes, function(d) {return d.idx; })
.enter().append("g")
.attr("class", "node");
node.append("circle")
.attr("r", 10)
.style("fill", function(d) { return color(0); });
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name });
Use translate function as below to move group elements.
function tick() {
//Moving <g> elements using transform attribute
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
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; });
}
JSFiddle
I am trying to implement fisheye distortion on a force directed graph using d3.js. For some reason, the distortion works on the links but not the nodes. This might be caused by the nodes being g elements, but I am not sure. Any help would be appreciated!
var svg, node, link;
function make_graph() {
// Clear out the div first
$("#display_graph svg:first").remove();
// Sets size
var width = 960,
height = 500;
// Maps groups to colors
var color = d3.scale.category20();
// Select the div and append a svg
svg = d3.select("#display_graph").append("svg")
.attr("width", width)
.attr("height", height);
// Pull json from graph
var json_from_db = $('.graph_json').data('json');
var json_nodes = json_from_db.nodes
var json_links = json_from_db.links
// Sets up the force directed graph
var charge_val = $('#charge').val();
var link_distance_val = $('#link_distance').val();
var force = d3.layout.force()
.charge(charge_val)
.linkDistance(link_distance_val)
.size([width, height])
.nodes(json_nodes)
.links(json_links)
.start();
link = svg.selectAll(".link")
.data(json_links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var font_size_px = $('#font_size').val();
node = svg.selectAll(".node")
.data(json_nodes)
.enter().append("g")
.attr("class", "node")
.style("font-size", font_size_px)
.call(force.drag);
var radius = $('#radius').val();
node.append("circle")
.attr("r", radius)
.style("fill", function(d) { return color(d.group); });
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
force.on("tick", function() {
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 + ")"; });
});
$('#fisheye_btn').click( function() {
var glyph_color = $(this).css('color');
// original color is white
orig_color = 'rgb(255, 255, 255)';
if (glyph_color == orig_color) {
$(this).css('color', 'orange');
} else {
$(this).css('color', orig_color);
};
});
};
function make_fisheye() {
var fisheye = d3.fisheye.circular()
.radius(200)
.distortion(2);
svg.on("mousemove", function() {
fisheye.focus(d3.mouse(this));
node.each(function(d) { d.fisheye = fisheye(d); })
.attr("cx", function(d) { return d.fisheye.x; })
.attr("cy", function(d) { return d.fisheye.y; })
.attr("r", function(d) { return d.fisheye.z * 4.5; });
link.attr("x1", function(d) { return d.source.fisheye.x; })
.attr("y1", function(d) { return d.source.fisheye.y; })
.attr("x2", function(d) { return d.target.fisheye.x; })
.attr("y2", function(d) { return d.target.fisheye.y; });
});
}
Eventually, I want the user to be able to turn the distortion on or off by clicking a button. Thanks for your help!
I updated the code. I can turn the distortion on or off with a button click now.
// Make force directed graph on button click
$(document).ready( function() {
$("#refresh_btn").click( function() {
make_graph();
});
});
// Turn on and off fisheye distortion
$(document).ready( function() {
$('#fisheye_btn').click( function() {
var glyph_color = $(this).css('color');
// original color is white
orig_color = 'rgb(255, 255, 255)';
if (glyph_color == orig_color) {
$(this).css('color', 'orange');
make_graph();
make_fisheye();
} else {
$(this).css('color', orig_color);
make_graph();
};
});
});
var svg, node, link;
function make_graph() {
// Clear out the div first
$("#display_graph svg:first").remove();
// Sets size
var width = 960,
height = 500;
// Maps groups to colors
var color = d3.scale.category20();
// Select the div and append a svg
svg = d3.select("#display_graph").append("svg")
.attr("width", width)
.attr("height", height);
// Pull json from graph
var json_from_db = $('.graph_json').data('json');
var json_nodes = json_from_db.nodes
var json_links = json_from_db.links
// Sets up the force directed graph
var charge_val = $('#charge').val();
var link_distance_val = $('#link_distance').val();
var force = d3.layout.force()
.charge(charge_val)
.linkDistance(link_distance_val)
.size([width, height])
.nodes(json_nodes)
.links(json_links)
.start();
link = svg.selectAll(".link")
.data(json_links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var font_size_px = $('#font_size').val();
node = svg.selectAll(".node")
.data(json_nodes)
.enter().append("g")
.attr("class", "node")
.style("font-size", font_size_px)
.call(force.drag);
var radius = $('#radius').val();
node.append("circle")
.attr("r", radius)
.style("fill", function(d) { return color(d.group); });
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
force.on("tick", function() {
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 make_fisheye() {
var fisheye = d3.fisheye.circular()
.radius(200)
.distortion(2);
svg.on("mousemove", function() {
fisheye.focus(d3.mouse(this));
node.each(function(d) { d.fisheye = fisheye(d); })
.attr("cx", function(d) { return d.fisheye.x; })
.attr("cy", function(d) { return d.fisheye.y; })
.attr("r", function(d) { return d.fisheye.z * 4.5; });
link.attr("x1", function(d) { return d.source.fisheye.x; })
.attr("y1", function(d) { return d.source.fisheye.y; })
.attr("x2", function(d) { return d.target.fisheye.x; })
.attr("y2", function(d) { return d.target.fisheye.y; });
});
}
Unfortunately, I am still having issues with just the links being distorted. The nodes are actually g elements, which I am becoming more and more convinced might be the problem. Is there a way to select elements inside the g element using d3.js? I am surprised that the fisheye distortion is not just passed on to the elements inside the g element. Maybe my guess is wrong?
New Code
Now both the nodes and links are distorted on a button click! Here is the code:
// Global variables
var svg, node, link;
var fisheye_on = false;
// Make force directed graph on button click
$(document).ready( function() {
$("#refresh_btn").click( function() {
// Make sure fisheye is turned off
$('#fisheye_btn').css('color', 'white');
fisheye_on = false;
make_graph();
});
});
// Turn on and off fisheye distortion
$(document).ready( function() {
$('#fisheye_btn').click( function() {
var glyph_color = $(this).css('color');
// original color is white
orig_color = 'rgb(255, 255, 255)';
if (glyph_color == orig_color) {
$(this).css('color', 'orange');
fisheye_on = true;
make_graph();
} else {
$(this).css('color', orig_color);
fisheye_on = false;
make_graph();
};
});
});
function make_graph() {
// Clear out the div first
$("#display_graph svg:first").remove();
// Sets size
var width = 960,
height = 500;
// Maps groups to colors
var color = d3.scale.category20();
// Select the div and append a svg
svg = d3.select("#display_graph").append("svg")
.attr("width", width)
.attr("height", height);
// Pull json from graph
var json_from_db = $('.graph_json').data('json');
var json_nodes = json_from_db.nodes
var json_links = json_from_db.links
// Sets up the force directed graph
var charge_val = $('#charge').val();
var link_distance_val = $('#link_distance').val();
var force = d3.layout.force()
.charge(charge_val)
.linkDistance(link_distance_val)
.size([width, height])
.nodes(json_nodes)
.links(json_links)
.start();
link = svg.selectAll(".link")
.data(json_links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var font_size_px = $('#font_size').val();
node = svg.selectAll(".node")
.data(json_nodes)
.enter().append("g")
.attr("class", "node")
.style("font-size", font_size_px)
.call(force.drag);
var radius = $('#radius').val();
node.append("circle")
.attr("r", radius)
.style("fill", function(d) { return color(d.group); });
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
if (fisheye_on == false) {
force.on("tick", function() {
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 + ")"; });
});
} else {
var fisheye = d3.fisheye.circular()
.radius(200)
.distortion(2);
svg.on("mousemove", function() {
fisheye.focus(d3.mouse(this));
node.each(function(d) { d.fisheye = fisheye(d); });
node.selectAll("circle")
.attr("cx", function(d) { return d.fisheye.x - d.x; })
.attr("cy", function(d) { return d.fisheye.y - d.y; })
.attr("r", function(d) { return d.fisheye.z * 4.5; });
node.selectAll("text")
.attr("dx", function(d) { return d.fisheye.x - d.x; })
.attr("dy", function(d) { return d.fisheye.y - d.y; });
link.attr("x1", function(d) { return d.source.fisheye.x; })
.attr("y1", function(d) { return d.source.fisheye.y; })
.attr("x2", function(d) { return d.target.fisheye.x; })
.attr("y2", function(d) { return d.target.fisheye.y; });
});
};
};
Unfortunately, I have come across another issue. There seems to be an initial lag when the distortion is applied. The nodes get distorted first and then the links get distorted. Not sure what is causing this. Any hints?
Public JSFiddle
I managed to replicated the issue in a public JSFiddle:
http://jsfiddle.net/cspears2002/vVL99/
In order to make the graph, just click "Make Graph". Clicking "Fisheye" will turn the fisheye distortion on and off. The issue is that the nodes are distorted first and then the links follow. I want nodes and links to be distorted at the same time. Any help would be appreciated!