Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unifinished work - force label placement #14

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 156 additions & 59 deletions network-onefile.html
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,8 @@
.attr("height", "800px")
.attr("width", "90%");

var nodes = []
var g_edges = [];
var box_width=200; // variable that determines box width and text length
var box_width=100; // variable that determines box width and text length
function forceDirected() {

queue()
Expand All @@ -98,12 +97,17 @@

function createForceLayout(edges, group) {
var nodeHash = {};
var nodes = []
var labelAnchorLinks = []
var labelAnchors= []

// helper function to populate our node list
function add_node(name, group, edge_id) {
if ( nodeHash[name] === undefined ) {
nodeHash[name] ={id: name, group: group, edges: []} ;
nodes.push(nodeHash[name]);
labelAnchors.push({ node : nodeHash[name]})
labelAnchors.push({ node : nodeHash[name]})
}
nodeHash[name].edges.push(edge_id);
}
Expand All @@ -120,34 +124,71 @@
g_edges.push(edges[x]);
}

for(var i = 0; i < nodes.length; i++) {
//labelAnchors.push({ node : nodeHash[i] });
//labelAnchors.push({ node : nodeHash[i] });
labelAnchorLinks.push({
source : i * 2,
target : i * 2 + 1,
weight : 1
});
}
var weightScale = d3.scale.linear()

.domain(d3.extent(edges, function(d) {return d.weight}))
.range([.1,1]); // defaults to weight = 1

force = d3.layout.force()
.charge(-1200) // #a How much each node pushes away each other, if set to a positive value, nodes will attract each other
.charge(-3000) // #a How much each node pushes away each other, if set to a positive value, nodes will attract each other
.gravity(1.00)
.friction(.50)
.linkDistance(50)
// function(d,i) {
// console.log(d,i);
// return 30 + (i%3)*20;
// }
// )
.size([800,800]) // size of whole animation width and height
.nodes(nodes)
.links(edges)
.on("tick", forceTick); // #b “tick” events are fired continuously, running the associated function


d3.select("svg").selectAll("line.link")
// dense connection for labels, so they all repel each other

force.start();

force2 = d3.layout.force()
.nodes(labelAnchors)
.links(labelAnchorLinks)
.gravity(0.010)
.linkDistance(0)
.linkStrength(8)
.charge(-120) // #a How much each node pushes away each other, if set to a positive value, nodes will attract each other
// function(d,i) {
// console.log(d,i);
// return 30 + (i%3)*20;
// }
// )
.size([800,800]) // size of whole animation width and height
//.on("tick", forceTick);

force2.start()

var link = d3.select("svg").selectAll("line.link")
.data(edges, function (d) {return d.source.id + "-" + d.target.id}) // #c Key values for our nodes and edges will help when we update the network later
.enter()
.append("line")
.attr("class", "link")
.style("stroke-width", function(d) {return d.weight});

var nodeEnter = d3.select("svg").selectAll("g.node")
.data(nodes, function (d) {return d.id})
.data(force.nodes(), function (d) {return d.id})
.enter()
.append("g")
.attr("class", "node");

//console.log (nodeEnter); // shows all 27 nodes


nodeEnter.append("circle")
.attr("r", 5)
Expand Down Expand Up @@ -183,77 +224,133 @@
function (e,j) { return e.highlight });

}
var anchorLink = svg.selectAll("line.anchorLink").data(labelAnchorLinks)//.enter().append("svg:line").attr("class", "anchorLink").style("stroke", "#F00");

var anchorNode = svg.selectAll("g.anchorNode").data(force2.nodes()).enter().append("svg:g").attr("class", "anchorNode");
anchorNode.append("svg:circle").attr("r", 0).style("fill", "#FFF");
anchorNode.append("svg:text").text(function(d, i) {
console.log(d,i);
return i % 2 == 0 ? "" : d.node.id
}).style("fill", "#555").style("font-family", "Arial").style("font-size", 12);
// replace circle with rectangular
nodeEnter.append('rect')
.attr('x', -box_width/2)
.attr('y', -5)
.attr('rx', 5)
.attr('height', '20')
.attr('width' , box_width)
.attr("class", function (d) {return d.group})

.on("mouseover", function(d,i) {
//d3.select(this).attr('title', d.id) svg:title takes care of this
//console.log(d, d.edges);
highlight(d.edges);


// return d.value ;

})
.on("mouseout", function(d,i) {
var rect = d3.select(this);
//rect.style("class", function(
highlight(d.edges, false);


// return d.value ;

})

.on("click", function(d,i) {
console.log(d, this.nid);
highlight(d.edges, false);
});

;


nodeEnter.append("text")
.style("text-anchor", "middle")
.style("pointer-events", "none")
.attr("y", 7)
// .attr("dy", ".1em")
.text(function(d) {return d.id})
.attr("class", "text");
var updateLink = function() {
this.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;
});

}

var updateNode = function() {
this.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});

}

force.start(); // #d Initializing the network will start firing “tick” events as well as calculate the degree centrality of nodes

nodeEnter.call(force.drag);

//nodeEnter.append('rect')
// .attr('x', -box_width/2)
// .attr('y', -5)
// .attr('rx', 5)
// .attr('opacity', 0.5)
// .attr('height', '20')
// .attr('width' , box_width)
// .attr("class", function (d) {return d.group})
//
// .on("mouseover", function(d,i) {
// //d3.select(this).attr('title', d.id) svg:title takes care of this
// //console.log(d, d.edges);
// highlight(d.edges);
// })
// .on("mouseout", function(d,i) {
// var rect = d3.select(this);
// //rect.style("class", function(
// highlight(d.edges, false);
// })
//
// .on("click", function(d,i) {
// console.log(d, this.nid);
// highlight(d.edges, false);
// });
//
// ;


//nodeEnter.append("text")
//.style("text-anchor", "middle")
//.style("pointer-events", "none")
//.attr("y", 7)
// //.attr("dy", ".1em")
//.text(function(d) {return d.id})
//.attr("class", "text");

force.start(); // #d Initializing the network will start firing “tick” events as well as calculate the degree centrality of nodes

function forceTick() {
d3.selectAll("line.link")
.attr("x1", function (d) {return d.source.x}) // #e The tick function updates the edge drawing code and node drawing code based on the newly calculated node positions
.attr("x2", function (d) {return d.target.x})
.attr("y1", function (d) {return d.source.y})
.attr("y2", function (d) {return d.target.y});


d3.selectAll("g.node")
.attr("transform", function (d) {return "translate("+d.x+","+d.y+")"})
}
// force2.start();
// d3.selectAll("line.link")
// .attr("x1", function (d) {return d.source.x}) // #e The tick function updates the edge drawing code and node drawing code based on the newly calculated node positions
// .attr("x2", function (d) {return d.target.x})
// .attr("y1", function (d) {return d.source.y})
// .attr("y2", function (d) {return d.target.y});
//
//
// d3.selectAll("g.node")
// .attr("transform", function (d) {return "translate("+d.x+","+d.y+")"})
// }

force2.start();

nodeEnter.call(updateNode);

anchorNode.each(function(d, i) {
if(i % 2 == 0) {
d.x = d.node.x;
d.y = d.node.y;
} else {
var b = this.childNodes[1].getBBox();

var diffX = d.x - d.node.x;
var diffY = d.y - d.node.y;

var dist = Math.sqrt(diffX * diffX + diffY * diffY);

var shiftX = b.width * (diffX - dist) / (dist * 2);
shiftX = Math.max(-b.width, Math.min(0, shiftX));
var shiftY = 5;
this.childNodes[1].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")");
}
});


anchorNode.call(updateNode);

link.call(updateLink);
anchorLink.call(updateLink);
}
pi_wrap();
}

// helper function to drop all but the first set of characters which will fit
// inside the box, and adds and ellipsis to the end
function pi_wrap() {
var text = d3.selectAll('text')[0];
var text = d3.selectAll('g.node text')[0];
text.forEach(function(x,i ) {
while (x.getBBox().width > box_width - 20) {
// keep dropping one letter off the end until we're down to 200 pixels
x.textContent = x.textContent.slice(0, x.textContent.length-2)
//x.textContent += "…"
x.textContent += '\u2026'
x.textContent += '\u2026';
}
});
};
Expand Down