Hello im trying to implement this D3 project http://bl.ocks.org/929623:
with images like this one http://bl.ocks.org/950642:
But I can't make the source images to resize and move along with the nodes. Heres the code:
var nodesCreated = 1;
var newDistance = 100;
var width = document.documentElement.clientWidth,
height = document.documentElement.clientHeight,
fill = d3.scale.category20(),
nodes = [],
links = [];
var vis = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height);
vis.append("rect")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.linkDistance(newDistance)
.nodes(nodes)
.links(links)
.gravity(.01)
.size([width, height]);
force.on("tick", function() {
vis.selectAll("line.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; });
vis.selectAll(".node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
var tempX = window.innerWidth/2;
var tempY = window.innerHeight/2;
var point = tempX,tempY,
node = {imgsrc: "https://fbcdn-profile-a.akamaihd.net/hprofile-ak-prn1/48799_806120304_700633127_n.jpg"};
n = nodes.push(node);
vis.on("mousedown", function() {
var point = d3.mouse(this),
node = {imgsrc: "https://fbcdn-profile-a.akamaihd.net/hprofile-ak-ash4/211698_100002756979859_374256176_n.jpg"},
n = nodes.push(node);
nodesCreated++;
console.log(nodesCreated);
var tempCounter = 0;
newDistance == 10;
force.linkDistance(newDistance);
nodes.forEach(function(target) {
if (/*Math.sqrt(x * x + y * y) < 100 ||*/ tempCounter == 0) {
links.push({source: node, target: target});
tempCounter++;
}
});
restart();
});
function restart() {
force.start();
vis.selectAll("line.link")
.data(links)
.enter().insert("line", ".node")
.attr("class", "link");
var realNode = vis.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
realNode.append("image")
.attr("xlink:href", function(d) { return d.imgsrc; })
.attr("x", -8)
.attr("y", -8)
.attr("width", 160)
.attr("height", 160);
}
I have been looking for some help at google but I found no solution.
You should add X and Y co-ordinates to your nodes:
var tempX = window.innerWidth/2;
var tempY = window.innerHeight/2;
var point = [tempX,tempY],
node = {imgsrc: "https://fbcdn-profile-a.akamaihd.net/hprofile-ak-prn1/48799_806120304_700633127_n.jpg", x: tempX, y: tempY};
and
var point = d3.mouse(this),
node = {imgsrc: "https://fbcdn-profile-a.akamaihd.net/hprofile-ak-ash4/211698_100002756979859_374256176_n.jpg", x:point[0], y:point[1]},
n = nodes.push(node);
And then need to add a transform to the force.on("tick".... function:
vis.selectAll(".node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ") scale(0.30)"; });
This scales your images down to 30%, but you can configure this.
For completeness, here is all of the code:
var nodesCreated = 1;
var newDistance = 100;
var width = document.documentElement.clientWidth,
height = document.documentElement.clientHeight,
fill = d3.scale.category20(),
nodes = [],
links = [];
var vis = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height);
vis.append("rect")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.linkDistance(newDistance)
.nodes(nodes)
.links(links)
.gravity(.01)
.size([width, height]);
force.on("tick", function() {
vis.selectAll("line.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; });
vis.selectAll(".node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
vis.selectAll(".node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ") scale(0.30)"; });
});
var tempX = window.innerWidth/2;
var tempY = window.innerHeight/2;
var point = [tempX,tempY],
node = {imgsrc: "https://fbcdn-profile-a.akamaihd.net/hprofile-ak-prn1/48799_806120304_700633127_n.jpg", x: tempX, y:tempY};
n = nodes.push(node);
vis.on("mousedown", function() {
var point = d3.mouse(this),
node = {imgsrc: "https://fbcdn-profile-a.akamaihd.net/hprofile-ak-ash4/211698_100002756979859_374256176_n.jpg", x:point[0], y:point[1]},
n = nodes.push(node);
nodesCreated++;
console.log(nodesCreated);
var tempCounter = 0;
newDistance == 10;
force.linkDistance(newDistance);
nodes.forEach(function(target) {
if (/*Math.sqrt(x * x + y * y) < 100 ||*/ tempCounter == 0) {
links.push({source: node, target: target});
tempCounter++;
}
});
restart();
});
function restart() {
force.start();
vis.selectAll("line.link")
.data(links)
.enter().insert("line", ".node")
.attr("class", "link");
var realNode = vis.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
realNode.append("image")
.attr("xlink:href", function(d) { return d.imgsrc; })
.attr("x", -8)
.attr("y", -8)
.attr("width", 160)
.attr("height", 160);
}
Related
I've been wrestling very hard with D3 to try to make a simple bubble-chart using force collide that live-updates the bubble size.
I can get the chart to show on the first data update with force collide. However subsequent data calls freeze the chart and the sizes are never updated:
https://jsfiddle.net/d2zcfjfa/1/
node = svg.selectAll('g.node')
.data(root.children)
.enter()
.append('g')
.attr('class', 'node')
.append('circle')
.attr('r', function(d) { return d.r * 1.4; })
.attr('fill', function(d) { return color(d.data.name); })
.call(d3.drag()
.on("start", dragStart)
.on("drag", dragged)
.on("end", dragEnd));
var circleUpdate = node.select('circle')
.attr('r', function(d)
{
return d.r;
});
simulation.nodes(root.children);
I can get updates to work but only without using the collide simulation as seen here:
https://jsfiddle.net/rgdox7g7/1/
node = svg.selectAll('g.node')
.data(root.children)
.enter()
.append('g')
.attr('id', function(d) { return d.id; })
.attr('class', 'node')
.attr('transform', function(d)
{
return "translate(" + d.x + "," + d.y + ")";
});
var nodeUpdate = svg.selectAll('g.node')
.transition()
.duration(2000)
.ease(d3.easeLinear);
var circleUpdate = nodeUpdate.select('circle')
.attr('r', function(d)
{
return d.r;
});
node.append("circle")
.attr("r", function(d) { return d.r; })
.style('fill', function(d) { return color(d.data.name); });
Everything I have tried to mix these two solutions together simply does not work. I have scoured the internet for other examples and nothing I can find is helping. Can someone please help me understand what to do? I never thought D3 would be such a frustration!
stackoverflow: the place where you have to answer your own questions.
here is my working solution:
https://jsfiddle.net/zc0fgh6y/
var subscription = null;
var width = 600;
var height = 300;
var maxSpeed = 1000000;
var pack = d3.pack().size([width, height]).padding(0);
var svg = d3.select('svg');
var node = svg.selectAll("g.node");
var root;
var nodes = [];
var first = true;
var scaleFactor = 1.4;
var color = d3.interpolateHcl("#0faac3", "#dd2323");
var forceCollide = d3.forceCollide()
.strength(.8)
.radius(function(d)
{
return d.r;
}).iterations(10);
var simulationStart = d3.forceSimulation()
.force("forceX", d3.forceX(width/2).strength(.04))
.force("forceY", d3.forceY(height/2).strength(.2))
.force('collide', forceCollide)
.on('tick', ticked);
var simulation = d3.forceSimulation()
.force("forceX", d3.forceX(width/2).strength(.0005))
.force("forceY", d3.forceY(height/2).strength(.0025))
.force('collide', forceCollide)
.on('tick', ticked);
function ticked()
{
if (node)
{
node.attr('transform', function(d)
{
return "translate(" + d.x + "," + d.y + ")";
}).select('circle').attr('r', function(d)
{
return d.r;
});
}
}
function rand(min, max)
{
return Math.random() * (max - min) + min;
};
setInterval(function()
{
var hosts = [];
for (var i = 0; i < 100; i++)
{
hosts.push({name: i, cpu: rand(10,100), speed: rand(0,maxSpeed)});
}
root = d3.hierarchy({children: hosts})
.sum(function(d)
{
return d.cpu ? d.cpu : 0;
});
var leaves = pack(root).leaves().map(function(item)
{
return {
id: 'node-'+item.data.name,
name: item.data.name,
r: item.r * scaleFactor,
x: width/2,
y: height/2,
cpu: item.data.cpu,
speed: item.data.speed
};
});
for (var i = 0; i < leaves.length; i++)
{
if (nodes[i] && nodes[i].id == leaves[i].id)
{
var oldR = nodes[i].newR;
nodes[i].oldR = oldR;
nodes[i].newR = leaves[i].r;
nodes[i].cpu = leaves[i].cpu;
nodes[i].speed = leaves[i].speed;
}
else
{
nodes[i] = leaves[i];
//nodes[i].r = 1;
nodes[i].oldR = 1;//nodes[i].r;
nodes[i].newR = leaves[i].r;
}
}
if (first)
{
first = false;
node = node.data(nodes, function(d) { return d.id; });
node = node.enter()
.append('g')
.attr('class', 'node');
node.append("circle")
.style("fill", 'transparent');
node.append("text")
.attr("dy", "0.3em")
.style('fill', 'transparent')
.style("text-anchor", "middle")
.text(function(d)
{
return d.name;//.substring(0, d.r / 4);
});
// transition in size
node.transition()
.ease(d3.easePolyInOut)
.duration(950)
.tween('radius', function(d)
{
var that = d3.select(this);
var i = d3.interpolate(1, d.newR);
return function(t)
{
d.r = i(t);
that.attr('r', function(d)
{
return d.r;
});
simulationStart.nodes(nodes).alpha(1);
}
});
// fade in text color
node.select('text')
.transition()
.ease(d3.easePolyInOut)
.duration(950)
.style('fill', 'white');
// fade in circle size
node.select('circle')
.transition()
.ease(d3.easePolyInOut)
.duration(950)
.style('fill', function(d)
{
return color(d.speed / maxSpeed);
});
}
else
{
// transition to new size
node.transition()
.ease(d3.easeLinear)
.duration(950)
.tween('radius', function(d)
{
var that = d3.select(this);
var i = d3.interpolate(d.oldR, d.newR);
return function(t)
{
d.r = i(t);
that.attr('r', function(d)
{
return d.r;
});
simulation.nodes(nodes).alpha(1);
}
});
// transition to new color
node.select('circle')
.transition()
.ease(d3.easeLinear)
.duration(950)
.style('fill', function(d)
{
return color(d.speed / maxSpeed);
});
}
}, 1000);
I built in Apex a D3 force graph basically like http://bl.ocks.org/mbostock/1093130 or http://bl.ocks.org/mbostock/4062045. The difference is, that I pull my data with an Application Process from a address table from the database. It works just fine.
The colors of the nodes are defined by the address type (like Contact, Payment Office, Licensees, ...). Now I want to add a legend on the side of the page with the different colors the graph is using and the connected address type.
Do I do that in the Page Attributes in the CSS Inline Part, or do I have to add something in the D3 graph JavaScript code.
Here is my code:
var graph;
function get_chart_data() {
var get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=AddressData',$v('pFlowStepId'));
var data_all = get.get();
var obj = eval ("(" + data_all + ")");
return obj;
}
function showChart2() {
graph = get_chart_data();
var width = 1000,
height = 800;
var color = d3.scale.category20();
var force = d3.layout.force()
.gravity(0)
.charge(-400)
.linkDistance(90)
.size([width, height]);
var svg = d3.select("#chart2").append("svg")
.attr("width", width)
.attr("height", height);
var nodeById = d3.map();
graph.nodes.forEach(function(node) {
nodeById.set(node.id, node);
});
graph.links.forEach(function(link) {
link.source = nodeById.get(link.source);
link.target = nodeById.get(link.target);
});
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 8)
.style("fill", function(d) { return color(d.type); })
node.append("text")
.attr("x", 12)
.attr("dy", ".35em")
.text(function(d) { return d.first_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 + ")"; });
});
};
I hope I explained it well enough for you to understand it.
Guess what, I just solved my own question :)
I added a code in the JavaScript part of the Page Attributes at the end of the function showChart2(), but still in it.
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
And here is the full working code:
var graph;
function get_chart_data() {
var get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=AddressData',$v('pFlowStepId'));
var data_all = get.get();
var obj = eval ("(" + data_all + ")");
return obj;
}
function showChart2() {
graph = get_chart_data();
var width = 1000,
height = 800;
var color = d3.scale.category20();
var force = d3.layout.force()
.gravity(0)
.charge(-400)
.linkDistance(90)
.size([width, height]);
var svg = d3.select("#chart2").append("svg")
.attr("width", width)
.attr("height", height);
var nodeById = d3.map();
graph.nodes.forEach(function(node) {
nodeById.set(node.id, node);
});
graph.links.forEach(function(link) {
link.source = nodeById.get(link.source);
link.target = nodeById.get(link.target);
});
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 8)
.style("fill", function(d) { return color(d.type); })
node.append("text")
.attr("x", 12)
.attr("dy", ".35em")
.text(function(d) { return d.first_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 + ")"; });
});
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
};
I never thought I could answer my own question, but it works ;)
I hope it helps somebody else too...
So I am trying to create a legend in the bottom right corner of my D3. I have written all of the code for the legend but it comes up as just a black screen with the force-directed graph not showing up as well. Any advice would help.
Legend Code:
var color = d3.scale.ordinal()
.domain(["<400", "400-549", "550-699", "700-849", "850-999", "1000-1149", "1150-1299", "1300-1449", ">1450"])
.range(["#1a9850", "#66bd63", "#a6d96a","#d9ef8b","#ffffbf","#fee08b","#fdae61","#f46d43","#d73027"]);
var legend = d3.append('svg')
.append("g")
.selectAll("g")
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize;
var x = 0;
var y = i * height;
return 'translate(' + x + ',' + y + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d; });
D3 Code:
function start(){
var w = 1200,
h = 600,
radius = 10,
node,
link,
root;
var count = 0;
var color = d3.scale.ordinal()
.domain(["<400", "400-549", "550-699", "700-849", "850-999", "1000-1149", "1150-1299", "1300-1449", ">1450"])
.range(["#1a9850", "#66bd63", "#a6d96a","#d9ef8b","#ffffbf","#fee08b","#fdae61","#f46d43","#d73027"]);
var force = d3.layout.force()
.on("tick", tick)
.charge(function(d) { return -500; })
.linkDistance(function(d) { return d.target._children ? 100 : 50; })
.size([w, h - 160]);
`
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "#000");
var legend = d3.append('svg')
.append("g")
.selectAll("g")
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize;
var x = 0;
var y = i * height;
return 'translate(' + x + ',' + y + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d; });
root = JSON.parse(jsonObject);
console.log("root"+root);
root.fixed = true;
root.x = w / 2;
root.y = h / 2 - 80;
update();
function update() {
var nodes = root.nodes,
links = root.links;
// Restart the force layout.
force
.nodes(nodes)
.links(links)
.start();
// Update the links…
link = svg.selectAll(".link")
.data(links);
// Enter any new links.
link.enter().insert("svg: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; });
// Exit any old links.
link.exit().remove();
// Update the nodes…
node = svg.selectAll("circle.node")
.data(nodes, function(d) {
return d.name;
})
.style("fill", color);
node.transition()
.attr("r", radius);
// Enter any new nodes.
node.enter().append("svg:circle")
.attr("xlink:href", function(d) { return d.image;})
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", radius)
.attr("r", function(d)
{return d.size * 2 ;})
.style("fill", color)
.on("click", click)
.call(force.drag);
node.append("title")
.text(function(d) { return d.name; });
// Exit any old nodes.
node.exit().remove();
title = svg.selectAll("text.title")
.data(nodes);
// Enter any new titles.
title.enter()
.append("text")
.attr("class", "title");
//.text(function(d) { return d.name; });
// Exit any old titles.
title.exit().remove();
}
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; });
title.attr("transform", function(d){ return "translate("+d.x+","+d.y+")"; });
}
// Color leaf nodes orange, and packages white or blue.
function color(d) {
if(d._children){
return "#95a5a6";
}else{
switch(d.group) {
case 'r': //adverb
return "#e74c3c";
break;
case 'n': //noun
return "#3498db";
break;
case 'v': //verb
return "#2ecc71";
break;
case 's': //adjective
return "#e78229";
break;
default:
return "rgb(0, 238, 238)";
}
}
}
// Toggle children on click.
function click(d) {
document.getElementById("image").src = d.image;
document.getElementById("username").innerHTML = "Username:"+d.name;
document.getElementById("id").innerHTML = "ID:" + d.id;
document.getElementById("friends").innerHTML = d.friend;
document.getElementById("nodeTitle").innerHTML = "";
document.getElementById("size").innerHTML = d.size;
//document.getElementById("id").innerHTML = "Friend Count:" + d.name;
//if (d._children)
//grabImage();
//document.getElementById("image").innerHTML = (d.image);
/*if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update();*/
}
function mouseover() {
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", 16);
}
function mouseout() {
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", 8);
}
// Returns a list of all nodes under the root.
function flatten(root) {
var nodes = [], i = 0;
function recurse(node) {
if (node.children) node.size = node.children.reduce(function(p, v) { return p + recurse(v); }, 0);
if (!node.id) node.id = ++i;
nodes.push(node);
return node.size;
}
root.size = recurse(root);
return nodes;
}};
do{
var intervalID = window.setTimeout(start, 1000)
}
while(jsonObject!=""){
}
I believe the error is in here somewhere:
var force = d3.layout.force()
.on("tick", tick)
.charge(function(d) { return -500; })
.linkDistance(function(d) { return d.target._children ? 100 : 50; })
.size([w, h - 160]);
`
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "#000");
var legend = d3.append('svg')
.append("g")
.selectAll("g")
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize;
var x = 0;
var y = i * height;
return 'translate(' + x + ',' + y + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d; });
JSFIDDLE :
jsfiddle.net/d1kp0qeL/1
This is incorrect:
var legend = d3.append('svg').append("g")
should have been (you should append, the g group which holds legend to the svg)
var legend = svg.append("g")
I'm trying to do a graph like this example: http://bl.ocks.org/mbostock/1747543
The problem that I have is that when I execute my html, there are an error that says:
SyntaxError: expected expression, got '.'
My code is:
var width = 900,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.gravity(.1)
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("body").select('#contenedor').select('#contenido').append("svg")
.attr("width", width)
.attr("height", height);
d3.json("fisica_noms.json", function(error, graph) {
if (error) throw error;
var clusters = []
var getColors = function(category){
var nods = graph.nodes;
var subs = [];
var m = {};
for (var ele in nods){
for(var categs in ele){
if (!m[categs] && categs == category){
m[categs] = true;
subs.push(categs);
};
};
};
return subs;
};
var sameCategory = function(category,subCategory){
var nods = graph.nodes;
var subs = [];
for(var i=0; i<nods.length;i++){
if(nods[i][category]===subCategory){
subs.push(nods[i])};
};
return subs
};
var searchClusters = function(){
var nods = graph.nodes;
var nCom = getColors('Comunitat').length;
for(var i=0; i<nCom;i++){
clusters.push(sameCategory('Comunitat',i));
clusters[i] = d3.max(clusters[i], function(d) {return d.degree;});
};
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("weight", function(d) { return Math.sqrt(d.value); });
force.linkStrength(function(link){return link.value}) ;
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function(d){return d.degree/60})
.style("fill", function(d) { return color(d.Comunitat); })
.call(force.drag)
.on('click',function(d){showInfo(d);});
node.append("title")
.text(function(d) { return d.id; });
force.on("tick",tick);
function tick (e) {
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; });
console.log(e);
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
.each(cluster(10 * e.alpha * e.alpha))
};
// Move d to be adjacent to the cluster node.
function cluster(alpha) {
return function(d) {
var cluster = clusters[d.Comunitat];
if (cluster === d) return;
var x = d.x - cluster.x,
y = d.y - cluster.y,
l = Math.sqrt(x * x + y * y),
r = d.degree/60 + cluster.degree/60;
if (l != r) {
l = (l - r) / l * alpha;
d.x -= x *= l;
d.y -= y *= l;
cluster.x += x;
cluster.y += y;
}
};
}
});
};
The console says that my error is here:
.each(cluster(10 * e.alpha * e.alpha))
This question already has answers here:
d3.js linkStrength influence on linkDistance in a force graph
(2 answers)
Closed 2 years ago.
I am trying to create a static force directed graph. One that loads without any animation in. Here's what I'm trying to emulate: http://bl.ocks.org/mbostock/1667139
I have the following D3 graph:
var width = $("#theVizness").width(),
height = $("#theVizness").height();
var color = d3.scale.ordinal().range(["#ff0000", "#fff000", "#ff4900"]);
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("#theVizness").append("svg")
.attr("width", width)
.attr("height", height);
var loading = svg.append("text")
.attr("class", "loading")
.attr("x", width / 2)
.attr("y", height / 2)
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text("Loading...");
d3.json("https://dl.dropboxusercontent.com/u/5772230/ForceDirectData.json", function (error, json) {
var nodes = json.nodes;
force.nodes(nodes)
.links(json.links)
.linkDistance(function (d) {
return d.value * 1.5;
})
.friction(0.4);
var link = svg.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", 1);
var files = svg.selectAll(".file")
.data(json.nodes)
.enter().append("circle")
.attr("class", "file")
.attr("r", 10)
.attr("fill", function (d) {
return color(d.colorGroup);
});
var totalNodes = files[0].length;
files.append("title")
.text(function (d) { return d.name; });
force.start();
for (var i = totalNodes * totalNodes; i > 0; --i) force.tick();
force.stop();
nodes[0].x = width / 2;
nodes[0].y = height / 2;
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; });
files.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("class", function(d){
var classString = "file"
if (d.index === 0) classString += " rootFile";
return classString;
})
.attr("r", function(d){
var radius = 10;
if (d.index === 0) radius = radius * 2;
return radius;
});
loading.remove();
});
Here's my data: https://dl.dropboxusercontent.com/u/5772230/ForceDirectData.json
{
"nodes":[
{"name":"File1.exe","colorGroup":0},
{"name":"File2.exe","colorGroup":0},
{"name":"File3.exe","colorGroup":0},
{"name":"File4.exe","colorGroup":0},
{"name":"File5.exe","colorGroup":0},
{"name":"File6.exe","colorGroup":0},
{"name":"File7.exe","colorGroup":0},
{"name":"File8.exe","colorGroup":0},
{"name":"File8.exe","colorGroup":0},
{"name":"File9.exe","colorGroup":0}
],
"links":[
{"source":1,"target":0,"value":10},
{"source":2,"target":0,"value":35},
{"source":3,"target":0,"value":50},
{"source":4,"target":0,"value":50},
{"source":5,"target":0,"value":65},
{"source":6,"target":0,"value":65},
{"source":7,"target":0,"value":81},
{"source":8,"target":0,"value":98},
{"source":9,"target":0,"value":100}
]
}
Fiddle
From my understanding of the bl.ocks page, this graph is running the tick method a certain amount of times. But my issue is the lengths of my links between the nodes are not proportionate to what I have in my JSON file.
I've opted for the static graph because I did not want to have the graph animate in, like in the standard graph.
Why are my links to the nodes nor correctly proportioned to match my JSON file?
I do not understand your question.
Is this what you mean?
var width = $("#theVizness").width(),
height = $("#theVizness").height();
var color = d3.scale.ordinal().range(["#ff0000", "#fff000", "#ff4900"]);
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("#theVizness").append("svg")
.attr("width", width)
.attr("height", height);
var loading = svg.append("text")
.attr("class", "loading")
.attr("x", width / 2)
.attr("y", height / 2)
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text("Loading...");
d3.json("https://dl.dropboxusercontent.com/u/5772230/ForceDirectData.json", function (error, json) {
var nodes = json.nodes;
force.nodes(nodes)
.links(json.links)
.linkDistance(function (d) {
return d.value * 1.5;
})
.friction(0.4);
var link = svg.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", 1);
var files = svg.selectAll(".file")
.data(json.nodes)
.enter().append("circle")
.attr("class", "file")
.attr("r", 10)
.attr("fill", function (d) {
return color(d.colorGroup);
});
var totalNodes = files[0].length;
files.append("title")
.text(function (d) { return d.name; });
force.start();
for (var i = totalNodes * totalNodes; i > 0; --i) force.tick();
nodes[0].x = width / 2;
nodes[0].y = height / 2;
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; });
files.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
.attr("class", function(d){
var classString = "file"
if (d.index === 0) classString += " rootFile";
return classString;
})
.attr("r", function(d){
var radius = 10;
if (d.index === 0) radius = radius * 2;
return radius;
});
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; });
files.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
loading.remove();
});
JSFiddle